fix(wireguard): Add line indexes

This commit is contained in:
Myzel394 2024-08-18 14:26:46 +02:00
parent dfba267b40
commit 9eedc063a2
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
9 changed files with 197 additions and 78 deletions

2
go.mod
View File

@ -11,7 +11,9 @@ require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/k0kubun/pp v3.0.1+incompatible // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/muesli/termenv v0.15.2 // indirect

6
go.sum
View File

@ -5,8 +5,13 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40=
github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
@ -37,6 +42,7 @@ golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

View File

@ -86,5 +86,7 @@ func (p wireguardSection) analyzeInterfaceSection() []protocol.Diagnostic {
}
func (p wireguardParser) analyzeAllowedIPIsInRange() []protocol.Diagnostic {
diagnostics := []protocol.Diagnostic{}
return diagnostics
}

View File

@ -314,3 +314,8 @@ Oocal NAT-ed node to remote public node
var peerAllowedDuplicateFields = map[string]struct{}{
"AllowedIPs": {},
}
var optionsHeaderMap = map[string](map[string]docvalues.DocumentationValue){
"Interface": interfaceOptions,
"Peer": peerOptions,
}

View File

@ -3,6 +3,8 @@ package wireguard
import (
"strings"
"testing"
"github.com/k0kubun/pp"
)
func dedent(s string) string {
@ -66,6 +68,22 @@ PublicKey = 5555
if !(parser.Sections[2].Properties[10].Key.Name == "PublicKey") {
t.Fatalf("parseFromString failed to collect properties of section 2 %v", parser.Sections[2].Properties)
}
// Check if line indexes are correct
if !(parser.LineIndexes[0].Type == LineTypeHeader &&
parser.LineIndexes[1].Type == LineTypeProperty &&
parser.LineIndexes[2].Type == LineTypeProperty &&
parser.LineIndexes[3].Type == LineTypeEmpty &&
parser.LineIndexes[4].Type == LineTypeComment &&
parser.LineIndexes[5].Type == LineTypeHeader &&
parser.LineIndexes[6].Type == LineTypeProperty &&
parser.LineIndexes[7].Type == LineTypeProperty &&
parser.LineIndexes[8].Type == LineTypeEmpty &&
parser.LineIndexes[9].Type == LineTypeHeader &&
parser.LineIndexes[10].Type == LineTypeProperty) {
pp.Println(parser.LineIndexes)
t.Fatal("parseFromString: Invalid line indexes")
}
}
func TestEmptySectionAtStartWorksFine(
@ -138,7 +156,7 @@ func TestEmptyFileWorksFine(
t.Fatalf("parseFromString failed with error %v", errors)
}
if !(len(parser.Sections) == 0) {
if !(len(parser.Sections) == 1) {
t.Fatalf("parseFromString failed to collect sections %v", parser.Sections)
}
}
@ -221,7 +239,7 @@ func TestFileWithOnlyComments(
t.Fatalf("parseFromString failed with error: %v", errors)
}
if !(len(parser.Sections) == 0) {
if !(len(parser.Sections) == 1) {
t.Fatalf("parseFromString failed to collect sections: %v", parser.Sections)
}

View File

@ -79,38 +79,46 @@ PublicKey = 1234567890
section := parser.getBelongingSectionByLine(0)
// Comment
if section != nil {
t.Fatalf("getBelongingSectionByLine: Expected line 0 to be in no section, but it is in %v", section)
}
section = parser.getBelongingSectionByLine(1)
if section != nil {
t.Fatalf("getBelongingSectionByLine: Expected line 1 to be in no section, but it is in %v", section)
if section != parser.Sections[1] {
t.Fatalf("getBelongingSectionByLine: Expected line 1 to be in global section, but it is in %v", section)
}
section = parser.getBelongingSectionByLine(2)
if section != nil {
t.Fatalf("getBelongingSectionByLine: Expected line 2 to be in no section, but it is in %v", section)
if section != parser.Sections[1] {
t.Fatalf("getBelongingSectionByLine: Expected line 2 to be in global section, but it is in %v", section)
}
section = parser.getBelongingSectionByLine(3)
if section == nil || *section.Name != "Interface" {
if section != parser.Sections[2] {
t.Fatalf("getBelongingSectionByLine: Expected line 3 to be in section Interface, but it is in %v", section)
}
section = parser.getBelongingSectionByLine(4)
if section == nil || *section.Name != "Interface" {
if section != parser.Sections[2] {
t.Fatalf("getBelongingSectionByLine: Expected line 4 to be in section Interface, but it is in %v", section)
}
section = parser.getBelongingSectionByLine(6)
if section == nil || *section.Name != "Interface" {
if section != parser.Sections[2] {
t.Fatalf("getBelongingSectionByLine: Expected line 6 to be in section Interface, but it is in %v", section)
}
section = parser.getBelongingSectionByLine(10)
if section == nil || *section.Name != "Peer" {
if section != parser.Sections[3] {
t.Fatalf("getBelongingSectionByLine: Expected line 10 to be in section Peer, but it is in %v", section)
}
section = parser.getBelongingSectionByLine(12)
// Comment
if section != nil {
t.Fatalf("getBelongingSectionByLine: Expected line 12 to be in no section, but it is in %v", section)
}
}

View File

@ -25,10 +25,6 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
return section.getCompletionsForEmptyLine()
case LineTypeProperty:
if section == nil {
return nil, nil
}
completions, err := section.getCompletionsForPropertyLine(lineNumber, params.Position.Character)
if completions == nil && err != nil {

View File

@ -18,23 +18,41 @@ type characterLocation struct {
End uint32
}
type wireguardLineIndex struct {
Type lineType
BelongingSection *wireguardSection
}
type wireguardParser struct {
GlobalSection *wireguardSection
// <key = name>: if nil then does not belong to a section
Sections map[string]wireguardSection
Sections []*wireguardSection
// Used to identify where not to show diagnostics
CommentLines map[uint32]struct{}
// Indexes
LineIndexes map[uint32]wireguardLineIndex
}
func (p *wireguardParser) clear() {
p.Sections = map[string]wireguardSection{}
p.Sections = []*wireguardSection{}
p.CommentLines = map[uint32]struct{}{}
p.LineIndexes = map[uint32]wireguardLineIndex{}
}
func (p wireguardParser) getInterfaceSection() (*wireguardSection, bool) {
for _, section := range p.Sections {
if section.Name != nil && *section.Name == "Interface" {
return section, true
}
}
return nil, false
}
func (p wireguardParser) getRootCompletionsForEmptyLine() []protocol.CompletionItem {
completions := []protocol.CompletionItem{}
if _, found := p.Sections["Interface"]; !found {
if _, found := p.getInterfaceSection(); !found {
completions = append(completions, headerInterfaceEnum.ToCompletionItem())
}
@ -76,7 +94,7 @@ func getLineType(line string) lineType {
}
func (p *wireguardParser) parseFromString(input string) []common.ParseError {
errors := []common.ParseError{}
var errors []common.ParseError
lines := strings.Split(
input,
"\n",
@ -86,7 +104,6 @@ func (p *wireguardParser) parseFromString(input string) []common.ParseError {
collectedProperties := wireguardProperties{}
var lastPropertyLine *uint32
var earliestPropertyLine *uint32
for index, line := range lines {
currentLineNumber := uint32(len(lines) - index - 1)
@ -95,6 +112,10 @@ func (p *wireguardParser) parseFromString(input string) []common.ParseError {
switch lineType {
case LineTypeComment:
p.CommentLines[currentLineNumber] = struct{}{}
p.LineIndexes[currentLineNumber] = wireguardLineIndex{
Type: LineTypeComment,
BelongingSection: nil,
}
case LineTypeEmpty:
continue
@ -110,8 +131,6 @@ func (p *wireguardParser) parseFromString(input string) []common.ParseError {
continue
}
earliestPropertyLine = &currentLineNumber
if lastPropertyLine == nil {
lastPropertyLine = &currentLineNumber
}
@ -126,14 +145,26 @@ func (p *wireguardParser) parseFromString(input string) []common.ParseError {
lastLine = *lastPropertyLine
}
name, section := createWireguardSection(
section := createWireguardSection(
currentLineNumber,
lastLine,
line,
collectedProperties,
)
p.Sections[name] = section
p.Sections = append(p.Sections, &section)
// Add indexes
for lineNumber := range collectedProperties {
p.LineIndexes[lineNumber] = wireguardLineIndex{
Type: LineTypeProperty,
BelongingSection: &section,
}
}
p.LineIndexes[currentLineNumber] = wireguardLineIndex{
Type: LineTypeHeader,
BelongingSection: &section,
}
// Reset
collectedProperties = wireguardProperties{}
@ -141,12 +172,80 @@ func (p *wireguardParser) parseFromString(input string) []common.ParseError {
}
}
var emptySection *wireguardSection
if len(collectedProperties) > 0 {
p.GlobalSection = &wireguardSection{
StartLine: *earliestPropertyLine,
EndLine: *lastPropertyLine,
emptySection = &wireguardSection{
StartLine: 0,
EndLine: p.Sections[len(p.Sections)-1].StartLine - 1,
Properties: collectedProperties,
}
p.Sections = append(p.Sections, emptySection)
for lineNumber := range collectedProperties {
p.LineIndexes[lineNumber] = wireguardLineIndex{
Type: LineTypeProperty,
BelongingSection: emptySection,
}
}
p.Sections = append(p.Sections, emptySection)
} else {
// Add empty section
var endLine = uint32(len(lines))
if len(p.Sections) > 0 {
endLine = p.Sections[len(p.Sections)-1].StartLine
}
// Add empty section
if endLine != 0 {
emptySection = &wireguardSection{
StartLine: 0,
EndLine: endLine,
Properties: collectedProperties,
}
p.Sections = append(p.Sections, emptySection)
for newLine := uint32(0); newLine < endLine; newLine++ {
if _, found := p.LineIndexes[newLine]; found {
continue
}
p.LineIndexes[newLine] = wireguardLineIndex{
Type: LineTypeEmpty,
BelongingSection: emptySection,
}
}
}
}
// Since we parse the content from bottom to top, we need to reverse the sections
// so its in correct order
slices.Reverse(p.Sections)
// Fill empty lines between sections
for lineNumber, section := range p.Sections {
var endLine uint32
if len(p.Sections) > lineNumber+1 {
nextSection := p.Sections[lineNumber+1]
endLine = nextSection.StartLine
} else {
endLine = uint32(len(lines))
}
for newLine := section.StartLine; newLine < endLine; newLine++ {
if _, found := p.LineIndexes[newLine]; found {
continue
}
p.LineIndexes[newLine] = wireguardLineIndex{
Type: LineTypeEmpty,
BelongingSection: section,
}
}
}
return errors
@ -158,20 +257,8 @@ func (p wireguardParser) getTypeByLine(line uint32) lineType {
return LineTypeComment
}
// Check if line is a section
for _, section := range p.Sections {
if section.StartLine <= line && section.EndLine >= line {
if section.StartLine == line && section.Name != nil {
return LineTypeHeader
}
// Check for properties
for propertyLineNumber := range section.Properties {
if propertyLineNumber == line {
return LineTypeProperty
}
}
}
if info, found := p.LineIndexes[line]; found {
return info.Type
}
return LineTypeEmpty
@ -186,15 +273,10 @@ func (p wireguardParser) getTypeByLine(line uint32) lineType {
// [Peer]
//
// This would return the section [Interface]
func (p wireguardParser) getBelongingSectionByLine(line uint32) *wireguardSection {
for index := range p.Sections {
section := p.Sections[len(p.Sections)-index-1]
if section.StartLine <= line && section.Name != nil {
return &section
}
func (p *wireguardParser) getBelongingSectionByLine(line uint32) *wireguardSection {
if info, found := p.LineIndexes[line]; found {
return info.BelongingSection
}
// Global section
return nil
}

View File

@ -5,7 +5,6 @@ import (
"config-lsp/utils"
"fmt"
"maps"
"math"
"regexp"
protocol "github.com/tliron/glsp/protocol_3_16"
@ -23,9 +22,18 @@ func (e propertyNotFullyTypedError) Error() string {
return "Property not fully typed"
}
type wireguardSectionType uint
const (
wireguardSectionUnknownType wireguardSectionType = 0
wireguardSectionInterfaceType wireguardSectionType = 1
wireguardSectionPeerType wireguardSectionType = 2
)
type wireguardSection struct {
StartLine uint32
EndLine uint32
Name *string
StartLine uint32
EndLine uint32
Properties wireguardProperties
}
@ -130,36 +138,27 @@ func (p wireguardSection) getCompletionsForPropertyLine(
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{}
}
if p.Name == nil {
return nil, propertyNotFoundError{}
}
var option docvalues.Value
options, found := optionsHeaderMap[*p.Name]
switch *p.Name {
case "Interface":
option = interfaceOptions[property.Key.Name]
case "Peer":
option = peerOptions[property.Key.Name]
if !found {
return nil, propertyNotFoundError{}
}
if option == nil {
if property.Separator == nil {
if _, found := options[property.Key.Name]; found {
return getSeparatorCompletion(*property, character)
}
// Get empty line completions
return nil, propertyNotFullyTypedError{}
}
option, found := options[property.Key.Name]
if !found {
return nil, propertyNotFoundError{}
}
@ -183,7 +182,7 @@ func createWireguardSection(
endLine uint32,
headerLine string,
props wireguardProperties,
) (string, wireguardSection) {
) wireguardSection {
match := validHeaderPattern.FindStringSubmatch(headerLine)
var header string
@ -195,7 +194,8 @@ func createWireguardSection(
header = match[1]
}
return header, wireguardSection{
return wireguardSection{
Name: &header,
StartLine: startLine,
EndLine: endLine,
Properties: props,