fix(wireguard): Improve completions for the separator

This commit is contained in:
Myzel394 2024-08-14 21:26:28 +02:00
parent c5c3ad802e
commit d9903805c5
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
5 changed files with 133 additions and 9 deletions

View File

@ -1,7 +1,9 @@
// Documentation taken from https://github.com/pirate/wireguard-docs // Documentation taken from https://github.com/pirate/wireguard-docs
package wireguard package wireguard
import docvalues "config-lsp/doc-values" import (
docvalues "config-lsp/doc-values"
)
var HeaderField = docvalues.EnumValue{ var HeaderField = docvalues.EnumValue{
EnforceValues: true, EnforceValues: true,

View File

@ -96,3 +96,53 @@ func TestInterfaceAndPeerSectionRootCompletionsWork(
t.Fatalf("getRootCompletionsForEmptyLine: Expected 1 completions, but got %v", len(completions)) t.Fatalf("getRootCompletionsForEmptyLine: Expected 1 completions, but got %v", len(completions))
} }
} }
func TestPropertyNoSepatorShouldCompleteSeparator(
t *testing.T,
) {
sample := dedent(`
[Interface]
DNS
`)
parser := createWireguardParser()
parser.parseFromString(sample)
completions, err := parser.Sections[0].getCompletionsForPropertyLine(1, 3)
if err == nil {
t.Fatalf("getCompletionsForPropertyLine err is nil but should not be")
}
if len(completions) != 1 {
t.Fatalf("getCompletionsForPropertyLine: Expected 1 completion, but got %v", len(completions))
}
if *completions[0].InsertText != " = " {
t.Fatalf("getCompletionsForPropertyLine: Expected completion to be ' = ', but got '%v'", completions[0].Label)
}
}
func TestPropertyNoSeparatorWithSpaceShouldCompleteSeparator(
t *testing.T,
) {
sample := dedent(`
[Interface]
DNS
`)
parser := createWireguardParser()
parser.parseFromString(sample)
completions, err := parser.Sections[0].getCompletionsForPropertyLine(1, 4)
if err == nil {
t.Fatalf("getCompletionsForPropertyLine err is nil but should not be")
}
if len(completions) != 1 {
t.Fatalf("getCompletionsForPropertyLine: Expected 1 completion, but got %v", len(completions))
}
if *completions[0].InsertText != "= " {
t.Fatalf("getCompletionsForPropertyLine: Expected completion to be '= ', but got '%v'", completions[0].Label)
}
}

View File

@ -17,7 +17,7 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
case LineTypeComment: case LineTypeComment:
return nil, nil return nil, nil
case LineTypeHeader: case LineTypeHeader:
return nil, nil return parser.getRootCompletionsForEmptyLine(), nil
case LineTypeEmpty: case LineTypeEmpty:
if section == nil { if section == nil {
return parser.getRootCompletionsForEmptyLine(), nil return parser.getRootCompletionsForEmptyLine(), nil
@ -25,8 +25,12 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
return section.getCompletionsForEmptyLine() return section.getCompletionsForEmptyLine()
case LineTypeProperty: case LineTypeProperty:
if section == nil {
return nil, nil return nil, nil
} }
return section.getCompletionsForPropertyLine(lineNumber, params.Position.Character)
}
panic("TextDocumentCompletion: unexpected line type") panic("TextDocumentCompletion: unexpected line type")
} }

View File

@ -10,6 +10,18 @@ import (
protocol "github.com/tliron/glsp/protocol_3_16" 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 { type wireguardSection struct {
StartLine uint32 StartLine uint32
EndLine uint32 EndLine uint32
@ -30,6 +42,16 @@ func (s wireguardSection) String() string {
return fmt.Sprintf("[%s]; %d-%d: %v", name, s.StartLine, s.EndLine, s.Properties) return fmt.Sprintf("[%s]; %d-%d: %v", name, s.StartLine, s.EndLine, s.Properties)
} }
func (s *wireguardSection) findProperty(lineNumber uint32) (*wireguardProperty, error) {
for _, property := range s.Properties {
if property.Key.Location.Start <= lineNumber && property.Key.Location.End >= lineNumber {
return &property, nil
}
}
return nil, propertyNotFoundError{}
}
func (s wireguardSection) getCompletionsForEmptyLine() ([]protocol.CompletionItem, error) { func (s wireguardSection) getCompletionsForEmptyLine() ([]protocol.CompletionItem, error) {
if s.Name == nil { if s.Name == nil {
return nil, nil return nil, nil
@ -76,6 +98,57 @@ func (s wireguardSection) getCompletionsForEmptyLine() ([]protocol.CompletionIte
return []protocol.CompletionItem{}, nil return []protocol.CompletionItem{}, nil
} }
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 {
var insertText string
if character == property.Key.Location.End {
insertText = " = "
} else {
insertText = "= "
}
return []protocol.CompletionItem{
{
Label: "=",
InsertText: &insertText,
},
}, propertyNotFullyTypedError{}
}
var option docvalues.Value
for enum, opt := range interfaceOptions {
if enum.InsertText == property.Key.Name {
option = opt
break
}
}
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<header>.+?)\]\s*$`) var validHeaderPattern = regexp.MustCompile(`^\s*\[(?P<header>.+?)\]\s*$`)
func createWireguardSection(startLine uint32, endLine uint32, headerLine string, props wireguardProperties) wireguardSection { func createWireguardSection(startLine uint32, endLine uint32, headerLine string, props wireguardProperties) wireguardSection {

View File

@ -2,14 +2,9 @@ package utils
import ( import (
"regexp" "regexp"
"strings"
) )
func IndexOffset(s string, search string, start int) int { var trimIndexPattern = regexp.MustCompile(`^\s*(.+?)\s*$`)
return strings.Index(s[start:], search) + start
}
var trimIndexPattern = regexp.MustCompile(`^\s+(.+?)\s+`)
func GetTrimIndex(s string) []int { func GetTrimIndex(s string) []int {
indexes := trimIndexPattern.FindStringSubmatchIndex(s) indexes := trimIndexPattern.FindStringSubmatchIndex(s)