By Sami Samhuri

TextMate: Insert text into self.down

UPDATE: I got everything working and it's all packaged up here. There's an installation script this time as well.

Thanks to a helpful thread on the TextMate mailing list I have the beginning of a solution to insert text at 2 (or more) locations in a file.

I implemented this for a new snippet I was working on for migrations, rename_column. Since the command is the same in self.up and self.down simply doing a reverse search for rename_column in my hackish macro didn't return the cursor the desired location.

That's enough introduction, here's the program to do the insertion:

#!/usr/bin/env ruby
def indent(s)
  s =~ /^(\s*)/
  ' ' * $1.length

up_line = 'rename_column "${1:table}", "${2:column}", "${3:new_name}"$0'
down_line = "rename_column \"$$1\", \"$$3\", \"$$2\"\n"

# find the end of self.down and insert 2nd line
lines =
ends_seen = 0
lines.each_with_index do |line, i|
  ends_seen += 1    if line =~ /^\s*end\b/
  if ends_seen == 2
    lines[i..i] = [lines[i], indent(lines[i]) * 2 + down_line]

# return the new text, escaping special chars
print up_line + lines.reverse.to_s.gsub('[$`\\]', '\\\\\1').gsub('\\$\\$', '$')

Save this as a command in your Rails, or syncPeople on Rails, bundle. The command options should be as follows:

The first modification it needs is to get the lines to insert as command line arguments so we can use it for other snippets. Secondly, regardless of the Re-indent pasted text setting the text returned is indented incorrectly.

The macro I'm thinking of to invoke this is tab-triggered and will simply: