fix: Updated nushell version.

This commit is contained in:
2025-12-29 13:40:39 -05:00
parent 66c36e6a42
commit c0878b0295
16 changed files with 145 additions and 85 deletions

View File

@@ -1,4 +1,4 @@
SHELL:=/nix/store/zicq9x6aznw7x202564p8iy0rm04py6l-nushell-0.89.0/bin/nu
SHELL:=/nix/store/kx4ic1nmgsfh3qhr74vxq7g97pal7mn4-nushell-0.108.0/bin/nu
all: README.md

137
README.md
View File

@@ -18,7 +18,7 @@ Utility commands for working with ffmpeg in nushell.
The `ffmpeg` and `ffprobe` commands are required to be installed and available
in your path; they are not installed for you.
Currently only nushell version 0.89.0 is supported.
Currently only nushell version 0.108.0 is supported.
After that, clone this repository and add the following code to your scripts,
or to your `config.nu` file:
@@ -32,8 +32,9 @@ use <path-to-repository>/filters *
### Commands
| name | usage |
| name | description |
| --------------------- | ---------------------------------------------------------------- |
| ffprobe banner | Print a banner for Nushell with information about the project |
| ffprobe | Run ffprobe on a list of files and return the output as a table. |
| ffprobe dimensions | Get the dimensions of a video stream |
| ffprobe streams | Retrieve all the streams from a list of ffprobe outputs |
@@ -45,16 +46,17 @@ use <path-to-repository>/filters *
### Supported Filters
| name | usage |
| name | description |
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| banner | Print a banner for Nushell with information about the project |
| crop | Crop the input video to given dimensions. |
| format | Convert the input video to one of the specified pixel formats. Libavfilter will try to pick one that is suitable as input to the next filter. |
| fps | Convert the video to specified constant frame rate by duplicating or dropping frames as necessary. |
| loop | loop video frames |
| overlay | Overlay one video on top of another. |
| settb | Set the timebase to use for the output frames timestamps. It is mainly useful for testing timebase configuration. |
| split | |
| vflip | Flip the input video vertically. |
| vloop | loop video frames Same as the `loop` filter in ffmpeg, but had to be renamed due to collisions with the [nushell builtin](https://www.nushell.sh/commands/docs/loop.html) |
| xfade | Apply cross fade from one input video stream to another input video stream. The cross fade is applied for specified duration. Both inputs must be constant frame-rate and have the same resolution, pixel format, frame rate and timebase. |
@@ -63,54 +65,109 @@ use <path-to-repository>/filters *
```nu
# Return a table from ffprobe
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4
╭───┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────╮
# │ streams │ format
├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────┤
0 ╭───┬────────────┬───────────────────────────────────────────┬─────────┬────────────┬──────────────────┬────────────┬───────┬────────┬─────────────┬──────────────┬─────────────────┬────────────┬──────────────┬─────╮ {record 11
# │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_tag │ width │ height │ coded_width │ coded_height │ closed_captions │ film_grain │ has_b_frames │ ... │ │ fields} │
├───┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼──────────────────┼────────────┼───────┼────────┼─────────────┼──────────────┼─────────────────┼────────────┼──────────────┼─────┤
0 h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 Main video avc1 0x31637661 1280 720 1280 720 0 0 0 ...
1 aac AAC (Advanced Audio Coding) LC audio mp4a 0x6134706d ...
╰───┴────────────┴───────────────────────────────────────────┴─────────┴──────────────────────────────────────────────────────────────────────┴──────────────┴─────────────────┴────────────┴──────────────┴─────╯
╰───┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────╯
╭───┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
# │ streams │ f
o
r
m
a
t
├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───┤
0 ╭───┬────────────┬───────────────────────────────────────────┬───────────────────────────────────────── {
# │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_str │ ... │ │ r │
ing e
├───┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼───────────────┼─────┤ c
0 h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 Main video avc1 ... o
1 aac AAC (Advanced Audio Coding) LC audio mp4a ... r
╰───┴────────────┴───────────────────────────────────────────┴─────────┴────────────┴───────────────┴─────╯ d
1
2
f
i
e
l
d
s
}
╰───┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───╯
```
```nu
# Use ffprobe on mutliple files at once
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 https://sample-videos.com/video321/mkv/720/big_buck_bunny_720p_1mb.mkv
╭───┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────╮
# │ streams │ format
├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────┤
0 ╭───┬────────────┬───────────────────────────────────────────┬─────────┬────────────┬──────────────────┬────────────┬───────┬────────┬─────────────┬──────────────┬─────────────────┬────────────┬──────────────┬─────╮ {record 11
# │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_tag │ width │ height │ coded_width │ coded_height │ closed_captions │ film_grain │ has_b_frames │ ... │ │ fields} │
├───┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼──────────────────┼────────────┼───────┼────────┼─────────────┼──────────────┼─────────────────┼────────────┼──────────────┼─────┤
0 h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 Main video avc1 0x31637661 1280 720 1280 720 0 0 0 ...
1 aac AAC (Advanced Audio Coding) LC audio mp4a 0x6134706d ...
╰───┴────────────┴───────────────────────────────────────────┴─────────┴──────────────────────────────────────────────────────────────────────┴──────────────┴─────────────────┴────────────┴──────────────┴─────╯
1 ╭───┬────────────┬─────────────────────────────┬────────────────┬────────────┬──────────────────┬───────────┬───────┬────────┬─────────────┬──────────────┬─────────────────┬────────────┬──────────────┬─────╮ {record 10
# │ codec_name │ codec_long_name profile │ codec_type │ codec_tag_string │ codec_tag │ width │ height │ coded_width │ coded_height │ closed_captions │ film_grain │ has_b_frames │ ... │ │ fields} │
├───┼────────────┼─────────────────────────────┼────────────────┼────────────┼──────────────────┼───────────┼───────┼────────┼─────────────┼──────────────┼─────────────────┼────────────┼──────────────┼─────┤
0 mpeg4 MPEG-4 part 2 Simple Profile video [0][0][0][0] 0x0000 1280 720 1280 720 0 0 0 ...
1 aac AAC (Advanced Audio Coding) LC audio [0][0][0][0] 0x0000 ...
╰───┴────────────┴─────────────────────────────────────────────┴────────────┴──────────────────┴───────────┴───────┴────────┴─────────────┴──────────────┴─────────────────┴────────────┴──────────────┴─────╯
╰───┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────╯
╭───┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
# │ streams │ f
o
r
m
a
t
├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───┤
0 ╭───┬────────────┬───────────────────────────────────────────┬───────────────────────────────────────── {
# │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_str │ ... │ │ r │
ing e
├───┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼───────────────┼─────┤ c
0 h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 Main video avc1 ... o
1 aac AAC (Advanced Audio Coding) LC audio mp4a ... r
╰───┴────────────┴────────────────────────────────────────────────────┴────────────┴───────────────┴─────╯ d
1
2
f
i
e
l
d
s
}
1 ╭───┬────────────┬─────────────────────────────┬────────────────┬────────────┬──────────────────┬───┬─────╮ {
# │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ c │ ... │ │ r │
o e
d c
e o
c r
_ d
t
a 1
g 1
├───┼────────────┼─────────────────────────────┼────────────────┼────────────┼──────────────────┼───┼─────┤
0 mpeg4 MPEG-4 part 2 Simple Profile video [0][0][0][0] 0 ... f
x i
0 e
0 l
0 d
0 s
1 aac AAC (Advanced Audio Coding) LC audio [0][0][0][0] 0 ... }
x
0
0
0
0
╰───┴────────────┴─────────────────────────────┴────────────────┴────────────┴──────────────────┴───┴─────╯
╰───┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───╯
```
```nu
# Extract the video streams from a video
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams video
╭───┬────────────┬───────────────────────────────────────────┬─────────┬────────────┬──────────────────┬────────────┬───────┬────────┬─────────────┬──────────────┬─────────────────┬────────────┬──────────────┬─────────────────────┬─────╮
# │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_tag │ width │ height │ coded_width │ coded_height │ closed_captions │ film_grain │ has_b_frames │ sample_aspect_ratio │ ... │
├────┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼──────────────────┼────────────┼───────┼────────┼─────────────┼──────────────┼─────────────────┼────────────┼──────────────┼─────────────────────┼─────┤
0 h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 Main video avc1 0x31637661 1280 720 1280 720 0 0 0 1:1 ...
╰────┴────────────┴───────────────────────────────────────────┴─────────┴────────────┴──────────────────┴────────────┴───────┴────────┴─────────────┴──────────────┴─────────────────┴────────────┴──────────────┴─────────────────────┴─────╯
╭───┬────────────┬───────────────────────────────────────────┬─────────┬────────────┬──────────────────┬────────┬─────╮
# │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_ │ ... │
tag
├───┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼──────────────────┼────────┼─────┤
0 h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 Main video avc1 0x3163 ...
7661
╰───┴────────────┴───────────────────────────────────────────┴─────────┴────────────┴──────────────────┴────────┴─────╯
# Extract the audio streams from a video
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams audio
╭───┬────────────┬─────────────────────────────┬─────────┬────────────┬──────────────────┬────────────┬────────────┬─────────────┬──────────┬────────────────┬─────────────────┬─────────────────┬─────┬──────────────┬────────────────┬─────╮
# │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_tag │ sample_fmt │ sample_rate │ channels │ channel_layout │ bits_per_sample │ initial_padding │ id │ r_frame_rate │ avg_frame_rate │ ... │
├───┼────────────┼─────────────────────────────┼─────────┼────────────┼──────────────────┼────────────┼────────────┼─────────────┼──────────┼────────────────┼─────────────────┼─────────────────┼─────┼──────────────┼────────────────┼─────┤
1 aac AAC (Advanced Audio Coding) LC audio mp4a 0x6134706d fltp 48000 6 5.1 0 0 0x2 0/0 0/0 ...
╰───┴────────────┴─────────────────────────────┴─────────┴────────────┴──────────────────┴────────────┴────────────┴─────────────┴──────────┴────────────────┴─────────────────┴─────────────────┴─────┴──────────────┴────────────────┴─────╯
╭───┬────────────┬─────────────────────────────┬─────────┬────────────┬──────────────────┬────────────┬─────────┬─────╮
# │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_tag │ sample_ │ ... │
fmt
├───┼────────────┼─────────────────────────────┼─────────┼────────────┼──────────────────┼────────────┼─────────┼─────┤
1 aac AAC (Advanced Audio Coding) LC audio mp4a 0x6134706d fltp ...
╰───┴────────────┴─────────────────────────────┴─────────┴────────────┴──────────────────┴────────────┴─────────┴─────╯
```
```nu

View File

@@ -3,8 +3,12 @@
use ../ffprobe ["main" "dimensions" "streams video"];
def main [] {
echo "# Extract the dimensions of a video stream"
echo "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams video | first | dimensions"
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
| streams video | first | dimensions
print "# Extract the dimensions of a video stream"
print "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams video | first | dimensions"
(
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
| streams video
| first
| dimensions
)
}

View File

@@ -3,8 +3,8 @@
use ../ffprobe;
def main [] {
echo "# Use ffprobe on mutliple files at once"
echo "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 https://sample-videos.com/video321/mkv/720/big_buck_bunny_720p_1mb.mkv"
print "# Use ffprobe on mutliple files at once"
print "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 https://sample-videos.com/video321/mkv/720/big_buck_bunny_720p_1mb.mkv"
(
ffprobe
$'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'

View File

@@ -3,7 +3,7 @@
use ../ffprobe;
def main [] {
echo "# Return a table from ffprobe"
echo "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4"
print "# Return a table from ffprobe"
print "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4"
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
}

View File

@@ -3,8 +3,8 @@
use ../ffprobe ["main" "streams audio"];
def main [] {
echo "# Extract the audio streams from a video"
echo "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams audio"
print "# Extract the audio streams from a video"
print "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams audio"
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
| streams audio
}

View File

@@ -3,8 +3,8 @@
use ../ffprobe ["main" "streams video"];
def main [] {
echo "# Extract the video streams from a video"
echo "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams video"
print "# Extract the video streams from a video"
print "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams video"
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
| streams video
}

View File

@@ -82,8 +82,8 @@ export def "parse filter" [
]: string -> table<name: string params: table<param: string, value: string>> {
parse --regex '^\s*(?:\[(?<input>[^\s]+)\]\s*)?(?<name>[^=\s\[]+)\s*(?:=(?<params>[^\[\s,;]*)\s*)?(?:\[(?<output>[^\s,;]+)\])?' | first | update params {
parse --regex `(?:(?<param>[^=]+)=)?(?<value>[^:]+):?`
} | update input { split row '][' | filter { is-not-empty }
} | update output { split row '][' | filter { is-not-empty } }
} | update input { split row '][' | where { is-not-empty }
} | update output { split row '][' | where { is-not-empty } }
}
# TODO: Remove export
@@ -95,7 +95,7 @@ def "filterchain to-string" []: table -> string {
$in | each { filter to-string }| str join ','
}
def "filter to-string" []: record<input: list<string> name: string params: table<name: string value: string> output: list<string>> -> string {
def "filter to-string" []: record<input: list<string> name: string params: table<param: string value: string> output: list<string>> -> string {
$in | update input {
str join ']['
} | update output {
@@ -176,7 +176,3 @@ export def append-complex-filter [
(complex-filter --input $input --output $output $name $params)
]
}
def is-not-empty []: any -> bool {
is-empty | not $in
}

View File

@@ -100,7 +100,7 @@ def boolean_params_are_converted_to_1_or_0 [] {
#[test]
def without_filterchain_chains_are_concated [] {
let got = (cmd ['INPUT'] ['OUTPUT'] | fps 25 | loop 2 1);
let got = (cmd ['INPUT'] ['OUTPUT'] | fps 25 | vloop 2 1);
assert equal $got {
input: ['INPUT']
@@ -140,7 +140,7 @@ def without_filterchain_chains_are_concated [] {
}
#[test]
def filterchain_concats_filters [] {
let got = (cmd ['INPUT'] ['OUTPUT'] | filterchain { fps 25 -i ['in'] | loop 2 1 -o ['out']});
let got = (cmd ['INPUT'] ['OUTPUT'] | filterchain { fps 25 -i ['in'] | vloop 2 1 -o ['out']});
assert equal $got {
input: ['INPUT']
@@ -179,7 +179,7 @@ def filterchain_concats_filters [] {
#[test]
def filterchain_appends_current_filter [] {
let got = (cmd ['INPUT'] ['OUTPUT'] | fps 12 | filterchain { fps 25 -i ['in'] | loop 2 1 -o ['out']});
let got = (cmd ['INPUT'] ['OUTPUT'] | fps 12 | filterchain { fps 25 -i ['in'] | vloop 2 1 -o ['out']});
assert equal $got {
input: ['INPUT']

View File

@@ -31,6 +31,6 @@ export def "streams audio" []: table<streams: table, format: record> -> table {
}
# Get the dimensions of a video stream
export def "dimensions" []: table<streams: table, format: record> -> record<width: int, height: int> {
export def "dimensions" []: record<width: int, height: int> -> record<width: int, height: int> {
$in | select width height
}

View File

@@ -5,9 +5,11 @@ use std [assert];
use ./ffmpeg.nu ["append-complex-filter"]
# loop video frames
export def loop [
--input (-i): list<string>: = []
--output (-o): list<string>: = []
# Same as the `loop` filter in ffmpeg, but
# had to be renamed due to collisions with the [nushell builtin](https://www.nushell.sh/commands/docs/loop.html)
export def "vloop" [
--input (-i): list<string> = []
--output (-o): list<string> = []
loop: int # Set the number of loops. Setting this value to -1 will result in infinite loops. Default is 0.
size: int # Set maximal size in number of frames. Default is 0.
--start (-s): int # Set first frame of loop. Default is 0.
@@ -23,8 +25,8 @@ export def loop [
# Convert the video to specified constant frame rate by duplicating or dropping frames as necessary.
export def fps [
--input (-i): list<string>: = []
--output (-o): list<string>: = []
--input (-i): list<string> = []
--output (-o): list<string> = []
--start-time (-s) # Assume the first PTS should be the given value, in seconds.
# This allows for padding/trimming at the start of stream. By default, no assumption is made about the first frames expected PTS, so no padding or trimming is done. For example, this could be set to 0 to pad the beginning with duplicates of the first frame if a video stream starts after the audio stream or to trim any frames with a negative PTS.
--round (-r): string@fps-round # Timestamp (PTS) rounding method. use completion to view available options.
@@ -63,8 +65,8 @@ def fps-fps [] {
# Set the timebase to use for the output frames timestamps. It is mainly useful for testing timebase configuration.
export def settb [
--input (-i): list<string>: = []
--output (-o): list<string>: = []
--input (-i): list<string> = []
--output (-o): list<string> = []
timebase # The value for tb is an arithmetic expression representing a rational. The expression can contain the constants "AVTB" (the default timebase), "intb" (the input timebase) and "sr" (the sample rate, audio only). Default value is "intb".
] {
(append-complex-filter settb {expr: $timebase} -i $input -o $output)
@@ -81,8 +83,8 @@ def "list to-pipe-separated-string" []: list -> string {
# Convert the input video to one of the specified pixel formats. Libavfilter will try to pick one that is suitable as input to the next filter.
export def format [
--input (-i): list<string>: = []
--output (-o): list<string>: = []
--input (-i): list<string> = []
--output (-o): list<string> = []
--pix-fmts (-p): list<string> # A list of pixel format names
--color-spaces (-c): list<string> # A list of color space names
--color-ranges (-r): list<string> # A list of color range names
@@ -208,7 +210,7 @@ def xfade-expressions [context: string] {
}
export def split [
--input (-i): list<string>: = []
--input (-i): list<string> = []
output: list<string>
] {
let cmd = $in;

View File

@@ -2,18 +2,19 @@
use std [assert];
use ./filters.nu [complex-filter loop "parse filter"];
use ./ffmpeg.nu [complex-filter "parse filter"];
use ./filters.nu [vloop];
# #[test]
def loop_has_defaults [] {
let got = (loop 10 1);
let got = (vloop 10 1);
let want = (complex-filter 'loop' { loop: 10 size: 1 });
assert equal $got $want;
}
# #[test]
def setting_time_sets_start_to-1 [] {
let got = (loop 10 1 -t 0.5);
let got = (vloop 10 1 -t 0.5);
let want = (complex-filter 'loop' {
loop: 10
size: 1

6
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1712163089,
"narHash": "sha256-Um+8kTIrC19vD4/lUCN9/cU9kcOsD1O1m+axJqQPyMM=",
"lastModified": 1766902085,
"narHash": "sha256-coBu0ONtFzlwwVBzmjacUQwj3G+lybcZ1oeNSQkgC0M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "fd281bd6b7d3e32ddfa399853946f782553163b5",
"rev": "c0b0e0fddf73fd517c3471e546c0df87a42d53f4",
"type": "github"
},
"original": {

View File

@@ -20,7 +20,7 @@
hugo
yarn
nushellFull
nushell
];
};
};

View File

@@ -7,9 +7,9 @@ def main [] {
(
help commands
| where command_type == "custom" and name !~ "p(rompt|wd)"
| select name usage
| select name description
| update name { if $in == 'main' { 'ffprobe' } else { $'ffprobe ($in)' } }
| filter { not ($in.name == 'ffprobe' and ($in.usage | is-empty)) }
| where { not ($in.name == 'ffprobe' and ($in.description | is-empty)) }
| to md -p
)
}

View File

@@ -7,8 +7,8 @@ def main [] {
(
help commands
| where command_type == "custom" and name !~ "p(rompt|wd)|^main$"
| select name usage
| update usage {
| select name description
| update description {
str replace -a "\n" " "
}
| to md -p