1use crate as nu_protocol;
4use crate::FromValue;
5use helper::*;
6use prelude::*;
7use std::collections::HashMap;
8
9pub use ansi_coloring::UseAnsiColoring;
10pub use completions::{
11 CompletionAlgorithm, CompletionConfig, CompletionSort, ExternalCompleterConfig,
12};
13pub use datetime_format::DatetimeFormatConfig;
14pub use display_errors::DisplayErrors;
15pub use filesize::FilesizeConfig;
16pub use helper::extract_value;
17pub use history::{HistoryConfig, HistoryFileFormat};
18pub use hooks::Hooks;
19pub use ls::LsConfig;
20pub use output::ErrorStyle;
21pub use plugin_gc::{PluginGcConfig, PluginGcConfigs};
22pub use reedline::{CursorShapeConfig, EditBindings, NuCursorShape, ParsedKeybinding, ParsedMenu};
23pub use rm::RmConfig;
24pub use shell_integration::ShellIntegrationConfig;
25pub use table::{FooterMode, TableConfig, TableIndent, TableIndexMode, TableMode, TrimStrategy};
26
27mod ansi_coloring;
28mod completions;
29mod datetime_format;
30mod display_errors;
31mod error;
32mod filesize;
33mod helper;
34mod history;
35mod hooks;
36mod ls;
37mod output;
38mod plugin_gc;
39mod prelude;
40mod reedline;
41mod rm;
42mod shell_integration;
43mod table;
44
45#[derive(Clone, Debug, IntoValue, Serialize, Deserialize)]
46pub struct Config {
47 pub filesize: FilesizeConfig,
48 pub table: TableConfig,
49 pub ls: LsConfig,
50 pub color_config: HashMap<String, Value>,
51 pub footer_mode: FooterMode,
52 pub float_precision: i64,
53 pub recursion_limit: i64,
54 pub use_ansi_coloring: UseAnsiColoring,
55 pub completions: CompletionConfig,
56 pub edit_mode: EditBindings,
57 pub history: HistoryConfig,
58 pub keybindings: Vec<ParsedKeybinding>,
59 pub menus: Vec<ParsedMenu>,
60 pub hooks: Hooks,
61 pub rm: RmConfig,
62 pub shell_integration: ShellIntegrationConfig,
63 pub buffer_editor: Value,
64 pub show_banner: Value,
65 pub bracketed_paste: bool,
66 pub render_right_prompt_on_last_line: bool,
67 pub explore: HashMap<String, Value>,
68 pub cursor_shape: CursorShapeConfig,
69 pub datetime_format: DatetimeFormatConfig,
70 pub error_style: ErrorStyle,
71 pub display_errors: DisplayErrors,
72 pub use_kitty_protocol: bool,
73 pub highlight_resolved_externals: bool,
74 pub plugins: HashMap<String, Value>,
80 pub plugin_gc: PluginGcConfigs,
82}
83
84impl Default for Config {
85 fn default() -> Config {
86 Config {
87 show_banner: Value::bool(true, Span::unknown()),
88
89 table: TableConfig::default(),
90 rm: RmConfig::default(),
91 ls: LsConfig::default(),
92
93 datetime_format: DatetimeFormatConfig::default(),
94
95 explore: HashMap::new(),
96
97 history: HistoryConfig::default(),
98
99 completions: CompletionConfig::default(),
100
101 recursion_limit: 50,
102
103 filesize: FilesizeConfig::default(),
104
105 cursor_shape: CursorShapeConfig::default(),
106
107 color_config: HashMap::new(),
108 footer_mode: FooterMode::RowCount(25),
109 float_precision: 2,
110 buffer_editor: Value::nothing(Span::unknown()),
111 use_ansi_coloring: UseAnsiColoring::default(),
112 bracketed_paste: true,
113 edit_mode: EditBindings::default(),
114
115 shell_integration: ShellIntegrationConfig::default(),
116
117 render_right_prompt_on_last_line: false,
118
119 hooks: Hooks::new(),
120
121 menus: Vec::new(),
122
123 keybindings: Vec::new(),
124
125 error_style: ErrorStyle::Fancy,
126 display_errors: DisplayErrors::default(),
127
128 use_kitty_protocol: false,
129 highlight_resolved_externals: false,
130
131 plugins: HashMap::new(),
132 plugin_gc: PluginGcConfigs::default(),
133 }
134 }
135}
136
137impl UpdateFromValue for Config {
138 fn update<'a>(
139 &mut self,
140 value: &'a Value,
141 path: &mut ConfigPath<'a>,
142 errors: &mut ConfigErrors,
143 ) {
144 let Value::Record { val: record, .. } = value else {
145 errors.type_mismatch(path, Type::record(), value);
146 return;
147 };
148
149 for (col, val) in record.iter() {
150 let path = &mut path.push(col);
151 match col.as_str() {
152 "ls" => self.ls.update(val, path, errors),
153 "rm" => self.rm.update(val, path, errors),
154 "history" => self.history.update(val, path, errors),
155 "completions" => self.completions.update(val, path, errors),
156 "cursor_shape" => self.cursor_shape.update(val, path, errors),
157 "table" => self.table.update(val, path, errors),
158 "filesize" => self.filesize.update(val, path, errors),
159 "explore" => self.explore.update(val, path, errors),
160 "color_config" => self.color_config.update(val, path, errors),
161 "footer_mode" => self.footer_mode.update(val, path, errors),
162 "float_precision" => self.float_precision.update(val, path, errors),
163 "use_ansi_coloring" => self.use_ansi_coloring.update(val, path, errors),
164 "edit_mode" => self.edit_mode.update(val, path, errors),
165 "shell_integration" => self.shell_integration.update(val, path, errors),
166 "buffer_editor" => match val {
167 Value::Nothing { .. } | Value::String { .. } => {
168 self.buffer_editor = val.clone();
169 }
170 Value::List { vals, .. }
171 if vals.iter().all(|val| matches!(val, Value::String { .. })) =>
172 {
173 self.buffer_editor = val.clone();
174 }
175 _ => errors.type_mismatch(
176 path,
177 Type::custom("string, list<string>, or nothing"),
178 val,
179 ),
180 },
181 "show_banner" => self.show_banner.update(val, path, errors),
182 "display_errors" => self.display_errors.update(val, path, errors),
183 "render_right_prompt_on_last_line" => self
184 .render_right_prompt_on_last_line
185 .update(val, path, errors),
186 "bracketed_paste" => self.bracketed_paste.update(val, path, errors),
187 "use_kitty_protocol" => self.use_kitty_protocol.update(val, path, errors),
188 "highlight_resolved_externals" => {
189 self.highlight_resolved_externals.update(val, path, errors)
190 }
191 "plugins" => self.plugins.update(val, path, errors),
192 "plugin_gc" => self.plugin_gc.update(val, path, errors),
193 "menus" => match Vec::from_value(val.clone()) {
194 Ok(menus) => self.menus = menus,
195 Err(err) => errors.error(err.into()),
196 },
197 "keybindings" => match Vec::from_value(val.clone()) {
198 Ok(keybindings) => self.keybindings = keybindings,
199 Err(err) => errors.error(err.into()),
200 },
201 "hooks" => self.hooks.update(val, path, errors),
202 "datetime_format" => self.datetime_format.update(val, path, errors),
203 "error_style" => self.error_style.update(val, path, errors),
204 "recursion_limit" => {
205 if let Ok(limit) = val.as_int() {
206 if limit > 1 {
207 self.recursion_limit = limit;
208 } else {
209 errors.invalid_value(path, "an int greater than 1", val);
210 }
211 } else {
212 errors.type_mismatch(path, Type::Int, val);
213 }
214 }
215 _ => errors.unknown_option(path, val),
216 }
217 }
218 }
219}
220
221impl Config {
222 pub fn update_from_value(&mut self, old: &Config, value: &Value) -> Option<ShellError> {
223 let mut errors = ConfigErrors::new(old);
227 let mut path = ConfigPath::new();
228
229 self.update(value, &mut path, &mut errors);
230
231 errors.into_shell_error()
232 }
233}