# mate and rmate

TextMate is and will always be a modern GUI application. However, developers are often forced to walk in two worlds using both GUI and command-line tools. TextMate has always bridged the gap between these environments with its trusty command-line sidekick: `mate`.

In TextMate 2, `mate` has learned some new tricks. A new partner-in-crime has also been introduced: `rmate`.

In this article will discuss:

- How to install the upgraded `mate`
- `mate`'s new features
- What `rmate` is
- The different ways to use `rmate`

## Upgrade Time

Once you have TextMate 2, you need to make sure you refresh the command-line `mate` application. This allows you to take advantage of its new features.

The installer of this command-line utility has moved in TextMate 2. You can now find it in the TextMate menu under Preferences… in the Terminal pane.

The Terminal Preferences pane

To install or upgrade `mate`, just select a Location and hit Install. You may be prompted to Replace an old version, if present.

This pane can later be used to uninstall the command if you need to do that.

Users usually install `mate` into `~/bin` if they just need it for the current user and `/usr/local/bin` if they would rather make it accessible to all users (assuming they have `/usr/local/bin` in their `PATH`). If you would like to find where your TextMate 1 version is before you upgrade, feed your Terminal this command: `which mate`.

## Your New mate

Let's get to the good stuff. What's upgraded in `mate`?

First, it's a small tweak, but you will be happy to hear that `mate` now works with `sudo`. You can use this to edit restricted access files in TextMate 2 without being bothered by an authorization dialog on save:

    sudo mate /etc/hosts

Next, `mate` has picked up some new command-line options. One is `-t`, which allows you to set the type of an opened file. Personally, I like this feature for README files, which I prefer to write in Markdown. Since the name of standard files like this don't always include an extension, we can just tell TextMate 2 how to handle the file as we open it:

    mate -t text.html.markdown README

Another new option is `--name`. This allows you to set `TM_DISPLAYNAME` which is typically shown in the title bar on TextMate's windows. For a good use of that, let me share a line from my Bash configuration:

    export GIT_EDITOR="mate --name 'Git Commit Message' -w -l 1"

The `-w` and `-l` options have been around for a while. `-w` just tells TextMate to wait for the edit to finish. That's what allows you to use the command as an external editor for tools like Git that are waiting for an answer.

`-l` just tells TextMate to place the caret on the indicated line. I force the first line here because Git has a habit of reusing commit message files and TextMate would otherwise try restore the caret to it's last location. Since that last location was probably at the end of a message that's changed or no longer present, the caret would likely be left in the middle of Git's comments. That's not too helpful for a quick edit, so `-l 1` forces the caret back to the beginning.

That leads us, finally, to the new option used above. Since Git will just use some file like `.git/COMMIT_EDITMSG`, our window isn't going to have the best title by default. This use of `--name` clears that up by telling me exactly what I'm looking at.

## Selection Strings

I mentioned before that TextMate 1's version of `mate` supported `-l`. That's true, but `-l` is far more powerful in TextMate 2 and that new power has spread to other commands.

With the old version of `mate`, `-l` was super simple. It just took a number and it took you to that line. Easy enough.

In the new version, it now takes a Selection String. These are a new tool in TextMate 2 for describing selections. Here's the formal grammar for a Selection String:

    selection    = «range» ('&' «range»)*
    range        = «pos» | «normal_range» | «column_range»
    pos          = «line» (':' «column»)?
    normal_range = «pos» '-' «pos»
    column_range = «pos» 'x' «pos»
    line         = [1-9][0-9]*
    column       = [1-9][0-9]*

OK, geeky, but what does it really mean? Let's look at some examples.

If I save the above grammar to a `selection_string_syntax.txt` file, I can open it with the following command:

    mate -l 3 selection_string_syntax.txt

That would drop my caret (shown as ‸) at the beginning of the third line:

    ‸pos          = «line» (':' «column»)?

If I prefer though, I can control where it is in the line:

    mate -l 3:16 selection_string_syntax.txt

That would place my caret here:

    pos          = ‸«line» (':' «column»)?

Of course, we can also make a selection:

    mate -l 3:32-3:38 selection_string_syntax.txt

That selects (shown between ‸ marks):

    pos          = «line» (':' «‸column‸»)?

But wait, is this TextMate 2 or what? We have Multiple Carets now, dang it! How do we use more than one at once? Like this:

    mate -l '3&6' selection_string_syntax.txt

That places two carets:

    selection    = «range» ('&' «range»)*
    range        = «pos» | «normal_range» | «column_range»
    ‸pos          = «line» (':' «column»)?
    normal_range = «pos» '-' «pos»
    column_range = «pos» 'x' «pos»
    ‸line         = [1-9][0-9]*
    column       = [1-9][0-9]*

You can also make column selections:

    mate -l '4:7x5:13' selection_string_syntax.txt

That gives us:

    normal‸_range‸ = «pos» '-' «pos»
    column‸_range‸ = «pos» 'x' «pos»

Or you can make several unlinked selections using all of the above features:

    mate -l '2:18-2:21&3:1-3:4&4:18x5:21&4:30x5:33' selection_string_syntax.txt

Which selects all occurrences of `pos` for replacement:

    selection    = «range» ('&' «range»)*
    range        = «‸pos‸» | «normal_range» | «column_range»
    ‸pos‸          = «line» (':' «column»)?
    normal_range = «‸pos‸» '-' «‸pos‸»
    column_range = «‸pos‸» 'x' «‸pos‸»
    line         = [1-9][0-9]*
    column       = [1-9][0-9]*

You get the idea.

The best news about these new Selection Strings is that they aren't just for `mate`. You can also use them in the Jump to Line (`⌘L`) and Go to File (`⌘T`) dialogs. For that latter, you just tack a colon (`:`) onto the end of the name matching string then follow it up with a Selection String.

This means that you could respond to a warning message like the following:

    main.cc:32: warning: no return statement.

by selecting `main.cc:32`, copying that to the Find clipboard with `⌘E`, opening TextMate 2, calling up the Go to File dialog with (`⌘T`), and pushing `↩` to go straight there. As this shows, Go to File honors the Find clipboard when it matches this format, just to make things like this easier.

## Remote mate

In the past, TextMate has suffered with editing files on a server, but that's all changed now. If you regularly find yourself SSHed into a remote box and wanting to edit a file using TextMate on your own box, your ship has come in.

TextMate 2 now ships with an `rmate` (Ruby) script that you can drop onto servers. When you trigger `rmate` on a remote box, it will connect back to your box, allow you to edit, and update the file on the server with the changes.

Let me show you how to get `rmate` installed on a server you want edit from remotely.

### Installing rmate

First, we need to copy `rmate` up to your server. You can find a link to the script in the Preferences… dialog of the TextMate menu, under the Terminal pane. Click that link to open the script, then finish the install with these steps:

1. Open a Terminal and type `scp` followed by a space
2. Drag the `rmate` icon out of the window title bar and drop it into your Terminal to fill in the path to the script
3. Add another space and then the server you wish to install the script on followed by a colon (`:`) and the path to install the script into

Your final command should look something like:

    scp /Applications/TextMate.app/Contents/Frameworks/Preferences.framework/Versions/A/Resources/rmate example.com:/usr/local/bin

If you don't have SSH setup to automatically log you into the server, you may also need to provide the proper authentication options. If your user doesn't have permission to copy directly into a the directory you want to install into, you may need to upload the script to your user's home directory, SSH into the remote, and move it into place using `sudo`. Alternately, you could place it in `~/bin` and ensure that directory is in your path.

Back on your own machine, you need to make sure TextMate 2 is ready for the incoming connections. Be sure Accept `rmate` connections is checked in the Terminal pane of Preferences… in the TextMate menu. You can leave "Access for" on "local clients" though, because I'll show you a secure trick for bridging the two computers.

The Terminal Preferences pane

### The Magic of SSH Tunnels

With the install out of the way, you should be ready to use `rmate`.

To do it's job, `rmate` needs a connection back to your computer so that it can talk to TextMate 2. There are multiple ways you can accomplish this, but probably the best way is to use a reverse SSH tunnel. With the proper setup, you can forward the port `rmate` likes back to your local machine where TextMate 2 can answer the call-to-duty.

The easiest way to do this is to connect to your server using a command like:

    ssh -R 52698:localhost:52698 example.com

The `-R` option sets up a reverse tunnel. The first `52698` names a port on the remote. It will be connected to `localhost:52698` or the same port on the connecting box. That port number is the default for TextMate 2 and `rmate`, so you should now be able to edit away.

To test things out, just try a command like:

    rmate test_file.txt

That should contact TextMate 2 on your local box. Note that TextMate 2 does need to be running for this to work.

Type some content using any TextMate editing features you just can't live without and save the file. Then check it on your server with:

    cat test_file.txt

You should see the content you typed on the server. Magic!

If you try to edit a file you don't have permission to change on the server, `rmate` will refuse the edit and warn you:

    $ rmate /etc/crontab
    File /etc/crontab is not writable! Use -f/--force to open anyway.

You can either use the `-f` option to force the open in read-only mode or use `sudo` to get the needed permissions. Remember that `rmate` is a Ruby script, so RVM users will probably need to use `rvmsudo` to keep the same Ruby selected:

    rvmsudo rmate /etc/crontab

After you verify that things are working, feel free to update your SSH setting to automatically setup the tunnel without you needing to supply the `-R` arguments all the time.

For a single server just add an entry like the following to your `~/.ssh/config`:

    Host example.com
    RemoteForward 52698 localhost:52698

If you want to make those settings the default for all of your servers, use the wildcard host:

    Host *
    RemoteForward 52698 localhost:52698

With settings like those in place, a bare `ssh` command (without `-R`) should still establish the tunnel for you and allow you to use `rmate`.

### Port Forwarding

SSH tunneling is probably the lowest configuration option for using `rmate`. It's also the safest since the computers chat over an encrypted connection. Go that way if you can.

However, if you can't, you do have other options. One reason you might need these is if you use multiple machines to connect to the same account on one remote. They wouldn't all be able to use the same port.

Of course, you can specify different ports when you setup TextMate 2 and/or your SSH tunnel. `rmate` also supports `--host` and `--port` options, so you can use those to customize the connection.

One thing you may desire in complex connection scenarios is for `rmate` to just connect back to where the connection came from. You can have it determine the IP address the SSH connection came from using `--host auto`.

You will probably need to setup port forwarding of the desired port in your router's settings to use a connection like this.

The real trick with these connections though is that it's really the client that knows how things should best be handled. Using another feature of SSH, we can have the client set some variables to the proper details and forward those settings to the remote so `rmate` can honor them.

A server whitelists the variables it will accept from connecting clients, so you'll need to edit `/etc/ssh/sshd_config`. It probably already have these lines in it:

    # Allow client to pass locale environment variables
    AcceptEnv LANG LC_*

You need to add allowances for `RMATE_HOST` and `RMATE_PORT`, so change that second line to read:

    AcceptEnv LANG LC_* RMATE_*

You also need a similar entry in your local `~/.ssh/config`:

    Host example.com
    SendEnv RMATE_*

Again, you can put that setting under the host wildcard if you prefer.

Then you can add lines like the following to your local `~/.bashrc`:

    export RMATE_HOST=auto
    export RMATE_PORT=12345

Those settings would be forwarded up to the server when you connect and `rmate` would use them to connect back to your computer for edits.

Either way, it's a little work to get `rmate` setup, but it sure expands TextMate 2 reach once you do. Welcome to remote editing with TextMate.