1
Fork 0
mirror of https://github.com/RGBCube/nu_scripts synced 2025-08-01 14:47:47 +00:00

autogenerate from Fish shell completions (#236)

* fish generator

* handle root command case

* documentation for cases

* fix edge cases in parse-fish script

* fix command description missing edge case
This commit is contained in:
Jacob Gonzalez 2022-05-30 23:31:55 +10:00 committed by GitHub
parent f6bd50a221
commit b74da8e5f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 167 additions and 86 deletions

View file

@ -1,8 +1,37 @@
# completions
# auto-generate completions
basic helper to parse --help information from cli commands and export nu completions source
- basic helpers to parse --help information from cli commands and export nu completions source
- basic helpers tp parse .fish complete files and export nu completions source
# current limitations
# parse-fish
## current
- only parses out simple complete's with no complete's boolean arguments like -f
- does not map fish autocomplete helpers to nu-complete helps (a nu library of autocomplete utils would be neat)
## usage
be in a directory with one or more .fish completion scripts
A good one is
`git clone https://github.com/fish-shell/fish-shell`
`cd fish-shell/share/completions`
To build all .fish files in the current directory `build-completions-from-pwd`
```nu
build-completions-from-pwd
ls *.nu
```
To build a single .fish file and choose the output file
```nu
build-completion cargo.fish cargo.nu
```
# parse-help
## current limitations
- Only flags are parsed, arguments are not parsed and ...args is injected at the end to catch all
- Some examples of `--flags` in descriptions can throw off the regex and get included in the parsed flags
@ -10,12 +39,10 @@ basic helper to parse --help information from cli commands and export nu complet
## usage
A basic example in [usage.nu](usage.nu)
generate and print source to tty
generate and save source to a file
```nu
cargo --help | parse-help | make-completion cargo | nu-highlight
cargo --help | parse-help | make-completion cargo | save cargo.nu
```
## example

View file

@ -1,66 +0,0 @@
extern "cargo" [
--version(-V) # Print version info and exit
--list # List installed commands
--explain # Run `rustc --explain CODE`
--verbose(-v) # Use verbose output (-vv very verbose/build.rs output)
--quiet(-q) # Do not print cargo log messages
--color # Coloring: auto, always, never
--frozen # Require Cargo.lock and cache are up to date
--locked # Require Cargo.lock is up to date
--offline # Run without accessing the network
--config # Override a configuration value (unstable)
--help(-h) # Print help information
...args
]
extern "nu" [
--help(-h) # Display this help message
--stdin # redirect the stdin
--login(-l) # start as a login shell
--interactive(-i) # start as an interactive shell
--version(-v) # print the version
--perf(-p) # start and print performance metrics during startup
--testbin # run internal test binary
--commands(-c) # run the given commands and then exit
--config # start with an alternate config file
--env-config # start with an alternate environment config file
--log-level # log level for performance logs
--threads(-t) # threads to use for parallel commands
...args
]
extern "bat" [
--show-all(-A) # Show non-printable characters like space, tab or newline. This option can also be used
--plain(-p) # Only show plain style, no decorations. This is an alias for '--style=plain'. When '-p'
--pager # =never').
--language(-l) # Explicitly set the language for syntax highlighting. The language can be specified as a
--highlight-line(-H) # ...
--file-name # ...
--diff(-d) # Only show lines that have been added/removed/modified with respect to the Git index. Use
--diff-context # =N to control how much context you want to see.
--diff-context # Include N lines of context around added/removed/modified lines when using '--diff'.
--tabs # Set the tab width to T spaces. Use a width of 0 to pass tabs through directly
--wrap # Specify the text-wrapping mode (*auto*, never, character). The '--terminal-width' option
--terminal-width # Explicitly set the width of the terminal instead of determining it automatically. If
--number(-n) # Only show line numbers, no other decorations. This is an alias for '--style=numbers'
--color # Specify when to use colored output. The automatic mode only enables colors if an
--italic-text # Specify when to use ANSI sequences for italic text in the output. Possible values:
--decorations # Specify when to use the decorations that have been specified via '--style'. The
--force-colorization(-f) # Alias for '--decorations=always --color=always'. This is useful if the output of bat is
--paging # Specify when to use the pager. To disable the pager, use --paging=never' or its
--pager # Determine which pager is used. This option will override the PAGER and BAT_PAGER
--map-syntax(-m) # ...
--ignored-suffix # ...
--theme # Set the theme for syntax highlighting. Use '--list-themes' to see all available themes.
--list-themes # Display a list of supported themes for syntax highlighting.
--style # Configure which elements (line numbers, file headers, grid borders, Git modifications,
--line-range(-r) # ...
--list-languages(-L) # Display a list of supported languages for syntax highlighting.
--unbuffered(-u) # This option exists for POSIX-compliance reasons ('u' is for 'unbuffered'). The output is
--diagnostic # Show diagnostic information for bug reports.
--acknowledgements # Show acknowledgements.
--help(-h) # Print this help message.
--version(-V) # Show version information.
...args
]

View file

@ -0,0 +1,133 @@
# a .fish complete file usually looks like a like
# `complete -c command -n '__fish_seen_subcommand_from arg' -a arg -l long -s short -d 'description'
# attempt to loosely pasrse it and convert to nu completions
# parse every .fish file in the current directory and make a .nu completions file of it
def build-completions-from-pwd [] {
ls *.fish | par-each { |f|
let out = ($f.name | str replace ".fish" ".nu")
print $"building nushell completions from ($f.name)"
build-completion $f.name $out
}
}
# build a completion form a .fish file and generate a .nu file
def build-completion [fish-file: path, nu-file: path] {
open $fish-file | parse-fish | make-commands-completion | str collect "\n\n" | save $nu-file
}
# parse a .fish file based on autogenerated complete syntax
# returns a table of flags to arguments
# currently only handles complete's args that don't use boolean flags (e.g. -f)
def parse-fish [] {
let data = (
$in | tokenize-complete-lines
| where (($it | length) mod 2) == 1 # currently we only support complete args that all have args (pairs). including 'complete' this means an odd number of tokens
| each { |tokens| $tokens | pair-args } # turn the tokens into a list of pairs
| flatten # merge them all into a top level label
)
# default every column in the table to "" to make processing easier
# some values having $nothing often breaks nu or requires lots of checking
$data | columns | reduce -f $data { |c, acc|
$acc | default "" $c
}
| default "" a
| cleanup_subcommands # clean garbage subcommands
}
# tokenize each line of the fish file into a list of tokens
# make use of detect columns -n which with one like properly tokenizers arguments including across quotes
def tokenize-complete-lines [] {
lines
| each { |line|
$line
| where $line starts-with complete
| str replace -a "\\\\'" "" # remove escaped quotes ' which break detect columns
| str replace -a "-f " "" # remove -f which is a boolean flag we don't support yet
| detect columns -n
| transpose -i tokens # turn columns into items, each is a token
}
| where ($it | length) > 0 # remove any empty lines
| get tokens # get the list of tokens
}
# turn a list of tokens for a line into a record of {flag: arg}
def pair-args [] {
where $it != complete # drop complete command as we don't need it
| window 2 -s 2 # group by ordered pairs, using window 2 -s 2 instead of group 2 to automatically drop any left overs
| each { |pair|
[
{$"($pair.0 | str trim -c '-')": ($pair.1 | unquote)} # turn into a [{<flag> :<arg>}] removing quotes
]
}
| reduce { |it, acc| $acc | merge { $it }} # merge the list of records into one big record
}
def unquote [] {
str trim -c "\'" # trim '
| str trim -c "\"" # trim "
}
# remove any entries which contain things in subcommands that may be fish functions or incorrect parses
def cleanup_subcommands [] {
where (not ($it.a | str contains "$")) && (not ($it.a | str starts-with "-")) && (not ($it.a starts-with "("))
}
# from a parsed fish table, create the completion for it's command and sub commands
def make-commands-completion [] {
let fishes = $in
$fishes
| get c # c is the command name
| uniq # is cloned on every complete line
| each { |command|
$fishes | where c == $command | make-subcommands-completion $command
}
}
let quote = '"' # "
# make the action nu completion string from subcommand and args
# subcommand can be empty which will be the root command
def make-subcommands-completion [parents: list] {
let fishes = $in
$fishes
| group-by a # group by sub command (a flag)
| transpose name args # turn it into a table of name to arguments
| each {|subcommand|
build-string (
if ('d' in ($subcommand.args | columns)) && ($subcommand.args.d != "") {
build-string "# " ($subcommand.args.d.0) "\n" # (sub)command description
}) "extern " $quote ($parents | str collect " ") (
if $subcommand.name != "" {
build-string " " $subcommand.name # sub command if present
}) $quote " [\n" (
$fishes
| if ('n' in ($in | columns)) {
if ($subcommand.name != "") {
where ($it.n | str contains $subcommand.name) # for subcommand -> any where n matches `__fish_seen_subcommand_from arg` for the subcommand name
} else {
where ($it.n == "__fish_use_subcommand") && ($it.a == "") # for root command -> any where n == __fish_use_subcommand and a is empty. otherwise a means a subcommand
}
} else {
$fishes # catch all
}
| build-flags
| str collect "\n"
) "\n\t...args\n]"
}
}
# build the list of flag string in nu syntax
def build-flags [] {
each { |subargs|
if ('l' in ($subargs | columns)) && ($subargs.l != "") {
build-string "\t--" $subargs.l (build-string
(if ('s' in ($subargs | columns)) && ($subargs.s != "") {
build-string "(-" $subargs.s ")"
}) (if ('d' in ($subargs | columns)) && ($subargs.d != "") {
build-string "\t\t\t\t\t# " $subargs.d
})
)
}
}
}

View file

@ -1,13 +0,0 @@
# something like this in $nu.env-path
rm completions.nu
source parse-help.nu
cargo --help | parse-help | build-string ($in | make-completion cargo) "\n\n" | save --append $"completions.nu"
nu --help | parse-help | build-string ($in | make-completion nu) "\n\n" | save --append $"completions.nu"
bat --help | parse-help | build-string ($in | make-completion bat) "\n\n" | save --append $"completions.nu"
# source this file in $nu.config-path
source completions.nu