forked from extern/nushell
# Description Our config exists both as a `Config` struct for internal consumption and as a `Value`. The latter is exposed through `$env.config` and can be both set and read. Thus we have a complex bug-prone mechanism, that reads a `Value` and then tries to plug anything where the value is unrepresentable in `Config` with the correct state from `Config`. The parsing involves therefore mutation of the `Value` in a nested `Record` structure. Previously this was wholy done manually, with indices. To enable deletion for example, things had to be iterated over from the back. Also things were indexed in a bunch of places. This was hard to read and an invitation for bugs. With #10876 we can now use `Record::retain_mut` to traverse the records, modify anything that needs fixing, and drop invalid fields. # Parts: - Error messages now consistently use the correct spans pointing to the problematic value and the paths displayed in some messages are also aligned with the keys used for lookup. - Reconstruction of values has been fixed for: - `table.padding` - `buffer_editor` - `hooks.command_not_found` - `datetime_format` (partial solution) - Fix validation of `table.padding` input so value is not set (and underflows `usize` causing `table` to run forever with negative values) - New proper types for settings. Fully validated enums instead of strings: - `config.edit_mode` -> `EditMode` - Don't fall back to vi-mode on invalid string - `config.table.mode` -> `TableMode` - there is still a fall back to `rounded` if given an invalid `TableMode` as argument to the `nu` binary - `config.completions.algorithm` -> `CompletionAlgorithm` - `config.error_style` -> `ErrorStyle` - don't implicitly fall back to `fancy` when given an invalid value. - This should also shrink the size of `Config` as instead of 4x24 bytes those fields now need only 4x1 bytes in `Config` - Completely removed macros relying on the scope of `Value::into_config` so we can break it up into smaller parts in the future. - Factored everything into smaller files with the types and helpers for particular topics. - `NuCursorShape` now explicitly expresses the `Inherit` setting. conversion to option only happens at the interface to `reedline`
89 lines
2.9 KiB
Rust
89 lines
2.9 KiB
Rust
use crate::{Config, Record, ShellError, Span, Value};
|
|
use serde::{Deserialize, Serialize};
|
|
/// Definition of a parsed hook from the config object
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
pub struct Hooks {
|
|
pub pre_prompt: Option<Value>,
|
|
pub pre_execution: Option<Value>,
|
|
pub env_change: Option<Value>,
|
|
pub display_output: Option<Value>,
|
|
pub command_not_found: Option<Value>,
|
|
}
|
|
|
|
impl Hooks {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
pre_prompt: None,
|
|
pre_execution: None,
|
|
env_change: None,
|
|
display_output: Some(Value::string(
|
|
"if (term size).columns >= 100 { table -e } else { table }",
|
|
Span::unknown(),
|
|
)),
|
|
command_not_found: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for Hooks {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
/// Parse the hooks to find the blocks to run when the hooks fire
|
|
pub(super) fn create_hooks(value: &Value) -> Result<Hooks, ShellError> {
|
|
let span = value.span();
|
|
match value {
|
|
Value::Record { val, .. } => {
|
|
let mut hooks = Hooks::new();
|
|
|
|
for (col, val) in val {
|
|
match col.as_str() {
|
|
"pre_prompt" => hooks.pre_prompt = Some(val.clone()),
|
|
"pre_execution" => hooks.pre_execution = Some(val.clone()),
|
|
"env_change" => hooks.env_change = Some(val.clone()),
|
|
"display_output" => hooks.display_output = Some(val.clone()),
|
|
"command_not_found" => hooks.command_not_found = Some(val.clone()),
|
|
x => {
|
|
return Err(ShellError::UnsupportedConfigValue(
|
|
"'pre_prompt', 'pre_execution', 'env_change', 'display_output', 'command_not_found'"
|
|
.to_string(),
|
|
x.to_string(),
|
|
span,
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(hooks)
|
|
}
|
|
_ => Err(ShellError::UnsupportedConfigValue(
|
|
"record for 'hooks' config".into(),
|
|
"non-record value".into(),
|
|
span,
|
|
)),
|
|
}
|
|
}
|
|
|
|
pub(super) fn reconstruct_hooks(config: &Config, span: Span) -> Value {
|
|
let mut hook = Record::new();
|
|
if let Some(ref value) = config.hooks.pre_prompt {
|
|
hook.push("pre_prompt", value.clone());
|
|
}
|
|
if let Some(ref value) = config.hooks.pre_execution {
|
|
hook.push("pre_execution", value.clone());
|
|
}
|
|
if let Some(ref value) = config.hooks.env_change {
|
|
hook.push("env_change", value.clone());
|
|
}
|
|
if let Some(ref value) = config.hooks.display_output {
|
|
hook.push("display_output", value.clone());
|
|
}
|
|
if let Some(ref value) = config.hooks.command_not_found {
|
|
hook.push("command_not_found", value.clone());
|
|
}
|
|
|
|
Value::record(hook, span)
|
|
}
|