| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import * as strings from '../../../base/common/strings.js';
- export class LineDecoration {
- constructor(startColumn, endColumn, className, type) {
- this.startColumn = startColumn;
- this.endColumn = endColumn;
- this.className = className;
- this.type = type;
- this._lineDecorationBrand = undefined;
- }
- static _equals(a, b) {
- return (a.startColumn === b.startColumn
- && a.endColumn === b.endColumn
- && a.className === b.className
- && a.type === b.type);
- }
- static equalsArr(a, b) {
- const aLen = a.length;
- const bLen = b.length;
- if (aLen !== bLen) {
- return false;
- }
- for (let i = 0; i < aLen; i++) {
- if (!LineDecoration._equals(a[i], b[i])) {
- return false;
- }
- }
- return true;
- }
- static extractWrapped(arr, startOffset, endOffset) {
- if (arr.length === 0) {
- return arr;
- }
- const startColumn = startOffset + 1;
- const endColumn = endOffset + 1;
- const lineLength = endOffset - startOffset;
- const r = [];
- let rLength = 0;
- for (const dec of arr) {
- if (dec.endColumn <= startColumn || dec.startColumn >= endColumn) {
- continue;
- }
- r[rLength++] = new LineDecoration(Math.max(1, dec.startColumn - startColumn + 1), Math.min(lineLength + 1, dec.endColumn - startColumn + 1), dec.className, dec.type);
- }
- return r;
- }
- static filter(lineDecorations, lineNumber, minLineColumn, maxLineColumn) {
- if (lineDecorations.length === 0) {
- return [];
- }
- const result = [];
- let resultLen = 0;
- for (let i = 0, len = lineDecorations.length; i < len; i++) {
- const d = lineDecorations[i];
- const range = d.range;
- if (range.endLineNumber < lineNumber || range.startLineNumber > lineNumber) {
- // Ignore decorations that sit outside this line
- continue;
- }
- if (range.isEmpty() && (d.type === 0 /* InlineDecorationType.Regular */ || d.type === 3 /* InlineDecorationType.RegularAffectingLetterSpacing */)) {
- // Ignore empty range decorations
- continue;
- }
- const startColumn = (range.startLineNumber === lineNumber ? range.startColumn : minLineColumn);
- const endColumn = (range.endLineNumber === lineNumber ? range.endColumn : maxLineColumn);
- result[resultLen++] = new LineDecoration(startColumn, endColumn, d.inlineClassName, d.type);
- }
- return result;
- }
- static _typeCompare(a, b) {
- const ORDER = [2, 0, 1, 3];
- return ORDER[a] - ORDER[b];
- }
- static compare(a, b) {
- if (a.startColumn !== b.startColumn) {
- return a.startColumn - b.startColumn;
- }
- if (a.endColumn !== b.endColumn) {
- return a.endColumn - b.endColumn;
- }
- const typeCmp = LineDecoration._typeCompare(a.type, b.type);
- if (typeCmp !== 0) {
- return typeCmp;
- }
- if (a.className !== b.className) {
- return a.className < b.className ? -1 : 1;
- }
- return 0;
- }
- }
- export class DecorationSegment {
- constructor(startOffset, endOffset, className, metadata) {
- this.startOffset = startOffset;
- this.endOffset = endOffset;
- this.className = className;
- this.metadata = metadata;
- }
- }
- class Stack {
- constructor() {
- this.stopOffsets = [];
- this.classNames = [];
- this.metadata = [];
- this.count = 0;
- }
- static _metadata(metadata) {
- let result = 0;
- for (let i = 0, len = metadata.length; i < len; i++) {
- result |= metadata[i];
- }
- return result;
- }
- consumeLowerThan(maxStopOffset, nextStartOffset, result) {
- while (this.count > 0 && this.stopOffsets[0] < maxStopOffset) {
- let i = 0;
- // Take all equal stopping offsets
- while (i + 1 < this.count && this.stopOffsets[i] === this.stopOffsets[i + 1]) {
- i++;
- }
- // Basically we are consuming the first i + 1 elements of the stack
- result.push(new DecorationSegment(nextStartOffset, this.stopOffsets[i], this.classNames.join(' '), Stack._metadata(this.metadata)));
- nextStartOffset = this.stopOffsets[i] + 1;
- // Consume them
- this.stopOffsets.splice(0, i + 1);
- this.classNames.splice(0, i + 1);
- this.metadata.splice(0, i + 1);
- this.count -= (i + 1);
- }
- if (this.count > 0 && nextStartOffset < maxStopOffset) {
- result.push(new DecorationSegment(nextStartOffset, maxStopOffset - 1, this.classNames.join(' '), Stack._metadata(this.metadata)));
- nextStartOffset = maxStopOffset;
- }
- return nextStartOffset;
- }
- insert(stopOffset, className, metadata) {
- if (this.count === 0 || this.stopOffsets[this.count - 1] <= stopOffset) {
- // Insert at the end
- this.stopOffsets.push(stopOffset);
- this.classNames.push(className);
- this.metadata.push(metadata);
- }
- else {
- // Find the insertion position for `stopOffset`
- for (let i = 0; i < this.count; i++) {
- if (this.stopOffsets[i] >= stopOffset) {
- this.stopOffsets.splice(i, 0, stopOffset);
- this.classNames.splice(i, 0, className);
- this.metadata.splice(i, 0, metadata);
- break;
- }
- }
- }
- this.count++;
- return;
- }
- }
- export class LineDecorationsNormalizer {
- /**
- * Normalize line decorations. Overlapping decorations will generate multiple segments
- */
- static normalize(lineContent, lineDecorations) {
- if (lineDecorations.length === 0) {
- return [];
- }
- const result = [];
- const stack = new Stack();
- let nextStartOffset = 0;
- for (let i = 0, len = lineDecorations.length; i < len; i++) {
- const d = lineDecorations[i];
- let startColumn = d.startColumn;
- let endColumn = d.endColumn;
- const className = d.className;
- const metadata = (d.type === 1 /* InlineDecorationType.Before */
- ? 2 /* LinePartMetadata.PSEUDO_BEFORE */
- : d.type === 2 /* InlineDecorationType.After */
- ? 4 /* LinePartMetadata.PSEUDO_AFTER */
- : 0);
- // If the position would end up in the middle of a high-low surrogate pair, we move it to before the pair
- if (startColumn > 1) {
- const charCodeBefore = lineContent.charCodeAt(startColumn - 2);
- if (strings.isHighSurrogate(charCodeBefore)) {
- startColumn--;
- }
- }
- if (endColumn > 1) {
- const charCodeBefore = lineContent.charCodeAt(endColumn - 2);
- if (strings.isHighSurrogate(charCodeBefore)) {
- endColumn--;
- }
- }
- const currentStartOffset = startColumn - 1;
- const currentEndOffset = endColumn - 2;
- nextStartOffset = stack.consumeLowerThan(currentStartOffset, nextStartOffset, result);
- if (stack.count === 0) {
- nextStartOffset = currentStartOffset;
- }
- stack.insert(currentEndOffset, className, metadata);
- }
- stack.consumeLowerThan(1073741824 /* Constants.MAX_SAFE_SMALL_INTEGER */, nextStartOffset, result);
- return result;
- }
- }
|