# The grid

The grid is a matrix of characters that represents what is seen on a screen. It
has a fixed number of columns (COLS) and lines (LINES) and maintains a current
position (pos) as a single number encoded as "y*COLS+x".

The grid API revolves around the "grid" value, around which all its words are
built. One creates a new grid through "newgrid" (or rather a grid implementation
"new" word) which yield a pointer to a struct compatible with the "grid" value.

The Grid API allows one to write a character at an arbitrary position in the
matrix, through for example "cell! ( c pos -- )". It also supplies
"gridemit ( c -- )" which can be hooked into "EMIT" to have a grid driven
console.

If a NL character ($0a) is emitted, the grid skips to the next line. If a BS
character ($08) is written to it, the cursor goes back one character.

In newline conditions (NL character or wrapping around the end of line), we
clear the next line and move the cursor there. If we're at the end of the
screen, we scroll if the underlying driver allows it. Otherwise, we wrap around
to the top.

The grid is buffered. It maintains a buffer of COLS*LINES characters that
represents what should normally be on screen considering past "cell!" calls.
This buffer allows scrolling without the backend having to read from video
memory, which is often much slower than writing to it. Moreover, "cell!" doesn't
call the backend method if "c" is the same as what is currently in buffer. This
makes scrolling much faster for the empty area of the screen.

This unit also supplies "gridstream ( -- stream )" which yields a struct
compatible with [io/stream] . This stream is write only. Writing to it is like
emitting, but it doesn't move the cursor (it advances "pos" though).

## API

Global fields (bound to "grid"):

COLS
  Width, in characters, of the grid.

LINES
  Height, in characters, of the grid.

pos
  Current position of the cursor

highlight
  Boolean flag indicating whether written cells should be "highlighted".
  Changing this flag doesn't affect existing contents on the screen, only newly
  written content.

buffer
  Pointer to the grid buffer, a COLS*LINES array of characters.

Words:

newgrid ( 'newln 'cursor! 'rawcell! cols lines -- grid )
  Create a new grid with the specifield fields. The three first one are pointers
  to words implementing the words with the corresponding name, described below.

rawcell! ( g pos -- )
  Set content of the cell at "pos" to glyph "g", bypassing buffering. A glyph is
  a 16-bit number with the lower part being the character and b8 being the
  "highlight" flag.

cell! ( c pos -- )
  Set content of the cell at "pos" to character "c". This is a front for
  "rawcell!". Before being sent to "rawcell!", the "highlight" field is combined
  with "c" to form a glyph and the buffer is looked up. If the value is the
  same, "rawcell!" is not called. Otherwise, it is called and the buffer is
  updated.

cursor! ( pos -- )
  Move cursor to "pos".

newln ( oldln -- newln )
  Prepare new line under line number "newln" and return the line number of that
  prepared line as "newln". Normally, "newln" is "oldln+1", but if scrolling is
  involved, then "newln" will be "oldln".

highlight! ( f -- )
  Set "highlight" field to "f".

pcell! ( c -- )
  Set content of the cell at current pos to character "c".

pcell!+ ( c -- )
  Same as pcell! but increases position by one afterwards.

pos! ( pos -- )
  Set current pos to "pos" and update cursor position.

clrline ( ln -- )
  Set all cells in line number "ln" to spaces.

linefeed ( -- )
  Clear a new line below the current one, scrolling if needed, then set pos to
  the beginning of that line

scroll ( -- )
  Read the buffer starting from the second line and for each character, call
  "cell!" for a position that is one line higher.

dbgnum1! ( n -- )
  Spit "n", formatted with ".x", at the top right corner of the screen. Useful
  for debugging purposes. To debug live numbers, you can combine this with
  sys/loop.

dbgnum2! ( n -- )
  Same as dbgnum1!, but one slot to the left.

grid# ( -- )
  Check that a grid is setup and errors out if it's not.

showruler ( -- )
  Fill upper and right edges of the grid in order to easily see its size.