builtin_metadata!() { /* proc-macro */ }
Expand description

Macro to generate the code to define a new builtin for bash.

§Usage

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:

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:

// help text for the `true` builtin.

long_doc = "
    Return a successful result.

    Exit Status:
    Always succeeds.
"

long_doc = "Return a successful result.\n\nExit Status:\nAlways succeeds.\n"

This transformation is similar to the indoc crate, the text blocks 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.

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:

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:

$ 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