nsys-curses-utils 0.1.0

Rust *curses utilities
Documentation
# `curses_utils`

## `libncurses`

ncurses represents the *terminal screen* using two data structures:

- a *physical screen* -- what is "actually" on the screen
- a *virtual screen* -- what is *intended* to be on the screen

a *window* is a two-dimensional array of characters representing all or *part*
of the terminal screen

*characters* in a window are of type `chtype` containing character *and*
attribute data;
on a 64-bit system, a `chtype` will be a 64-bit unsigned integer

there is also a type alias for `chtype`, `attr_t`

in ncurses there is a *default window* called `stdscr` that is the size of the
terminal screen


**Defines**

`#define NCURSES_ATTR_SHIFT 8` -- bitshift to start of attribute bits

`#define NCURSES_BITS (mask, shift) ...` -- takes a `chtype` mask and
*left-shifts* it by `NCURSES_ATTR_SHIFT + shift`

`#define COLOR_PAIR (n) ...` -- takes a color pair number and shifts it into a
`chtype` using `NCURSES_BITS (n, 0)`, and masks the result with `A_COLOR` to
clear out any bits outside of the color byte

`#define PAIR_NUMBER (attr) ...` -- inverse of `COLOR_PAIR`, masking the color
byte of a chtype with `A_COLOR` and shifting it into a color pair number


**Functions**

`initscr()` -- initializes the curses system, allocates the `stdscr`, and
refreshes the screen; this is equivalent to:

```
newterm(getenv("TERM"), stdout, stdin);
return stdscr;
```

and must be called before any other screen manipulation functions

`wnoutrefresh(WINDOW*)` copies named window to the virtual screen

`doupdate()` compares virtual screen to physical screen and does the "actual
update"

`wrefresh(WINDOW*)` equivalent to calling `wnoutrefresh` followed by `doupdate`
(`wnoutrefresh`), then *compares* the virtual screen to the physical screen and
does the update (`doupdate`)

`refresh()` equivalent to `wrefresh(stdscr)`

`border()`

`box()` calls `border()` with given top/bottom and left/right edges and
corners


**Global variables**

`int COLORS` -- number of colors supported by terminal; this is `256` on a
256-color terminal

`int COLOR_PAIRS` -- number of color pairs supported by terminal; this is `256`
on a 256-color terminal

`int COLS`

`int LINES`

`WINDOW* stdscr`


## `ncurses`

Rust bindings to libncurses

most of the C interface should be exposed in this crate

note that as the libncurses interface uses a number of `#define`s, they are
recreated in this crate as const functions

`lib.rs`:

- `const fn NCURSES_BITS (mask:u32, shift:u32) -> u32`
- `const fn A_NORMAL() -> attr_t`
- `const fn A_ATTRIBUTES() -> attr_t`
- ...

`COLOR_PAIR(n)` is recreated as a function, but it is not a const function:

- `fn COLOR_PAIR (n : i16) -> attr_t`

note that `PAIR_NUMBER` is a safe wrapper over an `ll` raw function

in `ll.rs`, a number of typedefs are made and `extern "C"` functions are
declared that will link to libncurses; these are called in the wrapper functions
defined elsewhere in the crate

in `constants.rs` some more constants are defined (the contents of this module
are re-exported at the crate root):

- `const ERR : i32 = -1`
- `const OK  : i32 =  0`
- `const NCURSES_ATTR_SHIFT : u32 = 8`
- `const COLOR_BLACK : i16 = 0`
- `const COLOR_RED   : i16 = 1`
- ...

some `extern "C"` global variables are also wrapped in `constants.rs`:

- `static stdscr      : WINDOW`
- `static COLORS      : c_int`
- `static COLOR_PAIRS : c_int`
- `static LINES       : c_int`
- `static COLS        : c_int`
- ...


## `pancurses`

pancurses provides a cross-platform curses library using `ncurses` for Linux and
`pdcurses` on Windows; most of the method names are the same, and on Linux, it
seems to mostly call raw `ncurses::ll` functions instead of the "safe" `ncurses`
wrapped functions

pancurses re-defines a number of constants from `ncurses`, such at `OK`,
`ERR`, `COLOR_BLACK`, `A_ATTRIBUTES`, etc., and some const funtions like
`NCURSES_BITS(mask,shift)` (private) and `COLOR_PAIR(n)` (public)


**Traits**

`trait ToChtype` -- trait with a single `to_chtype (&self) -> chtype` method;
this is only implemented for `char` as a primitive cast (`as chtype`), and
for `chtype` itself


**Structs**

`Window` -- contains a pointer to the backend `WINDOW` pointer, and a couple
flags to indicate if it is the `stdscr` or a deleted window; methods:

- `window.noutrefresh()` -- copies touched lines to the virtual screen;
  equivalent to `ncurses::wnoutrefresh (window)`
- `window.refresh()` -- copies window to the physical screen; must be called to
  get output to terminal; equivalent to `ncurses::wrefresh(window)`
- `window.touch()` -- sets entire window as touched
- `window.untouch()` -- unset the entire window as touched
- ...

`Attributes { chtype, ColorPair }` -- an attributes builder; can be converted
`Into<chtype>`

`ColorPair (u8)`


**Enums**

`Attribute`

`Input`


**Functions**

note that `ncurses::refresh()` is not exported; instead call `refresh()` on the
initial `Window` representing the `stdscr`

`initscr() -> Window` -- initialize the curses system and return the `stdscr`
window

`doupdate()` -- compare virtual screen to physical screen and perform update of
the physical screen; this should be called once per frame; if there is only one
window in use, instead calling the `refresh()` method on that window will
automatically call `doupdate()` after first calling `noutrefresh()` on that
window

`curs_set(i32)` -- set cursor visibility (`0` invisible, `1` visible, `2` very
visible)

`endwin()`


## `easycurses`

re-exports `pancurses::Input` as `easycurses::Input`


**Structs**

```
struct EasyCurses {
    pub win       : pancurses::Window
    auto_resize   : bool = true
    color_support : bool
}
```
-- ; methods:

- `set_color_pair (&mut self, ColorPair)` -- calls
  `pancurses::Window::color_set` with the color pair number contained in the
  color pair; with the ncurses backend, this will set the color in the attribute
  returned by `pancurses::Window.attrget()`, but not with PDCurses, i.e. the
  second byte is always `0x0`-- however in *both* backends, the color pair
  number will be returned in the right member of the tuple returned by
  `pancurses::Window.attrget()`, so the preferred way to clear the screen with
  the current window `color` would be to construct the attribute with
  `color_pair(color)` supplied in the argument to `bkgd` or `bkgdset`

`struct ColorPair (i16)` -- uses an internal function `fgbg_pairid` to combine
a pair of foreground and background color numbers into a *color pair* number,
using the formula:

`1 + (8 * fg + bg)`

during intialization, each fg/bg combination of the 8 base colors are
initialized for a total of `8 * 8 = 64` colors, using the above formula gives
color pairs numbered from `1` to `64`; it should be noted that this will not
work on a terminal that supports *only* 64 colors, since color `0` is
technically reserved for white/black, the maximum allowed color pair would be
`63`


**Enums**

`Color` -- an enumeration convertible to `i16` color numbers (i.e.
`COLOR_BLACK`, `COLOR_RED`, etc.)


**Functions**

`initialize_system() -> EasyCurses` -- initializes the curses system through
`pancurses::initscr()` and subsequently sets up the colors


## `Curses`

Newtype wrapping an `EasyCurses` window.

The `new()` creation method will construct an `EasyCurses` window with the
following settings:

- Hidden cursor
- No input echo
- No line buffering (immediate input mode)

There are a number of methods to get input which will set the input mode
as needed, depending on the type of input:

- `getch_wait() -> Option<pancurses::Input>` -- get single character, block
  indefinitely
- `getch_timeout(timeout) -> Option<pancurses::Input>` -- get single character,
  block until timeout
- `getch_nowait() -> Option<pancurses::Input>` -- get single character, returns
  immediately if no input is waiting
- `getline_wait() -> Option<pancurses::Input>` -- get line, block indefinitely
- `getline_nowait() -> Option<pancurses::Input>` -- get line, returns
  immediately if no input is waiting

The newly created window (the `stdscr`) will have attributes `A_NORMAL = 0`, and
background `chtype` of `(A_NORMAL | ' ' as chtype)`.


## Utility functions

`curses_utils` defines a few utility functions for working with curses `chtype`s
(attributes + character data):

- `color_pair_number (fg, bg) -> i16` -- gives the color pair number that
  `easycurses` uses to identify the fg/bg combination
- `character (chtype) -> char` -- returns the first byte of the `chtype` (the
  character data), cast to a `char`
- `color_pair (chtype) -> i16` -- returns the second byte of the `chtype` (the
  color pair number), cast to an `i16`


## Colors

ncurses:

- `PAIR_NUMBER (attr : i32) -> i32` -- inverse of `COLOR_PAIR`: masks out the
  color byte and right-shifts into a color pair number

Pancurses:

- `fn COLOR_PAIR (n : chtype) -> attr_t` -- turns a color pair number into an
  attribute (left-shifts by 8 bits and masks the color byte)
- `window.attrget() -> (attrs, color_pair : i16)` -- this returns the current
  window attributes (including the color attribute), along with the color pair
  number corresponding to the color attribute, equal to `PAIR_NUMBER(attrs)`
- `window.color_set (color_pair : i16)` -- change the color attribute to the
  given color pair number, equal to `COLOR_PAIR(color_pair)`
- `window.chgat (n, attrs, color_pair : i16)`
- `window.mvchgat (y, x, n, attrs, color_pair : i16)`
- `ColorPair (u8)` -- this type only appears to be used by the `Attribute`
  builder type; it is the color number which will be set in the 2nd byte of the
  attribute `chtype`
- `attributes.color_pair() -> ColorPair` -- get color pair of an attribute
  builder
- `attributes.set_color_pair(color_pair : ColorPair)` -- set color pair of an
  attribute builder

Easycurses:

- `Color` -- an enumeration of base colors that can be converted to `i16` color
  numbers
- `ColorPair (i16)` -- easycurses defines a color pair number by the formula
  `1 + 8*fg + bg`, giving a range of color pair numbers from 1-64
- `easycurses.set_color_pair (color_pair : ColorPair)`

the `easycurses::ColorPair` type is only used as the argument to the
`set_color_pair` method; as a convenience, `curses_utils` defines a function
`color_pair_number` which applies the above formula and returns a raw `i16`, so
that it can be used in other places where a color pair number is needed


## Attributes

`pancurses::Window::attrset (chtype)` -- sets the current window attributes; if
there is any character data here it will be "combined" with all inputs

`pancurses::Window::bkgdset (chtype)` -- sets the current window "background"
`chtype`; inserted text will be "combined" with the attributes set in this
variable, and any blank characters (spaces) will show the background character
data, if any; note that this function does not immediately change any window
contents, to fill the window with the background use `erase` or `bkgd`

`pancurses::Window::bkgd (chtype)` -- sets the current background and
immediately *applies* it to all cells in the window; note that this will copy
the background character into blank cells (spaces), but will not clear cells
with existing character data


## Drawing

`pancurses::Window::erase()` -- copies blanks to every cell of the window, in
combination with the background `chtype`

`pancurses::Window::clearok(bool)` -- if true, the next time this window calls
`window.refresh()`, *the entire screen will clear and re-draw*

`pancurses::Window::clear()` -- equivalent to `window.erase()` followed by
`window.clearok(true)`

`easycurses::Easycurses::clear()` -- just calls pancurses `window.clear()`
internally

`pancurses::Window::noutrefresh()` -- copies the window to the *virtual screen*

`pancurses::doupdate()` -- compares the virtual screen to the physical screen
and copies updated portions to the physical screen

`pancurses::Window::refresh()` -- equivalent to `window.noutrefresh()` followed
by `doupdate()`

`pancurses::Window::addch(chtype)` -- "adds" the chtype (attribute + character
data) to the window; note that if the cursor is moved past the end of the window
(i.e. the cursor was at `(ncurses::LINES()-1, ncurses::COLS()-1)`, then this
function will return '-1' (`pancurses::ERR`), but the character will still be
drawn-- this is also true for `addstr` and `printw`

`pancurses::Window::chgat(n:i32, ch:chtype, color_pair:i16)` -- "changes" `n`
consecutive characters to the given chtype and color pair number; this method
"*combines*" the character data with the current character data at the target
using a bitwise OR operation;
note that only character data and *non-color attributes* are taken from the
chtype argument-- a color number needs to be given in the color pair argument.

`pancurses::Window::hline/vline` -- note that this will return `-1` on windows
if called with `ncols=0`

... TODO: box drawing functions


## Inspecting

`pancurses::Window::mvinch (row:i32, col:i32) -> chtype` -- returns the rendered
chtype at the given position, or else returns `-1` (0xFFFFFFFF)