@@ -8,15 +8,13 @@ namespace ts.server {
8
8
export interface LineCollection {
9
9
charCount ( ) : number ;
10
10
lineCount ( ) : number ;
11
- isLeaf ( ) : boolean ;
11
+ isLeaf ( ) : this is LineLeaf ;
12
12
walk ( rangeStart : number , rangeLength : number , walkFns : ILineIndexWalker ) : void ;
13
13
}
14
14
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 ;
20
18
}
21
19
22
20
export enum CharRangeSection {
@@ -397,22 +395,27 @@ namespace ts.server {
397
395
// set this to true to check each edit for accuracy
398
396
checkEdits = false ;
399
397
400
- charOffsetToLineNumberAndPos ( charOffset : number ) {
401
- return this . root . charOffsetToLineNumberAndPos ( 1 , charOffset ) ;
398
+ absolutePositionOfStartOfLine ( oneBasedLine : number ) : number {
399
+ return this . lineNumberToInfo ( oneBasedLine ) . absolutePosition ;
402
400
}
403
401
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 {
405
412
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 } ;
410
416
}
411
417
else {
412
- return {
413
- line : lineNumber ,
414
- offset : this . root . charCount ( )
415
- } ;
418
+ return { absolutePosition : this . root . charCount ( ) , lineText : undefined } ;
416
419
}
417
420
}
418
421
@@ -502,17 +505,12 @@ namespace ts.server {
502
505
else if ( deleteLength > 0 ) {
503
506
// check whether last characters deleted are line break
504
507
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 ) {
507
510
// move range end just past line that will merge with previous line
508
- deleteLength += lineInfo . text . length ;
511
+ deleteLength += lineText . length ;
509
512
// 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 ;
516
514
}
517
515
}
518
516
if ( pos < this . root . charCount ( ) ) {
@@ -676,90 +674,88 @@ namespace ts.server {
676
674
}
677
675
}
678
676
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 ) ;
681
681
if ( ! childInfo . child ) {
682
682
return {
683
- line : lineNumber ,
684
- offset : charOffset ,
683
+ oneBasedLine : lineNumberAccumulator ,
684
+ zeroBasedColumn : relativePosition ,
685
+ lineText : undefined ,
685
686
} ;
686
687
}
687
688
else if ( childInfo . childIndex < this . children . length ) {
688
689
if ( childInfo . child . isLeaf ( ) ) {
689
690
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 ,
694
694
} ;
695
695
}
696
696
else {
697
697
const lineNode = < LineNode > ( childInfo . child ) ;
698
- return lineNode . charOffsetToLineNumberAndPos ( childInfo . lineNumber , childInfo . charOffset ) ;
698
+ return lineNode . charOffsetToLineInfo ( childInfo . lineNumberAccumulator , childInfo . relativePosition ) ;
699
699
}
700
700
}
701
701
else {
702
702
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 } ;
704
704
}
705
705
}
706
706
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 ) ;
709
709
if ( ! childInfo . child ) {
710
- return {
711
- line : lineNumber ,
712
- offset : charOffset
713
- } ;
710
+ return { position : positionAccumulator , leaf : undefined } ;
714
711
}
715
712
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 } ;
722
714
}
723
715
else {
724
716
const lineNode = < LineNode > ( childInfo . child ) ;
725
- return lineNode . lineNumberToInfo ( childInfo . relativeLineNumber , childInfo . charOffset ) ;
717
+ return lineNode . lineNumberToInfo ( childInfo . relativeOneBasedLine , childInfo . positionAccumulator ) ;
726
718
}
727
719
}
728
720
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 } {
730
727
let child : LineCollection ;
731
- let relativeLineNumber = lineNumber ;
732
728
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 ++ ) {
735
730
child = this . children [ i ] ;
736
731
const childLineCount = child . lineCount ( ) ;
737
- if ( childLineCount >= relativeLineNumber ) {
732
+ if ( childLineCount >= relativeOneBasedLine ) {
738
733
break ;
739
734
}
740
735
else {
741
- relativeLineNumber -= childLineCount ;
742
- charOffset += child . charCount ( ) ;
736
+ relativeOneBasedLine -= childLineCount ;
737
+ positionAccumulator += child . charCount ( ) ;
743
738
}
744
739
}
745
- return { child, childIndex : i , relativeLineNumber , charOffset } ;
740
+ return { child, relativeOneBasedLine , positionAccumulator } ;
746
741
}
747
742
748
- childFromCharOffset ( lineNumber : number , charOffset : number ) {
743
+ private childFromCharOffset ( lineNumberAccumulator : number , relativePosition : number
744
+ ) : { child : LineCollection , childIndex : number , relativePosition : number , lineNumberAccumulator : number } {
749
745
let child : LineCollection ;
750
746
let i : number ;
751
747
let len : number ;
752
748
for ( i = 0 , len = this . children . length ; i < len ; i ++ ) {
753
749
child = this . children [ i ] ;
754
- if ( child . charCount ( ) > charOffset ) {
750
+ if ( child . charCount ( ) > relativePosition ) {
755
751
break ;
756
752
}
757
753
else {
758
- charOffset -= child . charCount ( ) ;
759
- lineNumber += child . lineCount ( ) ;
754
+ relativePosition -= child . charCount ( ) ;
755
+ lineNumberAccumulator += child . lineCount ( ) ;
760
756
}
761
757
}
762
- return { child, childIndex : i , charOffset , lineNumber } ;
758
+ return { child, childIndex : i , relativePosition , lineNumberAccumulator } ;
763
759
}
764
760
765
761
private splitAfter ( childIndex : number ) {
0 commit comments