diff --git a/addons/addon-fit/test/FitAddon.test.ts b/addons/addon-fit/test/FitAddon.test.ts index 6a7c41fa8..d82d3640a 100644 --- a/addons/addon-fit/test/FitAddon.test.ts +++ b/addons/addon-fit/test/FitAddon.test.ts @@ -26,18 +26,24 @@ test.describe('FitAddon', () => { `); }); - // test.beforeEach(async function(): Promise { - // await ctx.page.evaluate(`document.querySelector('#terminal-container').style.display=''`); - // await openTerminal(page); - // }); + /* + * test.beforeEach(async function(): Promise { + * await ctx.page.evaluate(`document.querySelector('#terminal-container').style.display=''`); + * await openTerminal(page); + * }); + */ - // after(async () => { - // await browser.close(); - // }); + /* + * after(async () => { + * await browser.close(); + * }); + */ - // afterEach(async function(): Promise { - // await ctx.proxy.dispose(); - // }); + /* + * afterEach(async function(): Promise { + * await ctx.proxy.dispose(); + * }); + */ test('no terminal', async function(): Promise { await ctx.page.evaluate(`window.fit2 = new FitAddon();`); @@ -79,8 +85,10 @@ test.describe('FitAddon', () => { await ctx.page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`); await setDimensions(); const dimensions: { cols: number, rows: number } | undefined = await ctx.page.evaluate(`window.fit.proposeDimensions()`); - // The value of dims will be undefined if the char measure strategy falls back to the DOM - // method, so only assert if it's not undefined. + /* + * The value of dims will be undefined if the char measure strategy falls back to the DOM + * method, so only assert if it's not undefined. + */ if (dimensions) { ok(dimensions.cols > 85); ok(dimensions.cols < 88); diff --git a/addons/addon-image/src/IIPHeaderParser.ts b/addons/addon-image/src/IIPHeaderParser.ts index af4e9a68d..74e753289 100644 --- a/addons/addon-image/src/IIPHeaderParser.ts +++ b/addons/addon-image/src/IIPHeaderParser.ts @@ -24,8 +24,10 @@ export interface IHeaderFields { height?: string; // Optional, defaults to 1 respecting aspect ratio (width takes precedence). preserveAspectRatio?: number; - // Optional, defaults to 0. If set to 1, the file will be displayed inline, else downloaded - // (download not supported). + /* + * Optional, defaults to 0. If set to 1, the file will be displayed inline, else downloaded + * (download not supported). + */ inline?: number; } diff --git a/addons/addon-image/src/IIPMetrics.ts b/addons/addon-image/src/IIPMetrics.ts index b377cf061..1937a2740 100644 --- a/addons/addon-image/src/IIPMetrics.ts +++ b/addons/addon-image/src/IIPMetrics.ts @@ -23,8 +23,10 @@ export function imageType(d: Uint8Array): IMetrics { return UNSUPPORTED_TYPE; } const d32 = new Uint32Array(d.buffer, d.byteOffset, 6); - // PNG: 89 50 4E 47 0D 0A 1A 0A (8 first bytes == magic number for PNG) - // + first chunk must be IHDR + /* + * PNG: 89 50 4E 47 0D 0A 1A 0A (8 first bytes == magic number for PNG) + * + first chunk must be IHDR + */ if (d32[0] === 0x474E5089 && d32[1] === 0x0A1A0A0D && d32[3] === 0x52444849) { return { mime: 'image/png', diff --git a/addons/addon-image/src/ImageAddon.ts b/addons/addon-image/src/ImageAddon.ts index 7e0f29d3f..930a74bd8 100644 --- a/addons/addon-image/src/ImageAddon.ts +++ b/addons/addon-image/src/ImageAddon.ts @@ -137,11 +137,13 @@ export class ImageAddon implements ITerminalAddon, IImageApi { // enable size reports if (this._opts.enableSizeReports) { - // const windowOptions = terminal.getOption('windowOptions'); - // windowOptions.getWinSizePixels = true; - // windowOptions.getCellSizePixels = true; - // windowOptions.getWinSizeChars = true; - // terminal.setOption('windowOptions', windowOptions); + /* + * const windowOptions = terminal.getOption('windowOptions'); + * windowOptions.getWinSizePixels = true; + * windowOptions.getCellSizePixels = true; + * windowOptions.getWinSizeChars = true; + * terminal.setOption('windowOptions', windowOptions); + */ const windowOps = terminal.options.windowOptions ?? {}; windowOps.getWinSizePixels = true; windowOps.getCellSizePixels = true; @@ -290,11 +292,13 @@ export class ImageAddon implements ITerminalAddon, IImageApi { if (params[0]) { return true; } - // reported features: - // 62 - VT220 - // 4 - SIXEL support - // 9 - charsets - // 22 - ANSI colors + /* + * reported features: + * 62 - VT220 + * 4 - SIXEL support + * 9 - charsets + * 22 - ANSI colors + */ if (this._opts.sixelSupport) { this._report(`\x1b[?62;4;9;22c`); return true; @@ -352,8 +356,10 @@ export class ImageAddon implements ITerminalAddon, IImageApi { let width = this._renderer?.dimensions?.css.canvas.width; let height = this._renderer?.dimensions?.css.canvas.height; if (!width || !height) { - // for some reason we have no working image renderer - // --> fallback to default cell size + /* + * for some reason we have no working image renderer + * --> fallback to default cell size + */ const cellSize = CELL_SIZE_DEFAULT; width = (this._terminal?.cols || 80) * cellSize.width; height = (this._terminal?.rows || 24) * cellSize.height; diff --git a/addons/addon-image/src/ImageRenderer.ts b/addons/addon-image/src/ImageRenderer.ts index b36cdd004..b00002ca2 100644 --- a/addons/addon-image/src/ImageRenderer.ts +++ b/addons/addon-image/src/ImageRenderer.ts @@ -197,10 +197,12 @@ export class ImageRenderer extends Disposable implements IDisposable { const finalWidth = count * width + sx > img.width ? img.width - sx : count * width; const finalHeight = sy + height > img.height ? img.height - sy : height; - // Floor all pixel offsets to get stable tile mapping without any overflows. - // Note: For not pixel perfect aligned cells like in the DOM renderer - // this will move a tile slightly to the top/left (subpixel range, thus ignore it). - // FIX #34: avoid striping on displays with pixelDeviceRatio != 1 by ceiling height and width + /* + * Floor all pixel offsets to get stable tile mapping without any overflows. + * Note: For not pixel perfect aligned cells like in the DOM renderer + * this will move a tile slightly to the top/left (subpixel range, thus ignore it). + * FIX #34: avoid striping on displays with pixelDeviceRatio != 1 by ceiling height and width + */ ctx.drawImage( img, Math.floor(sx), Math.floor(sy), Math.ceil(finalWidth), Math.ceil(finalHeight), @@ -342,21 +344,27 @@ export class ImageRenderer extends Disposable implements IDisposable { ); canvas.classList.add(`xterm-image-layer-${layer}`); const screenElement = this._terminal._core.screenElement; - // Use isolation to create a stacking context without overriding z-index, - // which would conflict with integrators (e.g. VS Code) that set their - // own z-index on the screen element. + /* + * Use isolation to create a stacking context without overriding z-index, + * which would conflict with integrators (e.g. VS Code) that set their + * own z-index on the screen element. + */ screenElement.style.isolation = 'isolate'; if (layer === 'bottom') { - // Use z-index:-1 so it paints behind non-positioned text elements. - // The screen element needs to be a stacking context (via isolation) - // to contain the negative z-index, otherwise it would go behind the - // entire terminal. + /* + * Use z-index:-1 so it paints behind non-positioned text elements. + * The screen element needs to be a stacking context (via isolation) + * to contain the negative z-index, otherwise it would go behind the + * entire terminal. + */ canvas.style.zIndex = '-1'; screenElement.insertBefore(canvas, screenElement.firstChild); } else { - // Explicit z-index ensures the image canvas reliably stacks above - // the text layer (DOM renderer rows). z-index: 0 is below the - // selection overlay (z-index: 1). + /* + * Explicit z-index ensures the image canvas reliably stacks above + * the text layer (DOM renderer rows). z-index: 0 is below the + * selection overlay (z-index: 1). + */ canvas.style.zIndex = '0'; screenElement.appendChild(canvas); } diff --git a/addons/addon-image/src/ImageStorage.ts b/addons/addon-image/src/ImageStorage.ts index 8c89a16b0..3e3a7c298 100644 --- a/addons/addon-image/src/ImageStorage.ts +++ b/addons/addon-image/src/ImageStorage.ts @@ -154,8 +154,10 @@ export class ImageStorage implements IDisposable { for (const spec of this._images.values()) { spec.marker?.dispose(); } - // NOTE: marker.dispose above already calls ImageBitmap.close - // therefore we can just wipe the map here + /* + * NOTE: marker.dispose above already calls ImageBitmap.close + * therefore we can just wipe the map here + */ this._images.clear(); this._renderer.clearAll(); } @@ -306,8 +308,10 @@ export class ImageStorage implements IDisposable { this._delImg(id); } - // eviction marker: - // delete the image when the marker gets disposed + /* + * eviction marker: + * delete the image when the marker gets disposed + */ const endMarker = this._terminal.registerMarker(0); endMarker?.onDispose(() => { const spec = this._images.get(imageId); @@ -316,8 +320,10 @@ export class ImageStorage implements IDisposable { } }); - // since markers do not work on alternate for some reason, - // we evict images here manually + /* + * since markers do not work on alternate for some reason, + * we evict images here manually + */ if (this._terminal.buffer.active.type === 'alternate') { this._evictOnAlternate(); } @@ -416,10 +422,12 @@ export class ImageStorage implements IDisposable { const drawCalls: { imgSpec: IImageSpec, tileId: number, col: number, row: number, count: number }[] = []; const placeholderCalls: { col: number, row: number, count: number }[] = []; - // walk all cells in viewport and collect tiles found - // Note: We check _extendedAttrs directly (not just HAS_EXTENDED flag) - // because text writes clear the BG flag but leave image tile data intact. - // This lets top-layer images survive text overwrites (kitty C=1 behavior). + /* + * walk all cells in viewport and collect tiles found + * Note: We check _extendedAttrs directly (not just HAS_EXTENDED flag) + * because text writes clear the BG flag but leave image tile data intact. + * This lets top-layer images survive text overwrites (kitty C=1 behavior). + */ for (let row = start; row <= end; ++row) { const line = buffer.lines.get(row + buffer.ydisp) as IBufferLineExt; if (!line) return; @@ -492,8 +500,10 @@ export class ImageStorage implements IDisposable { return; } - // handle only viewport width enlargements, exit all other cases - // TODO: needs patch for tile counter + /* + * handle only viewport width enlargements, exit all other cases + * TODO: needs patch for tile counter + */ if (this._viewportMetrics.cols >= metrics.cols) { this._viewportMetrics = metrics; return; @@ -581,8 +591,10 @@ export class ImageStorage implements IDisposable { } } - // TODO: Do we need some blob offloading tricks here to avoid early eviction? - // also see https://stackoverflow.com/questions/28307789/is-there-any-limitation-on-javascript-max-blob-size + /* + * TODO: Do we need some blob offloading tricks here to avoid early eviction? + * also see https://stackoverflow.com/questions/28307789/is-there-any-limitation-on-javascript-max-blob-size + */ private _evictOldest(room: number): number { const used = this._getStoredPixels(); let current = used; @@ -605,9 +617,11 @@ export class ImageStorage implements IDisposable { const old = line._extendedAttrs[x]; if (old) { if (old.imageId !== undefined) { - // found an old ExtendedAttrsImage, since we know that - // they are always isolated instances (single cell usage), - // we can re-use it and just update their id entries + /* + * found an old ExtendedAttrsImage, since we know that + * they are always isolated instances (single cell usage), + * we can re-use it and just update their id entries + */ const oldSpec = this._images.get(old.imageId); if (oldSpec) { // early eviction for in-viewport overwrites diff --git a/addons/addon-image/src/SixelHandler.ts b/addons/addon-image/src/SixelHandler.ts index 1af2d85bc..da4798bf6 100644 --- a/addons/addon-image/src/SixelHandler.ts +++ b/addons/addon-image/src/SixelHandler.ts @@ -113,13 +113,17 @@ export class SixelHandler implements IDcsHandler, IResetHandler { * Some helpers to extract current terminal colors. */ -// get currently active background color from terminal -// also respect INVERSE setting +/* + * get currently active background color from terminal + * also respect INVERSE setting + */ function extractActiveBg(attr: AttributeData, colors: ReadonlyColorSet | undefined): RGBA8888 { let bg = 0; if (!colors) { - // FIXME: theme service is prolly not available yet, - // happens if .open() was not called yet (bug in core?) + /* + * FIXME: theme service is prolly not available yet, + * happens if .open() was not called yet (bug in core?) + */ return bg; } if (attr.isInverse()) { diff --git a/addons/addon-image/src/kitty/KittyGraphicsHandler.ts b/addons/addon-image/src/kitty/KittyGraphicsHandler.ts index de889dfff..8ad8ef794 100644 --- a/addons/addon-image/src/kitty/KittyGraphicsHandler.ts +++ b/addons/addon-image/src/kitty/KittyGraphicsHandler.ts @@ -62,9 +62,11 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos // Storage related states private _pendingTransmissions: Map = new Map(); - // Tracks the pending key of the most recently started chunked upload. - // Per spec, subsequent chunks only need m= (and optionally q=), without i=. - // When a chunk arrives with no i=, this key is used to find the pending upload. + /* + * Tracks the pending key of the most recently started chunked upload. + * Per spec, subsequent chunks only need m= (and optionally q=), without i=. + * When a chunk arrives with no i=, this key is used to find the pending upload. + */ private _lastPendingKey: number | undefined; constructor( @@ -173,9 +175,11 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos private _streamPayload(data: Uint32Array, start: number, end: number): void { if (this._aborted) return; - // Check size limit (compare encoded bytes against pre-calculated limit) - // Include cumulative size from pending transmission for multi-chunk images. - // Per spec, subsequent chunks may omit i=, so fall back to _lastPendingKey. + /* + * Check size limit (compare encoded bytes against pre-calculated limit) + * Include cumulative size from pending transmission for multi-chunk images. + * Per spec, subsequent chunks may omit i=, so fall back to _lastPendingKey. + */ const pendingKey = this._parsedCommand?.id ?? this._lastPendingKey ?? 0; const pending = this._pendingTransmissions.get(pendingKey); const previousEncodedSize = pending?.totalEncodedSize ?? 0; @@ -285,9 +289,11 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos } this._activeDecoder = null; - // Handle command first — handlers create Blob/ImageData from imageBytes, - // which copies the data. Only then is it safe to release the decoder's - // wasm memory that imageBytes points into. + /* + * Handle command first — handlers create Blob/ImageData from imageBytes, + * which copies the data. Only then is it safe to release the decoder's + * wasm memory that imageBytes points into. + */ const result = this._handleCommandWithBytesAndCmd(finalCmd, imageBytes, decodeError); if (decoder) { decoder.release(); @@ -325,10 +331,12 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos case KittyAction.PLACEMENT: return this._handlePlacement(cmd); default: - // TODO: Implement remaining actions when needed: - // - a=f (frame): animation frame operations - // - a=a (animation): animation control - // - a=c (compose): compose images + /* + * TODO: Implement remaining actions when needed: + * - a=f (frame): animation frame operations + * - a=a (animation): animation control + * - a=c (compose): compose images + */ if (cmd.id !== undefined) { this._sendResponse(cmd.id, 'EINVAL:unsupported action', cmd.quiet ?? 0); } @@ -342,8 +350,10 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos switch (action) { case KittyAction.TRANSMIT: { const result = this._handleTransmit(cmd, bytes, decodeError); - // Only send response when _handleTransmit didn't already respond - // (it handles unsupported transmission medium responses internally) + /* + * Only send response when _handleTransmit didn't already respond + * (it handles unsupported transmission medium responses internally) + */ if ((cmd.transmission ?? 'd') === 'd' && cmd.id !== undefined) { if (decodeError) { this._sendResponse(cmd.id, 'EINVAL:invalid base64 data', cmd.quiet ?? 0); @@ -361,10 +371,12 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos // a=p ignores any payload — image data was already transmitted return this._handlePlacement(cmd); default: - // TODO: Implement remaining actions when needed: - // - a=f (frame): animation frame operations - // - a=a (animation): animation control - // - a=c (compose): compose images + /* + * TODO: Implement remaining actions when needed: + * - a=f (frame): animation frame operations + * - a=a (animation): animation control + * - a=c (compose): compose images + */ if (cmd.id !== undefined) { this._sendResponse(cmd.id, 'EINVAL:unsupported action', cmd.quiet ?? 0); } @@ -390,16 +402,18 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos } private _handleTransmit(cmd: IKittyCommand, bytes: Uint8Array, decodeError: boolean): boolean { - // TODO: Support file-based transmission modes (t=f, t=t, t=s) - // Currently only supports direct transmission (t=d, the default). - // - t=f (file): Payload is base64-encoded file path. Terminal reads image from that path. - // - t=t (temp file): Payload is base64-encoded path in temp directory. Terminal reads, deletes. - // - t=s: Payload is base64-encoded POSIX shm name. Terminal reads from shared memory. - // These modes require filesystem/IPC access not available in browsers. For Node.js/Electron: - // 1. Check cmd.transmission (t key) before treating bytes as image data - // 2. For t=f/t/s: decode bytes as UTF-8 string (the path/name), then read file contents - // 3. For t=d: treat bytes as image data (current behavior) - // When implementing, also update _handleQuery to accept these transmission mediums. + /* + * TODO: Support file-based transmission modes (t=f, t=t, t=s) + * Currently only supports direct transmission (t=d, the default). + * - t=f (file): Payload is base64-encoded file path. Terminal reads image from that path. + * - t=t (temp file): Payload is base64-encoded path in temp directory. Terminal reads, deletes. + * - t=s: Payload is base64-encoded POSIX shm name. Terminal reads from shared memory. + * These modes require filesystem/IPC access not available in browsers. For Node.js/Electron: + * 1. Check cmd.transmission (t key) before treating bytes as image data + * 2. For t=f/t/s: decode bytes as UTF-8 string (the path/name), then read file contents + * 3. For t=d: treat bytes as image data (current behavior) + * When implementing, also update _handleQuery to accept these transmission mediums. + */ const transmission = cmd.transmission ?? 'd'; if (transmission !== 'd') { if (cmd.id !== undefined) { @@ -449,9 +463,11 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos const id = cmd.id ?? 0; const quiet = cmd.quiet ?? 0; - // Per spec: reject unsupported transmission mediums (only t=d is supported atm) - // TODO: When filesystem support is added (Node.js/Electron), update this to accept - // t=f (file), t=t (temp file), and t=s (shared memory) and respond OK for queries. + /* + * Per spec: reject unsupported transmission mediums (only t=d is supported atm) + * TODO: When filesystem support is added (Node.js/Electron), update this to accept + * t=f (file), t=t (temp file), and t=s (shared memory) and respond OK for queries. + */ const transmission = cmd.transmission ?? 'd'; if (transmission !== 'd') { this._sendResponse(id, 'EINVAL:unsupported transmission medium', quiet); @@ -500,9 +516,11 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos // Per spec: default delete selector is 'a' (delete all visible placements) const selector = cmd.deleteSelector ?? 'a'; - // TODO: Distinguish lowercase (delete placements only) from uppercase - // (delete placements + free stored image data). Currently both variants - // free everything since we don't separate stored data from placements. + /* + * TODO: Distinguish lowercase (delete placements only) from uppercase + * (delete placements + free stored image data). Currently both variants + * free everything since we don't separate stored data from placements. + */ switch (selector) { case 'a': case 'A': @@ -511,10 +529,12 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos break; case 'i': case 'I': - // TODO: When placement id tracking is implemented (see TODO in - // KittyImageStorage), d=i with p= should delete only that - // specific placement, while d=i without p should delete all - // placements for the image. + /* + * TODO: When placement id tracking is implemented (see TODO in + * KittyImageStorage), d=i with p= should delete only that + * specific placement, while d=i without p should delete all + * placements for the image. + */ if (cmd.id !== undefined) { const pending = this._pendingTransmissions.get(cmd.id); if (pending) { @@ -576,8 +596,10 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos const cw = this._renderer.dimensions?.css.cell.width || CELL_SIZE_DEFAULT.width; const ch = this._renderer.dimensions?.css.cell.height || CELL_SIZE_DEFAULT.height; - // Per spec: c/r default to image's natural cell dimensions. - // If only one of c/r is specified, compute the other from image aspect ratio. + /* + * Per spec: c/r default to image's natural cell dimensions. + * If only one of c/r is specified, compute the other from image aspect ratio. + */ let imgCols: number; let imgRows: number; if (cmd.columns !== undefined && cmd.rows !== undefined) { @@ -613,10 +635,12 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos const savedY = buffer.y; const savedYbase = buffer.ybase; - // Determine layer based on z-index: negative = behind text, 0+ = on top. - // When z<0 we always use the bottom layer even without allowTransparency — - // the image will simply be hidden behind the opaque text background, which - // is the correct behavior (client asked for "behind text"). + /* + * Determine layer based on z-index: negative = behind text, 0+ = on top. + * When z<0 we always use the bottom layer even without allowTransparency — + * the image will simply be hidden behind the opaque text background, which + * is the correct behavior (client asked for "behind text"). + */ const wantsBottom = cmd.zIndex !== undefined && cmd.zIndex < 0; const layer: ImageLayer = wantsBottom ? 'bottom' : 'top'; @@ -630,10 +654,12 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos const xOffset = Math.min(Math.max(0, cmd.xOffset ?? 0), cw - 1); const yOffset = Math.min(Math.max(0, cmd.yOffset ?? 0), ch - 1); if (xOffset !== 0 || yOffset !== 0) { - // Per spec: X/Y is not added to c/r area. When c/r are explicit, the - // total placement area remains c*cw × r*ch pixels and the offset image - // is clipped to fit. When c/r are unset, the padded canvas determines - // the natural cell dimensions. + /* + * Per spec: X/Y is not added to c/r area. When c/r are explicit, the + * total placement area remains c*cw × r*ch pixels and the offset image + * is clipped to fit. When c/r are unset, the padded canvas determines + * the natural cell dimensions. + */ const canvasW = (cmd.columns !== undefined) ? Math.round(imgCols * cw) : bitmap.width + xOffset; const canvasH = (cmd.rows !== undefined) ? Math.round(imgRows * ch) : bitmap.height + yOffset; const offsetCanvas = ImageRenderer.createCanvas(window.document, canvasW, canvasH); @@ -664,9 +690,11 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos this._kittyStorage.addImage(image.id, bitmap, true, layer, zIndex); bitmap = undefined; // ownership transferred to storage - // Kitty cursor movement - // Per spec: cursor placed at first column after last image column, - // on the last row of the image. C=1 means don't move cursor. + /* + * Kitty cursor movement + * Per spec: cursor placed at first column after last image column, + * on the last row of the image. C=1 means don't move cursor. + */ if (cmd.cursorMovement === 1) { // C=1: restore cursor to position before image was placed const scrolled = buffer.ybase - savedYbase; @@ -674,8 +702,10 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos // Can't restore cursor to scrollback? buffer.y = Math.max(savedY - scrolled, 0); } else { - // Default (C=0): advance cursor horizontally past the image - // addImage already positioned cursor on the last row via lineFeeds + /* + * Default (C=0): advance cursor horizontally past the image + * addImage already positioned cursor on the last row via lineFeeds + */ buffer.x = Math.min(savedX + imgCols, this._coreTerminal.cols); } } catch (e) { @@ -736,9 +766,11 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos return createImageBitmap(new ImageData(new Uint8ClampedArray(bytes.buffer as ArrayBuffer, bytes.byteOffset, pixelCount * KittyPixelConstants.BYTES_PER_PIXEL_RGBA), width, height)); } - // RGB→RGBA: interleave alpha using uint32 block processing (4 pixels per iteration). - // 3 uint32 reads + 4 uint32 writes per 4 pixels vs 28 byte reads/writes — ~6x faster. - // Assumes little-endian (all modern browsers/Node.js). + /* + * RGB→RGBA: interleave alpha using uint32 block processing (4 pixels per iteration). + * 3 uint32 reads + 4 uint32 writes per 4 pixels vs 28 byte reads/writes — ~6x faster. + * Assumes little-endian (all modern browsers/Node.js). + */ const data = new Uint8ClampedArray(pixelCount * KittyPixelConstants.BYTES_PER_PIXEL_RGBA); const src32 = new Uint32Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 4)); const dst32 = new Uint32Array(data.buffer); diff --git a/addons/addon-image/src/kitty/KittyGraphicsTypes.ts b/addons/addon-image/src/kitty/KittyGraphicsTypes.ts index 448ebcc05..da94675d8 100644 --- a/addons/addon-image/src/kitty/KittyGraphicsTypes.ts +++ b/addons/addon-image/src/kitty/KittyGraphicsTypes.ts @@ -7,8 +7,10 @@ import type Base64Decoder from 'xterm-wasm-parts/lib/base64/Base64Decoder.wasm'; -// Kitty graphics protocol action types. -// See: https://sw.kovidgoyal.net/kitty/graphics-protocol/#control-data-reference under key 'a'. +/* + * Kitty graphics protocol action types. + * See: https://sw.kovidgoyal.net/kitty/graphics-protocol/#control-data-reference under key 'a'. + */ export const enum KittyAction { TRANSMIT = 't', TRANSMIT_DISPLAY = 'T', @@ -17,23 +19,29 @@ export const enum KittyAction { DELETE = 'd' } -// Kitty graphics protocol format types. -// See: https://sw.kovidgoyal.net/kitty/graphics-protocol/#control-data-reference +/* + * Kitty graphics protocol format types. + * See: https://sw.kovidgoyal.net/kitty/graphics-protocol/#control-data-reference + */ export const enum KittyFormat { RGB = 24, RGBA = 32, PNG = 100 } -// Kitty graphics protocol compression types. -// See: https://sw.kovidgoyal.net/kitty/graphics-protocol/#control-data-reference under key 'o'. +/* + * Kitty graphics protocol compression types. + * See: https://sw.kovidgoyal.net/kitty/graphics-protocol/#control-data-reference under key 'o'. + */ export const enum KittyCompression { NONE = '', ZLIB = 'z' } -// Kitty graphics protocol control data keys. -// See: https://sw.kovidgoyal.net/kitty/graphics-protocol/#control-data-reference +/* + * Kitty graphics protocol control data keys. + * See: https://sw.kovidgoyal.net/kitty/graphics-protocol/#control-data-reference + */ export const enum KittyKey { // Action to perform (t=transmit, T=transmit+display, q=query, p=placement, d=delete) ACTION = 'a', @@ -115,8 +123,10 @@ export interface IKittyCommand { payload?: string; } -// Pending chunked transmission state. -// Stores metadata from the first chunk while accumulating decoded payload data. +/* + * Pending chunked transmission state. + * Stores metadata from the first chunk while accumulating decoded payload data. + */ export interface IPendingTransmission { // The parsed command from the first chunk (contains action, format, dimensions, etc.) cmd: IKittyCommand; diff --git a/addons/addon-image/src/kitty/KittyImageStorage.ts b/addons/addon-image/src/kitty/KittyImageStorage.ts index 95ea594c7..766806532 100644 --- a/addons/addon-image/src/kitty/KittyImageStorage.ts +++ b/addons/addon-image/src/kitty/KittyImageStorage.ts @@ -8,27 +8,31 @@ import { ImageStorage } from '../ImageStorage'; import { ImageLayer } from '../Types'; import { IKittyImageData } from './KittyGraphicsTypes'; -// Kitty-specific image storage controller. -// -// Wraps shared ImageStorage with kitty protocol semantics: -// - tracks transmitted image payloads by kitty image id -// - tracks kitty image id -> shared ImageStorage id mapping for displayed images -// - mirrors shared-storage evictions into kitty maps -// - applies protocol-level undisplayed-image eviction policy +/* + * Kitty-specific image storage controller. + * + * Wraps shared ImageStorage with kitty protocol semantics: + * - tracks transmitted image payloads by kitty image id + * - tracks kitty image id -> shared ImageStorage id mapping for displayed images + * - mirrors shared-storage evictions into kitty maps + * - applies protocol-level undisplayed-image eviction policy + */ export class KittyImageStorage implements IDisposable { private static readonly _maxStoredImages = 256; private _nextImageId = 1; private readonly _images: Map = new Map(); - // TODO: Support multiple placements per image. The kitty spec identifies - // placements by an (image id, placement id) pair — same i + different p - // values should coexist, and same i + same p should replace the prior - // placement. Currently we track only one storage entry per kitty image id, - // so multiple placements of the same image overwrite each other. Fixing - // this requires changing these maps to Map> - // (kittyId → placementId → storageId) and updating addImage/deleteById - // accordingly. The underlying shared ImageStorage would also need to - // support multiple entries per logical image. + /* + * TODO: Support multiple placements per image. The kitty spec identifies + * placements by an (image id, placement id) pair — same i + different p + * values should coexist, and same i + same p should replace the prior + * placement. Currently we track only one storage entry per kitty image id, + * so multiple placements of the same image overwrite each other. Fixing + * this requires changing these maps to Map> + * (kittyId → placementId → storageId) and updating addImage/deleteById + * accordingly. The underlying shared ImageStorage would also need to + * support multiple entries per logical image. + */ private readonly _kittyIdToStorageId: Map = new Map(); private readonly _storageIdToKittyId: Map = new Map(); @@ -90,10 +94,12 @@ export class KittyImageStorage implements IDisposable { } public addImage(kittyId: number, image: HTMLCanvasElement | ImageBitmap, scrolling: boolean, layer: ImageLayer, zIndex: number): void { - // Clean up stale reverse-mapping from a previous placement of the same - // kitty image. The old shared-storage entry is kept (it may still be - // visible on screen) but its reverse mapping is removed so that eviction - // of the old entry won't incorrectly delete the kitty image data. + /* + * Clean up stale reverse-mapping from a previous placement of the same + * kitty image. The old shared-storage entry is kept (it may still be + * visible on screen) but its reverse mapping is removed so that eviction + * of the old entry won't incorrectly delete the kitty image data. + */ const oldStorageId = this._kittyIdToStorageId.get(kittyId); if (oldStorageId !== undefined) { this._storageIdToKittyId.delete(oldStorageId); diff --git a/addons/addon-image/test/ImageAddon.test.ts b/addons/addon-image/test/ImageAddon.test.ts index dc729ec63..9db26cd7f 100644 --- a/addons/addon-image/test/ImageAddon.test.ts +++ b/addons/addon-image/test/ImageAddon.test.ts @@ -64,8 +64,10 @@ const TESTDATA: ITestData = (() => { }; })(); const SIXEL_SEQ_0 = introducer(0) + TESTDATA.sixel + FINALIZER; -// const SIXEL_SEQ_1 = introducer(1) + TESTDATA.sixel + FINALIZER; -// const SIXEL_SEQ_2 = introducer(2) + TESTDATA.sixel + FINALIZER; +/* + * const SIXEL_SEQ_1 = introducer(1) + TESTDATA.sixel + FINALIZER; + * const SIXEL_SEQ_2 = introducer(2) + TESTDATA.sixel + FINALIZER; + */ // NOTE: the data is loaded as string for easier transport through playwright const TESTDATA_IIP: [string, [number, number]][] = [ diff --git a/addons/addon-image/test/KittyGraphics.test.ts b/addons/addon-image/test/KittyGraphics.test.ts index a9b5d6845..2822cce6b 100644 --- a/addons/addon-image/test/KittyGraphics.test.ts +++ b/addons/addon-image/test/KittyGraphics.test.ts @@ -101,12 +101,14 @@ test.beforeAll(async ({ browser }) => { test.afterAll(async () => await ctx.page.close()); test.describe('Kitty Graphics Protocol', () => { - // TODO: Add tests for larger images with various dimensions - // TODO: Add tests for virtual placement (U=1) - // TODO: Add tests for animation frames - // TODO: Add performance tests for streaming large images - // TODO: Implement cursor movement per Kitty spec - cursor should move by cols/rows after placement (unless C=1) - // TODO: Distinguish lowercase delete selectors (placement only) from uppercase (placement + free data) + /* + * TODO: Add tests for larger images with various dimensions + * TODO: Add tests for virtual placement (U=1) + * TODO: Add tests for animation frames + * TODO: Add performance tests for streaming large images + * TODO: Implement cursor movement per Kitty spec - cursor should move by cols/rows after placement (unless C=1) + * TODO: Distinguish lowercase delete selectors (placement only) from uppercase (placement + free data) + */ test.beforeEach(async ({}, testInfo) => { await ctx.page.evaluate(` @@ -209,8 +211,10 @@ test.describe('Kitty Graphics Protocol', () => { }); test('enforces size limit across chunked transmissions', async () => { - // Create a custom addon with very small size limit (100 bytes) - // The 1x1 PNG is ~164 bytes base64, so 2 chunks should exceed 100 + /* + * Create a custom addon with very small size limit (100 bytes) + * The 1x1 PNG is ~164 bytes base64, so 2 chunks should exceed 100 + */ await ctx.page.evaluate(() => { (window as any).smallLimitAddon = new ImageAddon({ kittySupport: true, @@ -1279,8 +1283,10 @@ test.describe('Kitty Graphics Protocol', () => { }); test('only c specified computes r from aspect ratio', async () => { - // 200x100 image (2:1 aspect) with c=10. - // Per spec: r = ceil((h/w) * c * cw / ch) = ceil(0.5 * 10 * cw / ch) + /* + * 200x100 image (2:1 aspect) with c=10. + * Per spec: r = ceil((h/w) * c * cw / ch) = ceil(0.5 * 10 * cw / ch) + */ await ctx.proxy.write(`\x1b_Ga=t,f=100,i=225;${KITTY_MULTICOLOR_200X100_BASE64}\x1b\\`); await timeout(100); @@ -1297,8 +1303,10 @@ test.describe('Kitty Graphics Protocol', () => { }); test('only r specified computes c from aspect ratio', async () => { - // 200x100 image (2:1 aspect) with r=5. - // Per spec: c = ceil((w/h) * r * ch / cw) = ceil(2 * 5 * ch / cw) + /* + * 200x100 image (2:1 aspect) with r=5. + * Per spec: c = ceil((w/h) * r * ch / cw) = ceil(2 * 5 * ch / cw) + */ await ctx.proxy.write(`\x1b_Ga=t,f=100,i=226;${KITTY_MULTICOLOR_200X100_BASE64}\x1b\\`); await timeout(100); @@ -1316,9 +1324,11 @@ test.describe('Kitty Graphics Protocol', () => { }); test.describe('Cursor positioning', () => { - // NOTE: Current tests document ACTUAL behavior (MVP - cursor doesn't move) - // Per Kitty spec: cursor placed at first column after last image column, - // on the last row of the image. C=1 means don't move cursor. + /* + * NOTE: Current tests document ACTUAL behavior (MVP - cursor doesn't move) + * Per Kitty spec: cursor placed at first column after last image column, + * on the last row of the image. C=1 means don't move cursor. + */ test('cursor advances past 1x1 image', async () => { const cursorBefore = await getCursor(); @@ -1376,8 +1386,10 @@ test.describe('Kitty Graphics Protocol', () => { }); test('cursor should move right by cols when c specified', async () => { - // c=5, r computed from 1x1 aspect ratio: r = ceil((1/1) * (5*cw) / ch) - // With 1:1 aspect, image height in pixels = 5*cw, so r = ceil(5*cw/ch) + /* + * c=5, r computed from 1x1 aspect ratio: r = ceil((1/1) * (5*cw) / ch) + * With 1:1 aspect, image height in pixels = 5*cw, so r = ceil(5*cw/ch) + */ await ctx.proxy.write(`\x1b_Ga=T,f=100,c=5;${KITTY_BLACK_1X1_BASE64}\x1b\\`); await timeout(100); @@ -1634,10 +1646,12 @@ test.describe('Kitty Graphics Protocol', () => { }); test.describe('Pixel verification', () => { - // The 200x100 image has 20 colored rectangles in a 10x2 grid. - // Each rectangle is 20px wide x 50px tall. - // Top row (y=0..49): Red, Orange, Yellow, Lime, Green, Cyan, SkyBlue, Blue, Purple, Magenta - // Bottom row (y=50..99): Pink, Brown, Maroon, Olive, Teal, Navy, Gray, DarkGray, LightGray, White + /* + * The 200x100 image has 20 colored rectangles in a 10x2 grid. + * Each rectangle is 20px wide x 50px tall. + * Top row (y=0..49): Red, Orange, Yellow, Lime, Green, Cyan, SkyBlue, Blue, Purple, Magenta + * Bottom row (y=50..99): Pink, Brown, Maroon, Olive, Teal, Navy, Gray, DarkGray, LightGray, White + */ test('renders red rectangle at top-left origin (0,0)', async () => { await ctx.proxy.write(`\x1b_Ga=T,f=100;${KITTY_MULTICOLOR_200X100_BASE64}\x1b\\`); @@ -1650,9 +1664,11 @@ test.describe('Kitty Graphics Protocol', () => { await ctx.proxy.write(`\x1b_Ga=T,f=100;${KITTY_MULTICOLOR_200X100_BASE64}\x1b\\`); await timeout(200); - // Sample center of each top-row rectangle (y=25, x=10,30,50,...,190) - // All within the first cell row, so we read from the canvas at cell (0,0) - // Red at x=10 + /* + * Sample center of each top-row rectangle (y=25, x=10,30,50,...,190) + * All within the first cell row, so we read from the canvas at cell (0,0) + * Red at x=10 + */ deepStrictEqual(await getPixel(0, 0, 10, 25), [255, 0, 0, 255]); // Orange at x=30 deepStrictEqual(await getPixel(0, 0, 30, 25), [255, 128, 0, 255]); @@ -1668,8 +1684,10 @@ test.describe('Kitty Graphics Protocol', () => { await ctx.proxy.write(`\x1b_Ga=T,f=100;${KITTY_MULTICOLOR_200X100_BASE64}\x1b\\`); await timeout(200); - // Bottom row starts at y=50. Center at y=75. - // Pink at x=10 + /* + * Bottom row starts at y=50. Center at y=75. + * Pink at x=10 + */ deepStrictEqual(await getPixel(0, 0, 10, 75), [255, 192, 203, 255]); // Brown at x=30 deepStrictEqual(await getPixel(0, 0, 30, 75), [165, 42, 42, 255]); @@ -1725,8 +1743,10 @@ test.describe('Kitty Graphics Protocol', () => { }); test('scales cropped source region to c/r placement rectangle', async () => { - // Firefox's createImageBitmap uses different resize sampling, producing - // slightly off pixel values compared to Chromium, so skip on Firefox. + /* + * Firefox's createImageBitmap uses different resize sampling, producing + * slightly off pixel values compared to Chromium, so skip on Firefox. + */ if (ctx.browser.browserType().name() === 'firefox') { test.skip(); } @@ -2137,8 +2157,10 @@ test.describe('Kitty Graphics Protocol', () => { }); test('memory limit eviction cleans Kitty handler maps', async () => { - // Resize terminal to fit 7 non-overlapping 200x100 images without scrolling. - // Each image ≈ 29 cols × 8 rows at default cell size. + /* + * Resize terminal to fit 7 non-overlapping 200x100 images without scrolling. + * Each image ≈ 29 cols × 8 rows at default cell size. + */ await ctx.page.evaluate(` window.term.reset(); window.imageAddon?.dispose(); @@ -2147,9 +2169,11 @@ test.describe('Kitty Graphics Protocol', () => { window.term.loadAddon(window.imageAddon); `); - // storageLimit 0.5 MB = 125,000 pixels. Each 200x100 image = 20,000 pixels. - // 6 images = 120K pixels (under limit). 7th triggers eviction (140K > 125K). - // Place non-overlapping so tile-count eviction doesn't interfere. + /* + * storageLimit 0.5 MB = 125,000 pixels. Each 200x100 image = 20,000 pixels. + * 6 images = 120K pixels (under limit). 7th triggers eviction (140K > 125K). + * Place non-overlapping so tile-count eviction doesn't interfere. + */ const positions = [[1, 1], [30, 1], [1, 9], [30, 9], [1, 17], [30, 17]]; for (let n = 0; n < 6; n++) { const [c, r] = positions[n]; diff --git a/addons/addon-ligatures/src/font.ts b/addons/addon-ligatures/src/font.ts index 60ab3d746..8e5f93dd5 100644 --- a/addons/addon-ligatures/src/font.ts +++ b/addons/addon-ligatures/src/font.ts @@ -43,9 +43,11 @@ export default async function load(fontFamily: string, cacheSize: number): Promi throw new Error('Permission to access local fonts not granted.'); } } catch (err: unknown) { - // A `TypeError` indicates the 'local-fonts' - // permission is not yet implemented, so - // only `throw` if this is _not_ the problem. + /* + * A `TypeError` indicates the 'local-fonts' + * permission is not yet implemented, so + * only `throw` if this is _not_ the problem. + */ if (err instanceof Error && err.name !== 'TypeError') { throw err; } @@ -89,9 +91,11 @@ export default async function load(fontFamily: string, cacheSize: number): Promi const fonts = await fontsPromise; for (const family of parse(fontFamily)) { - // If we reach one of the generic font families, the font resolution - // will end for the browser and we can't determine the specific font - // used. Throw. + /* + * If we reach one of the generic font families, the font resolution + * will end for the browser and we can't determine the specific font + * used. Throw. + */ if (genericFontFamilies.includes(family)) { return undefined; } diff --git a/addons/addon-ligatures/src/fontLigatures/index.ts b/addons/addon-ligatures/src/fontLigatures/index.ts index d65e73bc4..794b39ecc 100644 --- a/addons/addon-ligatures/src/fontLigatures/index.ts +++ b/addons/addon-ligatures/src/fontLigatures/index.ts @@ -88,9 +88,11 @@ class FontImpl implements IFont { glyphIds.push(this._font.charToGlyphIndex(char)); } - // If there are no lookup groups, there's no point looking for - // replacements. This gives us a minor performance boost for fonts with - // no ligatures + /* + * If there are no lookup groups, there's no point looking for + * replacements. This gives us a minor performance boost for fonts with + * no ligatures + */ if (this._lookupTrees.length === 0) { return { inputGlyphs: glyphIds, @@ -113,8 +115,10 @@ class FontImpl implements IFont { } public findLigatureRanges(text: string): [number, number][] { - // Short circuit the process if there are no possible ligatures in the - // font + /* + * Short circuit the process if there are no possible ligatures in the + * font + */ if (this._lookupTrees.length === 0) { return []; } @@ -170,9 +174,11 @@ class FontImpl implements IFont { } } } else { - // We don't need to do the lastGlyphIndex tracking here because - // reverse processing isn't allowed to replace more than one - // character at a time. + /* + * We don't need to do the lastGlyphIndex tracking here because + * reverse processing isn't allowed to replace more than one + * character at a time. + */ for (let i = nextLookup.last - 1; i >= nextLookup.first; i--) { const result = walkTree(lookup.tree, sequence, i, i); if (result) { @@ -224,8 +230,10 @@ class FontImpl implements IFont { for (let j = 0; j < lookups.length; j++) { const lookupIndex = lookups[j]; if (lookupIndex >= start) { - // Update the lookup information if it's the one we're - // storing or earlier than it. + /* + * Update the lookup information if it's the one we're + * storing or earlier than it. + */ if (result.index === null || lookupIndex <= result.index) { result.index = lookupIndex; diff --git a/addons/addon-ligatures/src/fontLigatures/merge.ts b/addons/addon-ligatures/src/fontLigatures/merge.ts index 262ea85ae..a16f748a9 100644 --- a/addons/addon-ligatures/src/fontLigatures/merge.ts +++ b/addons/addon-ligatures/src/fontLigatures/merge.ts @@ -32,9 +32,11 @@ export default function mergeTrees(trees: ILookupTree[]): ILookupTree { function mergeSubtree(mainTree: ILookupTree, mergeTree: ILookupTree, mergedEntries: WeakMap>): void { // Need to fix this recursively (and handle lookups) for (const [glyphId, value] of Object.entries(mergeTree.individual)) { - // The main tree is guaranteed to have no overlaps between the - // individual and range values, so if we match an invididual, there - // must not be a range + /* + * The main tree is guaranteed to have no overlaps between the + * individual and range values, so if we match an invididual, there + * must not be a range + */ if (mainTree.individual[glyphId]) { mergeTreeEntry(mainTree.individual[glyphId], value, mergedEntries); } else { @@ -49,13 +51,17 @@ function mergeSubtree(mainTree: ILookupTree, mergeTree: ILookupTree, mergedEntri matched = true; - // If they overlap, we have to split the range and then - // merge the overlap + /* + * If they overlap, we have to split the range and then + * merge the overlap + */ mainTree.individual[glyphId] = value; mergeTreeEntry(mainTree.individual[glyphId], cloneEntry(entry), mergedEntries); - // When there's an overlap, we also have to fix up the range - // that we had already processed + /* + * When there's an overlap, we also have to fix up the range + * that we had already processed + */ mainTree.range.splice(index, 1); for (const glyph of overlap.second) { if (Array.isArray(glyph)) { @@ -76,9 +82,11 @@ function mergeSubtree(mainTree: ILookupTree, mergeTree: ILookupTree, mergedEntri } for (const { range, entry } of mergeTree.range) { - // Ranges are more complicated, because they can overlap with - // multiple things, individual and range alike. We start by - // eliminating ranges that are already present in another range + /* + * Ranges are more complicated, because they can overlap with + * multiple things, individual and range alike. We start by + * eliminating ranges that are already present in another range + */ let remainingRanges: (number | [number, number])[] = [range]; for (let index = 0; index < mainTree.range.length; index++) { @@ -123,13 +131,17 @@ function mergeSubtree(mainTree: ILookupTree, mergeTree: ILookupTree, mergedEntri continue; } - // If they overlap, we have to split the range and then - // merge the overlap + /* + * If they overlap, we have to split the range and then + * merge the overlap + */ mainTree.individual[remainingRange] = cloneEntry(entry); mergeTreeEntry(mainTree.individual[remainingRange], cloneEntry(resultEntry), mergedEntries); - // When there's an overlap, we also have to fix up the range - // that we had already processed + /* + * When there's an overlap, we also have to fix up the range + * that we had already processed + */ mainTree.range.splice(index, 1); index--; diff --git a/addons/addon-ligatures/src/fontLigatures/mergeRange.ts b/addons/addon-ligatures/src/fontLigatures/mergeRange.ts index ec5305083..8058e077f 100644 --- a/addons/addon-ligatures/src/fontLigatures/mergeRange.ts +++ b/addons/addon-ligatures/src/fontLigatures/mergeRange.ts @@ -18,14 +18,18 @@ export default function mergeRange(ranges: [number, number][], newRangeStart: nu return ranges; } if (newRangeEnd <= range[1]) { - // Case 2: New range is either wholly contained within the - // search range or overlaps with the front of it + /* + * Case 2: New range is either wholly contained within the + * search range or overlaps with the front of it + */ range[0] = Math.min(newRangeStart, range[0]); return ranges; } if (newRangeStart < range[1]) { - // Case 3: New range either wholly contains the search range - // or overlaps with the end of it + /* + * Case 3: New range either wholly contains the search range + * or overlaps with the end of it + */ range[0] = Math.min(newRangeStart, range[0]); inRange = true; } else { @@ -34,21 +38,27 @@ export default function mergeRange(ranges: [number, number][], newRangeStart: nu } } else { if (newRangeEnd <= range[0]) { - // Case 5: New range extends from previous range but doesn't - // reach the current one + /* + * Case 5: New range extends from previous range but doesn't + * reach the current one + */ ranges[i - 1][1] = newRangeEnd; return ranges; } if (newRangeEnd <= range[1]) { - // Case 6: New range extends from prvious range into the - // current range + /* + * Case 6: New range extends from prvious range into the + * current range + */ ranges[i - 1][1] = Math.max(newRangeEnd, range[1]); ranges.splice(i, 1); inRange = false; return ranges; } - // Case 7: New range extends from previous range past the - // end of the current range + /* + * Case 7: New range extends from previous range past the + * end of the current range + */ ranges.splice(i, 1); i--; } diff --git a/addons/addon-ligatures/src/fontLigatures/processors/6-2.ts b/addons/addon-ligatures/src/fontLigatures/processors/6-2.ts index f39682423..890188508 100644 --- a/addons/addon-ligatures/src/fontLigatures/processors/6-2.ts +++ b/addons/addon-ligatures/src/fontLigatures/processors/6-2.ts @@ -72,8 +72,10 @@ export default function buildTree(table: ChainingContextualSubstitutionTable.IFo ); } - // When we get to the end, all of the entries we've accumulated - // should have a lookup defined + /* + * When we get to the end, all of the entries we've accumulated + * should have a lookup defined + */ for (const { entry, substitutions } of currentEntries) { entry.lookup = { substitutions, diff --git a/addons/addon-ligatures/src/fontLigatures/processors/6-3.ts b/addons/addon-ligatures/src/fontLigatures/processors/6-3.ts index 334e6a566..2f8290824 100644 --- a/addons/addon-ligatures/src/fontLigatures/processors/6-3.ts +++ b/addons/addon-ligatures/src/fontLigatures/processors/6-3.ts @@ -53,8 +53,10 @@ export default function buildTree(table: ChainingContextualSubstitutionTable.IFo ); } - // When we get to the end, all of the entries we've accumulated - // should have a lookup defined + /* + * When we get to the end, all of the entries we've accumulated + * should have a lookup defined + */ for (const { entry, substitutions } of currentEntries) { entry.lookup = { substitutions, diff --git a/addons/addon-ligatures/src/fontLigatures/processors/helper.ts b/addons/addon-ligatures/src/fontLigatures/processors/helper.ts index e6259b6d4..6bb6060d1 100644 --- a/addons/addon-ligatures/src/fontLigatures/processors/helper.ts +++ b/addons/addon-ligatures/src/fontLigatures/processors/helper.ts @@ -57,8 +57,10 @@ export function processLookaheadPosition( range: [] }; - // All glyphs at this position share ONE entry - lookahead just needs to match, - // all paths lead to the same result + /* + * All glyphs at this position share ONE entry - lookahead just needs to match, + * all paths lead to the same result + */ const sharedEntry: ILookupTreeEntry = {}; for (const glyph of glyphs) { @@ -100,8 +102,10 @@ export function processBacktrackPosition( range: [] }; - // All glyphs at this position share ONE entry - backtrack just needs to match, - // all paths lead to the same result + /* + * All glyphs at this position share ONE entry - backtrack just needs to match, + * all paths lead to the same result + */ const sharedEntry: ILookupTreeEntry = {}; for (const glyph of glyphs) { diff --git a/addons/addon-ligatures/src/fontLigatures/processors/substitution.ts b/addons/addon-ligatures/src/fontLigatures/processors/substitution.ts index 3a41e936c..7e461b87c 100644 --- a/addons/addon-ligatures/src/fontLigatures/processors/substitution.ts +++ b/addons/addon-ligatures/src/fontLigatures/processors/substitution.ts @@ -49,8 +49,10 @@ export function getIndividualSubstitutionGlyph(table: SubstitutionTable, glyphId switch (table.substFormat) { // https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#11-single-substitution-format-1 case 1: - // TODO: determine if there's a rhyme or reason to the 16-bit - // wraparound and if it can ever be a different number + /* + * TODO: determine if there's a rhyme or reason to the 16-bit + * wraparound and if it can ever be a different number + */ return (glyphId + table.deltaGlyphId) % (2 ** 16); // https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#12-single-substitution-format-2 case 2: diff --git a/addons/addon-ligatures/src/index.ts b/addons/addon-ligatures/src/index.ts index fb8e85e73..33990b773 100644 --- a/addons/addon-ligatures/src/index.ts +++ b/addons/addon-ligatures/src/index.ts @@ -15,8 +15,10 @@ const enum LoadingState { FAILED } -// Caches 100K characters worth of ligatures. In practice this works out to -// about 650 KB worth of cache, when a moderate number of ligatures are present. +/* + * Caches 100K characters worth of ligatures. In practice this works out to + * about 650 KB worth of cache, when a moderate number of ligatures are present. + */ const CACHE_SIZE = 100000; /** @@ -46,8 +48,10 @@ export function enableLigatures(term: Terminal, fallbackLigatures: string[] = [] load(currentCallFontName, CACHE_SIZE) .then(f => { - // Another request may have come in while we were waiting, so make - // sure our font is still vaild. + /* + * Another request may have come in while we were waiting, so make + * sure our font is still vaild. + */ if (currentCallFontName === term.options.fontFamily) { loadingState = LoadingState.LOADED; font = f; @@ -59,8 +63,10 @@ export function enableLigatures(term: Terminal, fallbackLigatures: string[] = [] } }) .catch(e => { - // Another request may have come in while we were waiting, so make - // sure our font is still vaild. + /* + * Another request may have come in while we were waiting, so make + * sure our font is still vaild. + */ if (currentCallFontName === term.options.fontFamily) { loadingState = LoadingState.FAILED; if (term.options.logLevel === 'debug') { @@ -73,8 +79,10 @@ export function enableLigatures(term: Terminal, fallbackLigatures: string[] = [] } if (font && loadingState === LoadingState.LOADED) { - // We clone the entries to avoid the internal cache of the ligature finder - // getting messed up. + /* + * We clone the entries to avoid the internal cache of the ligature finder + * getting messed up. + */ return font.findLigatureRanges(text).map<[number, number]>( range => [range[0], range[1]] ); diff --git a/addons/addon-ligatures/src/parse.ts b/addons/addon-ligatures/src/parse.ts index 6289e4681..7cf7ad2f8 100644 --- a/addons/addon-ligatures/src/parse.ts +++ b/addons/addon-ligatures/src/parse.ts @@ -27,8 +27,10 @@ export default function parse(family: string): string[] { const families = []; let currentFamily = ''; - // Work through the input character by character until there are none left. - // This lexing and parsing in one pass. + /* + * Work through the input character by character until there are none left. + * This lexing and parsing in one pass. + */ while (context.offset < context.input.length) { const char = context.input[context.offset++]; switch (char) { @@ -152,13 +154,17 @@ function parseUnicode(context: IParseContext): string { while (context.offset < context.input.length) { const char = context.input[context.offset++]; if (/\s/.test(char)) { - // The first whitespace character after a unicode escape indicates the end - // of the escape and is swallowed. + /* + * The first whitespace character after a unicode escape indicates the end + * of the escape and is swallowed. + */ return unicodeToString(str); } if (str.length >= 6 || !/[\dA-Fa-f]/.test(char)) { - // If the next character is not a valid hex digit or we have reached the - // maximum of 6 digits in the escape, terminate the escape. + /* + * If the next character is not a valid hex digit or we have reached the + * maximum of 6 digits in the escape, terminate the escape. + */ context.offset--; return unicodeToString(str); } diff --git a/addons/addon-search/src/SearchEngine.ts b/addons/addon-search/src/SearchEngine.ts index b9991974d..cbff3eb8e 100644 --- a/addons/addon-search/src/SearchEngine.ts +++ b/addons/addon-search/src/SearchEngine.ts @@ -261,8 +261,10 @@ export class SearchEngine { return; } - // This will iterate until we find the line start. - // When we find it, we will search using the calculated start column. + /* + * This will iterate until we find the line start. + * When we find it, we will search using the calculated start column. + */ searchPosition.startRow--; searchPosition.startCol += this._terminal.cols; return this._findInLine(term, searchPosition, searchOptions); @@ -315,8 +317,10 @@ export class SearchEngine { return; } - // Adjust the row number and search index if needed since a "line" of text can span multiple - // rows + /* + * Adjust the row number and search index if needed since a "line" of text can span multiple + * rows + */ let startRowOffset = 0; while (startRowOffset < offsets.length - 1 && resultIndex >= offsets[startRowOffset + 1]) { startRowOffset++; @@ -355,8 +359,10 @@ export class SearchEngine { if (char.length > 1) { offset -= char.length - 1; } - // Adjust the searchIndex for empty characters following wide unicode - // chars (eg. CJK) + /* + * Adjust the searchIndex for empty characters following wide unicode + * chars (eg. CJK) + */ const nextCell = line.getCell(i + 1); if (nextCell && nextCell.getWidth() === 0) { offset++; diff --git a/addons/addon-search/src/SearchLineCache.ts b/addons/addon-search/src/SearchLineCache.ts index 526f4bfcc..d62f47cd8 100644 --- a/addons/addon-search/src/SearchLineCache.ts +++ b/addons/addon-search/src/SearchLineCache.ts @@ -38,8 +38,10 @@ export class SearchLineCache extends Disposable { private _linesCache: LineCacheEntry[] | undefined; private _linesCacheTimeout = this._register(new MutableDisposable()); private _linesCacheDisposables = this._register(new MutableDisposable()); - // Track access to avoid recreating a timeout on every init call which occurs once per search - // result (findNext/findPrevious -> _highlightAllMatches -> find loop). + /* + * Track access to avoid recreating a timeout on every init call which occurs once per search + * result (findNext/findPrevious -> _highlightAllMatches -> find loop). + */ private _lastAccessTimestamp = 0; constructor(private readonly _terminal: Terminal) { diff --git a/addons/addon-serialize/src/SerializeAddon.ts b/addons/addon-serialize/src/SerializeAddon.ts index 4980c8eda..1d46fd918 100644 --- a/addons/addon-serialize/src/SerializeAddon.ts +++ b/addons/addon-serialize/src/SerializeAddon.ts @@ -84,8 +84,10 @@ function equalBg(cell1: IBufferCell | IAttributeData, cell2: IBufferCell): boole } function equalUnderline(cell1: IBufferCell | IAttributeData, cell2: IBufferCell): boolean { - // If neither cell has underline, consider them equal regardless of internal underline color - // values + /* + * If neither cell has underline, consider them equal regardless of internal underline color + * values + */ if (!cell1.isUnderline() && !cell2.isUnderline()) { return true; } @@ -134,14 +136,18 @@ class StringSerializeHandler extends BaseSerializeHandler { private _currentRow: string = ''; private _nullCellCount: number = 0; - // we can see a full colored cell and a null cell that only have background the same style - // but the information isn't preserved by null cell itself - // so wee need to record it when required. + /* + * we can see a full colored cell and a null cell that only have background the same style + * but the information isn't preserved by null cell itself + * so wee need to record it when required. + */ private _cursorStyle: IBufferCell = this._buffer.getNullCell(); - // where exact the cursor styles comes from - // because we can't copy the cell directly - // so we remember where the content comes from instead + /* + * where exact the cursor styles comes from + * because we can't copy the cell directly + * so we remember where the content comes from instead + */ private _cursorStyleRow: number = 0; private _cursorStyleCol: number = 0; @@ -172,8 +178,10 @@ class StringSerializeHandler extends BaseSerializeHandler { private _thisRowLastSecondChar: IBufferCell = this._buffer.getNullCell(); private _nextRowFirstChar: IBufferCell = this._buffer.getNullCell(); protected _rowEnd(row: number, isLastRow: boolean): void { - // if there is colorful empty cell at line end, whe must pad it back, or the the color block - // will missing + /* + * if there is colorful empty cell at line end, whe must pad it back, or the the color block + * will missing + */ if (this._nullCellCount > 0 && !equalBg(this._cursorStyle, this._backgroundCell)) { // use clear right to set background. this._currentRow += `\u001b[${this._nullCellCount}X`; @@ -206,8 +214,10 @@ class StringSerializeHandler extends BaseSerializeHandler { const nextRowFirstChar = nextLine.getCell(0, this._nextRowFirstChar)!; const isNextRowFirstCharDoubleWidth = nextRowFirstChar.getWidth() > 1; - // validate whether this line wrap is ever possible - // which mean whether cursor can placed at a overflow position (x === row) naturally + /* + * validate whether this line wrap is ever possible + * which mean whether cursor can placed at a overflow position (x === row) naturally + */ let isValid = false; if ( @@ -216,23 +226,31 @@ class StringSerializeHandler extends BaseSerializeHandler { isNextRowFirstCharDoubleWidth ? this._nullCellCount <= 1 : this._nullCellCount <= 0 ) { if ( - // the last character can't be null, - // you can't use control sequence to move cursor to (x === row) + /* + * the last character can't be null, + * you can't use control sequence to move cursor to (x === row) + */ (thisRowLastChar.getChars() || thisRowLastChar.getWidth() === 0) && - // change background of the first wrapped cell also affects BCE - // so we mark it as invalid to simply the process to determine line separator + /* + * change background of the first wrapped cell also affects BCE + * so we mark it as invalid to simply the process to determine line separator + */ equalBg(thisRowLastChar, nextRowFirstChar) ) { isValid = true; } if ( - // the second to last character can't be null if the next line starts with CJK, - // you can't use control sequence to move cursor to (x === row) + /* + * the second to last character can't be null if the next line starts with CJK, + * you can't use control sequence to move cursor to (x === row) + */ isNextRowFirstCharDoubleWidth && (thisRowLastSecondChar.getChars() || thisRowLastSecondChar.getWidth() === 0) && - // change background of the first wrapped cell also affects BCE - // so we mark it as invalid to simply the process to determine line separator + /* + * change background of the first wrapped cell also affects BCE + * so we mark it as invalid to simply the process to determine line separator + */ equalBg(thisRowLastChar, nextRowFirstChar) && equalBg(thisRowLastSecondChar, nextRowFirstChar) ) { @@ -241,8 +259,10 @@ class StringSerializeHandler extends BaseSerializeHandler { } if (!isValid) { - // force the wrap with magic - // insert enough character to force the wrap + /* + * force the wrap with magic + * insert enough character to force the wrap + */ rowSeparator = '-'.repeat(this._nullCellCount + 1); // move back and erase next line head rowSeparator += '\u001b[1D\u001b[1X'; @@ -256,8 +276,10 @@ class StringSerializeHandler extends BaseSerializeHandler { rowSeparator += '\u001b[B'; } - // This is content and need the be serialized even it is invisible. - // without this, wrap will be missing from outputs. + /* + * This is content and need the be serialized even it is invisible. + * without this, wrap will be missing from outputs. + */ this._lastContentCursorRow = row + 1; this._lastContentCursorCol = 0; @@ -358,8 +380,10 @@ class StringSerializeHandler extends BaseSerializeHandler { const sgrSeq = this._diffStyle(cell, this._cursorStyle); - // the empty cell style is only assumed to be changed when background changed, because - // foreground is always 0. + /* + * the empty cell style is only assumed to be changed when background changed, because + * foreground is always 0. + */ const styleChanged = isEmptyCell ? !equalBg(this._cursorStyle, cell) : sgrSeq.length > 0; /** @@ -398,9 +422,11 @@ class StringSerializeHandler extends BaseSerializeHandler { this._nullCellCount += cell.getWidth(); } else { if (this._nullCellCount > 0) { - // we can just assume we have same style with previous one here - // because style change is handled by previous stage - // use move right when background is empty, use clear right when there is background. + /* + * we can just assume we have same style with previous one here + * because style change is handled by previous stage + * use move right when background is empty, use clear right when there is background. + */ if (equalBg(this._cursorStyle, this._backgroundCell)) { this._currentRow += `\u001b[${this._nullCellCount}C`; } else { @@ -421,8 +447,10 @@ class StringSerializeHandler extends BaseSerializeHandler { protected _serializeString(excludeFinalCursorPosition: boolean): string { let rowEnd = this._allRows.length; - // the fixup is only required for data without scrollback - // because it will always be placed at last line otherwise + /* + * the fixup is only required for data without scrollback + * because it will always be placed at last line otherwise + */ if (this._buffer.length - this._firstRow <= this._terminal.rows) { rowEnd = this._lastContentCursorRow + 1 - this._firstRow; this._lastCursorCol = this._lastContentCursorCol; @@ -466,9 +494,11 @@ class StringSerializeHandler extends BaseSerializeHandler { } } - // Restore the cursor's current style, see https://github.com/xtermjs/xterm.js/issues/3677 - // HACK: Internal API access since it's awkward to expose this in the API and serialize will - // likely be the only consumer + /* + * Restore the cursor's current style, see https://github.com/xtermjs/xterm.js/issues/3677 + * HACK: Internal API access since it's awkward to expose this in the API and serialize will + * likely be the only consumer + */ const curAttrData: IAttributeData = (this._terminal as any)._core._inputHandler._curAttrData; const sgrSeq = this._diffStyle(curAttrData, this._cursorStyle); if (sgrSeq.length > 0) { @@ -581,8 +611,10 @@ export class SerializeAddon implements ITerminalAddon, ISerializeApi { } } - // Cursor visibility (DECTCEM) - // Default: visible + /* + * Cursor visibility (DECTCEM) + * Default: visible + */ if (!modes.showCursor) { content += '\x1b[?25l'; } diff --git a/addons/addon-serialize/test/SerializeAddon.test.ts b/addons/addon-serialize/test/SerializeAddon.test.ts index fb42d807d..02188146d 100644 --- a/addons/addon-serialize/test/SerializeAddon.test.ts +++ b/addons/addon-serialize/test/SerializeAddon.test.ts @@ -416,11 +416,13 @@ test.describe('SerializeAddon', () => { '中文中文', '12中文', '中文12', - // This line is going to be wrapped at last character - // because it has line length of 11 (1+2*5). - // We concat it back without the null cell currently. - // But this may be incorrect. - // see also #3097 + /* + * This line is going to be wrapped at last character + * because it has line length of 11 (1+2*5). + * We concat it back without the null cell currently. + * But this may be incorrect. + * see also #3097 + */ '1中文中文中' ]; await ctx.proxy.write(lines.join('\r\n')); @@ -503,9 +505,11 @@ test.describe('SerializeAddon', () => { const MOVE_DOWN = (l: number): string => `\u001b[${l}B`; const MOVE_LEFT = (l: number): string => `\u001b[${l}D`; - // A line wrap happened after current line. - // But there is no content. - // so wrap shouldn't even be able to happen. + /* + * A line wrap happened after current line. + * But there is no content. + * so wrap shouldn't even be able to happen. + */ const segments = [ `123456789012345`, MOVE_UP(1), @@ -531,9 +535,11 @@ test.describe('SerializeAddon', () => { 10 ); - // A line wrap happened after current line. - // But there is no content. - // so wrap shouldn't even be able to happen. + /* + * A line wrap happened after current line. + * But there is no content. + * so wrap shouldn't even be able to happen. + */ const lines = [ padLines.join('\r\n'), '\r\n', diff --git a/addons/addon-unicode-graphemes/src/UnicodeGraphemeProvider.ts b/addons/addon-unicode-graphemes/src/UnicodeGraphemeProvider.ts index 3d5717a0f..e68185f76 100644 --- a/addons/addon-unicode-graphemes/src/UnicodeGraphemeProvider.ts +++ b/addons/addon-unicode-graphemes/src/UnicodeGraphemeProvider.ts @@ -22,9 +22,11 @@ export class UnicodeGraphemeProvider implements IUnicodeVersionProvider { = UnicodeService.createPropertyValue(UC.GRAPHEME_BREAK_Other, 1, false); public charProperties(codepoint: number, preceding: UnicodeCharProperties): UnicodeCharProperties { - // Optimize the simple ASCII case, under the condition that - // UnicodeService.extractCharKind(preceding) === GRAPHEME_BREAK_Other - // (which also covers the case that preceding === 0). + /* + * Optimize the simple ASCII case, under the condition that + * UnicodeService.extractCharKind(preceding) === GRAPHEME_BREAK_Other + * (which also covers the case that preceding === 0). + */ if ((codepoint >= 32 && codepoint < 127) && (preceding >> 3) === 0) { return UnicodeGraphemeProvider._plainNarrowProperties; } diff --git a/addons/addon-web-fonts/test/WebFontsAddon.test.ts b/addons/addon-web-fonts/test/WebFontsAddon.test.ts index c94bff84d..100e34f55 100644 --- a/addons/addon-web-fonts/test/WebFontsAddon.test.ts +++ b/addons/addon-web-fonts/test/WebFontsAddon.test.ts @@ -21,8 +21,10 @@ test.describe('WebFontsAddon', () => { deepStrictEqual(empty, []); }); test.afterEach(async () => { - // for font loading tests to work, we have to remove added rules and fonts - // to work around the quite aggressive font caching done by the browsers + /* + * for font loading tests to work, we have to remove added rules and fonts + * to work around the quite aggressive font caching done by the browsers + */ await ctx.page.evaluate(` document.styleSheets[0].deleteRule(1); document.styleSheets[0].deleteRule(0); @@ -73,8 +75,10 @@ test.describe('WebFontsAddon', () => { }); test('autoload & relayout from ctor', async ({ browser }) => { - // to make this test work, we exclude the default measurement char W (x57) by restricting unicode-range - // now the browser will postpone font loading until codepoint is hit --> wrong glyph metrics on first usage + /* + * to make this test work, we exclude the default measurement char W (x57) by restricting unicode-range + * now the browser will postpone font loading until codepoint is hit --> wrong glyph metrics on first usage + */ const data = await ctx.page.evaluate(` document.styleSheets[0].insertRule("@font-face {font-family: Kongtext; src: url(/fonts/kongtext.regular.ttf) format('truetype'); unicode-range: U+00A0-00FF}", 0); `); @@ -97,8 +101,10 @@ test.describe('WebFontsAddon', () => { deepStrictEqual(await getDocumentFonts(), [{ family: 'Kongtext', status: 'unloaded' }]); } - // good case: addon fixes layout for webfont in ctor - // the relayout happens async, so wait a bit with a promise + /* + * good case: addon fixes layout for webfont in ctor + * the relayout happens async, so wait a bit with a promise + */ await ctx.page.evaluate(` window.helperTerm.dispose(); window.helperTerm = new Terminal({fontFamily: '"Kongtext", ' + term.options.fontFamily}); diff --git a/addons/addon-web-links/src/WebLinkProvider.ts b/addons/addon-web-links/src/WebLinkProvider.ts index efaead5c4..3f4a894dd 100644 --- a/addons/addon-web-links/src/WebLinkProvider.ts +++ b/addons/addon-web-links/src/WebLinkProvider.ts @@ -73,8 +73,10 @@ export class LinkComputer { continue; } - // map string positions back to buffer positions - // values are 0-based right side excluding + /* + * map string positions back to buffer positions + * values are 0-based right side excluding + */ const [startY, startX] = LinkComputer._mapStrIdx(terminal, startLineIndex, 0, match.index); const [endY, endX] = LinkComputer._mapStrIdx(terminal, startY, startX, text.length); @@ -172,11 +174,13 @@ export class LinkComputer { if (width) { stringIndex -= chars.length || 1; - // correct stringIndex for early wrapped wide chars: - // - currently only happens at last cell - // - cells to the right are reset with chars='' and width=1 in InputHandler.print - // - follow-up line must be wrapped and contain wide char at first cell - // --> if all these conditions are met, correct stringIndex by +1 + /* + * correct stringIndex for early wrapped wide chars: + * - currently only happens at last cell + * - cells to the right are reset with chars='' and width=1 in InputHandler.print + * - follow-up line must be wrapped and contain wide char at first cell + * --> if all these conditions are met, correct stringIndex by +1 + */ if (i === line.length - 1 && chars === '') { const line = buf.getLine(lineIndex + 1); if (line && line.isWrapped) { diff --git a/addons/addon-web-links/src/WebLinksAddon.ts b/addons/addon-web-links/src/WebLinksAddon.ts index 3328a3c3f..0a7171987 100644 --- a/addons/addon-web-links/src/WebLinksAddon.ts +++ b/addons/addon-web-links/src/WebLinksAddon.ts @@ -7,17 +7,19 @@ import type { Terminal, ITerminalAddon, IDisposable } from '@xterm/xterm'; import type { WebLinksAddon as IWebLinksApi } from '@xterm/addon-web-links'; import { ILinkProviderOptions, WebLinkProvider } from './WebLinkProvider'; -// consider everthing starting with http:// or https:// -// up to first whitespace, `"` or `'` as url -// NOTE: The repeated end clause is needed to not match a dangling `:` -// resembling the old (...)*([^:"\'\\s]) final path clause -// additionally exclude early + final: -// - unsafe from rfc3986: !*'() -// - unsafe chars from rfc1738: {}|\^~[]` (minus [] as we need them for ipv6 adresses, also allow ~) -// also exclude as finals: -// - final interpunction like ,.!? -// - any sort of brackets <>()[]{} (not spec conform, but often used to enclose urls) -// - unsafe chars from rfc1738: {}|\^~[]` +/* + * consider everthing starting with http:// or https:// + * up to first whitespace, `"` or `'` as url + * NOTE: The repeated end clause is needed to not match a dangling `:` + * resembling the old (...)*([^:"\'\\s]) final path clause + * additionally exclude early + final: + * - unsafe from rfc3986: !*'() + * - unsafe chars from rfc1738: {}|\^~[]` (minus [] as we need them for ipv6 adresses, also allow ~) + * also exclude as finals: + * - final interpunction like ,.!? + * - any sort of brackets <>()[]{} (not spec conform, but often used to enclose urls) + * - unsafe chars from rfc1738: {}|\^~[]` + */ const strictUrlRegex = /(https?|HTTPS?):[/]{2}[^\s"'!*(){}|\\\^<>`]*[^\s"':,.!?{}|\\\^~\[\]`()<>]/; diff --git a/addons/addon-webgl/src/CellColorResolver.ts b/addons/addon-webgl/src/CellColorResolver.ts index 3a4661cc3..fe8baa35a 100644 --- a/addons/addon-webgl/src/CellColorResolver.ts +++ b/addons/addon-webgl/src/CellColorResolver.ts @@ -47,8 +47,10 @@ export class CellColorResolver { this.result.bg = cell.bg; this.result.fg = cell.fg; this.result.ext = cell.bg & BgFlags.HAS_EXTENDED ? cell.extended.ext : 0; - // Get any foreground/background overrides, this happens on the model to avoid spreading - // override logic throughout the different sub-renderers + /* + * Get any foreground/background overrides, this happens on the model to avoid spreading + * override logic throughout the different sub-renderers + */ // Reset overrides work variables $bg = 0; @@ -186,8 +188,10 @@ export class CellColorResolver { } }); - // Convert any overrides from rgba to the fg/bg packed format. This resolves the inverse flag - // ahead of time in order to use the correct cache key + /* + * Convert any overrides from rgba to the fg/bg packed format. This resolves the inverse flag + * ahead of time in order to use the correct cache key + */ if ($hasBg) { if ($isSelected) { // Non-RGB attributes from model + force non-dim + override + force RGB color mode @@ -202,8 +206,10 @@ export class CellColorResolver { $fg = (cell.fg & ~Attributes.RGB_MASK & ~FgFlags.INVERSE) | $fg | Attributes.CM_RGB; } - // Handle case where inverse was specified by only one of bg override or fg override was set, - // resolving the other inverse color and setting the inverse flag if needed. + /* + * Handle case where inverse was specified by only one of bg override or fg override was set, + * resolving the other inverse color and setting the inverse flag if needed. + */ if (this.result.fg & FgFlags.INVERSE) { if ($hasBg && !$hasFg) { // Resolve bg color type (default color has a different meaning in fg vs bg) diff --git a/addons/addon-webgl/src/CharAtlasCache.ts b/addons/addon-webgl/src/CharAtlasCache.ts index 823a74cc6..5581ea22d 100644 --- a/addons/addon-webgl/src/CharAtlasCache.ts +++ b/addons/addon-webgl/src/CharAtlasCache.ts @@ -13,8 +13,10 @@ import type { ILogService } from 'common/services/Services'; interface ITextureAtlasCacheEntry { atlas: ITextureAtlas; config: ICharAtlasConfig; - // N.B. This implementation potentially holds onto copies of the terminal forever, so - // this may cause memory leaks. + /* + * N.B. This implementation potentially holds onto copies of the terminal forever, so + * this may cause memory leaks. + */ ownedBy: Terminal[]; } diff --git a/addons/addon-webgl/src/CharAtlasUtils.ts b/addons/addon-webgl/src/CharAtlasUtils.ts index 4ce103e98..15e796256 100644 --- a/addons/addon-webgl/src/CharAtlasUtils.ts +++ b/addons/addon-webgl/src/CharAtlasUtils.ts @@ -25,8 +25,10 @@ export function generateConfig(deviceCellWidth: number, deviceCellHeight: number scrollbarSliderBackground: NULL_COLOR, scrollbarSliderHoverBackground: NULL_COLOR, scrollbarSliderActiveBackground: NULL_COLOR, - // For the static char atlas, we only use the first 16 colors, but we need all 256 for the - // dynamic character atlas. + /* + * For the static char atlas, we only use the first 16 colors, but we need all 256 for the + * dynamic character atlas. + */ ansi: colors.ansi.slice(), contrastCache: colors.contrastCache, halfContrastCache: colors.halfContrastCache diff --git a/addons/addon-webgl/src/Constants.ts b/addons/addon-webgl/src/Constants.ts index a00434d61..af08fe8bb 100644 --- a/addons/addon-webgl/src/Constants.ts +++ b/addons/addon-webgl/src/Constants.ts @@ -6,7 +6,9 @@ import { isFirefox, isLegacyEdge } from 'common/Platform'; export const DIM_OPACITY = 0.5; -// The text baseline is set conditionally by browser. Using 'ideographic' for Firefox or Legacy Edge -// would result in truncated text (Issue 3353). Using 'bottom' for Chrome would result in slightly -// unaligned Powerline fonts (PR 3356#issuecomment-850928179). +/* + * The text baseline is set conditionally by browser. Using 'ideographic' for Firefox or Legacy Edge + * would result in truncated text (Issue 3353). Using 'bottom' for Chrome would result in slightly + * unaligned Powerline fonts (PR 3356#issuecomment-850928179). + */ export const TEXT_BASELINE: CanvasTextBaseline = isFirefox || isLegacyEdge ? 'bottom' : 'ideographic'; diff --git a/addons/addon-webgl/src/CursorBlinkStateManager.ts b/addons/addon-webgl/src/CursorBlinkStateManager.ts index 688aee7b7..1e9695c94 100644 --- a/addons/addon-webgl/src/CursorBlinkStateManager.ts +++ b/addons/addon-webgl/src/CursorBlinkStateManager.ts @@ -87,13 +87,17 @@ export class CursorBlinkStateManager { this._blinkInterval = undefined; } - // Setup the initial timeout which will hide the cursor, this is done before - // the regular interval is setup in order to support restarting the blink - // animation in a lightweight way (without thrashing clearInterval and - // setInterval). + /* + * Setup the initial timeout which will hide the cursor, this is done before + * the regular interval is setup in order to support restarting the blink + * animation in a lightweight way (without thrashing clearInterval and + * setInterval). + */ this._blinkStartTimeout = this._coreBrowserService.window.setTimeout(() => { - // Check if another animation restart was requested while this was being - // started + /* + * Check if another animation restart was requested while this was being + * started + */ if (this._animationTimeRestarted) { const time = Constants.BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted); this._animationTimeRestarted = undefined; @@ -114,8 +118,10 @@ export class CursorBlinkStateManager { this._blinkInterval = this._coreBrowserService.window.setInterval(() => { // Adjust the animation time if it was restarted if (this._animationTimeRestarted) { - // calc time diff - // Make restart interval do a setTimeout initially? + /* + * calc time diff + * Make restart interval do a setTimeout initially? + */ const time = Constants.BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted); this._animationTimeRestarted = undefined; this._restartInterval(time); diff --git a/addons/addon-webgl/src/DevicePixelObserver.ts b/addons/addon-webgl/src/DevicePixelObserver.ts index dcd8de0a6..c7af6a1bb 100644 --- a/addons/addon-webgl/src/DevicePixelObserver.ts +++ b/addons/addon-webgl/src/DevicePixelObserver.ts @@ -6,10 +6,12 @@ import { toDisposable, IDisposable } from 'common/Lifecycle'; export function observeDevicePixelDimensions(element: HTMLElement, parentWindow: Window & typeof globalThis, callback: (deviceWidth: number, deviceHeight: number) => void): IDisposable { - // Observe any resizes to the element and extract the actual pixel size of the element if the - // devicePixelContentBoxSize API is supported. This allows correcting rounding errors when - // converting between CSS pixels and device pixels which causes blurry rendering when device - // pixel ratio is not a round number. + /* + * Observe any resizes to the element and extract the actual pixel size of the element if the + * devicePixelContentBoxSize API is supported. This allows correcting rounding errors when + * converting between CSS pixels and device pixels which causes blurry rendering when device + * pixel ratio is not a round number. + */ let observer: ResizeObserver | undefined = new parentWindow.ResizeObserver((entries) => { const entry = entries.find((entry) => entry.target === element); if (!entry) { diff --git a/addons/addon-webgl/src/GlyphRenderer.ts b/addons/addon-webgl/src/GlyphRenderer.ts index 46b8efeb9..82ca01b63 100644 --- a/addons/addon-webgl/src/GlyphRenderer.ts +++ b/addons/addon-webgl/src/GlyphRenderer.ts @@ -148,9 +148,11 @@ export class GlyphRenderer extends Disposable { gl.enableVertexAttribArray(VertexAttribLocations.UNIT_QUAD); gl.vertexAttribPointer(VertexAttribLocations.UNIT_QUAD, 2, this._gl.FLOAT, false, 0, 0); - // Setup the unit quad element array buffer, this points to indices in - // unitQuadVertices to allow is to draw 2 triangles from the vertices via a - // triangle strip + /* + * Setup the unit quad element array buffer, this points to indices in + * unitQuadVertices to allow is to draw 2 triangles from the vertices via a + * triangle strip + */ const unitQuadElementIndices = new Uint8Array([0, 1, 2, 3]); const elementIndicesBuffer = gl.createBuffer(); this._register(toDisposable(() => gl.deleteBuffer(elementIndicesBuffer))); @@ -189,8 +191,10 @@ export class GlyphRenderer extends Disposable { gl.uniform1iv(this._textureLocation, textureUnits); gl.uniformMatrix4fv(this._projectionLocation, false, PROJECTION_MATRIX); - // Setup 1x1 red pixel textures for all potential atlas pages, if one of these invalid textures - // is ever drawn it will show characters as red rectangles. + /* + * Setup 1x1 red pixel textures for all potential atlas pages, if one of these invalid textures + * is ever drawn it will show characters as red rectangles. + */ this._atlasTextures = []; for (let i = 0; i < TextureAtlas.maxAtlasPages; i++) { const glTexture = new GLTexture(throwIfFalsy(gl.createTexture())); @@ -216,18 +220,22 @@ export class GlyphRenderer extends Disposable { } public updateCell(x: number, y: number, code: number, bg: number, fg: number, ext: number, chars: string, width: number, lastBg: number): void { - // Since this function is called for every cell (`rows*cols`), it must be very optimized. It - // should not instantiate any variables unless a new glyph is drawn to the cache where the - // slight slowdown is acceptable for the developer ergonomics provided as it's a once of for - // each glyph. + /* + * Since this function is called for every cell (`rows*cols`), it must be very optimized. It + * should not instantiate any variables unless a new glyph is drawn to the cache where the + * slight slowdown is acceptable for the developer ergonomics provided as it's a once of for + * each glyph. + */ this._updateCell(this._vertices.attributes, x, y, code, bg, fg, ext, chars, width, lastBg); } private _updateCell(array: Float32Array, x: number, y: number, code: number | undefined, bg: number, fg: number, ext: number, chars: string, width: number, lastBg: number): void { $i = (y * this._terminal.cols + x) * Constants.INDICES_PER_CELL; - // Exit early if this is a null character, allow space character to continue as it may have - // underline/strikethrough styles + /* + * Exit early if this is a null character, allow space character to continue as it may have + * underline/strikethrough styles + */ if (code === NULL_CELL_CODE || code === undefined/* This is used for the right side of wide chars */) { array.fill(0, $i, $i + Constants.INDICES_PER_CELL - 1 - Constants.CELL_POSITION_INDICES); return; @@ -279,8 +287,10 @@ export class GlyphRenderer extends Disposable { } // a_cellpos only changes on resize - // Reduce scale horizontally for wide glyphs printed in cells that would overlap with the - // following cell (ie. the width is not 2). + /* + * Reduce scale horizontally for wide glyphs printed in cells that would overlap with the + * following cell (ie. the width is not 2). + */ if (this._optionsService.rawOptions.rescaleOverlappingGlyphs) { if (allowRescaling(code, width, $glyph.size.x, this._dimensions.device.cell.width)) { array[$i + 2] = (this._dimensions.device.cell.width - 1) / this._dimensions.device.canvas.width; // - 1 to improve readability @@ -339,13 +349,15 @@ export class GlyphRenderer extends Disposable { this._activeBuffer = (this._activeBuffer + 1) % 2; const activeBuffer = this._vertices.attributesBuffers[this._activeBuffer]; - // Copy data for each cell of each line up to its line length (the last non-whitespace cell) - // from the attributes buffer into activeBuffer, which is the one that gets bound to the GPU. - // The reasons for this are as follows: - // - So the active buffer can be alternated so we don't get blocked on rendering finishing - // - To copy either the normal attributes buffer or the selection attributes buffer when there - // is a selection - // - So we don't send vertices for all the line-ending whitespace to the GPU + /* + * Copy data for each cell of each line up to its line length (the last non-whitespace cell) + * from the attributes buffer into activeBuffer, which is the one that gets bound to the GPU. + * The reasons for this are as follows: + * - So the active buffer can be alternated so we don't get blocked on rendering finishing + * - To copy either the normal attributes buffer or the selection attributes buffer when there + * is a selection + * - So we don't send vertices for all the line-ending whitespace to the GPU + */ let bufferLength = 0; for (let y = 0; y < renderModel.lineLengths.length; y++) { const si = y * this._terminal.cols * Constants.INDICES_PER_CELL; @@ -358,9 +370,11 @@ export class GlyphRenderer extends Disposable { gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer); gl.bufferData(gl.ARRAY_BUFFER, activeBuffer.subarray(0, bufferLength), gl.STREAM_DRAW); - // Bind the atlas page texture if they have changed. AtlasPage.version is globally - // monotonic, so a page object swap at the same index (which happens after a page merge) - // is detected by the same comparison. + /* + * Bind the atlas page texture if they have changed. AtlasPage.version is globally + * monotonic, so a page object swap at the same index (which happens after a page merge) + * is detected by the same comparison. + */ for (let i = 0; i < this._atlas.pages.length; i++) { if (this._atlas.pages[i].version !== this._atlasTextures[i].version) { this._bindAtlasPageTexture(gl, this._atlas, i); diff --git a/addons/addon-webgl/src/RectangleRenderer.ts b/addons/addon-webgl/src/RectangleRenderer.ts index 81e129e5c..e87bc690c 100644 --- a/addons/addon-webgl/src/RectangleRenderer.ts +++ b/addons/addon-webgl/src/RectangleRenderer.ts @@ -114,9 +114,11 @@ export class RectangleRenderer extends Disposable { gl.enableVertexAttribArray(VertexAttribLocations.UNIT_QUAD); gl.vertexAttribPointer(VertexAttribLocations.UNIT_QUAD, 2, this._gl.FLOAT, false, 0, 0); - // Setup the unit quad element array buffer, this points to indices in - // unitQuadVertices to allow is to draw 2 triangles from the vertices via a - // triangle strip + /* + * Setup the unit quad element array buffer, this points to indices in + * unitQuadVertices to allow is to draw 2 triangles from the vertices via a + * triangle strip + */ const unitQuadElementIndices = new Uint8Array([0, 1, 2, 3]); const elementIndicesBuffer = gl.createBuffer(); this._register(toDisposable(() => gl.deleteBuffer(elementIndicesBuffer))); diff --git a/addons/addon-webgl/src/TextureAtlas.ts b/addons/addon-webgl/src/TextureAtlas.ts index 34188235c..09293d4fa 100644 --- a/addons/addon-webgl/src/TextureAtlas.ts +++ b/addons/addon-webgl/src/TextureAtlas.ts @@ -151,13 +151,17 @@ export class TextureAtlas implements ITextureAtlas { } private _createNewPage(): AtlasPage { - // Try merge the set of the 4 most used pages of the largest size. This is is deferred to a - // microtask to ensure it does not interrupt textures that will be rendered in the current - // animation frame which would result in blank rendered areas. This is actually not that - // expensive relative to drawing the glyphs, so there is no need to wait for an idle callback. + /* + * Try merge the set of the 4 most used pages of the largest size. This is is deferred to a + * microtask to ensure it does not interrupt textures that will be rendered in the current + * animation frame which would result in blank rendered areas. This is actually not that + * expensive relative to drawing the glyphs, so there is no need to wait for an idle callback. + */ if (TextureAtlas.maxAtlasPages && this._pages.length >= Math.max(4, TextureAtlas.maxAtlasPages)) { - // Find the set of the largest 4 images, below the maximum size, with the highest - // percentages used + /* + * Find the set of the largest 4 images, below the maximum size, with the highest + * percentages used + */ const pagesBySize = this._pages.filter(e => { return e.canvas.width * 2 <= (TextureAtlas.maxTextureSize || Constants.FORCED_MAX_TEXTURE_SIZE); }).sort((a, b) => { @@ -180,8 +184,10 @@ export class TextureAtlas implements ITextureAtlas { // Gather details of the merge const mergingPages = pagesBySize.slice(sameSizeI, sameSizeI + 4); - // Only proceed with merge if we have exactly 4 same-sized pages. If not, we cannot - // effectively reduce page count and merging would cause issues. + /* + * Only proceed with merge if we have exactly 4 same-sized pages. If not, we cannot + * effectively reduce page count and merging would cause issues. + */ if (mergingPages.length < 4 || mergingPages.some(p => p.canvas.width !== mergingPages[0].canvas.width)) { const newPage = new AtlasPage(this._document, this._textureSize); this._pages.push(newPage); @@ -294,9 +300,11 @@ export class TextureAtlas implements ITextureAtlas { private _getBackgroundColor(bgColorMode: number, bgColor: number, inverse: boolean, dim: boolean): IColor { if (this._config.allowTransparency) { - // The background color might have some transparency, so we need to render it as fully - // transparent in the atlas. Otherwise we'd end up drawing the transparent background twice - // around the anti-aliased edges of the glyph, and it would look too dark. + /* + * The background color might have some transparency, so we need to render it as fully + * transparent in the atlas. Otherwise we'd end up drawing the transparent background twice + * around the anti-aliased edges of the glyph, and it would look too dark. + */ return NULL_COLOR; } @@ -418,8 +426,10 @@ export class TextureAtlas implements ITextureAtlas { const bgRgba = this._resolveBackgroundRgba(bgColorMode, bgColor, inverse); const fgRgba = this._resolveForegroundRgba(fgColorMode, fgColor, inverse, bold); - // Dim cells only require half the contrast, otherwise they wouldn't be distinguishable from - // non-dim cells + /* + * Dim cells only require half the contrast, otherwise they wouldn't be distinguishable from + * non-dim cells + */ const result = rgba.ensureContrastRatio(bgRgba, fgRgba, this._config.minimumContrastRatio / (dim ? 2 : 1)); if (!result) { @@ -447,20 +457,26 @@ export class TextureAtlas implements ITextureAtlas { private _drawToCache(codeOrChars: number | string, bg: number, fg: number, ext: number, restrictToCellHeight: boolean, domContainer: HTMLElement | undefined): IRasterizedGlyph { const chars = typeof codeOrChars === 'number' ? String.fromCharCode(codeOrChars) : codeOrChars; - // Uncomment for debugging - // console.log(`draw to cache "${chars}"`, bg, fg, ext); + /* + * Uncomment for debugging + * console.log(`draw to cache "${chars}"`, bg, fg, ext); + */ - // Attach the canvas to the DOM in order to inherit font-feature-settings - // from the parent elements. This is necessary for ligatures and variants to - // work. + /* + * Attach the canvas to the DOM in order to inherit font-feature-settings + * from the parent elements. This is necessary for ligatures and variants to + * work. + */ if (domContainer && this._tmpCanvas.parentElement !== domContainer) { this._tmpCanvas.style.display = 'none'; domContainer.append(this._tmpCanvas); } - // Allow 1 cell width per character, with a minimum of 2 (CJK), plus some padding. This is used - // to draw the glyph to the canvas as well as to restrict the bounding box search to ensure - // giant ligatures (eg. =====>) don't impact overall performance. + /* + * Allow 1 cell width per character, with a minimum of 2 (CJK), plus some padding. This is used + * to draw the glyph to the canvas as well as to restrict the bounding box search to ensure + * giant ligatures (eg. =====>) don't impact overall performance. + */ const allowedWidth = Math.min(this._config.deviceCellWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2, this._config.deviceMaxTextureSize); if (this._tmpCanvas.width < allowedWidth) { this._tmpCanvas.width = allowedWidth; @@ -503,8 +519,10 @@ export class TextureAtlas implements ITextureAtlas { // draw the background const backgroundColor = this._getBackgroundColor(bgColorMode, bgColor, inverse, dim); - // Use a 'copy' composite operation to clear any existing glyph out of _tmpCtxWithAlpha, - // regardless of transparency in backgroundColor + /* + * Use a 'copy' composite operation to clear any existing glyph out of _tmpCtxWithAlpha, + * regardless of transparency in backgroundColor + */ this._tmpCtx.globalCompositeOperation = 'copy'; this._tmpCtx.fillStyle = backgroundColor.css; this._tmpCtx.fillRect(0, 0, this._tmpCanvas.width, this._tmpCanvas.height); @@ -532,9 +550,11 @@ export class TextureAtlas implements ITextureAtlas { customGlyph = tryDrawCustomGlyph(this._tmpCtx, chars, padding, padding, this._config.deviceCellWidth, this._config.deviceCellHeight, this._config.deviceCharWidth, this._config.deviceCharHeight, this._config.fontSize, this._config.devicePixelRatio, backgroundColor.css, variantOffset); } - // Whether to clear pixels based on a threshold difference between the glyph color and the - // background color. This should be disabled when the glyph contains multiple colors such as - // underline colors to prevent important colors could get cleared. + /* + * Whether to clear pixels based on a threshold difference between the glyph color and the + * background color. This should be disabled when the glyph contains multiple colors such as + * underline colors to prevent important colors could get cleared. + */ let enableClearThresholdCheck = !powerlineGlyph; let chWidth: number; @@ -599,8 +619,10 @@ export class TextureAtlas implements ITextureAtlas { clipRegion.rect(xChLeft, yTop, this._config.deviceCellWidth, yBot - yTop); this._tmpCtx.clip(clipRegion); - // Draw a zigzag pattern, this is derived from the SVG used in monaco for the same - // style. The viewbox is 6x3 so scale it using that. + /* + * Draw a zigzag pattern, this is derived from the SVG used in monaco for the same + * style. The viewbox is 6x3 so scale it using that. + */ const cellW = this._config.deviceCellWidth; const curlyH = (yBot - yTop); const scaleX = cellW / 6; @@ -671,15 +693,21 @@ export class TextureAtlas implements ITextureAtlas { } this._tmpCtx.restore(); - // Draw stroke in the background color for non custom characters in order to give an outline - // between the text and the underline. Only do this when font size is >= 12 as the underline - // looks odd when the font size is too small + /* + * Draw stroke in the background color for non custom characters in order to give an outline + * between the text and the underline. Only do this when font size is >= 12 as the underline + * looks odd when the font size is too small + */ if (!customGlyph && this._config.fontSize >= 12) { - // This only works when transparency is disabled because it's not clear how to clear stroked - // text + /* + * This only works when transparency is disabled because it's not clear how to clear stroked + * text + */ if (!this._config.allowTransparency && chars !== ' ') { - // Measure the text, only draw the stroke if there is a descent beyond an alphabetic text - // baseline + /* + * Measure the text, only draw the stroke if there is a descent beyond an alphabetic text + * baseline + */ this._tmpCtx.save(); this._tmpCtx.textBaseline = 'alphabetic'; const metrics = this._tmpCtx.measureText(chars); @@ -687,9 +715,11 @@ export class TextureAtlas implements ITextureAtlas { if ('actualBoundingBoxDescent' in metrics && metrics.actualBoundingBoxDescent > 0) { // This translates to 1/2 the line width in either direction this._tmpCtx.save(); - // Clip the region to only draw in valid pixels near the underline to avoid a slight - // outline around the whole glyph, as well as additional pixels in the glyph at the top - // which would increase GPU memory demands + /* + * Clip the region to only draw in valid pixels near the underline to avoid a slight + * outline around the whole glyph, as well as additional pixels in the glyph at the top + * which would increase GPU memory demands + */ const clipRegion = new Path2D(); clipRegion.rect(xLeft, yTop - Math.ceil(lineWidth / 2), this._config.deviceCellWidth * chWidth, yBot - yTop + Math.ceil(lineWidth / 2)); this._tmpCtx.clip(clipRegion); @@ -719,8 +749,10 @@ export class TextureAtlas implements ITextureAtlas { this._tmpCtx.fillText(chars, padding, padding + this._config.deviceCharHeight); } - // If this character is underscore and beyond the cell bounds, shift it up until it is visible - // even on the bottom row, try for a maximum of 5 pixels. + /* + * If this character is underscore and beyond the cell bounds, shift it up until it is visible + * even on the bottom row, try for a maximum of 5 pixels. + */ if (chars === '_' && !this._config.allowTransparency) { let isBeyondCellBounds = clearColor(this._tmpCtx.getImageData(padding, padding, this._config.deviceCellWidth, this._config.deviceCellHeight), backgroundColor, foregroundColor, enableClearThresholdCheck); if (isBeyondCellBounds) { @@ -752,8 +784,10 @@ export class TextureAtlas implements ITextureAtlas { this._tmpCtx.restore(); - // clear the background from the character to avoid issues with drawing over the previous - // character if it extends past it's bounds + /* + * clear the background from the character to avoid issues with drawing over the previous + * character if it extends past it's bounds + */ const imageData = this._tmpCtx.getImageData( 0, 0, this._tmpCanvas.width, this._tmpCanvas.height ); @@ -796,12 +830,16 @@ export class TextureAtlas implements ITextureAtlas { } } - // TODO: This algorithm could be simplified: - // - Search for the page with ROW_PIXEL_THRESHOLD in mind - // - Keep track of current/fixed rows in a Map + /* + * TODO: This algorithm could be simplified: + * - Search for the page with ROW_PIXEL_THRESHOLD in mind + * - Keep track of current/fixed rows in a Map + */ - // Replace the best current row with a fixed row if there is one at least as good as the - // current row. Search in reverse to prioritize filling in older pages. + /* + * Replace the best current row with a fixed row if there is one at least as good as the + * current row. Search in reverse to prioritize filling in older pages. + */ for (let i = this._activePages.length - 1; i >= 0; i--) { for (const row of this._activePages[i].fixedRows) { if (row.height <= activeRow.height && rasterizedGlyph.size.y <= row.height) { @@ -832,12 +870,16 @@ export class TextureAtlas implements ITextureAtlas { break; } - // Create a new page if too much vertical space would be wasted or there is not enough room - // left in the page. The previous active row will become fixed in the process as it now has a - // fixed height + /* + * Create a new page if too much vertical space would be wasted or there is not enough room + * left in the page. The previous active row will become fixed in the process as it now has a + * fixed height + */ if (activeRow.y + rasterizedGlyph.size.y >= activePage.canvas.height || activeRow.height > rasterizedGlyph.size.y + Constants.ROW_PIXEL_THRESHOLD) { - // Create the new fixed height row, creating a new page if there isn't enough room on the - // current page + /* + * Create the new fixed height row, creating a new page if there isn't enough room on the + * current page + */ let wasPageAndRowFound = false; if (activePage.currentRow.y + activePage.currentRow.height + rasterizedGlyph.size.y >= activePage.canvas.height) { // Find the first page with room to create the new row on @@ -852,10 +894,12 @@ export class TextureAtlas implements ITextureAtlas { if (candidatePage) { activePage = candidatePage; } else { - // Before creating a new atlas page that would trigger a page merge, check if the - // current active row is sufficient when ignoring the ROW_PIXEL_THRESHOLD. This will - // improve texture utilization by using the available space before the page is merged - // and becomes static. + /* + * Before creating a new atlas page that would trigger a page merge, check if the + * current active row is sufficient when ignoring the ROW_PIXEL_THRESHOLD. This will + * improve texture utilization by using the available space before the page is merged + * and becomes static. + */ if ( TextureAtlas.maxAtlasPages && this._pages.length >= TextureAtlas.maxAtlasPages && @@ -923,8 +967,10 @@ export class TextureAtlas implements ITextureAtlas { rasterizedGlyph.sizeClipSpace.x /= activePage.canvas.width; rasterizedGlyph.sizeClipSpace.y /= activePage.canvas.height; - // Update atlas current row, for fixed rows the glyph height will never be larger than the row - // height + /* + * Update atlas current row, for fixed rows the glyph height will never be larger than the row + * height + */ activeRow.height = Math.max(activeRow.height, rasterizedGlyph.size.y); activeRow.x += rasterizedGlyph.size.x; @@ -1057,16 +1103,18 @@ class AtlasPage { public static nextVersion: number = 0; public version = ++AtlasPage.nextVersion; - // Texture atlas current positioning data. The texture packing strategy used is to fill from - // left-to-right and top-to-bottom. When the glyph being written is less than half of the current - // row's height, the following happens: - // - // - The current row becomes the fixed height row A - // - A new fixed height row B the exact size of the glyph is created below the current row - // - A new dynamic height current row is created below B - // - // This strategy does a good job preventing space being wasted for very short glyphs such as - // underscores, hyphens etc. or those with underlines rendered. + /* + * Texture atlas current positioning data. The texture packing strategy used is to fill from + * left-to-right and top-to-bottom. When the glyph being written is less than half of the current + * row's height, the following happens: + * + * - The current row becomes the fixed height row A + * - A new fixed height row B the exact size of the glyph is created below the current row + * - A new dynamic height current row is created below B + * + * This strategy does a good job preventing space being wasted for very short glyphs such as + * underscores, hyphens etc. or those with underlines rendered. + */ public currentRow: ICharAtlasActiveRow = { x: 0, y: 0, @@ -1086,9 +1134,11 @@ class AtlasPage { } } this.canvas = createCanvas(document, size, size); - // The canvas needs alpha because we use clearColor to convert the background color to alpha. - // It might also contain some characters with transparent backgrounds if allowTransparency is - // set. + /* + * The canvas needs alpha because we use clearColor to convert the background color to alpha. + * It might also contain some characters with transparent backgrounds if allowTransparency is + * set. + */ this.ctx = throwIfFalsy(this.canvas.getContext('2d', { alpha: true })); } @@ -1116,12 +1166,14 @@ function clearColor(imageData: ImageData, bg: IColor, fg: IColor, enableThreshol const fgG = fg.rgba >>> 16 & 0xFF; const fgB = fg.rgba >>> 8 & 0xFF; - // Calculate a threshold that when below a color will be treated as transpart when the sum of - // channel value differs. This helps improve rendering when glyphs overlap with others. This - // threshold is calculated relative to the difference between the background and foreground to - // ensure important details of the glyph are always shown, even when the contrast ratio is low. - // The number 12 is largely arbitrary to ensure the pixels that escape the cell in the test case - // were covered (fg=#8ae234, bg=#c4a000). + /* + * Calculate a threshold that when below a color will be treated as transpart when the sum of + * channel value differs. This helps improve rendering when glyphs overlap with others. This + * threshold is calculated relative to the difference between the background and foreground to + * ensure important details of the glyph are always shown, even when the contrast ratio is low. + * The number 12 is largely arbitrary to ensure the pixels that escape the cell in the test case + * were covered (fg=#8ae234, bg=#c4a000). + */ const threshold = Math.floor((Math.abs(r - fgR) + Math.abs(g - fgG) + Math.abs(b - fgB)) / 12); // Set alpha channel of relevent pixels to 0 diff --git a/addons/addon-webgl/src/WebglRenderer.ts b/addons/addon-webgl/src/WebglRenderer.ts index 500308bd1..2997129f2 100644 --- a/addons/addon-webgl/src/WebglRenderer.ts +++ b/addons/addon-webgl/src/WebglRenderer.ts @@ -84,9 +84,11 @@ export class WebglRenderer extends Disposable implements IRenderer { ) { super(); - // IMPORTANT: Canvas initialization and fetching of the context must be first in order to - // prevent possible listeners leaking and continuing to operate after the WebglRenderer has been - // discarded. + /* + * IMPORTANT: Canvas initialization and fetching of the context must be first in order to + * prevent possible listeners leaking and continuing to operate after the WebglRenderer has been + * discarded. + */ this._canvas = this._coreBrowserService.mainDocument.createElement('canvas'); const contextAttributes = { antialias: false, @@ -125,8 +127,10 @@ export class WebglRenderer extends Disposable implements IRenderer { console.log('webglcontextlost event received'); // Prevent the default behavior in order to enable WebGL context restoration. e.preventDefault(); - // Wait a few seconds to see if the 'webglcontextrestored' event is fired. - // If not, dispatch the onContextLoss notification to observers. + /* + * Wait a few seconds to see if the 'webglcontextrestored' event is fired. + * If not, dispatch the onContextLoss notification to observers. + */ this._contextRestorationTimeout = setTimeout(() => { this._contextRestorationTimeout = undefined; console.warn('webgl context not restored; firing onContextLoss'); @@ -137,8 +141,10 @@ export class WebglRenderer extends Disposable implements IRenderer { console.warn('webglcontextrestored event received'); clearTimeout(this._contextRestorationTimeout); this._contextRestorationTimeout = undefined; - // The texture atlas and glyph renderer must be fully reinitialized - // because their contents have been lost. + /* + * The texture atlas and glyph renderer must be fully reinitialized + * because their contents have been lost. + */ removeTerminalFromCache(this._terminal); this._initializeWebGLState(); this._requestRedrawViewport(); @@ -178,8 +184,10 @@ export class WebglRenderer extends Disposable implements IRenderer { } public handleDevicePixelRatioChange(): void { - // If the device pixel ratio changed, the char atlas needs to be regenerated - // and the terminal needs to refreshed + /* + * If the device pixel ratio changed, the char atlas needs to be regenerated + * and the terminal needs to refreshed + */ if (this._devicePixelRatio !== this._coreBrowserService.dpr) { this._devicePixelRatio = this._coreBrowserService.dpr; this.handleResize(this._terminal.cols, this._terminal.rows); @@ -215,8 +223,10 @@ export class WebglRenderer extends Disposable implements IRenderer { this._refreshCharAtlas(); - // Force a full refresh. Resizing `_glyphRenderer` should clear it already, - // so there is no need to clear it again here. + /* + * Force a full refresh. Resizing `_glyphRenderer` should clear it already, + * so there is no need to clear it again here. + */ this._clearModel(false); // Render synchronously to avoid flicker when the canvas is cleared @@ -368,9 +378,11 @@ export class WebglRenderer extends Disposable implements IRenderer { return; } - // Tell renderer the frame is beginning - // upon a model clear also refresh the full viewport model - // (also triggered by an atlas page merge, part of #4480) + /* + * Tell renderer the frame is beginning + * upon a model clear also refresh the full viewport model + * (also triggered by an atlas page merge, part of #4480) + */ if (this._glyphRenderer.value.beginFrame()) { this._clearModel(true); this._updateModel(0, this._terminal.rows - 1); @@ -379,8 +391,10 @@ export class WebglRenderer extends Disposable implements IRenderer { this._updateModel(start, end); } - // A mid-update atlas page merge invalidates vertex data and may not bump the host - // page's version, so re-run the update and force a full texture rebind. + /* + * A mid-update atlas page merge invalidates vertex data and may not bump the host + * page's version, so re-run the update and force a full texture rebind. + */ let merged = false; let mergeRetries = 0; while (this._charAtlas && this._glyphRenderer.value.beginFrame() && mergeRetries++ < Constants.MERGE_RETRY_LIMIT) { @@ -408,8 +422,10 @@ export class WebglRenderer extends Disposable implements IRenderer { } else { this._cursorBlinkStateManager.clear(); } - // Request a refresh from the terminal as management of rendering is being - // moved back to the terminal + /* + * Request a refresh from the terminal as management of rendering is being + * moved back to the terminal + */ this._requestRedrawCursor(); } @@ -470,20 +486,26 @@ export class WebglRenderer extends Disposable implements IRenderer { // If true, indicates that the current character(s) to draw were joined. isJoined = false; - // Indicates whether this cell is part of a joined range that should be ignored as it cannot - // be rendered entirely, like the selection state differs across the range. + /* + * Indicates whether this cell is part of a joined range that should be ignored as it cannot + * be rendered entirely, like the selection state differs across the range. + */ isValidJoinRange = (x >= skipJoinedCheckUntilX); lastCharX = x; - // Process any joined character ranges as needed. Because of how the - // ranges are produced, we know that they are valid for the characters - // and attributes of our input. + /* + * Process any joined character ranges as needed. Because of how the + * ranges are produced, we know that they are valid for the characters + * and attributes of our input. + */ if (joinedRanges.length > 0 && x === joinedRanges[0][0] && isValidJoinRange) { range = joinedRanges.shift()!; - // If the ligature's selection state is not consistent, don't join it. This helps the - // selection render correctly regardless whether they should be joined. + /* + * If the ligature's selection state is not consistent, don't join it. This helps the + * selection render correctly regardless whether they should be joined. + */ const firstSelectionState = this._model.selection.isCellSelected(this._terminal, range[0], row); for (i = range[0] + 1; i < range[1]; i++) { isValidJoinRange &&= (firstSelectionState === this._model.selection.isCellSelected(this._terminal, i, row)); @@ -495,8 +517,10 @@ export class WebglRenderer extends Disposable implements IRenderer { } else { isJoined = true; - // We already know the exact start and end column of the joined range, - // so we get the string and width representing it directly. + /* + * We already know the exact start and end column of the joined range, + * so we get the string and width representing it directly. + */ cell = new JoinedCellData( cell, line!.translateToString(true, range[0], range[1]), @@ -586,8 +610,10 @@ export class WebglRenderer extends Disposable implements IRenderer { j = ((y * terminal.cols) + x) * RenderModelConstants.INDICIES_PER_CELL; this._glyphRenderer.value!.updateCell(x, y, NULL_CELL_CODE, 0, 0, 0, NULL_CELL_CHAR, 0, 0); this._model.cells[j] = NULL_CELL_CODE; - // Don't re-resolve the cell color since multi-colored ligature backgrounds are not - // supported + /* + * Don't re-resolve the cell color since multi-colored ligature backgrounds are not + * supported + */ this._model.cells[j + RenderModelConstants.BG_OFFSET] = this._cellColorResolver.result.bg; this._model.cells[j + RenderModelConstants.FG_OFFSET] = this._cellColorResolver.result.fg; this._model.cells[j + RenderModelConstants.EXT_OFFSET] = this._cellColorResolver.result.ext; @@ -631,48 +657,64 @@ export class WebglRenderer extends Disposable implements IRenderer { return; } - // Calculate the device character width. Width is floored as it must be drawn to an integer grid - // in order for the char atlas glyphs to not be blurry. + /* + * Calculate the device character width. Width is floored as it must be drawn to an integer grid + * in order for the char atlas glyphs to not be blurry. + */ this.dimensions.device.char.width = Math.floor(this._charSizeService.width * this._devicePixelRatio); - // Calculate the device character height. Height is ceiled in case devicePixelRatio is a - // floating point number in order to ensure there is enough space to draw the character to the - // cell. + /* + * Calculate the device character height. Height is ceiled in case devicePixelRatio is a + * floating point number in order to ensure there is enough space to draw the character to the + * cell. + */ this.dimensions.device.char.height = Math.ceil(this._charSizeService.height * this._devicePixelRatio); - // Calculate the device cell height, if lineHeight is _not_ 1, the resulting value will be - // floored since lineHeight can never be lower then 1, this guarentees the device cell height - // will always be larger than device char height. + /* + * Calculate the device cell height, if lineHeight is _not_ 1, the resulting value will be + * floored since lineHeight can never be lower then 1, this guarentees the device cell height + * will always be larger than device char height. + */ this.dimensions.device.cell.height = Math.floor(this.dimensions.device.char.height * this._optionsService.rawOptions.lineHeight); - // Calculate the y offset within a cell that glyph should draw at in order for it to be centered - // correctly within the cell. + /* + * Calculate the y offset within a cell that glyph should draw at in order for it to be centered + * correctly within the cell. + */ this.dimensions.device.char.top = this._optionsService.rawOptions.lineHeight === 1 ? 0 : Math.round((this.dimensions.device.cell.height - this.dimensions.device.char.height) / 2); // Calculate the device cell width, taking the letterSpacing into account. this.dimensions.device.cell.width = this.dimensions.device.char.width + Math.round(this._optionsService.rawOptions.letterSpacing); - // Calculate the x offset with a cell that text should draw from in order for it to be centered - // correctly within the cell. + /* + * Calculate the x offset with a cell that text should draw from in order for it to be centered + * correctly within the cell. + */ this.dimensions.device.char.left = Math.floor(this._optionsService.rawOptions.letterSpacing / 2); - // Recalculate the canvas dimensions, the device dimensions define the actual number of pixel in - // the canvas + /* + * Recalculate the canvas dimensions, the device dimensions define the actual number of pixel in + * the canvas + */ this.dimensions.device.canvas.height = this._terminal.rows * this.dimensions.device.cell.height; this.dimensions.device.canvas.width = this._terminal.cols * this.dimensions.device.cell.width; - // The the size of the canvas on the page. It's important that this rounds to nearest integer - // and not ceils as browsers often have floating point precision issues where - // `window.devicePixelRatio` ends up being something like `1.100000023841858` for example, when - // it's actually 1.1. Ceiling may causes blurriness as the backing canvas image is 1 pixel too - // large for the canvas element size. + /* + * The the size of the canvas on the page. It's important that this rounds to nearest integer + * and not ceils as browsers often have floating point precision issues where + * `window.devicePixelRatio` ends up being something like `1.100000023841858` for example, when + * it's actually 1.1. Ceiling may causes blurriness as the backing canvas image is 1 pixel too + * large for the canvas element size. + */ this.dimensions.css.canvas.height = Math.round(this.dimensions.device.canvas.height / this._devicePixelRatio); this.dimensions.css.canvas.width = Math.round(this.dimensions.device.canvas.width / this._devicePixelRatio); - // Get the CSS dimensions of an individual cell. This needs to be derived from the calculated - // device pixel canvas value above. CharMeasure.width/height by itself is insufficient when the - // page is not at 100% zoom level as CharMeasure is measured in CSS pixels, but the actual char - // size on the canvas can differ. + /* + * Get the CSS dimensions of an individual cell. This needs to be derived from the calculated + * device pixel canvas value above. CharMeasure.width/height by itself is insufficient when the + * page is not at 100% zoom level as CharMeasure is measured in CSS pixels, but the actual char + * size on the canvas can differ. + */ this.dimensions.css.cell.height = this.dimensions.device.cell.height / this._devicePixelRatio; this.dimensions.css.cell.width = this.dimensions.device.cell.width / this._devicePixelRatio; } @@ -681,8 +723,10 @@ export class WebglRenderer extends Disposable implements IRenderer { if (this._canvas.width === width && this._canvas.height === height) { return; } - // While the actual canvas size has changed, keep device canvas dimensions as the value before - // the change as it's an exact multiple of the cell sizes. + /* + * While the actual canvas size has changed, keep device canvas dimensions as the value before + * the change as it's an exact multiple of the cell sizes. + */ this._canvas.width = width; this._canvas.height = height; // Render synchronously to avoid flicker when the canvas is cleared @@ -702,8 +746,10 @@ export class WebglRenderer extends Disposable implements IRenderer { // TODO: Share impl with core export class JoinedCellData extends AttributeData implements ICellData { private _width: number; - // .content carries no meaning for joined CellData, simply nullify it - // thus we have to overload all other .content accessors + /* + * .content carries no meaning for joined CellData, simply nullify it + * thus we have to overload all other .content accessors + */ public content: number = 0; public fg: number; public bg: number; @@ -731,8 +777,10 @@ export class JoinedCellData extends AttributeData implements ICellData { } public getCode(): number { - // code always gets the highest possible fake codepoint (read as -1) - // this is needed as code is used by caches as identifier + /* + * code always gets the highest possible fake codepoint (read as -1) + * this is needed as code is used by caches as identifier + */ return 0x1FFFFF; } diff --git a/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts b/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts index c35299809..d2c95723a 100644 --- a/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts +++ b/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts @@ -274,15 +274,17 @@ export const customGlyphDefinitions: { [index: string]: CustomGlyphCharacterDefi // #region Powerline Symbols (E0A0-E0BF) - // This contains the definitions of the primarily used box drawing characters as vector shapes. - // The reason these characters are defined specially is to avoid common problems if a user's font - // has not been patched with powerline characters and also to get pixel perfect rendering as - // rendering issues can occur around AA/SPAA. - // - // The line variants draw beyond the cell and get clipped to ensure the end of the line is not - // visible. - // - // Original symbols defined in https://github.com/powerline/fontpatcher + /* + * This contains the definitions of the primarily used box drawing characters as vector shapes. + * The reason these characters are defined specially is to avoid common problems if a user's font + * has not been patched with powerline characters and also to get pixel perfect rendering as + * rendering issues can occur around AA/SPAA. + * + * The line variants draw beyond the cell and get clipped to ensure the end of the line is not + * visible. + * + * Original symbols defined in https://github.com/powerline/fontpatcher + */ // Git branch '\u{E0A0}': { type: CustomGlyphDefinitionType.VECTOR_SHAPE, data: { d: 'M.3,1 L.03,1 L.03,.88 C.03,.82,.06,.78,.11,.73 C.15,.7,.2,.68,.28,.65 L.43,.6 C.49,.58,.53,.56,.56,.53 C.59,.5,.6,.47,.6,.43 L.6,.27 L.4,.27 L.69,.1 L.98,.27 L.78,.27 L.78,.46 C.78,.52,.76,.56,.72,.61 C.68,.66,.63,.67,.56,.7 L.48,.72 C.42,.74,.38,.76,.35,.78 C.32,.8,.31,.84,.31,.88 L.31,1 M.3,.5 L.03,.59 L.03,.09 L.3,.09 L.3,.655', type: CustomGlyphVectorType.FILL } }, @@ -355,8 +357,10 @@ export const customGlyphDefinitions: { [index: string]: CustomGlyphCharacterDefi // #region Progress Indicators (EE00-EE0B) - // initially added in Fira Code and later Nerd Fonts - // https://github.com/ryanoasis/nerd-fonts/pull/1733 + /* + * initially added in Fira Code and later Nerd Fonts + * https://github.com/ryanoasis/nerd-fonts/pull/1733 + */ // Progress bars (EE00-EE05) '\u{EE00}': { type: CustomGlyphDefinitionType.PATH, data: 'M0,0 L1,0 L1,.05 L.1,.05 L.1,.95 L1,.95 L1,1 L0,1 Z' }, // PROGRESS BAR EMPTY START @@ -378,8 +382,10 @@ export const customGlyphDefinitions: { [index: string]: CustomGlyphCharacterDefi // #region Git Branch Symbols (F5D0-F60D) - // Initially added in Kitty (https://github.com/kovidgoyal/kitty/pull/7681) - // then in Wezterm (https://github.com/wezterm/wezterm/issues/6328). + /* + * Initially added in Kitty (https://github.com/kovidgoyal/kitty/pull/7681) + * then in Wezterm (https://github.com/wezterm/wezterm/issues/6328). + */ // Straight lines (F5D0-F5D9) '\u{F5D0}': GitBranchSymbolsParts.LINE_H, // Same as 2500 @@ -433,8 +439,10 @@ export const customGlyphDefinitions: { [index: string]: CustomGlyphCharacterDefi '\u{F5FA}': [GitBranchSymbolsParts.NODE_FILL, GitBranchSymbolsParts.NODE_STROKE, GitBranchSymbolsParts.NODE_LINE_DOWN, GitBranchSymbolsParts.NODE_LINE_UP], '\u{F5FB}': [GitBranchSymbolsParts.NODE_STROKE, GitBranchSymbolsParts.NODE_LINE_DOWN, GitBranchSymbolsParts.NODE_LINE_UP], - // Extended Nodes (F5FC-F60D) - // These were added a little later https://github.com/kovidgoyal/kitty/pull/7805 + /* + * Extended Nodes (F5FC-F60D) + * These were added a little later https://github.com/kovidgoyal/kitty/pull/7805 + */ '\u{F5FC}': [GitBranchSymbolsParts.NODE_FILL, GitBranchSymbolsParts.NODE_STROKE, GitBranchSymbolsParts.NODE_LINE_DOWN, GitBranchSymbolsParts.NODE_LINE_RIGHT], '\u{F5FD}': [GitBranchSymbolsParts.NODE_STROKE, GitBranchSymbolsParts.NODE_LINE_DOWN, GitBranchSymbolsParts.NODE_LINE_RIGHT], '\u{F5FE}': [GitBranchSymbolsParts.NODE_FILL, GitBranchSymbolsParts.NODE_STROKE, GitBranchSymbolsParts.NODE_LINE_DOWN, GitBranchSymbolsParts.NODE_LINE_LEFT], @@ -460,8 +468,10 @@ export const customGlyphDefinitions: { [index: string]: CustomGlyphCharacterDefi // https://www.unicode.org/charts/PDF/U1FB00.pdf - // Block mosaic terminal graphic characters (1FB00-1FB3B) - // The term "sextant" refers to block mosaics divided into six parts. + /* + * Block mosaic terminal graphic characters (1FB00-1FB3B) + * The term "sextant" refers to block mosaics divided into six parts. + */ '\u{1FB00}': sextant(0b000001), // BLOCK SEXTANT-1 '\u{1FB01}': sextant(0b000010), // BLOCK SEXTANT-2 '\u{1FB02}': sextant(0b000011), // BLOCK SEXTANT-12 (upper one third block) @@ -724,8 +734,10 @@ export const customGlyphDefinitions: { [index: string]: CustomGlyphCharacterDefi '\u{1FBB2}': { type: CustomGlyphDefinitionType.PATH, data: 'M.29,.27 L0.13,.56 L.22,.59 L.35,0.35 L.67,.35 L.57,.57 L.71,.76 L.22,.76 L.42,1 L.53,.98 L.43,.86 L.9,.86 L.71,.6 L1,.6 L1,.52 L.83,.52 L.92,.36 L1,.36 L1,.27Z M.99,.13 A.12,.12,0,1,1,.75,.13 A.12,.12,0,1,1,.99,.13' }, // LEFT HALF RUNNING MAN '\u{1FBB3}': { type: CustomGlyphDefinitionType.PATH, data: 'M0,.27 L.3,.27 L.55,.12 L.63,.18 L.33,.36 L0,.36 M0,.52 L.33,.52 L.59,.89 L.73,.89 L.73,.98 L.53,.98 L.28,.6 L0,.6' }, // RIGHT HALF RUNNING MAN - // Arrows (1FBB4-1FBB8) - // TODO: Improve all arrows, use hybrid approach + /* + * Arrows (1FBB4-1FBB8) + * TODO: Improve all arrows, use hybrid approach + */ '\u{1FBB4}': { type: CustomGlyphDefinitionType.PATH_NEGATIVE, data: { d: 'M.15,.55 L.5,.4 L.5,.45 L.65,.45 L.65,.35 L.85,.35 L.85,.625 L.5,.625 L.5,.7 Z', type: CustomGlyphVectorType.FILL }, scaleType: CustomGlyphScaleType.CHAR }, // INVERSE DOWNWARDS ARROW WITH TIP LEFTWARDS '\u{1FBB5}': [ // LEFTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCK { type: CustomGlyphDefinitionType.VECTOR_SHAPE, data: { d: 'M0,0 L1,0 L1,.0625 L0,.0625 Z M0,.9375 L1,.9375 L1,1 L0,1 Z', type: CustomGlyphVectorType.FILL } }, @@ -880,9 +892,11 @@ function sextant(pattern: number): { type: CustomGlyphDefinitionType.PATH_FUNCTI return { type: CustomGlyphDefinitionType.PATH_FUNCTION, data: () => { - // Sextant grid: 2 columns, 3 rows - // Row heights in 8ths: top=3, middle=2, bottom=3 - // Column widths: left=4, right=4 + /* + * Sextant grid: 2 columns, 3 rows + * Row heights in 8ths: top=3, middle=2, bottom=3 + * Column widths: left=4, right=4 + */ const rects: string[] = []; const colW = 0.5; // Each column is half width const rowH = [3 / 8, 2 / 8, 3 / 8]; // Row heights as fractions @@ -932,10 +946,12 @@ function sextant(pattern: number): { type: CustomGlyphDefinitionType.PATH_FUNCTI function segmentedDigit(pattern: number): string { const paths: string[] = []; - // Each segment should have approximately the same stroke width, this is somewhat difficult to be - // precise since coordinates are 0-1 of the whole cell (percentage-based). To handle this, the - // fact that terminal cells are typically sized at ~2:1 (height:width) is leveraged. - // for horizontal vs vertical to make segments appear the same thickness + /* + * Each segment should have approximately the same stroke width, this is somewhat difficult to be + * precise since coordinates are 0-1 of the whole cell (percentage-based). To handle this, the + * fact that terminal cells are typically sized at ~2:1 (height:width) is leveraged. + * for horizontal vs vertical to make segments appear the same thickness + */ const segW = 0.15; // Width of vertical segments (fraction of cell width) const segH = 0.075; // Height of horizontal segments (fraction of cell height, ~half of segW for 2:1 cells) const padX = 0.05; // Horizontal padding from edge diff --git a/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts b/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts index ba8925727..ad36378cd 100644 --- a/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts +++ b/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts @@ -489,8 +489,10 @@ function drawPatternChar( pattern = throwIfFalsy(ctx.createPattern(tmpCanvas, null)); patternSet.set(fillStyle, pattern); } - // Apply pattern offset to ensure seamless tiling across cells when cell dimensions are odd. - // variantOffset encodes: bit 1 = x pixel shift, bit 0 = y pixel shift. + /* + * Apply pattern offset to ensure seamless tiling across cells when cell dimensions are odd. + * variantOffset encodes: bit 1 = x pixel shift, bit 0 = y pixel shift. + */ const dx = (variantOffset >> 1) & 1; const dy = variantOffset & 1; if (dx !== 0 || dy !== 0) { @@ -713,8 +715,10 @@ function translateArgs(args: string[], cellWidth: number, cellHeight: number, xO for (let x = 0; x < result.length; x += 2) { // Translate from 0-1 to 0-cellWidth result[x] *= cellWidth - (leftPadding * devicePixelRatio) - (rightPadding * devicePixelRatio); - // Round to the nearest 0.5 to ensure a crisp line at 100% devicePixelRatio, and optionally - // clamp to the cell bounds. + /* + * Round to the nearest 0.5 to ensure a crisp line at 100% devicePixelRatio, and optionally + * clamp to the cell bounds. + */ if (doClamp && result[x] !== 0) { const rounded = Math.round(result[x] + 0.5) - 0.5; result[x] = clampToCell ? clamp(rounded, cellWidth, 0) : rounded; @@ -726,8 +730,10 @@ function translateArgs(args: string[], cellWidth: number, cellHeight: number, xO for (let y = 1; y < result.length; y += 2) { // Translate from 0-1 to 0-cellHeight result[y] *= cellHeight; - // Round to the nearest 0.5 to ensure a crisp line at 100% devicePixelRatio, and optionally - // clamp to the cell bounds. + /* + * Round to the nearest 0.5 to ensure a crisp line at 100% devicePixelRatio, and optionally + * clamp to the cell bounds. + */ if (doClamp && result[y] !== 0) { const rounded = Math.round(result[y] + 0.5) - 0.5; result[y] = clampToCell ? clamp(rounded, cellHeight, 0) : rounded; diff --git a/addons/addon-webgl/test/WebglRenderer.test.ts b/addons/addon-webgl/test/WebglRenderer.test.ts index c425fa000..b39521180 100644 --- a/addons/addon-webgl/test/WebglRenderer.test.ts +++ b/addons/addon-webgl/test/WebglRenderer.test.ts @@ -24,9 +24,11 @@ test.beforeAll(async ({ browser }) => { test.afterAll(async () => await ctx.page.close()); test.describe('WebGL Renderer Integration Tests', async () => { - // HACK: webgl2 is often not supported in headless firefox on Linux - // https://github.com/microsoft/playwright/issues/11566 - // also disable safari due to #5852 + /* + * HACK: webgl2 is often not supported in headless firefox on Linux + * https://github.com/microsoft/playwright/issues/11566 + * also disable safari due to #5852 + */ if (platform() === 'linux') { test.skip(({ browserName }) => browserName === 'firefox' || browserName === 'webkit'); } diff --git a/demo/client/client.ts b/demo/client/client.ts index aab723b7e..b1718f64f 100644 --- a/demo/client/client.ts +++ b/demo/client/client.ts @@ -173,9 +173,11 @@ const createNewWindowButtonHandler: () => void = () => { terminalContainer.id = 'terminal-container'; win.document.body.appendChild(terminalContainer); - // Stylesheets are needed to get the terminal in the popout window to render - // correctly. We also need to wait for them to load before creating the - // terminal, otherwise we will not compute the correct metrics when rendering. + /* + * Stylesheets are needed to get the terminal in the popout window to render + * correctly. We also need to wait for them to load before creating the + * terminal, otherwise we will not compute the correct metrics when rendering. + */ let pendingStylesheets = 0; for (const linkNode of document.querySelectorAll('head link[rel=stylesheet]')) { const newLink = document.createElement('link'); @@ -359,8 +361,10 @@ function createTerminal(): Terminal { const resizeObserver = new ResizeObserver(entries => { if (optionsWindow.autoResize) { - // In general this should be debounced to avoid excessive work on the main - // thread by firing the expensive resize action repeatedly + /* + * In general this should be debounced to avoid excessive work on the main + * thread by firing the expensive resize action repeatedly + */ addons.fit.instance!.fit(); } }); @@ -547,8 +551,10 @@ function initAddons(term: Terminal): void { addon.instance = undefined; } if (name === 'ligatures') { - // Recreate webgl when ligatures are toggled so texture atlas picks up any font feature - // settings changes + /* + * Recreate webgl when ligatures are toggled so texture atlas picks up any font feature + * settings changes + */ if (addons.webgl.instance) { preDisposeWebgl(); addons.webgl.instance.dispose(); diff --git a/demo/client/components/window/addonImageWindow.ts b/demo/client/components/window/addonImageWindow.ts index 392b7177b..c089cf5f7 100644 --- a/demo/client/components/window/addonImageWindow.ts +++ b/demo/client/components/window/addonImageWindow.ts @@ -165,16 +165,18 @@ export class AddonImageWindow extends BaseWindow implements IControlWindow { this._terminal.element!.addEventListener('click', (ev: MouseEvent) => { if (!ev.ctrlKey || !imageAddon) return; - // TODO... - // if (ev.altKey) { - // const sel = term.getSelectionPosition(); - // if (sel) { - // addons.image.instance - // .extractCanvasAtBufferRange(term.getSelectionPosition()) - // ?.toBlob(data => window.open(URL.createObjectURL(data), '_blank')); - // return; - // } - // } + /* + * TODO... + * if (ev.altKey) { + * const sel = term.getSelectionPosition(); + * if (sel) { + * addons.image.instance + * .extractCanvasAtBufferRange(term.getSelectionPosition()) + * ?.toBlob(data => window.open(URL.createObjectURL(data), '_blank')); + * return; + * } + * } + */ const pos = (this._terminal as any)._core._mouseService!.getCoords(ev, (this._terminal as any)._core.screenElement!, this._terminal.cols, this._terminal.rows); const x = pos[0] - 1; diff --git a/demo/client/components/window/addonProgressWindow.ts b/demo/client/components/window/addonProgressWindow.ts index 167c9ca28..fe4e51ca7 100644 --- a/demo/client/components/window/addonProgressWindow.ts +++ b/demo/client/components/window/addonProgressWindow.ts @@ -66,11 +66,13 @@ export class AddonProgressWindow extends BaseWindow implements IControlWindow { const colors = { 0: '', 1: 'green', 2: 'red', 3: '', 4: 'yellow' }; function progressHandler({ state, value }: IProgressState): void { - // Simulate windows taskbar hack by windows terminal: - // Since the taskbar has no means to indicate error/pause state other than by coloring - // the current progress, we move 0 to 10% and distribute higher values in the remaining 90 % - // NOTE: This is most likely not what you want to do for other progress indicators, - // that have a proper visual state for error/paused. + /* + * Simulate windows taskbar hack by windows terminal: + * Since the taskbar has no means to indicate error/pause state other than by coloring + * the current progress, we move 0 to 10% and distribute higher values in the remaining 90 % + * NOTE: This is most likely not what you want to do for other progress indicators, + * that have a proper visual state for error/paused. + */ value = Math.min(10 + value * 0.9, 100); document.getElementById('progress-percent')!.style.width = `${value}%`; document.getElementById('progress-percent')!.style.backgroundColor = colors[state]; diff --git a/demo/client/components/window/testWindow.ts b/demo/client/components/window/testWindow.ts index 1ea6b3e67..e66795ab1 100644 --- a/demo/client/components/window/testWindow.ts +++ b/demo/client/components/window/testWindow.ts @@ -435,9 +435,11 @@ function customGlyphAlignmentHandler(term: Terminal): void { } function customGlyphRangesHandler(term: Terminal): void { - // Box Drawing - // 2500-257F - // https://www.unicode.org/charts/PDF/U2500.pdf + /* + * Box Drawing + * 2500-257F + * https://www.unicode.org/charts/PDF/U2500.pdf + */ writeUnicodeTable(term, 'Box Drawing', 0x2500, 0x257F, [ ['Light and heavy solid lines', 0x2500, 0x2503], ['Light and heavy dashed lines', 0x2504, 0x250B], @@ -450,39 +452,49 @@ function customGlyphRangesHandler(term: Terminal): void { ['Light and heavy half lines', 0x2574, 0x257B], ['Mixed light and heavy lines', 0x257C, 0x257F], ]); - // Box Elements - // 2580-259F - // https://www.unicode.org/charts/PDF/U2580.pdf + /* + * Box Elements + * 2580-259F + * https://www.unicode.org/charts/PDF/U2580.pdf + */ writeUnicodeTable(term, 'Box Elements', 0x2580, 0x259F, [ ['Block elements', 0x2580, 0x2590], ['Shade characters', 0x2591, 0x2593], ['Block elements', 0x2594, 0x2595], ['Terminal graphic characters', 0x2596, 0x259F], ]); - // Braille Patterns - // 2800-28FF - // https://www.unicode.org/charts/PDF/U2800.pdf + /* + * Braille Patterns + * 2800-28FF + * https://www.unicode.org/charts/PDF/U2800.pdf + */ writeUnicodeTable(term, 'Braille patterns', 0x2800, 0x28FF, [ ['Braille patterns', 0x2800, 0x28FF], ]); - // Powerline Symbols - // Range: E0A0–E0D4 - // https://github.com/ryanoasis/nerd-fonts + /* + * Powerline Symbols + * Range: E0A0–E0D4 + * https://github.com/ryanoasis/nerd-fonts + */ writeUnicodeTable(term, 'Powerline Symbols', 0xE0A0, 0xE0D4, [ ['Powerline symbols', 0xE0A0, 0xE0B3, [0xE0A4, 0xE0A5, 0xE0A6, 0xE0A7, 0xE0A8, 0xE0A9, 0xE0AA, 0xE0AB, 0xE0AC, 0xE0AD, 0xE0AE, 0xE0AF]], ['Powerline extra symbols', 0xE0B4, 0xE0D4, [0xE0C9, 0xE0CB, 0xE0D3]], ]); - // Progress Indicators - // Range: EE00-EE0B - // https://github.com/tonsky/FiraCode + /* + * Progress Indicators + * Range: EE00-EE0B + * https://github.com/tonsky/FiraCode + */ writeUnicodeTable(term, 'Progress Indicators', 0xEE00, 0xEE0B, [ ['Progress bars', 0xEE00, 0xEE05], ['Progress spinners', 0xEE06, 0xEE0B], ]); - // https://github.com/ryanoasis/nerd-fonts/pull/1733 - // Git Branch Symbols - // F5D0-F60D - // https://github.com/xtermjs/xterm.js/issues/5477 + /* + * https://github.com/ryanoasis/nerd-fonts/pull/1733 + * Git Branch Symbols + * F5D0-F60D + * https://github.com/xtermjs/xterm.js/issues/5477 + */ writeUnicodeTable(term, 'Git Branch Symbols', 0xF5D0, 0xF5FB, [ ['Straight lines', 0xF5D0, 0xF5D5], ['Curved lines', 0xF5D6, 0xF5D9], @@ -490,9 +502,11 @@ function customGlyphRangesHandler(term: Terminal): void { ['Nodes', 0xF5EE, 0xF5FB], ['Extended nodes', 0xF5FC, 0xF60D], ]); - // Symbols for Legacy Computing - // Range: 1FB00–1FBFF - // https://www.unicode.org/charts/PDF/U1FB00.pdf + /* + * Symbols for Legacy Computing + * Range: 1FB00–1FBFF + * https://www.unicode.org/charts/PDF/U1FB00.pdf + */ writeUnicodeTable(term, 'Symbols for Legacy Computing', 0x1FB00, 0x1FBFF, [ ['Block mosaic terminal graphic characters (Sextants)', 0x1FB00, 0x1FB3B], ['Smooth mosaic terminal graphic characters', 0x1FB3C, 0x1FB6F], @@ -690,8 +704,10 @@ function loadTest(term: Terminal, addons: AddonCollection): void { for (let i = 1; i < count + 1; i++) { data[i] = 0x61 + Math.floor(Math.random() * (0x7A - 0x61)); } - // End each line with \r so the cursor remains constant, this is what ls/tree do and improves - // performance significantly due to the cursor DOM element not needing to change + /* + * End each line with \r so the cursor remains constant, this is what ls/tree do and improves + * performance significantly due to the cursor DOM element not needing to change + */ data[data.length - 1] = 0x0D; // \r testData.push(data); } @@ -723,8 +739,10 @@ async function loadTestLongLines(term: Terminal, addons: AddonCollection): Promi for (let i = 1; i < count + 1; i++) { data[i] = 0x61 + Math.floor(Math.random() * (0x7A - 0x61)); } - // End each line with \r so the cursor remains constant, this is what ls/tree do and improves - // performance significantly due to the cursor DOM element not needing to change + /* + * End each line with \r so the cursor remains constant, this is what ls/tree do and improves + * performance significantly due to the cursor DOM element not needing to change + */ data[data.length - 1] = 0x0D; // \r testData.push(data); } @@ -734,8 +752,10 @@ async function loadTestLongLines(term: Terminal, addons: AddonCollection): Promi try { term.write(d); } catch { - // Flush events when cap is hit and try again(workaround for not having flow control in - // demo) + /* + * Flush events when cap is hit and try again(workaround for not having flow control in + * demo) + */ await new Promise(r => term.write('', () => r())); term.write(d); } diff --git a/demo/client/unicodeTable.ts b/demo/client/unicodeTable.ts index 61bba36f2..9755b911a 100644 --- a/demo/client/unicodeTable.ts +++ b/demo/client/unicodeTable.ts @@ -220,8 +220,10 @@ export function writeUnicodeTable(term: Terminal, name: string, start: number, e term.write('\n\r'); - // Render reserved labels that appear after the first label (below the row) - // Show one label per non-contiguous reserved range + /* + * Render reserved labels that appear after the first label (below the row) + * Show one label per non-contiguous reserved range + */ const lateReserved = rowLabels.length > 0 ? rowReserved.filter(r => r.col >= rowLabels[0].col) : rowReserved; diff --git a/demo/server/server.ts b/demo/server/server.ts index ef98eb84c..5bd594dcb 100644 --- a/demo/server/server.ts +++ b/demo/server/server.ts @@ -180,9 +180,11 @@ function startServer(): void { } const send = (USE_BINARY ? bufferUtf8 : buffer)(ws, 3, 262144); - // WARNING: This is a naive implementation that will not throttle the flow of data. This means - // it could flood the communication channel and make the terminal unresponsive. Learn more about - // the problem and how to implement flow control at https://xtermjs.org/docs/guides/flowcontrol/ + /* + * WARNING: This is a naive implementation that will not throttle the flow of data. This means + * it could flood the communication channel and make the terminal unresponsive. Learn more about + * the problem and how to implement flow control at https://xtermjs.org/docs/guides/flowcontrol/ + */ term.onData(function(data) { try { send(data as string & Buffer); @@ -209,8 +211,10 @@ function startServer(): void { app.listen(port, host, 0); } -// HACK: There is an EPIPE error thrown when reloading a page. This only seems to happen on Windows -// and it's unclear why it happens. Suppressing the error here since this is just the demo server. +/* + * HACK: There is an EPIPE error thrown when reloading a page. This only seems to happen on Windows + * and it's unclear why it happens. Suppressing the error here since this is just the demo server. + */ process.on('uncaughtException', (error) => { if (process.platform === 'win32' && error.message === 'read EPIPE') { return; diff --git a/eslint.config.mjs b/eslint.config.mjs index 6c2f80e30..18a4dfb59 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -88,6 +88,7 @@ export default tseslint.config( 'jsdoc/check-param-names': 'warn', 'jsdoc/no-multi-asterisks': 'warn', 'keyword-spacing': 'warn', + 'multiline-comment-style': ['warn', 'starred-block'], 'max-len': ['warn', { code: 1000, comments: 100, diff --git a/src/browser/AccessibilityManager.ts b/src/browser/AccessibilityManager.ts index 6fc421337..5960c8d4f 100644 --- a/src/browser/AccessibilityManager.ts +++ b/src/browser/AccessibilityManager.ts @@ -21,8 +21,10 @@ const enum BoundaryPosition { BOTTOM } -// Turn this on to unhide the accessibility tree and display it under -// (instead of overlapping with) the terminal. +/* + * Turn this on to unhide the accessibility tree and display it under + * (instead of overlapping with) the terminal. + */ const DEBUG = false; export class AccessibilityManager extends Disposable { @@ -223,8 +225,10 @@ export class AccessibilityManager extends Disposable { return; } - // Don't scroll when the last focused item was not the second row (focus is going the other - // direction) + /* + * Don't scroll when the last focused item was not the second row (focus is going the other + * direction) + */ if (e.relatedTarget !== beforeBoundaryElement) { return; } @@ -283,9 +287,11 @@ export class AccessibilityManager extends Disposable { } if (selection.isCollapsed) { - // Only do something when the anchorNode is inside the row container. This - // behavior mirrors what we do with mouse --- if the mouse clicks - // somewhere outside of the terminal, we don't clear the selection. + /* + * Only do something when the anchorNode is inside the row container. This + * behavior mirrors what we do with mouse --- if the mouse clicks + * somewhere outside of the terminal, we don't clear the selection. + */ if (this._rowContainer.contains(selection.anchorNode)) { this._terminal.clearSelection(); } diff --git a/src/browser/Clipboard.ts b/src/browser/Clipboard.ts index aaf8a48e4..513dfa60c 100644 --- a/src/browser/Clipboard.ts +++ b/src/browser/Clipboard.ts @@ -22,8 +22,10 @@ export function bracketTextForPaste(text: string, bracketedPasteMode: boolean): if (!bracketedPasteMode) { return text; } - // Sanitize pasted text to prevent injected escape sequences (e.g. exiting bracketed paste) - // by replacing ESC (\x1b) with its visible representation U+241B (␛). + /* + * Sanitize pasted text to prevent injected escape sequences (e.g. exiting bracketed paste) + * by replacing ESC (\x1b) with its visible representation U+241B (␛). + */ const sanitizedText = text.replace(/\x1b/g, '\u241b'); return `\x1b[200~${sanitizedText}\x1b[201~`; } diff --git a/src/browser/CoreBrowserTerminal.ts b/src/browser/CoreBrowserTerminal.ts index 52eb00025..519d8b1dc 100644 --- a/src/browser/CoreBrowserTerminal.ts +++ b/src/browser/CoreBrowserTerminal.ts @@ -323,8 +323,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { * Binds the desired blur behavior on a given terminal object. */ private _handleTextAreaBlur(): void { - // Text can safely be removed on blur. Doing it earlier could interfere with - // screen readers reading it out. + /* + * Text can safely be removed on blur. Doing it earlier could interfere with + * screen readers reading it out. + */ this.textarea!.value = ''; this.refresh(this.buffer.y, this.buffer.y); if (this.coreService.decPrivateModes.sendFocus) { @@ -350,8 +352,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { const cursorTop = this.buffer.y * this._renderService.dimensions.css.cell.height; const cursorLeft = cursorX * this._renderService.dimensions.css.cell.width; - // Sync the textarea to the exact position of the composition view so the IME knows where the - // text is. + /* + * Sync the textarea to the exact position of the composition view so the IME knows where the + * text is. + */ this.textarea.style.left = cursorLeft + 'px'; this.textarea.style.top = cursorTop + 'px'; this.textarea.style.width = cellWidth + 'px'; @@ -368,8 +372,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { // Bind clipboard functionality this._register(addDisposableListener(this.element!, 'copy', (event: ClipboardEvent) => { - // If mouse events are active it means the selection manager is disabled and - // copy should be handled by the host program. + /* + * If mouse events are active it means the selection manager is disabled and + * copy should be handled by the host program. + */ if (!this.hasSelection()) { return; } @@ -393,12 +399,16 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { })); } - // Move the textarea under the cursor when middle clicking on Linux to ensure - // middle click to paste selection works. This only appears to work in Chrome - // at the time is writing. + /* + * Move the textarea under the cursor when middle clicking on Linux to ensure + * middle click to paste selection works. This only appears to work in Chrome + * at the time is writing. + */ if (Browser.isLinux) { - // Use auxclick event over mousedown the latter doesn't seem to work. Note - // that the regular click event doesn't fire for the middle mouse button. + /* + * Use auxclick event over mousedown the latter doesn't seem to work. Note + * that the regular click event doesn't fire for the middle mouse button. + */ this._register(addDisposableListener(this.element!, 'auxclick', (event: MouseEvent) => { if (event.button === 1) { moveTextAreaUnderMouseCursor(event, this.textarea!, this.screenElement!); @@ -415,11 +425,13 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { this._register(addDisposableListener(this.textarea!, 'keydown', (ev: KeyboardEvent) => this._keyDown(ev), true)); this._register(addDisposableListener(this.textarea!, 'keypress', (ev: KeyboardEvent) => this._keyPress(ev), true)); this._register(addDisposableListener(this.textarea!, 'compositionstart', () => { - // Ensure the textarea is synced to the latest cursor location before composition begins. This - // is to workaround a problem where highly dynamic TUIs like agentic CLIs reprint agressively - // would cause the IME to appear in the wrong position. The theory is that when the IME is - // triggered during a partial render the textarea position becomes locked and will not move - // until it is hidden and a custom move occurs. + /* + * Ensure the textarea is synced to the latest cursor location before composition begins. This + * is to workaround a problem where highly dynamic TUIs like agentic CLIs reprint agressively + * would cause the IME to appear in the wrong position. The theory is that when the IME is + * triggered during a partial render the textarea position becomes locked and will not move + * until it is hidden and a custom move occurs. + */ this._syncTextArea(); this._compositionHelper!.compositionstart(); this._compositionHelper!.updateCompositionElements(); @@ -467,8 +479,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { this._register(this.optionsService.onSpecificOptionChange('allowTransparency', value => this.element!.classList.toggle('allow-transparency', value))); parent.appendChild(this.element); - // Performance: Use a document fragment to build the terminal - // viewport and helper elements detached from the DOM + /* + * Performance: Use a document fragment to build the terminal + * viewport and helper elements detached from the DOM + */ const fragment = this._document.createDocumentFragment(); this._viewportElement = this._document.createElement('div'); this._viewportElement.classList.add('xterm-viewport'); @@ -477,8 +491,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { this.screenElement = this._document.createElement('div'); this.screenElement.classList.add('xterm-screen'); this._register(addDisposableListener(this.screenElement, 'mousemove', (ev: MouseEvent) => this.updateCursorStyle(ev))); - // Create the container that will hold helpers like the textarea for - // capturing DOM Events. Then produce the helpers. + /* + * Create the container that will hold helpers like the textarea for + * capturing DOM Events. Then produce the helpers. + */ this._helperContainer = this._document.createElement('div'); this._helperContainer.classList.add('xterm-helpers'); this.screenElement.appendChild(this._helperContainer); @@ -488,8 +504,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { this.textarea.classList.add('xterm-helper-textarea'); this.textarea.setAttribute('aria-label', Strings.promptLabel.get()); if (!Browser.isChromeOS) { - // ChromeVox on ChromeOS does not like this. See - // https://issuetracker.google.com/issues/260170397 + /* + * ChromeVox on ChromeOS does not like this. See + * https://issuetracker.google.com/issues/260170397 + */ this.textarea.setAttribute('aria-multiline', 'false'); } this.textarea.setAttribute('autocorrect', 'off'); @@ -499,8 +517,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { this._register(this.optionsService.onSpecificOptionChange('disableStdin', () => textarea.readOnly = this.optionsService.rawOptions.disableStdin)); this.textarea.readOnly = this.optionsService.rawOptions.disableStdin; - // Register the core browser service before the generic textarea handlers are registered so it - // handles them first. Otherwise the renderers may use the wrong focus state. + /* + * Register the core browser service before the generic textarea handlers are registered so it + * handles them first. Otherwise the renderers may use the wrong focus state. + */ this._coreBrowserService = this._register(this._instantiationService.createInstance(CoreBrowserService, this.textarea, parent.ownerDocument.defaultView ?? window, @@ -598,9 +618,11 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { this._register(this._selectionService.onSelectionChange(() => this._onSelectionChange.fire())); this._register(this._selectionService.onRequestRedraw(e => this._renderService!.handleSelectionChanged(e.start, e.end, e.columnSelectMode))); this._register(this._selectionService.onLinuxMouseSelection(text => { - // If there's a new selection, put it into the textarea, focus and select it - // in order to register it as a selection on the OS. This event is fired - // only on Linux to enable middle click to paste selection. + /* + * If there's a new selection, put it into the textarea, focus and select it + * in order to register it as a selection on the OS. This event is fired + * only on Linux to enable middle click to paste selection. + */ this.textarea!.value = text; this.textarea!.focus(); this.textarea!.select(); @@ -625,8 +647,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { } if (this.options.screenReaderMode) { - // Note that this must be done *after* the renderer is created in order to - // ensure the correct order of the dprchange event + /* + * Note that this must be done *after* the renderer is created in order to + * ensure the correct order of the dprchange event + */ this._accessibilityManager.value = this._instantiationService.createInstance(AccessibilityManager, this); } this._register(this.optionsService.onSpecificOptionChange('screenReaderMode', e => this._handleScreenReaderModeOptionChange(e))); @@ -651,8 +675,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { // Initialize global actions that need to be taken on the document. this._initGlobal(); - // Listen for mouse events and translate - // them into terminal mouse protocols. + /* + * Listen for mouse events and translate + * them into terminal mouse protocols. + */ this._mouseService.bindMouse({ element: this.element!, screenElement: this.screenElement!, @@ -892,9 +918,11 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { return true; } - // HACK: Process A-Z in the keypress event to fix an issue with macOS IMEs where lower case - // letters cannot be input while caps lock is on. Skip this hack when using kitty protocol - // or Win32 input mode as they need to send proper sequences for all key events. + /* + * HACK: Process A-Z in the keypress event to fix an issue with macOS IMEs where lower case + * letters cannot be input while caps lock is on. Skip this hack when using kitty protocol + * or Win32 input mode as they need to send proper sequences for all key events. + */ if (!this._keyboardService.useKitty && !this._keyboardService.useWin32InputMode && event.key && !event.ctrlKey && !event.altKey && !event.metaKey && event.key.length === 1) { if (event.key.charCodeAt(0) >= 65 && event.key.charCodeAt(0) <= 90) { return true; @@ -906,9 +934,11 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { return true; } - // If ctrl+c or enter is being sent, clear out the textarea. This is done so that screen readers - // will announce deleted characters. This will not work 100% of the time but it should cover - // most scenarios. + /* + * If ctrl+c or enter is being sent, clear out the textarea. This is done so that screen readers + * will announce deleted characters. This will not work 100% of the time but it should cover + * most scenarios. + */ if (result.key === C0.ETX || result.key === C0.CR) { this.textarea!.value = ''; } @@ -918,10 +948,12 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { this._showCursor(); this.coreService.triggerDataEvent(result.key, !wasModifierOnly); - // Cancel events when not in screen reader mode so events don't get bubbled up and handled by - // other listeners. When screen reader mode is enabled, we don't cancel them (unless ctrl or alt - // is also depressed) so that the cursor textarea can be updated, which triggers the screen - // reader to read it. + /* + * Cancel events when not in screen reader mode so events don't get bubbled up and handled by + * other listeners. When screen reader mode is enabled, we don't cancel them (unless ctrl or alt + * is also depressed) so that the cursor textarea can be updated, which triggers the screen + * reader to read it. + */ if (!this.optionsService.rawOptions.screenReaderMode || event.altKey || event.ctrlKey) { event.preventDefault(); event.stopPropagation(); @@ -1010,8 +1042,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { this._keyPressHandled = true; - // The key was handled so clear the dead key state, otherwise certain keystrokes like arrow - // keys could be ignored + /* + * The key was handled so clear the dead key state, otherwise certain keystrokes like arrow + * keys could be ignored + */ this._unprocessedDeadKey = false; return true; @@ -1024,16 +1058,20 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { * @param ev The input event to be handled. */ protected _inputEvent(ev: InputEvent): boolean { - // Only support emoji IMEs when screen reader mode is disabled as the event must bubble up to - // support reading out character input which can doubling up input characters - // Based on these event traces: https://github.com/xtermjs/xterm.js/issues/3679 + /* + * Only support emoji IMEs when screen reader mode is disabled as the event must bubble up to + * support reading out character input which can doubling up input characters + * Based on these event traces: https://github.com/xtermjs/xterm.js/issues/3679 + */ if (ev.data && ev.inputType === 'insertText' && (!ev.composed || !this._keyDownSeen) && !this.optionsService.rawOptions.screenReaderMode) { if (this._keyPressHandled) { return false; } - // The key was handled so clear the dead key state, otherwise certain keystrokes like arrow - // keys could be ignored + /* + * The key was handled so clear the dead key state, otherwise certain keystrokes like arrow + * keys could be ignored + */ this._unprocessedDeadKey = false; const text = ev.data; @@ -1083,8 +1121,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { for (let i = 1; i < this.rows; i++) { this.buffer.lines.push(this.buffer.getBlankLine(DEFAULT_ATTR_DATA)); } - // IMPORTANT: Fire scroll event before viewport is reset. This ensures embedders get the clear - // scroll event and that the viewport's state will be valid for immediate writes. + /* + * IMPORTANT: Fire scroll event before viewport is reset. This ensures embedders get the clear + * scroll event and that the viewport's state will be valid for immediate writes. + */ this._onScroll.fire({ position: this.buffer.ydisp }); this.refresh(0, this.rows - 1); } diff --git a/src/browser/Linkifier.ts b/src/browser/Linkifier.ts index 31c91daee..e99c41dfa 100644 --- a/src/browser/Linkifier.ts +++ b/src/browser/Linkifier.ts @@ -87,9 +87,11 @@ export class Linkifier extends Disposable implements ILinkifier2 { } private _handleHover(position: IBufferCellPosition): void { - // TODO: This currently does not cache link provider results across wrapped lines, activeLine - // should be something like `activeRange: {startY, endY}` - // Check if we need to clear the link + /* + * TODO: This currently does not cache link provider results across wrapped lines, activeLine + * should be something like `activeRange: {startY, endY}` + * Check if we need to clear the link + */ if (this._activeLine !== position.y || this._wasResized) { this._clearCurrentLink(); this._askForLink(position, false); @@ -125,9 +127,11 @@ export class Linkifier extends Disposable implements ILinkifier2 { const existingReply = this._activeProviderReplies?.get(i); // If there isn't a reply, the provider hasn't responded yet. - // TODO: If there isn't a reply yet it means that the provider is still resolving. Ensuring - // provideLinks isn't triggered again saves ILink.hover firing twice though. This probably - // needs promises to get fixed + /* + * TODO: If there isn't a reply yet it means that the provider is still resolving. Ensuring + * provideLinks isn't triggered again saves ILink.hover firing twice though. This probably + * needs promises to get fixed + */ if (existingReply) { linkProvided = this._checkLinkProviderResult(i, position, linkProvided); } @@ -140,8 +144,10 @@ export class Linkifier extends Disposable implements ILinkifier2 { this._activeProviderReplies?.set(i, linksWithState); linkProvided = this._checkLinkProviderResult(i, position, linkProvided); - // If all providers have responded, remove lower priority links that intersect ranges of - // higher priority links + /* + * If all providers have responded, remove lower priority links that intersect ranges of + * higher priority links + */ if (this._activeProviderReplies?.size === this._linkProviderService.linkProviders.length) { this._removeIntersectingLinks(position.y, this._activeProviderReplies); } @@ -187,8 +193,10 @@ export class Linkifier extends Disposable implements ILinkifier2 { } } - // If all providers with higher priority came back undefined, then this provider's link for - // the position should be used + /* + * If all providers with higher priority came back undefined, then this provider's link for + * the position should be used + */ if (!hasLinkBefore && links) { const linkAtPosition = links.find(link => this._linkAtPosition(link.link, position)); if (linkAtPosition) { @@ -296,15 +304,19 @@ export class Linkifier extends Disposable implements ILinkifier2 { } }); - // Listen to viewport changes to re-render the link under the cursor (only when the line the - // link is on changes) + /* + * Listen to viewport changes to re-render the link under the cursor (only when the line the + * link is on changes) + */ this._linkCacheDisposables.push(this._renderService.onRenderedViewportChange(e => { // Sanity check, this shouldn't happen in practice as this listener would be disposed if (!this._currentLink) { return; } - // When start is 0 a scroll most likely occurred, make sure links above the fold also get - // cleared. + /* + * When start is 0 a scroll most likely occurred, make sure links above the fold also get + * cleared. + */ const start = e.start === 0 ? 0 : e.start + 1 + this._bufferService.buffer.ydisp; const end = this._bufferService.buffer.ydisp + 1 + e.end; // Only clear the link if the viewport change happened on this line diff --git a/src/browser/OscLinkProvider.ts b/src/browser/OscLinkProvider.ts index b6a3cce0a..8ed823203 100644 --- a/src/browser/OscLinkProvider.ts +++ b/src/browser/OscLinkProvider.ts @@ -33,8 +33,10 @@ export class OscLinkProvider implements ILinkProvider { let currentStart = -1; let finishLink = false; for (let x = 0; x < lineLength; x++) { - // Minor optimization, only check for content if there isn't a link in case the link ends with - // a null cell + /* + * Minor optimization, only check for content if there isn't a link in case the link ends with + * a null cell + */ if (currentStart === -1 && !line.hasContent(x)) { continue; } @@ -107,8 +109,10 @@ export class OscLinkProvider implements ILinkProvider { } } - // TODO: Handle fetching and returning other link ranges to underline other links with the same - // id + /* + * TODO: Handle fetching and returning other link ranges to underline other links with the same + * id + */ callback(result); } } diff --git a/src/browser/Terminal.test.ts b/src/browser/Terminal.test.ts index d359fa28c..425955982 100644 --- a/src/browser/Terminal.test.ts +++ b/src/browser/Terminal.test.ts @@ -576,14 +576,16 @@ describe('Terminal', () => { beforeEach(() => { term.clearSelection = () => { }; - // term.compositionHelper = { - // isComposing: false, - // keydown: { - // bind: () => { - // return () => { return true; }; - // } - // } - // }; + /* + * term.compositionHelper = { + * isComposing: false, + * keydown: { + * bind: () => { + * return () => { return true; }; + * } + * } + * }; + */ evKeyDown = { preventDefault: () => { }, stopPropagation: () => { }, @@ -1148,8 +1150,10 @@ describe('Terminal', () => { // FIXME: move to common/CoreTerminal.test once the trimming is moved over describe('marker lifecycle', () => { - // create a 10x5 terminal with markers on every line - // to test marker lifecycle under various terminal actions + /* + * create a 10x5 terminal with markers on every line + * to test marker lifecycle under various terminal actions + */ let markers: IMarker[]; let disposeStack: IMarker[]; let term: TestTerminal; diff --git a/src/browser/TimeBasedDebouncer.ts b/src/browser/TimeBasedDebouncer.ts index 997312901..8d609cb23 100644 --- a/src/browser/TimeBasedDebouncer.ts +++ b/src/browser/TimeBasedDebouncer.ts @@ -43,8 +43,10 @@ export class TimeBasedDebouncer implements IRenderDebouncer { this._rowStart = this._rowStart !== undefined ? Math.min(this._rowStart, rowStart) : rowStart; this._rowEnd = this._rowEnd !== undefined ? Math.max(this._rowEnd, rowEnd) : rowEnd; - // Only refresh if the time since last refresh is above a threshold, otherwise wait for - // enough time to pass before refreshing again. + /* + * Only refresh if the time since last refresh is above a threshold, otherwise wait for + * enough time to pass before refreshing again. + */ const refreshRequestTime: number = performance.now(); if (refreshRequestTime - this._lastRefreshMs >= this._debounceThresholdMS) { // Enough time has lapsed since the last refresh; refresh immediately diff --git a/src/browser/Types.ts b/src/browser/Types.ts index fa08de2e3..9c76fb07d 100644 --- a/src/browser/Types.ts +++ b/src/browser/Types.ts @@ -201,8 +201,10 @@ export const DEFAULT_ANSI_COLORS = Object.freeze((() => { css.toColor('#eeeeec') ]; - // Fill in the remaining 240 ANSI colors. - // Generate colors (16-231) + /* + * Fill in the remaining 240 ANSI colors. + * Generate colors (16-231) + */ const v = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]; for (let i = 0; i < 216; i++) { const r = v[(i / 36) % 6 | 0]; diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index 3b6ae8301..c629bc7a3 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -99,16 +99,20 @@ export class Viewport extends Disposable { this._register(this._bufferService.onResize(() => this.queueSync())); this._register(this._bufferService.buffers.onBufferActivate(() => { - // Reset _latestYDisp when switching buffers to prevent stale scroll position - // from alt buffer contaminating normal buffer scroll position + /* + * Reset _latestYDisp when switching buffers to prevent stale scroll position + * from alt buffer contaminating normal buffer scroll position + */ this._latestYDisp = undefined; this.queueSync(); })); this._register(this._bufferService.onScroll(() => this._sync())); - // Flush deferred viewport sync after a render completes (e.g. after ESU ends - // synchronized output mode). This ensures DOM scroll position updates atomically - // with the canvas render. + /* + * Flush deferred viewport sync after a render completes (e.g. after ESU ends + * synchronized output mode). This ensures DOM scroll position updates atomically + * with the canvas render. + */ this._register(this._renderService.onRender(() => { if (this._needsSyncOnRender) { this._needsSyncOnRender = false; @@ -173,16 +177,20 @@ export class Viewport extends Disposable { if (!this._renderService || this._isSyncing) { return; } - // Defer DOM scroll updates during synchronized output to prevent visible - // scroll position flickering while the canvas content is frozen. + /* + * Defer DOM scroll updates during synchronized output to prevent visible + * scroll position flickering while the canvas content is frozen. + */ if (this._coreService.decPrivateModes.synchronizedOutput) { this._needsSyncOnRender = true; return; } this._isSyncing = true; - // Ignore any onScroll event that happens as a result of dimensions changing as this should - // never cause a scrollLines call, only setScrollPosition can do that. + /* + * Ignore any onScroll event that happens as a result of dimensions changing as this should + * never cause a scrollLines call, only setScrollPosition can do that. + */ this._suppressOnScrollHandler = true; this._scrollableElement.setScrollDimensions({ height: this._renderService.dimensions.css.canvas.height, @@ -190,8 +198,10 @@ export class Viewport extends Disposable { }); this._suppressOnScrollHandler = false; - // If ydisp has been changed by some other component (input/buffer), then stop animating smooth - // scroll and scroll there immediately. + /* + * If ydisp has been changed by some other component (input/buffer), then stop animating smooth + * scroll and scroll there immediately. + */ if (ydisp !== this._latestYDisp) { this._scrollableElement.setScrollPosition({ scrollTop: ydisp * this._renderService.dimensions.css.cell.height diff --git a/src/browser/decorations/BufferDecorationRenderer.ts b/src/browser/decorations/BufferDecorationRenderer.ts index e374af260..fb4e047a7 100644 --- a/src/browser/decorations/BufferDecorationRenderer.ts +++ b/src/browser/decorations/BufferDecorationRenderer.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import { ICoreBrowserService, IRenderService } from 'browser/services/Services'; import { Disposable, toDisposable } from 'common/Lifecycle'; diff --git a/src/browser/decorations/ColorZoneStore.ts b/src/browser/decorations/ColorZoneStore.ts index d066bedb8..d1795ab8e 100644 --- a/src/browser/decorations/ColorZoneStore.ts +++ b/src/browser/decorations/ColorZoneStore.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import { IInternalDecoration } from 'common/services/Services'; @@ -32,9 +34,11 @@ interface IMinimalDecorationForColorZone { export class ColorZoneStore implements IColorZoneStore { private _zones: IColorZone[] = []; - // The zone pool is used to keep zone objects from being freed between clearing the color zone - // store and fetching the zones. This helps reduce GC pressure since the color zones are - // accumulated on potentially every scroll event. + /* + * The zone pool is used to keep zone objects from being freed between clearing the color zone + * store and fetching the zones. This helps reduce GC pressure since the color zones are + * accumulated on potentially every scroll event. + */ private _zonePool: IColorZone[] = []; private _zonePoolIndex = 0; diff --git a/src/browser/decorations/OverviewRulerRenderer.ts b/src/browser/decorations/OverviewRulerRenderer.ts index b28b25965..8ea3000b3 100644 --- a/src/browser/decorations/OverviewRulerRenderer.ts +++ b/src/browser/decorations/OverviewRulerRenderer.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import { ColorZoneStore, IColorZone, IColorZoneStore } from 'browser/decorations/ColorZoneStore'; import { ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services'; @@ -12,8 +14,10 @@ const enum Constants { OVERVIEW_RULER_BORDER_WIDTH = 1 } -// Helper objects to avoid excessive calculation and garbage collection during rendering. These are -// static values for each render and can be accessed using the decoration position as the key. +/* + * Helper objects to avoid excessive calculation and garbage collection during rendering. These are + * static values for each render and can be accessed using the decoration position as the key. + */ const drawHeight = { full: 0, left: 0, diff --git a/src/browser/input/CompositionHelper.test.ts b/src/browser/input/CompositionHelper.test.ts index 94b5841af..512d5a773 100644 --- a/src/browser/input/CompositionHelper.test.ts +++ b/src/browser/input/CompositionHelper.test.ts @@ -236,9 +236,11 @@ describe('CompositionHelper', () => { it('Should insert middle composition and subsequent input without appending existing trailing text', (done) => { textarea.value = '一二'; - // screenReaderMode keeps textarea content/selection for assistive technologies (eg. screen - // readers), so the caret can be moved within the textarea (eg. via arrow keys) before - // starting composition. + /* + * screenReaderMode keeps textarea content/selection for assistive technologies (eg. screen + * readers), so the caret can be moved within the textarea (eg. via arrow keys) before + * starting composition. + */ textarea.selectionStart = 1; textarea.selectionEnd = 1; diff --git a/src/browser/input/CompositionHelper.ts b/src/browser/input/CompositionHelper.ts index 283874139..f211e2553 100644 --- a/src/browser/input/CompositionHelper.ts +++ b/src/browser/input/CompositionHelper.ts @@ -72,8 +72,10 @@ export class CompositionHelper { */ public compositionstart(): void { this._isComposing = true; - // It's important to use the selection here instead of textarea length to avoid conflicts with - // screen reader mode + /* + * It's important to use the selection here instead of textarea length to avoid conflicts with + * screen reader mode + */ const start = this._textarea.selectionStart ?? this._textarea.value.length; const end = this._textarea.selectionEnd ?? start; this._compositionPosition.start = Math.min(start, end); @@ -89,8 +91,10 @@ export class CompositionHelper { * @param ev The event. */ public compositionupdate(ev: Pick): void { - // Mark text as LTR, direction=rtl is used in CSS so the end of the text is followed for long - // compositions + /* + * Mark text as LTR, direction=rtl is used in CSS so the end of the text is followed for long + * compositions + */ this._compositionView.textContent = `\u200E${ev.data}\u200E`; this.updateCompositionElements(); setTimeout(() => { @@ -115,22 +119,28 @@ export class CompositionHelper { public keydown(ev: KeyboardEvent): boolean { if (this._isComposing || this._isSendingComposition) { if (ev.keyCode === 20 || ev.keyCode === 229) { - // 20 is CapsLock, 229 is Enter - // Continue composing if the keyCode is the "composition character" + /* + * 20 is CapsLock, 229 is Enter + * Continue composing if the keyCode is the "composition character" + */ return false; } if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) { // Continue composing if the keyCode is a modifier key return false; } - // Finish composition immediately. This is mainly here for the case where enter is - // pressed and the handler needs to be triggered before the command is executed. + /* + * Finish composition immediately. This is mainly here for the case where enter is + * pressed and the handler needs to be triggered before the command is executed. + */ this._finalizeComposition(false); } if (ev.keyCode === 229) { - // If the "composition character" is used but gets to this point it means a non-composition - // character (eg. numbers and punctuation) was pressed when the IME was active. + /* + * If the "composition character" is used but gets to this point it means a non-composition + * character (eg. numbers and punctuation) was pressed when the IME was active. + */ this._handleAnyTextareaChanges(); return false; } @@ -156,39 +166,49 @@ export class CompositionHelper { const input = this._textarea.value.substring(this._compositionPosition.start, this._compositionPosition.end); this._coreService.triggerDataEvent(input, true); } else { - // Make a deep copy of the composition position here as a new compositionstart event may - // fire before the setTimeout executes. + /* + * Make a deep copy of the composition position here as a new compositionstart event may + * fire before the setTimeout executes. + */ const currentCompositionPosition = { start: this._compositionPosition.start, end: this._compositionPosition.end }; const currentCompositionSuffix = this._compositionSuffix; - // Since composition* events happen before the changes take place in the textarea on most - // browsers, use a setTimeout with 0ms time to allow the native compositionend event to - // complete. This ensures the correct character is retrieved. - // This solution was used because: - // - The compositionend event's data property is unreliable, at least on Chromium - // - The last compositionupdate event's data property does not always accurately describe - // the character, a counter example being Korean where an ending consonsant can move to - // the following character if the following input is a vowel. + /* + * Since composition* events happen before the changes take place in the textarea on most + * browsers, use a setTimeout with 0ms time to allow the native compositionend event to + * complete. This ensures the correct character is retrieved. + * This solution was used because: + * - The compositionend event's data property is unreliable, at least on Chromium + * - The last compositionupdate event's data property does not always accurately describe + * the character, a counter example being Korean where an ending consonsant can move to + * the following character if the following input is a vowel. + */ this._isSendingComposition = true; setTimeout(() => { // Ensure that the input has not already been sent if (this._isSendingComposition) { this._isSendingComposition = false; let input; - // Add length of data already sent due to keydown event, - // otherwise input characters can be duplicated. (Issue #3191) + /* + * Add length of data already sent due to keydown event, + * otherwise input characters can be duplicated. (Issue #3191) + */ currentCompositionPosition.start += this._dataAlreadySent.length; if (this._isComposing) { - // Use the start position of the new composition to get the string - // if a new composition has started. + /* + * Use the start position of the new composition to get the string + * if a new composition has started. + */ input = this._textarea.value.substring(currentCompositionPosition.start, this._compositionPosition.start); } else { - // Keep support for non-composition characters typed immediately after composition end - // while avoiding re-sending the trailing text that was already present - // before composition started. + /* + * Keep support for non-composition characters typed immediately after composition end + * while avoiding re-sending the trailing text that was already present + * before composition started. + */ const value = this._textarea.value; const valueEnd = currentCompositionSuffix.length > 0 && value.endsWith(currentCompositionSuffix) ? value.length - currentCompositionSuffix.length @@ -260,14 +280,18 @@ export class CompositionHelper { this._compositionView.style.lineHeight = cellHeight + 'px'; this._compositionView.style.fontFamily = this._optionsService.rawOptions.fontFamily; this._compositionView.style.fontSize = this._optionsService.rawOptions.fontSize + 'px'; - // Limit the composition view width to the space between the cursor and - // the terminal's right edge, preventing it from overflowing the terminal. + /* + * Limit the composition view width to the space between the cursor and + * the terminal's right edge, preventing it from overflowing the terminal. + */ const maxWidth = this._bufferService.cols * this._renderService.dimensions.css.cell.width - cursorLeft; this._compositionView.style.maxWidth = maxWidth + 'px'; this._compositionView.style.overflow = 'hidden'; this._compositionView.style.direction = 'rtl'; - // Sync the textarea to the exact position of the composition view so the IME knows where the - // text is. + /* + * Sync the textarea to the exact position of the composition view so the IME knows where the + * text is. + */ const compositionViewBounds = this._compositionView.getBoundingClientRect(); this._textarea.style.left = cursorLeft + 'px'; this._textarea.style.top = cursorTop + 'px'; diff --git a/src/browser/input/Mouse.ts b/src/browser/input/Mouse.ts index c40a7cc78..1094cdcf4 100644 --- a/src/browser/input/Mouse.ts +++ b/src/browser/input/Mouse.ts @@ -44,9 +44,11 @@ export function getCoords(window: Pick, event: Pick< coords[0] = Math.ceil((coords[0] + (isSelection ? cssCellWidth / 2 : 0)) / cssCellWidth); coords[1] = Math.ceil(coords[1] / cssCellHeight); - // Ensure coordinates are within the terminal viewport. Note that selections - // need an addition point of precision to cover the end point (as characters - // cover half of one char and half of the next). + /* + * Ensure coordinates are within the terminal viewport. Note that selections + * need an addition point of precision to cover the end point (as characters + * cover half of one char and half of the next). + */ coords[0] = Math.min(Math.max(coords[0], 1), colCount + (isSelection ? 1 : 0)); coords[1] = Math.min(Math.max(coords[1], 1), rowCount); diff --git a/src/browser/public/Terminal.ts b/src/browser/public/Terminal.ts index 75aada048..9255f67f2 100644 --- a/src/browser/public/Terminal.ts +++ b/src/browser/public/Terminal.ts @@ -54,9 +54,11 @@ export class Terminal extends Disposable implements ITerminalApi { } private _checkReadonlyOptions(propName: string): void { - // Throw an error if any constructor only option is modified - // from terminal.options - // Modifications from anywhere else are allowed + /* + * Throw an error if any constructor only option is modified + * from terminal.options + * Modifications from anywhere else are allowed + */ if (CONSTRUCTOR_ONLY_OPTIONS.includes(propName)) { throw new Error(`Option "${propName}" can only be set in the constructor`); } diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index 6f873af7b..943906524 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -114,8 +114,10 @@ export class DomRenderer extends Disposable implements IRenderer { this._register(toDisposable(() => { this._element.classList.remove(Constants.TERMINAL_CLASS_PREFIX + this._terminalClass); - // Outside influences such as React unmounts may manipulate the DOM before our disposal. - // https://github.com/xtermjs/xterm.js/issues/2960 + /* + * Outside influences such as React unmounts may manipulate the DOM before our disposal. + * https://github.com/xtermjs/xterm.js/issues/2960 + */ this._rowContainer.remove(); this._selectionContainer.remove(); this._widthCache.dispose(); @@ -184,9 +186,11 @@ export class DomRenderer extends Disposable implements IRenderer { // Base CSS let styles = `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS} {` + - // Disabling pointer events circumvents a browser behavior that prevents `click` events from - // being delivered if the target element is replaced during the click. This happened due to - // refresh() being called during the mousedown handler to start a selection. + /* + * Disabling pointer events circumvents a browser behavior that prevents `click` events from + * being delivered if the target element is replaced during the click. This happened due to + * refresh() being called during the mousedown handler to start a selection. + */ ` pointer-events: none;` + ` color: ${colors.foreground.css};` + `}`; @@ -257,9 +261,11 @@ export class DomRenderer extends Disposable implements IRenderer { `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS}.${Constants.CURSOR_BLINK_IDLE_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS} {` + ` animation: none !important;` + `}` + - // !important helps fix an issue where the cursor will not render on top of the selection, - // however it's very hard to fix this issue and retain the blink animation without the use of - // !important. So this edge case fails when cursor blink is on. + /* + * !important helps fix an issue where the cursor will not render on top of the selection, + * however it's very hard to fix this issue and retain the blink animation without the use of + * !important. So this edge case fails when cursor blink is on. + */ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` + ` background-color: ${colors.cursor.css};` + ` color: ${colors.cursorAccent.css};` + diff --git a/src/browser/renderer/dom/DomRendererRowFactory.test.ts b/src/browser/renderer/dom/DomRendererRowFactory.test.ts index 6ca84569a..4bd5b8e7b 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.test.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.test.ts @@ -359,8 +359,10 @@ describe('DomRendererRowFactory', () => { }); describe('createRow with merged spans', () => { - // for test purpose assume all in codepoints 0..255 are merging - // const ALL_MERGING = new Uint8Array(FontMetrics.MAX); + /* + * for test purpose assume all in codepoints 0..255 are merging + * const ALL_MERGING = new Uint8Array(FontMetrics.MAX); + */ beforeEach(() => { lineData = createEmptyLineData(10); diff --git a/src/browser/renderer/dom/DomRendererRowFactory.ts b/src/browser/renderer/dom/DomRendererRowFactory.ts index 0cff9c25f..fc03e27b3 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.ts @@ -115,20 +115,26 @@ export class DomRendererRowFactory { // If true, indicates that the current character(s) to draw were joined. let isJoined = false; - // Indicates whether this cell is part of a joined range that should be ignored as it cannot - // be rendered entirely, like the selection state differs across the range. + /* + * Indicates whether this cell is part of a joined range that should be ignored as it cannot + * be rendered entirely, like the selection state differs across the range. + */ let isValidJoinRange = (x >= skipJoinedCheckUntilX); let lastCharX = x; - // Process any joined character ranges as needed. Because of how the - // ranges are produced, we know that they are valid for the characters - // and attributes of our input. + /* + * Process any joined character ranges as needed. Because of how the + * ranges are produced, we know that they are valid for the characters + * and attributes of our input. + */ let cell: ICellData = this._workCell; if (joinedRanges.length > 0 && x === joinedRanges[0][0] && isValidJoinRange) { const range = joinedRanges.shift()!; - // If the ligature's selection state is not consistent, don't join it. This helps the - // selection render correctly regardless whether they should be joined. + /* + * If the ligature's selection state is not consistent, don't join it. This helps the + * selection render correctly regardless whether they should be joined. + */ const firstSelectionState = this._isCellInSelection(range[0], row); for (i = range[0] + 1; i < range[1]; i++) { isValidJoinRange &&= (firstSelectionState === this._isCellInSelection(i, row)); @@ -140,8 +146,10 @@ export class DomRendererRowFactory { } else { isJoined = true; - // We already know the exact start and end column of the joined range, - // so we get the string and width representing it directly + /* + * We already know the exact start and end column of the joined range, + * so we get the string and width representing it directly + */ cell = new JoinedCellData( this._workCell, lineData.translateToString(true, range[0], range[1]), @@ -243,9 +251,11 @@ export class DomRendererRowFactory { oldIsInSelection = isInSelection; if (isJoined) { - // The DOM renderer colors the background of the cursor but for ligatures all cells are - // joined. The workaround here is to show a cursor around the whole ligature so it shows up, - // the cursor looks the same when on any character of the ligature though + /* + * The DOM renderer colors the background of the cursor but for ligatures all cells are + * joined. The workaround here is to show a cursor around the whole ligature so it shows up, + * the cursor looks the same when on any character of the ligature though + */ if (cursorX >= x && cursorX <= lastCharX) { cursorX = x; } @@ -333,8 +343,10 @@ export class DomRendererRowFactory { classes.push(RowCss.STRIKETHROUGH_CLASS); } - // apply link hover underline late, effectively overrides any previous text-decoration - // settings + /* + * apply link hover underline late, effectively overrides any previous text-decoration + * settings + */ if (isLinkHover) { charElement.style.textDecoration = 'underline'; } @@ -353,8 +365,10 @@ export class DomRendererRowFactory { bgColorMode = temp2; } - // Apply any decoration foreground/background overrides, this must happen after inverse has - // been applied + /* + * Apply any decoration foreground/background overrides, this must happen after inverse has + * been applied + */ let bgOverride: IColor | undefined; let fgOverride: IColor | undefined; let isTop = false; @@ -377,15 +391,19 @@ export class DomRendererRowFactory { // Apply selection if (!isTop && isInSelection) { - // If in the selection, force the element to be above the selection to improve contrast and - // support opaque selections. The applies background is not actually needed here as - // selection is drawn in a seperate container, the main purpose of this to ensuring minimum - // contrast ratio + /* + * If in the selection, force the element to be above the selection to improve contrast and + * support opaque selections. The applies background is not actually needed here as + * selection is drawn in a seperate container, the main purpose of this to ensuring minimum + * contrast ratio + */ bgOverride = this._coreBrowserService.isFocused ? colors.selectionBackgroundOpaque : colors.selectionInactiveBackgroundOpaque; bg = bgOverride.rgba >> 8 & 0xFFFFFF; bgColorMode = Attributes.CM_RGB; - // Since an opaque selection is being rendered, the selection pretends to be a decoration to - // ensure text is drawn above the selection. + /* + * Since an opaque selection is being rendered, the selection pretends to be a decoration to + * ensure text is drawn above the selection. + */ isTop = true; // Apply selection foreground if applicable if (colors.selectionForeground) { @@ -459,9 +477,11 @@ export class DomRendererRowFactory { } } - // apply CSS classes - // slightly faster than using classList by omitting - // checks for doubled entries (code above should not have doublets) + /* + * apply CSS classes + * slightly faster than using classList by omitting + * checks for doubled entries (code above should not have doublets) + */ if (classes.length) { charElement.className = classes.join(' '); classes.length = 0; @@ -504,8 +524,10 @@ export class DomRendererRowFactory { // Calculate and store in cache if (adjustedColor === undefined) { - // Dim cells only require half the contrast, otherwise they wouldn't be distinguishable from - // non-dim cells + /* + * Dim cells only require half the contrast, otherwise they wouldn't be distinguishable from + * non-dim cells + */ const ratio = this._optionsService.rawOptions.minimumContrastRatio / (cell.isDim() ? 2 : 1); adjustedColor = color.ensureContrastRatio(bgOverride ?? bg, fgOverride ?? fg, ratio); cache.setColor((bgOverride ?? bg).rgba, (fgOverride ?? fg).rgba, adjustedColor ?? null); diff --git a/src/browser/renderer/dom/WidthCache.ts b/src/browser/renderer/dom/WidthCache.ts index b598bbd6f..1bf66204d 100644 --- a/src/browser/renderer/dom/WidthCache.ts +++ b/src/browser/renderer/dom/WidthCache.ts @@ -31,16 +31,20 @@ export interface IWidthCacheFontVariantCanvas { } export class WidthCache implements IDisposable { - // flat cache for regular variant up to CacheSettings.FLAT_SIZE - // NOTE: ~4x faster access than holey (serving >>80% of terminal content) - // It has a small memory footprint (only 1MB for full BMP caching), - // still the sweet spot is not reached before touching 32k different codepoints, - // thus we store the remaining <<20% of terminal data in a holey structure. + /* + * flat cache for regular variant up to CacheSettings.FLAT_SIZE + * NOTE: ~4x faster access than holey (serving >>80% of terminal content) + * It has a small memory footprint (only 1MB for full BMP caching), + * still the sweet spot is not reached before touching 32k different codepoints, + * thus we store the remaining <<20% of terminal data in a holey structure. + */ protected _flat = new Float32Array(WidthCacheSettings.FLAT_SIZE); - // holey cache for bold, italic and bold&italic for any string - // FIXME: can grow really big over time (~8.5 MB for full BMP caching), - // so a shared API across terminals is needed + /* + * holey cache for bold, italic and bold&italic for any string + * FIXME: can grow really big over time (~8.5 MB for full BMP caching), + * so a shared API across terminals is needed + */ protected _holey: Map | undefined; private _font = ''; diff --git a/src/browser/renderer/shared/RendererUtils.test.ts b/src/browser/renderer/shared/RendererUtils.test.ts index 4512cb6d9..87f6a3f20 100644 --- a/src/browser/renderer/shared/RendererUtils.test.ts +++ b/src/browser/renderer/shared/RendererUtils.test.ts @@ -13,8 +13,10 @@ describe('RendererUtils', () => { let line = 1; let variantOffset = 0; - // should line 1 - // =,_,=_,=_, + /* + * should line 1 + * =,_,=_,=_, + */ let cells = [cellWidth, cellWidth, doubleCellWidth, doubleCellWidth]; let result = [1, 0, 0, 0]; for (let index = 0; index < cells.length; index++) { @@ -23,8 +25,10 @@ describe('RendererUtils', () => { assert.equal(variantOffset, result[index]); } - // should line 2 - // ==__==__==_,_==__==__==,__==__==__==__==__==__,==__==__==__==__==__==, + /* + * should line 2 + * ==__==__==_,_==__==__==,__==__==__==__==__==__,==__==__==__==__==__==, + */ line = 2; variantOffset = 0; cells = [cellWidth, cellWidth, doubleCellWidth, doubleCellWidth]; @@ -35,8 +39,10 @@ describe('RendererUtils', () => { assert.equal(variantOffset, result[index]); } - // should line 3 - // ===___===__,_===___===_,__===___===___===___==,=___===___===___===___, + /* + * should line 3 + * ===___===__,_===___===_,__===___===___===___==,=___===___===___===___, + */ line = 3; variantOffset = 0; cells = [cellWidth, cellWidth, doubleCellWidth, doubleCellWidth]; diff --git a/src/browser/renderer/shared/RendererUtils.ts b/src/browser/renderer/shared/RendererUtils.ts index 010643648..30925f32f 100644 --- a/src/browser/renderer/shared/RendererUtils.ts +++ b/src/browser/renderer/shared/RendererUtils.ts @@ -13,9 +13,11 @@ export function throwIfFalsy(value: T | undefined | null): T { } export function isPowerlineGlyph(codepoint: number): boolean { - // Only return true for Powerline symbols which require - // different padding and should be excluded from minimum contrast - // ratio standards + /* + * Only return true for Powerline symbols which require + * different padding and should be excluded from minimum contrast + * ratio standards + */ return 0xE0A4 <= codepoint && codepoint <= 0xE0D6; } @@ -48,8 +50,10 @@ export function allowRescaling(codepoint: number | undefined, width: number, gly return ( // Is single cell width width === 1 && - // Glyph exceeds cell bounds, add 50% to avoid hurting readability by rescaling glyphs that - // barely overlap + /* + * Glyph exceeds cell bounds, add 50% to avoid hurting readability by rescaling glyphs that + * barely overlap + */ glyphSizeX > Math.ceil(deviceCellWidth * 1.5) && // Never rescale ascii codepoint !== undefined && codepoint > 0xFF && diff --git a/src/browser/scrollable/abstractScrollbar.ts b/src/browser/scrollable/abstractScrollbar.ts index 64c25d9d8..0463471b5 100644 --- a/src/browser/scrollable/abstractScrollbar.ts +++ b/src/browser/scrollable/abstractScrollbar.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import * as dom from '../Dom'; import { FastDomNode } from './fastDomNode'; diff --git a/src/browser/scrollable/fastDomNode.ts b/src/browser/scrollable/fastDomNode.ts index 1a795c2be..206416677 100644 --- a/src/browser/scrollable/fastDomNode.ts +++ b/src/browser/scrollable/fastDomNode.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ export class FastDomNode { diff --git a/src/browser/scrollable/globalPointerMoveMonitor.ts b/src/browser/scrollable/globalPointerMoveMonitor.ts index a80e0507f..b2e9b588a 100644 --- a/src/browser/scrollable/globalPointerMoveMonitor.ts +++ b/src/browser/scrollable/globalPointerMoveMonitor.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import * as dom from '../Dom'; import { DisposableStore, IDisposable, toDisposable } from 'common/Lifecycle'; diff --git a/src/browser/scrollable/horizontalScrollbar.ts b/src/browser/scrollable/horizontalScrollbar.ts index 299a3e473..8e48ea7ff 100644 --- a/src/browser/scrollable/horizontalScrollbar.ts +++ b/src/browser/scrollable/horizontalScrollbar.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import { AbstractScrollbar, ISimplifiedPointerEvent, IScrollbarHost } from './abstractScrollbar'; import { IScrollableElementResolvedOptions } from './scrollableElementOptions'; diff --git a/src/browser/scrollable/mouseEvent.ts b/src/browser/scrollable/mouseEvent.ts index a12b63d52..482ba82aa 100644 --- a/src/browser/scrollable/mouseEvent.ts +++ b/src/browser/scrollable/mouseEvent.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import * as platform from 'common/Platform'; diff --git a/src/browser/scrollable/scrollable.ts b/src/browser/scrollable/scrollable.ts index 18275ffe5..9f8cbb6f7 100644 --- a/src/browser/scrollable/scrollable.ts +++ b/src/browser/scrollable/scrollable.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import { Emitter, IEvent } from 'common/Event'; import { Disposable, IDisposable } from 'common/Lifecycle'; diff --git a/src/browser/scrollable/scrollableElement.ts b/src/browser/scrollable/scrollableElement.ts index 4039d0c4e..a41dde991 100644 --- a/src/browser/scrollable/scrollableElement.ts +++ b/src/browser/scrollable/scrollableElement.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import * as dom from '../Dom'; import { FastDomNode } from './fastDomNode'; diff --git a/src/browser/scrollable/scrollableElementOptions.ts b/src/browser/scrollable/scrollableElementOptions.ts index 037cd5c11..0e1d06226 100644 --- a/src/browser/scrollable/scrollableElementOptions.ts +++ b/src/browser/scrollable/scrollableElementOptions.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import { ScrollbarVisibility } from './scrollable'; diff --git a/src/browser/scrollable/scrollbarArrow.ts b/src/browser/scrollable/scrollbarArrow.ts index d543669c1..5784dc8dc 100644 --- a/src/browser/scrollable/scrollbarArrow.ts +++ b/src/browser/scrollable/scrollbarArrow.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import { GlobalPointerMoveMonitor } from './globalPointerMoveMonitor'; import { Widget } from './widget'; diff --git a/src/browser/scrollable/scrollbarState.ts b/src/browser/scrollable/scrollbarState.ts index f9129f1b0..7b7751f97 100644 --- a/src/browser/scrollable/scrollbarState.ts +++ b/src/browser/scrollable/scrollbarState.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ /** * The minimal size of the slider (such that it can still be clickable). diff --git a/src/browser/scrollable/scrollbarVisibilityController.ts b/src/browser/scrollable/scrollbarVisibilityController.ts index 59d172bce..b56e3524f 100644 --- a/src/browser/scrollable/scrollbarVisibilityController.ts +++ b/src/browser/scrollable/scrollbarVisibilityController.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import { FastDomNode } from './fastDomNode'; import { TimeoutTimer } from 'common/Async'; diff --git a/src/browser/scrollable/touch.ts b/src/browser/scrollable/touch.ts index 8ffdfe699..a734a79a1 100644 --- a/src/browser/scrollable/touch.ts +++ b/src/browser/scrollable/touch.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import * as DomUtils from '../Dom'; import { Disposable, IDisposable, toDisposable } from 'common/Lifecycle'; diff --git a/src/browser/scrollable/verticalScrollbar.ts b/src/browser/scrollable/verticalScrollbar.ts index 615f443a0..9f5a090af 100644 --- a/src/browser/scrollable/verticalScrollbar.ts +++ b/src/browser/scrollable/verticalScrollbar.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import { AbstractScrollbar, ISimplifiedPointerEvent, IScrollbarHost } from './abstractScrollbar'; import { IScrollableElementResolvedOptions } from './scrollableElementOptions'; diff --git a/src/browser/scrollable/widget.ts b/src/browser/scrollable/widget.ts index 80220c9b1..eae4ec185 100644 --- a/src/browser/scrollable/widget.ts +++ b/src/browser/scrollable/widget.ts @@ -1,7 +1,9 @@ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import * as dom from '../Dom'; import { IMouseEvent, StandardMouseEvent } from './mouseEvent'; diff --git a/src/browser/services/CharSizeService.ts b/src/browser/services/CharSizeService.ts index 6baf9b50a..8d97f233c 100644 --- a/src/browser/services/CharSizeService.ts +++ b/src/browser/services/CharSizeService.ts @@ -61,8 +61,10 @@ abstract class BaseMeasureStategy extends Disposable implements IMeasureStrategy protected _result: IMeasureResult = { width: 0, height: 0 }; protected _validateAndSet(width: number | undefined, height: number | undefined): void { - // If values are 0 then the element is likely currently display:none, in which case we should - // retain the previous value. + /* + * If values are 0 then the element is likely currently display:none, in which case we should + * retain the previous value. + */ if (width !== undefined && width > 0 && height !== undefined && height > 0) { this._result.width = width; this._result.height = height; diff --git a/src/browser/services/CharacterJoinerService.ts b/src/browser/services/CharacterJoinerService.ts index ca4f1984e..d0ded2623 100644 --- a/src/browser/services/CharacterJoinerService.ts +++ b/src/browser/services/CharacterJoinerService.ts @@ -13,8 +13,10 @@ import { ICharacterJoinerService } from 'browser/services/Services'; export class JoinedCellData extends AttributeData implements ICellData { private _width: number; - // .content carries no meaning for joined CellData, simply nullify it - // thus we have to overload all other .content accessors + /* + * .content carries no meaning for joined CellData, simply nullify it + * thus we have to overload all other .content accessors + */ public content: number = 0; public fg: number; public bg: number; @@ -42,8 +44,10 @@ export class JoinedCellData extends AttributeData implements ICellData { } public getCode(): number { - // code always gets the highest possible fake codepoint (read as -1) - // this is needed as code is used by caches as identifier + /* + * code always gets the highest possible fake codepoint (read as -1) + * this is needed as code is used by caches as identifier + */ return 0x1FFFFF; } @@ -101,10 +105,12 @@ export class CharacterJoinerService implements ICharacterJoinerService { const ranges: [number, number][] = []; const lineStr = line.translateToString(true); - // Because some cells can be represented by multiple javascript characters, - // we track the cell and the string indexes separately. This allows us to - // translate the string ranges we get from the joiners back into cell ranges - // for use when rendering + /* + * Because some cells can be represented by multiple javascript characters, + * we track the cell and the string indexes separately. This allows us to + * translate the string ranges we get from the joiners back into cell ranges + * for use when rendering + */ let rangeStartColumn = 0; let currentStringIndex = 0; let rangeStartStringIndex = 0; @@ -121,8 +127,10 @@ export class CharacterJoinerService implements ICharacterJoinerService { // End of range if (this._workCell.fg !== rangeAttrFG || this._workCell.bg !== rangeAttrBG) { - // If we ended up with a sequence of more than one character, - // look for ranges to join. + /* + * If we ended up with a sequence of more than one character, + * look for ranges to join. + */ if (x - rangeStartColumn > 1) { const joinedRanges = this._getJoinedRanges( lineStr, @@ -173,9 +181,11 @@ export class CharacterJoinerService implements ICharacterJoinerService { */ private _getJoinedRanges(line: string, startIndex: number, endIndex: number, lineData: IBufferLine, startCol: number): [number, number][] { const text = line.substring(startIndex, endIndex); - // At this point we already know that there is at least one joiner so - // we can just pull its value and assign it directly rather than - // merging it into an empty array, which incurs unnecessary writes. + /* + * At this point we already know that there is at least one joiner so + * we can just pull its value and assign it directly rather than + * merging it into an empty array, which incurs unnecessary writes. + */ let allJoinedRanges: [number, number][] = []; try { allJoinedRanges = this._characterJoiners[0].handler(text); @@ -220,8 +230,10 @@ export class CharacterJoinerService implements ICharacterJoinerService { const width = line.getWidth(x); const length = line.getString(x).length || WHITESPACE_CELL_CHAR.length; - // We skip zero-width characters when creating the string to join the text - // so we do the same here + /* + * We skip zero-width characters when creating the string to join the text + * so we do the same here + */ if (width === 0) { continue; } @@ -244,10 +256,12 @@ export class CharacterJoinerService implements ICharacterJoinerService { break; } - // Ranges can be on adjacent characters. Because the end index of the - // ranges are exclusive, this means that the index for the start of a - // range can be the same as the end index of the previous range. To - // account for the start of the next range, we check here just in case. + /* + * Ranges can be on adjacent characters. Because the end index of the + * ranges are exclusive, this means that the index for the start of a + * range can be the same as the end index of the previous range. To + * account for the start of the next range, we check here just in case. + */ if (currentRange[0] <= currentStringIndex) { currentRange[0] = x; currentRangeStarted = true; @@ -256,13 +270,17 @@ export class CharacterJoinerService implements ICharacterJoinerService { } } - // Adjust the string index based on the character length to line up with - // the column adjustment + /* + * Adjust the string index based on the character length to line up with + * the column adjustment + */ currentStringIndex += length; } - // If there is still a range left at the end, it must extend all the way to - // the end of the line. + /* + * If there is still a range left at the end, it must extend all the way to + * the end of the line. + */ if (currentRange) { currentRange[1] = this._bufferService.cols; } @@ -288,15 +306,19 @@ export class CharacterJoinerService implements ICharacterJoinerService { } if (newRange[1] <= range[1]) { - // Case 2: New range is either wholly contained within the - // search range or overlaps with the front of it + /* + * Case 2: New range is either wholly contained within the + * search range or overlaps with the front of it + */ range[0] = Math.min(newRange[0], range[0]); return ranges; } if (newRange[0] < range[1]) { - // Case 3: New range either wholly contains the search range - // or overlaps with the end of it + /* + * Case 3: New range either wholly contains the search range + * or overlaps with the end of it + */ range[0] = Math.min(newRange[0], range[0]); inRange = true; } @@ -305,22 +327,28 @@ export class CharacterJoinerService implements ICharacterJoinerService { continue; } else { if (newRange[1] <= range[0]) { - // Case 5: New range extends from previous range but doesn't - // reach the current one + /* + * Case 5: New range extends from previous range but doesn't + * reach the current one + */ ranges[i - 1][1] = newRange[1]; return ranges; } if (newRange[1] <= range[1]) { - // Case 6: New range extends from prvious range into the - // current range + /* + * Case 6: New range extends from prvious range into the + * current range + */ ranges[i - 1][1] = Math.max(newRange[1], range[1]); ranges.splice(i, 1); return ranges; } - // Case 7: New range extends from previous range past the - // end of the current range + /* + * Case 7: New range extends from previous range past the + * end of the current range + */ ranges.splice(i, 1); i--; } diff --git a/src/browser/services/MouseService.test.ts b/src/browser/services/MouseService.test.ts index f395083e3..63e14954a 100644 --- a/src/browser/services/MouseService.test.ts +++ b/src/browser/services/MouseService.test.ts @@ -127,8 +127,10 @@ describe('MouseService _triggerMouseEvent', () => { assert.equal(trigger({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.RIGHT, action: CoreMouseAction.DOWN }), true); assert.equal(trigger({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.WHEEL, action: CoreMouseAction.UP }), true); assert.equal(trigger({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE }), true); - // should not report in any case - // invalid button + action combinations + /* + * should not report in any case + * invalid button + action combinations + */ assert.equal(trigger({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.WHEEL, action: CoreMouseAction.MOVE }), false); assert.equal(trigger({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.DOWN }), false); assert.equal(trigger({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.UP }), false); diff --git a/src/browser/services/MouseService.ts b/src/browser/services/MouseService.ts index d701796c2..2f35957b7 100644 --- a/src/browser/services/MouseService.ts +++ b/src/browser/services/MouseService.ts @@ -147,8 +147,10 @@ export class MouseService implements IMouseService { return false; } - // exit if we cannot determine valid button/action values - // do nothing for higher buttons than wheel + /* + * exit if we cannot determine valid button/action values + * do nothing for higher buttons than wheel + */ if (action === undefined || but === undefined || but > CoreMouseButton.WHEEL) { return false; } @@ -204,19 +206,23 @@ export class MouseService implements IMouseService { ev.preventDefault(); ctx.focus(); - // Don't send the mouse button to the pty if mouse events are disabled or - // if the selection manager is having selection forced (ie. a modifier is - // held). + /* + * Don't send the mouse button to the pty if mouse events are disabled or + * if the selection manager is having selection forced (ie. a modifier is + * held). + */ if (!this._mouseStateService.areMouseEventsActive || this._selectionService.shouldForceSelection(ev)) { return; } this._sendEvent(ctx, ev); - // Register additional global handlers which should keep reporting outside - // of the terminal element. - // Note: Other emulators also do this for 'mousedown' while a button - // is held, we currently limit 'mousedown' to the terminal only. + /* + * Register additional global handlers which should keep reporting outside + * of the terminal element. + * Note: Other emulators also do this for 'mousedown' while a button + * is held, we currently limit 'mousedown' to the terminal only. + */ if (ctx.requestedEvents.mouseup) { ctx.target.document.addEventListener('mouseup', ctx.requestedEvents.mouseup); } @@ -236,12 +242,14 @@ export class MouseService implements IMouseService { } if (!this._bufferService.buffer.hasScrollback) { - // Convert wheel events into up/down events when the buffer does not have scrollback, this - // enables scrolling in apps hosted in the alt buffer such as vim or tmux even when mouse - // events are not enabled. - // This used implementation used get the actual lines/partial lines scrolled from the - // viewport but since moving to the new viewport implementation has been simplified to - // simply send a single up or down sequence. + /* + * Convert wheel events into up/down events when the buffer does not have scrollback, this + * enables scrolling in apps hosted in the alt buffer such as vim or tmux even when mouse + * events are not enabled. + * This used implementation used get the actual lines/partial lines scrolled from the + * viewport but since moving to the new viewport implementation has been simplified to + * simply send a single up or down sequence. + */ // Do nothing if there's no vertical scroll const deltaY = ev.deltaY; diff --git a/src/browser/services/RenderService.ts b/src/browser/services/RenderService.ts index e999b7eac..433a24eb5 100644 --- a/src/browser/services/RenderService.ts +++ b/src/browser/services/RenderService.ts @@ -88,9 +88,11 @@ export class RenderService extends Disposable implements IRenderService { this._register(this._optionsService.onOptionChange(() => this._handleOptionsChanged())); this._register(this._charSizeService.onCharSizeChange(() => this.handleCharSizeChanged())); - // Do a full refresh whenever any decoration is added or removed. This may not actually result - // in changes but since decorations should be used sparingly or added/removed all in the same - // frame this should have minimal performance impact. + /* + * Do a full refresh whenever any decoration is added or removed. This may not actually result + * in changes but since decorations should be used sparingly or added/removed all in the same + * frame this should have minimal performance impact. + */ this._register(decorationService.onDecorationRegistered(() => this._fullRefresh())); this._register(decorationService.onDecorationRemoved(() => this._fullRefresh())); @@ -124,8 +126,10 @@ export class RenderService extends Disposable implements IRenderService { } private _registerIntersectionObserver(w: Window & typeof globalThis, screenElement: HTMLElement): void { - // Detect whether IntersectionObserver is detected and enable renderer pause - // and resume based on terminal visibility if so + /* + * Detect whether IntersectionObserver is detected and enable renderer pause + * and resume based on terminal visibility if so + */ if ('IntersectionObserver' in w) { const observer = new w.IntersectionObserver(e => this._handleIntersectionChange(e[e.length - 1]), { threshold: 0 }); this._observerDisposable.value = toDisposable(() => { @@ -186,16 +190,20 @@ export class RenderService extends Disposable implements IRenderService { return; } - // Skip rendering if synchronized output mode is enabled. This check must happen here - // (in addition to refreshRows) to handle renders that were queued before the mode was enabled. + /* + * Skip rendering if synchronized output mode is enabled. This check must happen here + * (in addition to refreshRows) to handle renders that were queued before the mode was enabled. + */ if (this._coreService.decPrivateModes.synchronizedOutput) { this._syncOutputHandler.bufferRows(start, end); return; } - // Since this is debounced, a resize event could have happened between the time a refresh was - // requested and when this triggers. Clamp the values of start and end to ensure they're valid - // given the current viewport state. + /* + * Since this is debounced, a resize event could have happened between the time a refresh was + * requested and when this triggers. Clamp the values of start and end to ensure they're valid + * given the current viewport state. + */ start = Math.min(start, this._rowCount - 1); end = Math.min(end, this._rowCount - 1); @@ -277,8 +285,10 @@ export class RenderService extends Disposable implements IRenderService { } public handleDevicePixelRatioChange(): void { - // Force char size measurement as DomMeasureStrategy(getBoundingClientRect) is not stable - // when devicePixelRatio changes + /* + * Force char size measurement as DomMeasureStrategy(getBoundingClientRect) is not stable + * when devicePixelRatio changes + */ this._charSizeService.measure(); if (!this._renderer.value) { diff --git a/src/browser/services/SelectionService.test.ts b/src/browser/services/SelectionService.test.ts index be62ccc6b..822bb6b6d 100644 --- a/src/browser/services/SelectionService.test.ts +++ b/src/browser/services/SelectionService.test.ts @@ -257,8 +257,10 @@ describe('SelectionService', () => { ])); // The a is here to prevent the space being trimmed in selectionText selectionService.selectWordAt([0, 0]); assert.equal(selectionService.selectionText, ' '); - // ZWJ emojis do not combine in the terminal so the family emoji used here consumed 4 cells - // The selection text should retain ZWJ chars despite not combining on the terminal + /* + * ZWJ emojis do not combine in the terminal so the family emoji used here consumed 4 cells + * The selection text should retain ZWJ chars despite not combining on the terminal + */ selectionService.selectWordAt([1, 0]); assert.equal(selectionService.selectionText, '👨‍👩‍👧‍👦'); selectionService.selectWordAt([2, 0]); @@ -473,8 +475,10 @@ describe('SelectionService', () => { }); it('should select a column of text with double character emojis', () => { - // TODO the case this is testing works for me in the demo webapp, - // but doing it programmatically fails. + /* + * TODO the case this is testing works for me in the demo webapp, + * but doing it programmatically fails. + */ buffer.lines.length = 3; buffer.lines.set(0, stringToRow('a ')); buffer.lines.set(1, stringArrayToRow(['😁', ' '])); diff --git a/src/browser/services/SelectionService.ts b/src/browser/services/SelectionService.ts index 39692a871..29ed1b827 100644 --- a/src/browser/services/SelectionService.ts +++ b/src/browser/services/SelectionService.ts @@ -152,8 +152,10 @@ export class SelectionService extends Disposable implements ISelectionService { this._removeMouseDownListeners(); })); - // Clear selection when resizing vertically. This experience could be improved, this is the - // simple option to fix the buggy behavior. https://github.com/xtermjs/xterm.js/issues/5300 + /* + * Clear selection when resizing vertically. This experience could be improved, this is the + * simple option to fix the buggy behavior. https://github.com/xtermjs/xterm.js/issues/5300 + */ this._register(this._bufferService.onResize(e => { if (e.rowsChanged) { this.clearSelection(); @@ -215,8 +217,10 @@ export class SelectionService extends Disposable implements ISelectionService { return ''; } - // For column selection it's not enough to rely on final selection's swapping of reversed - // values, it also needs the x coordinates to swap independently of the y coordinate is needed + /* + * For column selection it's not enough to rely on final selection's swapping of reversed + * values, it also needs the x coordinates to swap independently of the y coordinate is needed + */ const startCol = start[0] < end[0] ? start[0] : end[0]; const endCol = start[0] < end[0] ? end[0] : start[0]; for (let i = start[1]; i <= end[1]; i++) { @@ -251,8 +255,10 @@ export class SelectionService extends Disposable implements ISelectionService { } } - // Format string by replacing non-breaking space chars with regular spaces - // and joining the array into a multi-line string. + /* + * Format string by replacing non-breaking space chars with regular spaces + * and joining the array into a multi-line string. + */ const formattedResult = result.map(line => { return line.replace(ALL_NON_BREAKING_SPACE_REGEX, ' '); }).join(Browser.isWindows ? '\r\n' : '\n'); @@ -281,8 +287,10 @@ export class SelectionService extends Disposable implements ISelectionService { this._refreshAnimationFrame = this._coreBrowserService.window.requestAnimationFrame(() => this._refresh()); } - // If the platform is Linux and the refresh call comes from a mouse event, - // we need to update the selection for middle click to paste selection. + /* + * If the platform is Linux and the refresh call comes from a mouse event, + * we need to update the selection for middle click to paste selection. + */ if (Browser.isLinux && isLinuxMouseSelection) { const selectionText = this.selectionText; if (selectionText.length) { @@ -447,8 +455,10 @@ export class SelectionService extends Disposable implements ISelectionService { */ public handleMouseDown(event: MouseEvent): void { this._mouseDownTimeStamp = event.timeStamp; - // If we have selection, we want the context menu on right click even if the - // terminal is in mouse mode. + /* + * If we have selection, we want the context menu on right click even if the + * terminal is in mouse mode. + */ if (event.button === 2 && this.hasSelection) { return; } @@ -561,8 +571,10 @@ export class SelectionService extends Disposable implements ISelectionService { return; } - // If the mouse is over the second half of a wide character, adjust the - // selection to cover the whole character + /* + * If the mouse is over the second half of a wide character, adjust the + * selection to cover the whole character + */ if (line.hasWidth(this._model.selectionStart[0]) === 0) { this._model.selectionStart[0]++; } @@ -605,19 +617,25 @@ export class SelectionService extends Disposable implements ISelectionService { * @param event The mousemove event. */ private _handleMouseMove(event: MouseEvent): void { - // If the mousemove listener is active it means that a selection is - // currently being made, we should stop propagation to prevent mouse events - // to be sent to the pty. + /* + * If the mousemove listener is active it means that a selection is + * currently being made, we should stop propagation to prevent mouse events + * to be sent to the pty. + */ event.stopImmediatePropagation(); - // Do nothing if there is no selection start, this can happen if the first - // click in the terminal is an incremental click + /* + * Do nothing if there is no selection start, this can happen if the first + * click in the terminal is an incremental click + */ if (!this._model.selectionStart) { return; } - // Record the previous position so we know whether to redraw the selection - // at the end. + /* + * Record the previous position so we know whether to redraw the selection + * at the end. + */ const previousSelectionEnd = this._model.selectionEnd ? [this._model.selectionEnd[0], this._model.selectionEnd[1]] : null; // Set the initial selection end based on the mouse coordinates @@ -641,9 +659,11 @@ export class SelectionService extends Disposable implements ISelectionService { // Determine the amount of scrolling that will happen. this._dragScrollAmount = this._getMouseEventScrollAmount(event); - // If the cursor was above or below the viewport, make sure it's at the - // start or end of the viewport respectively. This should only happen when - // NOT in column select mode. + /* + * If the cursor was above or below the viewport, make sure it's at the + * start or end of the viewport respectively. This should only happen when + * NOT in column select mode. + */ if (this._activeSelectionMode !== SelectionMode.COLUMN) { if (this._dragScrollAmount > 0) { this._model.selectionEnd[0] = this._bufferService.cols; @@ -652,9 +672,11 @@ export class SelectionService extends Disposable implements ISelectionService { } } - // If the character is a wide character include the cell to the right in the - // selection. Note that selections at the very end of the line will never - // have a character. + /* + * If the character is a wide character include the cell to the right in the + * selection. Note that selections at the very end of the line will never + * have a character. + */ const buffer = this._bufferService.buffer; if (this._model.selectionEnd[1] < buffer.lines.length) { const line = buffer.lines.get(this._model.selectionEnd[1]); @@ -683,10 +705,12 @@ export class SelectionService extends Disposable implements ISelectionService { } if (this._dragScrollAmount) { this._onRequestScrollLines.fire({ amount: this._dragScrollAmount, suppressScrollEvent: false }); - // Re-evaluate selection - // If the cursor was above or below the viewport, make sure it's at the - // start or end of the viewport respectively. This should only happen when - // NOT in column select mode. + /* + * Re-evaluate selection + * If the cursor was above or below the viewport, make sure it's at the + * start or end of the viewport respectively. This should only happen when + * NOT in column select mode. + */ const buffer = this._bufferService.buffer; if (this._dragScrollAmount > 0) { if (this._activeSelectionMode !== SelectionMode.COLUMN) { @@ -765,10 +789,12 @@ export class SelectionService extends Disposable implements ISelectionService { private _handleBufferActivate(e: {activeBuffer: IBuffer, inactiveBuffer: IBuffer}): void { this.clearSelection(); - // Only adjust the selection on trim, shiftElements is rarely used (only in - // reverseIndex) and delete in a splice is only ever used when the same - // number of elements was just added. Given this is could actually be - // beneficial to leave the selection as is for these cases. + /* + * Only adjust the selection on trim, shiftElements is rarely used (only in + * reverseIndex) and delete in a splice is only ever used when the same + * number of elements was just added. Given this is could actually be + * beneficial to leave the selection as is for these cases. + */ this._trimListener.dispose(); this._trimListener = e.activeBuffer.lines.onTrim(amount => this._handleTrim(amount)); } @@ -784,13 +810,17 @@ export class SelectionService extends Disposable implements ISelectionService { for (let i = 0; x >= i; i++) { const length = bufferLine.loadCell(i, this._workCell).getChars().length; if (this._workCell.getWidth() === 0) { - // Wide characters aren't included in the line string so decrement the - // index so the index is back on the wide character. + /* + * Wide characters aren't included in the line string so decrement the + * index so the index is back on the wide character. + */ charIndex--; } else if (length > 1 && x !== i) { - // Emojis take up multiple characters, so adjust accordingly. For these - // we don't want ot include the character at the column as we're - // returning the start index in the string, not the end index. + /* + * Emojis take up multiple characters, so adjust accordingly. For these + * we don't want ot include the character at the column as we're + * returning the start index in the string, not the end index. + */ charIndex += length - 1; } } @@ -853,15 +883,19 @@ export class SelectionService extends Disposable implements ISelectionService { endIndex++; } } else { - // Expand until whitespace is hit. This algorithm works by scanning left - // and right from the starting position, keeping both the index format - // (line) and the column format (bufferLine) in sync. When a wide - // character is hit, it is recorded and the column index is adjusted. + /* + * Expand until whitespace is hit. This algorithm works by scanning left + * and right from the starting position, keeping both the index format + * (line) and the column format (bufferLine) in sync. When a wide + * character is hit, it is recorded and the column index is adjusted. + */ let startCol = coords[0]; let endCol = coords[0]; - // Consider the initial position, skip it and increment the wide char - // variable + /* + * Consider the initial position, skip it and increment the wide char + * variable + */ if (bufferLine.getWidth(startCol) === 0) { leftWideCharCount++; startCol--; @@ -887,8 +921,10 @@ export class SelectionService extends Disposable implements ISelectionService { leftWideCharCount++; startCol--; } else if (length > 1) { - // If the next character's string is longer than 1 char (eg. emoji), - // adjust the index + /* + * If the next character's string is longer than 1 char (eg. emoji), + * adjust the index + */ leftLongCharOffset += length - 1; startIndex -= length - 1; } @@ -903,8 +939,10 @@ export class SelectionService extends Disposable implements ISelectionService { rightWideCharCount++; endCol++; } else if (length > 1) { - // If the next character's string is longer than 1 char (eg. emoji), - // adjust the index + /* + * If the next character's string is longer than 1 char (eg. emoji), + * adjust the index + */ rightLongCharOffset += length - 1; endIndex += length - 1; } @@ -916,16 +954,20 @@ export class SelectionService extends Disposable implements ISelectionService { // Incremenet the end index so it is at the start of the next character endIndex++; - // Calculate the start _column_, converting the the string indexes back to - // column coordinates. + /* + * Calculate the start _column_, converting the the string indexes back to + * column coordinates. + */ let start = startIndex // The index of the selection's start char in the line string + charOffset // The difference between the initial char's column and index - leftWideCharCount // The number of wide chars left of the initial char + leftLongCharOffset; // The number of additional chars left of the initial char added by columns with strings longer than 1 (emojis) - // Calculate the length in _columns_, converting the the string indexes back - // to column coordinates. + /* + * Calculate the length in _columns_, converting the the string indexes back + * to column coordinates. + */ let length = Math.min(this._bufferService.cols, // Disallow lengths larger than the terminal cols endIndex // The index of the selection's end char in the line string - startIndex // The index of the selection's start char in the line string @@ -1002,8 +1044,10 @@ export class SelectionService extends Disposable implements ISelectionService { endRow--; } - // Adjust wrapped length value, this only needs to happen when values are reversed as in that - // case we're interested in the start of the word, not the end + /* + * Adjust wrapped length value, this only needs to happen when values are reversed as in that + * case we're interested in the start of the word, not the end + */ if (!this._model.areSelectionValuesReversed()) { while (wordPosition.start + wordPosition.length > this._bufferService.cols) { wordPosition.length -= this._bufferService.cols; @@ -1021,8 +1065,10 @@ export class SelectionService extends Disposable implements ISelectionService { * @param cell The cell to check. */ private _isCharWordSeparator(cell: ICellData): boolean { - // Zero width characters are never separators as they are always to the - // right of wide characters + /* + * Zero width characters are never separators as they are always to the + * right of wide characters + */ if (cell.getWidth() === 0) { return false; } diff --git a/src/common/CircularList.ts b/src/common/CircularList.ts index 3663bfc17..9843a470c 100644 --- a/src/common/CircularList.ts +++ b/src/common/CircularList.ts @@ -52,8 +52,10 @@ export class CircularList extends Disposable implements ICircularList { return; } - // Reconstruct array, starting at index 0. Only transfer values from the - // indexes 0 to length. + /* + * Reconstruct array, starting at index 0. Only transfer values from the + * indexes 0 to length. + */ const newArray = new Array(newMaxLength); for (let i = 0; i < Math.min(newMaxLength, this.length); i++) { newArray[i] = this._array[this._getCyclicIndex(i)]; diff --git a/src/common/Color.ts b/src/common/Color.ts index b3d13fc99..eef573796 100644 --- a/src/common/Color.ts +++ b/src/common/Color.ts @@ -27,9 +27,11 @@ export namespace channels { } export function toRgba(r: number, g: number, b: number, a: number = 0xFF): number { - // Note: The aggregated number is RGBA32 (BE), thus needs to be converted to ABGR32 - // on LE systems, before it can be used for direct 32-bit buffer writes. - // >>> 0 forces an unsigned int + /* + * Note: The aggregated number is RGBA32 (BE), thus needs to be converted to ABGR32 + * on LE systems, before it can be used for direct 32-bit buffer writes. + * >>> 0 forces an unsigned int + */ return (r << 24 | g << 16 | b << 8 | a) >>> 0; } @@ -197,8 +199,10 @@ export namespace css { throw new Error('css.toColor: Unsupported css format'); } - // Validate the color using canvas fillStyle - // See https://html.spec.whatwg.org/multipage/canvas.html#fill-and-stroke-styles + /* + * Validate the color using canvas fillStyle + * See https://html.spec.whatwg.org/multipage/canvas.html#fill-and-stroke-styles + */ $ctx.fillStyle = $litmusColor; $ctx.fillStyle = css; if (typeof $ctx.fillStyle !== 'string') { @@ -213,9 +217,11 @@ export namespace css { throw new Error('css.toColor: Unsupported css format'); } - // Extract the color from the canvas' fillStyle property which exposes the color value in rgba() - // format - // See https://html.spec.whatwg.org/multipage/canvas.html#serialisation-of-a-color + /* + * Extract the color from the canvas' fillStyle property which exposes the color value in rgba() + * format + * See https://html.spec.whatwg.org/multipage/canvas.html#serialisation-of-a-color + */ return { rgba: channels.toRgba($r, $g, $b, $a), css @@ -321,8 +327,10 @@ export namespace rgba { } export function reduceLuminance(bgRgba: number, fgRgba: number, ratio: number): number { - // This is a naive but fast approach to reducing luminance as converting to - // HSL and back is expensive + /* + * This is a naive but fast approach to reducing luminance as converting to + * HSL and back is expensive + */ const bgR = (bgRgba >> 24) & 0xFF; const bgG = (bgRgba >> 16) & 0xFF; const bgB = (bgRgba >> 8) & 0xFF; @@ -341,8 +349,10 @@ export namespace rgba { } export function increaseLuminance(bgRgba: number, fgRgba: number, ratio: number): number { - // This is a naive but fast approach to increasing luminance as converting to - // HSL and back is expensive + /* + * This is a naive but fast approach to increasing luminance as converting to + * HSL and back is expensive + */ const bgR = (bgRgba >> 24) & 0xFF; const bgG = (bgRgba >> 16) & 0xFF; const bgB = (bgRgba >> 8) & 0xFF; diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index 9bd7faaf5..3e16fe0a2 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -176,8 +176,10 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { x = Math.max(x, BufferServiceConstants.MINIMUM_COLS); y = Math.max(y, BufferServiceConstants.MINIMUM_ROWS); - // Flush pending writes before resize to avoid race conditions where async - // writes are processed with incorrect dimensions + /* + * Flush pending writes before resize to avoid race conditions where async + * writes are processed with incorrect dimensions + */ this._writeBuffer.flushSync(); this._bufferService.resize(x, y); diff --git a/src/common/InputHandler.test.ts b/src/common/InputHandler.test.ts index f9da81a25..cf41d5746 100644 --- a/src/common/InputHandler.test.ts +++ b/src/common/InputHandler.test.ts @@ -613,8 +613,10 @@ describe('InputHandler', () => { await inputHandler.parseP('a'.repeat(bufferService.cols + 9)); // line 1 and 2 for (let i = 3; i < bufferService.rows; ++i) await inputHandler.parseP('a'.repeat(bufferService.cols)); - // params[1] left and above with wrap - // confirm precondition that line 2 is wrapped + /* + * params[1] left and above with wrap + * confirm precondition that line 2 is wrapped + */ assert.equal(bufferService.buffer.lines.get(2)!.isWrapped, true); bufferService.buffer.y = 2; bufferService.buffer.x = 40; @@ -628,8 +630,10 @@ describe('InputHandler', () => { await inputHandler.parseP('a'.repeat(bufferService.cols + 9)); // line 1 and 2 for (let i = 3; i < bufferService.rows; ++i) await inputHandler.parseP('a'.repeat(bufferService.cols)); - // params[1] left and above with wrap - // confirm precondition that line 2 is wrapped + /* + * params[1] left and above with wrap + * confirm precondition that line 2 is wrapped + */ assert.equal(bufferService.buffer.lines.get(2)!.isWrapped, true); bufferService.buffer.y = 1; bufferService.buffer.x = 90; // Cursor is beyond last column diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index 2b7142dd0..1fac29d91 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -33,10 +33,12 @@ const GLEVEL: { [key: string]: number } = { '(': 0, ')': 1, '*': 2, '+': 3, '-': /** * Document xterm VT features here that are currently unsupported */ -// @vt: #N DCS DECUDK "User Defined Keys" "DCS Ps ; Ps \| Pt ST" "Definitions for user-defined keys." -// @vt: #N DCS XTGETTCAP "Request Terminfo String" "DCS + q Pt ST" "Request Terminfo String." -// @vt: #N DCS XTSETTCAP "Set Terminfo Data" "DCS + p Pt ST" "Set Terminfo Data." -// @vt: #N OSC 1 "Set Icon Name" "OSC 1 ; Pt BEL" "Set icon name." +/* + * @vt: #N DCS DECUDK "User Defined Keys" "DCS Ps ; Ps \| Pt ST" "Definitions for user-defined keys." + * @vt: #N DCS XTGETTCAP "Request Terminfo String" "DCS + q Pt ST" "Request Terminfo String." + * @vt: #N DCS XTSETTCAP "Set Terminfo Data" "DCS + p Pt ST" "Set Terminfo Data." + * @vt: #N OSC 1 "Set Icon Name" "OSC 1 ; Pt BEL" "Set icon name." + */ /** * Max length of the UTF32 input buffer. Real memory consumption is 4 times higher. @@ -288,13 +290,17 @@ export class InputHandler extends Disposable implements IInputHandler { this._parser.registerOscHandler(1, new OscHandler(data => this.setIconName(data))); // 2 - title this._parser.registerOscHandler(2, new OscHandler(data => this.setTitle(data))); - // 3 - set property X in the form "prop=value" - // 4 - Change Color Number + /* + * 3 - set property X in the form "prop=value" + * 4 - Change Color Number + */ this._parser.registerOscHandler(4, new OscHandler(data => this.setOrReportIndexedColor(data))); - // 5 - Change Special Color Number - // 6 - Enable/disable Special Color Number c - // 7 - current directory? (not in xterm spec, see https://gitlab.com/gnachman/iterm2/issues/3939) - // 8 - create hyperlink (not in xterm spec, see https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda) + /* + * 5 - Change Special Color Number + * 6 - Enable/disable Special Color Number c + * 7 - current directory? (not in xterm spec, see https://gitlab.com/gnachman/iterm2/issues/3939) + * 8 - create hyperlink (not in xterm spec, see https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda) + */ this._parser.registerOscHandler(8, new OscHandler(data => this.setHyperlink(data))); // 10 - Change VT100 text foreground color to Pt. this._parser.registerOscHandler(10, new OscHandler(data => this.setOrReportFgColor(data))); @@ -302,34 +308,40 @@ export class InputHandler extends Disposable implements IInputHandler { this._parser.registerOscHandler(11, new OscHandler(data => this.setOrReportBgColor(data))); // 12 - Change text cursor color to Pt. this._parser.registerOscHandler(12, new OscHandler(data => this.setOrReportCursorColor(data))); - // 13 - Change mouse foreground color to Pt. - // 14 - Change mouse background color to Pt. - // 15 - Change Tektronix foreground color to Pt. - // 16 - Change Tektronix background color to Pt. - // 17 - Change highlight background color to Pt. - // 18 - Change Tektronix cursor color to Pt. - // 19 - Change highlight foreground color to Pt. - // 46 - Change Log File to Pt. - // 50 - Set Font to Pt. - // 51 - reserved for Emacs shell. - // 52 - Manipulate Selection Data. - // 104 ; c - Reset Color Number c. + /* + * 13 - Change mouse foreground color to Pt. + * 14 - Change mouse background color to Pt. + * 15 - Change Tektronix foreground color to Pt. + * 16 - Change Tektronix background color to Pt. + * 17 - Change highlight background color to Pt. + * 18 - Change Tektronix cursor color to Pt. + * 19 - Change highlight foreground color to Pt. + * 46 - Change Log File to Pt. + * 50 - Set Font to Pt. + * 51 - reserved for Emacs shell. + * 52 - Manipulate Selection Data. + * 104 ; c - Reset Color Number c. + */ this._parser.registerOscHandler(104, new OscHandler(data => this.restoreIndexedColor(data))); - // 105 ; c - Reset Special Color Number c. - // 106 ; c; f - Enable/disable Special Color Number c. - // 110 - Reset VT100 text foreground color. + /* + * 105 ; c - Reset Special Color Number c. + * 106 ; c; f - Enable/disable Special Color Number c. + * 110 - Reset VT100 text foreground color. + */ this._parser.registerOscHandler(110, new OscHandler(data => this.restoreFgColor(data))); // 111 - Reset VT100 text background color. this._parser.registerOscHandler(111, new OscHandler(data => this.restoreBgColor(data))); // 112 - Reset text cursor color. this._parser.registerOscHandler(112, new OscHandler(data => this.restoreCursorColor(data))); - // 113 - Reset mouse foreground color. - // 114 - Reset mouse background color. - // 115 - Reset Tektronix foreground color. - // 116 - Reset Tektronix background color. - // 117 - Reset highlight color. - // 118 - Reset Tektronix cursor color. - // 119 - Reset highlight foreground color. + /* + * 113 - Reset mouse foreground color. + * 114 - Reset mouse background color. + * 115 - Reset Tektronix foreground color. + * 116 - Reset Tektronix background color. + * 117 - Reset highlight color. + * 118 - Reset Tektronix cursor color. + * 119 - Reset highlight foreground color. + */ /** * ESC handlers @@ -466,8 +478,10 @@ export class InputHandler extends Disposable implements IInputHandler { } } - // Clear the dirty row service so we know which lines changed as a result of parsing - // Important: do not clear between async calls, otherwise we lost pending update information. + /* + * Clear the dirty row service so we know which lines changed as a result of parsing + * Important: do not clear between async calls, otherwise we lost pending update information. + */ if (!wasPaused) { this._dirtyRowTracker.clearRange(); } @@ -502,8 +516,10 @@ export class InputHandler extends Disposable implements IInputHandler { this._onCursorMove.fire(); } - // Refresh any dirty rows accumulated as part of parsing, fire only for rows within the - // _viewport_ which is relative to ydisp, not relative to ybase. + /* + * Refresh any dirty rows accumulated as part of parsing, fire only for rows within the + * _viewport_ which is relative to ydisp, not relative to ybase. + */ const viewportEnd = this._dirtyRowTracker.end + (this._bufferService.buffer.ybase - this._bufferService.buffer.ydisp); const viewportStart = this._dirtyRowTracker.start + (this._bufferService.buffer.ybase - this._bufferService.buffer.ydisp); if (viewportStart < this._bufferService.rows) { @@ -525,8 +541,10 @@ export class InputHandler extends Disposable implements IInputHandler { const curAttr = this._curAttrData; let bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y); - // Defensive check: bufferRow can be undefined if a resize occurred mid-write due to async - // scheduling gaps in WriteBuffer. See https://github.com/xtermjs/xterm.js/issues/5597 + /* + * Defensive check: bufferRow can be undefined if a resize occurred mid-write due to async + * scheduling gaps in WriteBuffer. See https://github.com/xtermjs/xterm.js/issues/5597 + */ if (!bufferRow) { return; } @@ -542,15 +560,19 @@ export class InputHandler extends Disposable implements IInputHandler { for (let pos = start; pos < end; ++pos) { code = data[pos]; - // Soft hyphen's (U+00AD) behavior is ambiguous and differs across terminals. We opt to treat - // it as a zero-width hint to text layout engines and simply ignore it. + /* + * Soft hyphen's (U+00AD) behavior is ambiguous and differs across terminals. We opt to treat + * it as a zero-width hint to text layout engines and simply ignore it. + */ if (code === 0xAD) { continue; } - // get charset replacement character - // charset is only defined for ASCII, therefore we only - // search for an replacement char if code < 127 + /* + * get charset replacement character + * charset is only defined for ASCII, therefore we only + * search for an replacement char if code < 127 + */ if (code < 127 && charset) { const ch = charset[String.fromCharCode(code)]; if (ch) { @@ -571,12 +593,16 @@ export class InputHandler extends Disposable implements IInputHandler { this._oscLinkService.addLineToLink(this._getCurrentLinkId(), this._activeBuffer.ybase + this._activeBuffer.y); } - // goto next line if ch would overflow - // NOTE: To avoid costly width checks here, - // the terminal does not allow a cols < 2. + /* + * goto next line if ch would overflow + * NOTE: To avoid costly width checks here, + * the terminal does not allow a cols < 2. + */ if (this._activeBuffer.x + chWidth - oldWidth > cols) { - // autowrap - DECAWM - // automatically wraps to the beginning of the next line + /* + * autowrap - DECAWM + * automatically wraps to the beginning of the next line + */ if (wraparoundMode) { const oldRow = bufferRow; let oldCol = this._activeBuffer.x - oldWidth; @@ -589,8 +615,10 @@ export class InputHandler extends Disposable implements IInputHandler { if (this._activeBuffer.y >= this._bufferService.rows) { this._activeBuffer.y = this._bufferService.rows - 1; } - // The line already exists (eg. the initial viewport), mark it as a - // wrapped line + /* + * The line already exists (eg. the initial viewport), mark it as a + * wrapped line + */ this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!.isWrapped = true; } // row changed, get it again @@ -599,8 +627,10 @@ export class InputHandler extends Disposable implements IInputHandler { return; } if (oldWidth > 0 && bufferRow instanceof BufferLine) { - // Combining character widens 1 column to 2. - // Move old character to next line. + /* + * Combining character widens 1 column to 2. + * Move old character to next line. + */ bufferRow.copyCellsFrom(oldRow as BufferLine, oldCol, 0, oldWidth, false); } @@ -611,22 +641,28 @@ export class InputHandler extends Disposable implements IInputHandler { } else { this._activeBuffer.x = cols - 1; if (chWidth === 2) { - // FIXME: check for xterm behavior - // What to do here? We got a wide char that does not fit into last cell + /* + * FIXME: check for xterm behavior + * What to do here? We got a wide char that does not fit into last cell + */ continue; } } } - // insert combining char at last cursor position - // this._activeBuffer.x should never be 0 for a combining char - // since they always follow a cell consuming char - // therefore we can test for this._activeBuffer.x to avoid overflow left + /* + * insert combining char at last cursor position + * this._activeBuffer.x should never be 0 for a combining char + * since they always follow a cell consuming char + * therefore we can test for this._activeBuffer.x to avoid overflow left + */ if (shouldJoin && this._activeBuffer.x) { const offset = bufferRow.getWidth(this._activeBuffer.x - 1) ? 1 : 2; - // if empty cell after fullwidth, need to go 2 cells back - // it is save to step 2 cells back here - // since an empty cell is only set by fullwidth chars + /* + * if empty cell after fullwidth, need to go 2 cells back + * it is save to step 2 cells back here + * since an empty cell is only set by fullwidth chars + */ bufferRow.addCodepointToCell(this._activeBuffer.x - offset, code, chWidth); for (let delta = chWidth - oldWidth; --delta >= 0;) { @@ -639,9 +675,11 @@ export class InputHandler extends Disposable implements IInputHandler { if (insertMode) { // right shift cells according to the width bufferRow.insertCells(this._activeBuffer.x, chWidth - oldWidth, this._activeBuffer.getNullCell(curAttr)); - // test last cell - since the last cell has only room for - // a halfwidth char any fullwidth shifted there is lost - // and will be set to empty cell + /* + * test last cell - since the last cell has only room for + * a halfwidth char any fullwidth shifted there is lost + * and will be set to empty cell + */ if (bufferRow.getWidth(cols - 1) === 2) { bufferRow.setCellFromCodepoint(cols - 1, NULL_CELL_CODE, NULL_CELL_WIDTH, curAttr); } @@ -650,9 +688,11 @@ export class InputHandler extends Disposable implements IInputHandler { // write current char to buffer and advance cursor bufferRow.setCellFromCodepoint(this._activeBuffer.x++, code, chWidth, curAttr); - // fullwidth char - also set next cell to placeholder stub and advance cursor - // for graphemes bigger than fullwidth we can simply loop to zero - // we already made sure above, that this._activeBuffer.x + chWidth will not overflow right + /* + * fullwidth char - also set next cell to placeholder stub and advance cursor + * for graphemes bigger than fullwidth we can simply loop to zero + * we already made sure above, that this._activeBuffer.x + chWidth will not overflow right + */ if (chWidth > 0) { while (--chWidth) { // other than a regular empty cell a cell following a wide char has no width @@ -750,11 +790,13 @@ export class InputHandler extends Disposable implements IInputHandler { } else if (this._activeBuffer.y >= this._bufferService.rows) { this._activeBuffer.y = this._bufferService.rows - 1; } else { - // There was an explicit line feed (not just a carriage return), so clear the wrapped state of - // the line. This is particularly important on conpty/Windows where revisiting lines to - // reprint is common, especially on resize. Note that the windowsMode wrapped line heuristics - // can mess with this so windowsMode should be disabled, which is recommended on Windows build - // 21376 and above. + /* + * There was an explicit line feed (not just a carriage return), so clear the wrapped state of + * the line. This is particularly important on conpty/Windows where revisiting lines to + * reprint is common, especially on resize. Note that the windowsMode wrapped line heuristics + * can mess with this so windowsMode should be disabled, which is recommended on Windows build + * 21376 and above. + */ this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!.isWrapped = false; } // If the end of the line is hit, prevent this action from wrapping around to the next line. @@ -799,9 +841,11 @@ export class InputHandler extends Disposable implements IInputHandler { return true; } - // reverse wrap-around is enabled - // other than for normal operation mode, reverse wrap-around allows the cursor - // to be at x=cols to be able to address the last cell of a row by BS + /* + * reverse wrap-around is enabled + * other than for normal operation mode, reverse wrap-around allows the cursor + * to be at x=cols to be able to address the last cell of a row by BS + */ this._restrictCursor(this._bufferService.cols); if (this._activeBuffer.x > 0) { @@ -822,17 +866,21 @@ export class InputHandler extends Disposable implements IInputHandler { this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!.isWrapped = false; this._activeBuffer.y--; this._activeBuffer.x = this._bufferService.cols - 1; - // find last taken cell - last cell can have 3 different states: - // - hasContent(true) + hasWidth(1): narrow char - we are done - // - hasWidth(0): second part of wide char - we are done - // - hasContent(false) + hasWidth(1): empty cell due to early wrapping wide char, go one - // cell further back + /* + * find last taken cell - last cell can have 3 different states: + * - hasContent(true) + hasWidth(1): narrow char - we are done + * - hasWidth(0): second part of wide char - we are done + * - hasContent(false) + hasWidth(1): empty cell due to early wrapping wide char, go one + * cell further back + */ const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!; if (line.hasWidth(this._activeBuffer.x) && !line.hasContent(this._activeBuffer.x)) { this._activeBuffer.x--; - // We do this only once, since width=1 + hasContent=false currently happens only once - // before early wrapping of a wide char. - // This needs to be fixed once we support graphemes taking more than 2 cells. + /* + * We do this only once, since width=1 + hasContent=false currently happens only once + * before early wrapping of a wide char. + * This needs to be fixed once we support graphemes taking more than 2 cells. + */ } } } @@ -913,8 +961,10 @@ export class InputHandler extends Disposable implements IInputHandler { * Set relative cursor position. */ private _moveCursor(x: number, y: number): void { - // for relative changes we have to make sure we are within 0 .. cols/rows - 1 - // before calculating the new position + /* + * for relative changes we have to make sure we are within 0 .. cols/rows - 1 + * before calculating the new position + */ this._restrictCursor(); this._setCursor(this._activeBuffer.x + x, this._activeBuffer.y + y); } @@ -1354,8 +1404,10 @@ export class InputHandler extends Disposable implements IInputHandler { const scrollBottomRowsOffset = this._bufferService.rows - 1 - this._activeBuffer.scrollBottom; const scrollBottomAbsolute = this._bufferService.rows - 1 + this._activeBuffer.ybase - scrollBottomRowsOffset + 1; while (param--) { - // test: echo -e '\e[44m\e[1L\e[0m' - // blankLine(true) - xterm/linux behavior + /* + * test: echo -e '\e[44m\e[1L\e[0m' + * blankLine(true) - xterm/linux behavior + */ this._activeBuffer.lines.splice(scrollBottomAbsolute - 1, 1); this._activeBuffer.lines.splice(row, 0, this._activeBuffer.getBlankLine(this._eraseAttrData())); } @@ -1388,8 +1440,10 @@ export class InputHandler extends Disposable implements IInputHandler { j = this._bufferService.rows - 1 - this._activeBuffer.scrollBottom; j = this._bufferService.rows - 1 + this._activeBuffer.ybase - j; while (param--) { - // test: echo -e '\e[44m\e[1M\e[0m' - // blankLine(true) - xterm/linux behavior + /* + * test: echo -e '\e[44m\e[1M\e[0m' + * blankLine(true) - xterm/linux behavior + */ this._activeBuffer.lines.splice(row, 1); this._activeBuffer.lines.splice(j, 0, this._activeBuffer.getBlankLine(this._eraseAttrData())); } @@ -1737,16 +1791,20 @@ export class InputHandler extends Disposable implements IInputHandler { if (params.params[0] > 0) { return true; } - // xterm and urxvt - // seem to spit this - // out around ~370 times (?). + /* + * xterm and urxvt + * seem to spit this + * out around ~370 times (?). + */ if (this._is('xterm')) { this._coreService.triggerDataEvent(C0.ESC + '[>0;276;0c'); } else if (this._is('rxvt-unicode')) { this._coreService.triggerDataEvent(C0.ESC + '[>85;95;0c'); } else if (this._is('linux')) { - // not supported by linux console. - // linux console echoes parameters. + /* + * not supported by linux console. + * linux console echoes parameters. + */ this._coreService.triggerDataEvent(params.params[0] + 'c'); } else if (this._is('screen')) { this._coreService.triggerDataEvent(C0.ESC + '[>83;40003;0c'); @@ -1979,13 +2037,17 @@ export class InputHandler extends Disposable implements IInputHandler { this._mouseStateService.activeProtocol = 'DRAG'; break; case 1003: // any event mouse - // any event - sends motion events, - // even if there is no button held down. + /* + * any event - sends motion events, + * even if there is no button held down. + */ this._mouseStateService.activeProtocol = 'ANY'; break; case 1004: // send focusin/focusout events - // focusin: ^[[I - // focusout: ^[[O + /* + * focusin: ^[[I + * focusout: ^[[O + */ this._coreService.decPrivateModes.sendFocus = true; this._onRequestSendFocus.fire(); break; @@ -2408,10 +2470,12 @@ export class InputHandler extends Disposable implements IInputHandler { * Returns advance for params index. */ private _extractColor(params: IParams, pos: number, attr: IAttributeData): number { - // normalize params - // meaning: [target, CM, ign, val, val, val] - // RGB : [ 38/48, 2, ign, r, g, b] - // P256 : [ 38/48, 5, ign, v, ign, ign] + /* + * normalize params + * meaning: [target, CM, ign, val, val, val] + * RGB : [ 38/48, 2, ign, r, g, b] + * P256 : [ 38/48, 5, ign, v, ign, ign] + */ const accu = [0, 0, -1, 0, 0, 0]; // alignment placeholder for non color space sequences @@ -2477,8 +2541,10 @@ export class InputHandler extends Disposable implements IInputHandler { * 4:5 - dashed underline */ private _processUnderline(style: number, attr: IAttributeData): void { - // treat extended attrs as immutable, thus always clone from old one - // this is needed since the buffer only holds references to it + /* + * treat extended attrs as immutable, thus always clone from old one + * this is needed since the buffer only holds references to it + */ attr.extended = attr.extended.clone(); // default to 1 == single underline @@ -2501,8 +2567,10 @@ export class InputHandler extends Disposable implements IInputHandler { attr.fg = DEFAULT_ATTR_DATA.fg; attr.bg = DEFAULT_ATTR_DATA.bg; attr.extended = attr.extended.clone(); - // Reset underline style and color. Note that we don't want to reset other - // fields such as the url id. + /* + * Reset underline style and color. Note that we don't want to reset other + * fields such as the url id. + */ attr.extended.underlineStyle = UnderlineStyle.NONE; attr.extended.underlineColor &= ~(Attributes.CM_MASK | Attributes.RGB_MASK); attr.updateExtended(); @@ -2641,8 +2709,10 @@ export class InputHandler extends Disposable implements IInputHandler { // blink attr.fg |= FgFlags.BLINK; } else if (p === 7) { - // inverse and positive - // test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m' + /* + * inverse and positive + * test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m' + */ attr.fg |= FgFlags.INVERSE; } else if (p === 8) { // invisible @@ -2756,8 +2826,10 @@ export class InputHandler extends Disposable implements IInputHandler { // @vt: #P[Only CPR is supported.] CSI DECDSR "DEC Device Status Report" "CSI ? Ps n" "Only CPR is supported (same as DSR)." public deviceStatusPrivate(params: IParams): boolean { - // modern xterm doesnt seem to - // respond to any of these except ?6, 6, and 5 + /* + * modern xterm doesnt seem to + * respond to any of these except ?6, 6, and 5 + */ switch (params.params[0]) { case 6: // cursor position @@ -2766,20 +2838,28 @@ export class InputHandler extends Disposable implements IInputHandler { this._coreService.triggerDataEvent(`${C0.ESC}[?${y};${x}R`); break; case 15: - // no printer - // this.handler(C0.ESC + '[?11n'); + /* + * no printer + * this.handler(C0.ESC + '[?11n'); + */ break; case 25: - // dont support user defined keys - // this.handler(C0.ESC + '[?21n'); + /* + * dont support user defined keys + * this.handler(C0.ESC + '[?21n'); + */ break; case 26: - // north american keyboard - // this.handler(C0.ESC + '[?27;1;0;0n'); + /* + * north american keyboard + * this.handler(C0.ESC + '[?27;1;0;0n'); + */ break; case 53: - // no dec locator/mouse - // this.handler(C0.ESC + '[?50n'); + /* + * no dec locator/mouse + * this.handler(C0.ESC + '[?50n'); + */ break; case 996: // color scheme query (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/) @@ -3401,9 +3481,11 @@ export class InputHandler extends Disposable implements IInputHandler { public reverseIndex(): boolean { this._restrictCursor(); if (this._activeBuffer.y === this._activeBuffer.scrollTop) { - // possibly move the code below to term.reverseScroll(); - // test: echo -ne '\e[1;1H\e[44m\eM\e[0m' - // blankLine(true) is xterm/linux behavior + /* + * possibly move the code below to term.reverseScroll(); + * test: echo -ne '\e[1;1H\e[44m\eM\e[0m' + * blankLine(true) is xterm/linux behavior + */ const scrollRegionHeight = this._activeBuffer.scrollBottom - this._activeBuffer.scrollTop; this._activeBuffer.lines.shiftElements(this._activeBuffer.ybase + this._activeBuffer.y, scrollRegionHeight, 1); this._activeBuffer.lines.set(this._activeBuffer.ybase + this._activeBuffer.y, this._activeBuffer.getBlankLine(this._eraseAttrData())); diff --git a/src/common/Platform.ts b/src/common/Platform.ts index 09ba097e6..ad2d1424c 100644 --- a/src/common/Platform.ts +++ b/src/common/Platform.ts @@ -9,14 +9,18 @@ interface INavigator { platform: string; } -// We're declaring a navigator global here as we expect it in all runtimes (node and browser), but -// we want this module to live in common. +/* + * We're declaring a navigator global here as we expect it in all runtimes (node and browser), but + * we want this module to live in common. + */ declare const navigator: INavigator; declare const process: unknown; -// navigator.userAgent is also checked here because bundling with the process module can cause -// issues otherwise. Note that navigator exists in Node.js 21+ but the userAgent is -// "Node.js/". +/* + * navigator.userAgent is also checked here because bundling with the process module can cause + * issues otherwise. Note that navigator exists in Node.js 21+ but the userAgent is + * "Node.js/". + */ export const isNode = (typeof process !== 'undefined' && 'title' in (process as any) && (typeof navigator === 'undefined' || navigator.userAgent.startsWith('Node.js/'))) ? true : false; const userAgent = (isNode) ? 'node' : navigator.userAgent; const platform = (isNode) ? 'node' : navigator.platform; @@ -44,9 +48,11 @@ export function getSafariVersion(): number { return parseInt(majorVersion[1]); } -// Find the users platform. We use this to interpret the meta key -// and ISO third level shifts. -// http://stackoverflow.com/q/19877924/577598 +/* + * Find the users platform. We use this to interpret the meta key + * and ISO third level shifts. + * http://stackoverflow.com/q/19877924/577598 + */ export const isMac = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'].includes(platform); export const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].includes(platform); export const isLinux = platform.indexOf('Linux') >= 0; diff --git a/src/common/SortedList.ts b/src/common/SortedList.ts index c6dc62085..8ae39d3d8 100644 --- a/src/common/SortedList.ts +++ b/src/common/SortedList.ts @@ -191,8 +191,10 @@ export class SortedList { return mid; } } - // key not in list - // still return closest min (also used as insert position) + /* + * key not in list + * still return closest min (also used as insert position) + */ return min; } } diff --git a/src/common/TaskQueue.ts b/src/common/TaskQueue.ts index 3cad0a140..ae9041d3a 100644 --- a/src/common/TaskQueue.ts +++ b/src/common/TaskQueue.ts @@ -83,17 +83,23 @@ abstract class TaskQueue implements ITaskQueue { if (!this._tasks[this._i]()) { this._i++; } - // other than performance.now, performance.now might not be stable (changes on wall clock - // changes), this is not an issue here as a clock change during a short running task is very - // unlikely in case it still happened and leads to negative duration, simply assume 1 msec + /* + * other than performance.now, performance.now might not be stable (changes on wall clock + * changes), this is not an issue here as a clock change during a short running task is very + * unlikely in case it still happened and leads to negative duration, simply assume 1 msec + */ taskDuration = Math.max(1, performance.now() - taskDuration); longestTask = Math.max(taskDuration, longestTask); - // Guess the following task will take a similar time to the longest task in this batch, allow - // additional room to try avoid exceeding the deadline + /* + * Guess the following task will take a similar time to the longest task in this batch, allow + * additional room to try avoid exceeding the deadline + */ deadlineRemaining = deadline.timeRemaining(); if (longestTask * 1.5 > deadlineRemaining) { - // Warn when the time exceeding the deadline is over 20ms, if this happens in practice the - // task should be split into sub-tasks to ensure the UI remains responsive. + /* + * Warn when the time exceeding the deadline is over 20ms, if this happens in practice the + * task should be split into sub-tasks to ensure the UI remains responsive. + */ if (lastDeadlineRemaining - taskDuration < -20) { this._logService.warn(`task queue exceeded allotted deadline by ${Math.abs(Math.round(lastDeadlineRemaining - taskDuration))}ms`); } diff --git a/src/common/Types.ts b/src/common/Types.ts index 5edf63637..fb95f5fe7 100644 --- a/src/common/Types.ts +++ b/src/common/Types.ts @@ -310,8 +310,10 @@ export const enum CoreMouseButton { RIGHT = 2, NONE = 3, WHEEL = 4, - // additional buttons 1..8 - // untested! + /* + * additional buttons 1..8 + * untested! + */ AUX1 = 8, AUX2 = 9, AUX3 = 10, @@ -528,8 +530,10 @@ export interface IInputHandler { /** CSI ' } */ insertColumns(params: IParams): boolean; /** CSI ' ~ */ deleteColumns(params: IParams): boolean; - /** OSC 0 - OSC 2 */ setTitle(data: string): boolean; + /** + * OSC 0 + * OSC 2 + */ setTitle(data: string): boolean; /** OSC 4 */ setOrReportIndexedColor(data: string): boolean; /** OSC 10 */ setOrReportFgColor(data: string): boolean; /** OSC 11 */ setOrReportBgColor(data: string): boolean; @@ -542,24 +546,30 @@ export interface IInputHandler { /** ESC E */ nextLine(): boolean; /** ESC = */ keypadApplicationMode(): boolean; /** ESC > */ keypadNumericMode(): boolean; - /** ESC % G - ESC % @ */ selectDefaultCharset(): boolean; - /** ESC ( C - ESC ) C - ESC * C - ESC + C - ESC - C - ESC . C - ESC / C */ selectCharset(collectAndFlag: string): boolean; + /** + * ESC % G + * ESC % @ + */ selectDefaultCharset(): boolean; + /** + * ESC ( C + * ESC ) C + * ESC * C + * ESC + C + * ESC - C + * ESC . C + * ESC / C + */ selectCharset(collectAndFlag: string): boolean; /** ESC D */ index(): boolean; /** ESC H */ tabSet(): boolean; /** ESC M */ reverseIndex(): boolean; /** ESC c */ fullReset(): boolean; - /** ESC n - ESC o - ESC | - ESC } - ESC ~ */ setgLevel(level: number): boolean; + /** + * ESC n + * ESC o + * ESC | + * ESC } + * ESC ~ + */ setgLevel(level: number): boolean; /** ESC # 8 */ screenAlignmentPattern(): boolean; } diff --git a/src/common/WindowsMode.ts b/src/common/WindowsMode.ts index 7cff094b2..f59343286 100644 --- a/src/common/WindowsMode.ts +++ b/src/common/WindowsMode.ts @@ -7,16 +7,18 @@ import { CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CODE } from 'comm import { IBufferService } from 'common/services/Services'; export function updateWindowsModeWrappedState(bufferService: IBufferService): void { - // Winpty does not support wraparound mode which means that lines will never - // be marked as wrapped. This causes issues for things like copying a line - // retaining the wrapped new line characters or if consumers are listening - // in on the data stream. - // - // The workaround for this is to listen to every incoming line feed and mark - // the line as wrapped if the last character in the previous line is not a - // space. This is certainly not without its problems, but generally on - // Windows when text reaches the end of the terminal it's likely going to be - // wrapped. + /* + * Winpty does not support wraparound mode which means that lines will never + * be marked as wrapped. This causes issues for things like copying a line + * retaining the wrapped new line characters or if consumers are listening + * in on the data stream. + * + * The workaround for this is to listen to every incoming line feed and mark + * the line as wrapped if the last character in the previous line is not a + * space. This is certainly not without its problems, but generally on + * Windows when text reaches the end of the terminal it's likely going to be + * wrapped. + */ const line = bufferService.buffer.lines.get(bufferService.buffer.ybase + bufferService.buffer.y - 1); const lastChar = line?.get(bufferService.cols - 1); diff --git a/src/common/buffer/Buffer.test.ts b/src/common/buffer/Buffer.test.ts index abfea7b06..f26807a94 100644 --- a/src/common/buffer/Buffer.test.ts +++ b/src/common/buffer/Buffer.test.ts @@ -348,8 +348,10 @@ describe('Buffer', () => { assert.equal(buffer.lines.get(4)!.translateToString(), ' '); }); it('should remove the correct amount of rows when reflowing larger', () => { - // This is a regression test to ensure that successive wrapped lines that are getting - // 3+ lines removed on a reflow actually remove the right lines + /* + * This is a regression test to ensure that successive wrapped lines that are getting + * 3+ lines removed on a reflow actually remove the right lines + */ buffer.fillViewportRows(); buffer.resize(10, 10); buffer.y = 2; @@ -429,10 +431,12 @@ describe('Buffer', () => { buffer.lines.get(2)!.set(i, [0, char, 1, code]); } buffer.y = 3; - // Buffer: - // abcdefghij - // 0123456789 - // abcdefghij + /* + * Buffer: + * abcdefghij + * 0123456789 + * abcdefghij + */ const firstMarker = buffer.addMarker(0); const secondMarker = buffer.addMarker(1); const thirdMarker = buffer.addMarker(2); @@ -492,10 +496,12 @@ describe('Buffer', () => { buffer.lines.get(2)!.set(i, [0, char, 1, code]); } buffer.y = 10; - // Buffer: - // abcdefghij - // 0123456789 - // abcdefghij + /* + * Buffer: + * abcdefghij + * 0123456789 + * abcdefghij + */ const firstMarker = buffer.addMarker(0); const secondMarker = buffer.addMarker(1); const thirdMarker = buffer.addMarker(2); @@ -539,9 +545,11 @@ describe('Buffer', () => { buffer.lines.get(1)!.set(0, [0, 'c', 1, 'c'.charCodeAt(0)]); buffer.lines.get(1)!.set(1, [0, 'd', 1, 'd'.charCodeAt(0)]); buffer.lines.get(1)!.isWrapped = true; - // Buffer: - // "ab " (wrapped) - // "cd" + /* + * Buffer: + * "ab " (wrapped) + * "cd" + */ buffer.resize(5, 10); assert.equal(buffer.ybase, 0); assert.equal(buffer.lines.length, 10); @@ -570,9 +578,11 @@ describe('Buffer', () => { buffer.lines.get(1)!.set(i, [0, '', 0, 0]); } buffer.lines.get(1)!.isWrapped = true; - // Buffer: - // 汉语汉语汉语 (wrapped) - // 汉语汉语汉语 + /* + * Buffer: + * 汉语汉语汉语 (wrapped) + * 汉语汉语汉语 + */ assert.equal(buffer.lines.get(0)!.translateToString(true), '汉语汉语汉语'); assert.equal(buffer.lines.get(1)!.translateToString(true), '汉语汉语汉语'); buffer.resize(13, 10); @@ -597,9 +607,11 @@ describe('Buffer', () => { buffer.lines.get(1)!.set(0, [0, 'c', 1, 'c'.charCodeAt(0)]); buffer.lines.get(1)!.set(1, [0, 'd', 1, 'd'.charCodeAt(0)]); buffer.lines.get(1)!.isWrapped = true; - // Buffer: - // "ab " (wrapped) - // "cd" + /* + * Buffer: + * "ab " (wrapped) + * "cd" + */ buffer.resize(3, 10); assert.equal(buffer.y, 2); assert.equal(buffer.ybase, 0); @@ -631,9 +643,11 @@ describe('Buffer', () => { buffer.lines.get(1)!.set(i, [0, '', 0, 0]); } buffer.lines.get(1)!.isWrapped = true; - // Buffer: - // 汉语汉语汉语 (wrapped) - // 汉语汉语汉语 + /* + * Buffer: + * 汉语汉语汉语 (wrapped) + * 汉语汉语汉语 + */ assert.equal(buffer.lines.get(0)!.translateToString(true), '汉语汉语汉语'); assert.equal(buffer.lines.get(1)!.translateToString(true), '汉语汉语汉语'); buffer.resize(11, 10); @@ -668,17 +682,19 @@ describe('Buffer', () => { describe('reflowLarger cases', () => { beforeEach(() => { - // Setup buffer state: - // 'ab' - // 'cd' (wrapped) - // 'ef' - // 'gh' (wrapped) - // 'ij' - // 'kl' (wrapped) - // ' ' - // ' ' - // ' ' - // ' ' + /* + * Setup buffer state: + * 'ab' + * 'cd' (wrapped) + * 'ef' + * 'gh' (wrapped) + * 'ij' + * 'kl' (wrapped) + * ' ' + * ' ' + * ' ' + * ' ' + */ buffer.fillViewportRows(); buffer.resize(2, 10); buffer.lines.get(0)!.set(0, [0, 'a', 1, 'a'.charCodeAt(0)]); @@ -859,17 +875,19 @@ describe('Buffer', () => { }); describe('reflowSmaller cases', () => { beforeEach(() => { - // Setup buffer state: - // 'abcd' - // 'efgh' (wrapped) - // 'ijkl' - // ' ' - // ' ' - // ' ' - // ' ' - // ' ' - // ' ' - // ' ' + /* + * Setup buffer state: + * 'abcd' + * 'efgh' (wrapped) + * 'ijkl' + * ' ' + * ' ' + * ' ' + * ' ' + * ' ' + * ' ' + * ' ' + */ buffer.fillViewportRows(); buffer.resize(4, 10); buffer.lines.get(0)!.set(0, [0, 'a', 1, 'a'.charCodeAt(0)]); @@ -1301,8 +1319,10 @@ describe('Buffer', () => { assert.equal(line.length, INIT_COLS / 2 - 1); } - // wait for a bit to give IdleTaskQueue a chance to kick in - // and finish memory cleaning + /* + * wait for a bit to give IdleTaskQueue a chance to kick in + * and finish memory cleaning + */ await new Promise(r => setTimeout(r, 30)); // cleanup should have realigned memory with exact bytelength diff --git a/src/common/buffer/Buffer.ts b/src/common/buffer/Buffer.ts index 34ef02f6a..a572418c4 100644 --- a/src/common/buffer/Buffer.ts +++ b/src/common/buffer/Buffer.ts @@ -169,19 +169,25 @@ export class Buffer extends Disposable implements IBuffer { // count bufferlines with overly big memory to be cleaned afterwards let dirtyMemoryLines = 0; - // Increase max length if needed before adjustments to allow space to fill - // as required. + /* + * Increase max length if needed before adjustments to allow space to fill + * as required. + */ const newMaxLength = this._getCorrectBufferLength(newRows); if (newMaxLength > this.lines.maxLength) { this.lines.maxLength = newMaxLength; } - // if (this._cols > newCols) { - // console.log('increase!'); - // } + /* + * if (this._cols > newCols) { + * console.log('increase!'); + * } + */ - // The following adjustments should only happen if the buffer has been - // initialized/filled. + /* + * The following adjustments should only happen if the buffer has been + * initialized/filled. + */ if (this.lines.length > 0) { // Deal with columns increasing (reducing needs to happen after reflow) if (this._cols < newCols) { @@ -197,13 +203,17 @@ export class Buffer extends Disposable implements IBuffer { for (let y = this._rows; y < newRows; y++) { if (this.lines.length < newRows + this.ybase) { if (this._optionsService.rawOptions.windowsPty.backend !== undefined || this._optionsService.rawOptions.windowsPty.buildNumber !== undefined) { - // Just add the new missing rows on Windows as conpty reprints the screen with it's - // view of the world. Once a line enters scrollback for conpty it remains there + /* + * Just add the new missing rows on Windows as conpty reprints the screen with it's + * view of the world. Once a line enters scrollback for conpty it remains there + */ this.lines.push(new BufferLine(this._stringCache, newCols, nullCell, false)); } else { if (this.ybase > 0 && this.lines.length <= this.ybase + this.y + addToY + 1) { - // There is room above the buffer and there are no empty elements below the line, - // scroll up + /* + * There is room above the buffer and there are no empty elements below the line, + * scroll up + */ this.ybase--; addToY++; if (this.ydisp > 0) { @@ -211,8 +221,10 @@ export class Buffer extends Disposable implements IBuffer { this.ydisp--; } } else { - // Add a blank line if there is no buffer left at the top to scroll to, or if there - // are blank lines after the cursor + /* + * Add a blank line if there is no buffer left at the top to scroll to, or if there + * are blank lines after the cursor + */ this.lines.push(new BufferLine(this._stringCache, newCols, nullCell, false)); } } @@ -233,8 +245,10 @@ export class Buffer extends Disposable implements IBuffer { } } - // Reduce max length if needed after adjustments, this is done after as it - // would otherwise cut data from the bottom of the buffer. + /* + * Reduce max length if needed after adjustments, this is done after as it + * would otherwise cut data from the bottom of the buffer. + */ if (newMaxLength < this.lines.maxLength) { // Trim from the top of the buffer and adjust ybase and ydisp. const amountToTrim = this.lines.length - newMaxLength; @@ -275,8 +289,10 @@ export class Buffer extends Disposable implements IBuffer { this._cols = newCols; this._rows = newRows; - // Ensure the cursor position invariant: ybase + y must be within buffer bounds - // This can be violated during reflow or when shrinking rows + /* + * Ensure the cursor position invariant: ybase + y must be within buffer bounds + * This can be violated during reflow or when shrinking rows + */ if (this.lines.length > 0) { const maxY = Math.max(0, this.lines.length - this.ybase - 1); this.y = Math.min(this.y, maxY); @@ -293,8 +309,10 @@ export class Buffer extends Disposable implements IBuffer { private _batchedMemoryCleanup(): boolean { let normalRun = true; if (this._memoryCleanupPosition >= this.lines.length) { - // cleanup made it once through all lines, thus rescan in loop below to also catch shifted - // lines, which should finish rather quick if there are no more cleanups pending + /* + * cleanup made it once through all lines, thus rescan in loop below to also catch shifted + * lines, which should finish rather quick if there are no more cleanups pending + */ this._memoryCleanupPosition = 0; normalRun = false; } @@ -306,9 +324,11 @@ export class Buffer extends Disposable implements IBuffer { return true; } } - // normal runs always need another rescan afterwards - // if we made it here with normalRun=false, we are in a final run - // and can end the cleanup task for sure + /* + * normal runs always need another rescan afterwards + * if we made it here with normalRun=false, we are in a final run + * and can end the cleanup task for sure + */ return normalRun; } @@ -369,8 +389,10 @@ export class Buffer extends Disposable 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 + /* + * Gather all BufferLines that need to be inserted into the Buffer here so that they can be + * batched up and only committed once + */ const toInsert = []; let countToInsert = 0; // Go backwards as many lines may be trimmed and this will avoid considering them @@ -389,8 +411,10 @@ export class Buffer extends Disposable implements IBuffer { } if (!reflowCursorLine) { - // If these lines contain the cursor don't touch them, the program will handle fixing up - // wrapped lines with the cursor + /* + * 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; @@ -416,8 +440,10 @@ export class Buffer extends Disposable implements IBuffer { } if (newLines.length > 0) { toInsert.push({ - // countToInsert here gets the actual index, taking into account other inserted items. - // using this we can iterate through the list forwards + /* + * countToInsert here gets the actual index, taking into account other inserted items. + * using this we can iterate through the list forwards + */ start: y + wrappedLines.length + countToInsert, newLines }); @@ -437,8 +463,10 @@ export class Buffer extends Disposable implements IBuffer { while (srcLineIndex >= 0) { const cellsToCopy = Math.min(srcCol, destCol); if (wrappedLines[destLineIndex] === undefined) { - // Sanity check that the line exists, this has been known to fail for an unknown reason - // which would stop the reflow from happening if an exception would throw. + /* + * Sanity check that the line exists, this has been known to fail for an unknown reason + * which would stop the reflow from happening if an exception would throw. + */ break; } wrappedLines[destLineIndex].copyCellsFrom(wrappedLines[srcLineIndex], srcCol - cellsToCopy, destCol - cellsToCopy, cellsToCopy, true); @@ -486,12 +514,16 @@ export class Buffer extends Disposable implements IBuffer { this.savedY = Math.min(this.savedY + linesToAdd, this.ybase + newRows - 1); } - // Rearrange lines in the buffer if there are any insertions, this is done at the end rather - // than earlier so that it's a single O(n) pass through the buffer, instead of O(n^2) from many - // costly calls to CircularList.splice. + /* + * Rearrange lines in the buffer if there are any insertions, this is done at the end rather + * than earlier so that it's a single O(n) pass through the buffer, instead of O(n^2) from many + * costly calls to CircularList.splice. + */ if (toInsert.length > 0) { - // Record buffer insert events and then play them back backwards so that the indexes are - // correct + /* + * Record buffer insert events and then play them back backwards so that the indexes are + * correct + */ const insertEvents: IInsertEvent[] = []; // Record original lines so they don't get overridden when we rearrange the list diff --git a/src/common/buffer/BufferLine.test.ts b/src/common/buffer/BufferLine.test.ts index 3aec28872..7e8f73f4c 100644 --- a/src/common/buffer/BufferLine.test.ts +++ b/src/common/buffer/BufferLine.test.ts @@ -288,9 +288,11 @@ describe('BufferLine', function(): void { assert.equal(line2.isWrapped, line.isWrapped); }); it('should support combining chars', function(): void { - // CHAR_DATA_CODE_INDEX resembles current behavior in InputHandler.print - // --> set code to the last charCodeAt value of the string - // Note: needs to be fixed once the string pointer is in place + /* + * CHAR_DATA_CODE_INDEX resembles current behavior in InputHandler.print + * --> set code to the last charCodeAt value of the string + * Note: needs to be fixed once the string pointer is in place + */ const line = new TestBufferLine(2, createCellData(1, 'e\u0301', 1)); assert.deepEqual(line.toArray(), [[1, 'e\u0301', 1, '\u0301'.charCodeAt(0)], [1, 'e\u0301', 1, '\u0301'.charCodeAt(0)]]); const line2 = new TestBufferLine(5, createCellData(1, 'a', 1), true); @@ -478,9 +480,11 @@ describe('BufferLine', function(): void { }); it('should always return some sane value', function(): void { const columns: number[] = []; - // sanity check - broken line with invalid out of bound null width cells - // this can atm happen with deleting/inserting chars in inputhandler by "breaking" - // fullwidth pairs --> needs to be fixed after settling BufferLine impl + /* + * sanity check - broken line with invalid out of bound null width cells + * this can atm happen with deleting/inserting chars in inputhandler by "breaking" + * fullwidth pairs --> needs to be fixed after settling BufferLine impl + */ const line = new TestBufferLine(10, NULL_CELL_DATA, false); assert.equal(line.translateToString(false, undefined, undefined, columns), ' '); assert.deepEqual(columns, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); @@ -500,8 +504,10 @@ describe('BufferLine', function(): void { const line = new TestBufferLine(3, NULL_CELL_DATA, false); line.addCodepointToCell(0, '\u0301'.charCodeAt(0), 0); const cell = line.loadCell(0, new CellData()); - // chars contains single combining char - // width is set to 1 + /* + * chars contains single combining char + * width is set to 1 + */ assert.deepEqual(cell.getAsCharData(), [DEFAULT_ATTR, '\u0301', 1, 0x0301]); // do not account a single combining char as combined assert.equal(cell.isCombined(), 0); @@ -513,8 +519,10 @@ describe('BufferLine', function(): void { line.setCell(0, cell); line.addCodepointToCell(0, '\u0301'.charCodeAt(0), 0); line.loadCell(0, cell); - // chars contains 3 chars - // width is set to 1 + /* + * chars contains 3 chars + * width is set to 1 + */ assert.deepEqual(cell.getAsCharData(), [123, 'e\u0301\u0301', 1, 0x0301]); // do not account a single combining char as combined assert.equal(cell.isCombined(), Content.IS_COMBINED_MASK); @@ -526,8 +534,10 @@ describe('BufferLine', function(): void { line.setCell(0, cell); line.addCodepointToCell(0, '\u0301'.charCodeAt(0), 0); line.loadCell(0, cell); - // chars contains 2 chars - // width is set to 1 + /* + * chars contains 2 chars + * width is set to 1 + */ assert.deepEqual(cell.getAsCharData(), [123, 'e\u0301', 1, 0x0301]); // do not account a single combining char as combined assert.equal(cell.isCombined(), Content.IS_COMBINED_MASK); diff --git a/src/common/buffer/BufferLine.ts b/src/common/buffer/BufferLine.ts index be200f112..0cef299e1 100644 --- a/src/common/buffer/BufferLine.ts +++ b/src/common/buffer/BufferLine.ts @@ -9,11 +9,13 @@ import { CellData } from 'common/buffer/CellData'; import { Attributes, BgFlags, CHAR_DATA_ATTR_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, Content, NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, WHITESPACE_CELL_CHAR } from 'common/buffer/Constants'; import { stringFromCodePoint } from 'common/input/TextDecoder'; -// Buffer memory layout: -// -// [0]: content `uint32_t` - wcwidth(2) comb(1) codepoint(21) -// [1]: fg `uint32_t` - flags(8) r(8) g(8) b(8) -// [2]: bg `uint32_t` - flags(8) r(8) g(8) b(8) +/* + * Buffer memory layout: + * + * [0]: content `uint32_t` - wcwidth(2) comb(1) codepoint(21) + * [1]: fg `uint32_t` - flags(8) r(8) g(8) b(8) + * [2]: bg `uint32_t` - flags(8) r(8) g(8) b(8) + */ const enum Constants { /** The number of 32 bit array indices taken by one cell. */ @@ -255,15 +257,19 @@ export class BufferLine implements IBufferLine { this._combined[index] += stringFromCodePoint(codePoint); } else { if (content & Content.CODEPOINT_MASK) { - // normal case for combining chars: - // - move current leading char + new one into combined string - // - set combined flag + /* + * normal case for combining chars: + * - move current leading char + new one into combined string + * - set combined flag + */ this._combined[index] = stringFromCodePoint(content & Content.CODEPOINT_MASK) + stringFromCodePoint(codePoint); content &= ~Content.CODEPOINT_MASK; // set codepoint in buffer to 0 content |= Content.IS_COMBINED_MASK; } else { - // should not happen - we actually have no data in the cell yet - // simply set the data in the cell buffer with a width of 1 + /* + * should not happen - we actually have no data in the cell yet + * simply set the data in the cell buffer with a width of 1 + */ content = codePoint | (1 << Content.WIDTH_SHIFT); } } @@ -318,9 +324,11 @@ export class BufferLine implements IBufferLine { } } - // handle fullwidth at pos: - // - reset pos-1 if wide char - // - reset pos if width==0 (previous second cell of a wide char) + /* + * handle fullwidth at pos: + * - reset pos-1 if wide char + * - reset pos if width==0 (previous second cell of a wide char) + */ if (pos && this.getWidth(pos - 1) === 2) { this.setCellFromCodepoint(pos - 1, 0, 1, fillCellData); } diff --git a/src/common/buffer/BufferReflow.ts b/src/common/buffer/BufferReflow.ts index 44aa0976f..5eaeae406 100644 --- a/src/common/buffer/BufferReflow.ts +++ b/src/common/buffer/BufferReflow.ts @@ -23,8 +23,10 @@ export interface INewLayoutResult { * @param reflowCursorLine Whether to reflow the line containing the cursor. */ 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 + /* + * 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[] = []; for (let y = 0; y < lines.length - 1; y++) { @@ -43,8 +45,10 @@ export function reflowLargerGetLinesToRemove(lines: CircularList, o } if (!reflowCursorLine) { - // If these lines contain the cursor don't touch them, the program will handle fixing up - // wrapped lines with the cursor + /* + * 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; @@ -180,8 +184,10 @@ export function reflowSmallerGetNewLineLengths(wrappedLines: BufferLine[], oldCo const newLineLengths: number[] = []; const cellsNeeded = wrappedLines.map((l, i) => getWrappedLineTrimmedLength(wrappedLines, i, oldCols)).reduce((p, c) => p + c); - // Use srcCol and srcLine to find the new wrapping point, use that to get the cellsAvailable and - // linesNeeded + /* + * Use srcCol and srcLine to find the new wrapping point, use that to get the cellsAvailable and + * linesNeeded + */ let srcCol = 0; let srcLine = 0; let cellsAvailable = 0; @@ -214,9 +220,11 @@ export function getWrappedLineTrimmedLength(lines: BufferLine[], i: number, cols if (i === lines.length - 1) { return lines[i].getTrimmedLength(); } - // 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] + /* + * 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] + */ const endsInNull = !(lines[i].hasContent(cols - 1)) && lines[i].getWidth(cols - 1) === 1; const followingLineStartsWithWide = lines[i + 1].getWidth(0) === 2; if (endsInNull && followingLineStartsWithWide) { diff --git a/src/common/buffer/BufferSet.ts b/src/common/buffer/BufferSet.ts index 32a4bf3b4..2bad2171f 100644 --- a/src/common/buffer/BufferSet.ts +++ b/src/common/buffer/BufferSet.ts @@ -43,8 +43,10 @@ export class BufferSet extends Disposable implements IBufferSet { this._normalBuffer.value = this._normal; this._normal.fillViewportRows(); - // The alt buffer should never have scrollback. - // See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer + /* + * The alt buffer should never have scrollback. + * See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer + */ this._alt = new Buffer(false, this._optionsService, this._bufferService, this._logService); this._altBuffer.value = this._alt; this._activeBuffer = this._normal; @@ -86,9 +88,11 @@ export class BufferSet extends Disposable implements IBufferSet { } this._normal.x = this._alt.x; this._normal.y = this._alt.y; - // The alt buffer should always be cleared when we switch to the normal - // buffer. This frees up memory since the alt buffer should always be new - // when activated. + /* + * The alt buffer should always be cleared when we switch to the normal + * buffer. This frees up memory since the alt buffer should always be new + * when activated. + */ this._alt.clearAllMarkers(); this._alt.clear(); this._activeBuffer = this._normal; @@ -105,8 +109,10 @@ export class BufferSet extends Disposable implements IBufferSet { if (this._activeBuffer === this._alt) { return; } - // Since the alt buffer is always cleared when the normal buffer is - // activated, we want to fill it when switching to it. + /* + * Since the alt buffer is always cleared when the normal buffer is + * activated, we want to fill it when switching to it. + */ this._alt.fillViewportRows(fillAttr); this._alt.x = this._normal.x; this._alt.y = this._normal.y; diff --git a/src/common/buffer/CellData.ts b/src/common/buffer/CellData.ts index 43c4c594b..29e4a0f50 100644 --- a/src/common/buffer/CellData.ts +++ b/src/common/buffer/CellData.ts @@ -65,8 +65,10 @@ export class CellData extends AttributeData implements ICellData { } else if (value[CHAR_DATA_CHAR_INDEX].length === 2) { const code = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0); - // if the 2-char string is a surrogate create single codepoint - // everything else is combined + /* + * if the 2-char string is a surrogate create single codepoint + * everything else is combined + */ if (0xD800 <= code && code <= 0xDBFF) { const second = value[CHAR_DATA_CHAR_INDEX].charCodeAt(1); if (0xDC00 <= second && second <= 0xDFFF) { diff --git a/src/common/input/Keyboard.test.ts b/src/common/input/Keyboard.test.ts index 47f516f0f..4e47cbce0 100644 --- a/src/common/input/Keyboard.test.ts +++ b/src/common/input/Keyboard.test.ts @@ -123,8 +123,10 @@ describe('Keyboard', () => { }); describe('On non-macOS platforms', () => { - // Evalueate alt + arrow key movement, which is a feature of terminal emulators but not VT100 - // http://unix.stackexchange.com/a/108106 + /* + * Evalueate alt + arrow key movement, which is a feature of terminal emulators but not VT100 + * http://unix.stackexchange.com/a/108106 + */ it('should return \\x1b[1;3D for alt+left', () => { assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 37 }, { isMac: false }).key, '\x1b[1;3D'); // CSI 1;3 D }); diff --git a/src/common/input/Keyboard.ts b/src/common/input/Keyboard.ts index 545b436c8..54bc4a27e 100644 --- a/src/common/input/Keyboard.ts +++ b/src/common/input/Keyboard.ts @@ -43,8 +43,10 @@ export function evaluateKeyboardEvent( ): IKeyboardResult { const result: IKeyboardResult = { type: KeyboardResultType.SEND_KEY, - // Whether to cancel event propagation (NOTE: this may not be needed since the event is - // canceled at the end of keyDown + /* + * Whether to cancel event propagation (NOTE: this may not be needed since the event is + * canceled at the end of keyDown + */ cancel: false, // The new key even to emit key: undefined @@ -100,8 +102,10 @@ export function evaluateKeyboardEvent( case 13: // return/enter if (ev.key === 'c' && ev.ctrlKey) { - // HACK: Safari on iPad, iOS, AppleVisionPro sends key 13 when typing ctrl-c on hardware - // keyboard + /* + * HACK: Safari on iPad, iOS, AppleVisionPro sends key 13 when typing ctrl-c on hardware + * keyboard + */ result.key = C0.ETX; } else { result.key = ev.altKey ? C0.ESC + C0.CR : C0.CR; @@ -171,8 +175,10 @@ export function evaluateKeyboardEvent( case 45: // insert if (!ev.shiftKey && !ev.ctrlKey) { - // or + are used to - // copy-paste on some systems. + /* + * or + are used to + * copy-paste on some systems. + */ result.key = C0.ESC + '[2~'; } break; @@ -346,11 +352,13 @@ export function evaluateKeyboardEvent( } else if (ev.keyCode === 32) { result.key = C0.ESC + (ev.ctrlKey ? C0.NUL : ' '); } else if (ev.key === 'Dead' && ev.code.startsWith('Key')) { - // Reference: https://github.com/xtermjs/xterm.js/issues/3725 - // Alt will produce a "dead key" (initate composition) with some - // of the letters in US layout (e.g. N/E/U). - // It's safe to match against Key* since no other `code` values begin with "Key". - // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values#code_values_on_mac + /* + * Reference: https://github.com/xtermjs/xterm.js/issues/3725 + * Alt will produce a "dead key" (initate composition) with some + * of the letters in US layout (e.g. N/E/U). + * It's safe to match against Key* since no other `code` values begin with "Key". + * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values#code_values_on_mac + */ let keyString = ev.code.slice(3, 4); if (!ev.shiftKey) { keyString = keyString.toLowerCase(); @@ -363,8 +371,10 @@ export function evaluateKeyboardEvent( result.type = KeyboardResultType.SELECT_ALL; } } else if (ev.key && !ev.ctrlKey && !ev.altKey && !ev.metaKey && ev.keyCode >= 48 && ev.key.length === 1) { - // Include only keys that that result in a _single_ character; don't include num lock, - // volume up, etc. + /* + * Include only keys that that result in a _single_ character; don't include num lock, + * volume up, etc. + */ result.key = ev.key; } else if (ev.key && ev.ctrlKey && ev.shiftKey) { switch (ev.code) { diff --git a/src/common/input/KittyKeyboard.test.ts b/src/common/input/KittyKeyboard.test.ts index 2a832d75f..44c4ae2bb 100644 --- a/src/common/input/KittyKeyboard.test.ts +++ b/src/common/input/KittyKeyboard.test.ts @@ -40,8 +40,10 @@ describe('KittyKeyboard', () => { const flags = KittyKeyboardFlags.DISAMBIGUATE_ESCAPE_CODES; it('shift+letter sends plain character in DISAMBIGUATE mode', () => { - // Kitty spec: DISAMBIGUATE only encodes keys ambiguous in legacy encoding - // Shift+a → "A" is not ambiguous, so send plain "A" + /* + * Kitty spec: DISAMBIGUATE only encodes keys ambiguous in legacy encoding + * Shift+a → "A" is not ambiguous, so send plain "A" + */ const result = kitty.evaluate(createEvent({ key: 'A', shiftKey: true }), flags); assert.strictEqual(result.key, 'A'); }); @@ -554,8 +556,10 @@ describe('KittyKeyboard', () => { }); }); - // Enabling REPORT_EVENT_TYPES without DISAMBIGUATE_ESCAPE_CODES doesn't really make sense and - // isn't specified in the spec, but press and repeat events shouldn't get swallowed. + /* + * Enabling REPORT_EVENT_TYPES without DISAMBIGUATE_ESCAPE_CODES doesn't really make sense and + * isn't specified in the spec, but press and repeat events shouldn't get swallowed. + */ describe('REPORT_EVENT_TYPES flag without DISAMBIGUATE_ESCAPE_CODES', () => { const flags = KittyKeyboardFlags.REPORT_EVENT_TYPES; diff --git a/src/common/input/KittyKeyboard.ts b/src/common/input/KittyKeyboard.ts index ff57b4f89..658d4e0d9 100644 --- a/src/common/input/KittyKeyboard.ts +++ b/src/common/input/KittyKeyboard.ts @@ -437,10 +437,12 @@ export class KittyKeyboard { return result; } - // Spec § "Report all keys as escape codes": "Additionally, with this mode, - // events for pressing modifier keys are reported." — i.e. *without* this - // mode, modifier-key press events are suppressed. Kitty's is_modifier_key() - // treats CapsLock/NumLock/ScrollLock as modifier keys for this rule. + /* + * Spec § "Report all keys as escape codes": "Additionally, with this mode, + * events for pressing modifier keys are reported." — i.e. *without* this + * mode, modifier-key press events are suppressed. Kitty's is_modifier_key() + * treats CapsLock/NumLock/ScrollLock as modifier keys for this rule. + */ if (this._isLockKey(ev) && !(flags & KittyKeyboardFlags.REPORT_ALL_KEYS_AS_ESCAPE_CODES)) { return result; } @@ -474,8 +476,10 @@ export class KittyKeyboard { // Special handling for Enter/Tab/Backspace. const specialKey = keyCode === 13 || keyCode === 9 || keyCode === 127; - // Per spec, Enter/Tab/Backspace will not have release events unless "Report all keys as escape - // codes" is also set. + /* + * Per spec, Enter/Tab/Backspace will not have release events unless "Report all keys as escape + * codes" is also set. + */ if (specialKey && eventType === KittyKeyboardEventType.RELEASE && !(flags & KittyKeyboardFlags.REPORT_ALL_KEYS_AS_ESCAPE_CODES)) { return result; } @@ -485,14 +489,18 @@ export class KittyKeyboard { const useCsiU = !!( flags & KittyKeyboardFlags.REPORT_ALL_KEYS_AS_ESCAPE_CODES || (reportEventTypes && eventType === KittyKeyboardEventType.RELEASE) || - // Enabling REPORT_EVENT_TYPES without DISAMBIGUATE_ESCAPE_CODES doesn't really make sense, so - // just make REPORT_EVENT_TYPES imply DISAMBIGUATE_ESCAPE_CODES here for simplicity. - // See: https://github.com/kovidgoyal/kitty/issues/9999 + /* + * Enabling REPORT_EVENT_TYPES without DISAMBIGUATE_ESCAPE_CODES doesn't really make sense, so + * just make REPORT_EVENT_TYPES imply DISAMBIGUATE_ESCAPE_CODES here for simplicity. + * See: https://github.com/kovidgoyal/kitty/issues/9999 + */ ((flags & KittyKeyboardFlags.DISAMBIGUATE_ESCAPE_CODES || reportEventTypes) && ( - // Per spec, Enter/Tab/Backspace "still generate the same bytes as in legacy mode" and - // consider space to be a text-generating key, so these skip the isFunc fast-path and only - // get CSI u when modifiers are present (handled below). + /* + * Per spec, Enter/Tab/Backspace "still generate the same bytes as in legacy mode" and + * consider space to be a text-generating key, so these skip the isFunc fast-path and only + * get CSI u when modifiers are present (handled below). + */ (isFunc && !specialKey) || ( (modifiers > 0 && ev.key.length !== 1) || diff --git a/src/common/input/TextDecoder.ts b/src/common/input/TextDecoder.ts index 7ec9c7cd2..cc503166d 100644 --- a/src/common/input/TextDecoder.ts +++ b/src/common/input/TextDecoder.ts @@ -28,11 +28,13 @@ export function utf32ToString(data: Uint32Array, start: number = 0, end: number for (let i = start; i < end; ++i) { let codepoint = data[i]; if (codepoint > 0xFFFF) { - // JS strings are encoded as UTF16, thus a non BMP codepoint gets converted into a surrogate - // pair conversion rules: - // - subtract 0x10000 from code point, leaving a 20 bit number - // - add high 10 bits to 0xD800 --> first surrogate - // - add low 10 bits to 0xDC00 --> second surrogate + /* + * JS strings are encoded as UTF16, thus a non BMP codepoint gets converted into a surrogate + * pair conversion rules: + * - subtract 0x10000 from code point, leaving a 20 bit number + * - add high 10 bits to 0xD800 --> first surrogate + * - add low 10 bits to 0xDC00 --> second surrogate + */ codepoint -= 0x10000; result += String.fromCharCode((codepoint >> 10) + 0xD800) + String.fromCharCode((codepoint % 0x400) + 0xDC00); } else { diff --git a/src/common/input/UnicodeV6.test.ts b/src/common/input/UnicodeV6.test.ts index 98dc97dc2..95c2f6e2f 100644 --- a/src/common/input/UnicodeV6.test.ts +++ b/src/common/input/UnicodeV6.test.ts @@ -12,8 +12,10 @@ it('wcwidth should match all values from the old implementation', function(): vo // old implementation const wcwidthOld = (function(opts: {nul: number, control: number}): (ucs: number) => number { - // extracted from https://www.cl.cam.ac.uk/%7Emgk25/ucs/wcwidth.c - // combining characters + /* + * extracted from https://www.cl.cam.ac.uk/%7Emgk25/ucs/wcwidth.c + * combining characters + */ const COMBINING_BMP = [ [0x0300, 0x036F], [0x0483, 0x0486], [0x0488, 0x0489], [0x0591, 0x05BD], [0x05BF, 0x05BF], [0x05C1, 0x05C2], @@ -149,18 +151,20 @@ it('wcwidth should match all values from the old implementation', function(): vo } return table; } - // get width from lookup table - // position in container : num / CODEPOINTS_PER_ITEM - // ==> n = table[Math.floor(num / 16)] - // ==> n = table[num >> 4] - // 16 codepoints per number: FFEEDDCCBBAA99887766554433221100 - // position in number : (num % CODEPOINTS_PER_ITEM) * BITWIDTH - // ==> m = (n % 16) * 2 - // ==> m = (num & 15) << 1 - // right shift to position m - // ==> n = n >> m e.g. m=12 000000000000FFEEDDCCBBAA99887766 - // we are only interested in 2 LSBs, cut off higher bits - // ==> n = n & 3 e.g. 000000000000000000000000000000XX + /* + * get width from lookup table + * position in container : num / CODEPOINTS_PER_ITEM + * ==> n = table[Math.floor(num / 16)] + * ==> n = table[num >> 4] + * 16 codepoints per number: FFEEDDCCBBAA99887766554433221100 + * position in number : (num % CODEPOINTS_PER_ITEM) * BITWIDTH + * ==> m = (n % 16) * 2 + * ==> m = (num & 15) << 1 + * right shift to position m + * ==> n = n >> m e.g. m=12 000000000000FFEEDDCCBBAA99887766 + * we are only interested in 2 LSBs, cut off higher bits + * ==> n = n & 3 e.g. 000000000000000000000000000000XX + */ return (num: number): number => { num |= 0; // get asm.js like optimization under V8 if (num < 32) { diff --git a/src/common/input/UnicodeV6.ts b/src/common/input/UnicodeV6.ts index 83265f705..4b6bd55c0 100644 --- a/src/common/input/UnicodeV6.ts +++ b/src/common/input/UnicodeV6.ts @@ -94,8 +94,10 @@ export class UnicodeV6 implements IUnicodeVersionProvider { table.fill(0, 1, 32); table.fill(0, 0x7f, 0xa0); - // apply wide char rules first - // wide chars + /* + * apply wide char rules first + * wide chars + */ table.fill(2, 0x1100, 0x1160); table[0x2329] = 2; table[0x232a] = 2; @@ -109,11 +111,13 @@ export class UnicodeV6 implements IUnicodeVersionProvider { table.fill(2, 0xff00, 0xff61); table.fill(2, 0xffe0, 0xffe7); - // apply combining last to ensure we overwrite - // wrongly wide set chars: - // the original algo evals combining first and falls - // through to wide check so we simply do here the opposite - // combining 0 + /* + * apply combining last to ensure we overwrite + * wrongly wide set chars: + * the original algo evals combining first and falls + * through to wide check so we simply do here the opposite + * combining 0 + */ for (let r = 0; r < BMP_COMBINING.length; ++r) { table.fill(0, BMP_COMBINING[r][0], BMP_COMBINING[r][1] + 1); } diff --git a/src/common/input/Win32InputMode.ts b/src/common/input/Win32InputMode.ts index 72907836d..23f6ade0f 100644 --- a/src/common/input/Win32InputMode.ts +++ b/src/common/input/Win32InputMode.ts @@ -198,8 +198,10 @@ export class Win32InputMode { * Returns 0 for non-character keys. */ private _getUnicodeChar(ev: IKeyboardEvent): number { - // Handle special keys that produce control characters - // Ctrl modifies some of these: Ctrl+Enter=LF, Ctrl+Backspace=DEL + /* + * Handle special keys that produce control characters + * Ctrl modifies some of these: Ctrl+Enter=LF, Ctrl+Backspace=DEL + */ if (ev.ctrlKey && !ev.altKey && !ev.metaKey) { if (ev.key === 'Enter') { return 0x0A; // Line feed (Ctrl+Enter) @@ -245,9 +247,11 @@ export class Win32InputMode { state |= Win32ControlKeyState.SHIFT_PRESSED; } - // Note: We can't distinguish left/right for ctrl/alt in standard browser events, - // so we use the generic pressed flags. The right-side flags are used when - // we can detect them (e.g., via code property). + /* + * Note: We can't distinguish left/right for ctrl/alt in standard browser events, + * so we use the generic pressed flags. The right-side flags are used when + * we can detect them (e.g., via code property). + */ if (ev.ctrlKey) { if (ev.code === 'ControlRight') { state |= Win32ControlKeyState.RIGHT_CTRL_PRESSED; diff --git a/src/common/input/WriteBuffer.ts b/src/common/input/WriteBuffer.ts index b936c9dbf..888db9ac5 100644 --- a/src/common/input/WriteBuffer.ts +++ b/src/common/input/WriteBuffer.ts @@ -90,12 +90,16 @@ export class WriteBuffer extends Disposable { * @deprecated Unreliable, to be removed soon. */ public writeSync(data: string | Uint8Array, maxSubsequentCalls?: number): void { - // stop writeSync recursions with maxSubsequentCalls argument - // This is dangerous to use as it will lose the current data chunk - // and return immediately. + /* + * stop writeSync recursions with maxSubsequentCalls argument + * This is dangerous to use as it will lose the current data chunk + * and return immediately. + */ if (maxSubsequentCalls !== undefined && this._syncCalls > maxSubsequentCalls) { - // comment next line if a whole loop block should only contain x `writeSync` calls - // (total flat vs. deep nested limit) + /* + * comment next line if a whole loop block should only contain x `writeSync` calls + * (total flat vs. deep nested limit) + */ this._syncCalls = 0; return; } @@ -112,18 +116,22 @@ export class WriteBuffer extends Disposable { } this._isSyncWriting = true; - // force sync processing on pending data chunks to avoid in-band data scrambling - // does the same as innerWrite but without event loop - // we have to do it here as single loop steps to not corrupt loop subject - // by another writeSync call triggered from _action + /* + * force sync processing on pending data chunks to avoid in-band data scrambling + * does the same as innerWrite but without event loop + * we have to do it here as single loop steps to not corrupt loop subject + * by another writeSync call triggered from _action + */ let chunk: string | Uint8Array | undefined; while (chunk = this._writeBuffer.shift()) { this._action(chunk); const cb = this._callbacks.shift(); if (cb) cb(); } - // reset to avoid reprocessing of chunks with scheduled innerWrite call - // stopping scheduled innerWrite by offset > length condition + /* + * reset to avoid reprocessing of chunks with scheduled innerWrite call + * stopping scheduled innerWrite by offset > length condition + */ this._pendingData = 0; this._bufferOffset = 0x7FFFFFFF; @@ -141,9 +149,11 @@ export class WriteBuffer extends Disposable { if (!this._writeBuffer.length) { this._bufferOffset = 0; - // If this is the first write call after the user has done some input, - // parse it immediately to minimize input latency, - // otherwise schedule for the next event + /* + * If this is the first write call after the user has done some input, + * parse it immediately to minimize input latency, + * otherwise schedule for the next event + */ if (this._didUserInput) { this._didUserInput = false; this._pendingData += data.length; @@ -234,15 +244,19 @@ export class WriteBuffer extends Disposable { * throughput by eval'ing `startTime` upfront pulling at least one more chunk into the * current microtask queue (executed before setTimeout). */ - // const continuation: (r: boolean) => void = performance.now() - startTime >= - // Constants.WRITE_TIMEOUT_MS - // ? r => setTimeout(() => this._innerWrite(0, r)) - // : r => this._innerWrite(startTime, r); + /* + * const continuation: (r: boolean) => void = performance.now() - startTime >= + * Constants.WRITE_TIMEOUT_MS + * ? r => setTimeout(() => this._innerWrite(0, r)) + * : r => this._innerWrite(startTime, r); + */ - // Handle exceptions synchronously to current band position, idea: - // 1. spawn a single microtask which we allow to throw hard - // 2. spawn a promise immediately resolving to `true` - // (executed on the same queue, thus properly aligned before continuation happens) + /* + * Handle exceptions synchronously to current band position, idea: + * 1. spawn a single microtask which we allow to throw hard + * 2. spawn a promise immediately resolving to `true` + * (executed on the same queue, thus properly aligned before continuation happens) + */ result.catch(err => { queueMicrotask(() => {throw err;}); return Promise.resolve(false); @@ -260,8 +274,10 @@ export class WriteBuffer extends Disposable { } } if (this._writeBuffer.length > this._bufferOffset) { - // Allow renderer to catch up before processing the next batch - // trim already processed chunks if we are above threshold + /* + * Allow renderer to catch up before processing the next batch + * trim already processed chunks if we are above threshold + */ if (this._bufferOffset > Constants.WRITE_BUFFER_LENGTH_THRESHOLD) { this._writeBuffer = this._writeBuffer.slice(this._bufferOffset); this._callbacks = this._callbacks.slice(this._bufferOffset); diff --git a/src/common/input/XParseColor.ts b/src/common/input/XParseColor.ts index ae4a3bcae..2f4a79dc8 100644 --- a/src/common/input/XParseColor.ts +++ b/src/common/input/XParseColor.ts @@ -50,9 +50,11 @@ export function parseColor(data: string): [number, number, number] | undefined { } } - // Named colors are currently not supported due to the large addition to the xterm.js bundle size - // they would add. In order to support named colors, we would need some way of optionally loading - // additional payloads so startup/download time is not bloated (see #3530). + /* + * Named colors are currently not supported due to the large addition to the xterm.js bundle size + * they would add. In order to support named colors, we would need some way of optionally loading + * additional payloads so startup/download time is not bloated (see #3530). + */ } // pad hex output to requested bit width diff --git a/src/common/parser/ApcParser.ts b/src/common/parser/ApcParser.ts index 8f921f8cb..453c71110 100644 --- a/src/common/parser/ApcParser.ts +++ b/src/common/parser/ApcParser.ts @@ -181,8 +181,10 @@ export class ApcHandler implements IApcHandler { } else if (success) { ret = this._handler(this._data); if (ret instanceof Promise) { - // need to hold data until `ret` got resolved - // dont care for errors, data will be freed anyway on next start + /* + * need to hold data until `ret` got resolved + * dont care for errors, data will be freed anyway on next start + */ return ret.then(res => { this._data = ''; this._hitLimit = false; diff --git a/src/common/parser/DcsParser.ts b/src/common/parser/DcsParser.ts index 692200230..849b82709 100644 --- a/src/common/parser/DcsParser.ts +++ b/src/common/parser/DcsParser.ts @@ -147,10 +147,12 @@ export class DcsHandler implements IDcsHandler { constructor(private _handler: (data: string, params: IParams) => boolean | Promise) { } public hook(params: IParams): void { - // since we need to preserve params until `unhook`, we have to clone it - // (only borrowed from parser and spans multiple parser states) - // perf optimization: - // clone only, if we have non empty params, otherwise stick with default + /* + * since we need to preserve params until `unhook`, we have to clone it + * (only borrowed from parser and spans multiple parser states) + * perf optimization: + * clone only, if we have non empty params, otherwise stick with default + */ this._params = (params.length > 1 || params.params[0]) ? params.clone() : EMPTY_PARAMS; this._data = ''; this._hitLimit = false; @@ -174,8 +176,10 @@ export class DcsHandler implements IDcsHandler { } else if (success) { ret = this._handler(this._data, this._params); if (ret instanceof Promise) { - // need to hold data and params until `ret` got resolved - // dont care for errors, data will be freed anyway on next start + /* + * need to hold data and params until `ret` got resolved + * dont care for errors, data will be freed anyway on next start + */ return ret.then(res => { this._params = EMPTY_PARAMS; this._data = ''; diff --git a/src/common/parser/EscapeSequenceParser.test.ts b/src/common/parser/EscapeSequenceParser.test.ts index 2d5a04df7..17cc37ee3 100644 --- a/src/common/parser/EscapeSequenceParser.test.ts +++ b/src/common/parser/EscapeSequenceParser.test.ts @@ -2065,8 +2065,10 @@ async function throwsAsync(fn: () => Promise, message?: string | undefined) } describe('EscapeSequenceParser - async', () => { - // sequences: SGR 1;31 | hello SP | ESC %G | wor | ESC E | ld! | SGR 0 | EXE \r\n | $> | DCS 1;2 a [xyz] ST | OSC 1;foo=bar ST | APC X abc ST | FIN - // needed handlers: CSI m, PRINT, ESC %G, ESC E, EXE \r, EXE \n, OSC 1, APC X + /* + * sequences: SGR 1;31 | hello SP | ESC %G | wor | ESC E | ld! | SGR 0 | EXE \r\n | $> | DCS 1;2 a [xyz] ST | OSC 1;foo=bar ST | APC X abc ST | FIN + * needed handlers: CSI m, PRINT, ESC %G, ESC E, EXE \r, EXE \n, OSC 1, APC X + */ const INPUT = '\x1b[1;31mhello \x1b%Gwor\x1bEld!\x1b[0m\r\n$>\x1bP1;2axyz\x1b\\\x1b]1;foo=bar\x1b\\\x1b_Xabc\x1b\\FIN'; let RESULT: any[]; let parser: TestEscapeSequenceParser; @@ -2155,8 +2157,10 @@ describe('EscapeSequenceParser - async', () => { it('sync parse call does not work anymore', () => { assert.notEqual(!parseSync(parser, INPUT), true); assert.notDeepEqual(callstack, RESULT); - // due to sync calling we should save exactly one saved stack - // proper continuation is not possible anymore, as we lost the promise resolve value + /* + * due to sync calling we should save exactly one saved stack + * proper continuation is not possible anymore, as we lost the promise resolve value + */ assert.equal(parser.trackedStack.length, 1); }); it('improper continuation should throw', async () => { @@ -2222,8 +2226,10 @@ describe('EscapeSequenceParser - async', () => { // split to single char input for (let i = 0; i < INPUT.length; ++i) { - // Note: a single fully awaited parse call always ends in sync mode, - // which re-enables faster sync processing in the higher up callstack + /* + * Note: a single fully awaited parse call always ends in sync mode, + * which re-enables faster sync processing in the higher up callstack + */ await parseP(parser, INPUT[i]); } assert.deepEqual(callstack, RESULT); diff --git a/src/common/parser/EscapeSequenceParser.ts b/src/common/parser/EscapeSequenceParser.ts index d944112db..be4877766 100644 --- a/src/common/parser/EscapeSequenceParser.ts +++ b/src/common/parser/EscapeSequenceParser.ts @@ -15,20 +15,22 @@ import { ApcParser } from 'common/parser/ApcParser'; /** * VT commands done by the parser */ -// @vt: #Y ESC CSI "Control Sequence Introducer" "ESC [" "Start of a CSI sequence." -// @vt: #Y ESC OSC "Operating System Command" "ESC ]" "Start of an OSC sequence." -// @vt: #Y ESC DCS "Device Control String" "ESC P" "Start of a DCS sequence." -// @vt: #Y ESC ST "String Terminator" "ESC \" "Terminator used for string type sequences." -// @vt: #Y ESC PM "Privacy Message" "ESC ^" "Start of a privacy message." -// @vt: #Y ESC APC "Application Program Command" "ESC _" "Start of an APC sequence." -// @vt: #Y C1 CSI "Control Sequence Introducer" "\x9B" "Start of a CSI sequence." -// @vt: #Y C1 OSC "Operating System Command" "\x9D" "Start of an OSC sequence." -// @vt: #Y C1 DCS "Device Control String" "\x90" "Start of a DCS sequence." -// @vt: #Y C1 ST "String Terminator" "\x9C" "Terminator used for string type sequences." -// @vt: #Y C1 PM "Privacy Message" "\x9E" "Start of a privacy message." -// @vt: #Y C1 APC "Application Program Command" "\x9F" "Start of an APC sequence." -// @vt: #Y C0 NUL "Null" "\0, \x00" "NUL is ignored." -// @vt: #Y C0 ESC "Escape" "\e, \x1B" "Start of a sequence. Cancels any other sequence." +/* + * @vt: #Y ESC CSI "Control Sequence Introducer" "ESC [" "Start of a CSI sequence." + * @vt: #Y ESC OSC "Operating System Command" "ESC ]" "Start of an OSC sequence." + * @vt: #Y ESC DCS "Device Control String" "ESC P" "Start of a DCS sequence." + * @vt: #Y ESC ST "String Terminator" "ESC \" "Terminator used for string type sequences." + * @vt: #Y ESC PM "Privacy Message" "ESC ^" "Start of a privacy message." + * @vt: #Y ESC APC "Application Program Command" "ESC _" "Start of an APC sequence." + * @vt: #Y C1 CSI "Control Sequence Introducer" "\x9B" "Start of a CSI sequence." + * @vt: #Y C1 OSC "Operating System Command" "\x9D" "Start of an OSC sequence." + * @vt: #Y C1 DCS "Device Control String" "\x90" "Start of a DCS sequence." + * @vt: #Y C1 ST "String Terminator" "\x9C" "Terminator used for string type sequences." + * @vt: #Y C1 PM "Privacy Message" "\x9E" "Start of a privacy message." + * @vt: #Y C1 APC "Application Program Command" "\x9F" "Start of an APC sequence." + * @vt: #Y C0 NUL "Null" "\0, \x00" "NUL is ignored." + * @vt: #Y C0 ESC "Escape" "\e, \x1B" "Start of a sequence. Cancels any other sequence." + */ /** * Table values are generated like this: @@ -95,8 +97,10 @@ const NON_ASCII_PRINTABLE = 0xA0; * Taken from https://vt100.net/emu/dec_ansi_parser. */ export const VT500_TRANSITION_TABLE = (function (): TransitionTable { - // table size: - // (ParserState.STATE_LENGTH - 1) << TableAccess.INDEX_STATE_SHIFT | NON_ASCII_PRINTABLE + 1 + /* + * table size: + * (ParserState.STATE_LENGTH - 1) << TableAccess.INDEX_STATE_SHIFT | NON_ASCII_PRINTABLE + 1 + */ const table: TransitionTable = new TransitionTable(4257); // range macro for byte @@ -500,9 +504,11 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP this._params.resetZdm(); this._collect = 0; this.precedingJoinState = 0; - // abort pending continuation from async handler - // Here the RESET type indicates, that the next parse call will - // ignore any saved stack, instead continues sync with next codepoint from GROUND + /* + * abort pending continuation from async handler + * Here the RESET type indicates, that the next parse call will + * ignore any saved stack, instead continues sync with next codepoint from GROUND + */ if (this._parseStack.state !== ParserStackType.NONE) { this._parseStack.state = ParserStackType.RESET; this._parseStack.handlers = []; // also release handlers ref @@ -579,8 +585,10 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP // resume from async handler if (this._parseStack.state) { - // allow sync parser reset even in continuation mode - // Note: can be used to recover parser from improper continuation error below + /* + * allow sync parser reset even in continuation mode + * Note: can be used to recover parser from improper continuation error below + */ if (this._parseStack.state === ParserStackType.RESET) { this._parseStack.state = ParserStackType.NONE; start = this._parseStack.chunkPos + 1; // continue with next codepoint in GROUND @@ -605,9 +613,11 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP throw new Error('improper continuation due to previous async handler, giving up parsing'); } - // we have to resume the old handler loop if: - // - return value of the promise was `false` - // - handlers are not exhausted yet + /* + * we have to resume the old handler loop if: + * - return value of the promise was `false` + * - handlers are not exhausted yet + */ const handlers = this._parseStack.handlers; let handlerPos = this._parseStack.handlerPos - 1; switch (this._parseStack.state) { @@ -794,8 +804,10 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP const handlers = this._csiHandlers[this._collect << 8 | code]; let j = handlers ? handlers.length - 1 : -1; for (; j >= 0; j--) { - // true means success and to stop bubbling - // a promise indicates an async handler that needs to finish before progressing + /* + * true means success and to stop bubbling + * a promise indicates an async handler that needs to finish before progressing + */ handlerResult = handlers[j](this._params); if (handlerResult === true) { break; @@ -833,8 +845,10 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP const handlersEsc = this._escHandlers[this._collect << 8 | code]; let jj = handlersEsc ? handlersEsc.length - 1 : -1; for (; jj >= 0; jj--) { - // true means success and to stop bubbling - // a promise indicates an async handler that needs to finish before progressing + /* + * true means success and to stop bubbling + * a promise indicates an async handler that needs to finish before progressing + */ handlerResult = handlersEsc[jj](); if (handlerResult === true) { break; @@ -856,8 +870,10 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP this._dcsParser.hook(this._collect << 8 | code, this._params); break; case ParserAction.DCS_PUT: - // inner loop - exit DCS_PUT: 0x18, 0x1a, 0x1b, 0x7f, 0x80 - 0x9f - // unhook triggered by: 0x1b, 0x9c (success) and 0x18, 0x1a (abort) + /* + * inner loop - exit DCS_PUT: 0x18, 0x1a, 0x1b, 0x7f, 0x80 - 0x9f + * unhook triggered by: 0x1b, 0x9c (success) and 0x18, 0x1a (abort) + */ for (let j = i + 1; ; ++j) { if (j >= length || (code = data[j]) === 0x18 || code === 0x1a || code === 0x1b || (code > 0x7f && code < NON_ASCII_PRINTABLE)) { this._dcsParser.put(data, i, j); @@ -905,8 +921,10 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP this._apcParser.start(this._collect << 8 | code); break; case ParserAction.APC_PUT: - // inner loop - exit APC_PUT: 0x18, 0x1a, 0x1b, 0x9c - // allowed: 00/08 .. 00/13, 02/00 .. 07/14 + NON_ASCII_PRINTABLE + /* + * inner loop - exit APC_PUT: 0x18, 0x1a, 0x1b, 0x9c + * allowed: 00/08 .. 00/13, 02/00 .. 07/14 + NON_ASCII_PRINTABLE + */ for (let j = i + 1; ; ++j) { if (j < length && ( (data[j] >= 0x20 && data[j] < 0x7f) || (data[j] >= 0x08 && data[j] < 0x0e) || data[j] >= NON_ASCII_PRINTABLE diff --git a/src/common/parser/OscParser.ts b/src/common/parser/OscParser.ts index 1f0c8cb23..d348f483b 100644 --- a/src/common/parser/OscParser.ts +++ b/src/common/parser/OscParser.ts @@ -133,9 +133,11 @@ export class OscParser implements IOscParser { } // do nothing if command was faulty if (this._state !== OscState.ABORT) { - // if we are still in ID state and get an early end - // means that the command has no payload thus we still have - // to announce START and send END right after + /* + * if we are still in ID state and get an early end + * means that the command has no payload thus we still have + * to announce START and send END right after + */ if (this._state === OscState.ID) { this._start(); } @@ -166,9 +168,11 @@ export class OscParser implements IOscParser { } j--; } - // cleanup left over handlers - // we always have to call .end for proper cleanup, - // here we use `success` to indicate whether a handler should execute + /* + * cleanup left over handlers + * we always have to call .end for proper cleanup, + * here we use `success` to indicate whether a handler should execute + */ for (; j >= 0; j--) { handlerResult = this._active[j].end(false); if (handlerResult instanceof Promise) { @@ -222,8 +226,10 @@ export class OscHandler implements IOscHandler { } else if (success) { ret = this._handler(this._data); if (ret instanceof Promise) { - // need to hold data until `ret` got resolved - // dont care for errors, data will be freed anyway on next start + /* + * need to hold data until `ret` got resolved + * dont care for errors, data will be freed anyway on next start + */ return ret.then(res => { this._data = ''; this._hitLimit = false; diff --git a/src/common/services/BufferService.ts b/src/common/services/BufferService.ts index 06ac6b10a..ecf71eaf8 100644 --- a/src/common/services/BufferService.ts +++ b/src/common/services/BufferService.ts @@ -103,22 +103,28 @@ export class BufferService extends Disposable implements IBufferService { buffer.ydisp++; } } else { - // When the buffer is full and the user has scrolled up, keep the text - // stable unless ydisp is right at the top + /* + * When the buffer is full and the user has scrolled up, keep the text + * stable unless ydisp is right at the top + */ if (this.isUserScrolling) { buffer.ydisp = Math.max(buffer.ydisp - 1, 0); } } } else { - // scrollTop is non-zero which means no line will be going to the - // scrollback, instead we can just shift them in-place. + /* + * scrollTop is non-zero which means no line will be going to the + * scrollback, instead we can just shift them in-place. + */ const scrollRegionHeight = bottomRow - topRow + 1 /* as it's zero-based */; buffer.lines.shiftElements(topRow + 1, scrollRegionHeight - 1, -1); buffer.lines.set(bottomRow, newLine.clone()); } - // Move the viewport to the bottom of the buffer unless the user is - // scrolling. + /* + * Move the viewport to the bottom of the buffer unless the user is + * scrolling. + */ if (!this.isUserScrolling) { buffer.ydisp = buffer.ybase; } diff --git a/src/common/services/InstantiationService.ts b/src/common/services/InstantiationService.ts index 7e7695485..f11ff7f6e 100644 --- a/src/common/services/InstantiationService.ts +++ b/src/common/services/InstantiationService.ts @@ -4,10 +4,12 @@ * * This was heavily inspired from microsoft/vscode's dependency injection system (MIT). */ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import { IInstantiationService, IServiceIdentifier } from 'common/services/Services'; import { getServiceDependencies } from 'common/services/ServiceRegistry'; diff --git a/src/common/services/LogService.ts b/src/common/services/LogService.ts index 8bc1e0aaa..eea09f47d 100644 --- a/src/common/services/LogService.ts +++ b/src/common/services/LogService.ts @@ -16,8 +16,10 @@ interface IConsole { warn: LogType; } -// console is available on both node.js and browser contexts but the common -// module doesn't depend on them so we need to explicitly declare it. +/* + * console is available on both node.js and browser contexts but the common + * module doesn't depend on them so we need to explicitly declare it. + */ declare const console: IConsole; const optionsKeyToLogLevel: { [key: string]: LogLevelEnum } = { diff --git a/src/common/services/MouseStateService.ts b/src/common/services/MouseStateService.ts index 21420460a..6316dbfc9 100644 --- a/src/common/services/MouseStateService.ts +++ b/src/common/services/MouseStateService.ts @@ -105,8 +105,10 @@ function eventCode(e: ICoreMouseEvent, isSGR: boolean): number { if (e.action === CoreMouseAction.MOVE) { code |= CoreMouseAction.MOVE; } else if (e.action === CoreMouseAction.UP && !isSGR) { - // special case - only SGR can report button on release - // all others have to go with NONE + /* + * special case - only SGR can report button on release + * all others have to go with NONE + */ code |= CoreMouseButton.NONE; } } @@ -126,10 +128,12 @@ const DEFAULT_ENCODINGS: { [key: string]: CoreMouseEncoding } = { */ DEFAULT: (e: ICoreMouseEvent) => { const params = [eventCode(e, false) + 32, e.col + 32, e.row + 32]; - // supress mouse report if we exceed addressible range - // Note this is handled differently by emulators - // - xterm: sends 0;0 coords instead - // - vte, konsole: no report + /* + * supress mouse report if we exceed addressible range + * Note this is handled differently by emulators + * - xterm: sends 0;0 coords instead + * - vte, konsole: no report + */ if (params[0] > 255 || params[1] > 255 || params[2] > 255) { return ''; } diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index ec647aaa5..252b38ef9 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -90,8 +90,10 @@ export class OptionsService extends Disposable implements IOptionsService { this.options = { ... defaultOptions }; this._setupOptions(); - // Clear out options that could link outside xterm.js as they could easily cause an embedder - // memory leak + /* + * Clear out options that could link outside xterm.js as they could easily cause an embedder + * memory leak + */ this._register(toDisposable(() => { this.rawOptions.linkHandler = null; this.rawOptions.documentOverride = null; diff --git a/src/common/services/ServiceRegistry.ts b/src/common/services/ServiceRegistry.ts index af51d1641..fef07d54c 100644 --- a/src/common/services/ServiceRegistry.ts +++ b/src/common/services/ServiceRegistry.ts @@ -4,10 +4,12 @@ * * This was heavily inspired from microsoft/vscode's dependency injection system (MIT). */ -/*--------------------------------------------------------------------------------------------- +/* + *--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------------------------- + */ import { IServiceIdentifier } from 'common/services/Services'; diff --git a/src/common/services/UnicodeService.ts b/src/common/services/UnicodeService.ts index d0dd8584d..a04bf00a1 100644 --- a/src/common/services/UnicodeService.ts +++ b/src/common/services/UnicodeService.ts @@ -78,16 +78,20 @@ export class UnicodeService implements IUnicodeService { // surrogate pair first if (0xD800 <= code && code <= 0xDBFF) { if (++i >= length) { - // this should not happen with strings retrieved from - // Buffer.translateToString as it converts from UTF-32 - // and therefore always should contain the second part - // for any other string we still have to handle it somehow: - // simply treat the lonely surrogate first as a single char (UCS-2 behavior) + /* + * this should not happen with strings retrieved from + * Buffer.translateToString as it converts from UTF-32 + * and therefore always should contain the second part + * for any other string we still have to handle it somehow: + * simply treat the lonely surrogate first as a single char (UCS-2 behavior) + */ return result + this.wcwidth(code); } const second = s.charCodeAt(i); - // convert surrogate pair to high codepoint only for valid second part (UTF-16) - // otherwise treat them independently (UCS-2 behavior) + /* + * convert surrogate pair to high codepoint only for valid second part (UTF-16) + * otherwise treat them independently (UCS-2 behavior) + */ if (0xDC00 <= second && second <= 0xDFFF) { code = (code - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; } else { diff --git a/src/headless/public/Terminal.ts b/src/headless/public/Terminal.ts index 0d4e6e93b..d9d604917 100644 --- a/src/headless/public/Terminal.ts +++ b/src/headless/public/Terminal.ts @@ -58,9 +58,11 @@ export class Terminal extends Disposable implements ITerminalApi { } private _checkReadonlyOptions(propName: string): void { - // Throw an error if any constructor only option is modified - // from terminal.options - // Modifications from anywhere else are allowed + /* + * Throw an error if any constructor only option is modified + * from terminal.options + * Modifications from anywhere else are allowed + */ if (CONSTRUCTOR_ONLY_OPTIONS.includes(propName)) { throw new Error(`Option "${propName}" can only be set in the constructor`); } diff --git a/test/playwright/InputHandler.test.ts b/test/playwright/InputHandler.test.ts index eec2938a8..451346f3a 100644 --- a/test/playwright/InputHandler.test.ts +++ b/test/playwright/InputHandler.test.ts @@ -227,9 +227,11 @@ test.describe('InputHandler Integration Tests', () => { await ctx.proxy.write('\x1b[2S'); await pollFor(ctx.page, () => getLinesAsArray(5), ['3', '4', '5', '', '']); }); - // This is intentionally not implemented here are image support lives within an addon - // test.skip('CSI ? Pi ; Pa ; Pv S - XTSMGRAPHICS: Set or request graphics attribute, xterm', async () => { - // }); + /* + * This is intentionally not implemented here are image support lives within an addon + * test.skip('CSI ? Pi ; Pa ; Pv S - XTSMGRAPHICS: Set or request graphics attribute, xterm', async () => { + * }); + */ test('CSI Ps T - SD: Scroll down Ps lines (default = 1), VT420', async () => { await ctx.proxy.write('1\r\n2\r\n3\r\n4\r\n5'); await pollFor(ctx.page, () => getLinesAsArray(5), ['1', '2', '3', '4', '5']); @@ -349,8 +351,10 @@ test.describe('InputHandler Integration Tests', () => { await pollFor(ctx.page, () => getLinesAsArray(3), ['aoo', '', ' b']); }); test('CSI Ps g - TBC: Tab Clear (default = 0)', async () => { - // Default: Clear tab stop at cursor position - // Move to column 9 (first tab stop), clear it, go back to column 1, tab should skip to column 17 + /* + * Default: Clear tab stop at cursor position + * Move to column 9 (first tab stop), clear it, go back to column 1, tab should skip to column 17 + */ await ctx.proxy.write('\x1b[9G\x1b[g\x1b[1G\ta'); await pollFor(ctx.page, () => getLinesAsArray(1), [' a']); // Ps=3: Clear all tab stops @@ -523,8 +527,10 @@ test.describe('InputHandler Integration Tests', () => { test('Ps = 6 9 - Enable left and right margin mode (DECLRMM), VT420 and up', async () => { await assertNoModeChange('\x1b[?69h'); }); - // test.skip('Ps = 8 0 - Enable Sixel Display Mode (DECSDM), VT330, VT340, VT382', async () => { - // }); + /* + * test.skip('Ps = 8 0 - Enable Sixel Display Mode (DECSDM), VT330, VT340, VT382', async () => { + * }); + */ test('Ps = 9 5 - Do not clear screen when DECCOLM is set/reset (DECNCSM), VT510 and up', async () => { await assertNoModeChange('\x1b[?95h'); }); @@ -881,9 +887,11 @@ test.describe('InputHandler Integration Tests', () => { test('Ps = 6 9 - Disable left and right margin mode (DECLRMM), VT420 and up.', async () => { await assertNoModeChange('\x1b[?69l'); }); - // This is intentionally not implemented here are image support lives within an addon - // test.skip('Ps = 8 0 - Disable Sixel Display Mode (DECSDM), VT330, VT340, VT382. Turns on "Sixel Scrolling". See the section Sixel Graphics and mode 8 4 5 2 .', async () => { - // }); + /* + * This is intentionally not implemented here are image support lives within an addon + * test.skip('Ps = 8 0 - Disable Sixel Display Mode (DECSDM), VT330, VT340, VT382. Turns on "Sixel Scrolling". See the section Sixel Graphics and mode 8 4 5 2 .', async () => { + * }); + */ test('Ps = 9 5 - Clear screen when DECCOLM is set/reset (DECNCSM), VT510 and up.', async () => { await assertNoModeChange('\x1b[?95l'); }); diff --git a/test/playwright/MouseTracking.test.ts b/test/playwright/MouseTracking.test.ts index 355bac3ba..fc3a112e5 100644 --- a/test/playwright/MouseTracking.test.ts +++ b/test/playwright/MouseTracking.test.ts @@ -12,13 +12,17 @@ test.beforeAll(async ({ browser }) => { }); test.afterAll(async () => await ctx.page.close()); -// adjusted to work inside devcontainer -// see https://github.com/xtermjs/xterm.js/issues/2379 +/* + * adjusted to work inside devcontainer + * see https://github.com/xtermjs/xterm.js/issues/2379 + */ const width = 1280; const height = 960; -// adjust terminal row/col size so we can test -// >80 up to 223 and >255 +/* + * adjust terminal row/col size so we can test + * >80 up to 223 and >255 + */ const fontSize = 6; const cols = 260; const rows = 50; @@ -40,9 +44,11 @@ async function getReports(encoding: string): Promise { return reports.map((report: number[]) => parseReport(encoding, report)); } -// translate cell positions into pixel offset -// always adds +2 in each direction so we dont end up in the wrong cell -// due to rounding issues +/* + * translate cell positions into pixel offset + * always adds +2 in each direction so we dont end up in the wrong cell + * due to rounding issues + */ async function cellPos(col: number, row: number): Promise { const coords: any = await ctx.page.evaluate(` (function() { @@ -165,10 +171,12 @@ function parseReport(encoding: string, msg: number[]): { state: any, row: number test.describe('Mouse Tracking Tests', () => { test.beforeAll(async () => { await ctx.page.setViewportSize({ width, height }); - // patch terminal to get the onData calls - // we encode the msg here to an array of codes to not lose bytes - // (transmission strips non utf8 bytes) - // also resize so we can properly test the edge cases + /* + * patch terminal to get the onData calls + * we encode the msg here to an array of codes to not lose bytes + * (transmission strips non utf8 bytes) + * also resize so we can properly test the edge cases + */ await ctx.page.evaluate(` window.term.onData(e => window.calls.push( Array.from(e).map(el => el.charCodeAt(0)) )); window.term.onBinary(e => window.calls.push( Array.from(e).map(el => el.charCodeAt(0)) )); @@ -214,8 +222,10 @@ test.describe('Mouse Tracking Tests', () => { await mouseUp('left'); await pollFor(ctx.page, () => getReports(encoding), [{ col: 51, row: 11, state: { action: 'press', button: 'left', modifier: { control: false, shift: false, meta: false } } }]); - // test at max rows/cols - // capped at 223 (1-based) + /* + * test at max rows/cols + * capped at 223 (1-based) + */ await mouseMove(223 - 1, rows - 1); await mouseDown('left'); await mouseUp('left'); @@ -227,24 +237,28 @@ test.describe('Mouse Tracking Tests', () => { await mouseUp('left'); await pollFor(ctx.page, () => getReports(encoding), []); - // button press/move/release tests - // left button + /* + * button press/move/release tests + * left button + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('left'); await mouseMove(44, 24); await mouseUp('left'); await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: false, meta: false } } }]); - // middle button - // bug: default action not cancelled (adds data to getReports from clipboard under X11) - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await mouseDown('middle'); - // await mouseMove(44, 24); - // await mouseUp('middle'); - // await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); - // right button - // bug: default action not cancelled (popup shown) + /* + * middle button + * bug: default action not cancelled (adds data to getReports from clipboard under X11) + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await mouseDown('middle'); + * await mouseMove(44, 24); + * await mouseUp('middle'); + * await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); + * right button + * bug: default action not cancelled (popup shown) + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('right'); @@ -252,16 +266,20 @@ test.describe('Mouse Tracking Tests', () => { await mouseUp('right'); await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'press', button: 'right', modifier: { control: false, shift: false, meta: false } } }]); - // wheel - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await wheelUp(); - // await pollFor(ctx.page, () => getReports(encoding), []); - // await wheelDown(); - // await pollFor(ctx.page, () => getReports(encoding), []); + /* + * wheel + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await wheelUp(); + * await pollFor(ctx.page, () => getReports(encoding), []); + * await wheelDown(); + * await pollFor(ctx.page, () => getReports(encoding), []); + */ - // modifiers - // CTRL + /* + * modifiers + * CTRL + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -284,10 +302,12 @@ test.describe('Mouse Tracking Tests', () => { await ctx.page.keyboard.up('Alt'); await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: false, meta: false } } }]); - // SHIFT - // note: caught by selection manager - // bug? Why not caught by selection manger on macos? - // bug: no modifier reported + /* + * SHIFT + * note: caught by selection manager + * bug? Why not caught by selection manger on macos? + * bug: no modifier reported + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Shift'); // defaults to ShiftLeft @@ -304,8 +324,10 @@ test.describe('Mouse Tracking Tests', () => { ]); } - // all modifiers - // bug: Shift not working - reporting totally wrong coords and modifiers - selection manager again? + /* + * all modifiers + * bug: Shift not working - reporting totally wrong coords and modifiers - selection manager again? + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -351,24 +373,28 @@ test.describe('Mouse Tracking Tests', () => { await mouseUp('left'); await pollFor(ctx.page, () => getReports(encoding), [{ col: cols, row: rows, state: { action: 'press', button: 'left', modifier: { control: false, shift: false, meta: false } } }]); - // button press/move/release tests - // left button + /* + * button press/move/release tests + * left button + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('left'); await mouseMove(44, 24); await mouseUp('left'); await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: false, meta: false } } }]); - // middle button - // bug: default action not cancelled (adds data to getReports from clipboard under X11) - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await mouseDown('middle'); - // await mouseMove(44, 24); - // await mouseUp('middle'); - // await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); - // right button - // bug: default action not cancelled (popup shown) + /* + * middle button + * bug: default action not cancelled (adds data to getReports from clipboard under X11) + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await mouseDown('middle'); + * await mouseMove(44, 24); + * await mouseUp('middle'); + * await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); + * right button + * bug: default action not cancelled (popup shown) + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('right'); @@ -376,16 +402,20 @@ test.describe('Mouse Tracking Tests', () => { await mouseUp('right'); await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'press', button: 'right', modifier: { control: false, shift: false, meta: false } } }]); - // wheel - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await wheelUp(); - // await pollFor(ctx.page, () => getReports(encoding), []); - // await wheelDown(); - // await pollFor(ctx.page, () => getReports(encoding), []); + /* + * wheel + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await wheelUp(); + * await pollFor(ctx.page, () => getReports(encoding), []); + * await wheelDown(); + * await pollFor(ctx.page, () => getReports(encoding), []); + */ - // modifiers - // CTRL + /* + * modifiers + * CTRL + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -408,8 +438,10 @@ test.describe('Mouse Tracking Tests', () => { await ctx.page.keyboard.up('Alt'); await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: false, meta: false } } }]); - // SHIFT - // note: caught by selection manager + /* + * SHIFT + * note: caught by selection manager + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Shift'); // defaults to ShiftLeft @@ -426,8 +458,10 @@ test.describe('Mouse Tracking Tests', () => { ]); } - // all modifiers - // bug: Shift not working - reporting totally wrong coords and modifiers - selection manager again? + /* + * all modifiers + * bug: Shift not working - reporting totally wrong coords and modifiers - selection manager again? + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -483,8 +517,10 @@ test.describe('Mouse Tracking Tests', () => { { col: 51, row: 11, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // test at max rows/cols - // capped at 223 (1-based) + /* + * test at max rows/cols + * capped at 223 (1-based) + */ await mouseMove(223 - 1, rows - 1); await mouseDown('left'); await mouseUp('left'); @@ -493,8 +529,10 @@ test.describe('Mouse Tracking Tests', () => { { col: 223, row: rows, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // button press/move/release tests - // left button + /* + * button press/move/release tests + * left button + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('left'); @@ -504,16 +542,18 @@ test.describe('Mouse Tracking Tests', () => { { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: false, meta: false } } }, { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // middle button - // bug: default action not cancelled (adds data to getReports from clipboard under X11) - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await mouseDown('middle'); - // await mouseMove(44, 24); - // await mouseUp('middle'); - // await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); - // right button - // bug: default action not cancelled (popup shown) + /* + * middle button + * bug: default action not cancelled (adds data to getReports from clipboard under X11) + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await mouseDown('middle'); + * await mouseMove(44, 24); + * await mouseUp('middle'); + * await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); + * right button + * bug: default action not cancelled (popup shown) + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('right'); @@ -524,16 +564,20 @@ test.describe('Mouse Tracking Tests', () => { { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // wheel - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await wheelUp(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); - // await wheelDown(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + /* + * wheel + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await wheelUp(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + * await wheelDown(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + */ - // modifiers - // CTRL + /* + * modifiers + * CTRL + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -563,31 +607,35 @@ test.describe('Mouse Tracking Tests', () => { // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: true } } } ]); - // SHIFT - // note: press/release caught by selection manager - // bug: modifier not reported for passed events - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await ctx.page.keyboard.down('Shift'); // defaults to ShiftLeft - // await mouseDown('left'); - // await mouseMove(44, 24); - // await mouseUp('left'); - // // await wheelDown(); - // await ctx.page.keyboard.up('Shift'); - // // if (noShift) { - // // await pollFor(ctx.page, () => getReports(encoding), [ - // // // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // // ]); - // // } else { - // await pollFor(ctx.page, () => getReports(encoding), [ - // { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: true, meta: false } } }, - // // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // ]); - // // } + /* + * SHIFT + * note: press/release caught by selection manager + * bug: modifier not reported for passed events + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await ctx.page.keyboard.down('Shift'); // defaults to ShiftLeft + * await mouseDown('left'); + * await mouseMove(44, 24); + * await mouseUp('left'); + * // await wheelDown(); + * await ctx.page.keyboard.up('Shift'); + * // if (noShift) { + * // await pollFor(ctx.page, () => getReports(encoding), [ + * // // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * // ]); + * // } else { + * await pollFor(ctx.page, () => getReports(encoding), [ + * { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: true, meta: false } } }, + * // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * ]); + * // } + */ - // all modifiers - // bug: Shift not working - selection manager? + /* + * all modifiers + * bug: Shift not working - selection manager? + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -647,8 +695,10 @@ test.describe('Mouse Tracking Tests', () => { { col: cols, row: rows, state: { action: 'release', button: 'left', modifier: { control: false, shift: false, meta: false } } } ]); - // button press/move/release tests - // left button + /* + * button press/move/release tests + * left button + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('left'); @@ -658,16 +708,18 @@ test.describe('Mouse Tracking Tests', () => { { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: false, meta: false } } }, { col: 45, row: 25, state: { action: 'release', button: 'left', modifier: { control: false, shift: false, meta: false } } } ]); - // middle button - // bug: default action not cancelled (adds data to getReports from clipboard under X11) - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await mouseDown('middle'); - // await mouseMove(44, 24); - // await mouseUp('middle'); - // await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); - // right button - // bug: default action not cancelled (popup shown) + /* + * middle button + * bug: default action not cancelled (adds data to getReports from clipboard under X11) + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await mouseDown('middle'); + * await mouseMove(44, 24); + * await mouseUp('middle'); + * await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); + * right button + * bug: default action not cancelled (popup shown) + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('right'); @@ -678,16 +730,20 @@ test.describe('Mouse Tracking Tests', () => { { col: 45, row: 25, state: { action: 'release', button: 'right', modifier: { control: false, shift: false, meta: false } } } ]); - // wheel - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await wheelUp(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); - // await wheelDown(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + /* + * wheel + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await wheelUp(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + * await wheelDown(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + */ - // modifiers - // CTRL + /* + * modifiers + * CTRL + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -717,30 +773,34 @@ test.describe('Mouse Tracking Tests', () => { // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: true } } } ]); - // SHIFT - // note: press/release caught by selection manager - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await ctx.page.keyboard.down('Shift'); // defaults to ShiftLeft - // await mouseDown('left'); - // await mouseMove(44, 24); - // await mouseUp('left'); - // await wheelDown(); - // await ctx.page.keyboard.up('Shift'); - // if (noShift) { - // await pollFor(ctx.page, () => getReports(encoding), [ - // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // ]); - // } else { - // await pollFor(ctx.page, () => getReports(encoding), [ - // { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'release', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // ]); - // } + /* + * SHIFT + * note: press/release caught by selection manager + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await ctx.page.keyboard.down('Shift'); // defaults to ShiftLeft + * await mouseDown('left'); + * await mouseMove(44, 24); + * await mouseUp('left'); + * await wheelDown(); + * await ctx.page.keyboard.up('Shift'); + * if (noShift) { + * await pollFor(ctx.page, () => getReports(encoding), [ + * { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * ]); + * } else { + * await pollFor(ctx.page, () => getReports(encoding), [ + * { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'release', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * ]); + * } + */ - // all modifiers - // bug: Shift not working - selection manager? + /* + * all modifiers + * bug: Shift not working - selection manager? + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -800,8 +860,10 @@ test.describe('Mouse Tracking Tests', () => { { col: 51, row: 11, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // test at max rows/cols - // capped at 223 (1-based) + /* + * test at max rows/cols + * capped at 223 (1-based) + */ await mouseMove(223 - 1, rows - 1); await mouseDown('left'); await mouseUp('left'); @@ -810,8 +872,10 @@ test.describe('Mouse Tracking Tests', () => { { col: 223, row: rows, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // button press/move/release tests - // left button + /* + * button press/move/release tests + * left button + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('left'); @@ -822,16 +886,18 @@ test.describe('Mouse Tracking Tests', () => { { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: false, meta: false } } }, { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // middle button - // bug: default action not cancelled (adds data to getReports from clipboard under X11) - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await mouseDown('middle'); - // await mouseMove(44, 24); - // await mouseUp('middle'); - // await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); - // right button - // bug: default action not cancelled (popup shown) + /* + * middle button + * bug: default action not cancelled (adds data to getReports from clipboard under X11) + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await mouseDown('middle'); + * await mouseMove(44, 24); + * await mouseUp('middle'); + * await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); + * right button + * bug: default action not cancelled (popup shown) + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('right'); @@ -843,16 +909,20 @@ test.describe('Mouse Tracking Tests', () => { { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // wheel - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await wheelUp(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); - // await wheelDown(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + /* + * wheel + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await wheelUp(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + * await wheelDown(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + */ - // modifiers - // CTRL + /* + * modifiers + * CTRL + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -884,31 +954,35 @@ test.describe('Mouse Tracking Tests', () => { // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: true } } } ]); - // SHIFT - // note: press/release/drag caught by selection manager - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await ctx.page.keyboard.down('Shift'); // defaults to ShiftLeft - // await mouseDown('left'); - // await mouseMove(44, 24); - // await mouseUp('left'); - // await wheelDown(); - // await ctx.page.keyboard.up('Shift'); - // if (noShift) { - // await pollFor(ctx.page, () => getReports(encoding), [ - // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // ]); - // } else { - // await pollFor(ctx.page, () => getReports(encoding), [ - // { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // ]); - // } + /* + * SHIFT + * note: press/release/drag caught by selection manager + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await ctx.page.keyboard.down('Shift'); // defaults to ShiftLeft + * await mouseDown('left'); + * await mouseMove(44, 24); + * await mouseUp('left'); + * await wheelDown(); + * await ctx.page.keyboard.up('Shift'); + * if (noShift) { + * await pollFor(ctx.page, () => getReports(encoding), [ + * { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * ]); + * } else { + * await pollFor(ctx.page, () => getReports(encoding), [ + * { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * ]); + * } + */ - // all modifiers - // bug: Shift not working + /* + * all modifiers + * bug: Shift not working + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -938,8 +1012,10 @@ test.describe('Mouse Tracking Tests', () => { await mouseMove(0, 0); await ctx.proxy.write('\x1b[?1002h\x1b[?1006h'); - // test at 0,0 - // bug: release is fired immediately + /* + * test at 0,0 + * bug: release is fired immediately + */ await mouseDown('left'); await pollFor(ctx.page, () => getReports(encoding), [ { col: 1, row: 1, state: { action: 'press', button: 'left', modifier: { control: false, shift: false, meta: false } } } @@ -970,8 +1046,10 @@ test.describe('Mouse Tracking Tests', () => { { col: cols, row: rows, state: { action: 'release', button: 'left', modifier: { control: false, shift: false, meta: false } } } ]); - // button press/move/release tests - // left button + /* + * button press/move/release tests + * left button + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('left'); @@ -982,16 +1060,18 @@ test.describe('Mouse Tracking Tests', () => { { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: false, meta: false } } }, { col: 45, row: 25, state: { action: 'release', button: 'left', modifier: { control: false, shift: false, meta: false } } } ]); - // middle button - // bug: default action not cancelled (adds data to getReports from clipboard under X11) - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await mouseDown('middle'); - // await mouseMove(44, 24); - // await mouseUp('middle'); - // await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); - // right button - // bug: default action not cancelled (popup shown) + /* + * middle button + * bug: default action not cancelled (adds data to getReports from clipboard under X11) + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await mouseDown('middle'); + * await mouseMove(44, 24); + * await mouseUp('middle'); + * await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); + * right button + * bug: default action not cancelled (popup shown) + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await mouseDown('right'); @@ -1003,16 +1083,20 @@ test.describe('Mouse Tracking Tests', () => { { col: 45, row: 25, state: { action: 'release', button: 'right', modifier: { control: false, shift: false, meta: false } } } ]); - // wheel - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await wheelUp(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); - // await wheelDown(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + /* + * wheel + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await wheelUp(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + * await wheelDown(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + */ - // modifiers - // CTRL + /* + * modifiers + * CTRL + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -1044,31 +1128,35 @@ test.describe('Mouse Tracking Tests', () => { // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: true } } } ]); - // SHIFT - // note: press/release/drag caught by selection manager - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await ctx.page.keyboard.down('Shift'); // defaults to ShiftLeft - // await mouseDown('left'); - // await mouseMove(44, 24); - // await mouseUp('left'); - // await wheelDown(); - // await ctx.page.keyboard.up('Shift'); - // if (noShift) { - // await pollFor(ctx.page, () => getReports(encoding), [ - // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // ]); - // } else { - // await pollFor(ctx.page, () => getReports(encoding), [ - // { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'release', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // ]); - // } + /* + * SHIFT + * note: press/release/drag caught by selection manager + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await ctx.page.keyboard.down('Shift'); // defaults to ShiftLeft + * await mouseDown('left'); + * await mouseMove(44, 24); + * await mouseUp('left'); + * await wheelDown(); + * await ctx.page.keyboard.up('Shift'); + * if (noShift) { + * await pollFor(ctx.page, () => getReports(encoding), [ + * { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * ]); + * } else { + * await pollFor(ctx.page, () => getReports(encoding), [ + * { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'release', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * ]); + * } + */ - // all modifiers - // bug: this is totally broken with wrong coords and messed up modifiers + /* + * all modifiers + * bug: this is totally broken with wrong coords and messed up modifiers + */ await mouseMove(43, 24); await getReports(encoding); // clear reports await ctx.page.keyboard.down('Control'); @@ -1128,8 +1216,10 @@ test.describe('Mouse Tracking Tests', () => { { col: 51, row: 11, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // test at max rows/cols - // capped at 223 (1-based) + /* + * test at max rows/cols + * capped at 223 (1-based) + */ await mouseMove(223 - 1, rows - 1); await mouseDown('left'); await mouseUp('left'); @@ -1139,8 +1229,10 @@ test.describe('Mouse Tracking Tests', () => { { col: 223, row: rows, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // button press/move/release tests - // left button + /* + * button press/move/release tests + * left button + */ await mouseMove(43, 24); await mouseDown('left'); await mouseMove(44, 24); @@ -1151,16 +1243,18 @@ test.describe('Mouse Tracking Tests', () => { { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: false, meta: false } } }, { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // middle button - // bug: default action not cancelled (adds data to getReports from clipboard under X11) - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await mouseDown('middle'); - // await mouseMove(44, 24); - // await mouseUp('middle'); - // await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); - // right button - // bug: default action not cancelled (popup shown) + /* + * middle button + * bug: default action not cancelled (adds data to getReports from clipboard under X11) + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await mouseDown('middle'); + * await mouseMove(44, 24); + * await mouseUp('middle'); + * await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); + * right button + * bug: default action not cancelled (popup shown) + */ await mouseMove(43, 24); await mouseDown('right'); await mouseMove(44, 24); @@ -1172,16 +1266,20 @@ test.describe('Mouse Tracking Tests', () => { { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: false, meta: false } } } ]); - // wheel - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await wheelUp(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); - // await wheelDown(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + /* + * wheel + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await wheelUp(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + * await wheelDown(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + */ - // modifiers - // CTRL + /* + * modifiers + * CTRL + */ await ctx.page.keyboard.down('Control'); await mouseMove(43, 24); await mouseDown('left'); @@ -1213,32 +1311,36 @@ test.describe('Mouse Tracking Tests', () => { // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: true } } } ]); - // SHIFT - // note: press/release/drag caught by selection manager - // await ctx.page.keyboard.down('Shift'); - // await mouseMove(43, 24); - // await mouseDown('left'); - // await mouseMove(44, 24); - // await mouseUp('left'); - // await wheelDown(); - // await ctx.page.keyboard.up('Shift'); - // if (noShift) { - // await pollFor(ctx.page, () => getReports(encoding), [ - // { col: 44, row: 25, state: { action: 'move', button: '', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // ]); - // } else { - // await pollFor(ctx.page, () => getReports(encoding), [ - // { col: 44, row: 25, state: { action: 'move', button: '', modifier: { control: false, shift: true, meta: false } } }, - // { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // ]); - // } + /* + * SHIFT + * note: press/release/drag caught by selection manager + * await ctx.page.keyboard.down('Shift'); + * await mouseMove(43, 24); + * await mouseDown('left'); + * await mouseMove(44, 24); + * await mouseUp('left'); + * await wheelDown(); + * await ctx.page.keyboard.up('Shift'); + * if (noShift) { + * await pollFor(ctx.page, () => getReports(encoding), [ + * { col: 44, row: 25, state: { action: 'move', button: '', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * ]); + * } else { + * await pollFor(ctx.page, () => getReports(encoding), [ + * { col: 44, row: 25, state: { action: 'move', button: '', modifier: { control: false, shift: true, meta: false } } }, + * { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'release', button: '', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * ]); + * } + */ - // all modifiers - // bug: Shift not working + /* + * all modifiers + * bug: Shift not working + */ await ctx.page.keyboard.down('Control'); await ctx.page.keyboard.down('Alt'); // await ctx.page.keyboard.down('Shift'); @@ -1292,9 +1394,11 @@ test.describe('Mouse Tracking Tests', () => { { col: 51, row: 11, state: { action: 'release', button: 'left', modifier: { control: false, shift: false, meta: false } } } ]); - // test at max rows/cols - // bug: we are capped at col 95 currently - // fix: allow values up to 223, any bigger should drop to 0 + /* + * test at max rows/cols + * bug: we are capped at col 95 currently + * fix: allow values up to 223, any bigger should drop to 0 + */ await mouseMove(cols - 1, rows - 1); await mouseDown('left'); await mouseUp('left'); @@ -1304,8 +1408,10 @@ test.describe('Mouse Tracking Tests', () => { { col: cols, row: rows, state: { action: 'release', button: 'left', modifier: { control: false, shift: false, meta: false } } } ]); - // button press/move/release tests - // left button + /* + * button press/move/release tests + * left button + */ await mouseMove(43, 24); await mouseDown('left'); await mouseMove(44, 24); @@ -1316,16 +1422,18 @@ test.describe('Mouse Tracking Tests', () => { { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: false, meta: false } } }, { col: 45, row: 25, state: { action: 'release', button: 'left', modifier: { control: false, shift: false, meta: false } } } ]); - // middle button - // bug: default action not cancelled (adds data to getReports from clipboard under X11) - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await mouseDown('middle'); - // await mouseMove(44, 24); - // await mouseUp('middle'); - // await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); - // right button - // bug: default action not cancelled (popup shown) + /* + * middle button + * bug: default action not cancelled (adds data to getReports from clipboard under X11) + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await mouseDown('middle'); + * await mouseMove(44, 24); + * await mouseUp('middle'); + * await pollFor(ctx.page, () => getReports(encoding), [{col: 44, row: 25, state: {action: 'press', button: 'middle', modifier: {control: false, shift: false, meta: false}}}]); + * right button + * bug: default action not cancelled (popup shown) + */ await mouseMove(43, 24); await mouseDown('right'); await mouseMove(44, 24); @@ -1337,16 +1445,20 @@ test.describe('Mouse Tracking Tests', () => { { col: 45, row: 25, state: { action: 'release', button: 'right', modifier: { control: false, shift: false, meta: false } } } ]); - // wheel - // await mouseMove(43, 24); - // await getReports(encoding); // clear reports - // await wheelUp(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); - // await wheelDown(); - // await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + /* + * wheel + * await mouseMove(43, 24); + * await getReports(encoding); // clear reports + * await wheelUp(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'up', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + * await wheelDown(); + * await pollFor(ctx.page, () => getReports(encoding), [{ col: 44, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: false } } }]); + */ - // modifiers - // CTRL + /* + * modifiers + * CTRL + */ await ctx.page.keyboard.down('Control'); await mouseMove(43, 24); await mouseDown('left'); @@ -1378,32 +1490,36 @@ test.describe('Mouse Tracking Tests', () => { // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: false, meta: true } } } ]); - // SHIFT - // note: press/release/drag caught by selection manager - // await ctx.page.keyboard.down('Shift'); - // await mouseMove(43, 24); - // await mouseDown('left'); - // await mouseMove(44, 24); - // await mouseUp('left'); - // await wheelDown(); - // await ctx.page.keyboard.up('Shift'); - // if (noShift) { - // await pollFor(ctx.page, () => getReports(encoding), [ - // { col: 44, row: 25, state: { action: 'move', button: '', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // ]); - // } else { - // await pollFor(ctx.page, () => getReports(encoding), [ - // { col: 44, row: 25, state: { action: 'move', button: '', modifier: { control: false, shift: true, meta: false } } }, - // { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'release', button: 'left', modifier: { control: false, shift: true, meta: false } } }, - // { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } - // ]); - // } + /* + * SHIFT + * note: press/release/drag caught by selection manager + * await ctx.page.keyboard.down('Shift'); + * await mouseMove(43, 24); + * await mouseDown('left'); + * await mouseMove(44, 24); + * await mouseUp('left'); + * await wheelDown(); + * await ctx.page.keyboard.up('Shift'); + * if (noShift) { + * await pollFor(ctx.page, () => getReports(encoding), [ + * { col: 44, row: 25, state: { action: 'move', button: '', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * ]); + * } else { + * await pollFor(ctx.page, () => getReports(encoding), [ + * { col: 44, row: 25, state: { action: 'move', button: '', modifier: { control: false, shift: true, meta: false } } }, + * { col: 44, row: 25, state: { action: 'press', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'move', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'release', button: 'left', modifier: { control: false, shift: true, meta: false } } }, + * { col: 45, row: 25, state: { action: 'down', button: 'wheel', modifier: { control: false, shift: true, meta: false } } } + * ]); + * } + */ - // all modifiers - // bug: Shift not working + /* + * all modifiers + * bug: Shift not working + */ await ctx.page.keyboard.down('Control'); await ctx.page.keyboard.down('Alt'); // await ctx.page.keyboard.down('Shift'); diff --git a/test/playwright/SharedRendererTests.ts b/test/playwright/SharedRendererTests.ts index db5c4c073..75b330abd 100644 --- a/test/playwright/SharedRendererTests.ts +++ b/test/playwright/SharedRendererTests.ts @@ -378,8 +378,10 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void const r = parseInt(cssColor.slice(1, 3), 16); const g = parseInt(cssColor.slice(3, 5), 16); const b = parseInt(cssColor.slice(5, 7), 16); - // It's difficult to assert the exact color due to rounding, just ensure the color differs - // to the regular color + /* + * It's difficult to assert the exact color due to rounding, just ensure the color differs + * to the regular color + */ await pollFor(ctx.value.page, async () => { const c = await getCellColor(ctx.value, x + 1, y + 1); return ( @@ -783,9 +785,11 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void await pollFor(ctx.value.page, () => getCellColor(ctx.value, 6, 2), [0xad, 0x7f, 0xa8, 255]); await pollFor(ctx.value.page, () => getCellColor(ctx.value, 7, 2), [0x34, 0xe2, 0xe2, 255]); await pollFor(ctx.value.page, () => getCellColor(ctx.value, 8, 2), [0xee, 0xee, 0xec, 255]); - // Setting and check for minimum contrast values, note that these are not - // exact to the contrast ratio, if the increase luminance algorithm - // changes then these will probably fail + /* + * Setting and check for minimum contrast values, note that these are not + * exact to the contrast ratio, if the increase luminance algorithm + * changes then these will probably fail + */ await ctx.value.page.evaluate(`window.term.options.minimumContrastRatio = 10;`); frameDetails = undefined; await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 1), [176, 180, 180, 255]); @@ -852,9 +856,11 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void await pollFor(ctx.value.page, () => getCellColor(ctx.value, 6, 2), [0xad, 0x7f, 0xa8, 255]); await pollFor(ctx.value.page, () => getCellColor(ctx.value, 7, 2), [0x34, 0xe2, 0xe2, 255]); await pollFor(ctx.value.page, () => getCellColor(ctx.value, 8, 2), [0xee, 0xee, 0xec, 255]); - // Setting and check for minimum contrast values, note that these are not - // exact to the contrast ratio, if the increase luminance algorithm - // changes then these will probably fail + /* + * Setting and check for minimum contrast values, note that these are not + * exact to the contrast ratio, if the increase luminance algorithm + * changes then these will probably fail + */ await ctx.value.page.evaluate(`window.term.options.minimumContrastRatio = 10;`); frameDetails = undefined; await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 1), [46, 52, 54, 255]); @@ -935,9 +941,11 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void await pollForApproximate(ctx.value.page, marginOfError, () => getFgColor(6, 2), [Math.floor((255 + 0xad) / 2), Math.floor((255 + 0x7f) / 2), Math.floor((255 + 0xa8) / 2), 255]); await pollForApproximate(ctx.value.page, marginOfError, () => getFgColor(7, 2), [Math.floor((255 + 0x34) / 2), Math.floor((255 + 0xe2) / 2), Math.floor((255 + 0xe2) / 2), 255]); await pollForApproximate(ctx.value.page, marginOfError, () => getFgColor(8, 2), [Math.floor((255 + 0xee) / 2), Math.floor((255 + 0xee) / 2), Math.floor((255 + 0xec) / 2), 255]); - // Setting and check for minimum contrast values, note that these are not - // exact to the contrast ratio, if the increase luminance algorithm - // changes then these will probably fail + /* + * Setting and check for minimum contrast values, note that these are not + * exact to the contrast ratio, if the increase luminance algorithm + * changes then these will probably fail + */ await waitForRenderAfter(ctx.value, () => ctx.value.page.evaluate(`window.term.options.minimumContrastRatio = 10;`)); await pollForApproximate(ctx.value.page, marginOfError, () => getFgColor(1, 1), [150, 153, 154, 255]); await pollForApproximate(ctx.value.page, marginOfError, () => getFgColor(2, 1), [229, 127, 127, 255]); diff --git a/test/playwright/Terminal.test.ts b/test/playwright/Terminal.test.ts index 2d1133cce..387197c6d 100644 --- a/test/playwright/Terminal.test.ts +++ b/test/playwright/Terminal.test.ts @@ -837,8 +837,10 @@ test.describe('API Integration Tests', () => { test.describe('registerLinkProvider', () => { test('should fire provideLinks when hovering cells', async () => { await openTerminal(ctx); - // Focus the terminal as the cursor will show and trigger a rerender, which can clear the - // active link + /* + * Focus the terminal as the cursor will show and trigger a rerender, which can clear the + * active link + */ await ctx.proxy.focus(); await ctx.page.evaluate(` window.calls = []; @@ -859,8 +861,10 @@ test.describe('API Integration Tests', () => { test('should fire hover and leave events on the link', async () => { await openTerminal(ctx); - // Focus the terminal as the cursor will show and trigger a rerender, which can clear the - // active link + /* + * Focus the terminal as the cursor will show and trigger a rerender, which can clear the + * active link + */ await ctx.page.evaluate('window.term.focus()'); await ctx.proxy.write('foo bar baz'); // Wait for renderer to catch up as links are cleared on render @@ -897,8 +901,10 @@ test.describe('API Integration Tests', () => { test('should work fine when hover and leave callbacks are not provided', async () => { await openTerminal(ctx); - // Focus the terminal as the cursor will show and trigger a rerender, which can clear the - // active link + /* + * Focus the terminal as the cursor will show and trigger a rerender, which can clear the + * active link + */ await ctx.page.evaluate('window.term.focus()'); await ctx.proxy.write('foo bar baz'); // Wait for renderer to catch up as links are cleared on render @@ -940,8 +946,10 @@ test.describe('API Integration Tests', () => { test('should fire activate events when clicking the link', async () => { await openTerminal(ctx); - // Focus the terminal as the cursor will show and trigger a rerender, which can clear the - // active link + /* + * Focus the terminal as the cursor will show and trigger a rerender, which can clear the + * active link + */ await ctx.page.evaluate('window.term.focus()'); await ctx.proxy.write('a b c'); // Wait for renderer to catch up as links are cleared on render @@ -982,8 +990,10 @@ test.describe('API Integration Tests', () => { test('should work when multiple links are provided on the same line', async () => { await openTerminal(ctx); - // Focus the terminal as the cursor will show and trigger a rerender, which can clear the - // active link + /* + * Focus the terminal as the cursor will show and trigger a rerender, which can clear the + * active link + */ await ctx.page.evaluate('window.term.focus()'); await ctx.proxy.write('foo bar baz'); // Wait for renderer to catch up as links are cleared on render @@ -1031,8 +1041,10 @@ test.describe('API Integration Tests', () => { test('should dispose links when hovering away', async () => { await openTerminal(ctx); - // Focus the terminal as the cursor will show and trigger a rerender, which can clear the - // active link + /* + * Focus the terminal as the cursor will show and trigger a rerender, which can clear the + * active link + */ await ctx.page.evaluate('window.term.focus()'); await ctx.proxy.write('foo bar baz'); // Wait for renderer to catch up as links are cleared on render diff --git a/test/playwright/TestUtils.ts b/test/playwright/TestUtils.ts index 8a76c8820..76a5eb200 100644 --- a/test/playwright/TestUtils.ts +++ b/test/playwright/TestUtils.ts @@ -459,8 +459,10 @@ export async function openTerminal( } catch {} } `); - // HACK: Tests may have side effects that could cause the terminal not to be removed. This - // assertion catches this case early. + /* + * HACK: Tests may have side effects that could cause the terminal not to be removed. This + * assertion catches this case early. + */ strictEqual(await ctx.page.evaluate(`document.querySelector('#terminal-container').children.length`), 0, 'there must be no terminals on the page'); let script = ` @@ -501,8 +503,10 @@ export async function openTerminal( await ctx.page.evaluate(script); - // HACK: This is a soft layer breaker that's temporarily included until unicode graphemes have - // more complete integration tests. See https://github.com/xtermjs/xterm.js/pull/4519#discussion_r1285234453 + /* + * HACK: This is a soft layer breaker that's temporarily included until unicode graphemes have + * more complete integration tests. See https://github.com/xtermjs/xterm.js/pull/4519#discussion_r1285234453 + */ if (testOptions.loadUnicodeGraphemesAddon) { await ctx.page.evaluate(` window.unicode = new UnicodeGraphemesAddon();