diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ab42d9..f2f8edb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ All notable changes to the Docker Language Server will be documented in this fil - Bake - textDocument/codeLens - refactor the URI handling code so it will accept a WSL URI with a dollar sign ([#388](https://github.com/docker/docker-language-server/issues/388)) + - textDocument/completion + - fix build stage and ARG name inference completion items for files in a folder under the `\\wsl$` host ([#396](https://github.com/docker/docker-language-server/issues/396)) - textDocument/definition - handle WSL URIs with a dollar sign properly to fix build stage lookups on those hosts ([#390](https://github.com/docker/docker-language-server/issues/390)) - handle WSL URIs with a dollar sign properly to fix build ARG reference lookups on those hosts ([#393](https://github.com/docker/docker-language-server/issues/393)) diff --git a/internal/bake/hcl/completion.go b/internal/bake/hcl/completion.go index 065ad2d..e4ec45a 100644 --- a/internal/bake/hcl/completion.go +++ b/internal/bake/hcl/completion.go @@ -68,12 +68,12 @@ func Completion(ctx context.Context, params *protocol.CompletionParams, manager } } - dockerfilePath, err := bakeDocument.DockerfileForTarget(b) + dockerfileURI, dockerfilePath, err := bakeDocument.DockerfileDocumentPathForTarget(b) if dockerfilePath == "" || err != nil { - continue + break } - _, nodes := document.OpenDockerfile(ctx, manager, "", dockerfilePath) + _, nodes := document.OpenDockerfile(ctx, manager, dockerfileURI, dockerfilePath) if nodes != nil { if attribute, ok := attributes["target"]; ok && isInsideRange(attribute.Expr.Range(), params.Position) { if _, ok := attributes["dockerfile-inline"]; ok { @@ -119,8 +119,8 @@ func Completion(ctx context.Context, params *protocol.CompletionParams, manager } } } - break } + break } } diff --git a/internal/bake/hcl/completion_test.go b/internal/bake/hcl/completion_test.go index bb75fc6..b004ef5 100644 --- a/internal/bake/hcl/completion_test.go +++ b/internal/bake/hcl/completion_test.go @@ -400,6 +400,111 @@ func TestCompletion(t *testing.T) { } } +func TestCompletion_WSL(t *testing.T) { + testCases := []struct { + name string + content string + dockerfileContent string + line uint32 + character uint32 + items []protocol.CompletionItem + }{ + { + name: "target attribute in target block", + content: "target \"api\" {\n target = \"\"\n}", + line: 1, + dockerfileContent: "", + character: 12, + items: []protocol.CompletionItem{ + { + Label: "base", + }, + { + Label: "tests", + }, + { + Label: "release", + }, + }, + }, + { + name: "args keys in target block", + content: "target \"api\" {\n args = {\n \"blah\" = \"\"\n }\n}", + line: 2, + dockerfileContent: "", + character: 5, + items: []protocol.CompletionItem{ + { + Label: "TARGETOS", + }, + { + Label: "TARGETARCH", + }, + { + Label: "argOne", + }, + { + Label: "argTwo", + }, + { + Label: "argOnePredefined", + }, + }, + }, + { + name: "resolve build stage targets from a Dockerfile inside a context folder", + content: "target \"backend\" {\n context = \"./backend\"\n target=\"\"\n}", + line: 2, + character: 10, + items: []protocol.CompletionItem{ + { + Label: "nested", + }, + }, + }, + } + + wd, err := os.Getwd() + require.NoError(t, err) + projectRoot := filepath.Dir(filepath.Dir(filepath.Dir(wd))) + completionTestFolderPath := path.Join(projectRoot, "testdata", "completion") + + dockerfilePath := filepath.ToSlash(filepath.Join(completionTestFolderPath, "Dockerfile")) + backendDockerfilePath := filepath.ToSlash(filepath.Join(completionTestFolderPath, "backend", "Dockerfile")) + + dockerfileBytes, err := os.ReadFile(dockerfilePath) + require.NoError(t, err) + backendDockerfileBytes, err := os.ReadFile(backendDockerfilePath) + require.NoError(t, err) + + dockerfileURI := uri.URI("file://wsl%24/docker-desktop/tmp/Dockerfile") + backendDockerfileURI := uri.URI("file://wsl%24/docker-desktop/tmp/backend/Dockerfile") + bakeFileURI := uri.URI("file://wsl%24/docker-desktop/tmp/docker-bake.hcl") + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + manager := document.NewDocumentManager() + changed, err := manager.Write(context.Background(), dockerfileURI, protocol.DockerfileLanguage, 1, dockerfileBytes) + require.NoError(t, err) + require.True(t, changed) + changed, err = manager.Write(context.Background(), backendDockerfileURI, protocol.DockerfileLanguage, 1, backendDockerfileBytes) + require.NoError(t, err) + require.True(t, changed) + + doc := document.NewBakeHCLDocument(bakeFileURI, 1, []byte(tc.content)) + list, err := Completion(context.Background(), &protocol.CompletionParams{ + TextDocumentPositionParams: protocol.TextDocumentPositionParams{ + TextDocument: protocol.TextDocumentIdentifier{URI: string(bakeFileURI)}, + Position: protocol.Position{Line: tc.line, Character: tc.character}, + }, + }, manager, doc) + require.NoError(t, err) + require.False(t, list.IsIncomplete) + require.Equal(t, tc.items, list.Items) + }) + } +} + func TestIsInsideRange(t *testing.T) { testCases := []struct { name string