nu_protocol/config/
hooks.rs

1use super::prelude::*;
2use crate as nu_protocol;
3use std::collections::HashMap;
4
5/// Definition of a parsed hook from the config object
6#[derive(Clone, Debug, IntoValue, PartialEq, Serialize, Deserialize)]
7pub struct Hooks {
8    pub pre_prompt: Vec<Value>,
9    pub pre_execution: Vec<Value>,
10    pub env_change: HashMap<String, Vec<Value>>,
11    pub display_output: Option<Value>,
12    pub command_not_found: Option<Value>,
13}
14
15impl Hooks {
16    pub fn new() -> Self {
17        Self {
18            pre_prompt: Vec::new(),
19            pre_execution: Vec::new(),
20            env_change: HashMap::new(),
21            display_output: Some(Value::string(
22                "if (term size).columns >= 100 { table -e } else { table }",
23                Span::unknown(),
24            )),
25            command_not_found: None,
26        }
27    }
28}
29
30impl Default for Hooks {
31    fn default() -> Self {
32        Self::new()
33    }
34}
35
36impl UpdateFromValue for Hooks {
37    fn update<'a>(
38        &mut self,
39        value: &'a Value,
40        path: &mut ConfigPath<'a>,
41        errors: &mut ConfigErrors,
42    ) {
43        let Value::Record { val: record, .. } = value else {
44            errors.type_mismatch(path, Type::record(), value);
45            return;
46        };
47
48        for (col, val) in record.iter() {
49            let path = &mut path.push(col);
50            match col.as_str() {
51                "pre_prompt" => {
52                    if let Ok(hooks) = val.as_list() {
53                        self.pre_prompt = hooks.into()
54                    } else {
55                        errors.type_mismatch(path, Type::list(Type::Any), val);
56                    }
57                }
58                "pre_execution" => {
59                    if let Ok(hooks) = val.as_list() {
60                        self.pre_execution = hooks.into()
61                    } else {
62                        errors.type_mismatch(path, Type::list(Type::Any), val);
63                    }
64                }
65                "env_change" => {
66                    if let Ok(record) = val.as_record() {
67                        self.env_change = record
68                            .iter()
69                            .map(|(key, val)| {
70                                let old = self.env_change.remove(key).unwrap_or_default();
71                                let new = if let Ok(hooks) = val.as_list() {
72                                    hooks.into()
73                                } else {
74                                    errors.type_mismatch(
75                                        &path.push(key),
76                                        Type::list(Type::Any),
77                                        val,
78                                    );
79                                    old
80                                };
81                                (key.as_str().into(), new)
82                            })
83                            .collect();
84                    } else {
85                        errors.type_mismatch(path, Type::record(), val);
86                    }
87                }
88                "display_output" => {
89                    self.display_output = if val.is_nothing() {
90                        None
91                    } else {
92                        Some(val.clone())
93                    }
94                }
95                "command_not_found" => {
96                    self.command_not_found = if val.is_nothing() {
97                        None
98                    } else {
99                        Some(val.clone())
100                    }
101                }
102                _ => errors.unknown_option(path, val),
103            }
104        }
105    }
106}