Skip to content

Commit 8326ae1

Browse files
authored
Merge pull request #146 from docker/highlight-all-references
Support highlighting for referenced networks, volumes, configs, and secrets
2 parents e898426 + 0bc0952 commit 8326ae1

File tree

4 files changed

+625
-13
lines changed

4 files changed

+625
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ All notable changes to the Docker Language Server will be documented in this fil
1717
- textDocument/documentHighlight
1818
- support highlighting the short form `depends_on` syntax for services ([#70](https://github.com/docker/docker-language-server/issues/70))
1919
- support highlighting the long form `depends_on` syntax for services ([#71](https://github.com/docker/docker-language-server/issues/71))
20+
- support highlighting referenced networks, volumes, configs, and secrets ([#145](https://github.com/docker/docker-language-server/issues/145))
2021

2122
### Fixed
2223

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ The Docker Language Server relies on some features that are dependent on [Buildx
1616
- code completion
1717
- code navigation
1818
- document outline support
19+
- highlight named references of services, networks, volumes, configs, and secrets
1920
- hover tooltips
2021
- open links to images
2122
- Bake files

internal/compose/documentHighlight.go

Lines changed: 96 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package compose
22

33
import (
4+
"strings"
5+
46
"github.com/docker/docker-language-server/internal/pkg/document"
57
"github.com/docker/docker-language-server/internal/tliron/glsp/protocol"
68
"github.com/goccy/go-yaml/ast"
79
"github.com/goccy/go-yaml/token"
810
)
911

10-
func serviceReferences(node *ast.MappingValueNode, dependencyAttributeName string) []*token.Token {
12+
func serviceDependencyReferences(node *ast.MappingValueNode, dependencyAttributeName string, arrayOnly bool) []*token.Token {
1113
if servicesNode, ok := node.Value.(*ast.MappingNode); ok {
1214
tokens := []*token.Token{}
1315
for _, serviceNode := range servicesNode.Values {
@@ -18,8 +20,52 @@ func serviceReferences(node *ast.MappingValueNode, dependencyAttributeName strin
1820
for _, service := range sequenceNode.Values {
1921
tokens = append(tokens, service.GetToken())
2022
}
21-
} else if dependentService, ok := attributeNode.Value.(*ast.StringNode); ok {
22-
tokens = append(tokens, dependentService.GetToken())
23+
} else if !arrayOnly {
24+
if mappingNode, ok := attributeNode.Value.(*ast.MappingNode); ok {
25+
for _, dependentService := range mappingNode.Values {
26+
tokens = append(tokens, dependentService.Key.GetToken())
27+
}
28+
}
29+
}
30+
}
31+
}
32+
}
33+
}
34+
return tokens
35+
}
36+
return nil
37+
}
38+
39+
func volumeToken(t *token.Token) *token.Token {
40+
idx := strings.Index(t.Value, ":")
41+
if idx != -1 {
42+
return &token.Token{
43+
Value: t.Value[0:idx],
44+
Position: t.Position,
45+
}
46+
}
47+
return t
48+
}
49+
50+
func volumeReferences(node *ast.MappingValueNode) []*token.Token {
51+
if servicesNode, ok := node.Value.(*ast.MappingNode); ok {
52+
tokens := []*token.Token{}
53+
for _, serviceNode := range servicesNode.Values {
54+
if serviceAttributes, ok := serviceNode.Value.(*ast.MappingNode); ok {
55+
for _, attributeNode := range serviceAttributes.Values {
56+
if attributeNode.Key.GetToken().Value == "volumes" {
57+
if sequenceNode, ok := attributeNode.Value.(*ast.SequenceNode); ok {
58+
for _, service := range sequenceNode.Values {
59+
if volumeObjectNode, ok := service.(*ast.MappingNode); ok {
60+
for _, volumeAttribute := range volumeObjectNode.Values {
61+
if volumeAttribute.Key.GetToken().Value == "source" {
62+
tokens = append(tokens, volumeAttribute.Value.GetToken())
63+
}
64+
}
65+
} else {
66+
tokens = append(tokens, volumeToken(service.GetToken()))
67+
}
68+
}
2369
} else if mappingNode, ok := attributeNode.Value.(*ast.MappingNode); ok {
2470
for _, dependentService := range mappingNode.Values {
2571
tokens = append(tokens, dependentService.Key.GetToken())
@@ -56,51 +102,88 @@ func DocumentHighlight(doc document.ComposeDocument, position protocol.Position)
56102
line := int(position.Line) + 1
57103
character := int(position.Character) + 1
58104
if mappingNode, ok := file.Docs[0].Body.(*ast.MappingNode); ok {
105+
var networkRefs []*token.Token
106+
var volumeRefs []*token.Token
107+
var configRefs []*token.Token
108+
var secretRefs []*token.Token
109+
var networkDeclarations []*token.Token
110+
var volumeDeclarations []*token.Token
111+
var configDeclarations []*token.Token
112+
var secretDeclarations []*token.Token
59113
for _, node := range mappingNode.Values {
60114
if s, ok := node.Key.(*ast.StringNode); ok {
61115
switch s.Value {
62116
case "services":
63-
refs := serviceReferences(node, "depends_on")
117+
refs := serviceDependencyReferences(node, "depends_on", false)
64118
decls := declarations(node, "services")
65-
highlights := highlightServiceReferences(refs, decls, line, character)
119+
highlights := highlightReferences(refs, decls, line, character)
66120
if len(highlights) > 0 {
67121
return highlights, nil
68122
}
123+
networkRefs = serviceDependencyReferences(node, "networks", false)
124+
configRefs = serviceDependencyReferences(node, "configs", true)
125+
secretRefs = serviceDependencyReferences(node, "secrets", true)
126+
volumeRefs = volumeReferences(node)
127+
case "networks":
128+
networkDeclarations = declarations(node, "networks")
129+
case "volumes":
130+
volumeDeclarations = declarations(node, "volumes")
131+
case "configs":
132+
configDeclarations = declarations(node, "configs")
133+
case "secrets":
134+
secretDeclarations = declarations(node, "secrets")
69135
}
70136
}
71137
}
138+
highlights := highlightReferences(networkRefs, networkDeclarations, line, character)
139+
if len(highlights) > 0 {
140+
return highlights, nil
141+
}
142+
highlights = highlightReferences(volumeRefs, volumeDeclarations, line, character)
143+
if len(highlights) > 0 {
144+
return highlights, nil
145+
}
146+
highlights = highlightReferences(configRefs, configDeclarations, line, character)
147+
if len(highlights) > 0 {
148+
return highlights, nil
149+
}
150+
highlights = highlightReferences(secretRefs, secretDeclarations, line, character)
151+
if len(highlights) > 0 {
152+
return highlights, nil
153+
}
154+
return highlights, nil
72155
}
73156
return nil, nil
74157
}
75158

76-
func highlightServiceReferences(refs, decls []*token.Token, line, character int) []protocol.DocumentHighlight {
77-
var match *token.Token
159+
func highlightReferences(refs, decls []*token.Token, line, character int) []protocol.DocumentHighlight {
160+
var highlightedName *string
78161
for _, reference := range refs {
79162
if inToken(reference, line, character) {
80-
match = reference
163+
highlightedName = &reference.Value
81164
break
82165
}
83166
}
84167

85-
if match == nil {
168+
if highlightedName == nil {
86169
for _, declaration := range decls {
87170
if inToken(declaration, line, character) {
88-
match = declaration
171+
highlightedName = &declaration.Value
89172
break
90173
}
91174
}
92175
}
93176

94-
if match != nil {
177+
if highlightedName != nil {
95178
highlights := []protocol.DocumentHighlight{}
96179
for _, reference := range refs {
97-
if reference.Value == match.Value {
180+
if reference.Value == *highlightedName {
98181
highlights = append(highlights, documentHighlightFromToken(reference, protocol.DocumentHighlightKindRead))
99182
}
100183
}
101184

102185
for _, declaration := range decls {
103-
if declaration.Value == match.Value {
186+
if declaration.Value == *highlightedName {
104187
highlights = append(highlights, documentHighlightFromToken(declaration, protocol.DocumentHighlightKindWrite))
105188
}
106189
}

0 commit comments

Comments
 (0)