64 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			64 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | /** | ||
|  |  * @license | ||
|  |  * Copyright Google Inc. 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
 | ||
|  |  */ | ||
|  | 
 | ||
|  | 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. */ | ||
|  | export function getLineAndCharacterFromPosition(lineStartsMap: number[], position: number) { | ||
|  |   const lineIndex = findClosestLineStartPosition(lineStartsMap, position); | ||
|  |   return {character: position - lineStartsMap[lineIndex], line: lineIndex}; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * 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. | ||
|  |  */ | ||
|  | export function computeLineStartsMap(text: string): number[] { | ||
|  |   const result: number[] = [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; | ||
|  | } | ||
|  | 
 | ||
|  | /** Finds the closest line start for the given position. */ | ||
|  | function findClosestLineStartPosition<T>( | ||
|  |     linesMap: T[], position: T, low = 0, high = linesMap.length - 1) { | ||
|  |   while (low <= high) { | ||
|  |     const pivotIdx = Math.floor((low + high) / 2); | ||
|  |     const pivotEl = linesMap[pivotIdx]; | ||
|  | 
 | ||
|  |     if (pivotEl === position) { | ||
|  |       return pivotIdx; | ||
|  |     } else if (position > pivotEl) { | ||
|  |       low = pivotIdx + 1; | ||
|  |     } else { | ||
|  |       high = pivotIdx - 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; | ||
|  | } |