X-Git-Url: https://git.josue.xyz/?p=VSoRC%2F.git;a=blobdiff_plain;f=node_modules%2Fxterm%2Fsrc%2Fcommon%2Fbuffer%2FBuffer.ts;fp=node_modules%2Fxterm%2Fsrc%2Fcommon%2Fbuffer%2FBuffer.ts;h=0000000000000000000000000000000000000000;hp=152bab7a3c1bb3caff791d3c16895d0b188155ba;hb=5e96dd57ddd883604e87f62bdddcb111c63a6e1a;hpb=acb5f682a2b75b972710cabd81658f63071324b0 diff --git a/node_modules/xterm/src/common/buffer/Buffer.ts b/node_modules/xterm/src/common/buffer/Buffer.ts deleted file mode 100644 index 152bab7..0000000 --- a/node_modules/xterm/src/common/buffer/Buffer.ts +++ /dev/null @@ -1,671 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { CircularList, IInsertEvent } from 'common/CircularList'; -import { IBuffer, BufferIndex, IBufferStringIterator, IBufferStringIteratorResult } from 'common/buffer/Types'; -import { IBufferLine, ICellData, IAttributeData, ICharset } from 'common/Types'; -import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { CellData } from 'common/buffer/CellData'; -import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_WIDTH, WHITESPACE_CELL_CODE, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX } from 'common/buffer/Constants'; -import { reflowLargerApplyNewLayout, reflowLargerCreateNewLayout, reflowLargerGetLinesToRemove, reflowSmallerGetNewLineLengths, getWrappedLineTrimmedLength } from 'common/buffer/BufferReflow'; -import { Marker } from 'common/buffer/Marker'; -import { IOptionsService, IBufferService } from 'common/services/Services'; -import { DEFAULT_CHARSET } from 'common/data/Charsets'; - -export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1 - -/** - * This class represents a terminal buffer (an internal state of the terminal), where the - * following information is stored (in high-level): - * - text content of this particular buffer - * - cursor position - * - scroll position - */ -export class Buffer implements IBuffer { - public lines: CircularList; - public ydisp: number = 0; - public ybase: number = 0; - public y: number = 0; - public x: number = 0; - public scrollBottom: number; - public scrollTop: number; - // TODO: Type me - public tabs: any; - public savedY: number = 0; - public savedX: number = 0; - public savedCurAttrData = DEFAULT_ATTR_DATA.clone(); - public savedCharset: ICharset | null = DEFAULT_CHARSET; - public markers: Marker[] = []; - private _nullCell: ICellData = CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]); - private _whitespaceCell: ICellData = CellData.fromCharData([0, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_WIDTH, WHITESPACE_CELL_CODE]); - private _cols: number; - private _rows: number; - - constructor( - private _hasScrollback: boolean, - private _optionsService: IOptionsService, - private _bufferService: IBufferService - ) { - this._cols = this._bufferService.cols; - this._rows = this._bufferService.rows; - this.lines = new CircularList(this._getCorrectBufferLength(this._rows)); - this.scrollTop = 0; - this.scrollBottom = this._rows - 1; - this.setupTabStops(); - } - - public getNullCell(attr?: IAttributeData): ICellData { - if (attr) { - this._nullCell.fg = attr.fg; - this._nullCell.bg = attr.bg; - } else { - this._nullCell.fg = 0; - this._nullCell.bg = 0; - } - return this._nullCell; - } - - public getWhitespaceCell(attr?: IAttributeData): ICellData { - if (attr) { - this._whitespaceCell.fg = attr.fg; - this._whitespaceCell.bg = attr.bg; - } else { - this._whitespaceCell.fg = 0; - this._whitespaceCell.bg = 0; - } - return this._whitespaceCell; - } - - public getBlankLine(attr: IAttributeData, isWrapped?: boolean): IBufferLine { - return new BufferLine(this._bufferService.cols, this.getNullCell(attr), isWrapped); - } - - public get hasScrollback(): boolean { - return this._hasScrollback && this.lines.maxLength > this._rows; - } - - public get isCursorInViewport(): boolean { - const absoluteY = this.ybase + this.y; - const relativeY = absoluteY - this.ydisp; - return (relativeY >= 0 && relativeY < this._rows); - } - - /** - * Gets the correct buffer length based on the rows provided, the terminal's - * scrollback and whether this buffer is flagged to have scrollback or not. - * @param rows The terminal rows to use in the calculation. - */ - private _getCorrectBufferLength(rows: number): number { - if (!this._hasScrollback) { - return rows; - } - - const correctBufferLength = rows + this._optionsService.options.scrollback; - - return correctBufferLength > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : correctBufferLength; - } - - /** - * Fills the buffer's viewport with blank lines. - */ - public fillViewportRows(fillAttr?: IAttributeData): void { - if (this.lines.length === 0) { - if (fillAttr === undefined) { - fillAttr = DEFAULT_ATTR_DATA; - } - let i = this._rows; - while (i--) { - this.lines.push(this.getBlankLine(fillAttr)); - } - } - } - - /** - * Clears the buffer to it's initial state, discarding all previous data. - */ - public clear(): void { - this.ydisp = 0; - this.ybase = 0; - this.y = 0; - this.x = 0; - this.lines = new CircularList(this._getCorrectBufferLength(this._rows)); - this.scrollTop = 0; - this.scrollBottom = this._rows - 1; - this.setupTabStops(); - } - - /** - * Resizes the buffer, adjusting its data accordingly. - * @param newCols The new number of columns. - * @param newRows The new number of rows. - */ - public resize(newCols: number, newRows: number): void { - // store reference to null cell with default attrs - const nullCell = this.getNullCell(DEFAULT_ATTR_DATA); - - // 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; - } - - // 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) { - for (let i = 0; i < this.lines.length; i++) { - this.lines.get(i)!.resize(newCols, nullCell); - } - } - - // Resize rows in both directions as needed - let addToY = 0; - if (this._rows < newRows) { - for (let y = this._rows; y < newRows; y++) { - if (this.lines.length < newRows + this.ybase) { - if (this._optionsService.options.windowsMode) { - // 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(newCols, nullCell)); - } 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 - this.ybase--; - addToY++; - if (this.ydisp > 0) { - // Viewport is at the top of the buffer, must increase downwards - 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 - this.lines.push(new BufferLine(newCols, nullCell)); - } - } - } - } - } else { // (this._rows >= newRows) - for (let y = this._rows; y > newRows; y--) { - if (this.lines.length > newRows + this.ybase) { - if (this.lines.length > this.ybase + this.y + 1) { - // The line is a blank line below the cursor, remove it - this.lines.pop(); - } else { - // The line is the cursor, scroll down - this.ybase++; - this.ydisp++; - } - } - } - } - - // 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; - if (amountToTrim > 0) { - this.lines.trimStart(amountToTrim); - this.ybase = Math.max(this.ybase - amountToTrim, 0); - this.ydisp = Math.max(this.ydisp - amountToTrim, 0); - this.savedY = Math.max(this.savedY - amountToTrim, 0); - } - this.lines.maxLength = newMaxLength; - } - - // Make sure that the cursor stays on screen - this.x = Math.min(this.x, newCols - 1); - this.y = Math.min(this.y, newRows - 1); - if (addToY) { - this.y += addToY; - } - this.savedX = Math.min(this.savedX, newCols - 1); - - this.scrollTop = 0; - } - - this.scrollBottom = newRows - 1; - - if (this._isReflowEnabled) { - this._reflow(newCols, newRows); - - // Trim the end of the line off if cols shrunk - if (this._cols > newCols) { - for (let i = 0; i < this.lines.length; i++) { - this.lines.get(i)!.resize(newCols, nullCell); - } - } - } - - this._cols = newCols; - this._rows = newRows; - } - - private get _isReflowEnabled(): boolean { - return this._hasScrollback && !this._optionsService.options.windowsMode; - } - - private _reflow(newCols: number, newRows: number): void { - if (this._cols === newCols) { - return; - } - - // Iterate through rows, ignore the last one as it cannot be wrapped - if (newCols > this._cols) { - this._reflowLarger(newCols, newRows); - } else { - this._reflowSmaller(newCols, newRows); - } - } - - private _reflowLarger(newCols: number, newRows: number): void { - const toRemove: number[] = reflowLargerGetLinesToRemove(this.lines, this._cols, newCols, this.ybase + this.y, this.getNullCell(DEFAULT_ATTR_DATA)); - if (toRemove.length > 0) { - const newLayoutResult = reflowLargerCreateNewLayout(this.lines, toRemove); - reflowLargerApplyNewLayout(this.lines, newLayoutResult.layout); - this._reflowLargerAdjustViewport(newCols, newRows, newLayoutResult.countRemoved); - } - } - - private _reflowLargerAdjustViewport(newCols: number, newRows: number, countRemoved: number): void { - const nullCell = this.getNullCell(DEFAULT_ATTR_DATA); - // Adjust viewport based on number of items removed - let viewportAdjustments = countRemoved; - while (viewportAdjustments-- > 0) { - if (this.ybase === 0) { - if (this.y > 0) { - this.y--; - } - if (this.lines.length < newRows) { - // Add an extra row at the bottom of the viewport - this.lines.push(new BufferLine(newCols, nullCell)); - } - } else { - if (this.ydisp === this.ybase) { - this.ydisp--; - } - this.ybase--; - } - } - this.savedY = Math.max(this.savedY - countRemoved, 0); - } - - private _reflowSmaller(newCols: number, newRows: number): void { - 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 - const toInsert = []; - let countToInsert = 0; - // Go backwards as many lines may be trimmed and this will avoid considering them - for (let y = this.lines.length - 1; y >= 0; y--) { - // Check whether this line is a problem - let nextLine = this.lines.get(y) as BufferLine; - if (!nextLine || !nextLine.isWrapped && nextLine.getTrimmedLength() <= newCols) { - continue; - } - - // Gather wrapped lines and adjust y to be the starting line - const wrappedLines: BufferLine[] = [nextLine]; - while (nextLine.isWrapped && y > 0) { - nextLine = this.lines.get(--y) as BufferLine; - wrappedLines.unshift(nextLine); - } - - // If these lines contain the cursor don't touch them, the program will handle fixing up - // wrapped lines with the cursor - const absoluteY = this.ybase + this.y; - if (absoluteY >= y && absoluteY < y + wrappedLines.length) { - continue; - } - - const lastLineLength = wrappedLines[wrappedLines.length - 1].getTrimmedLength(); - const destLineLengths = reflowSmallerGetNewLineLengths(wrappedLines, this._cols, newCols); - const linesToAdd = destLineLengths.length - wrappedLines.length; - let trimmedLines: number; - if (this.ybase === 0 && this.y !== this.lines.length - 1) { - // If the top section of the buffer is not yet filled - trimmedLines = Math.max(0, this.y - this.lines.maxLength + linesToAdd); - } else { - trimmedLines = Math.max(0, this.lines.length - this.lines.maxLength + linesToAdd); - } - - // Add the new lines - const newLines: BufferLine[] = []; - for (let i = 0; i < linesToAdd; i++) { - const newLine = this.getBlankLine(DEFAULT_ATTR_DATA, true) as BufferLine; - newLines.push(newLine); - } - 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 - start: y + wrappedLines.length + countToInsert, - newLines - }); - countToInsert += newLines.length; - } - wrappedLines.push(...newLines); - - // Copy buffer data to new locations, this needs to happen backwards to do in-place - let destLineIndex = destLineLengths.length - 1; // Math.floor(cellsNeeded / newCols); - let destCol = destLineLengths[destLineIndex]; // cellsNeeded % newCols; - if (destCol === 0) { - destLineIndex--; - destCol = destLineLengths[destLineIndex]; - } - let srcLineIndex = wrappedLines.length - linesToAdd - 1; - let srcCol = lastLineLength; - while (srcLineIndex >= 0) { - const cellsToCopy = Math.min(srcCol, destCol); - wrappedLines[destLineIndex].copyCellsFrom(wrappedLines[srcLineIndex], srcCol - cellsToCopy, destCol - cellsToCopy, cellsToCopy, true); - destCol -= cellsToCopy; - if (destCol === 0) { - destLineIndex--; - destCol = destLineLengths[destLineIndex]; - } - srcCol -= cellsToCopy; - if (srcCol === 0) { - srcLineIndex--; - const wrappedLinesIndex = Math.max(srcLineIndex, 0); - srcCol = getWrappedLineTrimmedLength(wrappedLines, wrappedLinesIndex, this._cols); - } - } - - // Null out the end of the line ends if a wide character wrapped to the following line - for (let i = 0; i < wrappedLines.length; i++) { - if (destLineLengths[i] < newCols) { - wrappedLines[i].setCell(destLineLengths[i], nullCell); - } - } - - // Adjust viewport as needed - let viewportAdjustments = linesToAdd - trimmedLines; - while (viewportAdjustments-- > 0) { - if (this.ybase === 0) { - if (this.y < newRows - 1) { - this.y++; - this.lines.pop(); - } else { - this.ybase++; - this.ydisp++; - } - } else { - // Ensure ybase does not exceed its maximum value - if (this.ybase < Math.min(this.lines.maxLength, this.lines.length + countToInsert) - newRows) { - if (this.ybase === this.ydisp) { - this.ydisp++; - } - this.ybase++; - } - } - } - 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. - if (toInsert.length > 0) { - // 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 - const originalLines: BufferLine[] = []; - for (let i = 0; i < this.lines.length; i++) { - originalLines.push(this.lines.get(i) as BufferLine); - } - const originalLinesLength = this.lines.length; - - let originalLineIndex = originalLinesLength - 1; - let nextToInsertIndex = 0; - let nextToInsert = toInsert[nextToInsertIndex]; - this.lines.length = Math.min(this.lines.maxLength, this.lines.length + countToInsert); - let countInsertedSoFar = 0; - for (let i = Math.min(this.lines.maxLength - 1, originalLinesLength + countToInsert - 1); i >= 0; i--) { - if (nextToInsert && nextToInsert.start > originalLineIndex + countInsertedSoFar) { - // Insert extra lines here, adjusting i as needed - for (let nextI = nextToInsert.newLines.length - 1; nextI >= 0; nextI--) { - this.lines.set(i--, nextToInsert.newLines[nextI]); - } - i++; - - // Create insert events for later - insertEvents.push({ - index: originalLineIndex + 1, - amount: nextToInsert.newLines.length - }); - - countInsertedSoFar += nextToInsert.newLines.length; - nextToInsert = toInsert[++nextToInsertIndex]; - } else { - this.lines.set(i, originalLines[originalLineIndex--]); - } - } - - // Update markers - let insertCountEmitted = 0; - for (let i = insertEvents.length - 1; i >= 0; i--) { - insertEvents[i].index += insertCountEmitted; - this.lines.onInsertEmitter.fire(insertEvents[i]); - insertCountEmitted += insertEvents[i].amount; - } - const amountToTrim = Math.max(0, originalLinesLength + countToInsert - this.lines.maxLength); - if (amountToTrim > 0) { - this.lines.onTrimEmitter.fire(amountToTrim); - } - } - } - - // private _reflowSmallerGetLinesNeeded() - - /** - * Translates a string index back to a BufferIndex. - * To get the correct buffer position the string must start at `startCol` 0 - * (default in translateBufferLineToString). - * The method also works on wrapped line strings given rows were not trimmed. - * The method operates on the CharData string length, there are no - * additional content or boundary checks. Therefore the string and the buffer - * should not be altered in between. - * TODO: respect trim flag after fixing #1685 - * @param lineIndex line index the string was retrieved from - * @param stringIndex index within the string - * @param startCol column offset the string was retrieved from - */ - public stringIndexToBufferIndex(lineIndex: number, stringIndex: number, trimRight: boolean = false): BufferIndex { - while (stringIndex) { - const line = this.lines.get(lineIndex); - if (!line) { - return [-1, -1]; - } - const length = (trimRight) ? line.getTrimmedLength() : line.length; - for (let i = 0; i < length; ++i) { - if (line.get(i)[CHAR_DATA_WIDTH_INDEX]) { - // empty cells report a string length of 0, but get replaced - // with a whitespace in translateToString, thus replace with 1 - stringIndex -= line.get(i)[CHAR_DATA_CHAR_INDEX].length || 1; - } - if (stringIndex < 0) { - return [lineIndex, i]; - } - } - lineIndex++; - } - return [lineIndex, 0]; - } - - /** - * Translates a buffer line to a string, with optional start and end columns. - * Wide characters will count as two columns in the resulting string. This - * function is useful for getting the actual text underneath the raw selection - * position. - * @param line The line being translated. - * @param trimRight Whether to trim whitespace to the right. - * @param startCol The column to start at. - * @param endCol The column to end at. - */ - public translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol: number = 0, endCol?: number): string { - const line = this.lines.get(lineIndex); - if (!line) { - return ''; - } - return line.translateToString(trimRight, startCol, endCol); - } - - public getWrappedRangeForLine(y: number): { first: number, last: number } { - let first = y; - let last = y; - // Scan upwards for wrapped lines - while (first > 0 && this.lines.get(first)!.isWrapped) { - first--; - } - // Scan downwards for wrapped lines - while (last + 1 < this.lines.length && this.lines.get(last + 1)!.isWrapped) { - last++; - } - return { first, last }; - } - - /** - * Setup the tab stops. - * @param i The index to start setting up tab stops from. - */ - public setupTabStops(i?: number): void { - if (i !== null && i !== undefined) { - if (!this.tabs[i]) { - i = this.prevStop(i); - } - } else { - this.tabs = {}; - i = 0; - } - - for (; i < this._cols; i += this._optionsService.options.tabStopWidth) { - this.tabs[i] = true; - } - } - - /** - * Move the cursor to the previous tab stop from the given position (default is current). - * @param x The position to move the cursor to the previous tab stop. - */ - public prevStop(x?: number): number { - if (x === null || x === undefined) { - x = this.x; - } - while (!this.tabs[--x] && x > 0); - return x >= this._cols ? this._cols - 1 : x < 0 ? 0 : x; - } - - /** - * Move the cursor one tab stop forward from the given position (default is current). - * @param x The position to move the cursor one tab stop forward. - */ - public nextStop(x?: number): number { - if (x === null || x === undefined) { - x = this.x; - } - while (!this.tabs[++x] && x < this._cols); - return x >= this._cols ? this._cols - 1 : x < 0 ? 0 : x; - } - - public addMarker(y: number): Marker { - const marker = new Marker(y); - this.markers.push(marker); - marker.register(this.lines.onTrim(amount => { - marker.line -= amount; - // The marker should be disposed when the line is trimmed from the buffer - if (marker.line < 0) { - marker.dispose(); - } - })); - marker.register(this.lines.onInsert(event => { - if (marker.line >= event.index) { - marker.line += event.amount; - } - })); - marker.register(this.lines.onDelete(event => { - // Delete the marker if it's within the range - if (marker.line >= event.index && marker.line < event.index + event.amount) { - marker.dispose(); - } - - // Shift the marker if it's after the deleted range - if (marker.line > event.index) { - marker.line -= event.amount; - } - })); - marker.register(marker.onDispose(() => this._removeMarker(marker))); - return marker; - } - - private _removeMarker(marker: Marker): void { - this.markers.splice(this.markers.indexOf(marker), 1); - } - - public iterator(trimRight: boolean, startIndex?: number, endIndex?: number, startOverscan?: number, endOverscan?: number): IBufferStringIterator { - return new BufferStringIterator(this, trimRight, startIndex, endIndex, startOverscan, endOverscan); - } -} - -/** - * Iterator to get unwrapped content strings from the buffer. - * The iterator returns at least the string data between the borders - * `startIndex` and `endIndex` (exclusive) and will expand the lines - * by `startOverscan` to the top and by `endOverscan` to the bottom, - * if no new line was found in between. - * It will never read/return string data beyond `startIndex - startOverscan` - * or `endIndex + endOverscan`. Therefore the first and last line might be truncated. - * It is possible to always get the full string for the first and last line as well - * by setting the overscan values to the actual buffer length. This not recommended - * since it might return the whole buffer within a single string in a worst case scenario. - */ -export class BufferStringIterator implements IBufferStringIterator { - private _current: number; - - constructor ( - private _buffer: IBuffer, - private _trimRight: boolean, - private _startIndex: number = 0, - private _endIndex: number = _buffer.lines.length, - private _startOverscan: number = 0, - private _endOverscan: number = 0 - ) { - if (this._startIndex < 0) { - this._startIndex = 0; - } - if (this._endIndex > this._buffer.lines.length) { - this._endIndex = this._buffer.lines.length; - } - this._current = this._startIndex; - } - - public hasNext(): boolean { - return this._current < this._endIndex; - } - - public next(): IBufferStringIteratorResult { - const range = this._buffer.getWrappedRangeForLine(this._current); - // limit search window to overscan value at both borders - if (range.first < this._startIndex - this._startOverscan) { - range.first = this._startIndex - this._startOverscan; - } - if (range.last > this._endIndex + this._endOverscan) { - range.last = this._endIndex + this._endOverscan; - } - // limit to current buffer length - range.first = Math.max(range.first, 0); - range.last = Math.min(range.last, this._buffer.lines.length); - let result = ''; - for (let i = range.first; i <= range.last; ++i) { - result += this._buffer.translateBufferLineToString(i, this._trimRight); - } - this._current = range.last + 1; - return {range: range, content: result}; - } -}