Skip to content

Latest commit

 

History

History
149 lines (111 loc) · 5.17 KB

tty.org

File metadata and controls

149 lines (111 loc) · 5.17 KB

ANSI / Terminal utilities for Elvish

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.

Table of Contents

Usage

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>

Functions

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 to row 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.

Implementation

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
}