@@ -3,81 +3,72 @@ import { yamlDocumentsCache } from '../parser/yaml-documents';
33import { TextDocument } from 'vscode-languageserver-textdocument' ;
44import { ASTNode } from 'vscode-json-languageservice' ;
55
6- export function getSelectionRanges ( document : TextDocument , positions : Position [ ] ) : SelectionRange [ ] | undefined {
7- if ( ! document ) {
8- return ;
9- }
6+ export function getSelectionRanges ( document : TextDocument , positions : Position [ ] ) : SelectionRange [ ] {
107 const doc = yamlDocumentsCache . getYamlDocument ( document ) ;
118 return positions . map ( ( position ) => {
129 const ranges = getRanges ( position ) ;
13- let current : SelectionRange ;
10+ let current : SelectionRange | undefined ;
1411 for ( const range of ranges ) {
1512 current = SelectionRange . create ( range , current ) ;
1613 }
17- if ( ! current ) {
18- current = SelectionRange . create ( {
19- start : position ,
20- end : position ,
21- } ) ;
22- }
23- return current ;
14+ return current ?? SelectionRange . create ( { start : position , end : position } ) ;
2415 } ) ;
2516
2617 function getRanges ( position : Position ) : Range [ ] {
2718 const offset = document . offsetAt ( position ) ;
2819 const result : Range [ ] = [ ] ;
2920 for ( const ymlDoc of doc . documents ) {
30- let currentNode : ASTNode ;
31- let firstNodeOffset : number ;
32- let isFirstNode = true ;
21+ let currentNode : ASTNode | undefined ;
22+ let overrideStartOffset : number | undefined ;
3323 ymlDoc . visit ( ( node ) => {
3424 const endOffset = node . offset + node . length ;
3525 // Skip if end offset doesn't even reach cursor position
3626 if ( endOffset < offset ) {
3727 return true ;
3828 }
39- let startOffset = node . offset ;
40- // Recheck start offset with the trimmed one in case of this
41- // key:
42- // - value
43- // ↑
44- if ( startOffset > offset ) {
45- const nodePosition = document . positionAt ( startOffset ) ;
46- if ( nodePosition . line !== position . line ) {
47- return true ;
48- }
49- const lineBeginning = { line : nodePosition . line , character : 0 } ;
50- const text = document . getText ( {
51- start : lineBeginning ,
52- end : nodePosition ,
53- } ) ;
54- if ( text . trim ( ) . length !== 0 ) {
29+ // Skip if we're ending at new line
30+ // times:
31+ // - second: 1
32+ // millisecond: 10
33+ // | - second: 2
34+ // ↑ millisecond: 0
35+ // (| is actually part of { second: 1, millisecond: 10 })
36+ // \r\n doesn't matter here
37+ if ( getTextFromOffsets ( endOffset - 1 , endOffset ) === '\n' ) {
38+ if ( endOffset - 1 < offset ) {
5539 return true ;
5640 }
57- startOffset = document . offsetAt ( lineBeginning ) ;
58- if ( startOffset > offset ) {
41+ }
42+
43+ let startOffset = node . offset ;
44+ if ( startOffset > offset ) {
45+ // Recheck start offset for some special cases
46+ const newOffset = getStartOffsetForSpecialCases ( node , position ) ;
47+ if ( ! newOffset || newOffset > offset ) {
5948 return true ;
6049 }
50+ startOffset = newOffset ;
6151 }
52+
6253 // Allow equal for children to override
6354 if ( ! currentNode || startOffset >= currentNode . offset ) {
6455 currentNode = node ;
65- firstNodeOffset = startOffset ;
56+ overrideStartOffset = startOffset ;
6657 }
6758 return true ;
6859 } ) ;
6960 while ( currentNode ) {
70- const startOffset = isFirstNode ? firstNodeOffset : currentNode . offset ;
61+ const startOffset = overrideStartOffset ?? currentNode . offset ;
7162 const endOffset = currentNode . offset + currentNode . length ;
7263 const range = {
7364 start : document . positionAt ( startOffset ) ,
7465 end : document . positionAt ( endOffset ) ,
7566 } ;
7667 const text = document . getText ( range ) ;
77- const trimmedText = text . trimEnd ( ) ;
78- const trimmedLength = text . length - trimmedText . length ;
79- if ( trimmedLength > 0 ) {
80- range . end = document . positionAt ( endOffset - trimmedLength ) ;
68+ const trimmedText = trimEndNewLine ( text ) ;
69+ const trimmedEndOffset = startOffset + trimmedText . length ;
70+ if ( trimmedEndOffset >= offset ) {
71+ range . end = document . positionAt ( trimmedEndOffset ) ;
8172 }
8273 // Add a jump between '' "" {} []
8374 const isSurroundedBy = ( startCharacter : string , endCharacter ?: string ) : boolean => {
@@ -95,7 +86,7 @@ export function getSelectionRanges(document: TextDocument, positions: Position[]
9586 }
9687 result . push ( range ) ;
9788 currentNode = currentNode . parent ;
98- isFirstNode = false ;
89+ overrideStartOffset = undefined ;
9990 }
10091 // A position can't be in multiple documents
10192 if ( result . length > 0 ) {
@@ -104,4 +95,48 @@ export function getSelectionRanges(document: TextDocument, positions: Position[]
10495 }
10596 return result . reverse ( ) ;
10697 }
98+
99+ function getStartOffsetForSpecialCases ( node : ASTNode , position : Position ) : number | undefined {
100+ const nodeStartPosition = document . positionAt ( node . offset ) ;
101+ if ( nodeStartPosition . line !== position . line ) {
102+ return ;
103+ }
104+
105+ if ( node . parent ?. type === 'array' ) {
106+ // array:
107+ // - value
108+ // ↑
109+ if ( getTextFromOffsets ( node . offset - 2 , node . offset ) === '- ' ) {
110+ return node . offset - 2 ;
111+ }
112+ }
113+
114+ if ( node . type === 'array' || node . type === 'object' ) {
115+ // array:
116+ // - value
117+ // ↑
118+ const lineBeginning = { line : nodeStartPosition . line , character : 0 } ;
119+ const text = document . getText ( { start : lineBeginning , end : nodeStartPosition } ) ;
120+ if ( text . trim ( ) . length === 0 ) {
121+ return document . offsetAt ( lineBeginning ) ;
122+ }
123+ }
124+ }
125+
126+ function getTextFromOffsets ( startOffset : number , endOffset : number ) : string {
127+ return document . getText ( {
128+ start : document . positionAt ( startOffset ) ,
129+ end : document . positionAt ( endOffset ) ,
130+ } ) ;
131+ }
132+ }
133+
134+ function trimEndNewLine ( str : string ) : string {
135+ if ( str . endsWith ( '\r\n' ) ) {
136+ return str . substring ( 0 , str . length - 2 ) ;
137+ }
138+ if ( str . endsWith ( '\n' ) ) {
139+ return str . substring ( 0 , str . length - 1 ) ;
140+ }
141+ return str ;
107142}
0 commit comments