Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ All notable changes to the Docker Language Server will be documented in this fil
- textDocument/hover
- ignore 4XX errors when hovering over images with a non-standard tag ([#371](https://github.com/docker/docker-language-server/issues/371))
- Compose
- textDocument/completion
- correct file system suggestions if an absolute path is used ([#443](https://github.com/docker/docker-language-server/issues/443))
- textDocument/documentLink
- stop returning links for alias nodes in included paths ([#439](https://github.com/docker/docker-language-server/issues/439))
- Bake
Expand Down
58 changes: 58 additions & 0 deletions internal/compose/completion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -4995,6 +4996,63 @@ services:
}
}

func testCompletion_RootFolder(t *testing.T, composeFileURI, rootDir, content string, line, character protocol.UInteger) {
entries, err := os.ReadDir(rootDir)
require.NoError(t, err, "could not read root directory %v", rootDir)
require.True(t, len(entries) > 0, "no entries in %v which makes it hard to validate this test", rootDir)
items := make([]protocol.CompletionItem, len(entries))
for i := range entries {
items[i] = protocol.CompletionItem{Label: entries[i].Name()}
if entries[i].IsDir() {
items[i].Kind = types.CreateCompletionItemKindPointer(protocol.CompletionItemKindFolder)
} else if entries[i].Type() == os.ModeSymlink {
items[i].Kind = types.CreateCompletionItemKindPointer(protocol.CompletionItemKindReference)
} else {
items[i].Kind = types.CreateCompletionItemKindPointer(protocol.CompletionItemKindFile)
}
}

manager := document.NewDocumentManager()
hub := hub.NewService()
doc := document.NewComposeDocument(manager, uri.URI(composeFileURI), 1, []byte(content))
list, err := Completion(context.Background(), &protocol.CompletionParams{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
TextDocument: protocol.TextDocumentIdentifier{URI: composeFileURI},
Position: protocol.Position{Line: line, Character: character},
},
}, manager, &hub, doc)
require.NoError(t, err)
require.Equal(t, &protocol.CompletionList{Items: items}, list)
}

func TestCompletion_RootFolder(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping on windows as / is not a root folder on Windows")
return
}

composeFileURI := fmt.Sprintf("file://%v", filepath.Join(os.TempDir(), "compose.yaml"))
testCompletion_RootFolder(t, composeFileURI, "/", `
services:
s:
volumes:
- /`, 4, 9)
}

func TestCompletion_WindowsRootFolder(t *testing.T) {
if runtime.GOOS != "windows" {
t.Skip("skipping on non-Windows systems as it will not have a C:\\ folder")
return
}

composeFileURI := fmt.Sprintf("file:///%v", filepath.Join(os.TempDir(), "compose.yaml"))
testCompletion_RootFolder(t, composeFileURI, "C:\\", `
services:
s:
volumes:
- C:\`, 4, 11)
}

func TestCompletion_FileStructure(t *testing.T) {
testCases := []struct {
name string
Expand Down
15 changes: 15 additions & 0 deletions internal/pkg/document/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"net/url"
"strings"
"unicode"

"github.com/docker/docker-language-server/internal/tliron/glsp/protocol"
"github.com/docker/docker-language-server/internal/types"
Expand Down Expand Up @@ -39,13 +40,27 @@ func NewDocument(mgr *Manager, u uri.URI, identifier protocol.LanguageIdentifier
return NewDockerfileDocument(u, version, input)
}

// DirectoryForPrefix returns the parent directory to be used given the
// document's path and the prefix string that has been inserted into the
// document thus far.
//
// prefixRequired is true if prefix can just be a name without any
// slashes or backslashes.
func DirectoryForPrefix(documentPath DocumentPath, prefix, defaultValue string, prefixRequired bool) string {
idx := strings.LastIndex(prefix, "/")
if idx == -1 {
if prefixRequired {
if len(prefix) > 2 && unicode.IsLetter(rune(prefix[0])) && prefix[1] == ':' {
backslashIdx := strings.LastIndex(prefix, "\\")
if backslashIdx != -1 {
return prefix[0 : backslashIdx+1]
}
}
return defaultValue
}
return documentPath.Folder
} else if prefix[0] == '/' {
return prefix[0 : idx+1]
}
_, folder := types.Concatenate(documentPath.Folder, prefix[0:idx], documentPath.WSLDollarSignHost)
return folder
Expand Down
4 changes: 4 additions & 0 deletions internal/types/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ func FileStructureCompletionItems(folder string, hideFiles bool) []protocol.Comp
item := protocol.CompletionItem{Label: entry.Name()}
item.Kind = CreateCompletionItemKindPointer(protocol.CompletionItemKindFolder)
items = append(items, item)
} else if entry.Type() == os.ModeSymlink {
item := protocol.CompletionItem{Label: entry.Name()}
item.Kind = CreateCompletionItemKindPointer(protocol.CompletionItemKindReference)
items = append(items, item)
} else if !hideFiles {
item := protocol.CompletionItem{Label: entry.Name()}
item.Kind = CreateCompletionItemKindPointer(protocol.CompletionItemKindFile)
Expand Down
Loading