Skip to content

jcorbin/anansi

Repository files navigation

AnANSI - a bag of collected wisdom for manipulating terminals

... or yet ANother ANSI terminal library.

Why?

  • Designed to be a loosely coupled set of principled layers, rather than (just) one unified convenient interface
  • Be more Go-idiomatic / natural: e.g. ansi.DecodeEscape following utf8.DecodeRune convention, rather than heavier weight event parsing/handling
  • Supporting use cases other than fullscreen raw mode
  • Allow applications to choose input modality, rather than lock-in to one paradigm like non-blocking/SIGIO
  • Support implementing terminal emulators, e.g. to build a multiplexer or debug wrapper

Status

Experimental: AnANSI is currently in initial exploration mode, and while things on master are reasonably stable, there's no guarantees yet.

Demos

The Decode Demo Command demonstrates ansi Decoding, optionally with mouse reporting and terminal state manipulation (for raw and alternate screen mode). When run in batch mode (on a regular file rather than a terminal), it replaces ansi escape sequences with [ansi ...] representation strings; there is also a -strip flag, to simply strip all escape sequences from a file.

The Palette Demo Command demonstrates the various ansi color spaces, and optionally some vendor standard color themes.

There's also a lolwut demo, which is a port of antirez's, demonstrating braille-bitmap rendering capability. It has an optional interactive animated mode of which demonstrates the experimental x/platform layer.

There's another x/platform demo that draws a colorful test pattern.

Done

Experimental cohesive x/platform layer:

  • provides a platform.Events queue layered on top of anansi.input, which contains parsed rune, ansi.Escape, and ansi.MouseState data
  • synthesizes all of the below anansi pieces (Term, Input, Output, etc) into one cohesive platform.Context which supports a single combined round of non-blocking input processing and output generation
  • provides signal handling for typical things like SIGINT, SIGERM, SIGHUP, and SIGWINCH
  • drives a platform.Client in a platform.Tick loop at a desired Frames-Per-Second (FPS) rate
  • provides input record and replay on top of (de)serialized client and platform state
  • supports inter-frame background work
  • provides a diagnostic HUD overlay that displays things like Go's log output, FPS, time, mouse state, screen size, etc

Toplevel anansi package:

  • anansi.Term, anansi.Context, anansi.Attr, and anansi.Mode provide cohesive management of terminal state such as raw mode, ANSI escape sequenced modes, and SGR attribute state
  • anansi.Input supports reading input from a file handle, implementing both blocking .ReadMore() and non-blocking .ReadAny() modes
  • anansi.Output mediates flushing output from any io.WriterTo (implemented by both anansi.Cursor and anansi.Screen) into a file handle. It properly handles non-blocking IO (by temporarily doing a blocking write if necessary) to coexist with anansi.Input (since stdin and stdout share the same underlying file descriptor)
  • anansi.Cursor represents cursor state including position, visibility, and SGR attribute(s); it supports processing under an anansi.Buffer
  • anansi.Grid provides a 2d array of rune andansi.SGRAttr data; it supports processing under an anansi.Buffer.
  • anansi.Screen combines an anansi.Cursor with anansi.Grid, supporting differential screen updates and final post-update cursor display
  • anansi.Bitmap provides a 2d bitmap that can be rendered or drawn into braille runes.
  • Both anansi.Grid and anansi.Bitmap support anansi.Styled rendering into an anansi.Buffer, or drawing into an (other) anansi.Grid.
  • anansi.Buffer supports deferred writing to a terminal; the primary trick that it adds beyond a basic bytes.Buffer convenience, is allowing the users to process escape sequences, no matter how they're written. This enables keeping virtual state (such as cursor position or a cell grid) up to date without locking downstream users into specific APIs for writing

Core anansi/ansi package:

  • ansi.DecodeEscape provides escape sequence decoding as similarly to utf8.DecodeRune as possible. Additional support for decoding escape arguments is provided (DecodeNumber, DecodeSGR, DecodeMode, and DecodeCursorCardinal)
  • ansi.SGRAttr supports dealing with terminal colors and text attributes
  • ansi.MouseState supports handling xterm extended mouse reporting
  • function definitions like ansi.CUP and ansi.SM for building control sequences terminal state management
  • ansi.Mode supports setting and clearing various modes such as mouse reporting (and its optional extra levels like motion and full button reporting)
  • ansi.Point and ansi.Rectangle support sane handling of 1,1-originated screen geometry

Errata

  • differential screen update is still not perfect, although the glitches that were previously present are now lessened due to the functional test; however this was done by removing a (perhaps premature) cursor movement optimization to simplify diffing
  • Works For Me ™ in tmux-under-iTerm2: should also work in other modern xterm-descended terminals, such as the libvte family; however terminfo detection not yet used by the platform layer, so basic things like smcup/rmcup inversion may by broken
  • anansi.Screen doesn't (yet) implement full vt100 emulation, notably lacking is scrolling region support
  • there's something glitchy with trying to write into the final cell (last column of last row), sometimes it seems to trigger a scroll (as when used by hud log view) sometimes not (as when background filled by demo)

WIP

  • an experimental mid-tier anui package architected around a stack of cooperative layers with user-interaction-authority over each other provides a re-usable fullscreen run loop for many application cases.
  • an interact command demo which allows you to interactively manipulate arguments passed to a dynamically executed command

TODO

  • fancier image rendition (e.g. leveraging iTerm2's image support)
  • special decoding for CSI M, whose arg follows AFTER
  • provide DecodeEscapeInString(s string) for completeness
  • support bracketed paste mode (and decoding pastes from it)
  • consider compacting the record file format; maybe also compression it
  • terminfo layer:
    • automated codegen (for builtins)
    • full load rather than the termbox-inherited cherry picking
  • terminal interrogation:
    • where's the cursor?
    • CSI DA
    • CSI DSR

Branches

AnANSI uses a triple branch (master, rc, and dev) pattern that I've found useful:

  • the master branch has relatively stable code but is still pre v1.0.0, and so is not actually stable; tests must pass on all commits. NOTE any package under anansi/x/ doesn't even have the tacit attempt made at stability that the rest of anansi/ on master does.
  • the rc branch contains code that is stable-ish: tests should pass on all commits
  • the dev branch contains the sum of all hopes/fears, tests may not pass

Resources

About

AnANSI - a bag of collected wisdom for manipulating terminals

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages