1. 1 Preface
    1. 1.1 About the Documentation
    2. 1.2 Philosophy of TextMate
    3. 1.3 Terminology
    4. 1.4 Limitations
  2. 2 Working With Multiple Files
    1. 2.1 Creating Projects (With Tabs)
      1. 2.1.1 Auto-Updating Projects
      2. 2.1.2 Filtering Unwanted Files
      3. 2.1.3 Text and Binary Files
      4. 2.1.4 Positioning the Project Drawer
    2. 2.2 Find and Replace in Projects
    3. 2.3 Moving Between Files (With Grace)
  3. 3 Navigation / Overview
    1. 3.1 Bookmarks
    2. 3.2 Collapsing Text Blocks (Foldings)
      1. 3.2.1 Customizing Foldings
    3. 3.3 Function Pop-up
      1. 3.3.1 Customizing the List
  4. 4 Working With Text
    1. 4.1 Auto-Paired Characters (Quotes etc.)
    2. 4.2 Completion
    3. 4.3 Copy and Paste
      1. 4.3.1 Clipboard History
      2. 4.3.2 Re-indented Paste
    4. 4.4 Editing Modes
      1. 4.4.1 Freehanded Editing
      2. 4.4.2 Overwrite Mode
    5. 4.5 Find and Replace
      1. 4.5.1 Inserting Newlines and Tabs in the Find Dialog
      2. 4.5.2 Find Clipboard
    6. 4.6 Moving Text
      1. 4.6.1 Increase/Decrease Indent Level
      2. 4.6.2 Move Text Up/Down/Left/Right
      3. 4.6.3 Re-indent Text
    7. 4.7 Selecting Text
      1. 4.7.1 Editing Multiple Lines
      2. 4.7.2 Column Selections
    8. 4.8 Column Movement / Typing
    9. 4.9 Smart Tab Behavior
    10. 4.10 Spell Checking
    11. 4.11 Using Spaces Instead of Tabs
  5. 5 Bundles
    1. 5.1 Activation of Bundle Items
      1. 5.1.1 Key Equivalents
      2. 5.1.2 Tab Triggers
    2. 5.2 Editing Default Bundles / Items
    3. 5.3 Deleting Default Bundles / Items
    4. 5.4 Hiding Bundles
    5. 5.5 Sharing Bundles and Bundle Items
    6. 5.6 Assorted Bundles
      1. 5.6.1 Diff
      2. 5.6.2 HTML
      3. 5.6.3 LaTeX
      4. 5.6.4 Source
      5. 5.6.5 SQL
      6. 5.6.6 Subversion
      7. 5.6.7 Text
      8. 5.6.8 TextMate
      9. 5.6.9 Xcode
    7. 5.7 Getting More Bundles
      1. 5.7.1 Installing Subversion
      2. 5.7.2 Setting LC_CTYPE
      3. 5.7.3 Installing a Bundle
      4. 5.7.4 Support Folder
      5. 5.7.5 RSS Feed With Bundle Change Log
  6. 6 Macros
  7. 7 Snippets
    1. 7.1 Plain Text
    2. 7.2 Variables
    3. 7.3 Interpolated Shell Code
    4. 7.4 Tab Stops
    5. 7.5 Placeholders
    6. 7.6 Mirrors
    7. 7.7 Transformations
  8. 8 Shell Commands
    1. 8.1 Executing Commands / Filtering Text
    2. 8.2 Search Path
  9. 9 Environment Variables
    1. 9.1 Dynamic Variables
    2. 9.2 Static Variables
    3. 9.3 Context Dependent Variables
    4. 9.4 Project Dependent Variables
  10. 10 Commands
    1. 10.1 Command Input
    2. 10.2 Command Output
    3. 10.3 HTML Output
    4. 10.4 Changing Output Type
    5. 10.5 Useful bash Functions
    6. 10.6 Dialogs (Requesting Input & Showing Progress)
  11. 11 Drag Commands
  12. 12 Language Grammars
    1. 12.1 Example Grammar
    2. 12.2 Language Rules
    3. 12.3 Rule Keys
    4. 12.4 Naming Conventions
  13. 13 Scope Selectors
    1. 13.1 Element Names
    2. 13.2 Descendant Selectors
    3. 13.3 Excluding Elements
    4. 13.4 Grouping
    5. 13.5 Ranking Matches
  14. 14 Themes
    1. 14.1 Sharing
  15. 15 Preferences Items
    1. 15.1 Completions
    2. 15.2 Indentation
    3. 15.3 Symbol List
    4. 15.4 Paired Characters
    5. 15.5 Other
  16. 16 Key Bindings
    1. 16.1 Bundle Items
    2. 16.2 Menu Items
    3. 16.3 Text Move / Edit Actions
      1. 16.3.1 List of Standard Key Bindings
    4. 16.4 Conventions
  17. 17 Templates
  18. 18 Printing
  19. 19 Saving Files
    1. 19.1 Atomic Saves
    2. 19.2 Creator Code
    3. 19.3 Encoding
    4. 19.4 Extended Attributes (Metadata)
    5. 19.5 Save Automatically when Focus Is Lost
  20. 20 Regular Expressions
    1. 20.1 Introduction
      1. 20.1.1 External Resources
    2. 20.2 Regular Expressions in TextMate
    3. 20.3 Syntax (Oniguruma)
    4. 20.4 Replacement String Syntax (Format Strings)
      1. 20.4.1 Captures
      2. 20.4.2 Case Foldings
      3. 20.4.3 Conditional Insertions
      4. 20.4.4 Escape Codes
  21. 21 Calling TextMate from Other Applications
    1. 21.1 Shell / Terminal
      1. 21.1.1 The General EDITOR Variable
      2. 21.1.2 Git Editor
      3. 21.1.3 TeX Editor
      4. 21.1.4 Edit from less
    2. 21.2 URL Scheme (HTML)
    3. 21.3 ODB Editor Suite
    4. 21.4 Cocoa Text Fields
  22. 22 Expert Preferences
    1. 22.1 NSDragAndDropTextDelay
    2. 22.2 NSRecentDocumentsLimit
    3. 22.3 OakBundleItemsPopUpMenuKeyEquivalent
    4. 22.4 OakBundleManagerDisambiguateMenuFontSize
    5. 22.5 OakDefaultBundleForNewBundleItems
    6. 22.6 OakDefaultLanguage
    7. 22.7 OakDisableSessionRestore
    8. 22.8 OakDocumentCustomFSMetaData
    9. 22.9 OakDocumentDisableFSMetaData
    10. 22.10 OakFindPanelDisableHistory
    11. 22.11 OakToolTipMouseMoveIgnorePeriod and OakToolTipMouseDistanceThreshold
    12. 22.12 OakWrapColumns
    13. 22.13 OakWordsExcludedFromCapitalization
  23. 23 Getting Help
    1. 23.1 Mailing List
    2. 23.2 IRC Channel
    3. 23.3 Other Resources
      1. 23.3.1 TextMate Cheat Sheet
      2. 23.3.2 TextMate Tutorials
      3. 23.3.3 Screencasts
  24. 24 Appendix
    1. 24.1 Property List Format
      1. 24.1.1 Strings
      2. 24.1.2 Arrays
      3. 24.1.3 Dictionaries
    2. 24.2 Indentation Rules
      1. 24.2.1 Introduction
      2. 24.2.2 The System
      3. 24.2.3 Increase Pattern
      4. 24.2.4 Decrease Pattern
      5. 24.2.5 Increase Only Next Line
      6. 24.2.6 Ignoring Lines
    3. 24.3 Plug-in API

1 Preface

1.1 About the Documentation

The intended purpose of the documentation is to explain the main features of TextMate and to highlight features that may not be obvious to first time users. The documentation is not exhaustive.

You should have a good understanding of what a text editor is, in particular you should have some experience with Cocoa's text edit control (used in TextEdit, Mail and Xcode). While TextMate does not use that control, it does mimic its behavior for the most part.

If you want to print this documentation then here is a printable version.

1.2 Philosophy of TextMate

From UNIX we get that Tasks and Trends Change. In concrete terms this means that instead of writing a command (in UNIX) to solve the problem at hand, we find the underlying pattern, write a command to solve problems of that type and then use that command in a script.

This gives us a command which we can re-use in the future for multiple problems of the same type. Since it is generally much easier (and more flexible) to piece together a script of different commands than it is to write a specific command the increase in productivity can be very large. This is especially true since we do not actually write the command in the first place, we use an existing command that has already been written for this type of problem.

There are two ways in which TextMate leverages that philosophy. First it has good shell integration, so if you are skilled in using the UNIX shell, you should love TextMate.

But more ambitiously, TextMate tries to find the underlying patterns behind automating the tedious, being smart about what to do and then to provide you with the functionality so that you can combine it for your particular needs.

Granted, TextMate is not the first text editor which tries to be broad, but from Apple we get the venerable Keep It Simple. So even users with little or no experience with scripting and regular expressions are able to customize TextMate in ways that no other editor would have allowed them to.

Having said that, the philosophy of TextMate is also to Educate the User. So to fully capitalize on what TextMate gives you, you should learn about regular expressions, you should understand TextMate's scope, snippet system (also language grammars to some degree) and have an idea about the shell infrastructure provided (in particular environment variables, pipes and stdin/stdout).

1.3 Terminology

For the most part TextMate and this documentation abides by Apples terminology. Below is a table of terms that might be a source of misunderstanding.

Term Explanation

Caret

The text insertion point.

Cursor

Mouse pointer.

Document

This refers to a file when it is loaded into TextMate (for the purpose of being edited). Old-timers often refer to this as the buffer.

Directory

This is sometimes used instead of folder. Folder is mainly used when talking about the GUI and directory is used when talking about shell related things.

Generally TextMate and this documentation use the glyph representation of a key. Below is a table with most glyphs, the name of the key (as used in this documentation) and a short explanation.

Keyboard Viewer

If you are unsure about the location of a key, you can bring up the Keyboard Viewer, which you can add to the Input menu in the International pane of System Preferences.

Glyph Key Name Explanation

Control

This key is generally in the lower left corner of the keyboard (and symmetrically placed on the right side). In addition to key equivalents, this key is also used with a mouse click to bring up context sensitive menus.

Option

This is next to the control key and often bears the label Alt. You can hold down the option key while dragging with the mouse to select text rectangularly. It is also possible to place the caret beyond the end of a line by single-clicking the mouse while holding the down option key (⌥). Together with Shift, the option key does a (rectangular) selection to where you click.

Command

The command key is also referred to as the Apple key since it has an apple symbol on it ().

Shift

The Shift key should be well-known. When used together with a mouse click, it extends the selection.

Escape

The escape key is generally in the upper left corner of the keyboard. This key can be used to dismiss (cancel) panels, which means dialogs and some (but not all) windows. In TextMate it is also used to cycle through completion candidates.

Enter

The enter key is on the numeric keypad (and is not the same as return). On laptops it is fn-return.

Return

The return key should be well known.

Forward Delete

This is often just called delete and on the keyboard has a label of Del or Delete.

Backward Delete

Often called backspace. On most keyboards this has a left pointing arrow on the key (←).

﹖⃝

Help

The Help key is located above Forward Delete, but not all keyboards have it. Generally it has the word Help on the key, but it is also known as the Ins key.

Home

The Home key scrolls to the beginning of the document, but does not move the caret.

End

The End key scrolls to the end of the document, but does not move the caret.

Page Up

Scrolls up a page without moving the caret. Using the option key will cause the caret to be moved. When used with Shift it will create a selection.

Page Down

Scrolls down a page without moving the caret. Using the option key will cause the caret to be moved. When used with Shift it will create a selection.

Tab

The Tab key is used to insert a tab character (or equivalent amount of spaces if soft tabs are enabled). In normal controls it advances the focus to the next control.

Back-tab

The Back-tab key can be used by holding down Shift while pressing the normal Tab key.

1.4 Limitations

TextMate is a work-in-progress. One current key limitation (for non-Western users) is support for international input modes (e.g. CJK), proportional fonts, right-to-left text rendering and other (UniCode) features. As the author, I do understand the desire from users to have TextMate support these things, but currently proper support for this is a long-term to-do item.

And on the topic of limitations, I am also aware of the desire for (s)ftp integration, code hinting, split views, better printing, indented soft wrap, coffee making and literally hundreds of other user requests. You will be able to find my comments on most feature requests by searching the mailing list archive, but I do not give estimates or timeframes, other than what version number I plan for something to appear in.

2 Working With Multiple Files

2.1 Creating Projects (With Tabs)

In the current version of TextMate (1.5) file tabs are only supported when a project is created. Fortunately it is easy to create a project, namely by selecting File → New Project (⌃⌘N).

This opens a window which looks like the one below.

Project Window

It is possible to add files either by dragging them to the (project) drawer, or use the “Add Existing Files…” action in the project drawers action menu (the one with the gear icon).

Another way to create a project is by dragging files directly onto the TextMate application icon (shown e.g. in the dock). This is a shortcut for creating a new project consisting of these files.

One minor detail is that when creating a project this way, you will not be asked if you want to save the project, when it is closed.

The advantage of saving a project is to maintain state (e.g. which files were open) and to be able to quickly re-open a particular set of files. If you leave a (saved) project open when you quit TextMate, it will automatically re-open that project the next time you launch TextMate.

It is also possible to create projects from the terminal e.g. using the mate shell command.

2.1.1 Auto-Updating Projects

When you want to have your project mimic the files and folders on disk, you can drag a folder either onto the TextMate application icon, or into the project drawer.

TextMate will then create a folder reference where it automatically updates the contents of the folder when it changes on disk.

Project Window With Tabs

Currently updating is done when TextMate regains focus and can be slow for some network mounted disks, in which case you may want to settle for only adding individual files to the project (which can be grouped and re-ordered manually to mimic the structure on disk).

The refresh delay for network mounted disks will be addressed in a future release.

2.1.2 Filtering Unwanted Files

When using folder references, you may want to have certain files or folders excluded from the project. This can be done by changing the file and folder patterns found in Preferences → Advanced → Folder References.

Folder Reference Patterns

These are regular expressions which are matched against the full path of each file and folder. If the pattern does match the item, it is included, otherwise it is excluded. To reverse that, so that items which match are excluded from the project, prefix the pattern with an exclamation point (!).

The patterns are only used when creating new folder references. For existing folder references one can select the folder reference in the project drawer and use the info button (a circled letter I) in the project drawer to edit the patterns.

The complexity of this system will be addressed in a future release.

2.1.3 Text and Binary Files

You can either single or double click files in the project drawer. If you single click them and the file type is text, they open as a file tab in the main window.

Tab Bar

If you double click a file, it will open using the default application. Note that folders can also be double clicked e.g. Interface Builder’s nib files will appear as folders, but can still be double clicked (and will then open in Interface Builder).

As mentioned, only text files will open in the main window when single clicked. The way TextMate determines if a file is text is by its extension - if the extension is unknown it scans the first 8 KB of the file to see if it is valid UTF-8 (which is a superset of ASCII).

If TextMate does not open your file and it does have an extension you can bring up the action menu for that file and pick the last item, which should read: Treat Files With “.«ext»” Extension as Text.

2.1.4 Positioning the Project Drawer

The project drawer will by default open on the left side of the project window. If there is no room for it to open there, it will use the right side instead. This setting is sticky so will remember which side the project drawer was last opened on.

Project Drawer

To move it back to the left side you need to close the drawer (View → Hide Project Drawer) and then move the project window so that there is no longer room for the drawer on its right. When you then re-open the drawer, it will again appear on the left side and use that as the new default.

The opposite can be done to force it to open on the right side.

2.2 Find and Replace in Projects

Using Edit → Find → Find in Project… (⇧⌘F) will bring up the window shown below.

Find In Project

From here it is possible to search all (text) files in the current project and do replacements. After pressing Find it is possible to either press Replace All, or select which matches should be replaced, in which case the Replace All button will change to Replace Selected.

Currently it is not possible to limit the scope of the search to anything other than all text files in the full project. As a workaround, when you want to search only a subset of your project, you can select the files you want to search in the project drawer and drag the selection to the TextMate application icon to create a new scratch project. A find/replace can then be performed on that project, which can then be closed.

2.3 Moving Between Files (With Grace)

When working with projects there are a few ways to move between the open files.

The most straightforward way is by clicking on the file tab you need. This can also be done from the keyboard by pressing ⌘1-9, which will switch to file tab 1-9.

You can also use ⌥⌘← and ⌥⌘→ to select the file tab to the left or right of the current one.

It is possible to re-arrange the file tabs by using the mouse to drag-sort them (click and hold the mouse button on a tab and then drag it to the new location). This should make it possible to arrange them so that keyboard switching is more natural.

One more key is ⌥⌘↑ which cycles through text files with the same base name as the current file. This is mainly useful when working with languages which have an interface file (header) and implementation file (source).

When you want to move to a file which is not open you can use the Go to File… action in the Navigation menu (bound to ⌘T). This opens a window like the one shown below.

Go To File

This window lists all text files in the project sorted by last use, which means pressing return will open (or go to) the last file you worked on. So using it this way makes for easy switching to the most recently used file.

You can enter a filter string to narrow down the number of files shown. This filter string is matched against the filenames as an abbreviation and the files are sorted according to how well they match the given abbreviation. For example in the picture above the filter string is otv and TextMate determines that OakTextView.h is the best match for that (by placing it at the top).

The file I want is OakTextView.mm which ranks as #2. But since I have already corrected it in the past, TextMate has learned that this is the match that should go together with the otv filter string, i.e. it is adaptive and learns from your usage patterns.

3 Navigation / Overview

3.1 Bookmarks

If you need to move the caret to somewhere else in your document and want a quick way to return, you can place a bookmark on the current line.

This is done either by clicking in the gutter (in the column dedicated to bookmarks) or pressing ⌘F2. The bookmark will be indicated with a star as shown below.

Bookmark

When you want to return you can press F2, which moves you to the next bookmark in the document. If there is more than one bookmark, you can press F2 repeatedly. ⇧F2 will move to previous bookmark.

3.2 Collapsing Text Blocks (Foldings)

When working in a language which has start/end markers for blocks, like {}, doend, <tag></tag> and similar, TextMate can spot these blocks and will show up/down arrows in the gutter beside the start/end marker.

When these arrows are present, it is possible to fold the block into a single line either by using the mouse and clicking on the up/down arrow, or pressing the F1 key. This will make the arrow in the gutter point to the right and indicate that the entire block was folded by placing an ellipsis marker at the end of the line. An example where the two sub-blocks of the constructor has been folded can be seen below.

Folded Blocks

With text folded, it is possible to unfold it with F1 or clicking either the arrow in the gutter or the ellipsis image. It is also possible to hover the mouse pointer on the ellipsis image to get a tool tip which shows the contents of the folded block. The latter is shown on the following picture.

Folding Tool Tip

A word of caution: the folding system is based on both having clear indent markers and having the fold start/stop markers use the same indent level. This means that folding based purely on indent or where the start/stop markers do not align, is currently not supported.

3.2.1 Customizing Foldings

As mentioned the folding system uses explicitly defined start and stop markers. TextMate knows about these from the language grammar where you can setup a foldingStartMarker and foldingStopMarker regular expression.

Folding Patterns

Shown above are the HTML folding patterns, which are all relatively simple because they fold on a selected set of tag pairs, HTML comments, some Smarty tags and start/stop braces when either last on the line or used in embedded code tags like this:

<?php if(something) { // user is authenticated ?>

   ...

<?php } // user is authenticated ?>

To define a block that starts with { as the last non-space character on the line and stops with } as the first non-space character on the line, we can use the following patterns:

foldingStartMarker = '\{\s*$';
foldingStopMarker = '^\s*\}';

3.3 Function Pop-up

For languages that support it, the rightmost pop-up in the status bar shows the current “symbol” (often the function prototype or heading above the caret).

Status Bar

It is possible to click on the pop-up to get a list of all the symbols in the current document and move the caret to one of these. This is shown below.

Function Pop Up

For keyboard navigation there is also Navigation → Go to Symbol… (⇧⌘T) which opens a panel like the one shown below. The contents of this pane are the same as the pop-up from the status bar but this panel supports filtering similar to the Go to File… panel (i.e. where the filter string is treated as an abbreviation and matches are ranked according to how good a fit the abbreviation seems to be).

Symbol List

The panel can be left open and will automatically update as the document is edited. If you single-click an item in the list, the caret will move to the symbol clicked. Double-clicking will do the same but also closes the panel.

3.3.1 Customizing the List

The symbol list works using language grammars and scope selectors. A language grammar assigns names to each element in the document and a scope selector is capable of targeting a subset of the document based on these names. Normally the parallel is HTML and CSS, e.g. we can make a theme item which sets the background to blue and then use the scope selector to pick which elements in our document we want this theme (and hence the blue background) applied to.

Bundle preferences work like theme items, except that instead of changing visual settings they (generally) change non-visual settings. One exception is the showInSymbolList. By setting this to 1 and using a scope selector which (for example) targets all function names, we are using that scope selector as a query to extract all the function names from the document, for use in the symbol list.

So to populate the symbol list we need to:

  1. Make sure the language grammar assigns a name to what we want to show.

  2. Create a bundle preferences item that sets showInSymbolList to 1 and uses a scope selector that matches the symbols we want to have in the symbol list.

In addition to the showInSymbolList setting there is a symbolTransformation setting which is one or more regular expression substitutions which are performed on the text extracted. The value of this setting should be: s/«regexp»/«format»/«options» optionally followed by ; and more substitutions. It is also possible to put comments in the value, these start with # and end at the next newline.

So if we want to show Markdown headings in the list, which are lines that start with one or more # marks, then we first make sure our language grammar assigns a name to these, for Markdown that can be identified with this rule, by specifying the following in the language grammar:

{  name = 'markup.heading.markdown';
   match = '^#{1,9}\s*(.*)$';
},

Now we can target all headings using a scope selector of markup.heading.markdown. We can now create a bundle preferences item that is simply:

{  showInSymbolList = 1;   }

This will include the leading # marks in the list, which is undesirable. We can either assign a name (via the language grammar) to the actual title, or we can perform a regular expression substitution to get rid of the leading # marks. The latter has the advantage that we can change these to indent, so that is what we do, by changing the preferences item to:

{  showInSymbolList = 1;
   symbolTransformation = '
      s/(?<=#)#/ /g;          # change all but first # to m-space
      s/^#( *)\s+(.*)/$1$2/;  # strip first # and space before title
   ';
}

4 Working With Text

TextMate tries for the most part to mimic the behavior of the NSTextView system component, as used by applications such as Mail, Safari and basically all other Cocoa applications.

Some of the extra features related to text editing are covered in this section.

4.1 Auto-Paired Characters (Quotes etc.)

When writing structured text (like markup or source code) there are characters which go together in pairs. For example in a programming language you rarely type an opening brace ({) without also needing the closing brace (}).

To help you keep these characters balanced, TextMate will insert the appropriate closing character after the caret when you type the opening one. If you type the closing character TextMate is smart enough to overwrite the auto-inserted one. If you type an opening character and then delete it using backward delete (⌫) then the auto-inserted character will also be deleted. If you only want to delete the auto-inserted character, use forward delete instead (⌦).

It is also possible to wrap a selection in an open/close character by selecting text and typing the opening character. For example if you type foo, select it and type ( then TextMate will make it (foo) placing the caret after the ending parentheses.

The actual character pairs are defined in the bundle preferences with different settings for different languages and contexts. For example, in source code an apostrophe is set up to have itself as a closing character, except for comments and strings. This is achieved using scope selectors.

Two useful shortcuts in relation to auto-paired characters (defined as macros in the Source bundle and overridden for a few languages) are:

  1. ⌘↩
    Move to the end of the line and insert a newline.
    For example if you write:

    print("foo
    

    Then you will have ") to the right of the caret and can now use ⌘↩ to skip these two characters and insert a new line.

  2. ⇧⌘↩
    Move to the end of the line, insert a ; and then insert a newline.

4.2 Completion

TextMate has a simple yet effective completion function on ⎋ (escape). It will complete the current word based on matches in the current document. If there are multiple matches, you can cycle through these by pressing ⎋ continuously. It is also possible to cycle backwards using ⇧⎋.

The matches are sorted by distance from the caret, meaning candidates which are closer to the caret will be suggested before candidates farther away.

Two possibilities exist for augmenting this default completion. Both are done via bundle preferences.

The first option is to provide a list of candidates which should always be suggested. For example the Objective-C bundle has a list of commonly used Cocoa framework methods. This is an array of the candidates, e.g.:

completions = ( 'retain', 'release', 'autorelease', 'description' );

The other option is to set a custom shell command to gather the completions. The shell command will have the TM_CURRENT_WORD environment variable available (as the word which needs to be completed) along with the other variables.

For example the C bundle has a custom completion command setup for when the caret is inside the preprocessor include directive, it looks like this:

completionCommand = 'find "$TM_DIRECTORY" \
    -name "$TM_CURRENT_WORD*.h" -maxdepth 2 \
    -exec basename "{}" \;|sort';

This will find as matches, any file in the current directory (and direct sub-directories) which have the current word as prefix and an .h extension.

When you provide your own completion command (or list) you may want to disable the default matches. This can be done by setting disableDefaultCompletion to 1.

4.3 Copy and Paste

4.3.1 Clipboard History

Each time you copy or cut text, the text is pushed onto a stack.

By pressing ⌃⌥⌘V you will see the list of all previous clippings and can pick the one you want to paste using arrow keys. Use return to insert it and escape to dismiss the list. If you dismiss the list, the currently selected clipping will be what gets pasted the next time you use the paste function.

Clipboard History

Instead of having to pick the clip from the list, you can use ⇧⌘V to paste the previous clip in the list. Using that key again will advance to the clip before that and so on. To go back you can use ⌥⌘V. These key equivalents are useful when you want to make multiple copies from one document and then paste these LIFO-style (Last In First Out) into another document (or another location in the same document).

4.3.2 Re-indented Paste

When pasting text, TextMate will estimate the indent of the text pasted as well as the current indent level and adjust the pasted text so that it matches the current indent.

The estimates are done using the indentation rules mentioned in the Re-Indent Text section.

If you temporarily want to avoid this you can paste text using ⌃⌘V. You can also permanently disable re-indented pasting in the Text Editing part of the Preferences.

4.4 Editing Modes

4.4.1 Freehanded Editing

You can enable or disable freehanded editing in the Edit → Mode submenu (⌥⌘E).

With this mode enabled caret movement will not be restricted by line endings or tab stops.

This is useful when working with ASCII diagrams, when inserting something at a given column on several lines (and you do not want to insert the padding) and in a few other situations.

When making column selections freehanded mode is (temporarily) enabled, allowing you to make selections past the end of lines.

It is also possible to place the caret beyond the end of a line by single-clicking the mouse while holding down the option key (⌥).

4.4.2 Overwrite Mode

By enabling overwrite mode in the Edit → Mode submenu (⌥⌘O) characters already in the document will be overwritten as you type rather than inserted as normal.

This is useful when working with column data, e.g.:

foo     jaz
bar     sub
fud     dub

Imagine we want to overwrite some of the values in the first column. Somewhat similarly, we may have a line of a fixed width and want to replace part of it but preserve the width, for example we could have code like this where we must right-align the value to column 20 but want to overwrite the label:

printf("Value is         %3d", 37).

4.5 Find and Replace

In addition to the standard find dialog, TextMate has a Find submenu (located in the Edit menu) which gives you key equivalents for find and replace actions.

Find Menu

4.5.1 Inserting Newlines and Tabs in the Find Dialog

The find dialog uses normal system controls for accepting input. You can toggle between single line and multi line text controls using the arrow next to the Replace text field.

Multi Line Find Dialog

If you need to insert a newline or tab character into either of the text fields, you can hold down option (⌥) while pressing the tab (⇥) or return (↩) key. This will insert a literal tab or newline character.

4.5.2 Find Clipboard

Two useful key equivalents are ⌘E and ⌘G. The first copies the selection to the shared find clipboard. This works in the majority of applications and allows you to find the next occurrence of that string by then pressing ⌘G.

The find clipboard works across applications so whether in Safari, TextEdit, Mail, TextMate, Terminal, Console, or similar, one can copy the selected text to the find clipboard, switch application and use ⌘G to find that string.

In addition TextMate offers ⇧⌘E to copy the selection to the replace clipboard. This is often useful to save a trip to the find dialog, for example if you want to replace newlines with the pipe character (|) for a list of items, select a newline, press ⌘E to use that as the find string. Now type a |, select it and press ⇧⌘E so that it is copied to the replace clipboard.

The next step is then to either press ⌃⌘F to perform the replacement in the entire document, or select the range in which you want the replacement to occur and use ⌃⇧⌘F instead.

4.6 Moving Text

4.6.1 Increase/Decrease Indent Level

In the Text menu there is a Shift Left and Shift Right action bound to ⌘[ and ⌘]. These will increase and decrease the indent by the size of one tab.

On many european key layouts these keys are rather awkward, so in addition to these, you can also use ⌥⇥ and ⌥⇤ (where ⇤ is achieved using ⇧⇥).

4.6.2 Move Text Up/Down/Left/Right

If you want to move a line/block up/down a few lines or move a word/column selection, it can be done by holding down ⌃⌘ and using the arrow keys to move the selection around. It also works for moving lines up/down without a selection.

4.6.3 Re-indent Text

If you have code which has broken indent, you can select it and use Text → Indent Selection (without a selection it indents the current line).

The rules for estimating the indent are setup per-language using bundle preferences. For more details see the indentation rules section.

4.7 Selecting Text

Selecting text is achieved by holding down ⇧ while using the normal movement keys. In addition the Edit → Select submenu has actions to select current word, line, paragraph, enclosing brackets and entire document.

4.7.1 Editing Multiple Lines

Sometimes there is a need for adding a suffix to lines of variable length, or maybe editing the last part of these lines.

Although you can use find and replace for this, an easier way is to select the lines that needs to be edited, then use Text → Edit Each Line in Selection (⌥⌘A) and the caret will be placed at the end of the first line in the selection.

You can now type new text, delete text or go back and edit existing text and this will be mirrored down through all the (previously selected) lines. To leave this mode, simply move the caret away from the current line.

4.7.2 Column Selections

It is possible to select column data either by holding down ⌥ and making the selection with the mouse, or making a regular selection and then pressing ⌥ once (which toggles between the two types of selection).

You can use all the normal actions on a column selection e.g. move selection, replace in selection, transpose (lines), actions from the Text menu, filter the selection through a shell command, etc.

4.8 Column Movement / Typing

Using arrow up/down with ⌥ will move the caret to the first/last row in the current column. Hold down ⇧ to get it selected.

Column Data

For example if you have column data as shown above with the caret in front of foo, press ⌥⇧↓ and it will move the caret down in front of fud and leave the text between foo and fud selected.

Column Movement

You may now either want to press ⌥ once to switch to a zero-width column selection, then start typing to type on each line.

Column Typing

Alternatively use ⌥⇧→ and then ⌥ to leave the entire column selected (in column mode).

Column Selection

4.9 Smart Tab Behavior

When using the tab key at the beginning of a line, TextMate will insert as many tabs as it estimates to be correct for that line. If the line already has text the caret will move to the front of this text.

If the line already has the correct indent (or above) a single tab will be inserted.

4.10 Spell Checking

TextMate supports the system wide 'Check Spelling as You Type'. This can be changed in the Edit → Spelling submenu.

You can bring up the context sensitive menu for a misspelled word to get spelling suggestions.

Since TextMate is intended for structured text it is possible to exclude parts of the document from being checked. This is done by creating a preferences item in the bundle editor, setting spellChecking to 0 and filling in the scope selector with the selector to target for no spell checking.

By default spell checking is disabled for source code except strings and comments and also for keywords, tags and similar in HTML, LaTeX, Markdown, etc.

4.11 Using Spaces Instead of Tabs

TextMate can use spaces instead of tab characters. This is done by clicking the “Tab Size” pop-up in the status bar and enabling Soft Tabs.

This setting will only affect the current language and all languages with a common root that do not have the option set yet. The same applies to the state of spell checking, soft wrap and the actual tab size.

Tab Size Settings

When soft tabs are enabled, TextMate will for the most part act exactly as if you were using hard tabs but the document does indeed contain spaces.

5 Bundles

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).

5.1 Activation of Bundle Items

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

Bundle Editor

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.

5.1.1 Key Equivalents

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.

Key Equivalent

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).

Key Equivalent Ambiguity

5.1.2 Tab Triggers

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 Trigger Menu

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.

Tab Trigger Ambiguity

5.2 Editing Default Bundles / Items

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.

5.3 Deleting Default Bundles / Items

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):

defaults delete com.macromates.textmate OakBundleManagerDeletedBundles

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.

5.4 Hiding Bundles

Instead of deleting default bundles you may want to just hide them (since you never know if you someday will need some of the default ones).

This is done by clicking the Filter List… button below the list in the bundle editor. Here you can uncheck the bundles that you do not wish to have shown in the various lists of bundle items.

Hiding Bundles

5.5 Sharing Bundles and Bundle Items

If you want to share a bundle or particular bundle item then you can drag it directly from the bundle editor (from the list in the left side of the window) to the Finder.

This item can then be sent to other people and they will be able to double-click it to install it. Note: this also works for single items, like a snippet or a command.

5.6 Assorted Bundles

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:

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 ⌃⎋.

Bundle Actions

Below are a few highlights from miscellaneous bundles.

5.6.1 Diff

The Diff bundle provides a language grammar for the output produced by the diff shell command.

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).

5.6.2 HTML

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

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 PreferencesAdvanced 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).

For the records have a look at Sending XHTML as text/html Considered Harmful before embracing XHTML.

5.6.3 LaTeX

Three commands of special interest in the LaTeX bundle are:

If you have not installed LaTeX you can use the i-installer (binaries).

Alternatively, if you have MacPorts then open your terminal and run:

sudo port install teTeX

5.6.4 Source

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.

5.6.5 SQL

The SQL bundle has a command that can submit the current line or selection as a MySQL or Postgres query (⌃⇧Q) and show the result using HTML output.

It uses a few environment variables to store connection details. These are described in the bundle’s Help file.

5.6.6 Subversion

All actions in the subversion bundle are accessible through ⌃⇧A. These offer the commands which would be used in a common workflow.

None of the commands are made to prompt you for a password. For repositories offered through WebDav (i.e. http or https) svn should cache your authentication. This post describes how to generate an ssh key pair for secure-shell tunneling (ssh).

Subversion Commit

The commit action will commit the files selected in the project drawer or current file if there is no selection. The commit window also allows you to exclude files before doing the actual commit.

In the commit window you can use enter (⌅) to trigger the “Commit” button shown in the bottom right corner.

5.6.7 Text

The text bundle is for actions and preferences related to basic text editing. From a users perspective some of this should probably have a more native placement than being in a bundle.

The four probably most useful actions are:

5.6.8 TextMate

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.

Show Scope

One command which is useful when working on themes or language grammars is the Show Scope (⌃⇧P) which shows the current scope of the caret (more about scopes later).

5.6.9 Xcode

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.

Build With Xcode

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).

5.7 Getting More Bundles

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.

5.7.1 Installing Subversion

If you are not using Leopard you will need to install the subversion client.

5.7.2 Setting LC_CTYPE

You must set the LC_CTYPE variable to use UTF-8. If you do not, svn will give you an svn: Can't recode string error when it stumbles upon non-ASCII filenames (some of the bundle items use these).

If you are using bash you should put this in your ~/.bash_profile (or a similar file which gets sourced when you open a terminal):

export LC_CTYPE=en_US.UTF-8

Users of zsh should put it in ~/.zshrc and tcsh users should instead put this line in their ~/.tcshrc:

setenv LC_CTYPE en_US.UTF-8

Remember that after adding this, you need to start a new shell for the updated profile to take effect.

Also be aware that the LC_ALL environment variable takes precedence over LC_CTYPE, so if you have set this elsewhere you should either unset it or change that to use UTF-8.

5.7.3 Installing a Bundle

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:

mkdir -p /Library/Application\ Support/TextMate/Bundles
cd /Library/Application\ Support/TextMate/Bundles
svn co http://macromates.com/svn/Bundles/trunk/Bundles/Haskell.tmbundle

At a later time you can update the bundles which you have installed by executing these two lines:

cd /Library/Application\ Support/TextMate/Bundles
svn up *.tmbundle

If TextMate is running while you perform the update, you may want to also execute the following line:

osascript -e 'tell app "TextMate" to reload bundles'

This is equivalent to selecting Bundles → Bundle Editor → Reload Bundles from within TextMate.

5.7.4 Support Folder

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_PATH environment 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:

cd /Library/Application\ Support/TextMate
svn co http://macromates.com/svn/Bundles/trunk/Support

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.

5.7.5 RSS Feed With Bundle Change Log

Changes made to bundles are not part of the normal release notes. Instead these are available through an RSS feed.

6 Macros

TextMate supports recordable macros. A macro is recorded by selecting Macros → Start Recording from the Bundles menu.

While recording, a red dot will pulsate in the right part of status bar and all text editing actions are recorded together with things like Find, running commands, inserting snippets etc. When done, you select Stop Recording and can either replay the recorded macro or save it for later use.

When saving a macro, it will appear in the bundle editor as (currently) a read-only macro which can get an activation sequence and scope selector, just like any other bundle item.

It is possible to set whether or not the macro should use a local clipboard while being executed. The local clipboard is generally advantageous (thus the default) but sometimes you may want the macro to effect the “real” clipboard and can disable this option.

7 Snippets

A snippet is a piece of text that you would like to insert in your document. It can include code to run at insertion time, variables (like selected text), tab stops/placeholders for missing information (which you can tab through after insertion) and perform transformations on the data which you enter in the placeholders.

Snippet Editor

7.1 Plain Text

In the simplest case, you can use snippets to insert text that you do not want to type again and again, either because you type it a lot, or because the actual text to insert is hard to remember (like your bank account details or the HTML entities for the Apple modifier keys).

If you use snippets to insert plain text there is only one thing you should be aware of: $ and ` are reserved characters. So if you want to insert one of these, prefix it with an escape (i.e. \$). An escape not followed by one of these two characters (or followed by another escape) will be inserted as a literal character.

7.2 Variables

You can insert the value of a variable by prefixing the name of the variable with $. All the normal dynamic variables are supported, the most useful probably being TM_SELECTED_TEXT. If for example we want to create a snippet which wraps the selection in a LaTeX \textbf command, we can make a snippet which is:

\textbf{$TM_SELECTED_TEXT}

If no text is selected the variable will not be set, so nothing will be inserted in its place. We can provide a default value by using this syntax: ${«variable»:«default value»}. For example:

\textbf{${TM_SELECTED_TEXT:no text was selected}}

The default value can itself contain variables or shell code. If you want the default text to contain a }, you need to escape it. But all other characters are used verbatim.

Variables also support regular expression replacements using this syntax: ${«variable»/«regexp»/«format»/«options»}. If the variable is not set the replacement will be performed on the empty string. For example, to prepend a bullet to each non-empty line in the selection (and insert that) we can do:

${TM_SELECTED_TEXT/^.+$/• $0/g}

7.3 Interpolated Shell Code

You can use backticks to have shell code executed when the snippet is inserted. The result from running the code gets inserted into the snippet, though with the last newline in the result removed (if present). So for example to create a snippet that wraps the selection in an HTML link, where the URL of that link comes from the clipboard, we can do:

<a href="`pbpaste`">$TM_SELECTED_TEXT</a>

Since this is normal bash code, we can write a small program. For example we can let it verify that the clipboard contains only a single line of text like this:

<a href="`
    if [[ $(pbpaste|wc -l) -eq 0 ]]
        then pbpaste
        else echo http://example.com/
    fi
`">$TM_SELECTED_TEXT</a>

Inside shell code, the only character you need to escape is the backtick.

7.4 Tab Stops

After insertion, the caret will be placed after the last character of the snippet. This is not always desirable and we can change that by using $0 to mark where we want the caret to be. So if for example we make an HTML div-snippet and want the caret to end between the opening and closing tags, we could make it like this:

<div>
    $0
</div>

Often though we want to fill in text in several places in the snippet. Multiple tab stops can be provided by inserting $1-$n. The caret will start at $1, then when pressing tab it will move to $2 and $3 on next tab etc. until there are no more tab stops. If you do not explicitly set $0, the caret will be at the end of the snippet.

So we could for example change the above to:

<div$1>
    $0
</div>

This allows us to fill in an argument and then tab on to $0.

7.5 Placeholders

Like variables, tab stops can also have default values (and are generally referred to as placeholders when they do). The syntax is the same: ${«tab stop»:«default value»}. And the default value can contain both text, shell code and other placeholders. So we can refine the previous example further:

<div${1: id="${2:some_id}"}>
    $0
</div>

Inserting this snippet will insert a div tag with the id argument selected and we can then decide either to overtype the argument (i.e. delete it) and press tab again to reach $0, or we can press tab immediately to get to the second tab stop (the value part of the argument) and edit that.

When you edit the placeholder text, any embedded tab stops will be removed.

7.6 Mirrors

There are times when you need to provide the same value several places in the inserted text and in these situations you can re-use the tab stop to signal that you want it mirrored at that location. So for example to create a LaTeX environment with a snippet, we can use:

\begin{${1:enumerate}}
    $0
\end{$1}

After inserting this snippet, enumerate will be selected and if we edit it, the changes will be reflected in the \end part as well.

7.7 Transformations

There are situations where we want our placeholder text mirrored but with slight changes or where we want some text to appear depending on the value/presence of a placeholder.

We can accomplish this by doing a regular expression substitution on the placeholder text (when mirroring it). The syntax for this is: ${«tab stop»/«regexp»/«format»/«options»}.

As an example, the Objective-C getter/setter methods often look like this:

- (id)foo
{
    return foo;
}

- (void)setFoo:(id)aValue
{
    [foo autorelease];
    foo = [aValue retain];
}

In the format string we can use \u to uppercase the next character, so a snippet that only asks for the name of the instance variable once could look like this:

- (${1:id})${2:foo}
{
    return $2;
}

- (void)set${2/./\u$0/}:($1)aValue
{
    [$2 autorelease];
    $2 = [aValue retain];
}

We can also use conditional insertions in the format string to make decisions. For example if we create a snippet for a method we can let the return type decide whether or not the method should include a return statement like this:

- (${1:void})${2:methodName}
{${1/void$|(.+)/(?1:\n\treturn nil;)/}
}

Here we match placeholder 1 against void or anything (.+) and put the latter match in capture register 1. Then only if we did match something (other than void) will we insert a newline, tab and the return nil; text.

8 Shell Commands

The shell is a scripting language used to piece together various programs (shell commands), and often in an interactive way, e.g. as done when launching Terminal and entering commands to execute.

For a thorough introduction to the shell scripting language have a look at this shell tutorial provided by Apple.

8.1 Executing Commands / Filtering Text

TextMate allows shell commands to be executed in different contexts. Some of the more useful options are:

  1. In the current document, either press ⌃R with no selection to run the current line as a shell command, or select one or more lines and use ⌃R to run the selection as a shell script (it supports shebang as well).

    Execute Line

  2. From the Text menu you can select Filter Through Command… (⌥⌘R) which opens a panel where you can enter a shell command to run and set what should be given as input (stdin) plus what to do with the output of the command (often you want to set input to the selected text and let the output replace the selection).

    Filter Through Command

  3. Commands via the Bundle Editor. The first two options are mostly for one-shot commands, whereas commands created in the Bundle Editor are for stuff you want to run again later. The options here are the same as those of option 2, i.e. you can set what to do with input/output, even have the output shown as a tool tip (e.g. for commands which lookup help for the current word) or HTML (e.g. for commands which build the project and show results, incrementally). You can also set that documents should be saved before executing the command and give the command a key equivalent or tab trigger.

    Command Editor

8.2 Search Path

When running a command from Terminal, the shell will use the value of the PATH variable to locate it (when it is specified without an absolute location). For example ruby is located in /usr/bin/ruby and svn is (for me) located in /opt/local/bin/svn.

TextMate would normally inherit the value of PATH from Finder, which has only a few search locations specified, so this is not very useful.

Instead TextMate runs a custom script (named bash_init.sh located in $TM_SUPPORT_PATH/lib) before executing the actual shell command(s). This custom script contains the following code:

if [ ! -f "$TM_BASH_INIT" ]; then

   # First read system-wide profile
   [ -f /etc/profile ] && . /etc/profile

   # Then find the first local profile
   if   [ -f ~/.bash_profile ]; then . ~/.bash_profile
   elif [ -f ~/.bash_login   ]; then . ~/.bash_login
   elif [ -f ~/.profile      ]; then . ~/.profile
   fi

fi

What this means is that unless you create your own custom bash_init.sh script then TextMate will get the path which would occur by first sourcing (executing) /etc/profile and then the first bash initialization file found in your home folder.

If you do not normally use the bash shell, you may have to setup the path you normally have (in tcsh, zsh, or similar). For example create a ~/.bash_profile file containing these lines:

[ -f /etc/profile ] && . /etc/profile
[ -f ~/.bashrc ]    && . ~/.bashrc

export PATH="$HOME/bin:/opt/local/bin:$PATH"

This will add ~/bin and /opt/local/bin to the path. Notice that $HOME is used instead of ~, that is because inside double-quoted strings ~ is not expanded but $HOME is.

Important: commands which use the shell shebang syntax to call a specific interpreter (e.g. #!/usr/bin/ruby or #!/usr/bin/env ruby on the first line of the command) do not go through this startup procedure, so these will not get the extended path. For these it is possible to augment the path by setting PATH in ~/.MacOSX/environment.plist which is a property list that contains key/value pairs corresponding to environment variables read by Finder when you login.

So if you want to add /opt/local/bin to the path then create ~/.MacOSX/environment.plist and add the following:

{ PATH = "/opt/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"; }

After having created (or edited) this file you will need to re-login to your user account for the change to take effect.

Note that in this file you are not able to refer to $HOME so you will instead have to use something like /Users/allan/bin for $HOME/bin (substituting allan with the name of your user).

9 Environment Variables

Environment variables are used extensively in TextMate to provide scripts and commands with information.

Here is how to read the value of a variable (named VAR) in different scripting languages:

You can use them directly in Snippets, like in bash. Both bash and snippets support an extended form (${VAR}) where it is possible to do replacements in the variable, provide fallback values (if it is unset) etc.

Remember to double-quote variables used in shell scripts, otherwise bash will first expand the variable to its value and then split this according to the input-field-separator characters (read as the IFS variable, defaults to spaces, tabs and newlines). This means if TM_FILENAME is My Document.txt and we execute rm $TM_FILENAME then rm will actually get two arguments, first one being My and the second one being Document.txt.

For info about what can be done with environment variables in bash, see this blog post about the issue or check out the bash man file.

9.1 Dynamic Variables

The following variables reflect the users current configuration, which file he has open, where the caret is located in that file, the selection in the project drawer and so on.

A script can read these variables and make decisions accordingly.

Some of the variables are not always present. For example if the current file is untitled, or there is no selection, the corresponding variable will be unset. This is useful for example to make a command work with the selection, but fall back on the current line or word.

Bash has shorthand notation for providing a default value when a variable is not set, for example to fallback on the current word when there is no selection, we would use: "${TM_SELECTED_TEXT:-$TM_CURRENT_WORD}".

9.2 Static Variables

In addition to the dynamic variables, which TextMate provides automatically, it is sometimes useful to provide a list of static variables.

For example you may have templates or snippets that should insert your company name and prefer not to put the value directly in these, or there could be shared commands which need localized settings, for example the SQL bundle has a query command which use variables for username, password and database.

For this reason it is possible to set a default list of environment variables in Preferences → Advanced → Shell Variables.

Shell Variables

These variables are given to all shell commands started from TextMate and can also be used in snippets (as can the dynamic variables for that matter).

9.3 Context Dependent Variables

Some variables are a cross between dynamic and static. For example the Source bundle contains a Toggle Comment command which will toggle the comment for the current line or selection. This command uses three variables to decide what type of comment style the user wants.

A user who works with multiple languages will however need to specify this per language. This can be done by setting the shellVariables array in the bundle preferences and provide the proper scope selector to limit these variables.

Scoped Environment Variables

This has the advantage of actually being based on the carets location, which for the Toggle Comment command allows us to have it work differently for JavaScript, CSS, HTML and embedded PHP + Ruby, all in the same document.

An example of setting the 3 variables to comment the entire block (instead of line-by-line) with the HTML/SGML/XML comment markers is shown here:

shellVariables = (
   {  name = 'TM_COMMENT_START';
      value = '<!-- ';
   },
   {  name = 'TM_COMMENT_END';
      value = ' -->';
   },
   {  name = 'TM_COMMENT_MODE';
      value = 'block';
   },
);

9.4 Project Dependent Variables

Sometimes it is useful to have a command customized differently depending on the project. For this reason, it is possible to set variables for individual projects.

The way to do this is currently a little secret but if you deselect everything in the project drawer, then click the info (circled I) button, a panel will appear where you can set variables.

These variables are saved in the project file (*.tmproj) and will exist only for snippets and (shell) commands executed in the context of that project.

10 Commands

Commands are scripts interpreted by bash or the interpreter specified at the top using shebang notation (e.g. #!/usr/bin/ruby).

Editing commands is done from the Bundle Editor which you can open by selecting Bundles → Bundle Editor → Edit Commands…

Command Editor

TextMate can save either the current document or all modified documents in the project, before running the command. This is set using the top pop-up control. A document will only be saved when it has been modified.

10.1 Command Input

When running a command the various environment variables will be available for the command to read and use. In addition, the command can read either the entire document or the selected text as input (stdin).

If the input is set to “Selected Text” and there is no selection, the command will instead get the fallback unit specified in the additional input pop-up control. If the fallback unit is used and the output is set to “Replace Selection” then the unit used as input will be replaced. So if we make a command like tr '[a-z]' '[A-Z]' (uppercase text) and set input to Selected Text but fallback to word and set output to replace selected text, then running the command with no selection, will uppercase the current word.

Input Fallback Options

One fallback unit which requires a little explanation is Scope. When the input is set to this, TextMate will search backwards and forwards for the first character which is not matched by the scope selector of the command and use those as boundaries for the input.

This means that if the language grammar marks up URLs and gives these a scope of markup.underline.url then a command with that as the scope selector can set its input to Selection or Scope and will thus get the URL as input, when this command is executed with the caret on an URL.

When a command name is shown outside the bundle editor (like in the menus) and a fallback unit is provided then TextMate will substitute “Unit / Selection” (in its name) with either “Unit” or “Selection” depending on whether or not text is selected. The text used for Unit should be a single word representing the fallback unit, i.e. Character, Word, Line, Scope (or what the scope represents, but as a single word), or Document. So if you make a command with the name “Encrypt Document / Selection” and specify its input as Selected Text, but with Document set as a fallback, this command will be presented as “Encrypt Document” when no text is selected, otherwise “Encrypt Selection.”

10.2 Command Output

TextMate can do miscellaneous things with the output (stdout) of a command, the options are:

10.3 HTML Output

The HTML output option has a few advantages in addition to providing access to WebKit’s HTML and CSS engine.

  1. The HTML output does not stall TextMate while the command is running. A progress indicator is shown in the upper right hand corner while the command is running and it can be aborted by closing the output window (a confirmation requester is presented).

    Html Output Progress Indicator

  2. JavaScript running as part of the output has access to a TextMate object with a system method that mimics the one provided to Dashboard widgets. The TextMate object also has an isBusy property which can be set to true or false to control the windows progress indicator. So in the simplest case, to allow the user to start/stop the progress indicator one could make a command like this:

    cat <<'EOF'
       <a href="javascript:TextMate.isBusy = true">Start</a>
       <a href="javascript:TextMate.isBusy = false">Stop</a>
    EOF
    

    To create a link which opens the user’s browser, one could use the system method like this:

    cat <<'EOF'
       <a href="javascript:TextMate.system(
          'open http://example.com/', null);">Open Link</a>
    EOF
    

    The system method allows starting (and stopping) of commands asynchronously, reading standard out/error from the command and sending data to the commands standard input. For further information see the Dashboard documentation.

  3. The HTML output allows the use of the TextMate URL scheme to link back to a given document. This is useful either when the command reports errors (or warnings) with the current document (e.g. a build command or a validator) or when the command refers to other files in the project, e.g. svn status.

  4. Using either Tiger or Schuberts PDF Browser Plug-in it is possible to have the HTML output show PDF files. Mainly this is useful for typesetting programs like LaTeX, where it is then possible to typeset and view the result without leaving TextMate.

  5. It is possible to redirect to other pages and thereby treat the HTML output as a shortcut to your browser. For example in PHP the “Documentation for Word” command outputs a line like this:

    echo "<meta http-equiv='Refresh'
            content='0;URL=http://php.net/$TM_CURRENT_WORD'>"
    

Due to a (presumed) security restriction with WebKit it is not possible to have the HTML output redirect, link or reference files on your disk via the file: URL scheme. Instead you can use the tm-file: URL scheme, which works exactly like file:, but does not have this cross-scheme restriction.

For a longer post about how the HTML output can be used visit the TextMate blog.

10.4 Changing Output Type

There are situations where it is useful to change the output option of a command from within the command. For example a command which looks up documentation for the current word may want to show a “no documentation found” tool tip for when there is no documentation, but otherwise use the HTML output option for the result.

Command Output Options

TextMate has a few predefined bash functions which can be used for this purpose. They optionally take a string as an argument which is first echo’ed to stdout.

These functions only work when the initial output option is not set as "Show as HTML". The list of functions is as follows:

So for example the Diff bundle has a “[Diff] Document With Saved Copy” that compares the current document with the version saved on disk. The default output option for that is to create a new document (showing the diff output with syntax highlighting), but it will show an error (as a tool tip) if there is no file on disk. This can be done using the following command:

if [[ -e "$TM_FILEPATH" ]] # does the file exist?
   then diff -u "$TM_FILEPATH" -
   else exit_show_tool_tip "No saved copy exists."
fi

10.5 Useful bash Functions

When running commands there are a few predefined bash functions which might be useful:

The functions mentioned above are all defined in $TM_SUPPORT_PATH/lib/bash_init.sh. There are also functions to aid in HTML construction (from bash) in $TM_SUPPORT_PATH/lib/html.sh, but this file is not sourced by default. So to use the functions defined in that file you would start by sourcing it e.g.:

. "$TM_SUPPORT_PATH/lib/html.sh"
redirect "http://example.com/"

10.6 Dialogs (Requesting Input & Showing Progress)

TextMate ships with CocoaDialog so this can be used out-of-the-box. You call CocoaDialog (follow the link for full documentation) with the type of dialog you want and it will return two lines of text, the first is the button pressed (as a number) and the second is the actual result. While a little cumbersome, here is an example of how to request a line of text and only proceed if the user did not cancel:

res=$(CocoaDialog inputbox --title "I Need Input" \
    --informative-text "Please give me a string:" \
    --button1 "Okay" --button2 "Cancel")

[[ $(head -n1 <<<"$res") == "2" ]] && exit_discard

res=$(tail -n1 <<<"$res")
echo "You entered: $res"

We first call CocoaDialog to get a string of text. Then we test if the first line returned (using head) is equal to 2, which corresponds to the Cancel button and if so, we exit (using the discard output option). We then go on to extract the last line of the result and echo that.

Cocoadialog Inputbox

Another common dialog type is the progress indicator. The determinate version reads from stdin the value and text to use for each step. This means we can simply pipe that info to CocoaDialog in each step of our command, a simple example could be:

for (( i = 1; i <= 100; i++ )); do
    echo "$i We're now at $i%"; sleep .05
done|CocoaDialog progressbar --title "My Program"

Cocoadialog Determinate Progress

Often though we want to show the indeterminate version. This dialog stays onscreen for as long as its stdin is open. This means we can use a pipe like above but if we want a result back from the command that we are executing, we can instead redirect the commands stderr to an instance of CocoaDialog (using process substitution), this is shown in the following example:

revs=$(svn log -q "$TM_FILEPATH"|grep -v '^-*$' \
    2> >(CocoaDialog progressbar --indeterminate \
        --title "View Revision…" \
        --text "Retrieving List of Revisions…" \
    ))
echo "$revs"

Cocoadialog Indeterminate Progress

CocoaDialog also has other dialog types, like a pop-up list, file panel, text box and so on, but as an alternative there is also AppleScript.

If you open Script Editor and then open the Standard Additions dictionary (via Open Dictionary…) there are commands under User Interaction which allow various dialogs. One caveat though, in current version (1.5) TextMate will not listen to AppleScript commands while executing shell commands with an output option other than Show as HTML. This means that instead of targeting TextMate, you should use SystemUIServer or similar and in addition to that, since SystemUIServer needs to be activated to show the dialog (with focus) you need to reactivate TextMate. Here is an example of a command that allows selecting an item from a list:

res=$(osascript <<'AS'
    tell app "TextMate"
        activate
        choose from list { "red", "green", "blue" } \
            with title "Pick a Color" \
            with prompt "What color do you like?"
    end tell
AS)

echo "You selected: $res"

osascript -e 'tell app "TextMate" to activate' &>/dev/null &

The first part is just a small AppleScript which is executed from shell via osascript (reading the script from stdin using a here-doc). The last part is the line that gives focus back to TextMate but because TextMate will not respond to this event before the shell command has completed its execution, we need to run it asynchronously, which is done by adding & to the end of the command. The &>/dev/null part is to detach stdout/error from the shell command so that this does not cause a stall.

AppleScript Choose From List

11 Drag Commands

Drag commands are like normal commands but they are activated by dropping a particular file type (specified as a list of file type extensions) into the editing window.

Drag Command File Types

The output from executing a drag command is always inserted as a snippet and the drag command has three (additional) environment variables available:

So here is a slightly complex drag command:

img="$TM_DROPPED_FILE"
echo -n "<img src=\"$img\" "

sips -g pixelWidth -g pixelHeight "$img" \
|awk '/pixelWidth/  { printf("width=\"%d\" ",  $2) }
      /pixelHeight/ { printf("height=\"%d\" ", $2) }'

base=${img##*/}
alt=$(tr <<<${base%.*} '[_-]' ' '|perl -pe 's/(\w+)/\u$1/g')
echo -n "alt=\"\${1:$alt}\">"

First we output the <img src="…" part. Then we use sips to query the image and awk to parse the output from sips and output the proper width="…" and height="…" arguments. Last we convert - and _ in the path to spaces and capitalize each word and output this as the final alt="…" argument, where we make this text a placeholder (since the entire thing is inserted as a snippet).

Drag Command Result

12 Language Grammars

Language grammars are used to assign names to document elements such as keywords, comments, strings or similar. The purpose of this is to allow styling (syntax highlighting) and to make the text editor “smart” about which context the caret is in. For example you may want a key stroke or tab trigger to act differently depending on the context, or you may want to disable spell check as you type those portions of your text document which are not prose (e.g. HTML tags).

The language grammar is used only to parse the document and assign names to subsets of this document. Then scope selectors can be used for styling, preferences and deciding how keys and tab triggers should expand.

For a more thorough introduction to this concept see the introduction to scopes blog post.

12.1 Example Grammar

You can create a new language grammar by opening the bundle editor (Window → Show Bundle Editor) and select “New Language” from the add button in the lower left corner.

This will give you a starting grammar which will look like the one below, so let us start by explaining that.

 1  {  scopeName = 'source.untitled';
 2     fileTypes = ( );
 3     foldingStartMarker = '\{\s*$';
 4     foldingStopMarker = '^\s*\}';
 5     patterns = (
 6        {  name = 'keyword.control.untitled';
 7           match = '\b(if|while|for|return)\b';
 8        },
 9        {  name = 'string.quoted.double.untitled';
10           begin = '"';
11           end = '"';
12           patterns = ( 
13              {  name = 'constant.character.escape.untitled';
14                 match = '\\.';
15              }
16           );
17        },
18     );
19  }

The format is the property list format and at the root level there are five key/value pairs:

There are two additional (root level) keys which are not used in the example: