blob: fff470806c3e58854252858b2e5ab63325d4ab9f [file] [log] [blame]
"use strict";
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
Object.defineProperty(exports, "__esModule", { value: true });
/*
* Line mapping utilities which can be used to retrieve line and character based
* on an absolute character position in a given file. This functionality is similar
* to TypeScript's "ts.getLineAndCharacterFromPosition" utility, but we cannot leverage
* their logic for line mappings as it's internal and we need to generate line mappings
* for non-TypeScript files such as HTML templates or stylesheets.
*
* Line and character can be retrieved by splitting a given source text based on
* line breaks into line start entries. Later when a specific position is requested,
* the closest line-start position is determined based on the given position.
*/
const LF_CHAR = 10;
const CR_CHAR = 13;
const LINE_SEP_CHAR = 8232;
const PARAGRAPH_CHAR = 8233;
/** Gets the line and character for the given position from the line starts map. */
function getLineAndCharacterFromPosition(lineStartsMap, position) {
const lineIndex = findClosestLineStartPosition(lineStartsMap, position);
return { character: position - lineStartsMap[lineIndex], line: lineIndex };
}
exports.getLineAndCharacterFromPosition = getLineAndCharacterFromPosition;
/**
* Computes the line start map of the given text. This can be used in order to
* retrieve the line and character of a given text position index.
*/
function computeLineStartsMap(text) {
const result = [0];
let pos = 0;
while (pos < text.length) {
const char = text.charCodeAt(pos++);
// Handles the "CRLF" line break. In that case we peek the character
// after the "CR" and check if it is a line feed.
if (char === CR_CHAR) {
if (text.charCodeAt(pos) === LF_CHAR) {
pos++;
}
result.push(pos);
}
else if (char === LF_CHAR || char === LINE_SEP_CHAR || char === PARAGRAPH_CHAR) {
result.push(pos);
}
}
result.push(pos);
return result;
}
exports.computeLineStartsMap = computeLineStartsMap;
/** Finds the closest line start for the given position. */
function findClosestLineStartPosition(linesMap, position, low = 0, high = linesMap.length - 1) {
while (low <= high) {
const pivotIndex = Math.floor((low + high) / 2);
const pivotEl = linesMap[pivotIndex];
if (pivotEl === position) {
return pivotIndex;
}
else if (position > pivotEl) {
low = pivotIndex + 1;
}
else {
high = pivotIndex - 1;
}
}
// In case there was no exact match, return the closest "lower" line index. We also
// subtract the index by one because want the index of the previous line start.
return low - 1;
}
//# sourceMappingURL=line-mappings.js.map