fix: Fix BinarySearchFunc handling

This commit is contained in:
Myzel394 2024-09-21 09:34:05 +02:00
parent ea2e531393
commit 31c3d755a2
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
8 changed files with 320 additions and 17 deletions

View File

@ -16,15 +16,15 @@ func GetValueAtCursor(
index, found := slices.BinarySearchFunc( index, found := slices.BinarySearchFunc(
entry.Values.Values, entry.Values.Values,
cursor, cursor,
func(entry ast.AliasValueInterface, pos uint32) int { func(current ast.AliasValueInterface, target uint32) int {
value := entry.GetAliasValue() value := current.GetAliasValue()
if pos > value.Location.End.Character { if target < value.Location.Start.Character {
return -1 return 1
} }
if pos < value.Location.Start.Character { if target > value.Location.End.Character {
return 1 return -1
} }
return 0 return 0

View File

@ -0,0 +1,74 @@
package matchparser
import (
"testing"
)
func TestFullExample(
t *testing.T,
) {
input := "User alice,adam Address 192.168.1.1 Host *.example.com"
match := NewMatch()
errs := match.Parse(input, 0, 0)
if len(errs) > 0 {
t.Fatalf("Failed to parse match: %v", errs)
}
entry := match.GetEntryByCursor(0)
if !(entry == match.Entries[0]) {
t.Errorf("Expected entry at 0 to be %v, but got %v", match.Entries[0], entry)
}
entry = match.GetEntryByCursor(5)
if !(entry == match.Entries[0]) {
t.Errorf("Expected entry at 5 to be %v, but got %v", match.Entries[0], entry)
}
entry = match.GetEntryByCursor(13)
if !(entry == match.Entries[0]) {
t.Errorf("Expected entry at 13 to be %v, but got %v", match.Entries[1], entry)
}
entry = match.GetEntryByCursor(16)
if !(entry == match.Entries[1]) {
t.Errorf("Expected entry at 16 to be %v, but got %v", match.Entries[1], entry)
}
entry = match.GetEntryByCursor(24)
if !(entry == match.Entries[1]) {
t.Errorf("Expected entry at 24 to be %v, but got %v", match.Entries[2], entry)
}
entry = match.GetEntryByCursor(36)
if !(entry == match.Entries[2]) {
t.Errorf("Expected entry at 36 to be %v, but got %v", match.Entries[2], entry)
}
}
func TestGetEntryForIncompleteExample(
t *testing.T,
) {
input := "User "
match := NewMatch()
errs := match.Parse(input, 0, 0)
if len(errs) > 0 {
t.Fatalf("Failed to parse match: %v", errs)
}
entry := match.GetEntryByCursor(0)
if !(entry == match.Entries[0]) {
t.Errorf("Expected entry at 0 to be %v, but got %v", match.Entries[0], entry)
}
entry = match.GetEntryByCursor(4)
if !(entry == match.Entries[0]) {
t.Errorf("Expected entry at 4 to be %v, but got %v", match.Entries[0], entry)
}
entry = match.GetEntryByCursor(5)
if !(entry == match.Entries[0]) {
t.Errorf("Expected entry at 5 to be %v, but got %v", match.Entries[0], entry)
}
}

View File

@ -6,12 +6,12 @@ func (m Match) GetEntryByCursor(cursor uint32) *MatchEntry {
index, found := slices.BinarySearchFunc( index, found := slices.BinarySearchFunc(
m.Entries, m.Entries,
cursor, cursor,
func(entry *MatchEntry, cursor uint32) int { func(current *MatchEntry, target uint32) int {
if cursor < entry.Start.Character { if target < current.Start.Character {
return 1 return 1
} }
if cursor > entry.End.Character { if target > current.End.Character {
return -1 return -1
} }
@ -40,12 +40,12 @@ func (e MatchEntry) GetValueByCursor(cursor uint32) *MatchValue {
index, found := slices.BinarySearchFunc( index, found := slices.BinarySearchFunc(
e.Values.Values, e.Values.Values,
cursor, cursor,
func(value *MatchValue, cursor uint32) int { func(current *MatchValue, target uint32) int {
if cursor < value.Start.Character { if target < current.Start.Character {
return 1 return 1
} }
if cursor > value.End.Character { if target > current.End.Character {
return -1 return -1
} }

View File

@ -16,13 +16,13 @@ func GetIncludeOptionLocation(
index, found := slices.BinarySearchFunc( index, found := slices.BinarySearchFunc(
include.Values, include.Values,
cursor, cursor,
func(i *indexes.SSHDIndexIncludeValue, cursor uint32) int { func(current *indexes.SSHDIndexIncludeValue, target uint32) int {
if cursor < i.Start.Character { if target < current.Start.Character {
return -1 return 1
} }
if cursor > i.End.Character { if target > current.End.Character {
return 1 return -1
} }
return 0 return 0

View File

@ -0,0 +1,38 @@
package handlers
import (
sshdconfig "config-lsp/handlers/sshd_config"
"config-lsp/handlers/sshd_config/ast"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func FormatDocument(
d *sshdconfig.SSHDocument,
textRange protocol.Range,
options protocol.FormattingOptions,
) ([]protocol.TextEdit, error) {
edits := make([]protocol.TextEdit, 0)
it := d.Config.Options.Iterator()
for it.Next() {
line := it.Key().(uint32)
entry := it.Value().(ast.SSHDEntry)
if !(line >= textRange.Start.Line && line <= textRange.End.Line) {
continue
}
switch entry.(type) {
case *ast.SSHDOption:
option := entry.(*ast.SSHDOption)
edits = append(edits, formatSSHDOption(option, options)...)
case *ast.SSHDMatchBlock:
matchBlock := entry.(*ast.SSHDMatchBlock)
edits = formatSSHDMatchBlock(matchBlock, options)
}
}
return edits, nil
}

View File

@ -0,0 +1,107 @@
package handlers
import (
"config-lsp/common/formatting"
"config-lsp/handlers/sshd_config/ast"
matchparser "config-lsp/handlers/sshd_config/fields/match-parser"
"config-lsp/utils"
"fmt"
"strings"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func formatSSHDOption(
option *ast.SSHDOption,
options protocol.FormattingOptions,
) []protocol.TextEdit {
template := formatting.FormatTemplate(
"%s/t%s",
)
var key string
if option.Key != nil {
key = option.Key.Key
} else {
key = ""
}
var value string
if option.OptionValue != nil {
value = option.OptionValue.Value.Raw
} else {
value = ""
}
return []protocol.TextEdit{
{
Range: option.ToLSPRange(),
NewText: template.Format(options, key, value),
},
}
}
func formatSSHDMatchBlock(
matchBlock *ast.SSHDMatchBlock,
options protocol.FormattingOptions,
) []protocol.TextEdit {
edits := make([]protocol.TextEdit, 0)
template := formatting.FormatTemplate(
"%s/t%s",
)
edits = append(edits, protocol.TextEdit{
Range: matchBlock.ToLSPRange(),
NewText: template.Format(options, matchBlock.MatchEntry.Key.Key, formatMatchToString(matchBlock.MatchValue, options)),
})
it := matchBlock.Options.Iterator()
for it.Next() {
option := it.Value().(*ast.SSHDOption)
edits = append(edits, formatSSHDOption(option, options)...)
}
return edits
}
func formatMatchToString(
match *matchparser.Match,
options protocol.FormattingOptions,
) string {
entriesAsStrings := utils.Map(
match.Entries,
func(entry *matchparser.MatchEntry) string {
return formatMatchEntryToString(entry, options)
},
)
return strings.Join(entriesAsStrings, " ")
}
func formatMatchEntryToString(
entry *matchparser.MatchEntry,
options protocol.FormattingOptions,
) string {
return fmt.Sprintf(
"%s %s",
string(entry.Criteria.Type),
formatMatchValuesToString(entry.Values, options),
)
}
func formatMatchValuesToString(
values *matchparser.MatchValues,
options protocol.FormattingOptions,
) string {
valuesAsStrings := utils.Map(
values.Values,
func(value *matchparser.MatchValue) string {
return value.Value.Raw
},
)
return strings.Join(valuesAsStrings, ",")
}

View File

@ -0,0 +1,62 @@
package handlers
import (
sshdconfig "config-lsp/handlers/sshd_config"
"config-lsp/handlers/sshd_config/ast"
"config-lsp/handlers/sshd_config/indexes"
"config-lsp/utils"
"testing"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func TestSimpleFormattingExampleWorks(
t *testing.T,
) {
input := utils.Dedent(`
PermitRootLogin yes
a b
`)
config := ast.NewSSHConfig()
errors := config.Parse(input)
if len(errors) > 0 {
t.Fatalf("Failed to parse SSHD config: %v", errors)
}
i, errors := indexes.CreateIndexes(*config)
if len(errors) > 0 {
t.Fatalf("Failed to create indexes: %v", errors)
}
d := sshdconfig.SSHDocument{
Config: config,
Indexes: i,
}
options := protocol.FormattingOptions{}
options["insertSpaces"] = true
options["tabSize"] = float64(4)
edits, err := FormatDocument(
&d,
protocol.Range{
Start: protocol.Position{
Line: 0,
Character: protocol.UInteger(0),
},
End: protocol.Position{
Line: 1,
Character: protocol.UInteger(0),
},
},
options,
)
if err != nil {
t.Errorf("Failed to format document: %v", err)
}
_ = edits
}

View File

@ -0,0 +1,22 @@
package lsp
import (
sshdconfig "config-lsp/handlers/sshd_config"
"config-lsp/handlers/sshd_config/handlers"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func TextDocumentRangeFormatting(
context *glsp.Context,
params *protocol.DocumentRangeFormattingParams,
) ([]protocol.TextEdit, error) {
d := sshdconfig.DocumentParserMap[params.TextDocument.URI]
return handlers.FormatDocument(
d,
params.Range,
params.Options,
)
}