Skip to content

Commit

Permalink
support code templates
Browse files Browse the repository at this point in the history
  • Loading branch information
ms-henglu committed Aug 1, 2024
1 parent 58c8c30 commit 5b063f5
Show file tree
Hide file tree
Showing 5 changed files with 1,294 additions and 0 deletions.
7 changes: 7 additions & 0 deletions internal/langserver/handlers/complete/complete.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ func CandidatesAtPos(data []byte, filename string, pos hcl.Pos, logger *log.Logg
candidateList = append(candidateList, snippets.CodeSampleCandidates(block, editRange)...)
}
}
} else {
editRange := lsp.Range{
Start: ilsp.HCLPosToLSP(pos),
End: ilsp.HCLPosToLSP(pos),
}
editRange.Start.Character = 0
candidateList = append(candidateList, snippets.TemplateCandidates(editRange)...)
}

sort.Slice(candidateList, func(i, j int) bool { return candidateList[i].SortText < candidateList[j].SortText })
Expand Down
47 changes: 47 additions & 0 deletions internal/langserver/handlers/complete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,53 @@ func TestCompletion_codeSample(t *testing.T) {
}, string(expectRaw))
}

func TestCompletion_template(t *testing.T) {
tmpDir := TempDir(t)
InitPluginCache(t, tmpDir.Dir())

ls := langserver.NewLangServerMock(t, NewMockSession(&MockSessionInput{}))
stop := ls.Start(t)
defer stop()

config, err := os.ReadFile(fmt.Sprintf("./testdata/%s/main.tf", t.Name()))
if err != nil {
t.Fatal(err)
}

ls.Call(t, &langserver.CallRequest{
Method: "initialize",
ReqParams: fmt.Sprintf(`{
"capabilities": {},
"rootUri": %q,
"processId": 12345
}`, tmpDir.URI()),
})
ls.Notify(t, &langserver.CallRequest{
Method: "initialized",
ReqParams: "{}",
})
ls.Call(t, &langserver.CallRequest{
Method: "textDocument/didOpen",
ReqParams: buildReqParamsTextDocument(string(config), tmpDir.URI()),
})

rawResponse := ls.Call(t, &langserver.CallRequest{
Method: "textDocument/completion",
ReqParams: buildReqParamsCompletion(1, 14, tmpDir.URI()),
})

var result map[string]interface{}
err = json.Unmarshal(rawResponse.Result, &result)
if err != nil {
t.Fatalf("failed to unmarshal response: %v", err)
}

items := result["items"].([]interface{})
if len(items) < 100 {
t.Fatalf("expected at least 100 items, got %d", len(items))
}
}

func buildReqParamsCompletion(line int, character int, uri string) string {
param := make(map[string]interface{})
textDocument := make(map[string]interface{})
Expand Down
60 changes: 60 additions & 0 deletions internal/langserver/handlers/snippets/templates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package snippets

import (
"embed"
"encoding/json"

lsp "github.com/Azure/azapi-lsp/internal/protocol"
)

//go:embed templates.json
var templateJSON embed.FS

type CompletionModel struct {
Label string `json:"label"`
Documentation DocumentationModel `json:"documentation"`
SortText string `json:"sortText"`
TextEdit TextEditModel `json:"textEdit"`
}

type TextEditModel struct {
NewText string `json:"newText"`
}

type DocumentationModel struct {
Kind string `json:"kind"`
Value string `json:"value"`
}

func TemplateCandidates(editRange lsp.Range) []lsp.CompletionItem {
templates := make([]CompletionModel, 0)
data, err := templateJSON.ReadFile("templates.json")
if err != nil {
return nil
}
err = json.Unmarshal(data, &templates)
if err != nil {
return nil
}

candidates := make([]lsp.CompletionItem, 0)
for _, template := range templates {
candidates = append(candidates, lsp.CompletionItem{
Label: template.Label,
Kind: lsp.SnippetCompletion,
Detail: "Code Sample",
Documentation: lsp.MarkupContent{
Kind: "markdown",
Value: template.Documentation.Value,
},
SortText: template.SortText,
InsertTextFormat: lsp.SnippetTextFormat,
InsertTextMode: lsp.AdjustIndentation,
TextEdit: &lsp.TextEdit{
Range: editRange,
NewText: template.TextEdit.NewText,
},
})
}
return candidates
}
Loading

0 comments on commit 5b063f5

Please sign in to comment.