internal/langserver/handlers/complete_v2.go (126 lines of code) (raw):

package handlers import ( "context" "fmt" "github.com/Azure/azurerm-lsp/internal/parser" "github.com/Azure/azurerm-lsp/internal/protocol" "github.com/Azure/azurerm-lsp/internal/utils" "github.com/Azure/azurerm-lsp/provider-schema" "github.com/Azure/azurerm-lsp/provider-schema/azurerm/schema" ) func (svc *service) HandleComplete(ctx context.Context, params protocol.CompletionParams) ([]protocol.CompletionItem, error) { docContent, docFileName, err := parser.GetDocumentContent(ctx, params.TextDocument.URI) if err != nil { return nil, err } ctxInfo, diags, err := parser.BuildHCLContext(docContent, docFileName, params.Position) if err != nil || (diags != nil && diags.HasErrors()) { docContent, fieldName, isNewBlock, err := parser.AttemptReparse(docContent, params.Position.Line) if err != nil { if isNewBlock { return GetTopLevelCompletions(params), nil } return nil, nil } ctxInfo, diags, err = parser.BuildHCLContext(docContent, docFileName, params.Position) if err != nil || (diags != nil && diags.HasErrors()) { if utils.MatchAnyPrefix(fieldName, schema.AzureRMPrefix, schema.ResourcesPrefix) { return GetTopLevelCompletions(params), nil } return nil, nil } if ctxInfo.Block != nil || ctxInfo.SubBlock != nil || ctxInfo.Attribute != nil { return GetAttributeCompletions(ctxInfo.Resource, ctxInfo.ParsedPath+"."+fieldName), nil } return GetTopLevelCompletions(params), nil } switch { case ctxInfo.Attribute != nil: return GetAttributeCompletions(ctxInfo.Resource, ctxInfo.ParsedPath), nil case ctxInfo.SubBlock != nil || ctxInfo.Block != nil: return GetBlockAttributeCompletions(ctxInfo.Resource, ctxInfo.ParsedPath), nil default: return GetTopLevelCompletions(params), nil } } func GetTopLevelCompletions(params protocol.CompletionParams) []protocol.CompletionItem { resources := provider_schema.ListAllResources() dataSources := provider_schema.ListAllDataSources() lineRange := getLineRange(params) var items []protocol.CompletionItem for _, name := range append(resources, dataSources...) { snippet, err := provider_schema.GetSnippet(name) if err != nil { continue } content, isDataSource, err := provider_schema.GetResourceContent(name) if err != nil { continue } kind := "resource" if isDataSource { kind = "data source" } items = append(items, protocol.CompletionItem{ Label: fmt.Sprintf("☁️(%s) %s", kind, name), InsertText: snippet, InsertTextFormat: protocol.SnippetTextFormat, Kind: protocol.SnippetCompletion, Detail: "AzureRM " + kind, TextEdit: &protocol.TextEdit{ Range: lineRange, NewText: snippet, }, Documentation: protocol.MarkupContent{ Kind: protocol.Markdown, Value: content, }, }) } return items } func GetBlockAttributeCompletions(resourceName, path string) []protocol.CompletionItem { props, err := provider_schema.ListDirectProperties(resourceName, path) if err != nil { return nil } var items []protocol.CompletionItem for _, p := range props { content, prop, err := provider_schema.GetAttributeContent(resourceName, p.AttributePath) if err != nil || prop == nil { continue } items = append(items, protocol.CompletionItem{ Label: fmt.Sprintf("☁️(property) %s (%s)", p.Name, prop.GetRequirementType()), Kind: protocol.SnippetCompletion, SortText: p.GetSortOrder(), Detail: "Property Info", InsertText: p.Name, Documentation: protocol.MarkupContent{ Kind: protocol.Markdown, Value: content, }, }) } return items } func GetAttributeCompletions(resourceName, path string) []protocol.CompletionItem { values, err := provider_schema.GetPossibleValuesForProperty(resourceName, path) if err != nil { return nil } items := make([]protocol.CompletionItem, 0, len(values)) for _, val := range values { items = append(items, protocol.CompletionItem{ Label: "☁️(value) " + val, Kind: protocol.SnippetCompletion, InsertText: val, }) } return items } func getLineRange(params protocol.CompletionParams) protocol.Range { start := protocol.Position{Line: params.Position.Line, Character: 0} end := params.Position return protocol.Range{Start: start, End: end} }