diff --git a/demo/client.ts b/demo/client.ts index 49ba67438e..6e0be22f57 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -366,14 +366,19 @@ function createTerminal(): void { // Set terminal size again to set the specific dimensions on the demo updateTerminalSize(); - const res = await fetch('/terminals?cols=' + term.cols + '&rows=' + term.rows, { method: 'POST' }); - const processId = await res.text(); - pid = processId; - socketURL += processId; - socket = new WebSocket(socketURL); - socket.onopen = runRealTerminal; - socket.onclose = runFakeTerminal; - socket.onerror = runFakeTerminal; + const useRealTerminal = document.getElementById('use-real-terminal'); + if (useRealTerminal instanceof HTMLInputElement && !useRealTerminal.checked) { + runFakeTerminal(); + } else { + const res = await fetch('/terminals?cols=' + term.cols + '&rows=' + term.rows, { method: 'POST' }); + const processId = await res.text(); + pid = processId; + socketURL += processId; + socket = new WebSocket(socketURL); + socket.onopen = runRealTerminal; + socket.onclose = runFakeTerminal; + socket.onerror = runFakeTerminal; + } }, 0); } diff --git a/demo/index.html b/demo/index.html index 064518475b..3d46f61cab 100644 --- a/demo/index.html +++ b/demo/index.html @@ -81,6 +81,7 @@

Test

Lifecycle
+
diff --git a/src/common/buffer/Buffer.ts b/src/common/buffer/Buffer.ts index d5e057318a..81ab156b57 100644 --- a/src/common/buffer/Buffer.ts +++ b/src/common/buffer/Buffer.ts @@ -315,7 +315,8 @@ export class Buffer implements IBuffer { } private _reflowLarger(newCols: number, newRows: number): void { - const toRemove: number[] = reflowLargerGetLinesToRemove(this.lines, this._cols, newCols, this.ybase + this.y, this.getNullCell(DEFAULT_ATTR_DATA)); + const reflowCursorLine = this._optionsService.rawOptions.reflowCursorLine; + const toRemove: number[] = reflowLargerGetLinesToRemove(this.lines, this._cols, newCols, this.ybase + this.y, this.getNullCell(DEFAULT_ATTR_DATA), reflowCursorLine); if (toRemove.length > 0) { const newLayoutResult = reflowLargerCreateNewLayout(this.lines, toRemove); reflowLargerApplyNewLayout(this.lines, newLayoutResult.layout); @@ -347,6 +348,7 @@ export class Buffer implements IBuffer { } private _reflowSmaller(newCols: number, newRows: number): void { + const reflowCursorLine = this._optionsService.rawOptions.reflowCursorLine; const nullCell = this.getNullCell(DEFAULT_ATTR_DATA); // Gather all BufferLines that need to be inserted into the Buffer here so that they can be // batched up and only committed once @@ -367,11 +369,13 @@ export class Buffer implements IBuffer { wrappedLines.unshift(nextLine); } - // If these lines contain the cursor don't touch them, the program will handle fixing up - // wrapped lines with the cursor - const absoluteY = this.ybase + this.y; - if (absoluteY >= y && absoluteY < y + wrappedLines.length) { - continue; + if (!reflowCursorLine) { + // If these lines contain the cursor don't touch them, the program will handle fixing up + // wrapped lines with the cursor + const absoluteY = this.ybase + this.y; + if (absoluteY >= y && absoluteY < y + wrappedLines.length) { + continue; + } } const lastLineLength = wrappedLines[wrappedLines.length - 1].getTrimmedLength(); diff --git a/src/common/buffer/BufferReflow.ts b/src/common/buffer/BufferReflow.ts index af1c64738e..44aa0976fe 100644 --- a/src/common/buffer/BufferReflow.ts +++ b/src/common/buffer/BufferReflow.ts @@ -20,8 +20,9 @@ export interface INewLayoutResult { * @param newCols The columns after resize. * @param bufferAbsoluteY The absolute y position of the cursor (baseY + cursorY). * @param nullCell The cell data to use when filling in empty cells. + * @param reflowCursorLine Whether to reflow the line containing the cursor. */ -export function reflowLargerGetLinesToRemove(lines: CircularList, oldCols: number, newCols: number, bufferAbsoluteY: number, nullCell: ICellData): number[] { +export function reflowLargerGetLinesToRemove(lines: CircularList, oldCols: number, newCols: number, bufferAbsoluteY: number, nullCell: ICellData, reflowCursorLine: boolean): number[] { // Gather all BufferLines that need to be removed from the Buffer here so that they can be // batched up and only committed once const toRemove: number[] = []; @@ -41,11 +42,13 @@ export function reflowLargerGetLinesToRemove(lines: CircularList, o nextLine = lines.get(++i) as BufferLine; } - // If these lines contain the cursor don't touch them, the program will handle fixing up wrapped - // lines with the cursor - if (bufferAbsoluteY >= y && bufferAbsoluteY < i) { - y += wrappedLines.length - 1; - continue; + if (!reflowCursorLine) { + // If these lines contain the cursor don't touch them, the program will handle fixing up + // wrapped lines with the cursor + if (bufferAbsoluteY >= y && bufferAbsoluteY < i) { + y += wrappedLines.length - 1; + continue; + } } // Copy buffer data to new locations diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index a757c17916..4b8ca82271 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -44,6 +44,7 @@ export const DEFAULT_OPTIONS: Readonly> = { allowTransparency: false, tabStopWidth: 8, theme: {}, + reflowCursorLine: false, rescaleOverlappingGlyphs: false, rightClickSelectsWord: isMac, windowOptions: {}, diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index 0ceff36c4e..0e5c518484 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -237,6 +237,7 @@ export interface ITerminalOptions { macOptionIsMeta?: boolean; macOptionClickForcesSelection?: boolean; minimumContrastRatio?: number; + reflowCursorLine?: boolean; rescaleOverlappingGlyphs?: boolean; rightClickSelectsWord?: boolean; rows?: number; diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index 3cbde44b2b..1085db9b43 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -142,6 +142,13 @@ declare module '@xterm/headless' { */ minimumContrastRatio?: number; + /** + * Whether to reflow the line containing the cursor when the terminal is + * resized. Defaults to false, because shells usually handle this + * themselves. + */ + reflowCursorLine?: boolean; + /** * Whether to rescale glyphs horizontally that are a single cell wide but * have glyphs that would overlap following cell(s). This typically happens diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index f9cf14f9c7..15a0332789 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -213,6 +213,13 @@ declare module '@xterm/xterm' { */ minimumContrastRatio?: number; + /** + * Whether to reflow the line containing the cursor when the terminal is + * resized. Defaults to false, because shells usually handle this + * themselves. + */ + reflowCursorLine?: boolean; + /** * Whether to rescale glyphs horizontally that are a single cell wide but * have glyphs that would overlap following cell(s). This typically happens