| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- import 'dart:math';
- import 'dart:typed_data';
- import 'package:xterm/terminal/cursor.dart';
- /// Line layout:
- /// | cell | cell | cell | cell | ...
- /// (16 bytes per cell)
- ///
- /// Cell layout:
- /// | code point | fg color | bg color | attributes |
- /// 4bytes 4bytes 4bytes 4bytes
- ///
- /// Attributes layout:
- /// | width | flags | reserved | reserved |
- /// 1byte 1byte 1byte 1byte
- const _cellSize = 16;
- const _cellSize64Bit = _cellSize >> 3;
- const _cellContent = 0;
- const _cellFgColor = 4;
- const _cellBgColor = 8;
- // const _cellAttributes = 12;
- const _cellWidth = 12;
- const _cellFlags = 13;
- int _nextLength(int lengthRequirement) {
- var nextLength = 2;
- while (nextLength < lengthRequirement) {
- nextLength *= 2;
- }
- return nextLength;
- }
- class BufferLine {
- BufferLine({int length = 64, this.isWrapped = false}) {
- _maxCols = _nextLength(length);
- _cells = ByteData(_maxCols * _cellSize);
- }
- late ByteData _cells;
- bool isWrapped;
- int _maxCols = 64;
- void ensure(int length) {
- if (length <= _maxCols) {
- return;
- }
- final nextLength = _nextLength(length);
- final newCells = ByteData(nextLength * _cellSize);
- newCells.buffer.asInt64List().setAll(0, _cells.buffer.asInt64List());
- _cells = newCells;
- _maxCols = nextLength;
- }
- void insert(int index) {
- insertN(index, 1);
- }
- void removeN(int index, int count) {
- final moveStart = index * _cellSize64Bit;
- final moveOffset = count * _cellSize64Bit;
- final moveEnd = (_maxCols - count) * _cellSize64Bit;
- final bufferEnd = _maxCols * _cellSize64Bit;
- // move data backward
- final cells = _cells.buffer.asInt64List();
- for (var i = moveStart; i < moveEnd; i++) {
- cells[i] = cells[i + moveOffset];
- }
- // set empty cells to 0
- for (var i = moveEnd; i < bufferEnd; i++) {
- cells[i] = 0x00;
- }
- }
- void insertN(int index, int count) {
- // start
- // +--------------------------|-----------------------------------+
- // | | |
- // +--------------------------\--\--------------------------------+ end
- // \ \
- // \ \
- // v v
- // +--------------------------|--|--------------------------------+
- // | | | |
- // +--------------------------|--|--------------------------------+ end
- // start start+offset
- final moveStart = index * _cellSize64Bit;
- final moveOffset = count * _cellSize64Bit;
- final bufferEnd = _maxCols * _cellSize64Bit;
- // move data forward
- final cells = _cells.buffer.asInt64List();
- for (var i = bufferEnd - moveOffset - 1; i >= moveStart; i--) {
- cells[i + moveOffset] = cells[i];
- }
- // set inserted cells to 0
- for (var i = moveStart; i < moveStart + moveOffset; i++) {
- cells[i] = 0x00;
- }
- }
- void clear() {
- clearRange(0, _cells.lengthInBytes ~/ _cellSize);
- }
- void erase(Cursor cursor, int start, int end, [bool resetIsWrapped = false]) {
- ensure(end);
- for (var i = start; i < end; i++) {
- cellErase(i, cursor);
- }
- if (resetIsWrapped) {
- isWrapped = false;
- }
- }
- void cellClear(int index) {
- _cells.setInt64(index * _cellSize, 0x00);
- _cells.setInt64(index * _cellSize + 8, 0x00);
- }
- void cellInitialize(
- int index, {
- required int content,
- required int width,
- required Cursor cursor,
- }) {
- final cell = index * _cellSize;
- _cells.setInt32(cell + _cellContent, content);
- _cells.setInt32(cell + _cellFgColor, cursor.fg);
- _cells.setInt32(cell + _cellBgColor, cursor.bg);
- _cells.setInt8(cell + _cellWidth, width);
- _cells.setInt8(cell + _cellFlags, cursor.flags);
- }
- bool cellHasContent(int index) {
- return cellGetContent(index) != 0;
- }
- int cellGetContent(int index) {
- if (index > _maxCols) {
- return 0;
- }
- return _cells.getUint32(index * _cellSize + _cellContent);
- }
- void cellSetContent(int index, int content) {
- _cells.setInt32(index * _cellSize + _cellContent, content);
- }
- int cellGetFgColor(int index) {
- if (index >= _maxCols) {
- return 0;
- }
- return _cells.getInt32(index * _cellSize + _cellFgColor);
- }
- void cellSetFgColor(int index, int color) {
- _cells.setInt32(index * _cellSize + _cellFgColor, color);
- }
- int cellGetBgColor(int index) {
- if (index >= _maxCols) {
- return 0;
- }
- return _cells.getInt32(index * _cellSize + _cellBgColor);
- }
- void cellSetBgColor(int index, int color) {
- _cells.setInt32(index * _cellSize + _cellBgColor, color);
- }
- int cellGetFlags(int index) {
- if (index >= _maxCols) {
- return 0;
- }
- return _cells.getInt8(index * _cellSize + _cellFlags);
- }
- void cellSetFlags(int index, int flags) {
- _cells.setInt8(index * _cellSize + _cellFlags, flags);
- }
- int cellGetWidth(int index) {
- if (index >= _maxCols) {
- return 1;
- }
- return _cells.getInt8(index * _cellSize + _cellWidth);
- }
- void cellSetWidth(int index, int width) {
- _cells.setInt8(index * _cellSize + _cellWidth, width);
- }
- void cellClearFlags(int index) {
- cellSetFlags(index, 0);
- }
- bool cellHasFlag(int index, int flag) {
- if (index >= _maxCols) {
- return false;
- }
- return cellGetFlags(index) & flag != 0;
- }
- void cellSetFlag(int index, int flag) {
- cellSetFlags(index, cellGetFlags(index) | flag);
- }
- void cellErase(int index, Cursor cursor) {
- cellSetContent(index, 0x00);
- cellSetFgColor(index, cursor.fg);
- cellSetBgColor(index, cursor.bg);
- cellSetFlags(index, cursor.flags);
- cellSetWidth(index, 0);
- }
- int getTrimmedLength([int? cols]) {
- if (cols == null) {
- cols = _maxCols;
- }
- for (var i = cols - 1; i >= 0; i--) {
- if (cellGetContent(i) != 0) {
- // we are at the last cell in this line that has content.
- // the length of this line is the index of this cell + 1
- // the only exception is that if that last cell is wider
- // than 1 then we have to add the diff
- final lastCellWidth = cellGetWidth(i);
- return i + lastCellWidth;
- }
- }
- return 0;
- }
- void copyCellsFrom(BufferLine src, int srcCol, int dstCol, int len) {
- ensure(dstCol + len);
- final intsToCopy = len * _cellSize64Bit;
- final srcStart = srcCol * _cellSize64Bit;
- final dstStart = dstCol * _cellSize64Bit;
- final cells = _cells.buffer.asInt64List();
- final srcCells = src._cells.buffer.asInt64List();
- for (var i = 0; i < intsToCopy; i++) {
- cells[dstStart + i] = srcCells[srcStart + i];
- }
- }
- // int cellGetHash(int index) {
- // final cell = index * _cellSize;
- // final a = _cells.getInt64(cell);
- // final b = _cells.getInt64(cell + 8);
- // return a ^ b;
- // }
- void removeRange(int start, int end) {
- end = min(end, _maxCols);
- this.removeN(start, end - start);
- }
- void clearRange(int start, int end) {
- end = min(end, _maxCols);
- for (var index = start; index < end; index++) {
- cellClear(index);
- }
- }
- @override
- String toString() {
- final result = StringBuffer();
- for (int i = 0; i < _maxCols; i++) {
- final code = cellGetContent(i);
- if (code == 0) {
- continue;
- }
- result.writeCharCode(code);
- }
- return result.toString();
- }
- String toDebugString(int cols) {
- final result = StringBuffer();
- final length = getTrimmedLength();
- for (int i = 0; i < max(cols, length); i++) {
- var code = cellGetContent(i);
- if (code == 0) {
- if (cellGetWidth(i) == 0) {
- code = '_'.runes.first;
- } else {
- code = cellGetWidth(i).toString().runes.first;
- }
- }
- result.writeCharCode(code);
- }
- return result.toString();
- }
- }
|