rewriting nushell implementation

This commit is contained in:
Jack Wright 2024-11-27 21:05:56 -08:00
parent 29af015b57
commit e7abbf39a3

View file

@ -23,141 +23,94 @@ import (
func (c *Command) GenNushellCompletion(w io.Writer, includeDesc bool) error { func (c *Command) GenNushellCompletion(w io.Writer, includeDesc bool) error {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
name := c.Name()
WriteStringAndCheck(buf, fmt.Sprintf(` WriteStringAndCheck(buf, fmt.Sprintf(`
# A list of cobra apps that completion will be attempted for.
# Add new apps to this list to enable completion for them.
let cobra_apps = ["%[1]s"]
# An external completer that works with any cobra based # An external completer that works with any cobra based
# command line application (e.g. kubectl, minikube) # command line application (e.g. kubectl, minikube)
let cobra_completer = {|spans| let cobra_completer = {|spans|
let cmd = $spans.0 let ShellCompDirectiveError = %[1]d
let ShellCompDirectiveNoSpace = %[2]d
let ShellCompDirectiveNoFileComp = %[3]d
let ShellCompDirectiveFilterFileExt = %[4]d
let ShellCompDirectiveFilterDirs = %[5]d
if not ($cobra_apps | where $cmd =~ $it | is-empty) { let cmd = $spans | first
let ShellCompDirectiveError = %[2]d let rest = $spans | skip
let ShellCompDirectiveNoSpace = %[3]d
let ShellCompDirectiveNoFileComp = %[4]d
let ShellCompDirectiveFilterFileExt = %[5]d
let ShellCompDirectiveFilterDirs = %[6]d
let last_span = ($spans | last | str trim)
def exec_complete [ def exec_complete [
--fuzzy, spans: list<string>
spans: list ] {
] { # This will catch the stderr message related to the directive and any other errors,
let params = { # such as the command not being a cobra based command
last_span: ($spans | last | str trim), let result = do --ignore-errors { cobra_active_help=0 run-external $cmd "__complete" ...$spans | complete }
spans: $spans
}
# If there is an equals in the last span
# parse the span into two
let params = if $last_span =~ '=' {
let split = ($last_span | split row '=')
if ($split | length) > 1 {
{
last_span: ($split | last),
spans: ($spans | drop | append ($split | first) | append ($split | last))
}
} else {
{
last_span: '',
spans: ($spans | drop | append ($split | first) | append '')
}
}
} else {
$params
}
let last_span = $params.last_span if $result != null and $result.exit_code == 0 {
let spans = $params.spans let completions = $result.stdout | lines
# Drop the last param so we can fuzzy search on it # the directive is the last line
let spans = if $fuzzy { let directive = do -i { $completions | last | str replace ':' '' | into int }
$spans | drop
} else {
$spans
}
# skip the first entry in the span (the command) and join the rest of the span to create __complete args let completions = $completions | drop | each { |it|
let cmd_args = ($spans | skip 1 | str join ' ') # the first word is the command, the rest is the description
let words = $it | split row -r '\s{1}'
# If the last span entry was empty add "" to the end of the command args # If the last span contains a hypen and equals, attach it to the name
let cmd_args = if ($last_span | is-empty) or $fuzzy { let last_span = $spans | last
$'($cmd_args) ""' let words = if ($last_span =~ '^-') and ($last_span =~ '=$') {
} else { $words | each {|it| $"($last_span)($it)" }
$cmd_args } else {
} $words
}
# The full command to be executed with active help disable (Nushell does not support active help) {value: ($words | first | str trim), description: ($words | skip | str join ' ')}
let full_cmd = $'COBRA_ACTIVE_HELP=0 ($cmd) __complete ($cmd_args)' }
# Since nushell doesn't have anything like eval, execute in a subshell {completions: $completions, directive: $directive}
let result = (do -i { nu -c $"'($full_cmd)'" } | complete) } else {
{completions: [], directive: -1}
}
}
# Create a record with all completion related info. if (not ($rest | is-empty)) {
# directive and directive_str are for posterity let result = exec_complete $rest
let stdout_lines = ($result.stdout | lines) let completions = $result.completions
let directive = ($stdout_lines | last | str trim | str replace ":" "" | into int) let directive = $result.directive
let completions = ($stdout_lines | drop | parse -r '([\w\-\.:\+\=\/]*)\t?(.*)' | rename value description)
let completions = if $fuzzy {
$completions | where $it.value =~ $last_span
} else { # Add space at the end of each completion
($completions | where {|it| $it.value | str starts-with $last_span }) let completions = if $directive != $ShellCompDirectiveNoSpace {
} $completions | each {|it| {value: $"($it.value) ", description: $it.description}}
} else {
$completions
}
{ # Cobra returns a list of completions that are supported with this directive
directive: $directive, # There is no way to currently support this in a nushell external completer
completions: $completions let completions = if $directive == $ShellCompDirectiveFilterFileExt {
} []
} } else {
$completions
}
let result = (exec_complete $spans) if $directive == $ShellCompDirectiveNoFileComp {
let result = if (not ($last_span | is-empty)) and ($result.completions | is-empty) { # Allow empty results as this will stop file completion
exec_complete --fuzzy $spans $completions
} else { } else if ($completions | is-empty) or $directive == $ShellCompDirectiveError {
$result # Not returning null causes file completions to break
} # Return null if there are no completions or ShellCompDirectiveError
null
let directive = $result.directive } else {
let completions = $result.completions $completions
}
# Add space at the end of each completion
let completions = if $directive != $ShellCompDirectiveNoSpace { if ($completions | is-empty) {
$completions | each {|it| {value: $"($it.value) ", description: $it.description}} null
} else { } else {
$completions $completions
} }
} else {
# Cobra returns a list of completions that are supported with this directive null
# There is no way to currently support this in a nushell external completer }
let completions = if $directive == $ShellCompDirectiveFilterFileExt {
[]
} else {
$completions
}
let return_val = if $last_span =~ '=' {
# if the completion is of the form -n= return flag as part of the completion so that it doesn't get replaced
$completions | each {|it| $"($last_span | split row '=' | first)=($it.value)" }
} else if $directive == $ShellCompDirectiveNoFileComp {
# Allow empty results as this will stop file completion
$completions
} else if ($completions | is-empty) or $directive == $ShellCompDirectiveError {
# Not returning null causes file completions to break
# Return null if there are no completions or ShellCompDirectiveError
null
} else {
$completions
}
$return_val
} else {
null
}
} }
`, name, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, `, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
_, err := buf.WriteTo(w) _, err := buf.WriteTo(w)