mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-19 07:25:27 +02:00
feat: Improve root handler; Improve language detection; Bugfixes
This commit is contained in:
parent
0ed506f604
commit
67085d761e
@ -1,10 +1,21 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
type LSPError struct {
|
type LSPError struct {
|
||||||
Range LocationRange
|
Range LocationRange
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l LSPError) ToDiagnostic() protocol.Diagnostic {
|
||||||
|
return protocol.Diagnostic{
|
||||||
|
Range: l.Range.ToLSPRange(),
|
||||||
|
Message: l.Err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type SyntaxError struct {
|
type SyntaxError struct {
|
||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
|
import protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
|
||||||
type Location struct {
|
type Location struct {
|
||||||
Line uint32
|
Line uint32
|
||||||
Character uint32
|
Character uint32
|
||||||
@ -10,11 +12,37 @@ type LocationRange struct {
|
|||||||
End Location
|
End Location
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l LocationRange) ToLSPRange() protocol.Range {
|
||||||
|
return protocol.Range{
|
||||||
|
Start: protocol.Position{
|
||||||
|
Line: l.Start.Line,
|
||||||
|
Character: l.Start.Character,
|
||||||
|
},
|
||||||
|
End: protocol.Position{
|
||||||
|
Line: l.End.Line,
|
||||||
|
Character: l.End.Character,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (l *LocationRange) ChangeBothLines(newLine uint32) {
|
func (l *LocationRange) ChangeBothLines(newLine uint32) {
|
||||||
l.Start.Line = newLine
|
l.Start.Line = newLine
|
||||||
l.End.Line = newLine
|
l.End.Line = newLine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateFullLineRange(line uint32) LocationRange {
|
||||||
|
return LocationRange{
|
||||||
|
Start: Location{
|
||||||
|
Line: line,
|
||||||
|
Character: 0,
|
||||||
|
},
|
||||||
|
End: Location{
|
||||||
|
Line: line,
|
||||||
|
Character: 999999,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func CreateSingleCharRange(line uint32, character uint32) LocationRange {
|
func CreateSingleCharRange(line uint32, character uint32) LocationRange {
|
||||||
return LocationRange{
|
return LocationRange{
|
||||||
Start: Location{
|
Start: Location{
|
||||||
|
BIN
config-lsp
BIN
config-lsp
Binary file not shown.
@ -1 +1,32 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/hosts/tree"
|
||||||
|
"config-lsp/utils"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Analyze(parser tree.HostsParser) []protocol.Diagnostic {
|
||||||
|
errors := analyzeEntriesAreValid(parser)
|
||||||
|
|
||||||
|
if len(errors) > 0 {
|
||||||
|
return utils.Map(
|
||||||
|
errors,
|
||||||
|
func(err common.LSPError) protocol.Diagnostic {
|
||||||
|
return err.ToDiagnostic()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
errors = append(errors, analyzeDoubleIPs(parser)...)
|
||||||
|
errors = append(errors, analyzeDoubleHostNames(parser)...)
|
||||||
|
|
||||||
|
return utils.Map(
|
||||||
|
errors,
|
||||||
|
func(err common.LSPError) protocol.Diagnostic {
|
||||||
|
return err.ToDiagnostic()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -52,11 +52,11 @@ func TestWorksWithDoubleIPs(
|
|||||||
t.Errorf("Expected 1 error, but got %v", len(errors))
|
t.Errorf("Expected 1 error, but got %v", len(errors))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(errors[0].Range.Start.Line == 3) {
|
if !(errors[0].Range.Start.Line == 2) {
|
||||||
t.Errorf("Expected error on line 3, but got %v", errors[0].Range.Start.Line)
|
t.Errorf("Expected error on line 3, but got %v", errors[0].Range.Start.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(errors[0].Err.(DuplicateIPDeclaration).AlreadyFoundAt == 1) {
|
if !(errors[0].Err.(DuplicateIPDeclaration).AlreadyFoundAt == 0) {
|
||||||
t.Errorf("Expected error on line 1, but got %v", errors[0].Err.(DuplicateIPDeclaration).AlreadyFoundAt)
|
t.Errorf("Expected error on line 1, but got %v", errors[0].Err.(DuplicateIPDeclaration).AlreadyFoundAt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ type hostnameEntry struct {
|
|||||||
HostName string
|
HostName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateResolverFromParser(p tree.HostsParser) (Resolver, []common.LSPError) {
|
func createResolverFromParser(p tree.HostsParser) (Resolver, []common.LSPError) {
|
||||||
errors := make([]common.LSPError, 0)
|
errors := make([]common.LSPError, 0)
|
||||||
resolver := Resolver{
|
resolver := Resolver{
|
||||||
Entries: make(map[string]ResolverEntry),
|
Entries: make(map[string]ResolverEntry),
|
||||||
@ -91,3 +91,9 @@ func CreateResolverFromParser(p tree.HostsParser) (Resolver, []common.LSPError)
|
|||||||
|
|
||||||
return resolver, errors
|
return resolver, errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func analyzeDoubleHostNames(p tree.HostsParser) []common.LSPError {
|
||||||
|
_, errors := createResolverFromParser(p)
|
||||||
|
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
@ -21,7 +21,7 @@ func TestResolverEntriesWorksWithNonOverlapping(
|
|||||||
t.Fatalf("PARER FAILED! Expected no errors, but got %v", errors)
|
t.Fatalf("PARER FAILED! Expected no errors, but got %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
resolver, errors := CreateResolverFromParser(parser)
|
resolver, errors := createResolverFromParser(parser)
|
||||||
|
|
||||||
if len(errors) != 0 {
|
if len(errors) != 0 {
|
||||||
t.Errorf("Expected no errors, but got %v", errors)
|
t.Errorf("Expected no errors, but got %v", errors)
|
||||||
@ -63,7 +63,7 @@ func TestResolverEntriesWithSimpleOverlapping(
|
|||||||
t.Fatalf("PARER FAILED! Expected no errors, but got %v", errors)
|
t.Fatalf("PARER FAILED! Expected no errors, but got %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
resolver, errors := CreateResolverFromParser(parser)
|
resolver, errors := createResolverFromParser(parser)
|
||||||
|
|
||||||
if !(len(errors) == 1) {
|
if !(len(errors) == 1) {
|
||||||
t.Errorf("Expected 1 error, but got %v", len(errors))
|
t.Errorf("Expected 1 error, but got %v", len(errors))
|
||||||
@ -93,7 +93,7 @@ func TestResolverEntriesWithComplexOverlapping(
|
|||||||
t.Fatalf("PARER FAILED! Expected no errors, but got %v", errors)
|
t.Fatalf("PARER FAILED! Expected no errors, but got %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
resolver, errors := CreateResolverFromParser(parser)
|
resolver, errors := createResolverFromParser(parser)
|
||||||
|
|
||||||
if !(len(errors) == 1) {
|
if !(len(errors) == 1) {
|
||||||
t.Errorf("Expected 1 error, but got %v", len(errors))
|
t.Errorf("Expected 1 error, but got %v", len(errors))
|
||||||
|
33
handlers/hosts/handlers/analyzer/values.go
Normal file
33
handlers/hosts/handlers/analyzer/values.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/hosts/tree"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func analyzeEntriesAreValid(
|
||||||
|
parser tree.HostsParser,
|
||||||
|
) []common.LSPError {
|
||||||
|
err := make([]common.LSPError, 0)
|
||||||
|
|
||||||
|
for lineNumber, entry := range parser.Tree.Entries {
|
||||||
|
if entry.IPAddress == nil {
|
||||||
|
err = append(err, common.LSPError{
|
||||||
|
Range: common.CreateFullLineRange(lineNumber),
|
||||||
|
Err: errors.New("IP Address is required"),
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.Hostname == nil {
|
||||||
|
err = append(err, common.LSPError{
|
||||||
|
Range: common.CreateFullLineRange(lineNumber),
|
||||||
|
Err: errors.New("Hostname is required"),
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
9
handlers/hosts/lsp/shared.go
Normal file
9
handlers/hosts/lsp/shared.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package lsp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/handlers/hosts/tree"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
var documentParserMap = map[protocol.DocumentUri]*tree.HostsParser{}
|
12
handlers/hosts/lsp/text-document-completion.go
Normal file
12
handlers/hosts/lsp/text-document-completion.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package lsp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tliron/glsp"
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionParams) (any, error) {
|
||||||
|
// p := documentParserMap[params.TextDocument.URI]
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
41
handlers/hosts/lsp/text-document-did-change.go
Normal file
41
handlers/hosts/lsp/text-document-did-change.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package lsp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/hosts/handlers/analyzer"
|
||||||
|
"config-lsp/utils"
|
||||||
|
|
||||||
|
"github.com/tliron/glsp"
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TextDocumentDidChange(
|
||||||
|
context *glsp.Context,
|
||||||
|
params *protocol.DidChangeTextDocumentParams,
|
||||||
|
) error {
|
||||||
|
content := params.ContentChanges[0].(protocol.TextDocumentContentChangeEventWhole).Text
|
||||||
|
common.ClearDiagnostics(context, params.TextDocument.URI)
|
||||||
|
|
||||||
|
parser := documentParserMap[params.TextDocument.URI]
|
||||||
|
parser.Clear()
|
||||||
|
|
||||||
|
diagnostics := make([]protocol.Diagnostic, 0)
|
||||||
|
errors := parser.Parse(content)
|
||||||
|
|
||||||
|
if len(errors) > 0 {
|
||||||
|
diagnostics = append(diagnostics, utils.Map(
|
||||||
|
errors,
|
||||||
|
func(err common.LSPError) protocol.Diagnostic {
|
||||||
|
return err.ToDiagnostic()
|
||||||
|
},
|
||||||
|
)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostics = append(diagnostics, analyzer.Analyze(*parser)...)
|
||||||
|
|
||||||
|
if len(diagnostics) > 0 {
|
||||||
|
common.SendDiagnostics(context, params.TextDocument.URI, diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
12
handlers/hosts/lsp/text-document-did-close.go
Normal file
12
handlers/hosts/lsp/text-document-did-close.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package lsp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tliron/glsp"
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TextDocumentDidClose(context *glsp.Context, params *protocol.DidCloseTextDocumentParams) error {
|
||||||
|
delete(documentParserMap, params.TextDocument.URI)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
41
handlers/hosts/lsp/text-document-did-open.go
Normal file
41
handlers/hosts/lsp/text-document-did-open.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package lsp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/hosts/handlers/analyzer"
|
||||||
|
"config-lsp/handlers/hosts/tree"
|
||||||
|
"config-lsp/utils"
|
||||||
|
|
||||||
|
"github.com/tliron/glsp"
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TextDocumentDidOpen(
|
||||||
|
context *glsp.Context,
|
||||||
|
params *protocol.DidOpenTextDocumentParams,
|
||||||
|
) error {
|
||||||
|
common.ClearDiagnostics(context, params.TextDocument.URI)
|
||||||
|
|
||||||
|
parser := tree.CreateNewHostsParser()
|
||||||
|
documentParserMap[params.TextDocument.URI] = &parser
|
||||||
|
|
||||||
|
errors := parser.Parse(params.TextDocument.Text)
|
||||||
|
|
||||||
|
diagnostics := utils.Map(
|
||||||
|
errors,
|
||||||
|
func(err common.LSPError) protocol.Diagnostic {
|
||||||
|
return err.ToDiagnostic()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
diagnostics = append(
|
||||||
|
diagnostics,
|
||||||
|
analyzer.Analyze(parser)...,
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(diagnostics) > 0 {
|
||||||
|
common.SendDiagnostics(context, params.TextDocument.URI, diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -3,8 +3,8 @@ package tree
|
|||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
"config-lsp/handlers/hosts/parser"
|
"config-lsp/handlers/hosts/parser"
|
||||||
|
"config-lsp/utils"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/antlr4-go/antlr/v4"
|
"github.com/antlr4-go/antlr/v4"
|
||||||
)
|
)
|
||||||
@ -51,10 +51,10 @@ func (p *HostsParser) parseStatement(
|
|||||||
|
|
||||||
func (p *HostsParser) Parse(input string) []common.LSPError {
|
func (p *HostsParser) Parse(input string) []common.LSPError {
|
||||||
errors := make([]common.LSPError, 0)
|
errors := make([]common.LSPError, 0)
|
||||||
lines := strings.Split(input, "\n")
|
lines := utils.SplitIntoLines(input)
|
||||||
|
|
||||||
for rawLineNumber, line := range lines {
|
for rawLineNumber, line := range lines {
|
||||||
lineNumber := uint32(rawLineNumber + 1)
|
lineNumber := uint32(rawLineNumber)
|
||||||
|
|
||||||
if commentPattern.MatchString(line) {
|
if commentPattern.MatchString(line) {
|
||||||
p.CommentLines[lineNumber] = struct{}{}
|
p.CommentLines[lineNumber] = struct{}{}
|
||||||
|
@ -24,44 +24,44 @@ func TestValidSimpleExampleWorks(
|
|||||||
t.Errorf("Expected 1 entry, but got %v", len(parser.Tree.Entries))
|
t.Errorf("Expected 1 entry, but got %v", len(parser.Tree.Entries))
|
||||||
}
|
}
|
||||||
|
|
||||||
if parser.Tree.Entries[1].IPAddress == nil {
|
if parser.Tree.Entries[0].IPAddress == nil {
|
||||||
t.Errorf("Expected IP address to be present, but got nil")
|
t.Errorf("Expected IP address to be present, but got nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].IPAddress.Value.String() == net.ParseIP("1.2.3.4").String()) {
|
if !(parser.Tree.Entries[0].IPAddress.Value.String() == net.ParseIP("1.2.3.4").String()) {
|
||||||
t.Errorf("Expected IP address to be 1.2.3.4, but got %v", parser.Tree.Entries[1].IPAddress.Value)
|
t.Errorf("Expected IP address to be 1.2.3.4, but got %v", parser.Tree.Entries[0].IPAddress.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].Hostname.Value == "hello.com") {
|
if !(parser.Tree.Entries[0].Hostname.Value == "hello.com") {
|
||||||
t.Errorf("Expected hostname to be hello.com, but got %v", parser.Tree.Entries[1].Hostname.Value)
|
t.Errorf("Expected hostname to be hello.com, but got %v", parser.Tree.Entries[0].Hostname.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].Aliases == nil) {
|
if !(parser.Tree.Entries[0].Aliases == nil) {
|
||||||
t.Errorf("Expected no aliases, but got %v", parser.Tree.Entries[1].Aliases)
|
t.Errorf("Expected no aliases, but got %v", parser.Tree.Entries[0].Aliases)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].Location.Start.Line == 1) {
|
if !(parser.Tree.Entries[0].Location.Start.Line == 0) {
|
||||||
t.Errorf("Expected line to be 1, but got %v", parser.Tree.Entries[1].Location.Start.Line)
|
t.Errorf("Expected line to be 1, but got %v", parser.Tree.Entries[0].Location.Start.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].Location.Start.Character == 0) {
|
if !(parser.Tree.Entries[0].Location.Start.Character == 0) {
|
||||||
t.Errorf("Expected start to be 0, but got %v", parser.Tree.Entries[1].Location.Start)
|
t.Errorf("Expected start to be 0, but got %v", parser.Tree.Entries[0].Location.Start)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].Location.End.Character == 16) {
|
if !(parser.Tree.Entries[0].Location.End.Character == 16) {
|
||||||
t.Errorf("Expected end to be 16, but got %v", parser.Tree.Entries[1].Location.End.Character)
|
t.Errorf("Expected end to be 16, but got %v", parser.Tree.Entries[0].Location.End.Character)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].IPAddress.Location.Start.Line == 1) {
|
if !(parser.Tree.Entries[0].IPAddress.Location.Start.Line == 0) {
|
||||||
t.Errorf("Expected IP address line to be 1, but got %v", parser.Tree.Entries[1].IPAddress.Location.Start.Line)
|
t.Errorf("Expected IP address line to be 1, but got %v", parser.Tree.Entries[0].IPAddress.Location.Start.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].IPAddress.Location.Start.Character == 0) {
|
if !(parser.Tree.Entries[0].IPAddress.Location.Start.Character == 0) {
|
||||||
t.Errorf("Expected IP address start to be 0, but got %v", parser.Tree.Entries[1].IPAddress.Location.Start.Character)
|
t.Errorf("Expected IP address start to be 0, but got %v", parser.Tree.Entries[0].IPAddress.Location.Start.Character)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].IPAddress.Location.End.Character == 6) {
|
if !(parser.Tree.Entries[0].IPAddress.Location.End.Character == 6) {
|
||||||
t.Errorf("Expected IP address end to be 6, but got %v", parser.Tree.Entries[1].IPAddress.Location.End.Character)
|
t.Errorf("Expected IP address end to be 6, but got %v", parser.Tree.Entries[0].IPAddress.Location.End.Character)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(len(parser.CommentLines) == 0) {
|
if !(len(parser.CommentLines) == 0) {
|
||||||
@ -91,11 +91,11 @@ func TestValidComplexExampleWorks(
|
|||||||
t.Errorf("Expected 3 entries, but got %v", len(parser.Tree.Entries))
|
t.Errorf("Expected 3 entries, but got %v", len(parser.Tree.Entries))
|
||||||
}
|
}
|
||||||
|
|
||||||
if parser.Tree.Entries[3].IPAddress == nil {
|
if parser.Tree.Entries[2].IPAddress == nil {
|
||||||
t.Errorf("Expected IP address to be present, but got nil")
|
t.Errorf("Expected IP address to be present, but got nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[3].IPAddress.Value.String() == net.ParseIP("1.2.3.4").String()) {
|
if !(parser.Tree.Entries[2].IPAddress.Value.String() == net.ParseIP("1.2.3.4").String()) {
|
||||||
t.Errorf("Expected IP address to be 1.2.3.4, but got %v", parser.Tree.Entries[2].IPAddress.Value)
|
t.Errorf("Expected IP address to be 1.2.3.4, but got %v", parser.Tree.Entries[2].IPAddress.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ func TestValidComplexExampleWorks(
|
|||||||
t.Errorf("Expected 1 comment line, but got %v", len(parser.CommentLines))
|
t.Errorf("Expected 1 comment line, but got %v", len(parser.CommentLines))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(utils.KeyExists(parser.CommentLines, 2)) {
|
if !(utils.KeyExists(parser.CommentLines, 1)) {
|
||||||
t.Errorf("Expected comment line 2 to exist, but it does not")
|
t.Errorf("Expected comment line 2 to exist, but it does not")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,15 +130,15 @@ func TestInvalidExampleWorks(
|
|||||||
t.Errorf("Expected no comment lines, but got %v", len(parser.CommentLines))
|
t.Errorf("Expected no comment lines, but got %v", len(parser.CommentLines))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].IPAddress.Value.String() == net.ParseIP("1.2.3.4").String()) {
|
if !(parser.Tree.Entries[0].IPAddress.Value.String() == net.ParseIP("1.2.3.4").String()) {
|
||||||
t.Errorf("Expected IP address to be nil, but got %v", parser.Tree.Entries[1].IPAddress)
|
t.Errorf("Expected IP address to be nil, but got %v", parser.Tree.Entries[0].IPAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].Hostname == nil) {
|
if !(parser.Tree.Entries[0].Hostname == nil) {
|
||||||
t.Errorf("Expected hostname to be nil, but got %v", parser.Tree.Entries[1].Hostname)
|
t.Errorf("Expected hostname to be nil, but got %v", parser.Tree.Entries[0].Hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(parser.Tree.Entries[1].Aliases == nil) {
|
if !(parser.Tree.Entries[0].Aliases == nil) {
|
||||||
t.Errorf("Expected aliases to be nil, but got %v", parser.Tree.Entries[1].Aliases)
|
t.Errorf("Expected aliases to be nil, but got %v", parser.Tree.Entries[0].Aliases)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,14 @@ const (
|
|||||||
LanguageSSHDConfig SupportedLanguage = "sshd_config"
|
LanguageSSHDConfig SupportedLanguage = "sshd_config"
|
||||||
LanguageFstab SupportedLanguage = "fstab"
|
LanguageFstab SupportedLanguage = "fstab"
|
||||||
LanguageWireguard SupportedLanguage = "languagewireguard"
|
LanguageWireguard SupportedLanguage = "languagewireguard"
|
||||||
|
LanguageHosts SupportedLanguage = "hosts"
|
||||||
)
|
)
|
||||||
|
|
||||||
var AllSupportedLanguages = []string{
|
var AllSupportedLanguages = []string{
|
||||||
string(LanguageSSHDConfig),
|
string(LanguageSSHDConfig),
|
||||||
string(LanguageFstab),
|
string(LanguageFstab),
|
||||||
string(LanguageWireguard),
|
string(LanguageWireguard),
|
||||||
|
string(LanguageHosts),
|
||||||
}
|
}
|
||||||
|
|
||||||
type FatalFileNotReadableError struct {
|
type FatalFileNotReadableError struct {
|
||||||
@ -59,11 +61,19 @@ var valueToLanguageMap = map[string]SupportedLanguage{
|
|||||||
"wireguard": LanguageWireguard,
|
"wireguard": LanguageWireguard,
|
||||||
"wg": LanguageWireguard,
|
"wg": LanguageWireguard,
|
||||||
"languagewireguard": LanguageWireguard,
|
"languagewireguard": LanguageWireguard,
|
||||||
|
"host": LanguageHosts,
|
||||||
|
"hosts": LanguageHosts,
|
||||||
|
"etc/hosts": LanguageHosts,
|
||||||
}
|
}
|
||||||
|
|
||||||
var typeOverwriteRegex = regexp.MustCompile(`^#\?\s*lsp\.language\s*=\s*(\w+)\s*$`)
|
var typeOverwriteRegex = regexp.MustCompile(`#\?\s*lsp\.language\s*=\s*(\w+)\s*`)
|
||||||
var wireguardPattern = regexp.MustCompile(`/wg\d+\.conf$`)
|
var wireguardPattern = regexp.MustCompile(`/wg\d+\.conf$`)
|
||||||
|
|
||||||
|
var undetectableError = common.ParseError{
|
||||||
|
Line: 0,
|
||||||
|
Err: LanguageUndetectableError{},
|
||||||
|
}
|
||||||
|
|
||||||
func DetectLanguage(
|
func DetectLanguage(
|
||||||
content string,
|
content string,
|
||||||
advertisedLanguage string,
|
advertisedLanguage string,
|
||||||
@ -99,14 +109,13 @@ func DetectLanguage(
|
|||||||
return LanguageSSHDConfig, nil
|
return LanguageSSHDConfig, nil
|
||||||
case "file:///etc/fstab":
|
case "file:///etc/fstab":
|
||||||
return LanguageFstab, nil
|
return LanguageFstab, nil
|
||||||
|
case "file:///etc/hosts":
|
||||||
|
return LanguageHosts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(uri, "file:///etc/wireguard/") || wireguardPattern.MatchString(uri) {
|
if strings.HasPrefix(uri, "file:///etc/wireguard/") || wireguardPattern.MatchString(uri) {
|
||||||
return LanguageWireguard, nil
|
return LanguageWireguard, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", common.ParseError{
|
return "", undetectableError
|
||||||
Line: 0,
|
|
||||||
Err: LanguageUndetectableError{},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,14 @@ func (h *RootHandler) AddDocument(uri protocol.DocumentUri, language SupportedLa
|
|||||||
h.languageMap[uri] = language
|
h.languageMap[uri] = language
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *RootHandler) GetLanguageForDocument(uri protocol.DocumentUri) SupportedLanguage {
|
func (h *RootHandler) GetLanguageForDocument(uri protocol.DocumentUri) *SupportedLanguage {
|
||||||
return h.languageMap[uri]
|
language, found := h.languageMap[uri]
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &language
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *RootHandler) RemoveDocument(uri protocol.DocumentUri) {
|
func (h *RootHandler) RemoveDocument(uri protocol.DocumentUri) {
|
||||||
|
@ -9,14 +9,26 @@ import (
|
|||||||
func TextDocumentCodeAction(context *glsp.Context, params *protocol.CodeActionParams) (any, error) {
|
func TextDocumentCodeAction(context *glsp.Context, params *protocol.CodeActionParams) (any, error) {
|
||||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||||
|
|
||||||
switch language {
|
if language == nil {
|
||||||
|
showParseError(
|
||||||
|
context,
|
||||||
|
params.TextDocument.URI,
|
||||||
|
undetectableError,
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil, undetectableError.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *language {
|
||||||
case LanguageFstab:
|
case LanguageFstab:
|
||||||
return nil, nil
|
fallthrough
|
||||||
|
case LanguageHosts:
|
||||||
|
fallthrough
|
||||||
case LanguageSSHDConfig:
|
case LanguageSSHDConfig:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
case LanguageWireguard:
|
case LanguageWireguard:
|
||||||
return wireguard.TextDocumentCodeAction(context, params)
|
return wireguard.TextDocumentCodeAction(context, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("root-handler/TextDocumentCompletion: unexpected language" + language)
|
panic("root-handler/TextDocumentCompletion: unexpected language" + *language)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package roothandler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/handlers/fstab"
|
"config-lsp/handlers/fstab"
|
||||||
|
hosts "config-lsp/handlers/hosts/lsp"
|
||||||
wireguard "config-lsp/handlers/wireguard/lsp"
|
wireguard "config-lsp/handlers/wireguard/lsp"
|
||||||
|
|
||||||
"github.com/tliron/glsp"
|
"github.com/tliron/glsp"
|
||||||
@ -11,14 +12,26 @@ import (
|
|||||||
func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionParams) (any, error) {
|
func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionParams) (any, error) {
|
||||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||||
|
|
||||||
switch language {
|
if language == nil {
|
||||||
|
showParseError(
|
||||||
|
context,
|
||||||
|
params.TextDocument.URI,
|
||||||
|
undetectableError,
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil, undetectableError.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *language {
|
||||||
case LanguageFstab:
|
case LanguageFstab:
|
||||||
return fstab.TextDocumentCompletion(context, params)
|
return fstab.TextDocumentCompletion(context, params)
|
||||||
case LanguageSSHDConfig:
|
case LanguageSSHDConfig:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
case LanguageWireguard:
|
case LanguageWireguard:
|
||||||
return wireguard.TextDocumentCompletion(context, params)
|
return wireguard.TextDocumentCompletion(context, params)
|
||||||
|
case LanguageHosts:
|
||||||
|
return hosts.TextDocumentCompletion(context, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("root-handler/TextDocumentCompletion: unexpected language" + language)
|
panic("root-handler/TextDocumentCompletion: unexpected language" + *language)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package roothandler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/handlers/fstab"
|
"config-lsp/handlers/fstab"
|
||||||
|
hosts "config-lsp/handlers/hosts/lsp"
|
||||||
wireguard "config-lsp/handlers/wireguard/lsp"
|
wireguard "config-lsp/handlers/wireguard/lsp"
|
||||||
|
|
||||||
"github.com/tliron/glsp"
|
"github.com/tliron/glsp"
|
||||||
@ -11,14 +12,52 @@ import (
|
|||||||
func TextDocumentDidChange(context *glsp.Context, params *protocol.DidChangeTextDocumentParams) error {
|
func TextDocumentDidChange(context *glsp.Context, params *protocol.DidChangeTextDocumentParams) error {
|
||||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||||
|
|
||||||
switch language {
|
if language == nil {
|
||||||
|
content := params.ContentChanges[0].(protocol.TextDocumentContentChangeEventWhole).Text
|
||||||
|
newLanguage, err := initFile(
|
||||||
|
context,
|
||||||
|
content,
|
||||||
|
params.TextDocument.URI,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
language = newLanguage
|
||||||
|
|
||||||
|
params := &protocol.DidOpenTextDocumentParams{
|
||||||
|
TextDocument: protocol.TextDocumentItem{
|
||||||
|
URI: params.TextDocument.URI,
|
||||||
|
Text: content,
|
||||||
|
Version: params.TextDocument.Version,
|
||||||
|
LanguageID: string(*language),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *language {
|
||||||
|
case LanguageFstab:
|
||||||
|
return fstab.TextDocumentDidOpen(context, params)
|
||||||
|
case LanguageSSHDConfig:
|
||||||
|
break
|
||||||
|
case LanguageWireguard:
|
||||||
|
return wireguard.TextDocumentDidOpen(context, params)
|
||||||
|
case LanguageHosts:
|
||||||
|
return hosts.TextDocumentDidOpen(context, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *language {
|
||||||
case LanguageFstab:
|
case LanguageFstab:
|
||||||
return fstab.TextDocumentDidChange(context, params)
|
return fstab.TextDocumentDidChange(context, params)
|
||||||
case LanguageSSHDConfig:
|
case LanguageSSHDConfig:
|
||||||
return nil
|
return nil
|
||||||
case LanguageWireguard:
|
case LanguageWireguard:
|
||||||
return wireguard.TextDocumentDidChange(context, params)
|
return wireguard.TextDocumentDidChange(context, params)
|
||||||
|
case LanguageHosts:
|
||||||
|
return hosts.TextDocumentDidChange(context, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("root-handler/TextDocumentDidChange: unexpected language" + language)
|
panic("root-handler/TextDocumentDidChange: unexpected language" + *language)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package roothandler
|
package roothandler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
hosts "config-lsp/handlers/hosts/lsp"
|
||||||
wireguard "config-lsp/handlers/wireguard/lsp"
|
wireguard "config-lsp/handlers/wireguard/lsp"
|
||||||
|
|
||||||
"github.com/tliron/glsp"
|
"github.com/tliron/glsp"
|
||||||
@ -10,14 +11,26 @@ import (
|
|||||||
func TextDocumentDidClose(context *glsp.Context, params *protocol.DidCloseTextDocumentParams) error {
|
func TextDocumentDidClose(context *glsp.Context, params *protocol.DidCloseTextDocumentParams) error {
|
||||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||||
|
|
||||||
|
if language == nil {
|
||||||
|
showParseError(
|
||||||
|
context,
|
||||||
|
params.TextDocument.URI,
|
||||||
|
undetectableError,
|
||||||
|
)
|
||||||
|
|
||||||
|
return undetectableError.Err
|
||||||
|
}
|
||||||
|
|
||||||
delete(openedFiles, params.TextDocument.URI)
|
delete(openedFiles, params.TextDocument.URI)
|
||||||
rootHandler.RemoveDocument(params.TextDocument.URI)
|
rootHandler.RemoveDocument(params.TextDocument.URI)
|
||||||
|
|
||||||
switch language {
|
switch *language {
|
||||||
case LanguageFstab:
|
case LanguageFstab:
|
||||||
case LanguageSSHDConfig:
|
case LanguageSSHDConfig:
|
||||||
case LanguageWireguard:
|
case LanguageWireguard:
|
||||||
return wireguard.TextDocumentDidClose(context, params)
|
return wireguard.TextDocumentDidClose(context, params)
|
||||||
|
case LanguageHosts:
|
||||||
|
return hosts.TextDocumentDidClose(context, params)
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package roothandler
|
|||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
fstab "config-lsp/handlers/fstab"
|
fstab "config-lsp/handlers/fstab"
|
||||||
|
hosts "config-lsp/handlers/hosts/lsp"
|
||||||
wireguard "config-lsp/handlers/wireguard/lsp"
|
wireguard "config-lsp/handlers/wireguard/lsp"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
@ -15,31 +16,26 @@ func TextDocumentDidOpen(context *glsp.Context, params *protocol.DidOpenTextDocu
|
|||||||
|
|
||||||
// Find the file type
|
// Find the file type
|
||||||
content := params.TextDocument.Text
|
content := params.TextDocument.Text
|
||||||
language, err := DetectLanguage(content, params.TextDocument.LanguageID, params.TextDocument.URI)
|
language, err := initFile(
|
||||||
|
context,
|
||||||
|
content,
|
||||||
|
params.TextDocument.URI,
|
||||||
|
params.TextDocument.LanguageID,
|
||||||
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
parseError := err.(common.ParseError)
|
return err
|
||||||
showParseError(
|
|
||||||
context,
|
|
||||||
params.TextDocument.URI,
|
|
||||||
parseError,
|
|
||||||
)
|
|
||||||
|
|
||||||
return parseError.Err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
openedFiles[params.TextDocument.URI] = struct{}{}
|
switch *language {
|
||||||
|
|
||||||
// Everything okay, now we can handle the file
|
|
||||||
rootHandler.AddDocument(params.TextDocument.URI, language)
|
|
||||||
|
|
||||||
switch language {
|
|
||||||
case LanguageFstab:
|
case LanguageFstab:
|
||||||
return fstab.TextDocumentDidOpen(context, params)
|
return fstab.TextDocumentDidOpen(context, params)
|
||||||
case LanguageSSHDConfig:
|
case LanguageSSHDConfig:
|
||||||
break
|
break
|
||||||
case LanguageWireguard:
|
case LanguageWireguard:
|
||||||
return wireguard.TextDocumentDidOpen(context, params)
|
return wireguard.TextDocumentDidOpen(context, params)
|
||||||
|
case LanguageHosts:
|
||||||
|
return hosts.TextDocumentDidOpen(context, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
panic(fmt.Sprintf("unexpected roothandler.SupportedLanguage: %#v", language))
|
panic(fmt.Sprintf("unexpected roothandler.SupportedLanguage: %#v", language))
|
||||||
@ -73,3 +69,30 @@ func showParseError(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func initFile(
|
||||||
|
context *glsp.Context,
|
||||||
|
content string,
|
||||||
|
uri protocol.DocumentUri,
|
||||||
|
advertisedLanguage string,
|
||||||
|
) (*SupportedLanguage, error) {
|
||||||
|
language, err := DetectLanguage(content, advertisedLanguage, uri)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
parseError := err.(common.ParseError)
|
||||||
|
showParseError(
|
||||||
|
context,
|
||||||
|
uri,
|
||||||
|
parseError,
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil, parseError.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
openedFiles[uri] = struct{}{}
|
||||||
|
|
||||||
|
// Everything okay, now we can handle the file
|
||||||
|
rootHandler.AddDocument(uri, language)
|
||||||
|
|
||||||
|
return &language, nil
|
||||||
|
}
|
||||||
|
@ -11,14 +11,26 @@ import (
|
|||||||
func TextDocumentHover(context *glsp.Context, params *protocol.HoverParams) (*protocol.Hover, error) {
|
func TextDocumentHover(context *glsp.Context, params *protocol.HoverParams) (*protocol.Hover, error) {
|
||||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||||
|
|
||||||
switch language {
|
if language == nil {
|
||||||
case LanguageFstab:
|
showParseError(
|
||||||
return fstab.TextDocumentHover(context, params)
|
context,
|
||||||
|
params.TextDocument.URI,
|
||||||
|
undetectableError,
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil, undetectableError.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *language {
|
||||||
|
case LanguageHosts:
|
||||||
|
fallthrough
|
||||||
case LanguageSSHDConfig:
|
case LanguageSSHDConfig:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
case LanguageFstab:
|
||||||
|
return fstab.TextDocumentHover(context, params)
|
||||||
case LanguageWireguard:
|
case LanguageWireguard:
|
||||||
return wireguard.TextDocumentHover(context, params)
|
return wireguard.TextDocumentHover(context, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("root-handler/TextDocumentHover: unexpected language" + language)
|
panic("root-handler/TextDocumentHover: unexpected language" + *language)
|
||||||
}
|
}
|
||||||
|
@ -15,3 +15,7 @@ func GetTrimIndex(s string) []int {
|
|||||||
|
|
||||||
return indexes[2:4]
|
return indexes[2:4]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SplitIntoLines(s string) []string {
|
||||||
|
return regexp.MustCompile("\r?\n").Split(s, -1)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user