feat(aliases): Add support for renaming

This commit is contained in:
Myzel394 2024-09-07 18:02:34 +02:00
parent 654675524c
commit d56eef43bf
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
8 changed files with 247 additions and 4 deletions

View File

@ -23,7 +23,7 @@ func GetDefinitionLocationForValue(
return []protocol.Location{
{
URI: params.TextDocument.URI,
Range: entry.Location.ToLSPRange(),
Range: entry.Key.Location.ToLSPRange(),
},
}
}

View File

@ -0,0 +1,33 @@
package handlers
import (
"config-lsp/handlers/aliases/ast"
"config-lsp/handlers/aliases/indexes"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func RenameAlias(
i indexes.AliasesIndexes,
oldEntry *ast.AliasEntry,
newName string,
) []protocol.TextEdit {
occurrences := i.UserOccurrences[indexes.NormalizeKey(oldEntry.Key.Value)]
changes := make([]protocol.TextEdit, 0, len(occurrences))
// Own rename
changes = append(changes, protocol.TextEdit{
Range: oldEntry.Key.Location.ToLSPRange(),
NewText: newName,
})
// Other AliasValueUser occurrences
for _, value := range occurrences {
changes = append(changes, protocol.TextEdit{
Range: value.Location.ToLSPRange(),
NewText: newName,
})
}
return changes
}

View File

@ -0,0 +1,48 @@
package handlers
import (
"config-lsp/handlers/aliases/ast"
"config-lsp/handlers/aliases/indexes"
"config-lsp/utils"
"testing"
)
func TestComplexExample(
t *testing.T,
) {
input := utils.Dedent(`
alice: alice
bob: root
support: alice, bob
`)
parser := ast.NewAliasesParser()
errors := parser.Parse(input)
if len(errors) > 0 {
t.Fatalf("Unexpected errors: %v", errors)
}
i, errors := indexes.CreateIndexes(parser)
if len(errors) > 0 {
t.Fatalf("Expected no errors, but got: %v", errors)
}
edits := RenameAlias(i, i.Keys["alice"], "amelie")
if !(len(edits) == 3) {
t.Errorf("Expected 2 edits, but got %v", len(edits))
}
if !(edits[0].Range.Start.Line == 0 && edits[0].Range.Start.Character == 0 && edits[0].Range.End.Line == 0 && edits[0].Range.End.Character == 5) {
t.Errorf("Unexpected edit: %v", edits[0])
}
if !(edits[1].Range.Start.Line == 0 && edits[1].Range.Start.Character == 7 && edits[1].Range.End.Line == 0 && edits[1].Range.End.Character == 12) {
t.Errorf("Unexpected edit: %v", edits[1])
}
if !(edits[2].Range.Start.Line == 2 && edits[2].Range.Start.Character == 9 && edits[2].Range.End.Line == 2 && edits[2].Range.End.Character == 14) {
t.Errorf("Unexpected edit: %v", edits[2])
}
}

View File

@ -8,7 +8,8 @@ import (
)
type AliasesIndexes struct {
Keys map[string]*ast.AliasKey
Keys map[string]*ast.AliasEntry
UserOccurrences map[string][]*ast.AliasValueUser
}
func NormalizeKey(key string) string {
@ -18,7 +19,8 @@ func NormalizeKey(key string) string {
func CreateIndexes(parser ast.AliasesParser) (AliasesIndexes, []common.LSPError) {
errors := make([]common.LSPError, 0)
indexes := &AliasesIndexes{
Keys: make(map[string]*ast.AliasKey),
Keys: make(map[string]*ast.AliasEntry),
UserOccurrences: make(map[string][]*ast.AliasValueUser),
}
it := parser.Aliases.Iterator()
@ -26,6 +28,20 @@ func CreateIndexes(parser ast.AliasesParser) (AliasesIndexes, []common.LSPError)
for it.Next() {
entry := it.Value().(*ast.AliasEntry)
if entry.Values != nil {
for _, value := range entry.Values.Values {
switch value.(type) {
case ast.AliasValueUser:
userValue := value.(ast.AliasValueUser)
indexes.UserOccurrences[userValue.Value] = append(
indexes.UserOccurrences[userValue.Value],
&userValue,
)
}
}
}
if entry.Key == nil || entry.Key.Value == "" {
continue
}
@ -44,7 +60,7 @@ func CreateIndexes(parser ast.AliasesParser) (AliasesIndexes, []common.LSPError)
continue
}
indexes.Keys[normalizedAlias] = entry.Key
indexes.Keys[normalizedAlias] = entry
}
return *indexes, errors

View File

@ -0,0 +1,49 @@
package indexes
import (
"config-lsp/handlers/aliases/ast"
"config-lsp/utils"
"testing"
)
func TestComplexExample(
t *testing.T,
) {
input := utils.Dedent(`
postmaster: alice, bob
alice: root
bob: root
`)
parser := ast.NewAliasesParser()
errors := parser.Parse(input)
if len(errors) > 0 {
t.Fatalf("Unexpected errors: %v", errors)
}
indexes, errors := CreateIndexes(parser)
if len(errors) > 0 {
t.Fatalf("Expected no errors, but got: %v", errors)
}
if !(len(indexes.Keys) == 3) {
t.Errorf("Expected 3 keys, but got %v", len(indexes.Keys))
}
if !(len(indexes.UserOccurrences) == 3) {
t.Errorf("Expected 3 user occurrences, but got %v", len(indexes.UserOccurrences))
}
if !(len(indexes.UserOccurrences["root"]) == 2) {
t.Errorf("Expected 2 occurrences of root, but got %v", len(indexes.UserOccurrences["root"]))
}
if !(len(indexes.UserOccurrences["alice"]) == 1) {
t.Errorf("Expected 1 occurrence of alice, but got %v", len(indexes.UserOccurrences["alice"]))
}
if !(len(indexes.UserOccurrences["bob"]) == 1) {
t.Errorf("Expected 1 occurrence of bob, but got %v", len(indexes.UserOccurrences["bob"]))
}
}

View File

@ -0,0 +1,60 @@
package lsp
import (
"config-lsp/handlers/aliases"
"config-lsp/handlers/aliases/ast"
"config-lsp/handlers/aliases/handlers"
"config-lsp/handlers/aliases/indexes"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func TextDocumentRename(context *glsp.Context, params *protocol.RenameParams) (*protocol.WorkspaceEdit, error) {
d := aliases.DocumentParserMap[params.TextDocument.URI]
character := params.Position.Character
line := params.Position.Line
rawEntry, found := d.Parser.Aliases.Get(line)
if !found {
return nil, nil
}
entry := rawEntry.(*ast.AliasEntry)
if character >= entry.Key.Location.Start.Character && character <= entry.Key.Location.End.Character {
changes := handlers.RenameAlias(*d.Indexes, entry, params.NewName)
return &protocol.WorkspaceEdit{
Changes: map[protocol.DocumentUri][]protocol.TextEdit{
params.TextDocument.URI: changes,
},
}, nil
}
if entry.Values != nil && character >= entry.Values.Location.Start.Character && character <= entry.Values.Location.End.Character {
rawValue := handlers.GetValueAtCursor(character, entry)
if rawValue == nil {
return nil, nil
}
switch (*rawValue).(type) {
case ast.AliasValueUser:
userValue := (*rawValue).(ast.AliasValueUser)
definitionEntry := d.Indexes.Keys[indexes.NormalizeKey(userValue.Value)]
changes := handlers.RenameAlias(*d.Indexes, definitionEntry, params.NewName)
return &protocol.WorkspaceEdit{
Changes: map[protocol.DocumentUri][]protocol.TextEdit{
params.TextDocument.URI: changes,
},
}, nil
}
}
return nil, nil
}

View File

@ -29,6 +29,7 @@ func SetUpRootHandler() {
TextDocumentCodeAction: TextDocumentCodeAction,
TextDocumentDefinition: TextDocumentDefinition,
WorkspaceExecuteCommand: WorkspaceExecuteCommand,
TextDocumentRename: TextDocumentRename,
}
server := server.NewServer(&lspHandler, lsName, false)

View File

@ -0,0 +1,36 @@
package roothandler
import (
aliases "config-lsp/handlers/aliases/lsp"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func TextDocumentRename(context *glsp.Context, params *protocol.RenameParams) (*protocol.WorkspaceEdit, error) {
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
if language == nil {
showParseError(
context,
params.TextDocument.URI,
undetectableError,
)
return nil, undetectableError.Err
}
switch *language {
case LanguageHosts:
return nil, nil
case LanguageSSHDConfig:
return nil, nil
case LanguageFstab:
return nil, nil
case LanguageWireguard:
return nil, nil
case LanguageAliases:
return aliases.TextDocumentRename(context, params)
}
panic("root-handler/TextDocumentRename: unexpected language" + *language)
}