Преглед изворни кода

adapts reflow to new BufferLine logic

devmil пре 4 година
родитељ
комит
9c10cc2fa5
4 измењених фајлова са 94 додато и 29 уклоњено
  1. 20 7
      lib/buffer/buffer.dart
  2. 56 4
      lib/buffer/buffer_line.dart
  3. 13 14
      lib/buffer/buffer_reflow.dart
  4. 5 4
      lib/terminal/terminal.dart

+ 20 - 7
lib/buffer/buffer.dart

@@ -1,6 +1,7 @@
 import 'dart:math' show max, min;
 
 import 'package:xterm/buffer/buffer_line.dart';
+import 'package:xterm/buffer/buffer_reflow.dart';
 import 'package:xterm/terminal/charset.dart';
 import 'package:xterm/terminal/terminal.dart';
 import 'package:xterm/utli/scroll_range.dart';
@@ -493,17 +494,17 @@ class Buffer {
     lines.removeAt(index);
   }
 
-  void resize(int newWidth, int newHeight) {
-    if (newWidth > terminal.viewWidth) {
+  void resize(int oldWidth, int oldHeight, int newWidth, int newHeight) {
+    if (newWidth > oldWidth) {
       for (var line in lines) {
         line.ensure(newWidth);
       }
     }
 
-    if (newHeight > terminal.viewHeight) {
+    if (newHeight > oldHeight) {
       // Grow larger
-      for (var i = 0; i < newHeight - terminal.viewHeight; i++) {
-        if (_cursorY < terminal.viewHeight - 1) {
+      for (var i = 0; i < newHeight - oldHeight; i++) {
+        if (_cursorY < oldHeight - 1) {
           lines.add(_newEmptyLine());
         } else {
           _cursorY++;
@@ -511,8 +512,8 @@ class Buffer {
       }
     } else {
       // Shrink smaller
-      for (var i = 0; i < terminal.viewHeight - newHeight; i++) {
-        if (_cursorY < terminal.viewHeight - 1) {
+      for (var i = 0; i < oldHeight - newHeight; i++) {
+        if (_cursorY < oldHeight - 1) {
           lines.removeLast();
         } else {
           _cursorY++;
@@ -523,6 +524,9 @@ class Buffer {
     // Ensure cursor is within the screen.
     _cursorX = _cursorX.clamp(0, newWidth - 1);
     _cursorY = _cursorY.clamp(0, newHeight - 1);
+
+    final rf = BufferReflow(this);
+    rf.doReflow(oldWidth, newWidth);
   }
 
   BufferLine _newEmptyLine() {
@@ -530,4 +534,13 @@ class Buffer {
     line.ensure(terminal.viewWidth);
     return line;
   }
+
+  adjustSavedCursor(int dx, int dy) {
+    if (_savedCursorX != null) {
+      _savedCursorX = _savedCursorX! + dx;
+    }
+    if (_savedCursorY != null) {
+      _savedCursorY = _savedCursorY! + dy;
+    }
+  }
 }

+ 56 - 4
lib/buffer/buffer_line.dart

@@ -1,3 +1,4 @@
+import 'dart:math';
 import 'dart:typed_data';
 
 import 'package:xterm/terminal/cursor.dart';
@@ -25,9 +26,8 @@ const _cellWidth = 12;
 const _cellFlags = 13;
 
 class BufferLine {
-  BufferLine() {
-    const initLength = 64;
-    _cells = ByteData(initLength * _cellSize);
+  BufferLine({bool isWrapped = false}) : _isWrapped = isWrapped {
+    _cells = ByteData(_maxCols * _cellSize);
   }
 
   late ByteData _cells;
@@ -35,6 +35,8 @@ class BufferLine {
   bool get isWrapped => _isWrapped;
   bool _isWrapped = false;
 
+  int _maxCols = 64;
+
   void ensure(int length) {
     final expectedLengthInBytes = length * _cellSize;
 
@@ -50,6 +52,7 @@ class BufferLine {
     final newCells = ByteData(newLengthInBytes);
     newCells.buffer.asInt64List().setAll(0, _cells.buffer.asInt64List());
     _cells = newCells;
+    _maxCols = (newLengthInBytes / _cellSize).floor();
   }
 
   void insert(int index) {
@@ -88,11 +91,14 @@ class BufferLine {
     _cells.buffer.asInt64List().clear();
   }
 
-  void erase(Cursor cursor, int start, int end) {
+  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 cellInitialize(
@@ -109,7 +115,14 @@ class BufferLine {
     _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.getInt32(index * _cellSize + _cellContent);
   }
 
@@ -118,6 +131,9 @@ class BufferLine {
   }
 
   int cellGetFgColor(int index) {
+    if (index >= _maxCols) {
+      return 0;
+    }
     return _cells.getInt32(index * _cellSize + _cellFgColor);
   }
 
@@ -126,6 +142,9 @@ class BufferLine {
   }
 
   int cellGetBgColor(int index) {
+    if (index >= _maxCols) {
+      return 0;
+    }
     return _cells.getInt32(index * _cellSize + _cellBgColor);
   }
 
@@ -134,6 +153,9 @@ class BufferLine {
   }
 
   int cellGetFlags(int index) {
+    if (index >= _maxCols) {
+      return 0;
+    }
     return _cells.getInt8(index * _cellSize + _cellFlags);
   }
 
@@ -142,6 +164,9 @@ class BufferLine {
   }
 
   int cellGetWidth(int index) {
+    if (index >= _maxCols) {
+      return 1;
+    }
     return _cells.getInt8(index * _cellSize + _cellWidth);
   }
 
@@ -154,6 +179,9 @@ class BufferLine {
   }
 
   bool cellHasFlag(int index, int flag) {
+    if (index >= _maxCols) {
+      return false;
+    }
     return cellGetFlags(index) & flag != 0;
   }
 
@@ -168,6 +196,29 @@ class BufferLine {
     cellSetFlags(index, cursor.flags);
   }
 
+  int getTrimmedLength(int cols) {
+    for (int i = cols; i >= 0; i--) {
+      if (cellGetContent(i) != 0) {
+        int length = 0;
+        for (int j = 0; j <= i; j++) {
+          length += cellGetWidth(j);
+        }
+        return length;
+      }
+    }
+    return 0;
+  }
+
+  copyCellsFrom(BufferLine src, int srcCol, int dstCol, int len) {
+    final dstOffset = dstCol * _cellSize;
+    final srcOffset = srcCol * _cellSize;
+    final byteLen = len * _cellSize;
+
+    final srcCopyView = src._cells.buffer.asUint8List(srcOffset, byteLen);
+
+    _cells.buffer.asUint8List().setAll(dstOffset, srcCopyView);
+  }
+
   // int cellGetHash(int index) {
   //   final cell = index * _cellSize;
   //   final a = _cells.getInt64(cell);
@@ -176,6 +227,7 @@ class BufferLine {
   // }
 
   void removeRange(int start, int end) {
+    end = min(end, _maxCols);
     // start = start.clamp(0, _cells.length);
     // end ??= _cells.length;
     // end = end.clamp(start, _cells.length);

+ 13 - 14
lib/buffer/buffer_reflow.dart

@@ -60,7 +60,7 @@ class BufferReflow {
     for (int y = _buffer.lines.length - 1; y >= 0; y--) {
       // Check whether this line is a problem or not, if not skip it
       BufferLine nextLine = _buffer.lines[y];
-      int lineLength = nextLine.getTrimmedLength();
+      int lineLength = nextLine.getTrimmedLength(colsBefore);
       if (!nextLine.isWrapped && lineLength <= colsAfter) {
         continue;
       }
@@ -81,7 +81,7 @@ class BufferReflow {
         continue;
       }
 
-      int lastLineLength = wrappedLines.last.getTrimmedLength();
+      int lastLineLength = wrappedLines.last.getTrimmedLength(colsBefore);
       List<int> destLineLengths =
           _getNewLineLengths(wrappedLines, colsBefore, colsAfter);
       int linesToAdd = destLineLengths.length - wrappedLines.length;
@@ -135,7 +135,7 @@ class BufferReflow {
       // Null out the end of the line ends if a wide character wrapped to the following line
       for (int i = 0; i < wrappedLines.length; i++) {
         if (destLineLengths[i] < colsAfter) {
-          wrappedLines[i].removeRange(destLineLengths[i]);
+          wrappedLines[i].removeRange(destLineLengths[i], colsBefore);
         }
       }
 
@@ -236,7 +236,7 @@ class BufferReflow {
         srcLine++;
       }
 
-      bool endsWithWide = wrappedLines[srcLine].getWidthAt(srcCol - 1) == 2;
+      bool endsWithWide = wrappedLines[srcLine].cellGetWidth(srcCol - 1) == 2;
       if (endsWithWide) {
         srcCol--;
       }
@@ -369,27 +369,26 @@ class BufferReflow {
 
         // Make sure the last cell isn't wide, if it is copy it to the current dest
         if (destCol == 0 && destLineIndex != 0) {
-          if (wrappedLines[destLineIndex - 1].getWidthAt(colsAfter - 1) == 2) {
+          if (wrappedLines[destLineIndex - 1].cellGetWidth(colsAfter - 1) ==
+              2) {
             wrappedLines[destLineIndex].copyCellsFrom(
                 wrappedLines[destLineIndex - 1], colsAfter - 1, destCol++, 1);
             // Null out the end of the last row
             wrappedLines[destLineIndex - 1].erase(
-                _buffer.terminal.cellAttr.value,
-                colsAfter - 1,
-                colsAfter,
-                false);
+                _buffer.terminal.cursor, colsAfter - 1, colsAfter, false);
           }
         }
       }
 
       // Clear out remaining cells or fragments could remain;
       wrappedLines[destLineIndex]
-          .erase(_buffer.terminal.cellAttr.value, destCol, colsAfter, false);
+          .erase(_buffer.terminal.cursor, destCol, colsAfter, false);
 
       // Work backwards and remove any rows at the end that only contain null cells
       int countToRemove = 0;
       for (int ix = wrappedLines.length - 1; ix > 0; ix--) {
-        if (ix > destLineIndex || wrappedLines[ix].getTrimmedLength() == 0) {
+        if (ix > destLineIndex ||
+            wrappedLines[ix].getTrimmedLength(colsBefore) == 0) {
           countToRemove++;
         } else {
           break;
@@ -417,15 +416,15 @@ class BufferReflow {
       BufferLine line, BufferLine? nextLine, int cols) {
     // If this is the last row in the wrapped line, get the actual trimmed length
     if (nextLine == null) {
-      return line.getTrimmedLength();
+      return line.getTrimmedLength(cols);
     }
 
     // Detect whether the following line starts with a wide character and the end of the current line
     // is null, if so then we can be pretty sure the null character should be excluded from the line
     // length]
     bool endsInNull =
-        !(line.hasContentAt(cols - 1)) && line.getWidthAt(cols - 1) == 1;
-    bool followingLineStartsWithWide = nextLine.getWidthAt(0) == 2;
+        !(line.cellHasContent(cols - 1)) && line.cellGetWidth(cols - 1) == 1;
+    bool followingLineStartsWithWide = nextLine.cellGetWidth(0) == 2;
 
     if (endsInNull && followingLineStartsWithWide) {
       return cols - 1;

+ 5 - 4
lib/terminal/terminal.dart

@@ -345,13 +345,14 @@ class Terminal with Observable {
     newWidth = max(newWidth, 1);
     newHeight = max(newHeight, 1);
 
-    buffer.resize(newWidth, newHeight);
-
-    // maybe reflow should happen here.
-
+    final oldWidth = _viewWidth;
+    final oldHeight = _viewHeight;
     _viewWidth = newWidth;
     _viewHeight = newHeight;
 
+    buffer.resize(oldWidth, oldHeight, newWidth, newHeight);
+
+    // maybe reflow should happen here.
     if (buffer == _altBuffer) {
       buffer.clearScrollback();
     }