Shell Scripts

TEA allows you to create custom Text Editor Actions using any language that can be run from the Mac OS X command line (which incidentally means it’s pretty simple to port Textmate bundle actions to Espresso). Like all Espress actions, you will need to do two things:

  1. define the action via XML
  2. create the shell script

TEALoader action XML

Shell scripts use the TEALoader class, which supports all of the Espresso elements and attributes described in action XML definitions along with the universally available TEA elements. However, TEALoader’s <setup> tag is entirely different from the TEAforEspresso class.

XML defining actions for the TEALoader class could look like this:

    <action id="" category="action.category">
        <title>My Action</title>

            <undo_name>My Action</undo_name>
            <syntax-context>html, html *</syntax-context>

TEALoader elements

Just like the TEAforEspresso class, all TEALoader elements must be nested within the <setup> element.

script (required)
This is required, and should be the full name of your script file including the extension. In the example code, the script file is a Ruby file.
This is an optional tag, and designates what you want fed to your script via STDIN; options are selection and document
If you choose selection as your input, you may specify an alternate input in case the selection is empty. Valid options include document, line, word, or character.

Specify how you want your output dealt with. Options include:

  • snippet: output will be inserted as an Espresso snippet (tab stops, etc.); if there are multiple selections, only the first will be processed
  • text: output will be plain text inserted over any selected text
  • document: output will replace all content in the document
Like many of the generic actions, shell scripts can be assigned an undo name that will show up in the Edit menu after the action has been run.

See action XML definitions for more info about syntax-context and selection-context.

The actual shell script

As mentioned above, you can use any command-line ready language for your script; just indicate what to run using the shebang. For example, #!/usr/bin/env ruby.

Custom user action shell scripts should be saved here:

~/Library/Application Support/Espresso/Support/Scripts/

Shell script actions included with Sugars should be saved within the Sugar:


See Support folder for more info.

Environmental variables

Along with whatever STDIN you requested in your action XML, your script also can access the following environmental variables:

the path to the Sugar that defined the action; mainly useful for Sugar developers (otherwise it will always point to TEA)
the path to the active file (may be undefined)
the file’s name (may be undefined)
the path to the file’s directory (may be undefined)
the textual ID string of the root syntax zone; may be blank
0 if using tabs to indent; 1 if using spaces
the number of spaces to a tab if using soft tabs
the type of line ending being used as a string

These variables are also available, and will be updated every time your script is called (for instance, if there are multiple selections):

the selected text (may be empty)
the word under the cursor or beginning of the selection (may be empty)
the textual contents of the line surrounding the cursor or start of the selection (may be empty)
the line number of the line where the insertion point or selection begins
the index in the line (starting from 0) where the cursor or selection begins
the textual ID string of the active syntax zone; may be blank

If you wish, you may define custom shell variables in the TEA Preferences and they will be available to any shell scripts you run afterward.

Here’s an example Ruby script (ported directly from Textmate) that, if named my_action.rb, would interact with the above XML action to encrypt the current selection or line (notice the use of STDIN and ENV):

#!/usr/bin/env ruby

def e_js(str)
  str.gsub(/(?=[\\"])/, '\\').gsub(/\n/, '\n').gsub(/[@.\/]/) { |ch| sprintf('\\%03o', ch[0]) }

def rot_13(str)'A-Za-z', 'N-ZA-Mn-za-m')

print %{<script type="text/javascript">document.write(
"#{e_js(rot_13(}".replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);}));
Clicky Web Analytics