Environment-aware help for open and save (#15651)

# Description

This extends the documentation on the commands `open` and `save` can run
under the hood, and explicitly lists those, based on the current user
environment.

Also see [this discord
thread](https://discord.com/channels/601130461678272522/988303282931912704/1364930487092777020)

# User-Facing Changes

Users will be able to see the list of commands that `open` and `save`
can run, and the extensions that each command is run for, in `help open`
and `help save` respectively:

## `help open`

![image](https://github.com/user-attachments/assets/b245d12c-c6ef-4c6d-a9f1-6c5111cb0684)

## `help save`

![image](https://github.com/user-attachments/assets/e92ddb6b-6a1e-40cc-9139-78db8a921d4a)


# Tests + Formatting

All pass except for the ones that don't (and never did pass for me
before).

# After Submitting

No updates needed.
This commit is contained in:
Bruce Weirdan 2025-05-04 00:07:39 +02:00 committed by GitHub
parent 63e68934f6
commit 39b95fc59e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 90 additions and 0 deletions

View File

@ -281,6 +281,16 @@ impl Command for Open {
example: r#"def "from ndjson" [] { from json -o }; open myfile.ndjson"#,
result: None,
},
Example {
description: "Show the extensions for which the `open` command will automatically parse",
example: r#"scope commands
| where name starts-with "from "
| insert extension { get name | str replace -r "^from " "" | $"*.($in)" }
| select extension name
| rename extension command
"#,
result: None,
}
]
}
}

View File

@ -263,6 +263,17 @@ impl Command for Save {
example: r#"do -i {} | save foo.txt --stderr bar.txt"#,
result: None,
},
Example {
description:
"Show the extensions for which the `save` command will automatically serialize",
example: r#"scope commands
| where name starts-with "to "
| insert extension { get name | str replace -r "^to " "" | $"*.($in)" }
| select extension name
| rename extension command
"#,
result: None,
},
]
}

View File

@ -484,6 +484,62 @@ export def operators [
}
}
def get-extension-by-prefix [prefix: string] {
scope commands
| where name starts-with $prefix
| insert extension { get name | parse $"($prefix){ext}" | get ext.0 | $"*.($in)" }
| select extension name
| rename --column { name: command }
}
def get-command-extensions [command: string] {
# low-tech version of `nu-highlight`, which produces suboptimal results with unknown commands
def hl [shape: string] {
let color = $env.config.color_config | get $"shape_($shape)"
$"(ansi $color)($in)(ansi reset)"
}
let extensions = {
"open": {||
[
(
$"('open' | hl internalcall) will attempt to automatically parse the file according to its extension,"
+ $" by calling ('from ext' | hl internalcall) on the file contents. For example,"
+ $" ('open' | hl internalcall) ('file.json' | hl globpattern) will call"
+ $" ('from json' | hl internalcall). If the file is not a supported type, its content will be returned"
+ $" as a binary stream instead."
)
""
"The following extensions are recognized:"
(get-extension-by-prefix "from " | table --index false)
]
}
"save": {||
[
(
$"('save' | hl internalcall) will attempt to automatically serialize its input into the format"
+ $" determined by the file extension, by calling ('to ext' | hl internalcall) before writing the data"
+ $" to the file. For example, ('save' | hl internalcall) ('file.json' | hl globpattern)"
+ $" will call ('to json' | hl internalcall)."
)
""
"The following extensions are recognized:"
(get-extension-by-prefix "to " | table --index false)
]
}
}
if $command in $extensions {
$extensions
| get $command
| do $in
| each { lines | each { $" ($in)" } | str join "\n" }
} else {
[]
}
}
def build-command-page [command: record] {
let description = (if not ($command.description? | is-empty) {[
$command.description
@ -653,6 +709,18 @@ def build-command-page [command: record] {
] | flatten)
} else { [] })
# This section documents how the command can be extended
# E.g. `open` can be extended by adding more `from ...` commands
let extensions = (
get-command-extensions $command.name
| if ($in | is-not-empty) {
prepend [
""
(build-help-header -n "Extensions")
]
} else {}
)
let examples = (if not ($command.examples | is-empty) {[
""
(build-help-header -n "Examples")
@ -683,6 +751,7 @@ def build-command-page [command: record] {
$cli_usage
$subcommands
$rest
$extensions
$examples
] | flatten | str join "\n"
}