## 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.