TextMate — the missing editor for Mac OS X

A lot of functionality in TextMate is provided through various bundles, many of which are language specific.

The default bundles are located in /path/to/TextMate.app/Contents/SharedSupport/Bundles. Normally you do not need to care about this, as you inspect (and edit) the bundles through the bundle editor (which can be reached through the Window menu).

If you select Bundles → Bundle Editor → Show Bundle Editor you will see the command center for customizing TextMate.

From this window you can create and edit things like snippets, commands, language grammars, etc. which will be explained in more detail in the following sections.

Most items edited in the Bundle Editor represent actions you want to execute while editing text. TextMate offers a few ways to do this and has a simple yet powerful system to understand the current context when evaluating which action the activation method should result in, called scope selectors, which is explained in a later chapter.

The easiest way to perform an action (from the keyboard) is in the form of a key equivalent. A key equivalent can be any key with optional modifiers and is configured by activating the key equivalent field and pressing the key to which the item should be bound.

If you want to disassociate a key equivalent with an item, press the X shown while the key equivalent field is in recording mode.

If multiple items are given the same key equivalent then a menu will appear when that key equivalent is pressed, as shown below (all of the items in the Math bundle are bound to ⌃⇧C so a menu with each key equivalent option is displayed).

As well as assigning a single key equivalent to a bundle item, it is possible to assign a tab trigger to the item. This is a sequence of text that you enter in the document and follow it by pressing the tab key (⇥). This will remove the sequence entered and then execute the bundle item.

For example the Text bundle has a snippet which inserts the current date conforming to ISO 8601 (YYYY-MM-DD). The tab trigger for this snippet is isoD (short for ISO Date). In your document it is thus possible to type isoD and press tab to “expand” that to the current date.

This allows you to create much better mnemonics for your bundle items as you can literally type the thing you want to execute (e.g. the snippet to insert). It is generally a good idea to use actual words instead of abbreviations (like use list instead of lst) since the purpose is to make it easier to remember, so the tab trigger should generally be the first thing that pops into your mind in the unabbreviated form.

Tab triggers are rendered in the right side of the menu item with a slightly rounded rectangle as background and the tab character (⇥) shown as a suffix to the tab trigger.

Tab triggers are also useful when they match program keywords and lead to actions (such as inserting snippets) that do what you would normally do after entering the keyword. For example in Ruby a method starts with def so creating a snippet for a Ruby method and assigning it def as tab trigger gives a natural flow, as you would write def as usual and then use tab instead of taking the normal actions. Had the tab trigger for a method (in Ruby) instead been method or similar, it means you would have to remember “I can insert a snippet for this” before typing def, whereas with def as the tab trigger, you have to remember it before pressing the space after def (basically just pressing tab instead of space).

As with key equivalents, entering a tab trigger and pressing tab will show a menu, when multiple items share the same tab trigger. This can be used to provide a simple form of code-completion, for example in CSS the tab trigger list has been assigned to all properties that start with list. So in CSS typing list followed by tab will give a useful menu from where you can pick what list property needs to be inserted.

Some of the default items may not be to your exact liking, for example the coding style in snippets may differ from yours, so you may want other tab triggers, key equivalents, or similar modifications.

If you edit a default item the difference will be stored in ~/Library/Application Support/TextMate/Bundles. These are then merged with the default version so your changes will be effective even after upgrading TextMate. All new items you create also end up in this location.

Bundles or bundle items which you install by dragging them to TextMate or double clicking will be installed in ~/Library/Application Support/TextMate/Pristine Copy/Bundles. Editing these will also result in only the differences being stored in ~/Library/Application Support/TextMate/Bundles, meaning that if you later get a new version of this third party bundle, you can safely install this one on top of the old one (by dragging it to TextMate) and again your changes will be preserved.

If you want to discard local changes then currently the only option is to delete these from ~/Library/Application Support/TextMate/Bundles.

You can also transparently delete default bundles and bundle items from the bundle editor. However, since the items are shipped with the TextMate application, they are not removed on disk, since they would then reappear after an upgrade.

Instead each bundle has an info.plist file which keeps the ordering of bundle items and also stores which of the default items should act as if they have been deleted. When you change the ordering of items in a default bundle or delete items, this file is copied to ~/Library/Application Support/TextMate/Bundles/«bundle name».tmbundle and will contain this info.

If you delete an entire bundle the information is recorded in TextMate’s preferences. You can get a list of which default bundles have been deleted by running the following line in terminal:

defaults read com.macromates.textmate OakBundleManagerDeletedBundles

To reset the list of deleted bundles (i.e. undelete them) instead run this (while TextMate is not running):

This may all sound a little complicated, but generally you should not care about these details. Just use the bundle editor to create, edit and delete your items and bundles and it should work as expected.

Often a bundle will provide support for a particular language (though there are exceptions like the Source, Text and TextMate bundles). To get a good idea of what features the bundle provides, it is best to investigate it in the bundle editor (accessible from the Windows menu). When appropriate, a language bundle should provide the following, with key bindings as shown:

Run (⌘R) — run the current source (script) or product from building a project.

Documentation for Word (⌃H) — lookup the current word (or “unit”) in the documentation (often online).

Validate Syntax (⌃⇧V) — run the syntax through whatever form of syntax checker exist for the current document type. Generally show errors as a tool tip, but for more complex validation, HTML output is sometimes used.

Wrap in «Something» (⌃⇧W) — wrap the selection in what makes sense for the current document type, e.g. open/close tags in HTML, begin/end environment in LaTeX.

Convert to «Something» (⌃⇧H) — convert the document into something which makes sense, e.g. for HTML run it through tidy, for Markdown convert it to HTML, for an XML property list convert it to the more readable ASCII version, etc. Generally this is done in-place, overwriting the current document.

Continue «Something» (⌅) — continue the current construct on the next line e.g. a line comment, list item or similar.

Preview Document (⌃⌥⌘P) — by default this opens the Web Preview, but it has been overloaded for some markup languages for a preview more suited for that language (i.e. doing the HTML conversion and setting up a basic style sheet before showing it).

Insert Close Element (⌥⌘.) — by default this inserts the appropriate closing tag (HTML) but is overloaded in some contexts to insert whatever constitutes a close element (e.g. \end{environment} in LaTeX).

Comment Toggle (⌘/) — toggle comment characters around the current line or selection.

Many bundles also have a Help command with some details about how to use and customize its functionality.

Bundle actions can be accessed through the gear pop-up in the status bar. This menu can also be brought up by pressing ⌃⎋.

You can show the differences between two files in TextMate by running the following command from your terminal:

diff -u old_file new_file|mate

The bundle also has commands to show the differences between the current document and the saved copy, between the selected files in the project drawer (with an HTML output option) and it has a command to open the selected files in Apple's FileMerge using opendiff (requires the developer tools to be installed).

The HTML bundle contains useful stuff for working with HTML. A few particularly useful actions are:

Insert Open/Close Tag (⌃<) — this command will take the word just typed and change it into <word></word> placing the caret in the middle. It will recognize those tags where a close tag is not allowed (like hr) and instead insert <word> placing the caret after the tag.

Wrap Selection in Open/Close Tag (⌃⇧W) — this will put <p>…</p> around the selection but allows you to overtype the p (and add arguments). After you are done, press tab to move the caret past the </p> tag.

Wrap Selection as Link (⌃⇧L) — this turns the selection into link text for an anchor where you can then fill in the URL.

The HTML bundle also has a drag command for images which insert the dropped image with proper dimensions (width/height) and an alternative text derived from the file name.

A lot of actions in the HTML bundle will cause tags to be inserted. E.g. pressing ⌃↩ inserts <br>, dropping an image on a HTML document inserts <img …>, etc.

If you want tags with an EMPTY content model to use the minimized (XHTML) form (that is <br /> instead of <br>) then in Preferences → Advanced create a new variable named TM_XHTML and set it to ‘ /’ (the value of this variable will be inserted before the > in the generated tags with EMPTY content model).

Typeset & View (PDF) (⌘B) — this will run pdflatex on your current file, or TM_LATEX_MASTER (if that variable is set). If there were errors, these are shown as clickable links, otherwise the resulting PDF will be shown in the HTML output (requires Tiger or Schubert’s PDF Browser PlugIn).

Insert Environment Based on Current Word (⌘{) — this mimics the HTML bundles ⌃< in that it makes the current word into \begin{word} … \end{word} and places the caret in between. There are various configuration options for this command, for details see the Help command in the LaTeX bundle or the source for the command itself (via the Bundle Editor).

Insert Command Based on Current Word (⌘}) — like the previous command, but makes word into \word{} with the caret inside the braces.

The source bundle contains default actions and preferences for source code. Of interest is the Comment Line / Selection (⌘/) which will toggle the comment characters for the current line or selection. This command is setup for different languages via three context dependent variables.

The various macros to go to end-of-line and insert the line terminator character (; by default) and/or a newline are also rather useful.

The TextMate bundle is kind of a meta bundle. That means none of the actions are for text editing but are instead intended for creating new bundle items, searching the mailing list archive, pasting the current selection to an IRC channel or similar.

The Xcode bundle has actions to build the Xcode project located in the folder that contains the current document or project and to run the resulting target.

It also has commands to import an Xcode project but generally it is better to drag the folder with your Xcode project to the TextMate application icon, since currently the TM_PROJECT_DIRECTORY variable is not correctly setup for imported projects and a lot of bundle actions rely on this (e.g. the Subversion stuff).

Only the most popular bundles are included with TextMate. There is a subversion repository which has dozens of other bundles mostly adding support for various languages. You can see the list of bundles here.

When you have svn installed it is relatively easy to either checkout or export a bundle. TextMate searches for bundles in all the usual library locations, so if you have the rights to do so (on your machine) it is recommended that you perform all checkouts to /Library instead of ~/Library, since this then keeps installed bundles separate from custom bundles (or bundles you have edited).

As an example, to install the Haskell bundle, first create the install directory, then change to it and ask svn to check it out:

Included with TextMate is a support folder which contains miscellaneous support items used by various bundle items. This folder is reachable via the TM_SUPPORT_PATHenvironment variable and would normally point to /Applications/TextMate.app/Contents/SharedSupport/Support.

If you checkout a bundle from the subversion repository then this bundle may rely on a newer version of the support folder than the one included with TextMate. If this is the case, you will need to also checkout a local copy of the support folder.

The process is similar to checking out a bundle, first ensure you have LC_CTYPE setup properly and then execute the following in your shell:

After this you can test it by pasting the following line into TextMate and pressing ⌃R (to execute it):

echo "$TM_SUPPORT_PATH"

It should result in the following output:

/Library/Application Support/TextMate/Support

The support folder contains a version file (named version) so rather than pick the most local version of the support folder, TextMate will choose the one with the highest version. This means that if you do checkout a local copy of the support folder and later update TextMate, your local (potentially outdated) copy will not eclipse the default one.