class TermBuf::Grid

Overview

A rectangular array of cells.

Cells live in one flat slice, so a row is a contiguous Slice view and scrolling is a run of memmoves. Alongside them the grid keeps a hash per row, recomputed lazily, which is what lets the painter recognise a scrolled band without comparing cells.

The grid is the only place that knows a wide character occupies two cells, and it never lets those two get out of step: writing to either half blanks both first.

Defined in:

termbuf/core/grid.cr

Constant Summary

FNV_OFFSET = 14695981039346656037_u64
FNV_PRIME = 1099511628211_u64

Constructors

Instance Method Summary

Constructor Detail

def self.new(width : Int32, height : Int32, blank : Cell = Cell.blank) #

[View source]

Instance Method Detail

def ==(other : Grid) : Bool #

Whether both grids hold the same cells. Damage is not compared: it says what has yet to be painted, not what is on the screen.


[View source]
def [](x : Int32, y : Int32) : Cell #

The cell at (x, y). Raises if it is off the grid.


[View source]
def []=(x : Int32, y : Int32, cell : Cell) : Nil #

Writes one cell without regard for wide character pairing. Callers that place characters want #place; this is for filling, scrolling, and the internals of #place itself.


[View source]
def []?(x : Int32, y : Int32) : Cell | Nil #

The cell at (x, y), or nil if it is off the grid.


[View source]
def bounds : Rect #

The rectangle covering every cell.


[View source]
def clear(cell : Cell = Cell.blank) : Nil #

Sets every cell of the grid to cell.


[View source]
def clip_wide(rect : Rect, blank : Cell = Cell.blank) : Nil #

Blanks any wide character straddling the left or right edge of rect, so that filling or scrolling the rectangle cannot tear one in half.


[View source]
def contains?(x : Int32, y : Int32) : Bool #

Whether (x, y) is on the grid.


[View source]
def copy_from(other : Grid) : Nil #

Replaces this grid's contents with other's, which must be the same size. Used to bring the front buffer up to date once a paint has been written to the terminal.


[View source]
def damage : Damage #

Which rows have changed, and over what span.


[View source]
def detach(x : Int32, y : Int32, blank : Cell = Cell.blank) : Nil #

Blanks both halves of the wide character overlapping column x, if one does. A cell that is neither half of a pair is left alone.


[View source]
def fill(rect : Rect, cell : Cell) : Nil #

Sets every cell of rect to cell.


[View source]
def height : Int32 #

Rows down.


[View source]
def place(x : Int32, y : Int32, cell : Cell, blank : Cell = Cell.blank) : Int32 #

Places cell at (x, y), blanking the other half of any wide character it displaces. Returns the columns consumed, or zero when a wide character will not fit before the right edge and nothing was written.


[View source]
def resize(width : Int32, height : Int32, blank : Cell = Cell.blank) : Nil #

Resizes the grid, keeping whatever content still fits anchored at the top left and filling the rest with blank. Every cell is left marked dirty: the terminal's own reflow is not something the buffer can predict, so the next paint has to be a full one.


[View source]
def row(y : Int32) : Slice(Cell) #

The cells of row y, as a view into the grid's own storage.


[View source]
def row_hash(y : Int32) : UInt64 #

FNV-1a hash of row y, recomputed only when the row has been written to since it was last asked for.


[View source]
def row_span(rect : Rect, y : Int32) : Slice(Cell) #

The cells of row y within rect's columns.


[View source]
def scroll(rect : Rect, lines : Int32, blank : Cell = Cell.blank, & : Slice(Cell) -> ) : Nil #

Moves the contents of rect by lines rows, positive scrolling up so that content moves toward the top and blank rows appear at the bottom.

Each row that leaves the rectangle is yielded before being overwritten. The yielded slice is a view into the grid, valid only until the block returns, so a consumer keeping the row must copy it.


[View source]
def scroll(rect : Rect, lines : Int32, blank : Cell = Cell.blank) : Nil #

Scrolls without inspecting the rows that leave.


[View source]
def to_text(pool : ClusterPool = ClusterPool.new) : String #

Renders the grid as text, one line per row, for specs and debugging. Continuation cells contribute nothing, so a wide character appears once.


[View source]
def width : Int32 #

Columns across.


[View source]