feat: Improve root handler; Improve language detection; Bugfixes

This commit is contained in:
Myzel394 2024-08-25 15:49:27 +02:00
parent 0ed506f604
commit 67085d761e
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
24 changed files with 426 additions and 71 deletions

View File

@ -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
} }

View File

@ -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{

Binary file not shown.

View File

@ -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()
},
)
}

View File

@ -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)
} }
} }

View File

@ -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
}

View File

@ -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))

View 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
}

View 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{}

View 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
}

View 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
}

View 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
}

View 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
}

View File

@ -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{}{}

View File

@ -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)
} }
} }

View File

@ -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{},
}
} }

View File

@ -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) {

View File

@ -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)
} }

View File

@ -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)
} }

View File

@ -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)
} }

View File

@ -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:
} }

View File

@ -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(
if err != nil {
parseError := err.(common.ParseError)
showParseError(
context, context,
content,
params.TextDocument.URI, params.TextDocument.URI,
parseError, params.TextDocument.LanguageID,
) )
return parseError.Err if err != nil {
return 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
}

View File

@ -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)
} }

View File

@ -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)
}