From 4cdc916d51f6fbc5d7171b4927b9ffd8de8d207a Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Mon, 14 Oct 2024 12:16:55 +0200 Subject: [PATCH] feat(ssh_config): Do not handle includes if they contain tokens or environmental variables --- .../handlers/ssh_config/analyzer/include.go | 53 +++++++++++++++++++ .../ssh_config/handlers/definition.go | 43 +++++++++++++++ .../lsp/text-document-definition.go | 11 +++- 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 server/handlers/ssh_config/handlers/definition.go diff --git a/server/handlers/ssh_config/analyzer/include.go b/server/handlers/ssh_config/analyzer/include.go index 48c70f7..f833b98 100644 --- a/server/handlers/ssh_config/analyzer/include.go +++ b/server/handlers/ssh_config/analyzer/include.go @@ -12,17 +12,44 @@ import ( "path" "path/filepath" "regexp" + "strings" protocol "github.com/tliron/glsp/protocol_3_16" ) var whitespacePattern = regexp.MustCompile(`\S+`) +var environmtalVariablePattern = regexp.MustCompile(`\${.+?}`) +var availableTokens = []string{ + "%%", + "%C", + "%d", + "%f", + "%H", + "%h", + "%l", + "%i", + "%j", + "%K", + "%k", + "%L", + "%l", + "%n", + "%p", + "%r", + "%T", + "%t", + "%u", +} func analyzeIncludeValues( ctx *analyzerContext, ) { for _, include := range ctx.document.Indexes.Includes { for _, value := range include.Values { + if isImpossibleToVerify(value.Value) { + continue + } + validPaths, err := createIncludePaths(value.Value) if err != nil { @@ -38,6 +65,24 @@ func analyzeIncludeValues( } } +// We can't evaluate environmental variables or tokens as we don't know the actual +// values +func isImpossibleToVerify( + path string, +) bool { + if environmtalVariablePattern.MatchString(path) { + return true + } + + for _, token := range availableTokens { + if strings.Contains(path, token) { + return true + } + } + + return false +} + func createIncludePaths( suggestedPath string, ) ([]indexes.ValidPath, error) { @@ -45,6 +90,14 @@ func createIncludePaths( if path.IsAbs(suggestedPath) { absolutePath = suggestedPath + } else if strings.HasPrefix(suggestedPath, "~") { + homeFolder, err := os.UserHomeDir() + + if err != nil { + return nil, errors.New(fmt.Sprintf("Could not find home folder (error: %s)", err)) + } + + absolutePath = path.Join(homeFolder, suggestedPath[1:]) } else { homeFolder, err := os.UserHomeDir() diff --git a/server/handlers/ssh_config/handlers/definition.go b/server/handlers/ssh_config/handlers/definition.go new file mode 100644 index 0000000..ab19112 --- /dev/null +++ b/server/handlers/ssh_config/handlers/definition.go @@ -0,0 +1,43 @@ +package handlers + +import ( + "config-lsp/common" + "config-lsp/handlers/ssh_config/indexes" + "config-lsp/utils" + "slices" + + protocol "github.com/tliron/glsp/protocol_3_16" +) + +func GetIncludeOptionLocation( + include *indexes.SSHIndexIncludeLine, + index common.IndexPosition, +) []protocol.Location { + foundIndex, found := slices.BinarySearchFunc( + include.Values, + index, + func(current *indexes.SSHIndexIncludeValue, target common.IndexPosition) int { + if current.IsPositionAfterEnd(target) { + return -1 + } + + if current.IsPositionBeforeStart(target) { + return 1 + } + + return 0 + }, + ) + + if !found { + return nil + } + + path := include.Values[foundIndex] + + return utils.Map(path.Paths, func(path indexes.ValidPath) protocol.Location { + return protocol.Location{ + URI: path.AsURI(), + } + }) +} diff --git a/server/handlers/ssh_config/lsp/text-document-definition.go b/server/handlers/ssh_config/lsp/text-document-definition.go index a0d3288..83ace57 100644 --- a/server/handlers/ssh_config/lsp/text-document-definition.go +++ b/server/handlers/ssh_config/lsp/text-document-definition.go @@ -1,8 +1,10 @@ package lsp import ( + "config-lsp/common" sshconfig "config-lsp/handlers/ssh_config" "config-lsp/handlers/ssh_config/fields" + "config-lsp/handlers/ssh_config/handlers" "github.com/tliron/glsp" protocol "github.com/tliron/glsp/protocol_3_16" @@ -12,9 +14,16 @@ var tagOption = fields.CreateNormalizedName("Tag") func TextDocumentDefinition(context *glsp.Context, params *protocol.DefinitionParams) ([]protocol.Location, error) { line := params.Position.Line - + index := common.LSPCharacterAsIndexPosition(params.Position.Character) d := sshconfig.DocumentParserMap[params.TextDocument.URI] + if include, found := d.Indexes.Includes[line]; found { + return handlers.GetIncludeOptionLocation( + include, + index, + ), nil + } + option, _ := d.Config.FindOption(line) if option != nil && option.Key.Key == tagOption && option.OptionValue != nil {