1use crate::FromValue;
4use crate::{self as nu_protocol};
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::{BannerKind, 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 show_hints: bool,
58 pub history: HistoryConfig,
59 pub keybindings: Vec<ParsedKeybinding>,
60 pub menus: Vec<ParsedMenu>,
61 pub hooks: Hooks,
62 pub rm: RmConfig,
63 pub shell_integration: ShellIntegrationConfig,
64 pub buffer_editor: Value,
65 pub show_banner: BannerKind,
66 pub bracketed_paste: bool,
67 pub render_right_prompt_on_last_line: bool,
68 pub explore: HashMap<String, Value>,
69 pub cursor_shape: CursorShapeConfig,
70 pub datetime_format: DatetimeFormatConfig,
71 pub error_style: ErrorStyle,
72 pub error_lines: i64,
73 pub display_errors: DisplayErrors,
74 pub use_kitty_protocol: bool,
75 pub highlight_resolved_externals: bool,
76 pub plugins: HashMap<String, Value>,
82 pub plugin_gc: PluginGcConfigs,
84}
85
86impl Default for Config {
87 fn default() -> Config {
88 Config {
89 show_banner: BannerKind::default(),
90
91 table: TableConfig::default(),
92 rm: RmConfig::default(),
93 ls: LsConfig::default(),
94
95 datetime_format: DatetimeFormatConfig::default(),
96
97 explore: HashMap::new(),
98
99 history: HistoryConfig::default(),
100
101 completions: CompletionConfig::default(),
102
103 recursion_limit: 50,
104
105 filesize: FilesizeConfig::default(),
106
107 cursor_shape: CursorShapeConfig::default(),
108
109 color_config: HashMap::new(),
110 footer_mode: FooterMode::RowCount(25),
111 float_precision: 2,
112 buffer_editor: Value::nothing(Span::unknown()),
113 use_ansi_coloring: UseAnsiColoring::default(),
114 bracketed_paste: true,
115 edit_mode: EditBindings::default(),
116 show_hints: true,
117
118 shell_integration: ShellIntegrationConfig::default(),
119
120 render_right_prompt_on_last_line: false,
121
122 hooks: Hooks::new(),
123
124 menus: Vec::new(),
125
126 keybindings: Vec::new(),
127
128 error_style: ErrorStyle::default(),
129 error_lines: 1,
130 display_errors: DisplayErrors::default(),
131
132 use_kitty_protocol: false,
133 highlight_resolved_externals: false,
134
135 plugins: HashMap::new(),
136 plugin_gc: PluginGcConfigs::default(),
137 }
138 }
139}
140
141impl UpdateFromValue for Config {
142 fn update<'a>(
143 &mut self,
144 value: &'a Value,
145 path: &mut ConfigPath<'a>,
146 errors: &mut ConfigErrors,
147 ) {
148 let Value::Record { val: record, .. } = value else {
149 errors.type_mismatch(path, Type::record(), value);
150 return;
151 };
152
153 for (col, val) in record.iter() {
154 let path = &mut path.push(col);
155 match col.as_str() {
156 "ls" => self.ls.update(val, path, errors),
157 "rm" => self.rm.update(val, path, errors),
158 "history" => self.history.update(val, path, errors),
159 "completions" => self.completions.update(val, path, errors),
160 "cursor_shape" => self.cursor_shape.update(val, path, errors),
161 "table" => self.table.update(val, path, errors),
162 "filesize" => self.filesize.update(val, path, errors),
163 "explore" => self.explore.update(val, path, errors),
164 "color_config" => self.color_config.update(val, path, errors),
165 "footer_mode" => self.footer_mode.update(val, path, errors),
166 "float_precision" => self.float_precision.update(val, path, errors),
167 "use_ansi_coloring" => self.use_ansi_coloring.update(val, path, errors),
168 "edit_mode" => self.edit_mode.update(val, path, errors),
169 "show_hints" => self.show_hints.update(val, path, errors),
170 "shell_integration" => self.shell_integration.update(val, path, errors),
171 "buffer_editor" => match val {
172 Value::Nothing { .. } | Value::String { .. } => {
173 self.buffer_editor = val.clone();
174 }
175 Value::List { vals, .. }
176 if vals.iter().all(|val| matches!(val, Value::String { .. })) =>
177 {
178 self.buffer_editor = val.clone();
179 }
180 _ => errors.type_mismatch(
181 path,
182 Type::custom("string, list<string>, or nothing"),
183 val,
184 ),
185 },
186 "show_banner" => self.show_banner.update(val, path, errors),
187 "display_errors" => self.display_errors.update(val, path, errors),
188 "render_right_prompt_on_last_line" => self
189 .render_right_prompt_on_last_line
190 .update(val, path, errors),
191 "bracketed_paste" => self.bracketed_paste.update(val, path, errors),
192 "use_kitty_protocol" => self.use_kitty_protocol.update(val, path, errors),
193 "highlight_resolved_externals" => {
194 self.highlight_resolved_externals.update(val, path, errors)
195 }
196 "plugins" => self.plugins.update(val, path, errors),
197 "plugin_gc" => self.plugin_gc.update(val, path, errors),
198 "menus" => match Vec::from_value(val.clone()) {
199 Ok(menus) => self.menus = menus,
200 Err(err) => errors.error(err.into()),
201 },
202 "keybindings" => match Vec::from_value(val.clone()) {
203 Ok(keybindings) => self.keybindings = keybindings,
204 Err(err) => errors.error(err.into()),
205 },
206 "hooks" => self.hooks.update(val, path, errors),
207 "datetime_format" => self.datetime_format.update(val, path, errors),
208 "error_style" => self.error_style.update(val, path, errors),
209 "error_lines" => {
210 if let Ok(lines) = val.as_int() {
211 if lines >= 0 {
212 self.error_lines = lines;
213 } else {
214 errors.invalid_value(path, "an int greater than or equal to 0", val);
215 }
216 } else {
217 errors.type_mismatch(path, Type::Int, val);
218 }
219 }
220 "recursion_limit" => {
221 if let Ok(limit) = val.as_int() {
222 if limit > 1 {
223 self.recursion_limit = limit;
224 } else {
225 errors.invalid_value(path, "an int greater than 1", val);
226 }
227 } else {
228 errors.type_mismatch(path, Type::Int, val);
229 }
230 }
231 _ => errors.unknown_option(path, val),
232 }
233 }
234 }
235}
236
237impl Config {
238 pub fn update_from_value(
239 &mut self,
240 old: &Config,
241 value: &Value,
242 ) -> Result<Option<ShellWarning>, ShellError> {
243 let mut errors = ConfigErrors::new(old);
247 let mut path = ConfigPath::new();
248
249 self.update(value, &mut path, &mut errors);
250
251 errors.check()
252 }
253}