November 2nd, 2006

Increasing Productivity with Textmate's New tm_dialog

21 comments on 1415 words

TextMate has been one of those tools that has significantly increased my productivity. Allan has managed to create an editor that is great for Designers and Unix geeks alike, and not to mention a vibrant and helpful community who seem to thrive on making contributions. Allan has recently upped the ante with the recently released tm_dialog; a new dialog system for commands. I’ve already come up with a use for it that helps me get my job done faster. In addition to that, I’ve made use of the Drag Command which is also helping me clean up my workflow.

Get to know tm_dialog

If you have yet to check out Allan’s screencast on tm_dialog, I encourage you to do so. He shows how powerful it is by using Interface Builder to create a dialog for viewing subversion logs; Something I do regularly. In addition to that, he’ll be creating a complete series that helps us make the best use of tm_dialog.

Cleaning up the mundane task

While editing CSS files, I find myself clicking through the project drawer looking for image file names and locations time and time again. When I do find the image I’m looking for, I end up repeatedly writing code like this:


#header {
   background: url(../images/hdr-bg.gif) no-repeat;
}

Now Textmate offers a variety of ways to keep you from having to manually type this out. You could create a snippet that triggered when you typed bg that would do most of the typing for you, but you still have to sort out the path or what not. Using a drag command, we can speed up this process.

Using Drag Commands

What I want to do here is to drag an image file from the project drawer and drop it onto the document and have TextMate type all the url stuff for me and figure out the relative path to the image. Thats great and all, but what about the no-repeat, repeat-x, etc.? Again, there are a number of ways to do this as well, but if your like me I usually have a common naming convention I use for tiling images. If an image tiles, I usually name it something like hdr-bg-tile.gif, or if it tiles on the x axis, I name it something like hdr-bg-xtile.gif. The same applies for the y tile.

Wouldn’t it be great if TextMate could figure out all this for us and the only thing we needed to do was just drag the image onto the document? Well, it can, and here is a short video of this in action:

Nice eh? If you want this behavior, just create a new drag command and pop in the code below. Set your file types (gif, png, jpg, etc) and scope to source.css.


#!/usr/bin/env ruby
image = ENV['TM_DROPPED_FILE']
image_name = File.basename(image)
repeat = ' no-repeat'

if /(xtile|tilex|ytile|tiley|tile)\./ =~ image_name
  unless $1.nil?
    repeat = case $1
      when 'xtile', 'tilex' then ' repeat-x'
      when 'ytile', 'tiley' then ' repeat-y'
      when 'tile'           then ''
    end
  end
end

print %(url(#{image})#{repeat})

Using tm_dialog to create a menu with project images

One of the cool features of tm_dialog is that we now have the ability to create custom menus. With this in mind, I wanted to stop the hunt and peck process–Hunting for images in the project drawer, and typing the required information to make that image display in css. I want to hit a key combination and have TextMate present me with a menu of images it found in the project directory, when I select an image from the menu, it should fill in all the required info. And here it is:

I used Allan’s example for tm_dialog posted here and came up with this bit of Ruby: UPDATE: Modified to ignore .svn files.


#!/usr/bin/env ruby -wKU

SUPPORT = ENV['TM_SUPPORT_PATH']
DIALOG = SUPPORT + '/bin/tm_dialog'

require SUPPORT + '/lib/escape'
require SUPPORT + '/lib/plist'
require 'pathname'
require 'find'

images = []

Find.find(ENV['TM_PROJECT_DIRECTORY']) do |f|
  file_name = File.basename(f)
  if  /\.(gif|jpg|png)$/ =~ file_name
    images << { 
      'title' => file_name, 
      'path'  => Pathname.new(f).relative_path_from(Pathname.new(ENV['TM_FILEPATH']).parent).to_s 
    }
  end
end
abort if images.empty?

plist = { 'menuItems' => images }.to_plist
res = PropertyList::load(`#{e_sh DIALOG} -up #{e_sh plist}`)
abort unless res.has_key? 'selectedMenuItem'

print %(url(#{res['selectedMenuItem']['path']}))

This code uses Find and Pathname to get the images and their path and in turn stores those values in a Hash. When we have the hash built, we create a property list from it, using menuItems as the root key for the array of image information we just build.

After we have the plist, we can pass it on to the actual dialog in the next line. If the user selects an item from the menu the resource will have the key selectedMenuItem and then we’ll take that and ask for the path value which is wrapped up in the correct CSS syntax for referencing images and then printed to the document.

As you can see, this is some pretty nice stuff and TextMate makes it dead simple to increase your productivity and extend it into an editor that is perfect for you.

(P.S. Sorry for the video size, I’m experimenting with Revver, whom I’ve recently been doing some work for.)

Discussion

  1. kamal kamal said on November 3rd

    Since tm_dialog can support loading Interface Builder NIB files, it’d be awesome if had a dialog that displayed the images it found.

  2. Dr Nic Dr Nic said on November 3rd

    Video size seems ok for showing the examples, imo.

  3. blinking8s blinking8s said on November 3rd

    damn, that is tight…

    videos were fine for me.

  4. Jon Wood Jon Wood said on November 3rd

    I’ve been using TextMate as my primary editor (sadly I still have to swim through the soup that is Dreamweaver occassionally), and the ammount of functionality wrapped up in elegant solutions like this is amazing.

    So much so that I actually bought a Mac, with my main justification being TextMate.

  5. Thomas Aylott Thomas Aylott said on November 3rd

    Slick.

    I also just recently posed a couple new commands that use tm_dialog’s menu stuff. Screencasts and all.

    The one is for English Word Completion. And the other is for Filepath Completion.

    check it out: subtleGradient.com

  6. Charles Charles said on November 4th

    Wow I tried out the program and it really does work well, great find thanks.

  7. Chris Goffinet Chris Goffinet said on November 5th

    With the code above for tm_dialog, what type of command do you create and how do you map it to the code? I am quite new to this :)

  8. Chris Goffinet Chris Goffinet said on November 5th

    Nevermind, I ended up figuring it out by doing New Command, Input -> None, Output -> Insert as Snippet :)

  9. Justin Palmer Justin Palmer said on November 5th

    @kamal: There is an image browser dialog in TM that shows a preview. I really just wanted a quick list of images because most of the time I know what they are or know most of the file name and just want to be sure.

  10. Scott Scott said on November 5th

    This is brilliant Justin. Finding images and digging through Textmate projects for images is a bti of a pain. Love both commands and they’re going to be welcome additions to my workflow.

  11. Chris Goffinet Chris Goffinet said on November 5th

    would it be possible to translate what he’s done so far, into a file filter system like TextMate has using Apple + T to jump to files in a project but filter just images so you can pick which one to insert?

  12. Matte Matte said on November 6th

    This is fabolous! I’m also experimenting with some tm_dialog ang Interface Builder! It’s very simple. Now with your code I try more solutions for my idea!

  13. Reinier / DJUST.nl Reinier / DJUST.nl said on November 6th

    The vids do not work for me. Anybody else have that problem?

  14. Cody Cody said on November 6th

    I think you meant to type “upped the ante.” ;-)

  15. Justin Palmer Justin Palmer said on November 6th

    You know, thats not the first time I’ve put poor annie in harms way. ;-)

  16. Brett Terpstra Brett Terpstra said on November 6th

    Hi Justin, Just wanted to let you know that I took up where your image insert command left off… I’ve posted one to the TM list that adds your name-based repeat selector with a conditional check for scope and inserts the appropriate information depending on whether you’re in source.css or all the way inside of the single quotes of a url(’’). It also grabs and inserts image width and height automatically if it’s creating a full rule or declaration block. If you want a copy and don’t catch it on the list, email me. Great screecasts and thanks for the inspiration!

  17. nb nb said on November 7th

    Revver videos don’t work here, either. I get the initial logo animation like it’s loading, then black for a while, then an advertisement.

    Firefox 2.0 on OS 10.4.8.

  18. Justin Palmer Justin Palmer said on November 7th

    Nice work Brett. :-)

  19. Schleevoigt Schleevoigt said on November 27th

    The best idea since T.B. Lee.

    But I cannot solve the following problem: I want to get the id of a clicked element. It has an id. ;-))

    var Rules = { ’.bildrechts:click’ : function(element) { var app = element.id; alert(app); }}

    The alert shows everytime an empty string. ;-((

  20. SPQR SPQR said on November 27th

    Does someone know if the Prototype documentation project is dead already? A long time ago there were rumours about such an effort, and also about protoype 1.5 that is still not final. I fear that the whole Prototype thing is burried in silence. jQuey for example moves much faster. Can someone clarify; are my concerns right?

  21. Tobie Langel Tobie Langel said on November 27th

    Does someone know if the Prototype documentation project is dead already?

    It’s not, stay tuned…!

    I fear that the whole Prototype thing is burried in silence.

    Have a look at the changelog, things are moving!

Sorry, comments are closed for this article.