| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							| 
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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; | 
					
						
							|  |  |  | } |