aboutsummaryrefslogtreecommitdiffstats
path: root/node_modules/xterm/src/browser/services/CharacterJoinerService.ts
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/xterm/src/browser/services/CharacterJoinerService.ts')
-rw-r--r--node_modules/xterm/src/browser/services/CharacterJoinerService.ts339
1 files changed, 0 insertions, 339 deletions
diff --git a/node_modules/xterm/src/browser/services/CharacterJoinerService.ts b/node_modules/xterm/src/browser/services/CharacterJoinerService.ts
deleted file mode 100644
index ca4f198..0000000
--- a/node_modules/xterm/src/browser/services/CharacterJoinerService.ts
+++ /dev/null
@@ -1,339 +0,0 @@
-/**
- * Copyright (c) 2018 The xterm.js authors. All rights reserved.
- * @license MIT
- */
-
-import { IBufferLine, ICellData, CharData } from 'common/Types';
-import { ICharacterJoiner } from 'browser/Types';
-import { AttributeData } from 'common/buffer/AttributeData';
-import { WHITESPACE_CELL_CHAR, Content } from 'common/buffer/Constants';
-import { CellData } from 'common/buffer/CellData';
-import { IBufferService } from 'common/services/Services';
-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
- public content: number = 0;
- public fg: number;
- public bg: number;
- public combinedData: string = '';
-
- constructor(firstCell: ICellData, chars: string, width: number) {
- super();
- this.fg = firstCell.fg;
- this.bg = firstCell.bg;
- this.combinedData = chars;
- this._width = width;
- }
-
- public isCombined(): number {
- // always mark joined cell data as combined
- return Content.IS_COMBINED_MASK;
- }
-
- public getWidth(): number {
- return this._width;
- }
-
- public getChars(): string {
- return this.combinedData;
- }
-
- 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
- return 0x1FFFFF;
- }
-
- public setFromCharData(value: CharData): void {
- throw new Error('not implemented');
- }
-
- public getAsCharData(): CharData {
- return [this.fg, this.getChars(), this.getWidth(), this.getCode()];
- }
-}
-
-export class CharacterJoinerService implements ICharacterJoinerService {
- public serviceBrand: undefined;
-
- private _characterJoiners: ICharacterJoiner[] = [];
- private _nextCharacterJoinerId: number = 0;
- private _workCell: CellData = new CellData();
-
- constructor(
- @IBufferService private _bufferService: IBufferService
- ) { }
-
- public register(handler: (text: string) => [number, number][]): number {
- const joiner: ICharacterJoiner = {
- id: this._nextCharacterJoinerId++,
- handler
- };
-
- this._characterJoiners.push(joiner);
- return joiner.id;
- }
-
- public deregister(joinerId: number): boolean {
- for (let i = 0; i < this._characterJoiners.length; i++) {
- if (this._characterJoiners[i].id === joinerId) {
- this._characterJoiners.splice(i, 1);
- return true;
- }
- }
-
- return false;
- }
-
- public getJoinedCharacters(row: number): [number, number][] {
- if (this._characterJoiners.length === 0) {
- return [];
- }
-
- const line = this._bufferService.buffer.lines.get(row);
- if (!line || line.length === 0) {
- return [];
- }
-
- 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
- let rangeStartColumn = 0;
- let currentStringIndex = 0;
- let rangeStartStringIndex = 0;
- let rangeAttrFG = line.getFg(0);
- let rangeAttrBG = line.getBg(0);
-
- for (let x = 0; x < line.getTrimmedLength(); x++) {
- line.loadCell(x, this._workCell);
-
- if (this._workCell.getWidth() === 0) {
- // If this character is of width 0, skip it.
- continue;
- }
-
- // 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 (x - rangeStartColumn > 1) {
- const joinedRanges = this._getJoinedRanges(
- lineStr,
- rangeStartStringIndex,
- currentStringIndex,
- line,
- rangeStartColumn
- );
- for (let i = 0; i < joinedRanges.length; i++) {
- ranges.push(joinedRanges[i]);
- }
- }
-
- // Reset our markers for a new range.
- rangeStartColumn = x;
- rangeStartStringIndex = currentStringIndex;
- rangeAttrFG = this._workCell.fg;
- rangeAttrBG = this._workCell.bg;
- }
-
- currentStringIndex += this._workCell.getChars().length || WHITESPACE_CELL_CHAR.length;
- }
-
- // Process any trailing ranges.
- if (this._bufferService.cols - rangeStartColumn > 1) {
- const joinedRanges = this._getJoinedRanges(
- lineStr,
- rangeStartStringIndex,
- currentStringIndex,
- line,
- rangeStartColumn
- );
- for (let i = 0; i < joinedRanges.length; i++) {
- ranges.push(joinedRanges[i]);
- }
- }
-
- return ranges;
- }
-
- /**
- * Given a segment of a line of text, find all ranges of text that should be
- * joined in a single rendering unit. Ranges are internally converted to
- * column ranges, rather than string ranges.
- * @param line String representation of the full line of text
- * @param startIndex Start position of the range to search in the string (inclusive)
- * @param endIndex End position of the range to search in the string (exclusive)
- */
- 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.
- let allJoinedRanges: [number, number][] = [];
- try {
- allJoinedRanges = this._characterJoiners[0].handler(text);
- } catch (error) {
- console.error(error);
- }
- for (let i = 1; i < this._characterJoiners.length; i++) {
- // We merge any overlapping ranges across the different joiners
- try {
- const joinerRanges = this._characterJoiners[i].handler(text);
- for (let j = 0; j < joinerRanges.length; j++) {
- CharacterJoinerService._mergeRanges(allJoinedRanges, joinerRanges[j]);
- }
- } catch (error) {
- console.error(error);
- }
- }
- this._stringRangesToCellRanges(allJoinedRanges, lineData, startCol);
- return allJoinedRanges;
- }
-
- /**
- * Modifies the provided ranges in-place to adjust for variations between
- * string length and cell width so that the range represents a cell range,
- * rather than the string range the joiner provides.
- * @param ranges String ranges containing start (inclusive) and end (exclusive) index
- * @param line Cell data for the relevant line in the terminal
- * @param startCol Offset within the line to start from
- */
- private _stringRangesToCellRanges(ranges: [number, number][], line: IBufferLine, startCol: number): void {
- let currentRangeIndex = 0;
- let currentRangeStarted = false;
- let currentStringIndex = 0;
- let currentRange = ranges[currentRangeIndex];
-
- // If we got through all of the ranges, stop searching
- if (!currentRange) {
- return;
- }
-
- for (let x = startCol; x < this._bufferService.cols; x++) {
- 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
- if (width === 0) {
- continue;
- }
-
- // Adjust the start of the range
- if (!currentRangeStarted && currentRange[0] <= currentStringIndex) {
- currentRange[0] = x;
- currentRangeStarted = true;
- }
-
- // Adjust the end of the range
- if (currentRange[1] <= currentStringIndex) {
- currentRange[1] = x;
-
- // We're finished with this range, so we move to the next one
- currentRange = ranges[++currentRangeIndex];
-
- // If there are no more ranges left, stop searching
- if (!currentRange) {
- 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.
- if (currentRange[0] <= currentStringIndex) {
- currentRange[0] = x;
- currentRangeStarted = true;
- } else {
- currentRangeStarted = false;
- }
- }
-
- // 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 (currentRange) {
- currentRange[1] = this._bufferService.cols;
- }
- }
-
- /**
- * Merges the range defined by the provided start and end into the list of
- * existing ranges. The merge is done in place on the existing range for
- * performance and is also returned.
- * @param ranges Existing range list
- * @param newRange Tuple of two numbers representing the new range to merge in.
- * @returns The ranges input with the new range merged in place
- */
- private static _mergeRanges(ranges: [number, number][], newRange: [number, number]): [number, number][] {
- let inRange = false;
- for (let i = 0; i < ranges.length; i++) {
- const range = ranges[i];
- if (!inRange) {
- if (newRange[1] <= range[0]) {
- // Case 1: New range is before the search range
- ranges.splice(i, 0, newRange);
- return ranges;
- }
-
- if (newRange[1] <= range[1]) {
- // 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
- range[0] = Math.min(newRange[0], range[0]);
- inRange = true;
- }
-
- // Case 4: New range starts after the search range
- continue;
- } else {
- if (newRange[1] <= range[0]) {
- // 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
- 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
- ranges.splice(i, 1);
- i--;
- }
- }
-
- if (inRange) {
- // Case 8: New range extends past the last existing range
- ranges[ranges.length - 1][1] = newRange[1];
- } else {
- // Case 9: New range starts after the last existing range
- ranges.push(newRange);
- }
-
- return ranges;
- }
-}