mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-18 23:15:26 +02:00
104 lines
2.8 KiB
Go
104 lines
2.8 KiB
Go
package handlers
|
|
|
|
import (
|
|
"config-lsp/common"
|
|
sshconfig "config-lsp/handlers/ssh_config"
|
|
"config-lsp/handlers/ssh_config/diagnostics"
|
|
"config-lsp/handlers/ssh_config/fields"
|
|
"fmt"
|
|
|
|
"github.com/hbollon/go-edlib"
|
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
|
)
|
|
|
|
func getKeywordTypoFixes(
|
|
d *sshconfig.SSHDocument,
|
|
params *protocol.CodeActionParams,
|
|
) []protocol.CodeAction {
|
|
if common.ServerOptions.NoTypoSuggestions {
|
|
return nil
|
|
}
|
|
|
|
line := params.Range.Start.Line
|
|
|
|
if typoOption, found := d.Indexes.UnknownOptions[line]; found {
|
|
name := typoOption.Option.Key.Value.Value
|
|
|
|
suggestedOptions := findSimilarOptions(name)
|
|
|
|
actions := make([]protocol.CodeAction, 0, len(suggestedOptions))
|
|
|
|
kind := protocol.CodeActionKindQuickFix
|
|
for index, normalizedOptionName := range suggestedOptions {
|
|
isPreferred := index == 0
|
|
optionName := fields.FieldsNameFormattedMap[normalizedOptionName]
|
|
|
|
actions = append(actions, protocol.CodeAction{
|
|
Title: fmt.Sprintf("Typo Fix: %s", optionName),
|
|
IsPreferred: &isPreferred,
|
|
Kind: &kind,
|
|
Diagnostics: []protocol.Diagnostic{
|
|
diagnostics.GenerateUnknownOption(
|
|
typoOption.Option.Key.ToLSPRange(),
|
|
typoOption.Option.Key.Value.Value,
|
|
),
|
|
},
|
|
Edit: &protocol.WorkspaceEdit{
|
|
Changes: map[protocol.DocumentUri][]protocol.TextEdit{
|
|
params.TextDocument.URI: {
|
|
{
|
|
Range: typoOption.Option.Key.ToLSPRange(),
|
|
NewText: optionName,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
return actions
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Find options that are similar to the given option name.
|
|
// This is used to find typos & suggest the correct option name.
|
|
// Once an option is found that has a Damerau-Levenshtein distance of 1, it is immediately returned.
|
|
// If not, then the next 2 options of similarity 2, or 3 options of similarity 3 are returned.
|
|
// If no options with similarity <= 3 are found, then an empty slice is returned.
|
|
func findSimilarOptions(
|
|
optionName string,
|
|
) []fields.NormalizedOptionName {
|
|
normalizedOptionName := string(fields.CreateNormalizedName(optionName))
|
|
|
|
optionsPerSimilarity := map[uint8][]fields.NormalizedOptionName{
|
|
2: make([]fields.NormalizedOptionName, 0, 2),
|
|
3: make([]fields.NormalizedOptionName, 0, 3),
|
|
}
|
|
|
|
for name := range fields.Options {
|
|
normalizedName := string(name)
|
|
similarity := edlib.DamerauLevenshteinDistance(normalizedName, normalizedOptionName)
|
|
|
|
switch similarity {
|
|
case 1:
|
|
return []fields.NormalizedOptionName{name}
|
|
case 2:
|
|
optionsPerSimilarity[2] = append(optionsPerSimilarity[2], name)
|
|
|
|
if len(optionsPerSimilarity[2]) >= 2 {
|
|
return optionsPerSimilarity[2]
|
|
}
|
|
case 3:
|
|
optionsPerSimilarity[3] = append(optionsPerSimilarity[3], name)
|
|
|
|
if len(optionsPerSimilarity[3]) >= 3 {
|
|
return optionsPerSimilarity[3]
|
|
}
|
|
}
|
|
}
|
|
|
|
return append(optionsPerSimilarity[2], optionsPerSimilarity[3]...)
|
|
}
|