# Grid subsystem

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 is implemented as a IO structure (see doc/sys/io) extending SerialIO.
Its "pos" field is the "cursor" position on the screen and the IO screen
represents the terminal screen: whenever a byte is written to it through the IO
methods, the character is written at cursor position and that cursor is advanced
by one.

If a NL character ($0a) is written to it, 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 subsystem defines the Grid structure as well as a "grid" structbind to
it. During initialization, what you'll want to do is create an instance of the
Grid from the driver and bind it to "grid".

## Spit mode

Sometimes, we want to write things to screen that are at a position other than
the cursor and we don't want to update the cursor while writing there. Moreover,
we don't want the special handling of the regular mode (newline handling). One
such example is the ":dbgnum1!" word.

In these cases, you'll want to enable the "spit" mode with ":spiton", do your
thing, then go back to regular mode with ":spitoff".

## Driver implementation

To implement the grid, we need an underlying driver to extend it and implement
its methods, namely:

:cell! ( c pos self -- )
  Set content of the cell at "pos" to character "c". Should honor the
  "highlight" flag.

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

:newln ( oldln self -- 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".

## Grid API

Fields:

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.

Words:

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

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

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

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

:spiton ( pos self -- )
  Enable "spit mode" starting at position "pos". This doesn't affect regular
  position.

:spitoff ( self -- )
  Disable "spit mode".

:dbgnum1! ( n self -- )
  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 self -- )
  Same as :dbgnum1!, but one slot to the left.

## Other words

gridtest ( -- )
  Fill the grid with characters between $20 and $60 by calling :cell!
  repeatedly, alternating the "highlight" flag on each line.
