UNPKG

monaco-editor

Version:
187 lines (186 loc) • 8.2 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { findLastIdxMonotonous, findLastMonotonous, findFirstMonotonous } from '../../../../base/common/arraysFind.js'; import { OffsetRange } from '../../core/offsetRange.js'; import { Position } from '../../core/position.js'; import { Range } from '../../core/range.js'; import { isSpace } from './utils.js'; export class LinesSliceCharSequence { constructor(lines, lineRange, considerWhitespaceChanges) { // This slice has to have lineRange.length many \n! (otherwise diffing against an empty slice will be problematic) // (Unless it covers the entire document, in that case the other slice also has to cover the entire document ands it's okay) this.lines = lines; this.considerWhitespaceChanges = considerWhitespaceChanges; this.elements = []; this.firstCharOffsetByLine = []; // To account for trimming this.additionalOffsetByLine = []; // If the slice covers the end, but does not start at the beginning, we include just the \n of the previous line. let trimFirstLineFully = false; if (lineRange.start > 0 && lineRange.endExclusive >= lines.length) { lineRange = new OffsetRange(lineRange.start - 1, lineRange.endExclusive); trimFirstLineFully = true; } this.lineRange = lineRange; this.firstCharOffsetByLine[0] = 0; for (let i = this.lineRange.start; i < this.lineRange.endExclusive; i++) { let line = lines[i]; let offset = 0; if (trimFirstLineFully) { offset = line.length; line = ''; trimFirstLineFully = false; } else if (!considerWhitespaceChanges) { const trimmedStartLine = line.trimStart(); offset = line.length - trimmedStartLine.length; line = trimmedStartLine.trimEnd(); } this.additionalOffsetByLine.push(offset); for (let i = 0; i < line.length; i++) { this.elements.push(line.charCodeAt(i)); } // Don't add an \n that does not exist in the document. if (i < lines.length - 1) { this.elements.push('\n'.charCodeAt(0)); this.firstCharOffsetByLine[i - this.lineRange.start + 1] = this.elements.length; } } // To account for the last line this.additionalOffsetByLine.push(0); } toString() { return `Slice: "${this.text}"`; } get text() { return this.getText(new OffsetRange(0, this.length)); } getText(range) { return this.elements.slice(range.start, range.endExclusive).map(e => String.fromCharCode(e)).join(''); } getElement(offset) { return this.elements[offset]; } get length() { return this.elements.length; } getBoundaryScore(length) { // a b c , d e f // 11 0 0 12 15 6 13 0 0 11 const prevCategory = getCategory(length > 0 ? this.elements[length - 1] : -1); const nextCategory = getCategory(length < this.elements.length ? this.elements[length] : -1); if (prevCategory === 7 /* CharBoundaryCategory.LineBreakCR */ && nextCategory === 8 /* CharBoundaryCategory.LineBreakLF */) { // don't break between \r and \n return 0; } if (prevCategory === 8 /* CharBoundaryCategory.LineBreakLF */) { // prefer the linebreak before the change return 150; } let score = 0; if (prevCategory !== nextCategory) { score += 10; if (prevCategory === 0 /* CharBoundaryCategory.WordLower */ && nextCategory === 1 /* CharBoundaryCategory.WordUpper */) { score += 1; } } score += getCategoryBoundaryScore(prevCategory); score += getCategoryBoundaryScore(nextCategory); return score; } translateOffset(offset) { // find smallest i, so that lineBreakOffsets[i] <= offset using binary search if (this.lineRange.isEmpty) { return new Position(this.lineRange.start + 1, 1); } const i = findLastIdxMonotonous(this.firstCharOffsetByLine, (value) => value <= offset); return new Position(this.lineRange.start + i + 1, offset - this.firstCharOffsetByLine[i] + this.additionalOffsetByLine[i] + 1); } translateRange(range) { return Range.fromPositions(this.translateOffset(range.start), this.translateOffset(range.endExclusive)); } /** * Finds the word that contains the character at the given offset */ findWordContaining(offset) { if (offset < 0 || offset >= this.elements.length) { return undefined; } if (!isWordChar(this.elements[offset])) { return undefined; } // find start let start = offset; while (start > 0 && isWordChar(this.elements[start - 1])) { start--; } // find end let end = offset; while (end < this.elements.length && isWordChar(this.elements[end])) { end++; } return new OffsetRange(start, end); } countLinesIn(range) { return this.translateOffset(range.endExclusive).lineNumber - this.translateOffset(range.start).lineNumber; } isStronglyEqual(offset1, offset2) { return this.elements[offset1] === this.elements[offset2]; } extendToFullLines(range) { var _a, _b; const start = (_a = findLastMonotonous(this.firstCharOffsetByLine, x => x <= range.start)) !== null && _a !== void 0 ? _a : 0; const end = (_b = findFirstMonotonous(this.firstCharOffsetByLine, x => range.endExclusive <= x)) !== null && _b !== void 0 ? _b : this.elements.length; return new OffsetRange(start, end); } } function isWordChar(charCode) { return charCode >= 97 /* CharCode.a */ && charCode <= 122 /* CharCode.z */ || charCode >= 65 /* CharCode.A */ && charCode <= 90 /* CharCode.Z */ || charCode >= 48 /* CharCode.Digit0 */ && charCode <= 57 /* CharCode.Digit9 */; } const score = { [0 /* CharBoundaryCategory.WordLower */]: 0, [1 /* CharBoundaryCategory.WordUpper */]: 0, [2 /* CharBoundaryCategory.WordNumber */]: 0, [3 /* CharBoundaryCategory.End */]: 10, [4 /* CharBoundaryCategory.Other */]: 2, [5 /* CharBoundaryCategory.Separator */]: 30, [6 /* CharBoundaryCategory.Space */]: 3, [7 /* CharBoundaryCategory.LineBreakCR */]: 10, [8 /* CharBoundaryCategory.LineBreakLF */]: 10, }; function getCategoryBoundaryScore(category) { return score[category]; } function getCategory(charCode) { if (charCode === 10 /* CharCode.LineFeed */) { return 8 /* CharBoundaryCategory.LineBreakLF */; } else if (charCode === 13 /* CharCode.CarriageReturn */) { return 7 /* CharBoundaryCategory.LineBreakCR */; } else if (isSpace(charCode)) { return 6 /* CharBoundaryCategory.Space */; } else if (charCode >= 97 /* CharCode.a */ && charCode <= 122 /* CharCode.z */) { return 0 /* CharBoundaryCategory.WordLower */; } else if (charCode >= 65 /* CharCode.A */ && charCode <= 90 /* CharCode.Z */) { return 1 /* CharBoundaryCategory.WordUpper */; } else if (charCode >= 48 /* CharCode.Digit0 */ && charCode <= 57 /* CharCode.Digit9 */) { return 2 /* CharBoundaryCategory.WordNumber */; } else if (charCode === -1) { return 3 /* CharBoundaryCategory.End */; } else if (charCode === 44 /* CharCode.Comma */ || charCode === 59 /* CharCode.Semicolon */) { return 5 /* CharBoundaryCategory.Separator */; } else { return 4 /* CharBoundaryCategory.Other */; } }