@@ -18,6 +18,19 @@ const (
1818 PositionTypeNone
1919)
2020
21+ func (p PositionType ) String () string {
22+ switch p {
23+ case PositionTypeMixins :
24+ return "mixins"
25+ case PositionTypeDepends :
26+ return "depends"
27+ case PositionTypeCommandAlias :
28+ return "command_alias"
29+ default :
30+ return "none"
31+ }
32+ }
33+
2134var yamlLanguage = grammars .YamlLanguage ()
2235
2336func isCursorWithinNode (node * ts.Node , pos lsp.Position ) bool {
@@ -58,6 +71,41 @@ func parseYAMLDocument(document *string) (*ts.Tree, []byte, error) {
5871 return tree , docBytes , nil
5972}
6073
74+ func executeYAMLQuery (document * string , queryText string , visit func (capture ts.QueryCapture , docBytes []byte ) bool ) bool {
75+ tree , docBytes , err := parseYAMLDocument (document )
76+ if err != nil {
77+ return false
78+ }
79+ defer tree .Release ()
80+
81+ query , err := ts .NewQuery (queryText , yamlLanguage )
82+ if err != nil {
83+ return false
84+ }
85+
86+ root := tree .RootNode ()
87+ if root == nil {
88+ return false
89+ }
90+
91+ matches := query .Exec (root , yamlLanguage , docBytes )
92+
93+ for {
94+ match , ok := matches .NextMatch ()
95+ if ! ok {
96+ break
97+ }
98+
99+ for _ , capture := range match .Captures {
100+ if visit (capture , docBytes ) {
101+ return true
102+ }
103+ }
104+ }
105+
106+ return false
107+ }
108+
61109func getLine (document * string , line uint32 ) string {
62110 lines := strings .Split (* document , "\n " )
63111 if line >= uint32 (len (lines )) {
@@ -233,44 +281,15 @@ func (p *parser) inDependsPosition(document *string, position lsp.Position) bool
233281}
234282
235283func (p * parser ) inCommandAliasPosition (document * string , position lsp.Position ) bool {
236- tree , docBytes , err := parseYAMLDocument (document )
237- if err != nil {
238- return false
239- }
240- defer tree .Release ()
241-
242- query , err := ts .NewQuery (`
284+ return executeYAMLQuery (document , `
243285 (block_mapping_pair
244286 key: (flow_node) @keymerge
245287 value: (flow_node(alias) @alias)
246288 (#eq? @keymerge "<<")
247289 )
248- ` , yamlLanguage )
249- if err != nil {
250- return false
251- }
252-
253- root := tree .RootNode ()
254- if root == nil {
255- return false
256- }
257-
258- matches := query .Exec (root , yamlLanguage , docBytes )
259-
260- for {
261- match , ok := matches .NextMatch ()
262- if ! ok {
263- break
264- }
265-
266- for _ , capture := range match .Captures {
267- if capture .Name == "alias" && isCursorWithinNode (capture .Node , position ) {
268- return true
269- }
270- }
271- }
272-
273- return false
290+ ` , func (capture ts.QueryCapture , _ []byte ) bool {
291+ return capture .Name == "alias" && isCursorWithinNode (capture .Node , position )
292+ })
274293}
275294
276295func (p * parser ) extractFilenameFromMixins (document * string , position lsp.Position ) string {
@@ -321,20 +340,22 @@ func (p *parser) extractFilenameFromMixins(document *string, position lsp.Positi
321340
322341func (p * parser ) extractCommandReference (document * string , position lsp.Position ) string {
323342 if commandName := p .extractDependsCommandReference (document , position ); commandName != "" {
343+ p .log .Debugf ("resolved command reference from depends: %q" , commandName )
324344 return commandName
325345 }
326346
327- return p .extractAliasCommandReference (document , position )
347+ commandName := p .extractAliasCommandReference (document , position )
348+ if commandName != "" {
349+ p .log .Debugf ("resolved command reference from alias: %q" , commandName )
350+ }
351+
352+ return commandName
328353}
329354
330355func (p * parser ) extractDependsCommandReference (document * string , position lsp.Position ) string {
331- tree , docBytes , err := parseYAMLDocument (document )
332- if err != nil {
333- return ""
334- }
335- defer tree .Release ()
356+ var commandName string
336357
337- query , err := ts . NewQuery ( `
358+ executeYAMLQuery ( document , `
338359 (block_mapping_pair
339360 key: (flow_node) @keydepends
340361 value: [
@@ -352,35 +373,52 @@ func (p *parser) extractDependsCommandReference(document *string, position lsp.P
352373 ]
353374 (#eq? @keydepends "depends")
354375 )
355- ` , yamlLanguage )
356- if err != nil {
357- return ""
358- }
376+ ` , func (capture ts.QueryCapture , docBytes []byte ) bool {
377+ if capture .Name == "reference" && isCursorWithinNode (capture .Node , position ) {
378+ commandName = capture .Node .Text (docBytes )
379+ return true
380+ }
359381
360- root := tree .RootNode ()
361- if root == nil {
362- return ""
363- }
382+ return false
383+ })
364384
365- matches := query .Exec (root , yamlLanguage , docBytes )
385+ return commandName
386+ }
366387
367- for {
368- match , ok := matches .NextMatch ()
369- if ! ok {
370- break
371- }
388+ func (p * parser ) extractAliasCommandReference (document * string , position lsp.Position ) string {
389+ var anchorName string
372390
373- for _ , capture := range match .Captures {
374- if capture .Name == "reference" && isCursorWithinNode (capture .Node , position ) {
375- return capture .Node .Text (docBytes )
376- }
391+ executeYAMLQuery (document , `
392+ (block_mapping_pair
393+ key: (flow_node) @keymerge
394+ value: (flow_node(alias) @reference)
395+ (#eq? @keymerge "<<")
396+ )
397+ ` , func (capture ts.QueryCapture , docBytes []byte ) bool {
398+ if capture .Name == "reference" && isCursorWithinNode (capture .Node , position ) {
399+ anchorName = strings .TrimPrefix (capture .Node .Text (docBytes ), "*" )
400+ return true
377401 }
402+
403+ return false
404+ })
405+
406+ if anchorName == "" {
407+ return ""
378408 }
379409
380- return ""
410+ commandName := p .findCommandNameByAnchor (document , anchorName )
411+ if commandName == "" {
412+ p .log .Debugf ("alias anchor %q did not match any local command anchor" , anchorName )
413+ return ""
414+ }
415+
416+ p .log .Debugf ("resolved alias anchor %q to command %q" , anchorName , commandName )
417+
418+ return commandName
381419}
382420
383- func (p * parser ) extractAliasCommandReference (document * string , position lsp. Position ) string {
421+ func (p * parser ) findCommandNameByAnchor (document * string , anchorName string ) string {
384422 tree , docBytes , err := parseYAMLDocument (document )
385423 if err != nil {
386424 return ""
@@ -389,9 +427,17 @@ func (p *parser) extractAliasCommandReference(document *string, position lsp.Pos
389427
390428 query , err := ts .NewQuery (`
391429 (block_mapping_pair
392- key: (flow_node) @keymerge
393- value: (flow_node(alias) @reference)
394- (#eq? @keymerge "<<")
430+ key: (flow_node(plain_scalar(string_scalar)) @commands)
431+ value: (block_node
432+ (block_mapping
433+ (block_mapping_pair
434+ key: (flow_node
435+ (plain_scalar
436+ (string_scalar)) @cmd_key)
437+ value: (block_node
438+ (anchor
439+ (anchor_name) @anchor_name)))))
440+ (#eq? @commands "commands")
395441 )
396442 ` , yamlLanguage )
397443 if err != nil {
@@ -411,12 +457,20 @@ func (p *parser) extractAliasCommandReference(document *string, position lsp.Pos
411457 break
412458 }
413459
460+ var commandName string
461+ var matchedAnchor string
462+
414463 for _ , capture := range match .Captures {
415- if capture .Name != "reference" || ! isCursorWithinNode (capture .Node , position ) {
416- continue
464+ switch capture .Name {
465+ case "cmd_key" :
466+ commandName = capture .Node .Text (docBytes )
467+ case "anchor_name" :
468+ matchedAnchor = capture .Node .Text (docBytes )
417469 }
470+ }
418471
419- return strings .TrimPrefix (capture .Node .Text (docBytes ), "*" )
472+ if matchedAnchor == anchorName {
473+ return commandName
420474 }
421475 }
422476
0 commit comments