diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e18b07..2548c32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ All notable changes to the Docker Language Server will be documented in this fil - textDocument/documentLink - add anchor resolution for all supported document links ([#348](https://github.com/docker/docker-language-server/issues/348)) - return document links for the `file` attribute of a service object's `extends` attribute object ([#172](https://github.com/docker/docker-language-server/issues/172)) + - textDocument/hover + - support hovering over referenced models ([#343](https://github.com/docker/docker-language-server/issues/343)) ### Fixed diff --git a/internal/compose/hover.go b/internal/compose/hover.go index 3c6996a..2b1d857 100644 --- a/internal/compose/hover.go +++ b/internal/compose/hover.go @@ -50,6 +50,10 @@ func Hover(ctx context.Context, params *protocol.HoverParams, doc document.Compo if result != nil { return result, nil } + result = modelHover(doc, mappingNode, nodePath) + if result != nil { + return result, nil + } result = hover(composeSchema, nodePath, line, character, len(lines[params.Position.Line])+1) if result != nil { return result, nil @@ -149,26 +153,6 @@ func networkHover(doc document.ComposeDocument, mappingNode *ast.MappingNode, no return nil } -func createDependencyHover(doc document.ComposeDocument, mappingNode *ast.MappingNode, hovered *token.Token, dependencyType, dependencyName string) *protocol.Hover { - for _, node := range mappingNode.Values { - if s, ok := node.Key.(*ast.StringNode); ok && s.Value == dependencyType { - if mappingNode, ok := node.Value.(*ast.MappingNode); ok { - for _, service := range mappingNode.Values { - if service.Key.GetToken().Value == dependencyName { - return createYamlHover(service, hovered) - } - } - } - } - } - - node, _ := dependencyLookup(doc, dependencyType, dependencyName) - if node != nil { - return createYamlHover(node, hovered) - } - return nil -} - func configHover(doc document.ComposeDocument, mappingNode *ast.MappingNode, nodePath []ast.Node) *protocol.Hover { if len(nodePath) == 4 && nodePath[0].GetToken().Value == "services" { // array string @@ -249,6 +233,36 @@ func volumeHover(doc document.ComposeDocument, params *protocol.HoverParams, map return nil } +func modelHover(doc document.ComposeDocument, mappingNode *ast.MappingNode, nodePath []ast.Node) *protocol.Hover { + if len(nodePath) == 4 && nodePath[0].GetToken().Value == "services" { + if nodePath[2].GetToken().Value == "models" { + t := nodePath[3].GetToken() + return createDependencyHover(doc, mappingNode, t, "models", t.Value) + } + } + return nil +} + +func createDependencyHover(doc document.ComposeDocument, mappingNode *ast.MappingNode, hovered *token.Token, dependencyType, dependencyName string) *protocol.Hover { + for _, node := range mappingNode.Values { + if s, ok := node.Key.(*ast.StringNode); ok && s.Value == dependencyType { + if mappingNode, ok := node.Value.(*ast.MappingNode); ok { + for _, service := range mappingNode.Values { + if service.Key.GetToken().Value == dependencyName { + return createYamlHover(service, hovered) + } + } + } + } + } + + node, _ := dependencyLookup(doc, dependencyType, dependencyName) + if node != nil { + return createYamlHover(node, hovered) + } + return nil +} + func hover(schema *jsonschema.Schema, nodes []ast.Node, line, column, lineLength int) *protocol.Hover { for _, match := range nodes { if schema.Ref != nil { diff --git a/internal/compose/hover_test.go b/internal/compose/hover_test.go index aa0f426..9a8ff43 100644 --- a/internal/compose/hover_test.go +++ b/internal/compose/hover_test.go @@ -1139,6 +1139,89 @@ services: character: 10, result: nil, }, + { + name: "models hover with a single item", + content: ` +services: + app: + models: + - ai_model + +models: + ai_model: + model: ai/model`, + line: 4, + character: 12, + result: &protocol.Hover{ + Contents: protocol.MarkupContent{ + Kind: protocol.MarkupKindMarkdown, + Value: "```YAML\n" + `ai_model: + model: ai/model` + + "\n```", + }, + Range: &protocol.Range{ + Start: protocol.Position{Line: 4, Character: 8}, + End: protocol.Position{Line: 4, Character: 16}, + }, + }, + }, + { + name: "models hover with multiple items", + content: ` +services: + app: + models: + - model1 + - model2 + +models: + model1: + model: ai/model + model2: + model: ai/all-minilm`, + line: 5, + character: 12, + result: &protocol.Hover{ + Contents: protocol.MarkupContent{ + Kind: protocol.MarkupKindMarkdown, + Value: "```YAML\n" + `model2: + model: ai/all-minilm` + + "\n```", + }, + Range: &protocol.Range{ + Start: protocol.Position{Line: 5, Character: 8}, + End: protocol.Position{Line: 5, Character: 14}, + }, + }, + }, + { + name: "models hover on an object reference", + content: ` +services: + test: + models: + my_model: + endpoint_var: MODEL_URL + model_var: MODEL + +models: + my_model: + model: ai/model`, + line: 4, + character: 12, + result: &protocol.Hover{ + Contents: protocol.MarkupContent{ + Kind: protocol.MarkupKindMarkdown, + Value: "```YAML\n" + `my_model: + model: ai/model` + + "\n```", + }, + Range: &protocol.Range{ + Start: protocol.Position{Line: 4, Character: 6}, + End: protocol.Position{Line: 4, Character: 14}, + }, + }, + }, } composeFile := fmt.Sprintf("file:///%v", strings.TrimPrefix(filepath.ToSlash(filepath.Join(os.TempDir(), "compose.yaml")), "/"))