bash_builtins_macro 0.2.0

Macros for the bash-builtins crate
Documentation
Macro to generate the code to define a new builtin for bash.

# Usage

```notrust
builtin_metadata!(
    name = string literal,
    create | try_create = path,
    short_doc = string literal,
    long_doc = string literal,
);
```

Arguments are specified as `key = value` items, where `key` can be:

* `name`.

    The name of the builtin.

* `create` or `try_create`.

    A [path] to a function to initialize the builtin.

    Just one of these keys has to be present.

* `short_doc` and `long_doc`.

    Optional keys for the builtin documentation.

See below for more details.

The generated code requires the [`bash_builtins`] crate to be available in the
package.

# Example

A builtin like [`eval`] can be defined with the following arguments:

```ignore
builtin_metadata!(
    name = "eval",
    create = Eval::default,
    short_doc = "eval [arg ...]",
    long_doc = "
        Execute arguments as a shell command.

        Combine ARGs into a single string, use the result as input to the shell,
        and execute the resulting commands.

        Exit Status:
        Returns exit status of command or success if command is null.
    ",
);
```

`Eval::default` is a [path] to a function that returns an instance of the
[`Builtin`] trait.

# Arguments

## `name`

The name of the builtin. It is required to be an ASCII identifier.

Users will type this name to invoke the builtin defined by the macro.

## `create`

A [path] to a function that returns an instance of the [`Builtin`] trait.

See below for more details on how to define that function.

## `try_create`

Similar to `create`, but the function returns an instance of
`Result<T: Builtin, E: Display>`. If the function returns [`Err`],
the builtin will not be loaded.

## `short_doc` (optional)

A single line of text to describe how to use the builtin.

This is optional, but it is recommended.

## `long_doc` (optional)

Documentation of the builtin. Bash uses this text for the [`help`] command.
Like `short_doc`, it is optional but recommended.

The content of the text is processed to remove the leading new lines, and the
left margin introduced to indent the content.

These two `long_doc` expressions are equivalent:

```ignore
// help text for the `true` builtin.

# let
long_doc = "
    Return a successful result.

    Exit Status:
    Always succeeds.
"

# ; let
long_doc = "Return a successful result.\n\nExit Status:\nAlways succeeds.\n"
# ;
```

This transformation is similar to the [indoc](https://docs.rs/indoc)
crate, the [text blocks](https://openjdk.java.net/jeps/378) in Java,
[“squiggly” heredocs] in Ruby, and many others.

# Builtin Initialization

Builtins are implemented as instances of the [`Builtin`] trait. To create
that instance, one of `create` or `try_create` is required in the
`builtin_metadata!()` macro.

The function given in `create` returns the instance. In the following example
we use the generated [`default`] function to create a new instance of the
`Counter` type.

```ignore
use bash_builtins::{builtin_metadata, Args, Builtin, Result};

builtin_metadata!(
    name = "counter",
    create = Counter::default,
    // …
);

#[derive(Default)]
struct Counter(isize);

impl Builtin for Counter {
    fn call(&mut self, args: &mut Args) -> Result<()> {
        // …
    }
}
```

The function given in `try_create` returns a `Result<T, E>`, where
`T` is the type for the builtin, and `E` implements [`Display`]. If the
function returns an error then the builtin will not be loaded.

In the following example, the builtin will always fail to load:

```ignore
builtin_metadata!(
    name = "loadfail",
    try_create = try_create,
    // …
);

fn try_create() -> std::result::Result<LoadFail, &'static str> {
    Err("something really bad happened")
}

struct LoadFail;

impl Builtin for LoadFail {
    fn call(&mut self, _args: &mut Args) -> Result<()> {
        Ok(())
    }
}
```

We can compile this example and then try to load it:

```notrust
$ cargo build --release --examples

$ enable -f target/release/examples/libloadfail.so loadfail
loadfail: error: something really bad happened
bash: enable: load function for loadfail returns failure (0): not loaded
```

[`Builtin`]: trait.Builtin.html
[`Display`]: ::std::fmt::Display
[`Err`]: std::result::Result::Err
[`bash_builtins`]: https://docs.rs/bash_builtins
[`default`]: ::std::default::Default::default
[`eval`]: https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#index-eval
[`help`]: https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html#index-help
[path]: https://doc.rust-lang.org/reference/paths.html
[“squiggly” heredocs]: https://docs.ruby-lang.org/en/3.0.0/doc/syntax/literals_rdoc.html#label-Here+Documents+-28heredocs-29