Table of Contents

Scripting Fundamentals

Introduction

Sessions, tabs, windows, and the iTerm2 application itself each have bits of information that are useful to users and script writers. For example: a session has a working directory, a tab or a window may have a custom title, and the iTerm2 process has a theme such as light or dark mode.

iTerm2 manages the storage and communication of this information with a system called "variables".

A variable exists in some context. Each session, tab, and window has its own context. The application itself also has a context, called the global context.

A variable has a name, such as hostname, and a value. The value is any data type encodable in JSON: numbers, booleans, strings, dictionaries, arrays, and null. There is also a special kind of variable that references a different context, allowing you to reach (for example) variables in the tab's context from its sessions' contexts.

iTerm2 defines a number of built-in variables. There are also special contexts for user-defined variables. A user-defined variable has a value set by a control sequence or a script.

Variables were originally invented for Badges as a way for users to embed text in a badge. For example, a shell script could set a user-defined variable containing the name of the current git branch, and that could be displayed in the badge.

As the Python scripting API was developed, it became clear that variables were a useful tool for sharing information between iTerm2 and scripts.

See the Variables Reference for information about built-in variables.

Continue reading to see how variables can be used.

Function Calls

Scripts may register functions which users can invoke through various hooks. For example, you can bind the invocation of function call to a keypress or a trigger.

An invocation names the function, its arguments, and the values being passed to the function.

For example, let us consider a hypothetical function that creates a new window using a passed-in initial working directory and profile. We'll name our function create_window, since every function has a name.

A function may take parameters, and every parameter has a name. Let's call the parameter names for our example initialDirectory and profileName.

To open a window with the initial working directory of /etc and profile Default we would use the following invocation syntax:

create_window(initialDirectory: "/etc", profileName: "Default")

Because every parameter is named the order of parameters does not matter. You could exchange them and it would work the same.

If you wanted to use the working directory of the user's current session and you knew the function would be invoked in the session context (which is the context in which almost all function invocations occur) you could write:

create_window(initialDirectory: path, profileName: "Default")

The identifier path refers to a variable in the session context which holds the user's current working directory.

A function may also return a value. That will be discussed in the section on interpolated strings below.

To learn how to write your own functions, follow the Python Scripting Tutorial.

Built-in Functions

iTerm2 provides a few built-in functions. There are not many because this is a relatively new feature and is still under development.

  • iterm2.alert(title: str, subtitle: str, buttons: [str, ...]) - Shows a modal alert. If the buttons array is empty, OK will be shown.
  • iterm2.count(array: [Any]) - Returns number of items in the array.
  • iterm2.get_string(title: str, subtitle: str, placeholder: str, defaultValue: str, window_id: str?) - Prompts the user for textual input.
  • iterm2.move_tab_to_window(tab_id: str) - Moves the tab into its own window.

Expressions

The preceding discussion of function calls showed how you can pass strings or paths to variables as arguments. The following types of expressions are supported:

  • Interpolated strings
  • Integers
  • Floating point
  • Array literals
  • Array dereferences
  • Function calls
  • Paths to variables

Interpolated Strings

These are described below.

Integers

These are decimal integer literals. For example, -3, 0, and 2.

Floating point

Floating point values look like -1.2, 0, 2.3, or 1.2e5.

Array Literals

Array literals are of the form:

[ expression, expression, ... ]

They may contain zero or more expressions.

Array dereferences

Array dereferences are of the form:

path[index]

Where path is the path to a variable and index is a number. Yes, this is a very restrictive syntax! It is there for a very specific purpose (the matches array passed to Triggers' interpolated strings) and will be expanded in the future, if needed.

Function calls

A function call, as described above (e.g., foo(bar: baz)) is an expression. This implies that function calls may be composed.

Paths to variables

Variables in the current context can be referred to by a path like jobName, but you can also specify multi-part paths that refer to variables in different contexts. See the section Following Context References, below.

Interpolated Strings

Another way that varibles are exposed in iTerm2's user interface is through interpolated strings. An interpolated string is a string of text that contains embedded function calls or references to variables.

iTerm2 borrows some of the Swift language's syntax for interpolated strings. This is not an attempt to implement the full Swift language, nor will iTerm2 ever contain a full-fledged language of its own. To embed an expression in a string, place it in \(…). For example, you could set a session's name to:

The current host name is \(hostname)

The expression hostname will be replaced with its value. Since hostname is a variable defined in the session context, and iTerm2 defines it to be the name of the current hostname, the session's name will appear as something like The current host name is example.com.

Here's an example showing the interpolated string in the preferences window and the resulting session title:

As a function call is a valid expression, these may also go in interpolated strings. The function's return value will be converted to a string and expanded just as an expression referencing a variable is replaced with the variable's value.

For example, suppose you have a function add(x,y) that adds two numbers. Let's set the session name to:

Two plus three is \(add(x: 2, y: 3))

The session's name as it appears in the tab bar would be Two plus three is 5.

Interpolated strings may be nested. For example, imagine a function cat(x,y) that concatenates the value of x with the value of y. This would be a legal interpolated string:

\(cat(x: "Lorem \(cat(x: "ipsum ", y: "dolor")) sit ", y: "amet"))

Its value would be Lorem ipsum dolor sit amet.

Contexts

When writing an interpolated string, you must be mindful of the context in which it is evaluated. For example, window titles are evaluated in the window's context. If you want to put the current session's hostname in the window title, you'd use \(currentTab.currentSession.hostname). Likewise, tab titles are evaluated in the tab's context.

Following Context References

Some variables reference another context. For example, the session context has a variable named tab that references the session's containing tab's context. Likewise, the tab context has a currentSession variable that references the current session's context.

You can chain variable references with .. For example, the working directory of the current session of the containing tab is given by:

tab.currentSession.path

Setting User-Defined Variables

You can set user-defined variables that are attached to a session. These always begin with user.. For example, user.gitBranch.

Shell Integration

The easiest way to set a user-defined variable is with shell integration. Modify your shell's rc script by defining a function named iterm2_print_user_vars that calls iterm2_set_user_var one or more times.

Here's an example that sets a user-defined variable called "gitBranch" to the git branch of the current directory. Pick your shell to see the version you need:

bash | fish | tcsh | zsh

# bash: Place this in .bashrc.
function iterm2_print_user_vars() {
  iterm2_set_user_var gitBranch $((git branch 2> /dev/null) | grep \* | cut -c3-)
}

You could then set your badge to \(user.gitBranch), for exmaple.

Control Sequence

User-defined variables may be set with the following escape sequence:

OSC 1337 ; SetUserVar=name=Base64-encoded value ST

Here's a shell command that demonstrates setting user.foo to the value bar:

printf "\033]1337;SetUserVar=%s=%s\007" foo `echo -n bar | base64`

This is what iterm2_set_user_var sends. Generally you should use the iterm2_print_user_vars mechanism described above instead of sending this escape sequence directly.

Python Script

Use Session.async_set_variable() in a Python script to set a user-defined variable.