| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- import 'dart:math' show min;
- import 'dart:typed_data';
- import 'package:xterm/core/cell.dart';
- import 'package:xterm/core/cursor.dart';
- import 'package:xterm/utils/unicode_v11.dart';
- const _cellSize = 4;
- const _cellForeground = 0;
- const _cellBackground = 1;
- const _cellAttributes = 2;
- const _cellContent = 3;
- class BufferLine {
- BufferLine(
- this._length, {
- this.isWrapped = false,
- }) : _data = Uint32List(_calcCapacity(_length) * _cellSize);
- int _length;
- Uint32List _data;
- Uint32List get data => _data;
- var isWrapped = false;
- int get length => _length;
- int getForeground(int index) {
- return _data[index * _cellSize + _cellForeground];
- }
- int getBackground(int index) {
- return _data[index * _cellSize + _cellBackground];
- }
- int getAttributes(int index) {
- return _data[index * _cellSize + _cellAttributes];
- }
- int getContent(int index) {
- return _data[index * _cellSize + _cellContent];
- }
- int getCodePoint(int index) {
- return _data[index * _cellSize + _cellContent] & CellContent.codepointMask;
- }
- int getWidth(int index) {
- return _data[index * _cellSize + _cellContent] >> CellContent.widthShift;
- }
- void getCellData(int index, CellData cellData) {
- final offset = index * _cellSize;
- cellData.foreground = _data[offset + _cellForeground];
- cellData.background = _data[offset + _cellBackground];
- cellData.flags = _data[offset + _cellAttributes];
- cellData.content = _data[offset + _cellContent];
- }
- CellData createCellData(int index) {
- final cellData = CellData.empty();
- final offset = index * _cellSize;
- _data[offset + _cellForeground] = cellData.foreground;
- _data[offset + _cellBackground] = cellData.background;
- _data[offset + _cellAttributes] = cellData.flags;
- _data[offset + _cellContent] = cellData.content;
- return cellData;
- }
- void setForeground(int index, int value) {
- _data[index * _cellSize + _cellForeground] = value;
- }
- void setBackground(int index, int value) {
- _data[index * _cellSize + _cellBackground] = value;
- }
- void setAttributes(int index, int value) {
- _data[index * _cellSize + _cellAttributes] = value;
- }
- void setContent(int index, int value) {
- _data[index * _cellSize + _cellContent] = value;
- }
- void setCodePoint(int index, int char) {
- final width = unicodeV11.wcwidth(char);
- setContent(index, char | (width << CellContent.widthShift));
- }
- void setCell(int index, int char, int witdh, CursorStyle style) {
- final offset = index * _cellSize;
- _data[offset + _cellForeground] = style.foreground;
- _data[offset + _cellBackground] = style.background;
- _data[offset + _cellAttributes] = style.attrs;
- _data[offset + _cellContent] = char | (witdh << CellContent.widthShift);
- }
- void setCellData(int index, CellData cellData) {
- final offset = index * _cellSize;
- _data[offset + _cellForeground] = cellData.foreground;
- _data[offset + _cellBackground] = cellData.background;
- _data[offset + _cellAttributes] = cellData.flags;
- _data[offset + _cellContent] = cellData.content;
- }
- void eraseCell(int index, CursorStyle style) {
- final offset = index * _cellSize;
- _data[offset + _cellForeground] = style.foreground;
- _data[offset + _cellBackground] = style.background;
- _data[offset + _cellAttributes] = style.attrs;
- _data[offset + _cellContent] = 0;
- }
- void resetCell(int index) {
- final offset = index * _cellSize;
- _data[offset + _cellForeground] = 0;
- _data[offset + _cellBackground] = 0;
- _data[offset + _cellAttributes] = 0;
- _data[offset + _cellContent] = 0;
- }
- void eraseRange(int start, int end, CursorStyle style) {
- // reset cell one to the left if start is second cell of a wide char
- if (start > 0 && getWidth(start - 1) == 2) {
- eraseCell(start - 1, style);
- }
- // reset cell one to the right if end is second cell of a wide char
- if (end < _length && getWidth(end - 1) == 2) {
- eraseCell(end - 1, style);
- }
- end = min(end, _length);
- for (var i = start; i < end; i++) {
- eraseCell(i, style);
- }
- }
- void removeCells(int start, int count, [CursorStyle? style]) {
- assert(start >= 0 && start < _length);
- assert(count >= 0 && start + count <= _length);
- style ??= CursorStyle.empty;
- if (start + count < _length) {
- final moveStart = start * _cellSize;
- final moveEnd = (_length - count) * _cellSize;
- final moveOffset = count * _cellSize;
- for (var i = moveStart; i < moveEnd; i++) {
- _data[i] = _data[i + moveOffset];
- }
- }
- for (var i = _length - count; i < _length; i++) {
- eraseCell(i, style);
- }
- if (start > 0 && getWidth(start - 1) == 2) {
- eraseCell(start - 1, style);
- }
- }
- void insertCells(int start, int count, [CursorStyle? style]) {
- style ??= CursorStyle.empty;
- if (start > 0 && getWidth(start - 1) == 2) {
- eraseCell(start - 1, style);
- }
- if (start + count < _length) {
- final moveStart = start * _cellSize;
- final moveEnd = (_length - count) * _cellSize;
- final moveOffset = count * _cellSize;
- for (var i = moveEnd - 1; i >= moveStart; i--) {
- _data[i + moveOffset] = _data[i];
- }
- }
- final end = min(start + count, _length);
- for (var i = start; i < end; i++) {
- eraseCell(i, style);
- }
- if (getWidth(_length - 1) == 2) {
- eraseCell(_length - 1, style);
- }
- }
- void resize(int length) {
- assert(length >= 0);
- if (length == _length) {
- return;
- }
- final newBufferSize = _calcCapacity(length) * _cellSize;
- if (newBufferSize > _data.length) {
- final newBuffer = Uint32List(newBufferSize);
- newBuffer.setRange(0, _data.length, _data);
- _data = newBuffer;
- }
- _length = length;
- }
- int getTrimmedLength([int? cols]) {
- if (cols == null) {
- cols = _data.length ~/ _cellSize;
- }
- for (var i = cols - 1; i >= 0; i--) {
- var codePoint = getCodePoint(i);
- if (codePoint != 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 = getWidth(i);
- return i + lastCellWidth;
- }
- }
- return 0;
- }
- void copyFrom(BufferLine src, int srcCol, int dstCol, int len) {
- resize(dstCol + len);
- // data.setRange(
- // dstCol * _cellSize,
- // (dstCol + len) * _cellSize,
- // Uint32List.sublistView(src.data, srcCol * _cellSize, len * _cellSize),
- // );
- var srcOffset = srcCol * _cellSize;
- var dstOffset = dstCol * _cellSize;
- for (var i = 0; i < len * _cellSize; i++) {
- _data[dstOffset++] = src._data[srcOffset++];
- }
- }
- static int _calcCapacity(int length) {
- assert(length >= 0);
- var capacity = 64;
- if (length < 256) {
- while (capacity < length) {
- capacity *= 2;
- }
- } else {
- capacity = 256;
- while (capacity < length) {
- capacity += 32;
- }
- }
- return capacity;
- }
- String getText([int? from, int? to]) {
- if (from == null) {
- from = 0;
- }
- if (to == null) {
- to = _length;
- }
- final builder = StringBuffer();
- for (var i = from; i < to; i++) {
- final codePoint = getCodePoint(i);
- final width = getWidth(i);
- if (codePoint != 0 && i + width <= to) {
- builder.writeCharCode(codePoint);
- }
- }
- return builder.toString();
- }
- @override
- String toString() {
- return getText();
- }
- }
|