Functions for terminal ANSI code manipulation/interaction in Elvish.
This file is written in literate programming style, to make it easy to explain. See tty.elv for the generated file.
Install the elvish-modules
package using epm (you can put these statements in your rc.elv
file as well, to automatically install the package upon startup if needed):
use epm
epm:install &silent-if-installed github.com/zzamboni/elvish-modules
In your rc.elv
, load this module:
use github.com/zzamboni/elvish-modules/<module>
The base function is tty:csi
, which emits a CSI sequence composed by joining all the given parameters together, prepended with the ESC [
sequence. Parameters which are lists are joined by semicolons. For example:
tty:csi 0 K # Emits CSI 0 K, clear to end of line
tty:csi [3 5] H # Emits CSI 3;5H, move to row 3, column 5
If the escape sequence “reports” a value back via the terminal, you can use tty:csi-report
, which receives as first argument the delimiter character to expect for the response, and the rest of the arguments are the sequence to issue, as passed to tty:csi
. For example:
[~]|> tty:csi-report R 6 n
▶ "\e[6;1R"
Note: interactively, the tty:csi-report
function produces an extra empty line on some terminals, but the returned value is still correct.
The tty:with-stty
executes a function within a context with the given stty
parameters. For example:
Credits: thanks @hanche for this function, which made tty:cursor-pos
possible!
# Read a string without it echoing to the terminal
pass = (tty:with-stty [-echo] { read-line })
Some common sequences have their own functions. Both descriptive names and short names (according to this table) are available:
tty:cursor-pos
/tty:dsr
: return the cursor position as[row column]
.tty:set-cursor-pos
/tty:cup
: set the cursor position torow column
.tty:clear-line
/tty:el
: clear a part of the line.&mode
specifies what to clear. If&mode
is 0 (default), clear from cursor to the end of the line. If&mode
is 1, clear from cursor to beginning of the line. If&mode
is 2, clear entire line.
use re
use str
Execute a function with given stty
parameters.
fn with-stty {|args cmd~|
var stty = (stty -g </dev/tty)
try { stty $@args </dev/tty >/dev/tty; cmd } finally { stty $stty </dev/tty >/dev/tty}
}
Emit a CSI escape sequence. The arguments are joined without a separator, but elements that are lists are themselves joined by semicolons.
fn csi {|@cmd|
print "\e["(str:join '' [(
each {|e|
if (eq (kind-of $e) list) {
str:join ';' $e
} else {
put $e
}
} $cmd)]) >/dev/tty
}
Emit a CSI escape sequence which reports a return value on the input, and reads the produced string up to the given delimiter character. The first argument is the delimiter, the rest are the arguments passed to tty:csi
for the sequence to emit. Returns a string containing the whole reported result.
fn csi-report {|delim @cmd|
with-stty [-echo raw] { csi $@cmd; read-upto $delim </dev/tty }
}
Get cursor position. Returns a two-list element with [ row column ]
.
fn cursor-pos {
var res = (csi-report R 6 n)
put (re:find '\[(\d+);(\d+)R' $res)[groups][{1,2}][text]
}
# Short name alias according to https://en.wikipedia.org/wiki/ANSI_escape_code
var dsr~ = $cursor-pos~
Set cursor position. Takes two arguments row
and column
.
fn set-cursor-pos {|row col|
csi [$row $col] H
}
# Short name alias according to https://en.wikipedia.org/wiki/ANSI_escape_code
var cur~ = $set-cursor-pos~
Clear a part of the line. &mode
specifies what to clear. If &mode
is 0 (default), clear from cursor to the end of the line. If &mode
is 1, clear from cursor to beginning of the line. If &mode
is 2, clear entire line.
fn clear-line {|&mode=0|
csi $mode K
}
# Short name alias according to https://en.wikipedia.org/wiki/ANSI_escape_code
var el~ = $clear-line~
Hide or show the cursor.
fn hide-cursor {
csi '?' 25 l
}
fn show-cursor {
csi '?' 25 h
}