mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-18 23:15:26 +02:00
feat: Add tag import analyzer; Improvements
This commit is contained in:
parent
8517a722d1
commit
05335d42d0
@ -42,6 +42,8 @@ func Analyze(
|
||||
analyzeMatchBlocks(ctx)
|
||||
analyzeHostBlock(ctx)
|
||||
analyzeBlocks(ctx)
|
||||
analyzeTagOptions(ctx)
|
||||
analyzeTagImports(ctx)
|
||||
|
||||
return ctx.diagnostics
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"config-lsp/common"
|
||||
"config-lsp/handlers/ssh_config/fields"
|
||||
"fmt"
|
||||
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
var tagOption = fields.CreateNormalizedName("Tag")
|
||||
|
||||
func analyzeTags(
|
||||
ctx *analyzerContext,
|
||||
) {
|
||||
// Check if the specified tags actually exist
|
||||
for _, options := range ctx.document.Indexes.AllOptionsPerName[tagOption] {
|
||||
for _, option := range options {
|
||||
if _, found := ctx.document.Indexes.Tags[option.OptionValue.Value.Value]; !found {
|
||||
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||
Range: option.OptionValue.ToLSPRange(),
|
||||
Message: fmt.Sprintf("Unknown tag: %s", option.OptionValue.Value.Value),
|
||||
Severity: &common.SeverityError,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
server/handlers/ssh_config/analyzer/tag_imports.go
Normal file
33
server/handlers/ssh_config/analyzer/tag_imports.go
Normal file
@ -0,0 +1,33 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"config-lsp/common"
|
||||
"fmt"
|
||||
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func analyzeTagImports(
|
||||
ctx *analyzerContext,
|
||||
) {
|
||||
for name, info := range ctx.document.Indexes.Tags {
|
||||
if _, found := ctx.document.Indexes.TagImports[name]; !found {
|
||||
var diagnosticRange protocol.Range
|
||||
|
||||
if len(info.Block.MatchValue.Entries) == 1 {
|
||||
diagnosticRange = info.Block.MatchOption.ToLSPRange()
|
||||
} else {
|
||||
diagnosticRange = info.EntryValue.ToLSPRange()
|
||||
}
|
||||
|
||||
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||
Range: diagnosticRange,
|
||||
Message: fmt.Sprintf("Tag %s is not used", name),
|
||||
Severity: &common.SeverityWarning,
|
||||
Tags: []protocol.DiagnosticTag{
|
||||
protocol.DiagnosticTagUnnecessary,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
49
server/handlers/ssh_config/analyzer/tag_imports_test.go
Normal file
49
server/handlers/ssh_config/analyzer/tag_imports_test.go
Normal file
@ -0,0 +1,49 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
testutils_test "config-lsp/handlers/ssh_config/test_utils"
|
||||
"testing"
|
||||
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func TestUsedTagImportsExample(
|
||||
t *testing.T,
|
||||
) {
|
||||
d := testutils_test.DocumentFromInput(t, `
|
||||
Host test.com
|
||||
Tag auth
|
||||
|
||||
Match tagged auth
|
||||
User root
|
||||
`)
|
||||
ctx := &analyzerContext{
|
||||
document: d,
|
||||
diagnostics: make([]protocol.Diagnostic, 0),
|
||||
}
|
||||
|
||||
analyzeTagImports(ctx)
|
||||
|
||||
if len(ctx.diagnostics) > 0 {
|
||||
t.Errorf("Expected no errors, got %v", len(ctx.diagnostics))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnusedTagImportsExample(
|
||||
t *testing.T,
|
||||
) {
|
||||
d := testutils_test.DocumentFromInput(t, `
|
||||
Match tagged auth
|
||||
User root
|
||||
`)
|
||||
ctx := &analyzerContext{
|
||||
document: d,
|
||||
diagnostics: make([]protocol.Diagnostic, 0),
|
||||
}
|
||||
|
||||
analyzeTagImports(ctx)
|
||||
|
||||
if !(len(ctx.diagnostics) == 1) {
|
||||
t.Errorf("Expected 1 error, got %v", len(ctx.diagnostics))
|
||||
}
|
||||
}
|
32
server/handlers/ssh_config/analyzer/tag_options.go
Normal file
32
server/handlers/ssh_config/analyzer/tag_options.go
Normal file
@ -0,0 +1,32 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"config-lsp/common"
|
||||
"config-lsp/handlers/ssh_config/fields"
|
||||
"fmt"
|
||||
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
var tagOption = fields.CreateNormalizedName("Tag")
|
||||
|
||||
func analyzeTagOptions(
|
||||
ctx *analyzerContext,
|
||||
) {
|
||||
// Check if the specified tags actually exist
|
||||
for _, options := range ctx.document.Indexes.AllOptionsPerName[tagOption] {
|
||||
for _, option := range options {
|
||||
tag, found := ctx.document.Indexes.Tags[option.OptionValue.Value.Value]
|
||||
|
||||
if found && tag.Block.Start.Line > option.Start.Line {
|
||||
continue
|
||||
}
|
||||
|
||||
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||
Range: option.OptionValue.ToLSPRange(),
|
||||
Message: fmt.Sprintf("Unknown tag: %s", option.OptionValue.Value.Value),
|
||||
Severity: &common.SeverityError,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
52
server/handlers/ssh_config/analyzer/tag_options_test.go
Normal file
52
server/handlers/ssh_config/analyzer/tag_options_test.go
Normal file
@ -0,0 +1,52 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
testutils_test "config-lsp/handlers/ssh_config/test_utils"
|
||||
"testing"
|
||||
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func TestValidTagExample(
|
||||
t *testing.T,
|
||||
) {
|
||||
d := testutils_test.DocumentFromInput(t, `
|
||||
Host test.com
|
||||
Tag auth
|
||||
|
||||
Match tagged auth
|
||||
User root
|
||||
`)
|
||||
ctx := &analyzerContext{
|
||||
document: d,
|
||||
diagnostics: make([]protocol.Diagnostic, 0),
|
||||
}
|
||||
|
||||
analyzeTagOptions(ctx)
|
||||
|
||||
if len(ctx.diagnostics) > 0 {
|
||||
t.Errorf("Expected no errors, got %v", len(ctx.diagnostics))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagBlockBeforeExample(
|
||||
t *testing.T,
|
||||
) {
|
||||
d := testutils_test.DocumentFromInput(t, `
|
||||
Match tagged auth
|
||||
User root
|
||||
|
||||
Host test.com
|
||||
Tag auth
|
||||
`)
|
||||
ctx := &analyzerContext{
|
||||
document: d,
|
||||
diagnostics: make([]protocol.Diagnostic, 0),
|
||||
}
|
||||
|
||||
analyzeTagOptions(ctx)
|
||||
|
||||
if !(len(ctx.diagnostics) == 1) {
|
||||
t.Errorf("Expected 1 error, got %v", len(ctx.diagnostics))
|
||||
}
|
||||
}
|
@ -65,6 +65,7 @@ func GetOptionCompletions(
|
||||
d *sshconfig.SSHDocument,
|
||||
entry *ast.SSHOption,
|
||||
block ast.SSHBlock,
|
||||
line uint32,
|
||||
cursor common.CursorPosition,
|
||||
) ([]protocol.CompletionItem, error) {
|
||||
option, found := fields.Options[entry.Key.Key]
|
||||
@ -84,6 +85,7 @@ func GetOptionCompletions(
|
||||
if entry.Key.Key == tagOption {
|
||||
return getTagCompletions(
|
||||
d,
|
||||
line,
|
||||
cursor,
|
||||
entry,
|
||||
)
|
||||
@ -94,13 +96,13 @@ func GetOptionCompletions(
|
||||
}
|
||||
|
||||
// Hello wo|rld
|
||||
line := entry.OptionValue.Value.Raw
|
||||
lineValue := entry.OptionValue.Value.Raw
|
||||
// NEW: docvalues index
|
||||
return option.DeprecatedFetchCompletions(
|
||||
line,
|
||||
lineValue,
|
||||
common.DeprecatedImprovedCursorToIndex(
|
||||
cursor,
|
||||
line,
|
||||
lineValue,
|
||||
entry.OptionValue.Start.Character,
|
||||
),
|
||||
), nil
|
||||
|
@ -5,8 +5,6 @@ import (
|
||||
"config-lsp/common/formatting"
|
||||
sshconfig "config-lsp/handlers/ssh_config"
|
||||
"config-lsp/handlers/ssh_config/ast"
|
||||
"config-lsp/handlers/ssh_config/indexes"
|
||||
"config-lsp/utils"
|
||||
"fmt"
|
||||
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
@ -14,24 +12,30 @@ import (
|
||||
|
||||
func getTagCompletions(
|
||||
d *sshconfig.SSHDocument,
|
||||
line uint32,
|
||||
cursor common.CursorPosition,
|
||||
entry *ast.SSHOption,
|
||||
) ([]protocol.CompletionItem, error) {
|
||||
return utils.MapMapToSlice(
|
||||
d.Indexes.Tags,
|
||||
func(name string, info indexes.SSHIndexTagInfo) protocol.CompletionItem {
|
||||
completions := make([]protocol.CompletionItem, 0)
|
||||
|
||||
for name, info := range d.Indexes.Tags {
|
||||
if info.Block.Start.Line < line {
|
||||
continue
|
||||
}
|
||||
|
||||
kind := protocol.CompletionItemKindModule
|
||||
text := renderMatchBlock(info.Block)
|
||||
return protocol.CompletionItem{
|
||||
completions = append(completions, protocol.CompletionItem{
|
||||
Label: name,
|
||||
Kind: &kind,
|
||||
Documentation: protocol.MarkupContent{
|
||||
Kind: protocol.MarkupKindMarkdown,
|
||||
Value: fmt.Sprintf("```sshconfig\n%s\n```", text),
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
), nil
|
||||
|
||||
return completions, nil
|
||||
}
|
||||
|
||||
func renderMatchBlock(
|
||||
|
@ -42,6 +42,7 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
|
||||
d,
|
||||
option,
|
||||
block,
|
||||
line,
|
||||
cursor,
|
||||
)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user