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)" }
]
}