diff options
| author | Adam <[email protected]> | 2025-12-06 06:16:21 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-12-06 06:43:53 -0600 |
| commit | 91110051658f42341ac713327991605461d4bb0b (patch) | |
| tree | e415be079c7b38647c6797b433b91fc4e7e8d6aa /packages/desktop/src/addons/serialize.ts | |
| parent | 3ceac25fb54d1607c77de4cc861c394e3abd14f0 (diff) | |
| download | opencode-91110051658f42341ac713327991605461d4bb0b.tar.gz opencode-91110051658f42341ac713327991605461d4bb0b.zip | |
fix: terminal serialization and isolation
Diffstat (limited to 'packages/desktop/src/addons/serialize.ts')
| -rw-r--r-- | packages/desktop/src/addons/serialize.ts | 201 |
1 files changed, 77 insertions, 124 deletions
diff --git a/packages/desktop/src/addons/serialize.ts b/packages/desktop/src/addons/serialize.ts index c9f848180..cb1ff8442 100644 --- a/packages/desktop/src/addons/serialize.ts +++ b/packages/desktop/src/addons/serialize.ts @@ -157,6 +157,23 @@ function equalFlags(cell1: IBufferCell, cell2: IBufferCell): boolean { abstract class BaseSerializeHandler { constructor(protected readonly _buffer: IBuffer) {} + private _isRealContent(codepoint: number): boolean { + if (codepoint === 0) return false + if (codepoint >= 0xf000) return false + return true + } + + private _findLastContentColumn(line: IBufferLine): number { + let lastContent = -1 + for (let col = 0; col < line.length; col++) { + const cell = line.getCell(col) + if (cell && this._isRealContent(cell.getCode())) { + lastContent = col + } + } + return lastContent + 1 + } + public serialize(range: IBufferRange, excludeFinalCursorPosition?: boolean): string { let oldCell = this._buffer.getNullCell() @@ -171,7 +188,8 @@ abstract class BaseSerializeHandler { const line = this._buffer.getLine(row) if (line) { const startLineColumn = row === range.start.y ? startColumn : 0 - const endLineColumn = row === range.end.y ? endColumn : line.length + const maxColumn = row === range.end.y ? endColumn : this._findLastContentColumn(line) + const endLineColumn = Math.min(maxColumn, line.length) for (let col = startLineColumn; col < endLineColumn; col++) { const c = line.getCell(col) if (!c) { @@ -209,17 +227,11 @@ class StringSerializeHandler extends BaseSerializeHandler { private _currentRow: string = "" private _nullCellCount: number = 0 private _cursorStyle: IBufferCell - private _cursorStyleRow: number = 0 - private _cursorStyleCol: number = 0 - private _backgroundCell: IBufferCell private _firstRow: number = 0 private _lastCursorRow: number = 0 private _lastCursorCol: number = 0 private _lastContentCursorRow: number = 0 private _lastContentCursorCol: number = 0 - private _thisRowLastChar: IBufferCell - private _thisRowLastSecondChar: IBufferCell - private _nextRowFirstChar: IBufferCell constructor( buffer: IBuffer, @@ -227,10 +239,6 @@ class StringSerializeHandler extends BaseSerializeHandler { ) { super(buffer) this._cursorStyle = this._buffer.getNullCell() - this._backgroundCell = this._buffer.getNullCell() - this._thisRowLastChar = this._buffer.getNullCell() - this._thisRowLastSecondChar = this._buffer.getNullCell() - this._nextRowFirstChar = this._buffer.getNullCell() } protected _beforeSerialize(rows: number, start: number, _end: number): void { @@ -241,82 +249,15 @@ class StringSerializeHandler extends BaseSerializeHandler { } protected _rowEnd(row: number, isLastRow: boolean): void { - // if there is colorful empty cell at line end, we must pad it back - if (this._nullCellCount > 0 && !equalBg(this._cursorStyle, this._backgroundCell)) { - this._currentRow += `\u001b[${this._nullCellCount}X` - } - let rowSeparator = "" if (!isLastRow) { - // Enable BCE - if (row - this._firstRow >= this._terminal.rows) { - const line = this._buffer.getLine(this._cursorStyleRow) - const cell = line?.getCell(this._cursorStyleCol) - if (cell) { - this._backgroundCell = cell - } - } + const nextLine = this._buffer.getLine(row + 1) - const currentLine = this._buffer.getLine(row)! - const nextLine = this._buffer.getLine(row + 1)! - - if (!nextLine.isWrapped) { + if (!nextLine?.isWrapped) { rowSeparator = "\r\n" this._lastCursorRow = row + 1 this._lastCursorCol = 0 - } else { - rowSeparator = "" - const thisRowLastChar = currentLine.getCell(currentLine.length - 1) - const thisRowLastSecondChar = currentLine.getCell(currentLine.length - 2) - const nextRowFirstChar = nextLine.getCell(0) - - if (thisRowLastChar) this._thisRowLastChar = thisRowLastChar - if (thisRowLastSecondChar) this._thisRowLastSecondChar = thisRowLastSecondChar - if (nextRowFirstChar) this._nextRowFirstChar = nextRowFirstChar - - const isNextRowFirstCharDoubleWidth = this._nextRowFirstChar.getWidth() > 1 - - let isValid = false - - if ( - this._nextRowFirstChar.getChars() && - (isNextRowFirstCharDoubleWidth ? this._nullCellCount <= 1 : this._nullCellCount <= 0) - ) { - if ( - (this._thisRowLastChar.getChars() || this._thisRowLastChar.getWidth() === 0) && - equalBg(this._thisRowLastChar, this._nextRowFirstChar) - ) { - isValid = true - } - - if ( - isNextRowFirstCharDoubleWidth && - (this._thisRowLastSecondChar.getChars() || this._thisRowLastSecondChar.getWidth() === 0) && - equalBg(this._thisRowLastChar, this._nextRowFirstChar) && - equalBg(this._thisRowLastSecondChar, this._nextRowFirstChar) - ) { - isValid = true - } - } - - if (!isValid) { - rowSeparator = "-".repeat(this._nullCellCount + 1) - rowSeparator += "\u001b[1D\u001b[1X" - - if (this._nullCellCount > 0) { - rowSeparator += "\u001b[A" - rowSeparator += `\u001b[${currentLine.length - this._nullCellCount}C` - rowSeparator += `\u001b[${this._nullCellCount}X` - rowSeparator += `\u001b[${currentLine.length - this._nullCellCount}D` - rowSeparator += "\u001b[B" - } - - this._lastContentCursorRow = row + 1 - this._lastContentCursorCol = 0 - this._lastCursorRow = row + 1 - this._lastCursorCol = 0 - } } } @@ -338,11 +279,36 @@ class StringSerializeHandler extends BaseSerializeHandler { sgrSeq.push(0) } } else { + if (flagsChanged) { + if (!!cell.isInverse() !== !!oldCell.isInverse()) { + sgrSeq.push(cell.isInverse() ? 7 : 27) + } + if (!!cell.isBold() !== !!oldCell.isBold()) { + sgrSeq.push(cell.isBold() ? 1 : 22) + } + if (!!cell.isUnderline() !== !!oldCell.isUnderline()) { + sgrSeq.push(cell.isUnderline() ? 4 : 24) + } + if (!!cell.isBlink() !== !!oldCell.isBlink()) { + sgrSeq.push(cell.isBlink() ? 5 : 25) + } + if (!!cell.isInvisible() !== !!oldCell.isInvisible()) { + sgrSeq.push(cell.isInvisible() ? 8 : 28) + } + if (!!cell.isItalic() !== !!oldCell.isItalic()) { + sgrSeq.push(cell.isItalic() ? 3 : 23) + } + if (!!cell.isDim() !== !!oldCell.isDim()) { + sgrSeq.push(cell.isDim() ? 2 : 22) + } + if (!!cell.isStrikethrough() !== !!oldCell.isStrikethrough()) { + sgrSeq.push(cell.isStrikethrough() ? 9 : 29) + } + } if (fgChanged) { const color = cell.getFgColor() const mode = cell.getFgColorMode() - if (mode === 2) { - // RGB + if (mode === 2 || mode === 3 || mode === -1) { sgrSeq.push(38, 2, (color >>> 16) & 0xff, (color >>> 8) & 0xff, color & 0xff) } else if (mode === 1) { // Palette @@ -358,8 +324,7 @@ class StringSerializeHandler extends BaseSerializeHandler { if (bgChanged) { const color = cell.getBgColor() const mode = cell.getBgColorMode() - if (mode === 2) { - // RGB + if (mode === 2 || mode === 3 || mode === -1) { sgrSeq.push(48, 2, (color >>> 16) & 0xff, (color >>> 8) & 0xff, color & 0xff) } else if (mode === 1) { // Palette @@ -372,32 +337,6 @@ class StringSerializeHandler extends BaseSerializeHandler { sgrSeq.push(49) } } - if (flagsChanged) { - if (!!cell.isInverse() !== !!oldCell.isInverse()) { - sgrSeq.push(cell.isInverse() ? 7 : 27) - } - if (!!cell.isBold() !== !!oldCell.isBold()) { - sgrSeq.push(cell.isBold() ? 1 : 22) - } - if (!!cell.isUnderline() !== !!oldCell.isUnderline()) { - sgrSeq.push(cell.isUnderline() ? 4 : 24) - } - if (!!cell.isBlink() !== !!oldCell.isBlink()) { - sgrSeq.push(cell.isBlink() ? 5 : 25) - } - if (!!cell.isInvisible() !== !!oldCell.isInvisible()) { - sgrSeq.push(cell.isInvisible() ? 8 : 28) - } - if (!!cell.isItalic() !== !!oldCell.isItalic()) { - sgrSeq.push(cell.isItalic() ? 3 : 23) - } - if (!!cell.isDim() !== !!oldCell.isDim()) { - sgrSeq.push(cell.isDim() ? 2 : 22) - } - if (!!cell.isStrikethrough() !== !!oldCell.isStrikethrough()) { - sgrSeq.push(cell.isStrikethrough() ? 9 : 29) - } - } } } @@ -405,9 +344,31 @@ class StringSerializeHandler extends BaseSerializeHandler { } private _isAttributeDefault(cell: IBufferCell): boolean { + const mode = cell.getFgColorMode() + const bgMode = cell.getBgColorMode() + + if (mode === 0 && bgMode === 0) { + return ( + !cell.isBold() && + !cell.isItalic() && + !cell.isUnderline() && + !cell.isBlink() && + !cell.isInverse() && + !cell.isInvisible() && + !cell.isDim() && + !cell.isStrikethrough() + ) + } + + const fgColor = cell.getFgColor() + const bgColor = cell.getBgColor() + const nullCell = this._buffer.getNullCell() + const nullFg = nullCell.getFgColor() + const nullBg = nullCell.getBgColor() + return ( - cell.getFgColorMode() === 0 && - cell.getBgColorMode() === 0 && + fgColor === nullFg && + bgColor === nullBg && !cell.isBold() && !cell.isItalic() && !cell.isUnderline() && @@ -426,7 +387,9 @@ class StringSerializeHandler extends BaseSerializeHandler { return } - const isEmptyCell = cell.getChars() === "" + const codepoint = cell.getCode() + const isGarbage = codepoint >= 0xf000 + const isEmptyCell = codepoint === 0 || cell.getChars() === "" || isGarbage const sgrSeq = this._diffStyle(cell, this._cursorStyle) @@ -434,9 +397,6 @@ class StringSerializeHandler extends BaseSerializeHandler { if (styleChanged) { if (this._nullCellCount > 0) { - if (!equalBg(this._cursorStyle, this._backgroundCell)) { - this._currentRow += `\u001b[${this._nullCellCount}X` - } this._currentRow += `\u001b[${this._nullCellCount}C` this._nullCellCount = 0 } @@ -450,8 +410,6 @@ class StringSerializeHandler extends BaseSerializeHandler { const cellFromLine = line?.getCell(col) if (cellFromLine) { this._cursorStyle = cellFromLine - this._cursorStyleRow = row - this._cursorStyleCol = col } } @@ -459,12 +417,7 @@ class StringSerializeHandler extends BaseSerializeHandler { this._nullCellCount += cell.getWidth() } else { if (this._nullCellCount > 0) { - if (equalBg(this._cursorStyle, this._backgroundCell)) { - this._currentRow += `\u001b[${this._nullCellCount}C` - } else { - this._currentRow += `\u001b[${this._nullCellCount}X` - this._currentRow += `\u001b[${this._nullCellCount}C` - } + this._currentRow += `\u001b[${this._nullCellCount}C` this._nullCellCount = 0 } |
