@@ -8,15 +8,13 @@ namespace ts.server {
88 export interface LineCollection {
99 charCount ( ) : number ;
1010 lineCount ( ) : number ;
11- isLeaf ( ) : boolean ;
11+ isLeaf ( ) : this is LineLeaf ;
1212 walk ( rangeStart : number , rangeLength : number , walkFns : ILineIndexWalker ) : void ;
1313 }
1414
15- export interface ILineInfo {
16- line : number ;
17- offset : number ;
18- text ?: string ;
19- leaf ?: LineLeaf ;
15+ export interface AbsolutePositionAndLineText {
16+ absolutePosition : number ;
17+ lineText : string | undefined ;
2018 }
2119
2220 export enum CharRangeSection {
@@ -397,22 +395,27 @@ namespace ts.server {
397395 // set this to true to check each edit for accuracy
398396 checkEdits = false ;
399397
400- charOffsetToLineNumberAndPos ( charOffset : number ) {
401- return this . root . charOffsetToLineNumberAndPos ( 1 , charOffset ) ;
398+ absolutePositionOfStartOfLine ( oneBasedLine : number ) : number {
399+ return this . lineNumberToInfo ( oneBasedLine ) . absolutePosition ;
402400 }
403401
404- lineNumberToInfo ( lineNumber : number ) : ILineInfo {
402+ positionToLineOffset ( position : number ) : protocol . Location {
403+ const { oneBasedLine, zeroBasedColumn } = this . root . charOffsetToLineInfo ( 1 , position ) ;
404+ return { line : oneBasedLine , offset : zeroBasedColumn + 1 } ;
405+ }
406+
407+ private positionToColumnAndLineText ( position : number ) : { zeroBasedColumn : number , lineText : string } {
408+ return this . root . charOffsetToLineInfo ( 1 , position ) ;
409+ }
410+
411+ lineNumberToInfo ( oneBasedLine : number ) : AbsolutePositionAndLineText {
405412 const lineCount = this . root . lineCount ( ) ;
406- if ( lineNumber <= lineCount ) {
407- const lineInfo = this . root . lineNumberToInfo ( lineNumber , 0 ) ;
408- lineInfo . line = lineNumber ;
409- return lineInfo ;
413+ if ( oneBasedLine <= lineCount ) {
414+ const { position, leaf } = this . root . lineNumberToInfo ( oneBasedLine , 0 ) ;
415+ return { absolutePosition : position , lineText : leaf && leaf . text } ;
410416 }
411417 else {
412- return {
413- line : lineNumber ,
414- offset : this . root . charCount ( )
415- } ;
418+ return { absolutePosition : this . root . charCount ( ) , lineText : undefined } ;
416419 }
417420 }
418421
@@ -502,17 +505,12 @@ namespace ts.server {
502505 else if ( deleteLength > 0 ) {
503506 // check whether last characters deleted are line break
504507 const e = pos + deleteLength ;
505- const lineInfo = this . charOffsetToLineNumberAndPos ( e ) ;
506- if ( ( lineInfo && ( lineInfo . offset === 0 ) ) ) {
508+ const { zeroBasedColumn , lineText } = this . positionToColumnAndLineText ( e ) ;
509+ if ( zeroBasedColumn === 0 ) {
507510 // move range end just past line that will merge with previous line
508- deleteLength += lineInfo . text . length ;
511+ deleteLength += lineText . length ;
509512 // store text by appending to end of insertedText
510- if ( newText ) {
511- newText = newText + lineInfo . text ;
512- }
513- else {
514- newText = lineInfo . text ;
515- }
513+ newText = newText ? newText + lineText : lineText ;
516514 }
517515 }
518516 if ( pos < this . root . charCount ( ) ) {
@@ -676,90 +674,88 @@ namespace ts.server {
676674 }
677675 }
678676
679- charOffsetToLineNumberAndPos ( lineNumber : number , charOffset : number ) : ILineInfo {
680- const childInfo = this . childFromCharOffset ( lineNumber , charOffset ) ;
677+ // Input position is relative to the start of this node.
678+ // Output line number is absolute.
679+ charOffsetToLineInfo ( lineNumberAccumulator : number , relativePosition : number ) : { oneBasedLine : number , zeroBasedColumn : number , lineText : string | undefined } {
680+ const childInfo = this . childFromCharOffset ( lineNumberAccumulator , relativePosition ) ;
681681 if ( ! childInfo . child ) {
682682 return {
683- line : lineNumber ,
684- offset : charOffset ,
683+ oneBasedLine : lineNumberAccumulator ,
684+ zeroBasedColumn : relativePosition ,
685+ lineText : undefined ,
685686 } ;
686687 }
687688 else if ( childInfo . childIndex < this . children . length ) {
688689 if ( childInfo . child . isLeaf ( ) ) {
689690 return {
690- line : childInfo . lineNumber ,
691- offset : childInfo . charOffset ,
692- text : ( < LineLeaf > ( childInfo . child ) ) . text ,
693- leaf : ( < LineLeaf > ( childInfo . child ) )
691+ oneBasedLine : childInfo . lineNumberAccumulator ,
692+ zeroBasedColumn : childInfo . relativePosition ,
693+ lineText : childInfo . child . text ,
694694 } ;
695695 }
696696 else {
697697 const lineNode = < LineNode > ( childInfo . child ) ;
698- return lineNode . charOffsetToLineNumberAndPos ( childInfo . lineNumber , childInfo . charOffset ) ;
698+ return lineNode . charOffsetToLineInfo ( childInfo . lineNumberAccumulator , childInfo . relativePosition ) ;
699699 }
700700 }
701701 else {
702702 const lineInfo = this . lineNumberToInfo ( this . lineCount ( ) , 0 ) ;
703- return { line : this . lineCount ( ) , offset : lineInfo . leaf . charCount ( ) } ;
703+ return { oneBasedLine : this . lineCount ( ) , zeroBasedColumn : lineInfo . leaf . charCount ( ) , lineText : undefined } ;
704704 }
705705 }
706706
707- lineNumberToInfo ( lineNumber : number , charOffset : number ) : ILineInfo {
708- const childInfo = this . childFromLineNumber ( lineNumber , charOffset ) ;
707+ lineNumberToInfo ( relativeOneBasedLine : number , positionAccumulator : number ) : { position : number , leaf : LineLeaf | undefined } {
708+ const childInfo = this . childFromLineNumber ( relativeOneBasedLine , positionAccumulator ) ;
709709 if ( ! childInfo . child ) {
710- return {
711- line : lineNumber ,
712- offset : charOffset
713- } ;
710+ return { position : positionAccumulator , leaf : undefined } ;
714711 }
715712 else if ( childInfo . child . isLeaf ( ) ) {
716- return {
717- line : lineNumber ,
718- offset : childInfo . charOffset ,
719- text : ( < LineLeaf > ( childInfo . child ) ) . text ,
720- leaf : ( < LineLeaf > ( childInfo . child ) )
721- } ;
713+ return { position : childInfo . positionAccumulator , leaf : childInfo . child } ;
722714 }
723715 else {
724716 const lineNode = < LineNode > ( childInfo . child ) ;
725- return lineNode . lineNumberToInfo ( childInfo . relativeLineNumber , childInfo . charOffset ) ;
717+ return lineNode . lineNumberToInfo ( childInfo . relativeOneBasedLine , childInfo . positionAccumulator ) ;
726718 }
727719 }
728720
729- childFromLineNumber ( lineNumber : number , charOffset : number ) {
721+ /**
722+ * Input line number is relative to the start of this node.
723+ * Output line number is relative to the child.
724+ * positionAccumulator will be an absolute position once relativeLineNumber reaches 0.
725+ */
726+ private childFromLineNumber ( relativeOneBasedLine : number , positionAccumulator : number ) : { child : LineCollection , relativeOneBasedLine : number , positionAccumulator : number } {
730727 let child : LineCollection ;
731- let relativeLineNumber = lineNumber ;
732728 let i : number ;
733- let len : number ;
734- for ( i = 0 , len = this . children . length ; i < len ; i ++ ) {
729+ for ( i = 0 ; i < this . children . length ; i ++ ) {
735730 child = this . children [ i ] ;
736731 const childLineCount = child . lineCount ( ) ;
737- if ( childLineCount >= relativeLineNumber ) {
732+ if ( childLineCount >= relativeOneBasedLine ) {
738733 break ;
739734 }
740735 else {
741- relativeLineNumber -= childLineCount ;
742- charOffset += child . charCount ( ) ;
736+ relativeOneBasedLine -= childLineCount ;
737+ positionAccumulator += child . charCount ( ) ;
743738 }
744739 }
745- return { child, childIndex : i , relativeLineNumber , charOffset } ;
740+ return { child, relativeOneBasedLine , positionAccumulator } ;
746741 }
747742
748- childFromCharOffset ( lineNumber : number , charOffset : number ) {
743+ private childFromCharOffset ( lineNumberAccumulator : number , relativePosition : number
744+ ) : { child : LineCollection , childIndex : number , relativePosition : number , lineNumberAccumulator : number } {
749745 let child : LineCollection ;
750746 let i : number ;
751747 let len : number ;
752748 for ( i = 0 , len = this . children . length ; i < len ; i ++ ) {
753749 child = this . children [ i ] ;
754- if ( child . charCount ( ) > charOffset ) {
750+ if ( child . charCount ( ) > relativePosition ) {
755751 break ;
756752 }
757753 else {
758- charOffset -= child . charCount ( ) ;
759- lineNumber += child . lineCount ( ) ;
754+ relativePosition -= child . charCount ( ) ;
755+ lineNumberAccumulator += child . lineCount ( ) ;
760756 }
761757 }
762- return { child, childIndex : i , charOffset , lineNumber } ;
758+ return { child, childIndex : i , relativePosition , lineNumberAccumulator } ;
763759 }
764760
765761 private splitAfter ( childIndex : number ) {
0 commit comments