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;
							 | 
						||
| 
								 | 
							
								}
							 |