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 clip::ClipConfig;
11pub use completions::{
12 CompletionAlgorithm, CompletionConfig, CompletionSort, ExternalCompleterConfig,
13};
14pub use datetime_format::DatetimeFormatConfig;
15pub use display_errors::DisplayErrors;
16pub use filesize::FilesizeConfig;
17pub use helper::extract_value;
18pub use hinter::HinterConfig;
19pub use history::{HistoryConfig, HistoryFileFormat, HistoryPath};
20pub use hooks::Hooks;
21pub use ls::LsConfig;
22pub use output::{BannerKind, ErrorStyle};
23pub use plugin_gc::{PluginGcConfig, PluginGcConfigs};
24pub use reedline::{CursorShapeConfig, EditBindings, NuCursorShape, ParsedKeybinding, ParsedMenu};
25pub use rm::RmConfig;
26pub use shell_integration::ShellIntegrationConfig;
27pub use table::{FooterMode, TableConfig, TableIndent, TableIndexMode, TableMode, TrimStrategy};
28
29mod ansi_coloring;
30mod clip;
31mod completions;
32mod datetime_format;
33mod display_errors;
34mod error;
35mod filesize;
36mod helper;
37mod hinter;
38mod history;
39mod hooks;
40mod ls;
41mod output;
42mod plugin_gc;
43mod prelude;
44mod reedline;
45mod rm;
46mod shell_integration;
47mod table;
48
49#[derive(Clone, Debug, IntoValue, Serialize, Deserialize)]
50pub struct Config {
51 pub filesize: FilesizeConfig,
52 pub table: TableConfig,
53 pub ls: LsConfig,
54 pub clip: ClipConfig,
55 pub color_config: HashMap<String, Value>,
56 pub footer_mode: FooterMode,
57 pub float_precision: i64,
58 pub recursion_limit: i64,
59 pub use_ansi_coloring: UseAnsiColoring,
60 pub completions: CompletionConfig,
61 pub edit_mode: EditBindings,
62 pub show_hints: bool,
63 pub hinter: HinterConfig,
64 pub history: HistoryConfig,
65 pub keybindings: Vec<ParsedKeybinding>,
66 pub abbreviations: HashMap<String, String>,
67 pub menus: Vec<ParsedMenu>,
68 pub hooks: Hooks,
69 pub rm: RmConfig,
70 pub shell_integration: ShellIntegrationConfig,
71 pub buffer_editor: Value,
72 pub show_banner: BannerKind,
73 pub bracketed_paste: bool,
74 pub render_right_prompt_on_last_line: bool,
75 pub explore: HashMap<String, Value>,
76 pub cursor_shape: CursorShapeConfig,
77 pub datetime_format: DatetimeFormatConfig,
78 pub error_style: ErrorStyle,
79 pub error_lines: i64,
80 pub display_errors: DisplayErrors,
81 pub use_kitty_protocol: bool,
82 pub highlight_resolved_externals: bool,
83 pub auto_cd_implicit: bool,
84 pub plugins: HashMap<String, Value>,
90 pub plugin_gc: PluginGcConfigs,
92}
93
94impl Default for Config {
95 fn default() -> Config {
96 Config {
97 show_banner: BannerKind::default(),
98
99 table: TableConfig::default(),
100 rm: RmConfig::default(),
101 ls: LsConfig::default(),
102
103 datetime_format: DatetimeFormatConfig::default(),
104
105 explore: HashMap::new(),
106
107 history: HistoryConfig::default(),
108
109 completions: CompletionConfig::default(),
110
111 recursion_limit: 50,
112
113 filesize: FilesizeConfig::default(),
114
115 cursor_shape: CursorShapeConfig::default(),
116
117 clip: ClipConfig::default(),
118
119 color_config: HashMap::new(),
120 footer_mode: FooterMode::RowCount(25),
121 float_precision: 2,
122 buffer_editor: Value::nothing(Span::unknown()),
123 use_ansi_coloring: UseAnsiColoring::default(),
124 bracketed_paste: true,
125 edit_mode: EditBindings::default(),
126 show_hints: true,
127 hinter: HinterConfig::default(),
128
129 shell_integration: ShellIntegrationConfig::default(),
130
131 render_right_prompt_on_last_line: false,
132
133 hooks: Hooks::new(),
134
135 menus: Vec::new(),
136
137 keybindings: Vec::new(),
138 abbreviations: HashMap::new(),
139
140 error_style: ErrorStyle::default(),
141 error_lines: 1,
142 display_errors: DisplayErrors::default(),
143
144 use_kitty_protocol: false,
145 highlight_resolved_externals: false,
146
147 auto_cd_implicit: false,
148
149 plugins: HashMap::new(),
150 plugin_gc: PluginGcConfigs::default(),
151 }
152 }
153}
154
155impl UpdateFromValue for Config {
156 fn update<'a>(
157 &mut self,
158 value: &'a Value,
159 path: &mut ConfigPath<'a>,
160 errors: &mut ConfigErrors,
161 ) {
162 let Value::Record { val: record, .. } = value else {
163 errors.type_mismatch(path, Type::record(), value);
164 return;
165 };
166
167 for (col, val) in record.iter() {
168 let path = &mut path.push(col);
169 match col.as_str() {
170 "ls" => self.ls.update(val, path, errors),
171 "rm" => self.rm.update(val, path, errors),
172 "history" => self.history.update(val, path, errors),
173 "completions" => self.completions.update(val, path, errors),
174 "cursor_shape" => self.cursor_shape.update(val, path, errors),
175 "table" => self.table.update(val, path, errors),
176 "filesize" => self.filesize.update(val, path, errors),
177 "explore" => self.explore.update(val, path, errors),
178 "color_config" => self.color_config.update(val, path, errors),
179 "clip" => self.clip.update(val, path, errors),
180 "footer_mode" => self.footer_mode.update(val, path, errors),
181 "float_precision" => self.float_precision.update(val, path, errors),
182 "use_ansi_coloring" => self.use_ansi_coloring.update(val, path, errors),
183 "edit_mode" => self.edit_mode.update(val, path, errors),
184 "show_hints" => self.show_hints.update(val, path, errors),
185 "hinter" => self.hinter.update(val, path, errors),
186 "shell_integration" => self.shell_integration.update(val, path, errors),
187 "buffer_editor" => match val {
188 Value::Nothing { .. } | Value::String { .. } => {
189 self.buffer_editor = val.clone();
190 }
191 Value::List { vals, .. }
192 if vals.iter().all(|val| matches!(val, Value::String { .. })) =>
193 {
194 self.buffer_editor = val.clone();
195 }
196 _ => errors.type_mismatch(
197 path,
198 Type::custom("string, list<string>, or nothing"),
199 val,
200 ),
201 },
202 "show_banner" => self.show_banner.update(val, path, errors),
203 "display_errors" => self.display_errors.update(val, path, errors),
204 "render_right_prompt_on_last_line" => self
205 .render_right_prompt_on_last_line
206 .update(val, path, errors),
207 "bracketed_paste" => self.bracketed_paste.update(val, path, errors),
208 "use_kitty_protocol" => self.use_kitty_protocol.update(val, path, errors),
209 "highlight_resolved_externals" => {
210 self.highlight_resolved_externals.update(val, path, errors)
211 }
212 "auto_cd_implicit" => self.auto_cd_implicit.update(val, path, errors),
213 "plugins" => self.plugins.update(val, path, errors),
214 "plugin_gc" => self.plugin_gc.update(val, path, errors),
215 "menus" => match Vec::from_value(val.clone()) {
216 Ok(menus) => self.menus = menus,
217 Err(err) => errors.error(err.into()),
218 },
219 "keybindings" => match Vec::from_value(val.clone()) {
220 Ok(keybindings) => self.keybindings = keybindings,
221 Err(err) => errors.error(err.into()),
222 },
223 "abbreviations" => self.abbreviations.update(val, path, errors),
224 "hooks" => self.hooks.update(val, path, errors),
225 "datetime_format" => self.datetime_format.update(val, path, errors),
226 "error_style" => self.error_style.update(val, path, errors),
227 "error_lines" => {
228 if let Ok(lines) = val.as_int() {
229 if lines >= 0 {
230 self.error_lines = lines;
231 } else {
232 errors.invalid_value(path, "an int greater than or equal to 0", val);
233 }
234 } else {
235 errors.type_mismatch(path, Type::Int, val);
236 }
237 }
238 "recursion_limit" => {
239 if let Ok(limit) = val.as_int() {
240 if limit > 1 {
241 self.recursion_limit = limit;
242 } else {
243 errors.invalid_value(path, "an int greater than 1", val);
244 }
245 } else {
246 errors.type_mismatch(path, Type::Int, val);
247 }
248 }
249 _ => errors.unknown_option(path, val),
250 }
251 }
252 }
253}
254
255impl Config {
256 pub fn update_from_value(
257 &mut self,
258 old: &Config,
259 value: &Value,
260 ) -> Result<Option<ShellWarning>, ShellError> {
261 self.update_from_value_with_options(old, value, false)
262 }
263
264 pub fn update_from_value_with_options(
273 &mut self,
274 old: &Config,
275 value: &Value,
276 history_locked_after_startup: bool,
277 ) -> Result<Option<ShellWarning>, ShellError> {
278 let mut errors =
282 ConfigErrors::new(old).with_history_locked_after_startup(history_locked_after_startup);
283 let mut path = ConfigPath::new();
284
285 self.update(value, &mut path, &mut errors);
286
287 errors.check()
288 }
289}