mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-18 23:15:26 +02:00
feat(ssh_config): Add completions support for tokens
This commit is contained in:
parent
3caaf6aec4
commit
b4aaa2cc3a
@ -28,7 +28,7 @@ func analyzeTokens(
|
|||||||
tokens = []string{}
|
tokens = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
disallowedTokens := utils.Without(fields.AvailableTokens, tokens)
|
disallowedTokens := utils.Without(utils.KeysOfMap(fields.AvailableTokens), tokens)
|
||||||
|
|
||||||
for _, token := range disallowedTokens {
|
for _, token := range disallowedTokens {
|
||||||
if strings.Contains(text, token) {
|
if strings.Contains(text, token) {
|
||||||
|
@ -1,25 +1,27 @@
|
|||||||
package fields
|
package fields
|
||||||
|
|
||||||
var AvailableTokens = []string{
|
import "config-lsp/utils"
|
||||||
"%%",
|
|
||||||
"%C",
|
var AvailableTokens = map[string]string{
|
||||||
"%d",
|
"%%": "A literal ‘%’.",
|
||||||
"%f",
|
"%C": "Hash of %l%h%p%r%j.",
|
||||||
"%H",
|
"%d": "Local user's home directory.",
|
||||||
"%h",
|
"%f": "The fingerprint of the server's host key.",
|
||||||
"%l",
|
"%H": "The known_hosts hostname or address that is being searched for.",
|
||||||
"%i",
|
"%h": "The remote hostname.",
|
||||||
"%j",
|
"%I": "A string describing the reason for a KnownHostsCommand execution: either ADDRESS when looking up a host by address (only when CheckHostIP is enabled), HOSTNAME when searching by hostname, or ORDER when preparing the host key algorithm preference list to use for the destination host.",
|
||||||
"%K",
|
"%i": "The local user ID.",
|
||||||
"%k",
|
"%j": "The contents of the ProxyJump option, or the empty string if this option is unset.",
|
||||||
"%L",
|
"%K": "The base64 encoded host key.",
|
||||||
"%l",
|
"%k": "The host key alias if specified, otherwise the original remote hostname given on the command line.",
|
||||||
"%n",
|
"%L": "The local hostname.",
|
||||||
"%p",
|
"%l": "The local hostname, including the domain name.",
|
||||||
"%r",
|
"%n": "The original remote hostname, as given on the command line.",
|
||||||
"%T",
|
"%p": "The remote port.",
|
||||||
"%t",
|
"%r": "The remote username.",
|
||||||
"%u",
|
"%T": "The local tun(4) or tap(4) network interface assigned if tunnel forwarding was requested, or \"NONE\" otherwise.",
|
||||||
|
"%t": "The type of the server host key, e.g. ssh-ed25519.",
|
||||||
|
"%u": "The local username.",
|
||||||
}
|
}
|
||||||
|
|
||||||
// A map of <option name> to <list of supported tokens>
|
// A map of <option name> to <list of supported tokens>
|
||||||
@ -47,7 +49,7 @@ var OptionsTokensMap = map[NormalizedOptionName][]string{
|
|||||||
"%h",
|
"%h",
|
||||||
},
|
},
|
||||||
|
|
||||||
"localcommand": AvailableTokens,
|
"localcommand": utils.KeysOfMap(AvailableTokens),
|
||||||
|
|
||||||
"proxycommand": {
|
"proxycommand": {
|
||||||
"%%", "%h", "%n", "%p", "%r",
|
"%%", "%h", "%n", "%p", "%r",
|
||||||
|
@ -15,7 +15,7 @@ func GetRootCompletions(
|
|||||||
d *sshconfig.SSHDocument,
|
d *sshconfig.SSHDocument,
|
||||||
parentBlock ast.SSHBlock,
|
parentBlock ast.SSHBlock,
|
||||||
suggestValue bool,
|
suggestValue bool,
|
||||||
) ([]protocol.CompletionItem, error) {
|
) []protocol.CompletionItem {
|
||||||
kind := protocol.CompletionItemKindField
|
kind := protocol.CompletionItemKindField
|
||||||
|
|
||||||
availableOptions := make(map[fields.NormalizedOptionName]docvalues.DocumentationValue, 0)
|
availableOptions := make(map[fields.NormalizedOptionName]docvalues.DocumentationValue, 0)
|
||||||
@ -58,7 +58,7 @@ func GetRootCompletions(
|
|||||||
|
|
||||||
return *completion
|
return *completion
|
||||||
},
|
},
|
||||||
), nil
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetOptionCompletions(
|
func GetOptionCompletions(
|
||||||
@ -67,11 +67,11 @@ func GetOptionCompletions(
|
|||||||
block ast.SSHBlock,
|
block ast.SSHBlock,
|
||||||
line uint32,
|
line uint32,
|
||||||
cursor common.CursorPosition,
|
cursor common.CursorPosition,
|
||||||
) ([]protocol.CompletionItem, error) {
|
) []protocol.CompletionItem {
|
||||||
option, found := fields.Options[entry.Key.Key]
|
option, found := fields.Options[entry.Key.Key]
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
return nil, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if entry.Key.Key == matchOption {
|
if entry.Key.Key == matchOption {
|
||||||
@ -92,18 +92,48 @@ func GetOptionCompletions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if entry.OptionValue == nil {
|
if entry.OptionValue == nil {
|
||||||
return option.DeprecatedFetchCompletions("", 0), nil
|
return option.DeprecatedFetchCompletions("", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// token completions
|
||||||
|
completions := getTokenCompletions(entry, cursor)
|
||||||
|
|
||||||
// Hello wo|rld
|
// Hello wo|rld
|
||||||
lineValue := entry.OptionValue.Value.Raw
|
lineValue := entry.OptionValue.Value.Raw
|
||||||
// NEW: docvalues index
|
// NEW: docvalues index
|
||||||
return option.DeprecatedFetchCompletions(
|
completions = append(completions, option.DeprecatedFetchCompletions(
|
||||||
lineValue,
|
lineValue,
|
||||||
common.DeprecatedImprovedCursorToIndex(
|
common.DeprecatedImprovedCursorToIndex(
|
||||||
cursor,
|
cursor,
|
||||||
lineValue,
|
lineValue,
|
||||||
entry.OptionValue.Start.Character,
|
entry.OptionValue.Start.Character,
|
||||||
),
|
),
|
||||||
), nil
|
)...)
|
||||||
|
|
||||||
|
return completions
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTokenCompletions(
|
||||||
|
entry *ast.SSHOption,
|
||||||
|
cursor common.CursorPosition,
|
||||||
|
) []protocol.CompletionItem {
|
||||||
|
completions := make([]protocol.CompletionItem, 0)
|
||||||
|
index := common.CursorToCharacterIndex(uint32(cursor))
|
||||||
|
|
||||||
|
if entry.Value.Raw[index] == '%' {
|
||||||
|
if tokens, found := fields.OptionsTokensMap[entry.Key.Key]; found {
|
||||||
|
for _, token := range tokens {
|
||||||
|
description := fields.AvailableTokens[token]
|
||||||
|
kind := protocol.CompletionItemKindConstant
|
||||||
|
|
||||||
|
completions = append(completions, protocol.CompletionItem{
|
||||||
|
Label: token,
|
||||||
|
Kind: &kind,
|
||||||
|
Documentation: description,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return completions
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,12 @@ func getMatchCompletions(
|
|||||||
d *sshconfig.SSHDocument,
|
d *sshconfig.SSHDocument,
|
||||||
cursor common.CursorPosition,
|
cursor common.CursorPosition,
|
||||||
match *matchparser.Match,
|
match *matchparser.Match,
|
||||||
) ([]protocol.CompletionItem, error) {
|
) []protocol.CompletionItem {
|
||||||
if match == nil || len(match.Entries) == 0 {
|
if match == nil || len(match.Entries) == 0 {
|
||||||
completions := getMatchCriteriaCompletions()
|
completions := getMatchCriteriaCompletions()
|
||||||
completions = append(completions, getMatchAllKeywordCompletion())
|
completions = append(completions, getMatchAllKeywordCompletion())
|
||||||
|
|
||||||
return completions, nil
|
return completions
|
||||||
}
|
}
|
||||||
|
|
||||||
entry := match.GetEntryAtPosition(cursor)
|
entry := match.GetEntryAtPosition(cursor)
|
||||||
@ -39,10 +39,10 @@ func getMatchCompletions(
|
|||||||
completions = append(completions, getMatchAllKeywordCompletion())
|
completions = append(completions, getMatchAllKeywordCompletion())
|
||||||
}
|
}
|
||||||
|
|
||||||
return completions, nil
|
return completions
|
||||||
}
|
}
|
||||||
|
|
||||||
return getMatchValueCompletions(entry, cursor), nil
|
return getMatchValueCompletions(entry, cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMatchCriteriaCompletions() []protocol.CompletionItem {
|
func getMatchCriteriaCompletions() []protocol.CompletionItem {
|
||||||
|
@ -15,7 +15,7 @@ func getTagCompletions(
|
|||||||
line uint32,
|
line uint32,
|
||||||
cursor common.CursorPosition,
|
cursor common.CursorPosition,
|
||||||
entry *ast.SSHOption,
|
entry *ast.SSHOption,
|
||||||
) ([]protocol.CompletionItem, error) {
|
) []protocol.CompletionItem {
|
||||||
completions := make([]protocol.CompletionItem, 0)
|
completions := make([]protocol.CompletionItem, 0)
|
||||||
|
|
||||||
for name, info := range d.Indexes.Tags {
|
for name, info := range d.Indexes.Tags {
|
||||||
@ -35,7 +35,7 @@ func getTagCompletions(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return completions, nil
|
return completions
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderMatchBlock(
|
func renderMatchBlock(
|
||||||
|
@ -34,7 +34,7 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
|
|||||||
block,
|
block,
|
||||||
// Empty line, or currently typing a new key
|
// Empty line, or currently typing a new key
|
||||||
option == nil || isEmptyPattern.Match([]byte(option.Value.Raw[cursor:])),
|
option == nil || isEmptyPattern.Match([]byte(option.Value.Raw[cursor:])),
|
||||||
)
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if option.Separator != nil && option.OptionValue.IsPositionAfterStart(cursor) {
|
if option.Separator != nil && option.OptionValue.IsPositionAfterStart(cursor) {
|
||||||
@ -44,7 +44,7 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
|
|||||||
block,
|
block,
|
||||||
line,
|
line,
|
||||||
cursor,
|
cursor,
|
||||||
)
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
Loading…
x
Reference in New Issue
Block a user