Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/lpeterse/haskell-terminal

Haskell library for terminal interaction (without terminfo dependency but with Windows support)
https://github.com/lpeterse/haskell-terminal

ansi console ghc haskell terminal

Last synced: about 1 month ago
JSON representation

Haskell library for terminal interaction (without terminfo dependency but with Windows support)

Awesome Lists containing this project

README

        

terminal [![Hackage](https://img.shields.io/github/release/lpeterse/haskell-terminal.svg)](https://github.com/lpeterse/haskell-terminal/releases) [![Travis](https://img.shields.io/travis/lpeterse/haskell-terminal.svg)](https://travis-ci.org/lpeterse/haskell-terminal)
=======================

_terminal_ is a driver library for ANSI terminals like _xterm_.

## Features

- Abstract monadic interfaces for different concerns: Write code that is only allowed to print
to the screen using the `MonadColorPrinter m => m ()` constraint!
- A monad transformer `TerminalT` which implements all of the interfaces.
Either use it directly or include it in your monad transformer stack and lift/derive
the functions you need.
- Unicode support by design (assuming all terminals understand UTF-8; Windows support is implemented separately).
- Supports the `Text` instead of `String` movement without being to radical about it.
- Windows support:
- Windows 10 finally supports ANSI escape sequences and the _Windows Console_ now essentially
behaves like an _xterm_.
- Windows 8, Windows 7 and older is not supported. Windows 7's support officially ended in 2015 and
the extended support will end in 2020. As this is a hobby project aiming at
enthusiasts, I have no intention to bloat this code base with all the quirks necessary
to make it work on older versions of Windows.
- Unicode is fully supported on Windows for input and output and independant of unreliably
hacks like changing the code page. A Unicode compatible console font needs to be configured.
- A very small set of dependencies, most of which are likely to be included
in every Haskell project anyway.
- No dependency on terminfo (see below).
- Rich event handling (partly inspired by _vty_):
- Keyboard events (all control codes and escape sequences are mapped to a useful set of keys and modifiers).
- Mouse events (TODO on Linux).
- Screen resize events.
- Window focus events.
- Interrupt events.
- Event handling is implemented using [STM](https://hackage.haskell.org/package/stm) instead of `IO`
which makes it very easy to wait for several events simultaneously or combine it
with custom or external events like timeouts.
- Proper signal handling (Ctrl+C):
- When using the standard terminal, the library will hook the
interrupt signal (or something equivalent e.g. on Windows).
Incoming interrupts are passed to the application code and can be
dispatched and processed. A supervisor thread assures that the application
gets killed on a second interrupt when the application is non-responsive.
This resembles the default behavior of GHC's RTS and a lot of work has been
invested to make this mechanism work reliably.
- Integrates the relatively new [prettyprinter](https://hackage.haskell.org/package/prettyprinter)
library. Nicely formatted and colorful output requires nothing more than a few combinators.

## To use or not to use _terminfo_

The [terminfo](https://hackage.haskell.org/package/terminfo) library is a binding to
[libtinfo](https://en.wikipedia.org/wiki/Terminfo).

_libtinfo_ is a library that queries a database (usually below `/usr/share/terminfo`)
to determine the specifica and necessary control codes for interacting with a given
terminal.

Unfortunately, it is a reocurring source of issues:

- https://github.com/commercialhaskell/stack/issues/1012
- https://github.com/purescript/purescript/issues/2176
- https://ghc.haskell.org/trac/ghc/ticket/8746?cversion=0&cnum_hist=2
- https://ghc.haskell.org/trac/ghc/ticket/13210

Arguments in favor of _terminfo_:

- Would allow to support all terminals in existence.
- It's "the standard".

Arguments against _terminfo_:

- Static linking and stand-alone binaries:
Apart from eventual linking issues, _terminfo_ has a runtime dependency on the
terminfo database. This might be an issue when the environment is restricted
(`chroot` environment or if the process shall not be allowed to interact with the file
system for security reasons).
- _terminfo_ offers more than 500 capabilities. Only a very small part of it
is actually needed and since there is no legacy code to support there is no
real reason to expose more than a small subset of capabilities that is supported
by all terminals (-> ANSI sequences).
- Claim: All relevant terminals support and understand the relevant ANSI escape sequences
and/or try to behave like _xterm_. Terminals that don't are not relevant.
- Is it really necessary to support something like _tvi925_ (Televideo 925, around 1982)?
I honor that _terminfo_ takes the burden to maintain the definition files
for such historical hardware, but I doubt that anyone would miss it if we decide not
to support it.

For now, I decided to not use _terminfo_ and see how well it works.
This decision might be revised in the future. The API won't be affected by it.

## How _terminal_ compares to..

### ansi-terminal

- [ansi-terminal](https://hackage.haskell.org/package/ansi-terminal)
offers very similar primitives for printing to the terminal
and controlling the cursor.
- It also achieves doing this in portable way (very good Windows support,
no _terminfo_ requirement on Linux/Posix).
- It doesn't offer mechanisms for event processing.
- Its operations live in `IO` (control code output is possible as well)
and assume that the terminal is either connected to `stdin/stdout` or
to a handle.

### ansi-wl-pprint

- [ansi-wl-pprint](https://hackage.haskell.org/package/ansi-wl-pprint) is an
extension library to _ansi-terminal_. It offers a Wadler-Leyen pretty-printer
adapted to the needs of terminal screens (colors and text formatting).
- _terminal_ has a dependency on the more generic
[prettyprinter](https://hackage.haskell.org/package/prettyprinter) in order
to offer the same features and make pretty and colorful terminal output
the default rather than an exception.

### Haskeline

- [haskeline](https://hackage.haskell.org/package/haskeline) is a pure-Haskell
[readline](https://en.wikipedia.org/wiki/GNU_Readline) replacement.
- Its primary job is offering a line editing interface and it does this very well.
- Like _terminal_ it offers a monad transformer interface to the user (`InputT`).
- It does signal handling (Ctrl+C, Ctrl+D).
- It has a dependency on _terminfo_ in order to support a broad range of terminals
(especially those that are non-ANSI).
- It offers operations for printing to the terminal which pass control codes
unescaped.
- It might be interesting to investigate whether _terminal_ could be used
as an alternative backend for _haskeline_.

### vty

- [vty](https://hackage.haskell.org/package/vty) is a library that serves
as a foundation for _curses_-like applications (full-screen terminal applications
like `vim` or `htop`).
- It is very similar to `terminal` (especially the event processing has been inspired
by _vty_): It completely abstracts away the details and quirks of
communication with different terminals and offers a canonical interface to the user.
- Its scope is wider than that of _terminal_:
- _vty_ has the concept of `Images` that can be assembled and manipulated by the user.
The library keeps track of the changes and computes minimal changesets which it
then transmits to the terminal.
- Compared to _terminal_ it (currently) has the following shortcomings:
- Lack of Windows support (there has been
[a call to arms](https://www.reddit.com/r/haskell/comments/7tutxa/vty_needs_your_help_supporting_windows/) recently;
I'd be happy if my findings with _terminal_ could help improve the situation with _vty_).
- Dependency on `terminfo`.
- No proper signal handling.

### brick

- [brick](https://hackage.haskell.org/package/brick) is library on top of _vty_. Its
scope is different from what _terminal_ does.