Skip to content

Instantly share code, notes, and snippets.

@fdncred
Created December 20, 2023 15:38
Show Gist options
  • Select an option

  • Save fdncred/c649b8ab3577a0e2873a8f229730e939 to your computer and use it in GitHub Desktop.

Select an option

Save fdncred/c649b8ab3577a0e2873a8f229730e939 to your computer and use it in GitHub Desktop.
escape sequences

OSC4 - set foreground/background colors

OSC 4 ; -2; ? ST //bg
OSC 4 ; -1 ; ? ST //fg
OSC 4 ; -2 ; rgb : [red] / [green] / [blue] ST
OSC 4 ; -1 ; rgb : [red] / [green] / [blue] ST

OSC6 - set window title and tab color

OSC 6 ; 1 ; bg ; red ; brightness ; [N] ST
OSC 6 ; 1 ; bg ; green ; brightness ; [N] ST
OSC 6 ; 1 ; bg ; blue ; brightness ; [N] ST
OSC 6 ; 1 ; bg ; * ; default ST
echo -e "\033]6;1;bg;*;default\a"

OSC7

OSC 7 ; [Ps] ST //set window title

OSC8 - hyperlink

OSC 8 ; [params] ; [url] ST

OSC9 - post a notification

OSC 9 ; [Message content goes here] ST

OSC52

OSC 52 ; Pc ; [base64 encoded string] ST
OSC 52 ; Pc ; ? ST
OSC 52 ; Pc ; [base64 encoded string] ST

OSC133 - FinalTerm

OSC 133 ; A ST //prompt
OSC 133 ; B ST //command start
OSC 133 ; C ST //command executed
OSC 133 ; D ; [Ps] ST //command finished with exit code
OSC 133 ; D ST //command finished

OSC1337 - Leet

OSC 1337 ; CursorShape=[N] ST //0 block, 1 vertical bar, 2 underline
OSC 1337 ; SetMark ST
OSC 1337 ; StealFocus ST
OSC 1337 ; ClearScrollback ST
OSC 1337 ; CurrentDir=[current directory] ST
OSC 1337 ; SetProfile=[new profile name] ST
OSC 1337 ; CopyToClipboard=[clipboard name] ST
OSC 1337 ; EndCopy ST
OSC 1337 ; Copy=:[base64] ST
OSC 1337 ; SetColors=[key]=[value] ST
OSC 1337 ; AddAnnotation=[message] ST
OSC 1337 ; AddAnnotation=[length] | [message] ST
OSC 1337 ; AddAnnotation=[message] | [length] | [x-coord] | [y-coord] ST
OSC 1337 ; AddHiddenAnnotation=[message] ST
OSC 1337 ; AddHiddenAnnotation=[length] | [message] ST
OSC 1337 ; AddHiddenAnnotation=[message] | [length] | [x-coord] | [y-coord] ST
OSC 1337 ; HighlightCursorLine=[boolean] ST
OSC 1337 ; RequestAttention=[value] ST
OSC 1337 ; SetBackgroundImageFile=[base64] ST
OSC 1337 ; ReportCellSize ST
OSC 1337 ; ReportCellSize=[height];[width] ST
OSC 1337 ; ReportCellSize=[height];[width];[scale] ST
OSC 1337 ; ReportVariable=[base64] ST
OSC 1337 ; RequestUpload=format=[type] ST
OSC 1337 ; SetKeyLabel=[key]=[value] ST
OSC 1337 ; PushKeyLabels ST
OSC 1337 ; PopKeyLabels ST
OSC 1337 ; PushKeyLabels=[label] ST
OSC 1337 ; PopKeyLabels=[label] ST
OSC 1337 ; UnicodeVersion=[n] ST
OSC 1337 ; Custom=id=[secret]:[pattern] ST
OSC 1337 ; SetUserVar=[Ps1]=[Ps2] ST
OSC 1337 ; ShellIntegrationVersion=[Pn] ; [Ps] ST
OSC 1337 ; ShellIntegrationVersion=[Pn] ST
OSC 1337 ; RemoteHost=[Ps1]@[Ps2] ST
OSC 1337 ; CurrentDir=[Ps1] ST
OSC 1337 ; ClearCapturedOutput ST

CSI

CSI 0 SP q // reset cursor
CSI 4 : 3 m // curly underlines
CSI > q // report terminal name and version

Commands

OSC "133;L\007"

Do a fresh-line: If the cursor is the initial column (left, assuming left-to-right writing), do nothing. Otherwise, do the equivalent of "\r\n".

Issue: Possibly add an option for a character (with styling) to indicate that a newline is missing. For example fish uses , while zsh uses % (in inverse video).

OSC "133;A" options "\007"

First do a fresh-line. Then start a new command, and enter prompt mode: Subsequent text (until a OSC "133;B" or OSC "133;I" command) is a prompt string (as if followed by OSC 133;P;k=i\007).

Applicable options: aid, cl.

OSC "133;N" options "\007"

Same as OSC "133;A" but may first implicitly terminate a previous command: If the options specify an aid and there is an active (open) command with matching aid, finish the innermost such command (as well as any other commands nested more deeply). If no aid is specified, treat as an aid whose value is the empty string.

Applicable options: aid, cl.

OSC "133;P" options "\007"

Explicit start of prompt. Optional after an A or N command. The k (kind) option specifies the type of prompt: regular primary prompt (k=i or default), right-side prompts (k=r), or prompts for continuation lines (k=c or k=s).

Applicable options: k (kind).

OSC "133;B" options "\007"

End of prompt and start of user input, terminated by a OSC "133;C" or another prompt (OSC "133;P").

OSC "133;I" options "\007"

End of prompt and start of user input, terminated by end-of-line.

OSC "133;C" options "\007"

End of input, and start of output.

OSC "133;D" [";" exit-code _options ]"\007"

End of current command.

The exit-code need not be specified if if there are no options, or if the command was cancelled (no OSC "133;C"), such as by typing an interrupt/cancel character (typically ctrl-C) during line-editing. Otherwise, it must be an integer code, where 0 means the command succeeded, and other values indicate failure. In additing to the exit-code there may be an err= option, which non-legacy terminals should give precedence to. The err=_value_ option is more general: an empty string is success, and any non-empty value (which need not be an integer) is an error code. So to indicate success both ways you could send OSC "133;D;0;err=\007", though `OSC "133;D;0\007" is shorter.

These rules are for backward compatibility with iTerm2.

Applicable options: aid, err.

General options syntax

Options have the general format:

options ::= (";" option)*

In general, an option can be any string of characters not including control characters (value less than 32) or semicolon. Usually the will have the form of a named-option:

named-option ::= option-name "=" value

A terminal must ignore an option whose option-name it doesn't recognize.

Issue: Alternative specification: If a terminal doesn't recognize an option-name it should ignore it and any subsequernt options.

Issue: Maybe allow value to be a quoted string, with C-style escapes?

Standard options

aid= value

The current application identifier.

err= value

Only applicable to a OSC "133;Z"command. Specifies a string value that reports an error code from the command. Note that any non-empty value should be displayed as an error, even 0. A non-error is indicated by a missing err option or en empty value. This generality is to support command processors that don't follow the standard Unix convention of 0 for success. For a Unix-like shells, on success (zero exit code) there should be no err option or an empty err option; on failure (non-zero exit code), _value) should be the exit code.

cl= value

This option is defined for A or N commands.

This option is a request from the application to the terminal to translate clicks in the input area to cursor movement. The terminal is free to ignore this option, or to treat any specified value as line. See separate discussion below. If implemented. it provides a more natural user experience, especially for beginners, who are often surprised when a mouse click doesn't move the cursor.

The value can be one of line, m, v, or w, specifying what kind of cursor key sequences are handled by the application. The value line allows motion within single input line, using using standard left/right arrow escape sequences (or overridden by move-keys). Only a single left/right sequence should be emitted for double-width characters. The value m (for "multiple") allows movement between different lines (in the same group), but only using left/right arrow escape sequences. The values v or w is like m but cursor up/down should be used. Using w specifies that that there are no spurious spaces (written by the application though not typed by the user) at the end of the line, and that the application editor handles "smart vertical movement". (This means that moving 2 lines up from character position 20, where the intermediate line is 15 characters wide and the destination line is 18 characters wide, ends at position 18.) If v is specified instead of w then the terminal should be more conservative when moving between lines: It should move the cursor left to the start of line, then emit the needed up or down sequences, then move the cursor right to the clicked destination.

To support extensions, value is allowed to be a comma-separated list.

move-keys= left "," right ["," up, "," down]

Specify key sequences to use for click-move mode when translating clicks to cursor motion. The defaults are the standard arrow-key sequences: CSI D etc. (Note: this is an example where allowing quoted strings would be useful.)

k= prompt_kind

Specify the kind of prompt sequence. A normal left first-line prompt has kind i (initial), which is the default. Prompts for continuation lines have kind c (continuation), or kind s (secondary). The difference between c and s is that c allows the user to "go back" and edit previous lines, while s does not. A right-aligned prompt has kind r (right). When reflowing lines with a r prompt, a terminal may optionally adjust spacing so the right prompt stays at the right end of the line.

Input lines

Each input section consists of one or more input lines, The structure of an input line is an optional initial prompt, followed by a possibly-empty user input area, followed by "background area", followed by an optional final prompt.

End of input / start of output

The OSC "133;C" command can be used to explicitly end the input area and begin the output area. However, some applications don't provide a convenient way to emit that command. That is why we also specify an implicit way to end the input area at the end of the line. In the case of multiple input lines: If the cursor is on a fresh (empty) line and we see either OSC "133;P" or OSC "133;I" then this is the start of a continuation input line. If we see anything else, it is the start of the output area (or end of command).

Input vs background

The blank area between the input area and the right prompt (if any) or the end of line is the background area. There may be actual spaces (explicitly typed by the user) at the end of the input are, but it is desirable for the terminal to be able distinguish these from the background:

  • Selected text should include explicit spaces but not background space.
  • You may want a distinct styling for actual input text.
  • A terminal may want to handle mouse clicks in the input area different from those in the background.

A terminal can manage this distinction using a special logical style for text in the input area. Input text echoed by the application should get this style. Care must be taken when deleting characters: All deletion should be done with either Delete Character (CSI P) or Erase in Line (CSI K), but not by overwriting with a space. If the application needs to write a final (right) prompt, it should move the cursor in position using Cursor Forward (CSI C), not by writing spaces.

Prompts

An application should emit each prompt string as a single undivided sequence, not containing cursor motion (including no carriage return or line-feed). A prompt starts with a 'OSC 133;A' or 'OSC 133;N' sequence (for the initial prompt), or 'OSC 133;P' (for subsequent prompts). It must end with 'OSC 133;B' or 'OSC 133;I' or end-of-line (only for final/right prompts).

Initial indentation (such as emitted by fish) should treated and delimited as a (blank) prompt. Alternatively, it can be handled "background", which means it should be "written" using cursor motion (CSI C), not spaces.

If there is a right prompt in an input line that wraps around (logical line wider than screen width), the prompt should be written at the end of the final screen line, not the first. This allows line-wrap indicators to be correct.

Issue: Possibly add a way to mark indentation as distinct from prompts.

Canceling input

If input is cancelled (such as by typing ctrl-c), then the application should avoid emitting a OSC 133;C command, and instead just emit a OSC 133;D command. It is suggested it specify a err=CANCEL option, but it is not required.

Window re-size

Many terminals re-flow long (wrapped) lines when the containing window changes size. It is recommended that terminal should not re-flow the current input area when the cursor is in the area. The reason is that most input editors will repaint the input area on windows resize, and inconsistencies are possible if both terminal and application try to re-flow, as there is no easy synchronization.

Cursor motion from mouse clicks

People new to shells and similar REPLs usually expect that they can move the input cursor using a mouse click, and are surprised when it doesn't work. Experienced shell users also sometimes want this ability, for example making an edit to a long command. It is possible for an application (or input library) to implement this using xterm-style mouse support, but there are disadvantages doing that:

  • There is some per-application implementation effort to add mouse support. This may be infeasible if you don't have source-code access or the skills to modify the application.
  • The xterm mouse support is too coarse grain. If an application requests mouse reporting, it disables the default mouse behavior for selection-by-drag and for context menus (third-button click). It is difficult for an application to re-enable that functionality.

However, if an application supports cursor movement using the arrow keys (or some other key sequence), then it is easy for the terminal to translate a mouse click to the appropriate key sequence.

Moving the cursor within the current input line is requested by the cl=line option. If the terminal supports this feature, it should be activated when the user clicks in an input line containing the cursor, using a button-1 (left) click and no modifier keys. (If the click is in the left prompt, it is treated at the first character of the input area; if it is to the right of input area (in the background area or right prompt) it is treated as just after the input area.) The terminal calculates the character position of the click minus the character position of the cursor. (Character position is like column position, but double-width characters only count one.) If the count is positive, that many right sequences (by default CSI C) are sent; if negative, that many left sequences (by default CSI D).

Omitted-newline sequence

Both fish and zsh emit after a command finishes special strings to deal with output that does not end with a newline. These strings have no effect for output that (correctly) ends with a newline, but otherwise they append a special marker, and add the missing newline.

Such "omitted-newline" sequences can be emitted before or after the end-of-commmand sequence (D or Z), but must be emitted before the next start-of-command seuqnec (A or N).

Note that re-flow due to making the window narrower may cause an extra undesired blank line. A fresh-line sequence (L) does not have that downside, but it doesn't have a way to specify a marker.

Supported OSCs

OSC, Operating System Command, are escape sequences that interacts with the terminal emulator itself. Foot implements the following OSCs:

  • OSC 0 - change window icon + title (but only title is actually supported)
  • OSC 2 - change window title
  • OSC 4 - change color palette
  • OSC 7 - report CWD (see shell integration)
  • OSC 8 - hyperlink
  • OSC 9 - desktop notification
  • OSC 10 - change (default) foreground color
  • OSC 11 - change (default) background color
  • OSC 12 - change cursor color
  • OSC 17 - change highlight (selection) background color
  • OSC 19 - change highlight (selection) foreground color
  • OSC 22 - set the xcursor (mouse) pointer
  • OSC 52 - copy/paste clipboard data
  • OSC 104 - reset color palette
  • OSC 110 - reset default foreground color
  • OSC 111 - reset default background color
  • OSC 112 - reset cursor color
  • OSC 117 - reset highlight background color
  • OSC 119 - reset highlight foreground color
  • OSC 133 - shell integration
  • OSC 555 - flash screen (foot specific)
  • OSC 777 - desktop notification (only the ;notify sub-command of OSC 777 is supported.)

Shell integration works by having the shell (or any command line application) write special "escape sequences" to the Terminal. These escape sequences aren't printed to the Terminal - instead, they provide bits of metadata the terminal can use to know more about what's going on in the application. By sticking these sequences into your shell's prompt, you can have the shell continuously provide info to the terminal that only the shell knows.

For the following sequences:

  • OSC is the string "\x1b]" - an escape character, followed by ]
  • ST is the "string terminator", and can be either \x1b\ (an ESC character, followed by \) or \x7 (the BEL character)
  • Spaces are merely illustrative.
  • Strings in <> are parameters that should be replaced by some other value.

The relevant supported shell integration sequences as of Terminal v1.18 are:

  • OSC 133 ; A ST ("FTCS_PROMPT") - The start of a prompt.
  • OSC 133 ; B ST ("FTCS_COMMAND_START") - The start of a commandline (READ: the end of the prompt).
  • OSC 133 ; C ST ("FTCS_COMMAND_EXECUTED") - The start of the command output / the end of the commandline.
  • OSC 133 ; D ; <ExitCode> ST ("FTCS_COMMAND_FINISHED") - the end of a command. ExitCode If ExitCode is provided, then the Terminal will treat 0 as "success" and anything else as an error. If omitted, the terminal will just leave the mark the default color.

VS Code custom sequences 'OSC 633 ; ... ST'

VS Code has a set of custom escape sequences designed to enable the shell integration feature when run in VS Code's terminal. These are used by the built-in scripts but can also be used by any application capable of sending sequences to the terminal, for example the Julia extension uses these to support shell integration in the Julia REPL.

These sequences should be ignored by other terminals, but unless other terminals end up adopting the sequences more widely, it's recommended to check that $TERM_PROGRAM is vscode before writing them.

  • OSC 633 ; A ST - Mark prompt start.

  • OSC 633 ; B ST - Mark prompt end.

  • OSC 633 ; C ST - Mark pre-execution.

  • OSC 633 ; D [; <exitcode>] ST - Mark execution finished with an optional exit code.

  • OSC 633 ; E ; <commandline> ST - Explicitly set the command line.

    The E sequence allows the terminal to reliably get the exact command line interpreted by the shell. When this is not specified, the terminal may fallback to using the A, B and C sequences to get the command, or disable the detection all together if it's unreliable.

    The optional nonce can be used to verify the sequence came from the shell integration script to prevent command spoofing. When the nonce is verified successfully, some protections before using the commands will be removed for an improved user experience.

    The command line can escape ASCII characters using the \xAB format, where AB are the hexadecimal representation of the character code (case insensitive), and escape the \ character using \\. It's required to escape semi-colon (0x3b) and characters 0x20 and below and this is particularly important for new line and semi-colon.

    Some examples:

    "\"  -> "\\"
    "\n" -> "\x0a"
    ";"  -> "\x3b"
    
  • OSC 633 ; P ; <Property>=<Value> ST - Set a property on the terminal, only known properties will be handled.

    Known properties:

    • Cwd - Reports the current working directory to the terminal.
    • IsWindows - Indicates whether the terminal is using a Windows backend like winpty or conpty. This may be used to enable additional heuristics as the positioning of the shell integration sequences are not guaranteed to be correct. Valid values are True and False.

Final Term shell integration

VS Code supports Final Term's shell integration sequences, which allow non-VS Code shell integration scripts to work in VS Code. This results in a somewhat degraded experience as it doesn't support as many features as OSC 633. Here are the specific sequences that are supported:

  • OSC 133 ; A ST - Mark prompt start.
  • OSC 133 ; B ST - Mark prompt end.
  • OSC 133 ; C ST - Mark pre-execution.
  • OSC 133 ; D [; <exitcode>] ST - Mark execution finished with an optional exit code.

SetMark 'OSC 1337 ; SetMark ST'

This sequence adds a mark to the left of the line it was triggered on and also adds an annotation to the scroll bar:

When the sequence is written to the terminal a small grey circle will appear to the left of the command, with a matching annotation in the scroll bar

These marks integrate with command navigation to make them easy to navigate to via ctrl/cmd+up and ctrl/cmd+down by default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment