Today I Learned (June 18, 2024)

NuShell functions may be defined as wrapper functions

The key is to specify the option --wrapped when defining a function with def. This allows us to specify unknown function arguments and therefore enables the use of higher order functions with variadic arguments. If a function is defined with --wrapped, it also needs to declare its arguments as a rest parameter. I.e.

export def the_wrapper --wrapped [...rest] {
  print $rest
}

may be called like so

$ the_wrapper a b c d --foo=bar
╭───┬───────────╮
│ 0 │ a         │
│ 1 │ b         │
│ 2 │ c         │
│ 3 │ d         │
│ 4 │ --foo=bar │
╰───┴───────────╯

without any runtime errors.

We can use this to, for example, run an external program and catch errors in combination with the try-external command.

use std log

export def try_external --wrapped [...rest] {
  if ($rest | length) < 1 {
    error make {
      msg: "Invalid parameter."
      label: {
        text: "Expected program name and optional parameter here."
        span: (metadata $rest).span

      }
    }
  }
 
  let program = $rest.0
  let args = $rest | drop nth 0

  try {
    run-external $program ...$args
  } catch {
    let command_as_string = [$program ...$args] | str join " "
    log error $"External command `($command_as_string)` failed."
  }
}

And then use it like this to safely execute potentially failing external commands

$ try_external idontexist --foo=bar a b c
2024-06-18T13:24:33.817|ERR|External command `idontexist --foo=bar a b c` failed.
$ try_external cat /foo/bar                                                      /usr/bin/cat: /foo/bar: No such file or directory
2024-06-18T13:27:10.005|ERR|External command `cat /foo/bar` failed.