Skip to content

Commit d8843d7

Browse files
authored
Merge pull request #139 from docker/tighten-compose-completion-calculations
Consider array schema and indentation before returning items
2 parents 7ce5ac4 + b695f8f commit d8843d7

File tree

3 files changed

+63
-25
lines changed

3 files changed

+63
-25
lines changed

internal/compose/completion.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,21 @@ func prefix(line string, character int) string {
2626
return sb.String()
2727
}
2828

29+
func array(line string, character int) bool {
30+
isArray := false
31+
for i := range character {
32+
if unicode.IsSpace(rune(line[i])) {
33+
continue
34+
} else if line[i] == '-' {
35+
isArray = true
36+
} else {
37+
isArray = false
38+
break
39+
}
40+
}
41+
return isArray
42+
}
43+
2944
func Completion(ctx context.Context, params *protocol.CompletionParams, doc document.ComposeDocument) (*protocol.CompletionList, error) {
3045
if params.Position.Character == 0 {
3146
items := []protocol.CompletionItem{}
@@ -69,7 +84,11 @@ func Completion(ctx context.Context, params *protocol.CompletionParams, doc docu
6984
}
7085

7186
items := []protocol.CompletionItem{}
72-
nodeProps := nodeProperties(path, line, character)
87+
isArray := array(lines[lspLine], character-1)
88+
nodeProps, arrayAttributes := nodeProperties(path, line, character)
89+
if isArray != arrayAttributes {
90+
return nil, nil
91+
}
7392
if schema, ok := nodeProps.(*jsonschema.Schema); ok {
7493
if schema.Enum != nil {
7594
for _, value := range schema.Enum.Values {

internal/compose/completion_test.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,29 @@ networks:
18321832
character: 2,
18331833
list: nil,
18341834
},
1835+
{
1836+
name: "configs should not suggest attributes as-is",
1837+
content: `
1838+
services:
1839+
test:
1840+
configs:
1841+
`,
1842+
line: 4,
1843+
character: 6,
1844+
list: nil,
1845+
},
1846+
{
1847+
name: "array items should still consider indentation when calculating completion items",
1848+
content: `
1849+
services:
1850+
test:
1851+
configs:
1852+
- mode: 0
1853+
`,
1854+
line: 5,
1855+
character: 6,
1856+
list: nil,
1857+
},
18351858
}
18361859

18371860
composeFileURI := fmt.Sprintf("file:///%v", strings.TrimPrefix(filepath.ToSlash(filepath.Join(os.TempDir(), "compose.yaml")), "/"))
@@ -1846,11 +1869,7 @@ networks:
18461869
},
18471870
}, doc)
18481871
require.NoError(t, err)
1849-
if tc.list == nil {
1850-
require.Nil(t, list)
1851-
} else {
1852-
require.Equal(t, tc.list, list)
1853-
}
1872+
require.Equal(t, tc.list, list)
18541873
})
18551874
}
18561875
}

internal/compose/schema.go

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,44 +35,44 @@ func schemaProperties() map[string]*jsonschema.Schema {
3535
return composeSchema.Properties
3636
}
3737

38-
func nodeProperties(nodes []*ast.MappingValueNode, line, column int) any {
38+
func nodeProperties(nodes []*ast.MappingValueNode, line, column int) (any, bool) {
3939
if composeSchema != nil && slices.Contains(composeSchema.Types.ToStrings(), "object") && composeSchema.Properties != nil {
4040
if prop, ok := composeSchema.Properties[nodes[0].Key.GetToken().Value]; ok {
4141
for regexp, property := range prop.PatternProperties {
4242
if regexp.MatchString(nodes[1].Key.GetToken().Value) {
4343
if property.Ref != nil {
44-
return recurseNodeProperties(nodes, line, column, 2, property.Ref.Properties)
44+
return recurseNodeProperties(nodes, line, column, 2, property.Ref.Properties, false)
4545
}
4646
}
4747
}
4848
}
4949
}
50-
return nil
50+
return nil, false
5151
}
5252

53-
func recurseNodeProperties(nodes []*ast.MappingValueNode, line, column, nodeOffset int, properties map[string]*jsonschema.Schema) any {
53+
func recurseNodeProperties(nodes []*ast.MappingValueNode, line, column, nodeOffset int, properties map[string]*jsonschema.Schema, arrayAttributes bool) (any, bool) {
5454
if len(nodes) == nodeOffset {
55-
return properties
55+
return properties, arrayAttributes
5656
}
57-
if len(nodes) >= nodeOffset+2 && nodes[nodeOffset].Key.GetToken().Position.Column <= column && column < nodes[nodeOffset+1].Key.GetToken().Position.Column {
58-
return properties
57+
if len(nodes) >= nodeOffset+2 && nodes[nodeOffset].Key.GetToken().Position.Column == column {
58+
return properties, false
5959
}
6060
if column == nodes[nodeOffset].Key.GetToken().Position.Column {
61-
return properties
61+
return properties, false
6262
}
6363

6464
value := nodes[nodeOffset].Key.GetToken().Value
6565
if prop, ok := properties[value]; ok {
6666
if prop.Ref != nil {
6767
if len(prop.Ref.Properties) > 0 {
68-
return recurseNodeProperties(nodes, line, column, nodeOffset+1, prop.Ref.Properties)
68+
return recurseNodeProperties(nodes, line, column, nodeOffset+1, prop.Ref.Properties, false)
6969
}
7070
for regexp, property := range prop.Ref.PatternProperties {
7171
nextValue := nodes[nodeOffset+1].Key.GetToken().Value
7272
if regexp.MatchString(nextValue) {
7373
for _, nested := range property.OneOf {
7474
if slices.Contains(nested.Types.ToStrings(), "object") {
75-
return recurseNodeProperties(nodes, line, column, nodeOffset+2, nested.Properties)
75+
return recurseNodeProperties(nodes, line, column, nodeOffset+2, nested.Properties, false)
7676
}
7777
}
7878
}
@@ -81,7 +81,7 @@ func recurseNodeProperties(nodes []*ast.MappingValueNode, line, column, nodeOffs
8181
for _, nested := range schema.OneOf {
8282
if nested.Types != nil && slices.Contains(nested.Types.ToStrings(), "object") {
8383
if len(nested.Properties) > 0 {
84-
return recurseNodeProperties(nodes, line, column, nodeOffset+1, nested.Properties)
84+
return recurseNodeProperties(nodes, line, column, nodeOffset+1, nested.Properties, true)
8585
}
8686
}
8787
}
@@ -91,19 +91,19 @@ func recurseNodeProperties(nodes []*ast.MappingValueNode, line, column, nodeOffs
9191
for _, schema := range prop.OneOf {
9292
if schema.Types != nil && slices.Contains(schema.Types.ToStrings(), "object") {
9393
if len(schema.Properties) > 0 {
94-
return recurseNodeProperties(nodes, line, column, nodeOffset+1, schema.Properties)
94+
return recurseNodeProperties(nodes, line, column, nodeOffset+1, schema.Properties, false)
9595
}
9696

9797
for regexp, property := range schema.PatternProperties {
9898
if len(nodes) == nodeOffset+1 {
99-
return nil
99+
return nil, false
100100
}
101101

102102
nextValue := nodes[nodeOffset+1].Key.GetToken().Value
103103
if regexp.MatchString(nextValue) {
104104
for _, nested := range property.OneOf {
105105
if slices.Contains(nested.Types.ToStrings(), "object") {
106-
return recurseNodeProperties(nodes, line, column, nodeOffset+2, nested.Properties)
106+
return recurseNodeProperties(nodes, line, column, nodeOffset+2, nested.Properties, false)
107107
}
108108
}
109109
}
@@ -115,19 +115,19 @@ func recurseNodeProperties(nodes []*ast.MappingValueNode, line, column, nodeOffs
115115
for _, nested := range schema.OneOf {
116116
if nested.Types != nil && slices.Contains(nested.Types.ToStrings(), "object") {
117117
if len(nested.Properties) > 0 {
118-
return recurseNodeProperties(nodes, line, column, nodeOffset+1, nested.Properties)
118+
return recurseNodeProperties(nodes, line, column, nodeOffset+1, nested.Properties, true)
119119
}
120120
}
121121
}
122122
}
123123

124124
if nodes[nodeOffset].Key.GetToken().Position.Column < column {
125125
if nodes[nodeOffset].Key.GetToken().Position.Line == line {
126-
return prop
126+
return prop, false
127127
}
128-
return recurseNodeProperties(nodes, line, column, nodeOffset+1, prop.Properties)
128+
return recurseNodeProperties(nodes, line, column, nodeOffset+1, prop.Properties, false)
129129
}
130-
return prop.Properties
130+
return prop.Properties, false
131131
}
132-
return properties
132+
return properties, false
133133
}

0 commit comments

Comments
 (0)