Home Explore Blog CI



nushell

2nd chunk of `book/hooks.md`
a31a9d12735fa899889f7586486f2ef76c6963aac23624d00000000100000fa4
    pre_prompt: { $env.SPAM = "eggs" }
})

$env.SPAM
# => eggs
```

The hook blocks otherwise follow the general scoping rules, i.e., commands, aliases, etc. defined within the block will be thrown away once the block ends.

## `pre_execution` Hooks

`pre_execution` hooks can inspect the to-be-executed command through the [`commandline` command](/commands/docs/commandline.md).

For example, to print the command being executed:

```nu
$env.config = (
    $env.config
    | upsert hooks.pre_execution [ {||
        $env.repl_commandline = (commandline)
        print $"Command: ($env.repl_commandline)"
    } ]
)

print (1 + 3)
# => Command: print (1 + 3)
# => 4
```

## Conditional Hooks

One thing you might be tempted to do is to activate an environment whenever you enter a directory:

```nu
$env.config = ($env.config | upsert hooks {
    env_change: {
        PWD: [
            {|before, after|
                if $after == /some/path/to/directory {
                    load-env { SPAM: eggs }
                }
            }
        ]
    }
})
```

This won't work because the environment will be active only within the [`if`](/commands/docs/if.md) block.
In this case, you could easily rewrite it as `load-env (if $after == ... { ... } else { {} })` but this pattern is fairly common and later we'll see that not all cases can be rewritten like this.

To deal with the above problem, we introduce another way to define a hook - **a record**:

```nu
$env.config = ($env.config | upsert hooks {
    env_change: {
        PWD: [
            {
                condition: {|before, after| $after == /some/path/to/directory }
                code: {|before, after| load-env { SPAM: eggs } }
            }
        ]
    }
})
```

When the hook triggers, it evaluates the `condition` block.
If it returns `true`, the `code` block will be evaluated.
If it returns `false`, nothing will happen.
If it returns something else, an error will be thrown.
The `condition` field can also be omitted altogether in which case the hook will always evaluate.

The `pre_prompt` and `pre_execution` hook types also support the conditional hooks but they don't accept the `before` and `after` parameters.

## Hooks as Strings

So far a hook was defined as a block that preserves only the environment, but nothing else.
To be able to define commands or aliases, it is possible to define the `code` field as **a string**.
You can think of it as if you typed the string into the REPL and hit Enter.
So, the hook from the previous section can be also written as

```nu
$env.config = ($env.config | upsert hooks {
    pre_prompt: '$env.SPAM = "eggs"'
})

$env.SPAM
# => eggs
```

This feature can be used, for example, to conditionally bring in definitions based on the current directory:

```nu
$env.config = ($env.config | upsert hooks {
    env_change: {
        PWD: [
            {
                condition: {|_, after| $after == /some/path/to/directory }
                code: 'def foo [] { print "foo" }'
            }
            {
                condition: {|before, _| $before == /some/path/to/directory }
                code: 'hide foo'
            }
        ]
    }
})
```

When defining a hook as a string, the `$before` and `$after` variables are set to the previous and current environment variable value, respectively, similarly to the previous examples:

```nu
$env.config = ($env.config | upsert hooks {
    env_change: {
        PWD: {
            code: 'print $"changing directory from ($before) to ($after)"'
        }
    }
}
```

## Examples

### Adding a Single Hook to Existing Config

An example for PWD env change hook:

```nu
$env.config = ($env.config | upsert hooks.env_change.PWD {|config|
    let val = ($config | get -i hooks.env_change.PWD)

    if $val == null {
        $val | append {|before, after| print $"changing directory from ($before) to ($after)" }
    } else {
        [
            {|before, after| print $"changing directory from ($before) to ($after)" }
        ]
    }

Title: Advanced Nushell Hooks: Conditional Execution and String-Based Hooks
Summary
Nushell hooks support conditional execution using `condition` and `code` fields within a record, allowing hooks to run only when a specified condition is met. Additionally, the `code` field can be defined as a string, enabling the execution of arbitrary Nushell code as if typed into the REPL. This facilitates conditional definition of commands and aliases based on the current environment. The `$before` and `$after` variables are available when defining hooks as strings, providing access to the previous and current environment variable values. The document also provided an example of adding a single hook to an existing configuration.