1
Fork 0
mirror of https://github.com/RGBCube/nu_scripts synced 2025-07-30 13:47:46 +00:00

Fix parse-fish.nu (#1094)

Adjust so it does not throw syntax errors and works for at least some
sampled `.fish` files.

Related #968, #258, #256

---

Sample `abook`:

```nushell
nu ❯ rm abook.nu -f; build-completion abook.fish abook.nu; open abook.nu
# Show usage
extern "abook" [
        --add-email                                     # Read email message from stdin and add the sender
        --add-email-quiet                                       # Same as --add-email. Without confirmation
        --convert                                       # Convert address book files
        --informat                                      # Input file format
        --outformat                                     # Output file format
        --formats                                       # Print available formats
        ...args
]
```
This commit is contained in:
Jan Klass 2025-04-20 17:03:24 +02:00 committed by GitHub
parent 98973a271f
commit c62a46d6e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -39,16 +39,15 @@ def parse-fish [] {
# 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 | str length) > 0 # remove any empty lines
| where $it starts-with 'complete' # only complete command lines
| each {
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
| get tokens
}
| 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}
@ -80,53 +79,65 @@ def make-commands-completion [] {
| get c # c is the command name
| uniq # is cloned on every complete line
| each { |command|
$fishes | where c == $command | make-subcommands-completion $command
$fishes | where c == $command | make-subcommands-completion [$command]
| str join "\n\n"
}
}
# 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 quote = '"' # "
def make-subcommands-completion [parents: list<string>] {
let quote = '"' # a `"`
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)) and ($subcommand.args.d != "") {
build-string "# " ($subcommand.args.d.0) "\n" # (sub)command description
}) "extern " $quote ($parents | str join " ") (
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") and ($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 join "\n"
) "\n\t...args\n]"
[
# description
(if ('d' in ($subcommand.args | columns)) and ($subcommand.args.d != "") { $"# ($subcommand.args.d.0)\n" })
# extern name
$'extern "($parents | append $subcommand.name | str join " " | str trim)"'
# params
" [\n"
(
$fishes
| if ('n' in ($subcommand | 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") and ($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 join "\n"
)
"\n\t...args"
"\n]"
]
| str join
}
}
# build the list of flag string in nu syntax
# record<c, n, a, d, o> -> list<string>
def build-flags [] {
each { |subargs|
$in
| each { |subargs|
if ('l' in ($subargs | columns)) and ($subargs.l != "") {
build-string "\t--" $subargs.l (build-string
(if ('s' in ($subargs | columns)) and ($subargs.s != "") {
build-string "(-" $subargs.s ")"
}) (if ('d' in ($subargs | columns)) and ($subargs.d != "") {
build-string "\t\t\t\t\t# " $subargs.d
})
)
[
"\t--" $subargs.l
(
[
(if ('s' in ($subargs | columns)) and ($subargs.s != "") { [ "(-" $subargs.s ")" ] | str join })
(if ('d' in ($subargs | columns)) and ($subargs.d != "") { [ "\t\t\t\t\t# " $subargs.d ] | str join })
] | str join
)
] | str join
}
}
}