reflow.dart 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import 'package:xterm/core/buffer/line.dart';
  2. import 'package:xterm/utils/circular_list.dart';
  3. class _LineBuilder {
  4. _LineBuilder([this._capacity = 80]) {
  5. _result = BufferLine(_capacity);
  6. }
  7. final int _capacity;
  8. late BufferLine _result;
  9. int _length = 0;
  10. int get length => _length;
  11. bool get isEmpty => _length == 0;
  12. bool get isNotEmpty => _length != 0;
  13. void add(BufferLine src, int start, int length) {
  14. _result.copyFrom(src, start, _length, length);
  15. _length += length;
  16. }
  17. void setBuffer(BufferLine line, int length) {
  18. _result = line;
  19. _length = length;
  20. }
  21. BufferLine take({required bool wrapped}) {
  22. final result = _result;
  23. result.isWrapped = wrapped;
  24. result.resize(_length);
  25. _result = BufferLine(_capacity);
  26. _length = 0;
  27. return result;
  28. }
  29. }
  30. class _LineReflow {
  31. final int oldWidth;
  32. final int newWidth;
  33. _LineReflow(this.oldWidth, this.newWidth);
  34. final _lines = <BufferLine>[];
  35. late final _builder = _LineBuilder(newWidth);
  36. void add(BufferLine line) {
  37. final length = line.getTrimmedLength(oldWidth);
  38. if (length == 0) {
  39. _lines.add(line);
  40. return;
  41. }
  42. if (_lines.isNotEmpty || _builder.isNotEmpty) {
  43. _addRange(line, 0, length);
  44. return;
  45. }
  46. if (newWidth >= oldWidth) {
  47. _builder.setBuffer(line, length);
  48. } else {
  49. _lines.add(line);
  50. if (line.getWidth(newWidth - 1) == 2) {
  51. _addRange(line, newWidth - 1, length);
  52. } else {
  53. _addRange(line, newWidth, length);
  54. }
  55. }
  56. line.resize(newWidth);
  57. if (line.getWidth(newWidth - 1) == 2) {
  58. line.resetCell(newWidth - 1);
  59. }
  60. }
  61. void _addRange(BufferLine line, int start, int end) {
  62. var cellsLeft = end - start;
  63. while (cellsLeft > 0) {
  64. final spaceLeft = newWidth - _builder.length;
  65. var lineFilled = false;
  66. var cellsToCopy = cellsLeft;
  67. if (cellsToCopy >= spaceLeft) {
  68. cellsToCopy = spaceLeft;
  69. lineFilled = true;
  70. }
  71. // Avoid breaking wide characters
  72. if (cellsToCopy == spaceLeft &&
  73. line.getWidth(start + cellsToCopy - 1) == 2) {
  74. cellsToCopy--;
  75. }
  76. _builder.add(line, start, cellsToCopy);
  77. start += cellsToCopy;
  78. cellsLeft -= cellsToCopy;
  79. if (lineFilled) {
  80. _lines.add(_builder.take(wrapped: _lines.isNotEmpty));
  81. }
  82. }
  83. }
  84. List<BufferLine> finish() {
  85. if (_builder.isNotEmpty) {
  86. _lines.add(_builder.take(wrapped: _lines.isNotEmpty));
  87. }
  88. return _lines;
  89. }
  90. }
  91. List<BufferLine> reflow(
  92. CircularList<BufferLine> lines,
  93. int oldWidth,
  94. int newWidth,
  95. ) {
  96. final result = <BufferLine>[];
  97. for (var i = 0; i < lines.length; i++) {
  98. final line = lines[i];
  99. final reflow = _LineReflow(oldWidth, newWidth);
  100. reflow.add(line);
  101. for (var offset = i + 1; offset < lines.length; offset++) {
  102. final nextLine = lines[offset];
  103. if (!nextLine.isWrapped) {
  104. break;
  105. }
  106. i++;
  107. reflow.add(nextLine);
  108. }
  109. result.addAll(reflow.finish());
  110. }
  111. return result;
  112. }