diff --git a/docs/syntax-highlighting.md b/docs/syntax-highlighting.md index f847069c..e4e1458e 100644 --- a/docs/syntax-highlighting.md +++ b/docs/syntax-highlighting.md @@ -56,6 +56,7 @@ Fallback types are chosen based on meaningful semantic mapping and default theme | `hcl-traversalStep` | `variable` | | `hcl-typeCapsule` | `function` | | `hcl-typePrimitive` | `keyword` | +| `hcl-functionName` | `function` | #### Token Modifiers diff --git a/internal/langserver/handlers/semantic_tokens_test.go b/internal/langserver/handlers/semantic_tokens_test.go index 91799557..9c56d9b6 100644 --- a/internal/langserver/handlers/semantic_tokens_test.go +++ b/internal/langserver/handlers/semantic_tokens_test.go @@ -381,3 +381,123 @@ func TestVarsSemanticTokensFull(t *testing.T) { } }`) } + +func TestVarsSemanticTokensFull_functionToken(t *testing.T) { + tmpDir := TempDir(t) + InitPluginCache(t, tmpDir.Path()) + + var testSchema tfjson.ProviderSchemas + err := json.Unmarshal([]byte(testModuleSchemaOutput), &testSchema) + if err != nil { + t.Fatal(err) + } + + ss, err := state.NewStateStore() + if err != nil { + t.Fatal(err) + } + wc := walker.NewWalkerCollector() + + ls := langserver.NewLangServerMock(t, NewMockSession(&MockSessionInput{ + TerraformCalls: &exec.TerraformMockCalls{ + PerWorkDir: map[string][]*mock.Call{ + tmpDir.Path(): { + { + Method: "Version", + Repeatability: 1, + Arguments: []interface{}{ + mock.AnythingOfType(""), + }, + ReturnArguments: []interface{}{ + version.Must(version.NewVersion("1.0.0")), + nil, + nil, + }, + }, + { + Method: "GetExecPath", + Repeatability: 1, + ReturnArguments: []interface{}{ + "", + }, + }, + { + Method: "ProviderSchemas", + Repeatability: 1, + Arguments: []interface{}{ + mock.AnythingOfType(""), + }, + ReturnArguments: []interface{}{ + &testSchema, + nil, + }, + }, + }, + }, + }, + StateStore: ss, + WalkerCollector: wc, + })) + stop := ls.Start(t) + defer stop() + + ls.Call(t, &langserver.CallRequest{ + Method: "initialize", + ReqParams: fmt.Sprintf(`{ + "capabilities": { + "textDocument": { + "semanticTokens": { + "tokenTypes": [ + "type", + "property", + "string", + "function" + ], + "tokenModifiers": [ + "defaultLibrary", + "deprecated" + ], + "requests": { + "full": true + } + } + } + }, + "rootUri": %q, + "processId": 12345 + }`, tmpDir.URI)}) + waitForWalkerPath(t, ss, wc, tmpDir) + ls.Notify(t, &langserver.CallRequest{ + Method: "initialized", + ReqParams: "{}", + }) + ls.Call(t, &langserver.CallRequest{ + Method: "textDocument/didOpen", + ReqParams: fmt.Sprintf(`{ + "textDocument": { + "version": 0, + "languageId": "terraform", + "text": "locals {\n foo = abs(-42)\n}\n", + "uri": "%s/locals.tf" + } + }`, tmpDir.URI)}) + waitForAllJobs(t, ss) + + ls.CallAndExpectResponse(t, &langserver.CallRequest{ + Method: "textDocument/semanticTokens/full", + ReqParams: fmt.Sprintf(`{ + "textDocument": { + "uri": "%s/locals.tf" + } + }`, tmpDir.URI)}, `{ + "jsonrpc": "2.0", + "id": 3, + "result": { + "data": [ + 0,0,6,3,0, + 1,2,3,1,0, + 0,6,3,0,0 + ] + } + }`) +} diff --git a/internal/lsp/token_encoder.go b/internal/lsp/token_encoder.go index 6db11d4b..0b8234b2 100644 --- a/internal/lsp/token_encoder.go +++ b/internal/lsp/token_encoder.go @@ -145,6 +145,9 @@ func (te *TokenEncoder) resolveTokenType(token lang.SemanticToken) (semtok.Token case lang.TokenTypePrimitive: return te.firstSupportedTokenType( semtok.TokenType(lang.TokenTypePrimitive), semtok.TokenTypeKeyword) + case lang.TokenFunctionName: + return te.firstSupportedTokenType( + semtok.TokenType(lang.TokenFunctionName), semtok.TokenTypeFunction) } return "", false