Execute Text in Terminal

Kimo Johnson

22 March 2009

Most of the code I've written in the last few years has either been in MATLAB or Python, and both languages have interactive shells. As a result, the way I typically work is to write a few lines of code in my editor and then execute them in the shell to check the results. This is a great way to work if you're doing scientific computing because it's important to know what your data looks like at every stage. But I find myself copying and pasting between my editor and the shell all day long, which takes 3 keystrokes for every text selection: command-c, command-tab, command-v. Using the scripts here, this process can be streamlined.

Updated for OS X 10.5 (3/2009)

TextWrangler has great scripting capabilities with its UNIX filter, UNIX script, and AppleScript support. In addition, you can assign keystrokes that will execute a script on the current selection. That is the mechanism I will use to get my code from TextWrangler to the Terminal.

In OS X 10.5 Leopard, I can send text to the Terminal by invoking the “do script” command in Applescript. Here is the script, which you can save as “Execute Text.scpt” in ~/Library/Application Support/TextWrangler/Scripts:

(* Execute text script *)
to replaceTabs(this_text, new_tab)
        set AppleScript's text item delimiters to "        "
        set the item_list to every text item of this_text
        set AppleScript's text item delimiters to the new_tab
        set this_text to the item_list as string
        set AppleScript's text item delimiters to ""
        return this_text
end replaceTabs

set current_text to ""
tell application "TextWrangler"
        set current_text to get selection as text
end tell

set split_text to replaceTabs(current_text, "  ")

if length of split_text > 0 then
        tell application "Terminal"
                do script split_text in window 1
        end tell
end if

Since I mostly use MacVim these days, I wrote a similar python script that can be called from Vim. This script also uses new features in Leopard; in particular, the Scripting Bridge which allows Applescript commands to be called from other languages such as Python and Ruby.

import fileinput
from Foundation import *
from ScriptingBridge import *

Term = SBApplication.applicationWithBundleIdentifier_("com.apple.Terminal")

# Strip tabs
for line in fileinput.input():
        notabs = line.strip().replace('\t','   ')
        Term.doScript_in_(notabs, Term.windows()[0])
        print line,

This script can be run using a vim macro. I assigned the keystroke “,mt” to this script in my vimrc

nmap ,mt :.!/path/to/script/ToTerminal.py
vmap ,mt !/path/to/script/ToTerminal.py

Original post from 2006

Unfortunately, the Terminal that Apple ships with OS X does not have adequate AppleScript support for what I’m trying to do. Instead, I will use iTerm, which has much better AppleScript support (and tabs). Here is the script, which you can save as “Execute Text.scpt” in ~/Library/Application Support/TextWrangler/Scripts:

(* Execute Text script *)
to replaceTabs(this_text, new_tab)
    set AppleScript's text item delimiters to "\t" (* that should be a tab character *)
    set the item_list to every text item of this_text
    set AppleScript's text item delimiters to the new_tab
    set this_text to the item_list as string
    set AppleScript's text item delimiters to ""
    return this_text
end replaceTabs

set current_text to ""
tell application "TextWrangler"
    set current_text to get selection as text
end tell

set split_text to replaceTabs(current_text, "  ")

if length of split_text > 0 then
    tell application "iTerm"
        tell current session of current terminal
            write text split_text
        end tell
    end tell
end if
(* End of script *)

The first function replaces tabs with another string (in this case 3 spaces). I need this because MATLAB has tab completion in the shell, and entering tabs will cause it to attempt a completion and then beep when it can’t find one. I can’t just strip the tabs off because I also work in python and whitespace is important to the language. So I replace the tabs with three spaces.

The rest of the code is self-explanatory and I find that it works quite well. You will need to assign the shortcut in TextWrangler (Window->Palettes->Scripts, Set Key…) and then it should work. I expect it will work with other interpreted languages with few or no modifications.