Skip to content

Commit

Permalink
fix(yamlls): use yamlls hover method if possible
Browse files Browse the repository at this point in the history
  • Loading branch information
qvalentin committed Dec 22, 2023
1 parent 269dd1b commit ab71fac
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 75 deletions.
2 changes: 1 addition & 1 deletion internal/adapter/yamlls/diagnostics.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func filterDiagnostics(diagnostics []lsp.Diagnostic, ast *sitter.Tree, content s
}

func diagnisticIsRelevant(diagnostic lsp.Diagnostic, node *sitter.Node) bool {
logger.Println("Diagnostic", diagnostic.Message)
logger.Debug("Diagnostic", diagnostic.Message)
switch diagnostic.Message {
case "Map keys must be unique":
return !lsplocal.IsInElseBranch(node)
Expand Down
4 changes: 2 additions & 2 deletions internal/adapter/yamlls/documentSync.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (yamllsConnector Connector) DocumentDidOpen(ast *sitter.Tree, params lsp.Di

err := (*yamllsConnector.Conn).Notify(context.Background(), lsp.MethodTextDocumentDidOpen, params)
if err != nil {
logger.Println("Error calling yamlls for didOpen", err)
logger.Error("Error calling yamlls for didOpen", err)
}
}

Expand All @@ -44,7 +44,7 @@ func (yamllsConnector Connector) DocumentDidSave(doc *lsplocal.Document, params

err := (*yamllsConnector.Conn).Notify(context.Background(), lsp.MethodTextDocumentDidSave, params)
if err != nil {
logger.Println("Error calling yamlls for didSave", err)
logger.Error("Error calling yamlls for didSave", err)
}

yamllsConnector.DocumentDidChangeFullSync(doc, lsp.DidChangeTextDocumentParams{TextDocument: lsp.VersionedTextDocumentIdentifier{
Expand Down
2 changes: 2 additions & 0 deletions internal/adapter/yamlls/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ func (yamllsConnector *Connector) yamllsHandler(clientConn jsonrpc2.Conn, docume
case lsp.MethodWorkspaceConfiguration:
settings := yamllsConnector.handleConfiguration(req)
return reply(ctx, settings, nil)
default:
logger.Debug("Method not handled by yamlls handler: ", req.Method())
}

return reply(ctx, true, nil)
Expand Down
50 changes: 38 additions & 12 deletions internal/adapter/yamlls/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,58 @@ import (
lsp "go.lsp.dev/protocol"
)

// Calls the Completion method of yamlls to get a fitting hover response
// TODO: clarify why the hover method of yamlls can't be used
func (yamllsConnector Connector) CallHover(params lsp.HoverParams, word string) lsp.Hover {
// Calls the Hover method of yamlls to get a fitting hover response
// If hover returns nothing appropriate, calls yamlls for completions
func (yamllsConnector Connector) CallHover(ctx context.Context, params lsp.HoverParams, word string) (*lsp.Hover, error) {
if yamllsConnector.Conn == nil {
return lsp.Hover{}
return &lsp.Hover{}, nil
}

hoverResponse, err := (yamllsConnector).getHoverFromHover(ctx, params)
if err != nil {
return hoverResponse, err
}

if hoverResponse.Contents.Value != "" {
return hoverResponse, nil
}
return (yamllsConnector).getHoverFromCompletion(ctx, params, word)
}

func (yamllsConnector Connector) getHoverFromHover(ctx context.Context, params lsp.HoverParams) (*lsp.Hover, error) {

var hoverResponse = reflect.New(reflect.TypeOf(lsp.Hover{})).Interface()
_, err := (*yamllsConnector.Conn).Call(ctx, lsp.MethodTextDocumentHover, params, hoverResponse)
if err != nil {
logger.Error("Error calling yamlls for hover", err)
return &lsp.Hover{}, err
}
logger.Debug("Got hover from yamlls", hoverResponse.(*lsp.Hover).Contents.Value)
return hoverResponse.(*lsp.Hover), nil
}

func (yamllsConnector Connector) getHoverFromCompletion(ctx context.Context, params lsp.HoverParams, word string) (*lsp.Hover, error) {
var (
documentation string
response = reflect.New(reflect.TypeOf(lsp.CompletionList{})).Interface()
completionParams = lsp.CompletionParams{
err error
documentation string
completionResponse = reflect.New(reflect.TypeOf(lsp.CompletionList{})).Interface()
completionParams = lsp.CompletionParams{
TextDocumentPositionParams: params.TextDocumentPositionParams,
}
)

_, err := (*yamllsConnector.Conn).Call(context.Background(), lsp.MethodTextDocumentCompletion, completionParams, response)
_, err = (*yamllsConnector.Conn).Call(ctx, lsp.MethodTextDocumentCompletion, completionParams, completionResponse)
if err != nil {
return util.BuildHoverResponse(documentation, lsp.Range{})
logger.Error("Error calling yamlls for Completion", err)
return &lsp.Hover{}, err
}

for _, completionItem := range response.(*lsp.CompletionList).Items {
for _, completionItem := range completionResponse.(*lsp.CompletionList).Items {
if completionItem.InsertText == word {
documentation = completionItem.Documentation.(string)
break
}
}

return util.BuildHoverResponse(documentation, lsp.Range{})
response := util.BuildHoverResponse(documentation, lsp.Range{})
return &response, nil
}
97 changes: 52 additions & 45 deletions internal/adapter/yamlls/trimTemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,52 +15,9 @@ func prettyPrintNode(node *sitter.Node, previous []byte, result []byte) {

switch node.Type() {
case "if_action":
curser := sitter.NewTreeCursor(node)
curser.GoToFirstChild()
for curser.GoToNextSibling() {
if curser.CurrentFieldName() == "condition" {
earaseTemplate(curser.CurrentNode(), previous, result)
earaseTemplate(curser.CurrentNode().NextSibling(), previous, result)
continue
}
switch curser.CurrentNode().Type() {
case "if", "else if":
earaseTemplate(curser.CurrentNode(), previous, result)
earaseTemplate(curser.CurrentNode().PrevSibling(), previous, result)
case "end", "else":
earaseTemplateAndSiblings(curser.CurrentNode(), previous, result)
default:
prettyPrintNode(curser.CurrentNode(), previous, result)
}
}
curser.Close()

trim_if_action(node, previous, result)
case "block_action", "with_action", "range_action":
for i := 0; i < int(childCount); i++ {
child := node.Child(i)
switch child.Type() {
case
"if",
"selector_expression",
"else",
"range",
"function_call",
"with",
"define",
"{{",
"{{-",
"}}",
"-}}",
"end",
"interpreted_string_literal",
"block",
"variable_definition",
"range_variable_definition":
earaseTemplate(child, previous, result)
default:
prettyPrintNode(child, previous, result)
}
}
trim_action(childCount, node, previous, result)
case "define_action":
earaseTemplate(node, previous, result)
case "function_call":
Expand All @@ -74,6 +31,56 @@ func prettyPrintNode(node *sitter.Node, previous []byte, result []byte) {
}
}

func trim_action(childCount uint32, node *sitter.Node, previous []byte, result []byte) {
for i := 0; i < int(childCount); i++ {
child := node.Child(i)
switch child.Type() {
case
"if",
"selector_expression",
"else",
"range",
"function_call",
"with",
"define",
"{{",
"{{-",
"}}",
"-}}",
"end",
"interpreted_string_literal",
"block",
"variable_definition",
"range_variable_definition":
earaseTemplate(child, previous, result)
default:
prettyPrintNode(child, previous, result)
}
}
}

func trim_if_action(node *sitter.Node, previous []byte, result []byte) {
curser := sitter.NewTreeCursor(node)
curser.GoToFirstChild()
for curser.GoToNextSibling() {
if curser.CurrentFieldName() == "condition" {
earaseTemplate(curser.CurrentNode(), previous, result)
earaseTemplate(curser.CurrentNode().NextSibling(), previous, result)
continue
}
switch curser.CurrentNode().Type() {
case "if", "else if":
earaseTemplate(curser.CurrentNode(), previous, result)
earaseTemplate(curser.CurrentNode().PrevSibling(), previous, result)
case "end", "else":
earaseTemplateAndSiblings(curser.CurrentNode(), previous, result)
default:
prettyPrintNode(curser.CurrentNode(), previous, result)
}
}
curser.Close()
}

func trimFunctionCall(node *sitter.Node, previous []byte, result []byte) {
functionName := node.ChildByFieldName("function")
if functionName.Content(previous) == "include" {
Expand Down
22 changes: 22 additions & 0 deletions internal/adapter/yamlls/trimTemplate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,28 @@ metadata:
`,
},
{
documentText: `
data:
pod_template.yaml: |-
{{- if .Values.worker.podTemplate }}
{{- include "common.tplvalues.render" (dict "value" .Values.worker.podTemplate "context" $) | nindent 4 }}
{{- else }}
apiVersion: v1
kind: Pod
{{ end }}
`,
trimmedText: `
data:
pod_template.yaml: |-
apiVersion: v1
kind: Pod
`,
},
}

func TestTrimTemplate(t *testing.T) {
Expand Down
10 changes: 5 additions & 5 deletions internal/adapter/yamlls/yamlls.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ func NewConnector(yamllsConfiguration util.YamllsConfiguration, clientConn jsonr

stdin, err := yamllsCmd.StdinPipe()
if err != nil {
logger.Println("Could not connect to stdin of yaml-language-server, some features may be missing.")
logger.Error("Could not connect to stdin of yaml-language-server, some features may be missing.")
return &Connector{}
}
stout, err := yamllsCmd.StdoutPipe()
if err != nil {
logger.Println("Could not connect to stdout of yaml-language-server, some features may be missing.")
logger.Error("Could not connect to stdout of yaml-language-server, some features may be missing.")
return &Connector{}
}

Expand All @@ -40,13 +40,13 @@ func NewConnector(yamllsConfiguration util.YamllsConfiguration, clientConn jsonr
if err != nil {
switch e := err.(type) {
case *exec.Error:
logger.Println("Could not start yaml-language-server, some features may be missing. Spawning subprocess failed.", err)
logger.Error("Could not start yaml-language-server, some features may be missing. Spawning subprocess failed.", err)
return &Connector{}
case *exec.ExitError:
logger.Println("Could not start yaml-language-server, some features may be missing. Command exit rc =", e.ExitCode())
logger.Error("Could not start yaml-language-server, some features may be missing. Command exit rc =", e.ExitCode())
return &Connector{}
default:
logger.Println("Could not start yaml-language-server, some features may be missing. Spawning subprocess failed.", err)
logger.Error("Could not start yaml-language-server, some features may be missing. Spawning subprocess failed.", err)
return &Connector{}
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/handler/definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (h *langHandler) handleDefinition(ctx context.Context, reply jsonrpc2.Repli
// suppress errors for clients
// otherwise using go-to-definition on words that have no definition
// will result in an error
logger.Println(err)
logger.Println("Error getting definitions", err)
return reply(ctx, nil, nil)
}
return reply(ctx, result, err)
Expand Down
5 changes: 4 additions & 1 deletion internal/handler/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (h *langHandler) handleHover(ctx context.Context, reply jsonrpc2.Replier, r
if len(word) > 2 && string(word[len(word)-1]) == ":" {
word = word[0 : len(word)-1]
}
var response = h.yamllsConnector.CallHover(params, word)
var response, err = h.yamllsConnector.CallHover(ctx, params, word)
return reply(ctx, response, err)
}
if pt == "function_call" && ct == "identifier" {
Expand Down Expand Up @@ -103,6 +103,9 @@ func (h *langHandler) handleHover(ctx context.Context, reply jsonrpc2.Replier, r
}

if err == nil {
if value == "" {
value = "\"\""
}
result := util.BuildHoverResponse(value, wordRange)
return reply(ctx, result, err)
}
Expand Down
10 changes: 5 additions & 5 deletions internal/handler/initialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (h *langHandler) handleInitialize(ctx context.Context, reply jsonrpc2.Repli

workspaceURI, err := uri.Parse(params.WorkspaceFolders[0].URI)
if err != nil {
logger.Println("Error parsing workspace URI", err)
logger.Error("Error parsing workspace URI", err)
return err
}
h.yamllsConnector.CallInitialize(workspaceURI)
Expand All @@ -37,24 +37,24 @@ func (h *langHandler) handleInitialize(ctx context.Context, reply jsonrpc2.Repli

vals, err := chartutil.ReadValuesFile(h.projectFiles.ValuesFile)
if err != nil {
logger.Println("Error loading values.yaml file", err)
logger.Error("Error loading values.yaml file", err)
}
h.values = vals

chartMetadata, err := chartutil.LoadChartfile(h.projectFiles.ChartFile)
if err != nil {
logger.Println("Error loading Chart.yaml file", err)
logger.Error("Error loading Chart.yaml file", err)
}
h.chartMetadata = *chartMetadata
valueNodes, err := chartutil.ReadYamlFileToNode(h.projectFiles.ValuesFile)
if err != nil {
logger.Println("Error loading values.yaml file", err)
logger.Error("Error loading values.yaml file", err)
}
h.valueNode = valueNodes

chartNode, err := chartutil.ReadYamlFileToNode(h.projectFiles.ChartFile)
if err != nil {
logger.Println("Error loading Chart.yaml file", err)
logger.Error("Error loading Chart.yaml file", err)
}
h.chartNode = chartNode

Expand Down
3 changes: 0 additions & 3 deletions internal/util/lsp.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ package util
import lsp "go.lsp.dev/protocol"

func BuildHoverResponse(value string, wordRange lsp.Range) lsp.Hover {
if value == "" {
value = "\"\""
}
content := lsp.MarkupContent{
Kind: lsp.Markdown,
Value: value,
Expand Down

0 comments on commit ab71fac

Please sign in to comment.