mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-18 23:15:26 +02:00
fix(aliases): Improve aliases
This commit is contained in:
parent
5cbf5be8ad
commit
31faa9a96d
1
go.mod
1
go.mod
@ -10,6 +10,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/gorilla/websocket v1.5.3 // indirect
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
github.com/iancoleman/strcase v0.3.0 // indirect
|
github.com/iancoleman/strcase v0.3.0 // indirect
|
||||||
github.com/k0kubun/pp v3.0.1+incompatible // indirect
|
github.com/k0kubun/pp v3.0.1+incompatible // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -2,6 +2,8 @@ github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYW
|
|||||||
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
13
handlers/aliases/analyzer/analyzer.go
Normal file
13
handlers/aliases/analyzer/analyzer.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/handlers/hosts"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Analyze(
|
||||||
|
d *hosts.HostsDocument,
|
||||||
|
) []protocol.Diagnostic {
|
||||||
|
return nil
|
||||||
|
}
|
49
handlers/aliases/analyzer/parser.go
Normal file
49
handlers/aliases/analyzer/parser.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/aliases/ast"
|
||||||
|
|
||||||
|
ers "errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func analyzeValuesAreValid(
|
||||||
|
p ast.AliasesParser,
|
||||||
|
) []common.LSPError {
|
||||||
|
errors := make([]common.LSPError, 0)
|
||||||
|
|
||||||
|
it := p.Aliases.Iterator()
|
||||||
|
|
||||||
|
for it.Next() {
|
||||||
|
entry := it.Value().(*ast.AliasEntry)
|
||||||
|
|
||||||
|
if entry.Key == nil {
|
||||||
|
errors = append(errors, common.LSPError{
|
||||||
|
Range: entry.Location,
|
||||||
|
Err: ers.New("A name is required"),
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.Separator == nil {
|
||||||
|
errors = append(errors, common.LSPError{
|
||||||
|
Range: entry.Location,
|
||||||
|
Err: ers.New("The separator is required"),
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.Values == nil || len(entry.Values.Values) == 0 {
|
||||||
|
errors = append(errors, common.LSPError{
|
||||||
|
Range: entry.Location,
|
||||||
|
Err: ers.New("A value is required"),
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
package tree
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
|
"github.com/emirpasic/gods/maps/treemap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Procedure
|
// Procedure
|
||||||
@ -34,6 +35,6 @@ type AliasEntry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AliasesParser struct {
|
type AliasesParser struct {
|
||||||
Aliases map[uint32]*AliasEntry
|
Aliases *treemap.Map
|
||||||
CommentLines map[uint32]struct{}
|
CommentLines map[uint32]struct{}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
package tree
|
package ast
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package tree
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
@ -23,16 +23,21 @@ func (s *aliasesParserListener) EnterEntry(ctx *parser.EntryContext) {
|
|||||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||||
location.ChangeBothLines(s.aliasContext.line)
|
location.ChangeBothLines(s.aliasContext.line)
|
||||||
|
|
||||||
s.Parser.Aliases[location.Start.Line] = &AliasEntry{
|
s.Parser.Aliases.Put(
|
||||||
Location: location,
|
location.Start.Line,
|
||||||
}
|
&AliasEntry{
|
||||||
|
Location: location,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *aliasesParserListener) EnterSeparator(ctx *parser.SeparatorContext) {
|
func (s *aliasesParserListener) EnterSeparator(ctx *parser.SeparatorContext) {
|
||||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||||
location.ChangeBothLines(s.aliasContext.line)
|
location.ChangeBothLines(s.aliasContext.line)
|
||||||
|
|
||||||
entry := s.Parser.Aliases[location.Start.Line]
|
rawEntry, _ := s.Parser.Aliases.Get(location.Start.Line)
|
||||||
|
entry := rawEntry.(*AliasEntry)
|
||||||
|
|
||||||
entry.Separator = &location
|
entry.Separator = &location
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +45,9 @@ func (s *aliasesParserListener) EnterKey(ctx *parser.KeyContext) {
|
|||||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||||
location.ChangeBothLines(s.aliasContext.line)
|
location.ChangeBothLines(s.aliasContext.line)
|
||||||
|
|
||||||
entry := s.Parser.Aliases[location.Start.Line]
|
rawEntry, _ := s.Parser.Aliases.Get(location.Start.Line)
|
||||||
|
entry := rawEntry.(*AliasEntry)
|
||||||
|
|
||||||
entry.Key = &AliasKey{
|
entry.Key = &AliasKey{
|
||||||
Location: location,
|
Location: location,
|
||||||
Value: ctx.GetText(),
|
Value: ctx.GetText(),
|
||||||
@ -51,7 +58,9 @@ func (s *aliasesParserListener) EnterValues(ctx *parser.ValuesContext) {
|
|||||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||||
location.ChangeBothLines(s.aliasContext.line)
|
location.ChangeBothLines(s.aliasContext.line)
|
||||||
|
|
||||||
entry := s.Parser.Aliases[location.Start.Line]
|
rawEntry, _ := s.Parser.Aliases.Get(location.Start.Line)
|
||||||
|
entry := rawEntry.(*AliasEntry)
|
||||||
|
|
||||||
entry.Values = &AliasValues{
|
entry.Values = &AliasValues{
|
||||||
Location: location,
|
Location: location,
|
||||||
Values: make([]AliasValueInterface, 0, 5),
|
Values: make([]AliasValueInterface, 0, 5),
|
||||||
@ -71,7 +80,9 @@ func (s *aliasesParserListener) EnterUser(ctx *parser.UserContext) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
entry := s.Parser.Aliases[location.Start.Line]
|
rawEntry, _ := s.Parser.Aliases.Get(location.Start.Line)
|
||||||
|
entry := rawEntry.(*AliasEntry)
|
||||||
|
|
||||||
entry.Values.Values = append(entry.Values.Values, user)
|
entry.Values.Values = append(entry.Values.Values, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,9 +90,12 @@ func (s *aliasesParserListener) EnterFile(ctx *parser.FileContext) {
|
|||||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||||
location.ChangeBothLines(s.aliasContext.line)
|
location.ChangeBothLines(s.aliasContext.line)
|
||||||
|
|
||||||
|
rawEntry, _ := s.Parser.Aliases.Get(location.Start.Line)
|
||||||
|
entry := rawEntry.(*AliasEntry)
|
||||||
|
|
||||||
if s.aliasContext.currentIncludeIndex != nil {
|
if s.aliasContext.currentIncludeIndex != nil {
|
||||||
// This `file` is inside an `include`, so we need to set the path on the include
|
// This `file` is inside an `include`, so we need to set the path on the include
|
||||||
values := s.Parser.Aliases[location.Start.Line].Values
|
values := entry.Values
|
||||||
rawValue := values.Values[*s.aliasContext.currentIncludeIndex]
|
rawValue := values.Values[*s.aliasContext.currentIncludeIndex]
|
||||||
|
|
||||||
// Set the path
|
// Set the path
|
||||||
@ -107,7 +121,6 @@ func (s *aliasesParserListener) EnterFile(ctx *parser.FileContext) {
|
|||||||
Path: path(ctx.GetText()),
|
Path: path(ctx.GetText()),
|
||||||
}
|
}
|
||||||
|
|
||||||
entry := s.Parser.Aliases[location.Start.Line]
|
|
||||||
entry.Values.Values = append(entry.Values.Values, file)
|
entry.Values.Values = append(entry.Values.Values, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +136,9 @@ func (s *aliasesParserListener) EnterCommand(ctx *parser.CommandContext) {
|
|||||||
Command: ctx.GetText()[1:],
|
Command: ctx.GetText()[1:],
|
||||||
}
|
}
|
||||||
|
|
||||||
entry := s.Parser.Aliases[location.Start.Line]
|
rawEntry, _ := s.Parser.Aliases.Get(location.Start.Line)
|
||||||
|
entry := rawEntry.(*AliasEntry)
|
||||||
|
|
||||||
entry.Values.Values = append(entry.Values.Values, command)
|
entry.Values.Values = append(entry.Values.Values, command)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +153,9 @@ func (s *aliasesParserListener) EnterInclude(ctx *parser.IncludeContext) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
entry := s.Parser.Aliases[location.Start.Line]
|
rawEntry, _ := s.Parser.Aliases.Get(location.Start.Line)
|
||||||
|
entry := rawEntry.(*AliasEntry)
|
||||||
|
|
||||||
entry.Values.Values = append(entry.Values.Values, include)
|
entry.Values.Values = append(entry.Values.Values, include)
|
||||||
|
|
||||||
index := uint32(len(entry.Values.Values) - 1)
|
index := uint32(len(entry.Values.Values) - 1)
|
||||||
@ -156,7 +173,9 @@ func (s *aliasesParserListener) EnterEmail(ctx *parser.EmailContext) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
entry := s.Parser.Aliases[location.Start.Line]
|
rawEntry, _ := s.Parser.Aliases.Get(location.Start.Line)
|
||||||
|
entry := rawEntry.(*AliasEntry)
|
||||||
|
|
||||||
entry.Values.Values = append(entry.Values.Values, email)
|
entry.Values.Values = append(entry.Values.Values, email)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package tree
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
"config-lsp/handlers/aliases/parser"
|
"config-lsp/handlers/aliases/parser"
|
||||||
"config-lsp/utils"
|
"config-lsp/utils"
|
||||||
"github.com/antlr4-go/antlr/v4"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/antlr4-go/antlr/v4"
|
||||||
|
"github.com/emirpasic/gods/maps/treemap"
|
||||||
|
gods "github.com/emirpasic/gods/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewAliasesParser() AliasesParser {
|
func NewAliasesParser() AliasesParser {
|
||||||
@ -17,7 +20,7 @@ func NewAliasesParser() AliasesParser {
|
|||||||
|
|
||||||
func (p *AliasesParser) Clear() {
|
func (p *AliasesParser) Clear() {
|
||||||
p.CommentLines = make(map[uint32]struct{})
|
p.CommentLines = make(map[uint32]struct{})
|
||||||
p.Aliases = make(map[uint32]*AliasEntry)
|
p.Aliases = treemap.NewWith(gods.UInt32Comparator)
|
||||||
}
|
}
|
||||||
|
|
||||||
var commentPattern = regexp.MustCompile(`^\s*#.*$`)
|
var commentPattern = regexp.MustCompile(`^\s*#.*$`)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package tree
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/utils"
|
"config-lsp/utils"
|
||||||
@ -19,15 +19,17 @@ postmaster: root
|
|||||||
t.Fatalf("Expected no errors, got %v", errors)
|
t.Fatalf("Expected no errors, got %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(len(parser.Aliases) == 1) {
|
if !(parser.Aliases.Size() == 1) {
|
||||||
t.Fatalf("Expected 1 alias, got %v", len(parser.Aliases))
|
t.Fatalf("Expected 1 alias, got %v", parser.Aliases.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Aliases[0].Key.Value == "postmaster") {
|
rawEntry, _ := parser.Aliases.Get(uint32(0))
|
||||||
t.Fatalf("Expected key to be 'postmaster', got %v", parser.Aliases[1].Key.Value)
|
entry := rawEntry.(*AliasEntry)
|
||||||
|
if !(entry.Key.Value == "postmaster") {
|
||||||
|
t.Fatalf("Expected key to be 'postmaster', got %v", entry.Key.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
userValue := parser.Aliases[0].Values.Values[0].(AliasValueUser)
|
userValue := entry.Values.Values[0].(AliasValueUser)
|
||||||
if !(userValue.Value == "root") {
|
if !(userValue.Value == "root") {
|
||||||
t.Fatalf("Expected value to be 'root', got %v", userValue.Value)
|
t.Fatalf("Expected value to be 'root', got %v", userValue.Value)
|
||||||
}
|
}
|
||||||
@ -51,19 +53,23 @@ michel: raiks@example.com
|
|||||||
t.Fatalf("Expected no errors, got %v", errors)
|
t.Fatalf("Expected no errors, got %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(len(parser.Aliases) == 2) {
|
if !(parser.Aliases.Size() == 2) {
|
||||||
t.Fatalf("Expected 2 aliases, got %v", len(parser.Aliases))
|
t.Fatalf("Expected 2 aliases, got %v", parser.Aliases.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Aliases[0].Key.Value == "heinz") {
|
rawEntry, _ := parser.Aliases.Get(uint32(0))
|
||||||
t.Fatalf("Expected key to be 'heinz', got %v", parser.Aliases[1].Key.Value)
|
entry := rawEntry.(*AliasEntry)
|
||||||
|
if !(entry.Key.Value == "heinz") {
|
||||||
|
t.Fatalf("Expected key to be 'heinz', got %v", entry.Key.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Aliases[1].Key.Value == "michel") {
|
rawEntry, _ = parser.Aliases.Get(uint32(1))
|
||||||
t.Fatalf("Expected key to be 'michel', got %v", parser.Aliases[1].Key.Value)
|
entry = rawEntry.(*AliasEntry)
|
||||||
|
if !(entry.Key.Value == "michel") {
|
||||||
|
t.Fatalf("Expected key to be 'michel', got %v", entry.Key.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
emailValue := parser.Aliases[1].Values.Values[0].(AliasValueEmail)
|
emailValue := entry.Values.Values[0].(AliasValueEmail)
|
||||||
|
|
||||||
if !(emailValue.Value == "raiks@example.com") {
|
if !(emailValue.Value == "raiks@example.com") {
|
||||||
t.Fatalf("Expected value to be 'raiks@example.com', got %v", emailValue.Value)
|
t.Fatalf("Expected value to be 'raiks@example.com', got %v", emailValue.Value)
|
||||||
@ -83,15 +89,17 @@ luke: :include:/etc/other_aliases
|
|||||||
t.Fatalf("Expected no errors, got %v", errors)
|
t.Fatalf("Expected no errors, got %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(len(parser.Aliases) == 1) {
|
if !(parser.Aliases.Size() == 1) {
|
||||||
t.Fatalf("Expected 1 alias, got %v", len(parser.Aliases))
|
t.Fatalf("Expected 1 alias, got %v", parser.Aliases.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Aliases[0].Key.Value == "luke") {
|
rawEntry, _ := parser.Aliases.Get(uint32(0))
|
||||||
t.Fatalf("Expected key to be 'luke', got %v", parser.Aliases[1].Key.Value)
|
entry := rawEntry.(*AliasEntry)
|
||||||
|
if !(entry.Key.Value == "luke") {
|
||||||
|
t.Fatalf("Expected key to be 'luke', got %v", entry.Key.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
includeValue := parser.Aliases[0].Values.Values[0].(AliasValueInclude)
|
includeValue := entry.Values.Values[0].(AliasValueInclude)
|
||||||
|
|
||||||
if !(includeValue.Path.Path == "/etc/other_aliases") {
|
if !(includeValue.Path.Path == "/etc/other_aliases") {
|
||||||
t.Fatalf("Expected path to be '/etc/other_aliases', got %v", includeValue.Path.Path)
|
t.Fatalf("Expected path to be '/etc/other_aliases', got %v", includeValue.Path.Path)
|
||||||
@ -105,3 +113,39 @@ luke: :include:/etc/other_aliases
|
|||||||
t.Fatalf("Expected path location to be 15-33, got %v-%v", includeValue.Path.Location.Start.Character, includeValue.Path.Location.End.Character)
|
t.Fatalf("Expected path location to be 15-33, got %v-%v", includeValue.Path.Location.Start.Character, includeValue.Path.Location.End.Character)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInvalidWithEmptyValuesWorks(
|
||||||
|
t *testing.T,
|
||||||
|
) {
|
||||||
|
input := utils.Dedent(`
|
||||||
|
luke:
|
||||||
|
`)
|
||||||
|
parser := NewAliasesParser()
|
||||||
|
errors := parser.Parse(input)
|
||||||
|
|
||||||
|
if len(errors) == 0 {
|
||||||
|
t.Fatalf("Expected 1 error, got %v", errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(errors[0].Range.Start.Character == 5 && errors[0].Range.End.Character == 5) {
|
||||||
|
t.Fatalf("Expected error to be at 6, got %v", errors[0].Range.Start.Character)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidWithEmptyKeyWorks(
|
||||||
|
t *testing.T,
|
||||||
|
) {
|
||||||
|
input := utils.Dedent(`
|
||||||
|
: root
|
||||||
|
`)
|
||||||
|
parser := NewAliasesParser()
|
||||||
|
errors := parser.Parse(input)
|
||||||
|
|
||||||
|
if len(errors) == 0 {
|
||||||
|
t.Fatalf("Expected 1 error, got %v", errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(errors[0].Range.Start.Character == 0 && errors[0].Range.End.Character == 0) {
|
||||||
|
t.Fatalf("Expected error to be at 0, got %v", errors[0].Range.Start.Character)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package tree
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
|
43
handlers/aliases/indexes/indexes.go
Normal file
43
handlers/aliases/indexes/indexes.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package indexes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/aliases/ast"
|
||||||
|
"config-lsp/handlers/aliases/shared"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AliasesIndexes struct {
|
||||||
|
Keys map[string]*ast.AliasKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateIndexes(parser ast.AliasesParser) (AliasesIndexes, []common.LSPError) {
|
||||||
|
errors := make([]common.LSPError, 0)
|
||||||
|
indexes := &AliasesIndexes{
|
||||||
|
Keys: make(map[string]*ast.AliasKey),
|
||||||
|
}
|
||||||
|
|
||||||
|
it := parser.Aliases.Iterator()
|
||||||
|
|
||||||
|
for it.Next() {
|
||||||
|
entry := it.Value().(*ast.AliasEntry)
|
||||||
|
|
||||||
|
normalizedAlias := strings.ToLower(entry.Key.Value)
|
||||||
|
|
||||||
|
if existingEntry, found := indexes.Keys[normalizedAlias]; found {
|
||||||
|
errors = append(errors, common.LSPError{
|
||||||
|
Range: entry.Location,
|
||||||
|
Err: shared.DuplicateKeyEntry{
|
||||||
|
AlreadyFoundAt: existingEntry.Location.Start.Line,
|
||||||
|
Key: entry.Key.Value,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
indexes.Keys[normalizedAlias] = entry.Key
|
||||||
|
}
|
||||||
|
|
||||||
|
return *indexes, errors
|
||||||
|
}
|
15
handlers/aliases/shared.go
Normal file
15
handlers/aliases/shared.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package aliases
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/handlers/aliases/ast"
|
||||||
|
"config-lsp/handlers/aliases/indexes"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HostsDocument struct {
|
||||||
|
Parser *ast.AliasesParser
|
||||||
|
Indexes *indexes.AliasesIndexes
|
||||||
|
}
|
||||||
|
|
||||||
|
var DocumentParserMap = map[protocol.DocumentUri]*HostsDocument{}
|
12
handlers/aliases/shared/errors.go
Normal file
12
handlers/aliases/shared/errors.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package shared
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type DuplicateKeyEntry struct {
|
||||||
|
AlreadyFoundAt uint32
|
||||||
|
Key string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DuplicateKeyEntry) Error() string {
|
||||||
|
return fmt.Sprintf("Alias '%s' already defined on line %d", d.Key, d.AlreadyFoundAt+1)
|
||||||
|
}
|
@ -13,6 +13,8 @@ var sampleInvalidOptionsExample = `
|
|||||||
LABEL=test /mnt/test btrfs subvol=backup,fat=32 0 0
|
LABEL=test /mnt/test btrfs subvol=backup,fat=32 0 0
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// TODO: Improve `entries`, sometimes the indexes seem
|
||||||
|
// to be wrong. Use a treemap instead of a map.
|
||||||
func TestValidBasicExample(t *testing.T) {
|
func TestValidBasicExample(t *testing.T) {
|
||||||
// Arrange
|
// Arrange
|
||||||
parser := FstabParser{}
|
parser := FstabParser{}
|
||||||
|
@ -4,7 +4,9 @@ import (
|
|||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
"config-lsp/handlers/hosts"
|
"config-lsp/handlers/hosts"
|
||||||
"config-lsp/handlers/hosts/shared"
|
"config-lsp/handlers/hosts/shared"
|
||||||
|
"config-lsp/utils"
|
||||||
"net"
|
"net"
|
||||||
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ipToString(ip net.IPAddr) string {
|
func ipToString(ip net.IPAddr) string {
|
||||||
@ -17,7 +19,15 @@ func analyzeDoubleIPs(d *hosts.HostsDocument) []common.LSPError {
|
|||||||
|
|
||||||
d.Indexes.DoubleIPs = make(map[uint32]shared.DuplicateIPDeclaration)
|
d.Indexes.DoubleIPs = make(map[uint32]shared.DuplicateIPDeclaration)
|
||||||
|
|
||||||
for lineNumber, entry := range d.Parser.Tree.Entries {
|
// TODO: `range` does not seem to properly
|
||||||
|
// iterate in a sorted way.
|
||||||
|
// Instead, use a treemap
|
||||||
|
lines := utils.KeysOfMap(d.Parser.Tree.Entries)
|
||||||
|
slices.Sort(lines)
|
||||||
|
|
||||||
|
for _, lineNumber := range lines {
|
||||||
|
entry := d.Parser.Tree.Entries[lineNumber]
|
||||||
|
|
||||||
if entry.IPAddress != nil {
|
if entry.IPAddress != nil {
|
||||||
key := ipToString(entry.IPAddress.Value)
|
key := ipToString(entry.IPAddress.Value)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user