This library implements iTerm2’s Shell Integration for the Elvish shell.
- Usage
- Implementation
Install the elvish-modules
package using epm:
use epm
epm:install github.com/zzamboni/elvish-modules
In your rc.elv
, load this module and call iterm2:init
to enable the integration:
use github.com/zzamboni/elvish-modules/iterm2
If the iTerm2 utilities are installed in their default location of ~/.iterm2
, that directory will be added automatically to the path. Note that some of the functionality provided by the utilities is also provided by functions in this module.
After loading the module and after configuring your prompt, call the following command:
iterm2:init
After this all Shell Integration features will be available.
Notes:
- At the moment Elvish does not have a mechanism for capturing the exit code of the last command executed, therefore the prompt marker is always colored as if the command was successful.
- The Elvish prompt updates dynamically. If the length of the prompt changes as you are typing (e.g. if something in the background changes the git status of a repo and the git indicators in the prompt change), the context menu you get by right-clicking the prompt mark might show the wrong captured command.
- The
iterm2:init
function needs to hook into the prompt function to emit the necessary Escape codes. For this reason it is important that you call it only after you have configured your prompt function. - If you use the Elvish
readline-bindings
module, you should re-bind theCtrl-L
key to theiterm2:clear-screen
function, which clears the screen but emits the necessary prompt marker before redrawing it. For exampleedit:insert:binding[Ctrl-L] = $iterm2:clear-screen~
Most of the iTerm2 custom escape codes are implemented by this module, either through custom functions or by constructing them directly using the iterm2:escape-cmd
, iterm2:cmd
or iterm2:set
functions. See the Implementation section below for the full list of available functions.
The FTCS codes used for shell integration cal also be emitted manually if needed, using the iterm2:ftcs-prompt
, iterm2:ftcs-command-start
, iterm2:ftcs-command-executed
and iterm2:ftcs-command-finished
functions. You should for the most part not need to use these functions directly, as they are inserted in the correct places by the iterm2:init
function.
Note: This file is written in literate programming style, to make it easy to explain. See iterm2.elv for the generated file.
The escape sequences used by iTerm2 for shell integration are described in detail in the Proprietary Escape Codes documentation.
use str
use path
All escape sequences have the same basic sequence: start with an ESC character (\e
) followed by ]
, semi-colon separated components, and ending with a BEL character (\a
). The iterm2:mk-escape-str
builds such a string, using its arguments for the components.
fn mk-escape-str {|xs| put "\e]"(str:join ';' $xs)"\a" }
The iterm2:escape-cmd
calls iterm2:mk-escape-str
and prints the result.
fn escape-cmd {|xs|
print (mk-escape-str $xs)
}
Two types of escape sequences are used: custom iTerm2 commands start with 1337
, and the “FinalTerm” commands used for the basic shell integration start with 133
. These two sequences are produced by iterm2:mk-iterm2-cmd
and iterm2:mk-ftcs-cmd
, respectively.
fn mk-iterm2-cmd {|@x| mk-escape-str [1337 $@x] }
fn mk-ftcs-cmd {|@x| mk-escape-str [133 $@x] }
iTerm2 commands come in two types: plain commands and “set” commands, which assign a value. We have two functions to emit these as needed, and a function to emit FTCS command sequences.
fn cmd {|@x| print (mk-iterm2-cmd $@x) }
fn set-var {|@x| print (mk-iterm2-cmd (str:join '=' $x)) }
fn ftcs-cmd {|@x| print (mk-ftcs-cmd $@x) }
Set window title and tab background color. Arguments are the red, green and blue values. iterm2:reset-title-color
resets to the default.
fn set-title-color {|r g b|
escape-cmd [6 1 bg red brightness $r]
escape-cmd [6 1 bg green brightness $g]
escape-cmd [6 1 bg blue brightness $b]
}
fn reset-title-color {
escape-cmd [6 1 bg '*' default]
}
Change color palette. See the documentation for the possible key
values.
fn setcolor {|key r g b|
set-var SetColors $key (printf %02x%02x%02x $r $g $b)
}
Report foreground and background colors.
fn report-background-color {
print (mk-escape-str [4 -2 '?'])
}
fn report-foreground-color {
print (mk-escape-str [4 -1 '?'])
}
Set background image. Without an argument, the background image is removed.
fn setbackground {|@file|
var encoded-file = ""
if (not-eq $file []) {
set encoded-file = (print $file[0] | /usr/bin/base64)
}
set-var SetBackgroundImageFile $encoded-file
}
Produce a hyperlink in the terminal. params
if given, should be a map containing key/value pairs (the only supported param at the moment is id
). This function does not print the string, you need to do that with print
or echo
, e.g.:
echo "This is" (iterm2:hyperlink http://zzamboni.org "my website")
fn hyperlink {|url text ¶ms=[&]|
var params-str = ""
if (not-eq $params [&]) {
set params-str = (str:join ":" (each {|k| print $k"="$params[$k] } [(keys $params)]))
}
put (mk-escape-str [ '8' $params-str $url ])$text(mk-escape-str [ '8' '' ''])
}
Setting a mark at the current position.
fn mark { cmd SetMark }
fn focus { cmd StealFocus }
Inform iTerm2 of the current directory. This is a wrapper around iterm2:set CurrentDir
, but we have a dedicated function because it’s commonly used.
fn setdir {|d|
set-var CurrentDir $d
}
Post a notification through iTerm2.
fn notify {|msg|
print (mk-escape-str [9 $msg])
}
Everything displayed in the terminal between calling iterm2:startcopy
and iterm2:endcopy
is copied to the clipboard. The general clipboard is used by default, but an option &name
can be passed to iterm2:startcopy
with values rule
, find
or font
(not sure what each does, but they are mentioned in the iTerm2 documentation).
fn startcopy {|&name=""|
set-var CopyToClipboard $name
}
fn endcopy {
cmd EndCopy
}
If you want to put a stored string in the clipboard, you can use iterm2:copystr
.
fn copystr {|s|
var encoded-str = (print $s | /usr/bin/base64)
set-var Copy :$encoded-str
}
Set an annotation at the current position. By default, the annotation covers the whole line where the cursor is, and its label is shown immediately. The following options are supported:
&hidden
- the label is not shown immediately;
&length=n
- length of the annotation;
&xy=[x y]
- position of the annotation. If
&xy
is specified,&length
must ber specified as well.
fn annotate {|ann &hidden=$false &length=$nil &xy=$nil|
var parts = [ $ann ]
if (and $length $xy) {
set parts = [ $ann $length $@xy ]
} elif (and $length (not $xy)) {
set parts = [ $length $ann ]
}
var cmd = AddAnnotation
if $hidden { set cmd = AddHiddenAnnotation }
cmd $cmd=(str:join "|" $parts)
}
fn profile {|p| set-var SetProfile $p }
fn setuservar {|var val|
set-var SetUserVar $var (print $val | /usr/bin/base64)
}
fn reportvar {|var|
set-var ReportVariable (print $var | /usr/bin/base64)
}
fn setbadge {|@badge|
set-var SetBadgeFormat (print $@badge | /usr/bin/base64)
}
These functions can be used to set these values, which are used for allowing file downloads.
fn set-remotehost {|user host|
set-var RemoteHost $user"@"$host
}
fn set-currentdir {|dir|
set-var CurrentDir $dir
}
This is not really an iTerm2-specific escape sequence, but it’s here to maintain compatibility with the original code from which this module came :)
fn windowtitle {|t| print "\e]0;"$t"\a" }
Some of the less-common commands can be invoked through the iterm2:cmd
or iterm2:set
commands:
- Set cursor shape
iterm2:set CursorShape $shape
, where$shape
can indicate a block (0), vertical bar (1) or underline (2).- Clear scrollback history
iterm2:cmd ClearScrollback
.- Enable/disable cursor guide
iterm2:set HighlightCursorLine yes/no
.- Request attention
iterm2:set RequestAttention value
. Possible values areyes
,once
,no
andfireworks
.- Report cell size
iterm2:cmd ReportCellSize
.- Set function key labels
iterm2:set SetKeyLabel $key $label
.
The FTCS commands are used for the base shell integration, with some iTerm2 extensions.
The following commands are used to mark the different parts of the prompt, command line and command output, as per the following definition, which matches the documentation (see section “Shell Integration/FinalTerm”):
[ftcs-prompt]prompt% [ftcs-command-start] ls -l [ftcs-command-executed] -rw-r--r-- 1 user group 127 May 1 2016 filename [ftcs-command-finished]
fn ftcs-prompt { ftcs-cmd A }
fn ftcs-command-start { ftcs-cmd B }
fn ftcs-command-executed {|cmd| ftcs-cmd C }
fn ftcs-command-finished {|&status=0| ftcs-cmd D $status }
The iterm2:init
function inserts the corresponding FTCS commands in the appropriate places for the prompt and the command line.
At the moment, proper capture of the command means modifying the prompt function, which means iterm2:init
needs to be called after setting up your prompt. The original prompt function is saved in $iterm2:original-prompt-fn
, and used within the modified prompt function to display it. We also modify the $edit:before-readline
and $edit:after-readline
hooks to emit the corresponding escape sequences in the correct places.
Note: at the moment Elvish does not have a mechanism for capturing the exit code of the last command executed, therefore the FTCS “command finished” marker is always emitted with an exit code of zero, so the marker is always colored as if the command was successful.
use platform
var original-prompt-fn = $nil
fn init {
# Save the original prompt
set original-prompt-fn = $edit:prompt
# Define a new prompt function which calls the original one and
# additionally emits the necessary escape codes at the end.
set edit:prompt = {
$original-prompt-fn
set-currentdir $pwd >/dev/tty
ftcs-command-start >/dev/tty
}
# Emit end-of-command and start-of-prompt markers before displaying
# each new prompt line, and set current host/user/dir.
set edit:before-readline = [
{
ftcs-command-finished
set-remotehost $E:USER (platform:hostname)
ftcs-prompt
}
$@edit:before-readline
]
# Emit start-of-command-output marker after the user presses Enter
# on the command line.
set edit:after-readline = [
$ftcs-command-executed~
$@edit:after-readline
]
}
The iterm2:clear-screen
function clears the screen and issues the corresponding markers before redrawing the prompt. If you are using the readline bindings through use readline-bindings
, you should bind this function to the Ctrl-L
key to keep the correct markers when clearing the screen.
fn clear-screen {
edit:clear
ftcs-prompt > /dev/tty
}
If the iTerm2 utilities are installed in their default location of ~/.iterm2
, we detect them and add them automatically to the path. Note that some of the functionality provided by the utilities is also provided by functions in this module.
if (path:is-dir ~/.iterm2) {
set paths = [ $@paths ~/.iterm2 ]
}