package wireguard import ( docvalues "config-lsp/doc-values" "config-lsp/utils" "fmt" "maps" "math" "regexp" protocol "github.com/tliron/glsp/protocol_3_16" ) type propertyNotFoundError struct{} func (e propertyNotFoundError) Error() string { return "Property not found" } type propertyNotFullyTypedError struct{} func (e propertyNotFullyTypedError) Error() string { return "Property not fully typed" } type wireguardSection struct { StartLine uint32 EndLine uint32 Properties wireguardProperties } func (s wireguardSection) String() string { var name string if s.Name == nil { name = "" } else { name = *s.Name } return fmt.Sprintf("[%s]; %d-%d: %v", name, s.StartLine, s.EndLine, s.Properties) } func (s *wireguardSection) findProperty(lineNumber uint32) (*wireguardProperty, error) { property, found := s.Properties[lineNumber] if !found { return nil, propertyNotFoundError{} } return &property, nil } func (s wireguardSection) getCompletionsForEmptyLine() ([]protocol.CompletionItem, error) { if s.Name == nil { return nil, nil } options := make(map[string]docvalues.DocumentationValue) switch *s.Name { case "Interface": maps.Copy(options, interfaceOptions) // Remove existing options for _, property := range s.Properties { if _, found := interfaceAllowedDuplicateFields[property.Key.Name]; found { continue } delete(options, property.Key.Name) } case "Peer": maps.Copy(options, peerOptions) // Remove existing options for _, property := range s.Properties { if _, found := peerAllowedDuplicateFields[property.Key.Name]; found { continue } delete(options, property.Key.Name) } } kind := protocol.CompletionItemKindProperty return utils.MapMapToSlice( options, func(optionName string, value docvalues.DocumentationValue) protocol.CompletionItem { insertText := optionName + " = " return protocol.CompletionItem{ Kind: &kind, Documentation: value.Documentation, Label: optionName, InsertText: &insertText, } }, ), nil } func getSeparatorCompletion(property wireguardProperty, character uint32) ([]protocol.CompletionItem, error) { var insertText string if character == property.Key.Location.End { insertText = property.Key.Name + " = " } else { insertText = "= " } kind := protocol.CompletionItemKindValue return []protocol.CompletionItem{ { Label: insertText, InsertText: &insertText, Kind: &kind, }, }, propertyNotFullyTypedError{} } func (p wireguardSection) getCompletionsForPropertyLine( lineNumber uint32, character uint32, ) ([]protocol.CompletionItem, error) { property, err := p.findProperty(lineNumber) if err != nil { return nil, err } if property.Separator == nil { if p.Name != nil { switch *p.Name { case "Interface": if _, found := interfaceOptions[property.Key.Name]; found { return getSeparatorCompletion(*property, character) } case "Peer": if _, found := peerOptions[property.Key.Name]; found { return getSeparatorCompletion(*property, character) } } // Get empty line completions return nil, propertyNotFullyTypedError{} } return nil, propertyNotFoundError{} } var option docvalues.Value switch *p.Name { case "Interface": option = interfaceOptions[property.Key.Name] case "Peer": option = peerOptions[property.Key.Name] } if option == nil { return nil, propertyNotFoundError{} } if property.Value == nil { if character >= property.Separator.Location.End { return option.FetchCompletions("", 0), nil } } relativeCursor := character - property.Value.Location.Start return option.FetchCompletions(property.Value.Value, relativeCursor), nil } var validHeaderPattern = regexp.MustCompile(`^\s*\[(?P
.+?)\]\s*$`) // Create a new create section // Return (, ) func createWireguardSection( startLine uint32, endLine uint32, headerLine string, props wireguardProperties, ) (string, wireguardSection) { match := validHeaderPattern.FindStringSubmatch(headerLine) var header string if match == nil { // Still typing it header = headerLine[1:] } else { header = match[1] } return header, wireguardSection{ StartLine: startLine, EndLine: endLine, Properties: props, } }