TextMate is, by far, the preferred text-editor for most web developers on the Mac. In today's screencast we'll be taking a look at some of the features most developers simply don't use which can massively increase your productivity by allowing you to type less!
Not a Mac person? Jeffrey has a screencast titled "How I Can Code Twice As Fast As You" showing how to perform similar actions using a "text expander" application in Windows.
Full Screencast

Shortcuts Used
You can view all of TextMate's shortcuts and functions under the 'Bundles' menu. Here are some of the ones I use regularly:
Key
⇥ | Tab |
⇧ | Shift |
⌃ | Control |
⌥ | Option (Alt) |
⌘ | Command |
⎋ | Escape (esc) |
↩ | Return |
↓ ← ↑ → | Keyboard arrow keys |
HTML
Shortcut | Action |
⌃ ⇧ , | New HTML tag pair |
⌥ ⎋ | Tag/attribute auto-completion |
⌘ ⇧ 7 | Convert selection to HTML entities |
! ⇥ | Internet Explorer Conditionals |
⇧ ↩ | Line Break |
⌃ ⇧ V | Validate HTML / CSS |
link ⇥ | Stylesheet Link Tag |
style ⇥ | In-line style block |
scriptsrc ⇥ | External JavaScript tag |
script ⇥ | In-line JavaScript block |
PHP
Shortcut | Action |
php ⇥ | <?php ?> |
echo ⇥ | <?php echo ?> |
if ⇥ | <?php if (...): ?>
<?php endif ?> |
ifelse ⇥ | <?php if (...): ?>
<?php else: ?> <?php endif ?> |
for ⇥ foreach ⇥ while ⇥ array ⇥ switch ⇥ case ⇥ |
As you'd expect. |
req ⇥ req1 ⇥ incl ⇥ incl1 ⇥ |
require 'file'; require_once 'file'; include 'file'; include_once 'file'; |
$_ ⇥ | Select $_['POST'], $_['GET'] etc. (Global Arrays) |
⌃ ⇧ V | Validate syntax |
⌘ ⇧ R | Run PHP file |
Ruby
Shortcut | Action |
if ⇥ ife ⇥ (if, elsif) unless ⇥ while ⇥ |
As you'd expect. |
req ⇥ | require "" |
reqg ⇥ |
require "rubygems" require "" |
Hash ⇥ | Hash.new { |hash, key| hash[key] = } |
: ⇥ | :key => "value", |
File ⇥ | Select for different 'File' object methods (read, write etc.) |
⌘ R | Run Ruby file |
Rails
Shortcut | Action |
cla ⇥ | Create Rails Controller |
flash ⇥ | flash[:notice] = '' |
ra ⇥ | render :action => '' |
vp ⇥ | validates_presence_of :input |
vl ⇥ | validates_length_of :input, :within => 1..12 |
⌃ P | params[:object] |
⌃ J | session[:object] |
⌃ ⇧ . | <%= %> |
ff ⇥ | <% form_for @model do |f| -%>
<% end -%> |
f. ⇥ | Select for Rails' form helper - label, field, password, textarea, checkbox etc. |
slt ⇥ | <%= stylesheet_link_tag '' %> |
jit | <%= javascript_include_tag '' %> |
⇧ ⌥ ⌘ ↓ | Go to appropriate controller, model, view etc. for current file |
mcol ⇥ | Use in migrations. Select to add, edit, rename, remove columns etc. |
Create Your Own Shortcut/Hotkey
We're going to create a shortcut (accessed with ⌘⇧A) to wrap the currently selected text in a link, and jump you straight to the href="" attribute to enter the URL.
In TextMate, go to "Bundles > Bundle Editor > Show Bundle Editor" (or press ⌃⌥⌘B). This is what my editor looks like. Yours may look different as I have added some custom Bundles and removed some for languages I don't use:



Click on the HTML drop-down (bundle), click the + at the bottom-left of the window and select 'New Snippet'. Name this snippet 'Wrap Link' then for the 'Activation', select 'Key Equivalent' and in the box enter the key combination you wish to use (eg. ⌘⇧A).



Inside the text-area enter:
1 |
|
2 |
<a href="">$TM_SELECTED_TEXT</a> |
$TM_SELECTED_TEXT
is a variable containing the selected text. Close the window and try it out. Open a document in TextMate, highlight some text and press your key combination. The selection will be wrapped in anchor tags.
However, as it is now, you still have to move your cursor into the href=""
attribute to enter the actual link. Wouldn't it be easier if our cursor moved itself there automatically?
Change the 'Wrap Link' command to the following:
1 |
|
2 |
<a href="${1}">$TM_SELECTED_TEXT</a> |
The ${1}
tells TextMate where to place the cursor after performing the task. You can place ${2}
, ${3}
etc. and then move throughout them using the tab key.
Finally, change the command to:
1 |
|
2 |
<a href="${1}">${2:$TM_SELECTED_TEXT}</a> |
You can add default text at a location using ${2:Default text} . 'Default text' will display, and automatically highlighted when you tab into it.
In our case, we have set the selected text as a tab location for circumstances when you may want to change the original text.
You could also 'mirror' text entered at tab points, like so:
1 |
|
2 |
<p>Text: ${1}</p> |
3 |
<p>Some other text: ${2:blah de blah de blah}</p> |
4 |
<p>Mirror of 1: ${1}</p> |
Whatever you then enter on the first tab, will automatically be entered in other positions which hold the same value.
Further Examples:
Personally I've created my own bundles for including the jQuery libraries, entering 'Lorem Ipsum' text, and also for writing Nettuts articles. For example:
jQuery Snippets
Find yourself using mindlessly entering jQuery tags? Try these:
'jQuery CDN' accessed with inc-jquery
tab-trigger:
1 |
|
2 |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript" charset="utf-8"></script> |
'jQuery UI CDN' accessed with inc-ui
tab-trigger:
1 |
|
2 |
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js" type="text/javascript" charset="utf-8"></script> |
'jQuery Inline Script' accessed with inline-jquery
tab-trigger:
1 |
|
2 |
<script type="text/javascript" charset="utf-8"> |
3 |
\$(function() { |
4 |
${0} |
5 |
}); |
6 |
</script> |
'jQuery Document Ready' accessed with jquery
tab-trigger:
1 |
|
2 |
\$(function() { |
3 |
${0} |
4 |
});
|
Note: The back-slashes at the start of $(function() {
is to escape the $
character – otherwise TextMate will think it's a variable for it to try and render!
You could also simply assign all these to a jquery
tab-trigger, then when you execute it, you will get a drop-down menu to choose from. This is useful if you prefer not to memorise huge groups of snippet names!

Nettuts Snippets
I also have a bundle for the various tags Nettuts articles depend upon, such as:
'Pre Code Block' accessed using nt-pre tab-trigger:
1 |
|
2 |
<pre name="code" class="${1:php}"> |
3 |
${2} |
4 |
</pre> |
'Tuts Image' access using nt-img tab-trigger:
1 |
|
2 |
<div class="tutorial_image"><img src="images/${1}" border="0" /></div> |
When writing articles I use a small template to make it easier to read when proof-reading. This snippet has an example of 'mirroring' on the Title and H1 tags. I access this using the nt-template tab-trigger:
1 |
|
2 |
<style type="text/css" media="all"> |
3 |
body{color:#42423D;font-family:Arial,Helvetica,sans-serif}p,li,pre,blockquote{line-height:1.5em;font-size:0.9em}code{background-color:#efefef;color:#000;font-family:'Courier New',Courier,monospace;font-size:1.1em;margin:0 3px;padding:0 3px}code.filename{background-color:#f9f9f9;color:#42423D;font-family:'Courier New',Courier,monospace;font-size:1.1em;margin:0}#wrap{margin:15px auto;width:640px}code{font-size:1em !important}#meta{border-bottom:1px solid #f0f0f0;margin:40px 0 20px 0;overflow:hidden;padding-bottom:20px}#meta h1{margin-top:0}#meta img{border:5px solid #f0f0f0;float:left;margin:0 10px 10px 0}#meta p{font-size:0.9em;font-style:italic}.tutorial_image{background-color:#f0f0f0;border:1px solid #CECFD0;margin-bottom:10px;padding:10px 0;text-align:center}.tutorial_image img{border:1px solid #CBCBCB}.webroundup{padding:0px;margin:0px}.webroundup li{padding:0px;margin:0px;list-style:none;margin-bottom:20px;clear:both;margin-left:0px;padding-left:0px;background:none}.webroundup a{background-color:#468175;color:#fffffe;padding:3px 6px 3px;text-decoration:none;font-size:11px}.webroundup a:hover{background-color:#222323}.webroundup div{padding:10px;background-color:#f9f9f9;border:1px solid #cbcbcb;float:left;margin-right:15px;margin-bottom:20px}.webroundup img{border:1px solid #cbcbcb}.webroundup h4{display:block;margin-bottom:10px}.clear{clear:both;} |
4 |
</style> |
5 |
<title>${1:TITLE}</title> |
6 |
|
7 |
<div id="wrap"> |
8 |
|
9 |
<div id="meta"> |
10 |
<img src="images/${3:postimg.jpg}" /> |
11 |
<h1>${1}</h1> |
12 |
<p>${2:Summary text}</p> |
13 |
</div> |
14 |
<!--more--> |
15 |
|
16 |
<h3>${4:Header}</h3> |
17 |
<p>${5:Start typing! Use H3 for headings and H4 for sub-headings}</p> |
18 |
|
19 |
${0} |
20 |
|
21 |
|
22 |
</div><!-- #wrap --> |