TextMate News

Anything vaguely related to TextMate and macOS.

HOWTO: Iterate Selected Files (Project Drawer)

Ken Scott wrote a command to delete files selected in the project drawer from subversion (which is now part of the Subversion bundle.)

This command makes use of the TM_SELECTED_FILES environment variable, but the contents of that variable is a little special, as it contains multiple file names, and he wanted to present these nicely.

So let us look at how to do that.

A variable like TM_FILEPATH contains the exact path of the current file. So one can (in shell scripts) use it as "$TM_FILEPATH", here the quoting is important, so that the shell doesn’t parse the result after expanding the variable (basically doing word-splitting according to the value of the input-field-separator (IFS) variable).

But if we have selected /tmp/foo.txt and /tmp/bar.txt in the project drawer, the value of TM_SELECTED_FILES will be:

'/tmp/foo.txt' '/tmp/bar.txt'

That is, it lists the filenames as single-quoted and space separated, as you would type them in the shell, had you been using an interactive shell.

So what we want is to expand the variable and then re-execute the entire line. This could be done as:

echo svn rm "$TM_SELECTED_FILES"|sh

Here we use echo to create the actual command line we want to execute, and then feed that to sh (the shell interpreter). But a better way is to put eval first on the line. This will make the shell re-evaluate the line, after performing the initial variable expansions:

eval svn rm "$TM_SELECTED_FILES"

A follow-up question would be, what if we wanted to do something with each of the files listed in TM_SELECTED_FILES. For that, we can use bash arrays. An array is specified like below:

arr=(foo bar fud)

After that, arr will be a normal variable. We can use ${arr[n]} for the n’th element, or ${#arr[@]} for number of elements in the array. To iterate over the elements we can therefor do:

arr=(foo bar fud)
for (( i = 0; i < ${#arr[@]}; i++ )); do
   echo "element $i is ${arr[$i]}"
done

We still lack to convert the TM_SELECTED_FILES variable into an array. Similar to above, we use the variable where we want the list, and prefix the line with eval to have it re-evaluate the line, after having performed the variable expansion:

eval arr=("$TM_SELECTED_FILES")

So to iterate all selected files and output the basename, we end up with something liek this:

eval arr=("$TM_SELECTED_FILES")
for (( i = 0; i < ${#arr[@]}; i++ )); do
   file=${arr[$i]}
   base=$(basename "$file")
   echo "selected file number $i is $base"
done

categories TextMate Tricks

1 Comment

Hah! I didn’t even know there were tools for Subversion in TM. This is great. Now I can use this command to clear out my repository for a site upgrade. Thanks Ken and Allen.

-Mark