Skip to content

Commit 86ceb70

Browse files
authored
Merge pull request #200 from docker/link-compose-docs-hover
Improve Compose hovers by linking to the documentation
2 parents d361447 + 156d14c commit 86ceb70

File tree

4 files changed

+82
-32
lines changed

4 files changed

+82
-32
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ All notable changes to the Docker Language Server will be documented in this fil
1515
- updated Compose schema to the latest version
1616
- textDocument/definition
1717
- support navigating to a dependency that is defined in another file ([#190](https://github.com/docker/docker-language-server/issues/190))
18+
- textDocument/hover
19+
- improve hover result by linking to the schema and the online documentation ([#199](https://github.com/docker/docker-language-server/issues/199))
1820
- Bake
1921
- textDocument/publishDiagnostics
2022
- support filtering vulnerability diagnostics with an experimental setting ([#192](https://github.com/docker/docker-language-server/issues/192))

e2e-tests/hover_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ func TestHover(t *testing.T) {
110110
position: protocol.Position{Line: 0, Character: 4},
111111
result: &protocol.Hover{
112112
Contents: protocol.MarkupContent{
113-
Kind: protocol.MarkupKindPlainText,
114-
Value: "declared for backward compatibility, ignored. Please remove it.",
113+
Kind: protocol.MarkupKindMarkdown,
114+
Value: "declared for backward compatibility, ignored. Please remove it.\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/version-and-name/)",
115115
},
116116
},
117117
},

internal/compose/hover.go

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package compose
22

33
import (
4-
"bytes"
54
"context"
65
"fmt"
76
"slices"
@@ -119,6 +118,9 @@ func hover(schema *jsonschema.Schema, nodes []ast.Node, line, column, lineLength
119118
}
120119

121120
if nested, ok := schema.Items.(*jsonschema.Schema); ok {
121+
if nested.Ref != nil {
122+
nested = nested.Ref
123+
}
122124
for _, n := range nested.OneOf {
123125
if n.Types != nil && slices.Contains(n.Types.ToStrings(), "object") {
124126
if len(n.Properties) > 0 {
@@ -145,7 +147,7 @@ func hover(schema *jsonschema.Schema, nodes []ast.Node, line, column, lineLength
145147
if property, ok := schema.Properties[match.GetToken().Value]; ok {
146148
if property.Enum != nil {
147149
if match.GetToken().Position.Column <= column && column <= lineLength {
148-
var builder bytes.Buffer
150+
var builder strings.Builder
149151
if property.Description != "" {
150152
builder.WriteString(property.Description)
151153
builder.WriteString("\n\n")
@@ -159,6 +161,12 @@ func hover(schema *jsonschema.Schema, nodes []ast.Node, line, column, lineLength
159161
for _, value := range enumValues {
160162
builder.WriteString(fmt.Sprintf("- `%v`\n", value))
161163
}
164+
builder.WriteString("\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)")
165+
builder.WriteString(fmt.Sprintf(
166+
"\n\n[Online documentation](https://docs.docker.com/reference/compose-file/%v/#%v)",
167+
nodes[0].GetToken().Value,
168+
nodes[2].GetToken().Value,
169+
))
162170
return &protocol.Hover{
163171
Contents: protocol.MarkupContent{
164172
Kind: protocol.MarkupKindMarkdown,
@@ -169,10 +177,45 @@ func hover(schema *jsonschema.Schema, nodes []ast.Node, line, column, lineLength
169177
}
170178

171179
if match.GetToken().Position.Line == line && match.GetToken().Position.Column+len(match.GetToken().Value) >= column && property.Description != "" {
180+
var builder strings.Builder
181+
builder.WriteString(property.Description)
182+
builder.WriteString("\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)")
183+
switch nodes[0].GetToken().Value {
184+
case "name":
185+
builder.WriteString("\n\n[Online documentation](https://docs.docker.com/reference/compose-file/version-and-name/)")
186+
case "version":
187+
builder.WriteString("\n\n[Online documentation](https://docs.docker.com/reference/compose-file/version-and-name/)")
188+
case "include":
189+
if len(nodes) == 1 {
190+
builder.WriteString(fmt.Sprintf(
191+
"\n\n[Online documentation](https://docs.docker.com/reference/compose-file/%v/)",
192+
nodes[0].GetToken().Value,
193+
))
194+
} else {
195+
builder.WriteString(fmt.Sprintf(
196+
"\n\n[Online documentation](https://docs.docker.com/reference/compose-file/%v/#%v)",
197+
nodes[0].GetToken().Value,
198+
nodes[1].GetToken().Value,
199+
))
200+
}
201+
default:
202+
if len(nodes) == 1 {
203+
builder.WriteString(fmt.Sprintf(
204+
"\n\n[Online documentation](https://docs.docker.com/reference/compose-file/%v/)",
205+
nodes[0].GetToken().Value,
206+
))
207+
} else {
208+
builder.WriteString(fmt.Sprintf(
209+
"\n\n[Online documentation](https://docs.docker.com/reference/compose-file/%v/#%v)",
210+
nodes[0].GetToken().Value,
211+
nodes[2].GetToken().Value,
212+
))
213+
}
214+
}
172215
return &protocol.Hover{
173216
Contents: protocol.MarkupContent{
174-
Kind: protocol.MarkupKindPlainText,
175-
Value: property.Description,
217+
Kind: protocol.MarkupKindMarkdown,
218+
Value: builder.String(),
176219
},
177220
}
178221
}

internal/compose/hover_test.go

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ func TestHover(t *testing.T) {
2929
character: 4,
3030
result: &protocol.Hover{
3131
Contents: protocol.MarkupContent{
32-
Kind: protocol.MarkupKindPlainText,
33-
Value: "declared for backward compatibility, ignored. Please remove it.",
32+
Kind: protocol.MarkupKindMarkdown,
33+
Value: "declared for backward compatibility, ignored. Please remove it.\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/version-and-name/)",
3434
},
3535
},
3636
},
@@ -41,8 +41,8 @@ func TestHover(t *testing.T) {
4141
character: 4,
4242
result: &protocol.Hover{
4343
Contents: protocol.MarkupContent{
44-
Kind: protocol.MarkupKindPlainText,
45-
Value: "define the Compose project name, until user defines one explicitly.",
44+
Kind: protocol.MarkupKindMarkdown,
45+
Value: "define the Compose project name, until user defines one explicitly.\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/version-and-name/)",
4646
},
4747
},
4848
},
@@ -67,8 +67,21 @@ func TestHover(t *testing.T) {
6767
character: 4,
6868
result: &protocol.Hover{
6969
Contents: protocol.MarkupContent{
70-
Kind: protocol.MarkupKindPlainText,
71-
Value: "compose sub-projects to be included.",
70+
Kind: protocol.MarkupKindMarkdown,
71+
Value: "compose sub-projects to be included.\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/include/)",
72+
},
73+
},
74+
},
75+
{
76+
name: "include's project_directory attribute",
77+
content: `include:
78+
- project_directory: folder`,
79+
line: 1,
80+
character: 7,
81+
result: &protocol.Hover{
82+
Contents: protocol.MarkupContent{
83+
Kind: protocol.MarkupKindMarkdown,
84+
Value: "Path to resolve relative paths set in the Compose file\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/include/#project_directory)",
7285
},
7386
},
7487
},
@@ -91,7 +104,7 @@ services:
91104
result: &protocol.Hover{
92105
Contents: protocol.MarkupContent{
93106
Kind: protocol.MarkupKindMarkdown,
94-
Value: "The mount type: bind for mounting host directories, volume for named volumes, tmpfs for temporary filesystems, cluster for cluster volumes, npipe for named pipes, or image for mounting from an image.\n\nAllowed values:\n- `bind`\n- `cluster`\n- `image`\n- `npipe`\n- `tmpfs`\n- `volume`\n",
107+
Value: "The mount type: bind for mounting host directories, volume for named volumes, tmpfs for temporary filesystems, cluster for cluster volumes, npipe for named pipes, or image for mounting from an image.\n\nAllowed values:\n- `bind`\n- `cluster`\n- `image`\n- `npipe`\n- `tmpfs`\n- `volume`\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/services/#volumes)",
95108
},
96109
},
97110
},
@@ -109,7 +122,7 @@ services:
109122
result: &protocol.Hover{
110123
Contents: protocol.MarkupContent{
111124
Kind: protocol.MarkupKindMarkdown,
112-
Value: "SELinux relabeling options: 'z' for shared content, 'Z' for private unshared content.\n\nAllowed values:\n- `Z`\n- `z`\n",
125+
Value: "SELinux relabeling options: 'z' for shared content, 'Z' for private unshared content.\n\nAllowed values:\n- `Z`\n- `z`\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/services/#volumes)",
113126
},
114127
},
115128
},
@@ -127,7 +140,7 @@ services:
127140
result: &protocol.Hover{
128141
Contents: protocol.MarkupContent{
129142
Kind: protocol.MarkupKindMarkdown,
130-
Value: "Recursively mount the source directory.\n\nAllowed values:\n- `disabled`\n- `enabled`\n- `readonly`\n- `writable`\n",
143+
Value: "Recursively mount the source directory.\n\nAllowed values:\n- `disabled`\n- `enabled`\n- `readonly`\n- `writable`\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/services/#volumes)",
131144
},
132145
},
133146
},
@@ -145,7 +158,7 @@ services:
145158
result: &protocol.Hover{
146159
Contents: protocol.MarkupContent{
147160
Kind: protocol.MarkupKindMarkdown,
148-
Value: "Recursively mount the source directory.\n\nAllowed values:\n- `disabled`\n- `enabled`\n- `readonly`\n- `writable`\n",
161+
Value: "Recursively mount the source directory.\n\nAllowed values:\n- `disabled`\n- `enabled`\n- `readonly`\n- `writable`\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/services/#volumes)",
149162
},
150163
},
151164
},
@@ -163,7 +176,7 @@ services:
163176
result: &protocol.Hover{
164177
Contents: protocol.MarkupContent{
165178
Kind: protocol.MarkupKindMarkdown,
166-
Value: "Recursively mount the source directory.\n\nAllowed values:\n- `disabled`\n- `enabled`\n- `readonly`\n- `writable`\n",
179+
Value: "Recursively mount the source directory.\n\nAllowed values:\n- `disabled`\n- `enabled`\n- `readonly`\n- `writable`\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/services/#volumes)",
167180
},
168181
},
169182
},
@@ -181,7 +194,7 @@ services:
181194
result: &protocol.Hover{
182195
Contents: protocol.MarkupContent{
183196
Kind: protocol.MarkupKindMarkdown,
184-
Value: "Recursively mount the source directory.\n\nAllowed values:\n- `disabled`\n- `enabled`\n- `readonly`\n- `writable`\n",
197+
Value: "Recursively mount the source directory.\n\nAllowed values:\n- `disabled`\n- `enabled`\n- `readonly`\n- `writable`\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/services/#volumes)",
185198
},
186199
},
187200
},
@@ -196,7 +209,7 @@ services:
196209
result: &protocol.Hover{
197210
Contents: protocol.MarkupContent{
198211
Kind: protocol.MarkupKindMarkdown,
199-
Value: "Specify the cgroup namespace to join. Use 'host' to use the host's cgroup namespace, or 'private' to use a private cgroup namespace.\n\nAllowed values:\n- `host`\n- `private`\n",
212+
Value: "Specify the cgroup namespace to join. Use 'host' to use the host's cgroup namespace, or 'private' to use a private cgroup namespace.\n\nAllowed values:\n- `host`\n- `private`\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/services/#cgroup)",
200213
},
201214
},
202215
},
@@ -213,7 +226,7 @@ services:
213226
result: &protocol.Hover{
214227
Contents: protocol.MarkupContent{
215228
Kind: protocol.MarkupKindMarkdown,
216-
Value: "Condition to wait for. 'service_started' waits until the service has started, 'service_healthy' waits until the service is healthy (as defined by its healthcheck), 'service_completed_successfully' waits until the service has completed successfully.\n\nAllowed values:\n- `service_completed_successfully`\n- `service_healthy`\n- `service_started`\n",
229+
Value: "Condition to wait for. 'service_started' waits until the service has started, 'service_healthy' waits until the service is healthy (as defined by its healthcheck), 'service_completed_successfully' waits until the service has completed successfully.\n\nAllowed values:\n- `service_completed_successfully`\n- `service_healthy`\n- `service_started`\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/services/#depends_on)",
217230
},
218231
},
219232
},
@@ -231,7 +244,7 @@ services:
231244
result: &protocol.Hover{
232245
Contents: protocol.MarkupContent{
233246
Kind: protocol.MarkupKindMarkdown,
234-
Value: "Action to take when a change is detected: rebuild the container, sync files, restart the container, sync and restart, or sync and execute a command.\n\nAllowed values:\n- `rebuild`\n- `restart`\n- `sync`\n- `sync+exec`\n- `sync+restart`\n",
247+
Value: "Action to take when a change is detected: rebuild the container, sync files, restart the container, sync and restart, or sync and execute a command.\n\nAllowed values:\n- `rebuild`\n- `restart`\n- `sync`\n- `sync+exec`\n- `sync+restart`\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/services/#develop)",
235248
},
236249
},
237250
},
@@ -248,7 +261,7 @@ services:
248261
result: &protocol.Hover{
249262
Contents: protocol.MarkupContent{
250263
Kind: protocol.MarkupKindMarkdown,
251-
Value: "Order of operations during rollbacks: 'stop-first' (default) or 'start-first'.\n\nAllowed values:\n- `start-first`\n- `stop-first`\n",
264+
Value: "Order of operations during rollbacks: 'stop-first' (default) or 'start-first'.\n\nAllowed values:\n- `start-first`\n- `stop-first`\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/services/#deploy)",
252265
},
253266
},
254267
},
@@ -265,7 +278,7 @@ services:
265278
result: &protocol.Hover{
266279
Contents: protocol.MarkupContent{
267280
Kind: protocol.MarkupKindMarkdown,
268-
Value: "Order of operations during updates: 'stop-first' (default) or 'start-first'.\n\nAllowed values:\n- `start-first`\n- `stop-first`\n",
281+
Value: "Order of operations during updates: 'stop-first' (default) or 'start-first'.\n\nAllowed values:\n- `start-first`\n- `stop-first`\n\nSchema: [compose-spec.json](https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json)\n\n[Online documentation](https://docs.docker.com/reference/compose-file/services/#deploy)",
269282
},
270283
},
271284
},
@@ -451,15 +464,7 @@ services:
451464
},
452465
}, doc)
453466
require.NoError(t, err)
454-
if tc.result == nil {
455-
require.Nil(t, result)
456-
} else {
457-
require.NotNil(t, result)
458-
require.Nil(t, result.Range)
459-
markupContent, ok := result.Contents.(protocol.MarkupContent)
460-
require.True(t, ok)
461-
require.Equal(t, tc.result.Contents, markupContent)
462-
}
467+
require.Equal(t, tc.result, result)
463468
})
464469
}
465470
}

0 commit comments

Comments
 (0)