## The TextBuffer
A *textBuffer* is a buffer holding text contents that can be used for things like *text areas*, or even *text editors*.
A *textBuffer* is way more flexible than a raw *screenBuffer* for that purpose.
Nonetheless, a *textBuffer* is always backed by a [*screenBuffer*](ScreenBuffer.md#top), i.e. its *dst* (destination)
should be a *screenBuffer*.
Internally, it has 3 buffers:
* a buffer holding raw text (line of text): *raw text buffer*
* a buffer holding attributes (colors, styles): the *attr buffer*
* a misc buffer holding userland data, useful for your application: the *misc buffer*
It comes with a lot of facilities to interact with the text, to manage the cursor, to colorize the text, to manage tabs...
**Note:** The *TextBuffer* is still in *beta*, some methods are missing but the existing API should be **stable**
or remain **backward compatible**.
If you wonder what can be done with *textBuffers*, have a look to [Neon](https://www.npmjs.com/package/ne),
a small text-editor in early alpha stage, featuring a javascript syntax hilighter.
## Table of Contents
* Constructor and static methods:
* [TextBuffer()](#ref.TextBuffer.new)
* [TextBuffer.create()](#ref.TextBuffer.create)
* Properties:
* [.x](#ref.TextBuffer.xy)
* [.y](#ref.TextBuffer.xy)
* Methods:
* [.getText()](#ref.TextBuffer.getText)
* [.setText()](#ref.TextBuffer.setText)
* [.getHidden()](#ref.TextBuffer.getHidden)
* [.setHidden()](#ref.TextBuffer.setHidden)
* [.getContentSize()](#ref.TextBuffer.getContentSize)
* [.getCursorOffset()](#ref.TextBuffer.getCursorOffset)
* [.setCursorOffset()](#ref.TextBuffer.setCursorOffset)
* [.setEmptyCellAttr()](#ref.TextBuffer.setEmptyCellAttr)
* [.setAttrAt()](#ref.TextBuffer.setAttrAt)
* [.setAttrCodeAt()](#ref.TextBuffer.setAttrCodeAt)
* [.setAttrRegion()](#ref.TextBuffer.setAttrRegion)
* [.setAttrCodeRegion()](#ref.TextBuffer.setAttrCodeRegion)
* [.getMisc()](#ref.TextBuffer.getMisc)
* [.getMiscAt()](#ref.TextBuffer.getMiscAt)
* [.moveTo()](#ref.TextBuffer.moveTo)
* [.moveToColumn()](#ref.TextBuffer.moveToColumn)
* [.moveToLine(), .moveToRow()](#ref.TextBuffer.moveToLine)
* [.move()](#ref.TextBuffer.move)
* [.moveUp()](#ref.TextBuffer.moveUp)
* [.moveDown()](#ref.TextBuffer.moveDown)
* [.moveLeft()](#ref.TextBuffer.moveLeft)
* [.moveRight()](#ref.TextBuffer.moveRight)
* [.moveForward()](#ref.TextBuffer.moveForward)
* [.moveBackward()](#ref.TextBuffer.moveBackward)
* [.moveToStartOfWord()](#ref.TextBuffer.moveToStartOfWord)
* [.moveToEndOfWord()](#ref.TextBuffer.moveToEndOfWord)
* [.moveToStartOfLine()](#ref.TextBuffer.moveToStartOfLine)
* [.moveToEndOfLine()](#ref.TextBuffer.moveToEndOfLine)
* [.moveToStartOfBuffer()](#ref.TextBuffer.moveToStartOfBuffer)
* [.moveToEndOfBuffer()](#ref.TextBuffer.moveToEndOfBuffer)
* [.moveInBound()](#ref.TextBuffer.moveInBound)
* [.insert()](#ref.TextBuffer.insert)
* [.prepend()](#ref.TextBuffer.prepend)
* [.append()](#ref.TextBuffer.append)
* [.delete()](#ref.TextBuffer.delete)
* [.backDelete()](#ref.TextBuffer.backDelete)
* [.newLine()](#ref.TextBuffer.newLine)
* [.joinLine()](#ref.TextBuffer.joinLine)
* [.iterate()](#ref.TextBuffer.iterate)
* [.wrapLine()](#ref.TextBuffer.wrapLine)
* [.wrapAllLines()](#ref.TextBuffer.wrapAllLines)
* [.draw()](#ref.TextBuffer.draw)
* [.drawCursor()](#ref.TextBuffer.drawCursor)
* [.load()](#ref.TextBuffer.load)
* [.save()](#ref.TextBuffer.save)
### new TextBuffer( options )
* options `Object`, where:
* dst: `ScreenBuffer` the destination to write on
* width `integer` (optional, default: Infinity) width, i.e. max-length of a line
* height `integer` (optional, default: Infinity) height, i.e. maximum number of lines
* x: `integer` (optional) default x-position in the dst
* y: `integer` (optional) default y-position in the dst
* tabWidth: `integer` (optional, default: 4) set the tabulation width
* forceInBound: `integer` (optional, default: false) if true, the cursor cannot move out of bounds
* hidden: `boolean` (optional, default: false) if true, the text is invisible
* wrap: `boolean` (optional, default: false) set the wrapping behavior
This creates a TextBuffer instance with the appropriate options.
### TextBuffer.create( options )
DEPRECATED, use [new TextBuffer()](#ref.TextBuffer.new) instead.
### .x , .y
Those properties are respectively the x and the y coordinate, in the *dst* (destination), where the *textBuffer*
should be drawn.
This can be overriden when invoking *.draw()*.
### .getText()
It extracts and returns the text content of the *textBuffer*.
### .setText( text , [ [markup] , baseAttr ] )
* text `string` the text content
* markup `boolean` or 'ansi', true if the text contains markup that should be interpreted
'ansi' if it contains *ANSI* code (default: false - raw text)
* baseAttr `object` or `integer`, an attribute used as the base attribute for the text content
(if there is markup, the markup attributes are *stacked* with this base attribute)
This set the text content of the *textBuffer*.
It reset both the *attr buffer* (or set it to the correct attribute if there is markup) and the *misc buffer*.
For the *markup* option, see also [the full style markup reference](markup.md#top).
### .getHidden()
It returns *true* if the *textBuffer* is in *hidden mode*.
### .setHidden( state )
* state `boolean` if true, it enables the *hidden mode*, else it disables it
It set on or off the *hidden mode*.
The *hidden mode* is useful if your *textBuffer* is holding things like password.
### .getContentSize()
It returns an object with a *width* and *height* properties: the size of the text content.
### .getCursorOffset()
It returns the cursor offset in the raw text content.
### .setCursorOffset( offset )
* offset `integer` the new offset of the cursor
It set the cursor offset in the raw text content.
### .setEmptyCellAttr( attr )
* attr `Object` or `integer` attributes of the chars (attribute object or bit flags,
see: [the attribute object](ScreenBuffer.md#ref.ScreenBuffer.attributes))
This set the attributes for empty cells, i.e. cells in the *screenBuffer* where there is no *textBuffer* content (not even spaces).
### .setAttrAt( attr , x , y )
* attr `Object` or `integer` attributes of the char (attribute object or bit flags,
see: [the attribute object](ScreenBuffer.md#ref.ScreenBuffer.attributes))
* x `integer` the x-coordinate (i.e. the column number)
* y `integer` the y-coordinate (i.e. the row number)
This set the attributes for the *textBuffer* cell at *(x,y)* coordinates.
### .setAttrCodeAt( attr , x , y )
* attr `integer` attributes of the char in the bit flags form
* x `integer` the x-coordinate (i.e. the column number)
* y `integer` the y-coordinate (i.e. the row number)
Like [.setAttrAt()](#ref.TextBuffer.setAttrAt), but it only accepts attributes in the bit flags form (faster).
### .setAttrRegion( attr , [region] )
* attr `Object` or `integer` attributes of the char (attribute object or bit flags,
see: [the attribute object](ScreenBuffer.md#ref.ScreenBuffer.attributes))
* region `Object` (optional, default to the whole *textBuffer*) the targeted rectangular region, where:
* xmin `integer` the minimal x-coordinate
* xmax `integer` the maximal x-coordinate
* ymin `integer` the minimal y-coordinate
* ymax `integer` the maximal y-coordinate
This set the attributes for the *textBuffer* cells in the rectangular *region* (if specified), or all cells of the *textBuffer*.
### .setAttrCodeRegion( attr , [region] )
* attr `integer` attributes of the char in the bit flags form
* region `Object` (optional, default to the whole *textBuffer*) the targeted rectangular region, where:
* xmin `integer` the minimal x-coordinate
* xmax `integer` the maximal x-coordinate
* ymin `integer` the minimal y-coordinate
* ymax `integer` the maximal y-coordinate
Like [.setAttrRegion()](#ref.TextBuffer.setAttrRegion), but it only accepts attributes in the bit flags form (faster).
### .getMisc()
Get the *misc* meta data at the current cursor position.
### .getMiscAt( x , y )
* x `integer` the x-coordinate (i.e. the column number)
* y `integer` the y-coordinate (i.e. the row number)
Get the *misc* meta data at the *(x,y)* coordinates.
### .moveTo( x , y )
* x `integer` the x-coordinate (i.e. the column number)
* y `integer` the y-coordinate (i.e. the row number)
It moves the *textBuffer*'s cursor to the *(x,y)* coordinates.
### .moveToColumn( x )
* x `integer` the x-coordinate (i.e. the column number)
It moves the *textBuffer*'s cursor to the *xth* column.
### .moveToLine( y ) , .moveToRow( y )
* y `integer` the y-coordinate (i.e. the row number)
It moves the *textBuffer*'s cursor to the *yth* row/line.
### .move( x , y )
* x `integer` the **relative** x-coordinate (i.e. the column number)
* y `integer` the **relative** y-coordinate (i.e. the row number)
Like [.moveTo()](#ref.TextBuffer.moveTo), but it moves the *textBuffer*'s cursor relative to its current position.
### .moveUp()
It moves the *textBuffer*'s cursor one cell up.
### .moveDown()
It moves the *textBuffer*'s cursor one cell down.
### .moveLeft()
It moves the *textBuffer*'s cursor one cell left.
### .moveRight()
It moves the *textBuffer*'s cursor one cell right.
### .moveForward( justSkipNullCells )
* justSkipNullCells `boolean`
It moves the *textBuffer*'s cursor one *character* forward, different form [.moveRight()](#ref.TextBuffer.moveRight),
since it would move the cursor at the begining of the next line if it was on the last character of a line.
It always skips *null cells*.
*Null cells* are produced by tabulation: there is only one *text character* but followed by *n null cells*
that are not part of the actual text content.
If *justSkipNullCells* is set, it does not move forward unless the cursor is over a *null cell*.
### .moveBackward( justSkipNullCells )
* justSkipNullCells `boolean`
It moves the *textBuffer*'s cursor one *character* backward, different form [.moveLeft()](#ref.TextBuffer.moveLeft),
since it would move the cursor at the end of the previous line if it was on the first character of a line.
It always skips *null cells*.
*Null cells* are produced by tabulation: there is only one *text character* but followed by *n null cells*
that are not part of the actual text content.
If *justSkipNullCells* is set, it does not move backward unless the cursor is over a *null cell*.
### .moveToStartOfWord()
It moves the *textBuffer*'s cursor to the start of the current word.
### .moveToEndOfWord()
It moves the *textBuffer*'s cursor to the end of the current word.
### .moveToStartOfLine()
It moves the *textBuffer*'s cursor to the begining of the current line.
### .moveToEndOfLine()
It moves the *textBuffer*'s cursor to the end of the current line.
### .moveToStartOfBuffer()
It moves the *textBuffer*'s cursor to the begining of the buffer (i.e. the begining of the first line).
### .moveToEndOfBuffer()
It moves the *textBuffer*'s cursor to the end of the buffer (i.e. the end of the last line).
### .moveInBound( ignoreCx )
* ignoreCx `boolean` do not affect the cursor's x-coordinate
It moves the *textBuffer*'s cursor in bound, i.e. to a cell that has text content.
### .insert( text , [ [markup] , attr ] )
* text `string` the raw text to insert
* markup `boolean` or 'ansi', true if the text contains markup that should be interpreted
'ansi' if it contains *ANSI* code (default: false - raw text)
* attr `Object` or `integer` (optional, default: the empty cell attributes) attributes of the text about to be inserted
(attribute object or bit flags, see: [the attribute object](ScreenBuffer.md#ref.ScreenBuffer.attributes))
It inserts the text at the current cursor position, with the given attributes.
### .prepend( text , [ [markup] , attr ] )
* text `string` the raw text to insert
* markup `boolean` or 'ansi', true if the text contains markup that should be interpreted
'ansi' if it contains *ANSI* code (default: false - raw text)
* attr `Object` or `integer` (optional, default: the empty cell attributes) attributes of the text about to be inserted
(attribute object or bit flags, see: [the attribute object](ScreenBuffer.md#ref.ScreenBuffer.attributes))
It prepend the text (i.e. insert it at the begining), with the given attributes.
### .append( text , [ [markup] , attr ] )
* text `string` the raw text to insert
* markup `boolean` or 'ansi', true if the text contains markup that should be interpreted
'ansi' if it contains *ANSI* code (default: false - raw text)
* attr `Object` or `integer` (optional, default: the empty cell attributes) attributes of the text about to be inserted
(attribute object or bit flags, see: [the attribute object](ScreenBuffer.md#ref.ScreenBuffer.attributes))
It append the text (i.e. insert it at the end), with the given attributes.
### .delete( [n] )
* n `integer` (optional, default: 1) the number of chars to delete
It deletes *n* characters at the current cursor position.
This is the action usually bound to the *delete* key.
### .backDelete( [n] )
* n `integer` (optional, default: 1) the number of chars to delete
It deletes *n* characters **backward** starting from the current cursor position.
This is the action usually bound to the *backspace* key.
### .newLine()
It inserts a new line at the current cursor position.
It will split the current line in two, if there are characters at/after the current cursor position.
### .joinLine()
It moves the cursor to the end of the line and joins the current line with the following line.
### .iterate( options , callback )
* options `Object` where:
* finalCall `boolean` call the callback one more time at the end of the buffer with an empty string
* callback `Function( cellData )`, where:
* cellData `Object` where:
* offset `integer` the offset/position of the current cell in the raw/serialized text
* x `integer` the x-coordinate (i.e. the column number) of the current cell
* y `integer` the y-coordinate (i.e. the row number) of the current cell
* text `string` a single character string, the character of the current cell
* attr `integer` the attributes of the current cell in the bit flags mode, use
[ScreenBuffer.attr2object()](ScreenBuffer.md#ref.ScreenBuffer.attr2object) to convert it if necessary
* misc `Object` userland meta-data for the current cell
It iterates over the whole *textBuffer*, using the *callback* for each cell.
### .wrapLine( [y] , [width] , [wordWrap] )
* y `integer` the line to wrap (default: current line, the line where the cursor is)
* width `integer` the wanted width (default: the current textBuffer's *lineWrapWidth*)
* wordWrap `boolean` if true, force word-aware line-splitting (default: the current textBuffer's *wordWrap*)
It wraps the current line (or the line *y*), splitting it as many times it is necessary to fit the wanted width.
The *wordWrap* option can be used to avoid splitting in a middle of a word or before punctuation.
### .wrapAllLines( [width] , [wordWrap] )
* width `integer` the wanted width (default: the current textBuffer's *lineWrapWidth*)
* wordWrap `boolean` if true, force word-aware line-splitting (default: the current textBuffer's *wordWrap*)
Same than [`.wrapLine()`](#ref.TextBuffer.wrapLine), but for all lines.
### .draw( [options] )
* options `Object` (optional) if provided, each defined option will override the default behavior. Available options are:
* dst `ScreenBuffer` (optional) override `textBuffer.dst`
* x `integer` (optional) override `textBuffer.x`
* y `integer` (optional) override `textBuffer.y`
* srcClipRect `Rect` (optional, default: the whole source region is used) the source clipping rectangle
* dstClipRect `Rect` (optional, default: the whole destination region is used) the destination clipping rectangle
* blending `boolean` (optional, default: false) if true blending (transparencies) is allowed
* wrap `boolean` or `string` (optional, default: false) if set, wrapping will be enabled, it can be set to:
* 'x': only wrap along the x-axis
* 'y': only wrap along the y-axis
* true, 'both': wrap along the x and y axis
* false: no wrapping
* tile `boolean` (optional, default: false) if true, the source will fill the destination entirely using tiling:
the source is repeated multiple times along the x and y axis.
This draws the current *textBuffer* into its *dst* (destination), which is a `ScreenBuffer` instance.
To actually display a *textBuffer*, you need to:
* draw the *textBuffer* to a *screenBuffer*
* then draw that *screenBuffer* to the terminal (or draw the whole *screenBuffer* chain until the terminal)
### .drawCursor( [options] )
* options `Object` (optional) if provided, each defined option will override the default behavior. Available options are:
* dst `ScreenBuffer` (optional) override `textBuffer.dst`
This draws the current *textBuffer*'s cursor into its *dst* (destination), which is a `ScreenBuffer` instance.
*Drawing the cursor* means that the destination's cursor is moved to the coordinate of the source's cursor.
It updates the cursor position so the user know where he is typing.
### .load( filepath , [callback] )
* filepath `string` the path of the file to load
* callback `Function( error )` completion callback, DEPRECATED: prefer the Promise interface.
**If callback is omitted**, it returns a Promise on completion.
This erases all contents (text, attr and misc) and loads the content of the file (which is a text file).
### .save( filepath , [callback] )
* filepath `string` the path of the file to save into
* callback `Function( error )` completion callback, DEPRECATED: prefer the Promise interface.
**If callback is omitted**, it returns a Promise on completion.
This saves the raw text content into a file.