Use IntoValue in config code (#13751)

# Description

Cleans up and refactors the config code using the `IntoValue` macro.
Shoutout to @cptpiepmatz for making the macro!

# User-Facing Changes

Should be none.

# After Submitting

Somehow refactor the reverse transformation.
This commit is contained in:
Ian Manske 2024-09-05 00:44:23 -07:00 committed by GitHub
parent 4792328d0e
commit abd230e12e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 992 additions and 1206 deletions

View File

@ -55,7 +55,7 @@ impl Command for History {
HistoryFileFormat::Sqlite => { HistoryFileFormat::Sqlite => {
history_path.push("history.sqlite3"); history_path.push("history.sqlite3");
} }
HistoryFileFormat::PlainText => { HistoryFileFormat::Plaintext => {
history_path.push("history.txt"); history_path.push("history.txt");
} }
} }
@ -75,7 +75,7 @@ impl Command for History {
.ok() .ok()
} }
HistoryFileFormat::PlainText => FileBackedHistory::with_file( HistoryFileFormat::Plaintext => FileBackedHistory::with_file(
history.max_size as usize, history.max_size as usize,
history_path.clone().into(), history_path.clone().into(),
) )
@ -87,7 +87,7 @@ impl Command for History {
}; };
match history.file_format { match history.file_format {
HistoryFileFormat::PlainText => Ok(history_reader HistoryFileFormat::Plaintext => Ok(history_reader
.and_then(|h| { .and_then(|h| {
h.search(SearchQuery::everything(SearchDirection::Forward, None)) h.search(SearchQuery::everything(SearchDirection::Forward, None))
.ok() .ok()

View File

@ -51,7 +51,9 @@ impl CommandCompletion {
if working_set if working_set
.permanent_state .permanent_state
.config .config
.max_external_completion_results .completions
.external
.max_results
> executables.len() as i64 > executables.len() as i64
&& !executables.contains( && !executables.contains(
&item &item
@ -211,7 +213,7 @@ impl Completer for CommandCompletion {
working_set, working_set,
span, span,
offset, offset,
config.enable_external_completion, config.completions.external.enable,
options.match_algorithm, options.match_algorithm,
) )
} else { } else {

View File

@ -46,9 +46,9 @@ impl NuCompleter {
let config = self.engine_state.get_config(); let config = self.engine_state.get_config();
let options = CompletionOptions { let options = CompletionOptions {
case_sensitive: config.case_sensitive_completions, case_sensitive: config.completions.case_sensitive,
match_algorithm: config.completion_algorithm.into(), match_algorithm: config.completions.algorithm.into(),
sort: config.completion_sort, sort: config.completions.sort,
..Default::default() ..Default::default()
}; };
@ -208,7 +208,7 @@ impl NuCompleter {
// We got no results for internal completion // We got no results for internal completion
// now we can check if external completer is set and use it // now we can check if external completer is set and use it
if let Some(closure) = config.external_completer.as_ref() { if let Some(closure) = config.completions.external.completer.as_ref() {
if let Some(external_result) = if let Some(external_result) =
self.external_completion(closure, &spans, fake_offset, new_span) self.external_completion(closure, &spans, fake_offset, new_span)
{ {
@ -338,7 +338,9 @@ impl NuCompleter {
} }
// Try to complete using an external completer (if set) // Try to complete using an external completer (if set)
if let Some(closure) = config.external_completer.as_ref() { if let Some(closure) =
config.completions.external.completer.as_ref()
{
if let Some(external_result) = self.external_completion( if let Some(external_result) = self.external_completion(
closure, closure,
&spans, &spans,

View File

@ -167,7 +167,7 @@ pub fn complete_item(
.rfind(|c: &char| is_separator(*c)) .rfind(|c: &char| is_separator(*c))
.unwrap_or(SEP); .unwrap_or(SEP);
let cwd_pathbuf = Path::new(cwd).to_path_buf(); let cwd_pathbuf = Path::new(cwd).to_path_buf();
let ls_colors = (engine_state.config.use_ls_colors_completions let ls_colors = (engine_state.config.completions.use_ls_colors
&& engine_state.config.use_ansi_coloring) && engine_state.config.use_ansi_coloring)
.then(|| { .then(|| {
let ls_colors_env_str = match stack.get_env_var(engine_state, "LS_COLORS") { let ls_colors_env_str = match stack.get_env_var(engine_state, "LS_COLORS") {

View File

@ -245,7 +245,7 @@ pub(crate) fn get_history_path(storage_path: &str, mode: HistoryFileFormat) -> O
nu_path::config_dir().map(|mut history_path| { nu_path::config_dir().map(|mut history_path| {
history_path.push(storage_path); history_path.push(storage_path);
history_path.push(match mode { history_path.push(match mode {
HistoryFileFormat::PlainText => HISTORY_FILE_TXT, HistoryFileFormat::Plaintext => HISTORY_FILE_TXT,
HistoryFileFormat::Sqlite => HISTORY_FILE_SQLITE, HistoryFileFormat::Sqlite => HISTORY_FILE_SQLITE,
}); });
history_path.into() history_path.into()

View File

@ -53,7 +53,7 @@ pub fn evaluate_commands(
// Parse the source code // Parse the source code
let (block, delta) = { let (block, delta) = {
if let Some(ref t_mode) = table_mode { if let Some(ref t_mode) = table_mode {
Arc::make_mut(&mut engine_state.config).table_mode = Arc::make_mut(&mut engine_state.config).table.mode =
t_mode.coerce_str()?.parse().unwrap_or_default(); t_mode.coerce_str()?.parse().unwrap_or_default();
} }
@ -88,7 +88,7 @@ pub fn evaluate_commands(
} }
if let Some(t_mode) = table_mode { if let Some(t_mode) = table_mode {
Arc::make_mut(&mut engine_state.config).table_mode = Arc::make_mut(&mut engine_state.config).table.mode =
t_mode.coerce_str()?.parse().unwrap_or_default(); t_mode.coerce_str()?.parse().unwrap_or_default();
} }

View File

@ -118,13 +118,13 @@ pub(crate) fn update_prompt(
// Now that we have the prompt string lets ansify it. // Now that we have the prompt string lets ansify it.
// <133 A><prompt><133 B><command><133 C><command output> // <133 A><prompt><133 B><command><133 C><command output>
let left_prompt_string = if config.shell_integration_osc633 { let left_prompt_string = if config.shell_integration.osc633 {
if stack.get_env_var(engine_state, "TERM_PROGRAM") == Some(Value::test_string("vscode")) { if stack.get_env_var(engine_state, "TERM_PROGRAM") == Some(Value::test_string("vscode")) {
// We're in vscode and we have osc633 enabled // We're in vscode and we have osc633 enabled
Some(format!( Some(format!(
"{VSCODE_PRE_PROMPT_MARKER}{configured_left_prompt_string}{VSCODE_POST_PROMPT_MARKER}" "{VSCODE_PRE_PROMPT_MARKER}{configured_left_prompt_string}{VSCODE_POST_PROMPT_MARKER}"
)) ))
} else if config.shell_integration_osc133 { } else if config.shell_integration.osc133 {
// If we're in VSCode but we don't find the env var, but we have osc133 set, then use it // If we're in VSCode but we don't find the env var, but we have osc133 set, then use it
Some(format!( Some(format!(
"{PRE_PROMPT_MARKER}{configured_left_prompt_string}{POST_PROMPT_MARKER}" "{PRE_PROMPT_MARKER}{configured_left_prompt_string}{POST_PROMPT_MARKER}"
@ -132,7 +132,7 @@ pub(crate) fn update_prompt(
} else { } else {
configured_left_prompt_string.into() configured_left_prompt_string.into()
} }
} else if config.shell_integration_osc133 { } else if config.shell_integration.osc133 {
Some(format!( Some(format!(
"{PRE_PROMPT_MARKER}{configured_left_prompt_string}{POST_PROMPT_MARKER}" "{PRE_PROMPT_MARKER}{configured_left_prompt_string}{POST_PROMPT_MARKER}"
)) ))

View File

@ -159,8 +159,8 @@ fn add_menu(
stack: &Stack, stack: &Stack,
config: Arc<Config>, config: Arc<Config>,
) -> Result<Reedline, ShellError> { ) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span(); let span = menu.r#type.span();
if let Value::Record { val, .. } = &menu.menu_type { if let Value::Record { val, .. } = &menu.r#type {
let layout = extract_value("layout", val, span)?.to_expanded_string("", &config); let layout = extract_value("layout", val, span)?.to_expanded_string("", &config);
match layout.as_str() { match layout.as_str() {
@ -170,15 +170,15 @@ fn add_menu(
"description" => add_description_menu(line_editor, menu, engine_state, stack, config), "description" => add_description_menu(line_editor, menu, engine_state, stack, config),
_ => Err(ShellError::UnsupportedConfigValue { _ => Err(ShellError::UnsupportedConfigValue {
expected: "columnar, list, ide or description".to_string(), expected: "columnar, list, ide or description".to_string(),
value: menu.menu_type.to_abbreviated_string(&config), value: menu.r#type.to_abbreviated_string(&config),
span: menu.menu_type.span(), span: menu.r#type.span(),
}), }),
} }
} else { } else {
Err(ShellError::UnsupportedConfigValue { Err(ShellError::UnsupportedConfigValue {
expected: "only record type".to_string(), expected: "only record type".to_string(),
value: menu.menu_type.to_abbreviated_string(&config), value: menu.r#type.to_abbreviated_string(&config),
span: menu.menu_type.span(), span: menu.r#type.span(),
}) })
} }
} }
@ -224,11 +224,11 @@ pub(crate) fn add_columnar_menu(
stack: &Stack, stack: &Stack,
config: &Config, config: &Config,
) -> Result<Reedline, ShellError> { ) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span(); let span = menu.r#type.span();
let name = menu.name.to_expanded_string("", config); let name = menu.name.to_expanded_string("", config);
let mut columnar_menu = ColumnarMenu::default().with_name(&name); let mut columnar_menu = ColumnarMenu::default().with_name(&name);
if let Value::Record { val, .. } = &menu.menu_type { if let Value::Record { val, .. } = &menu.r#type {
columnar_menu = match extract_value("columns", val, span) { columnar_menu = match extract_value("columns", val, span) {
Ok(columns) => { Ok(columns) => {
let columns = columns.as_int()?; let columns = columns.as_int()?;
@ -299,8 +299,8 @@ pub(crate) fn add_list_menu(
let name = menu.name.to_expanded_string("", &config); let name = menu.name.to_expanded_string("", &config);
let mut list_menu = ListMenu::default().with_name(&name); let mut list_menu = ListMenu::default().with_name(&name);
let span = menu.menu_type.span(); let span = menu.r#type.span();
if let Value::Record { val, .. } = &menu.menu_type { if let Value::Record { val, .. } = &menu.r#type {
list_menu = match extract_value("page_size", val, span) { list_menu = match extract_value("page_size", val, span) {
Ok(page_size) => { Ok(page_size) => {
let page_size = page_size.as_int()?; let page_size = page_size.as_int()?;
@ -352,11 +352,11 @@ pub(crate) fn add_ide_menu(
stack: &Stack, stack: &Stack,
config: Arc<Config>, config: Arc<Config>,
) -> Result<Reedline, ShellError> { ) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span(); let span = menu.r#type.span();
let name = menu.name.to_expanded_string("", &config); let name = menu.name.to_expanded_string("", &config);
let mut ide_menu = IdeMenu::default().with_name(&name); let mut ide_menu = IdeMenu::default().with_name(&name);
if let Value::Record { val, .. } = &menu.menu_type { if let Value::Record { val, .. } = &menu.r#type {
ide_menu = match extract_value("min_completion_width", val, span) { ide_menu = match extract_value("min_completion_width", val, span) {
Ok(min_completion_width) => { Ok(min_completion_width) => {
let min_completion_width = min_completion_width.as_int()?; let min_completion_width = min_completion_width.as_int()?;
@ -536,8 +536,8 @@ pub(crate) fn add_description_menu(
let name = menu.name.to_expanded_string("", &config); let name = menu.name.to_expanded_string("", &config);
let mut description_menu = DescriptionMenu::default().with_name(&name); let mut description_menu = DescriptionMenu::default().with_name(&name);
let span = menu.menu_type.span(); let span = menu.r#type.span();
if let Value::Record { val, .. } = &menu.menu_type { if let Value::Record { val, .. } = &menu.r#type {
description_menu = match extract_value("columns", val, span) { description_menu = match extract_value("columns", val, span) {
Ok(columns) => { Ok(columns) => {
let columns = columns.as_int()?; let columns = columns.as_int()?;

View File

@ -72,11 +72,11 @@ pub fn evaluate_repl(
let mut entry_num = 0; let mut entry_num = 0;
// Let's grab the shell_integration configs // Let's grab the shell_integration configs
let shell_integration_osc2 = config.shell_integration_osc2; let shell_integration_osc2 = config.shell_integration.osc2;
let shell_integration_osc7 = config.shell_integration_osc7; let shell_integration_osc7 = config.shell_integration.osc7;
let shell_integration_osc9_9 = config.shell_integration_osc9_9; let shell_integration_osc9_9 = config.shell_integration.osc9_9;
let shell_integration_osc133 = config.shell_integration_osc133; let shell_integration_osc133 = config.shell_integration.osc133;
let shell_integration_osc633 = config.shell_integration_osc633; let shell_integration_osc633 = config.shell_integration.osc633;
let nu_prompt = NushellPrompt::new( let nu_prompt = NushellPrompt::new(
shell_integration_osc133, shell_integration_osc133,
@ -322,9 +322,9 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
start_time = std::time::Instant::now(); start_time = std::time::Instant::now();
// Find the configured cursor shapes for each mode // Find the configured cursor shapes for each mode
let cursor_config = CursorConfig { let cursor_config = CursorConfig {
vi_insert: map_nucursorshape_to_cursorshape(config.cursor_shape_vi_insert), vi_insert: map_nucursorshape_to_cursorshape(config.cursor_shape.vi_insert),
vi_normal: map_nucursorshape_to_cursorshape(config.cursor_shape_vi_normal), vi_normal: map_nucursorshape_to_cursorshape(config.cursor_shape.vi_normal),
emacs: map_nucursorshape_to_cursorshape(config.cursor_shape_emacs), emacs: map_nucursorshape_to_cursorshape(config.cursor_shape.emacs),
}; };
perf!("get config/cursor config", start_time, use_color); perf!("get config/cursor config", start_time, use_color);
@ -352,8 +352,8 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
// STACK-REFERENCE 2 // STACK-REFERENCE 2
stack_arc.clone(), stack_arc.clone(),
))) )))
.with_quick_completions(config.quick_completions) .with_quick_completions(config.completions.quick)
.with_partial_completions(config.partial_completions) .with_partial_completions(config.completions.partial)
.with_ansi_colors(config.use_ansi_coloring) .with_ansi_colors(config.use_ansi_coloring)
.with_cwd(Some( .with_cwd(Some(
engine_state engine_state
@ -457,12 +457,12 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
.with_completer(Box::<DefaultCompleter>::default()); .with_completer(Box::<DefaultCompleter>::default());
// Let's grab the shell_integration configs // Let's grab the shell_integration configs
let shell_integration_osc2 = config.shell_integration_osc2; let shell_integration_osc2 = config.shell_integration.osc2;
let shell_integration_osc7 = config.shell_integration_osc7; let shell_integration_osc7 = config.shell_integration.osc7;
let shell_integration_osc9_9 = config.shell_integration_osc9_9; let shell_integration_osc9_9 = config.shell_integration.osc9_9;
let shell_integration_osc133 = config.shell_integration_osc133; let shell_integration_osc133 = config.shell_integration.osc133;
let shell_integration_osc633 = config.shell_integration_osc633; let shell_integration_osc633 = config.shell_integration.osc633;
let shell_integration_reset_application_mode = config.shell_integration_reset_application_mode; let shell_integration_reset_application_mode = config.shell_integration.reset_application_mode;
// TODO: we may clone the stack, this can lead to major performance issues // TODO: we may clone the stack, this can lead to major performance issues
// so we should avoid it or making stack cheaper to clone. // so we should avoid it or making stack cheaper to clone.
@ -1173,7 +1173,7 @@ fn update_line_editor_history(
history_session_id: Option<HistorySessionId>, history_session_id: Option<HistorySessionId>,
) -> Result<Reedline, ErrReport> { ) -> Result<Reedline, ErrReport> {
let history: Box<dyn reedline::History> = match history.file_format { let history: Box<dyn reedline::History> = match history.file_format {
HistoryFileFormat::PlainText => Box::new( HistoryFileFormat::Plaintext => Box::new(
FileBackedHistory::with_file(history.max_size as usize, history_path) FileBackedHistory::with_file(history.max_size as usize, history_path)
.into_diagnostic()?, .into_diagnostic()?,
), ),
@ -1211,10 +1211,10 @@ fn confirm_stdin_is_terminal() -> Result<()> {
fn map_nucursorshape_to_cursorshape(shape: NuCursorShape) -> Option<SetCursorStyle> { fn map_nucursorshape_to_cursorshape(shape: NuCursorShape) -> Option<SetCursorStyle> {
match shape { match shape {
NuCursorShape::Block => Some(SetCursorStyle::SteadyBlock), NuCursorShape::Block => Some(SetCursorStyle::SteadyBlock),
NuCursorShape::UnderScore => Some(SetCursorStyle::SteadyUnderScore), NuCursorShape::Underscore => Some(SetCursorStyle::SteadyUnderScore),
NuCursorShape::Line => Some(SetCursorStyle::SteadyBar), NuCursorShape::Line => Some(SetCursorStyle::SteadyBar),
NuCursorShape::BlinkBlock => Some(SetCursorStyle::BlinkingBlock), NuCursorShape::BlinkBlock => Some(SetCursorStyle::BlinkingBlock),
NuCursorShape::BlinkUnderScore => Some(SetCursorStyle::BlinkingUnderScore), NuCursorShape::BlinkUnderscore => Some(SetCursorStyle::BlinkingUnderScore),
NuCursorShape::BlinkLine => Some(SetCursorStyle::BlinkingBar), NuCursorShape::BlinkLine => Some(SetCursorStyle::BlinkingBar),
NuCursorShape::Inherit => None, NuCursorShape::Inherit => None,
} }

View File

@ -167,7 +167,7 @@ fn rm(
} }
let span = call.head; let span = call.head;
let rm_always_trash = stack.get_config(engine_state).rm_always_trash; let rm_always_trash = stack.get_config(engine_state).rm.always_trash;
if !TRASH_SUPPORTED { if !TRASH_SUPPORTED {
if rm_always_trash { if rm_always_trash {

View File

@ -258,7 +258,7 @@ fn parse_table_config(
let flatten_separator: Option<String> = call.get_flag(state, stack, "flatten-separator")?; let flatten_separator: Option<String> = call.get_flag(state, stack, "flatten-separator")?;
let abbrivation: Option<usize> = call let abbrivation: Option<usize> = call
.get_flag(state, stack, "abbreviated")? .get_flag(state, stack, "abbreviated")?
.or_else(|| stack.get_config(state).table_abbreviation_threshold); .or_else(|| stack.get_config(state).table.abbreviated_row_count);
let table_view = match (expand, collapse) { let table_view = match (expand, collapse) {
(false, false) => TableView::General, (false, false) => TableView::General,
(_, true) => TableView::Collapsed, (_, true) => TableView::Collapsed,
@ -269,7 +269,7 @@ fn parse_table_config(
}, },
}; };
let theme = let theme =
get_theme_flag(call, state, stack)?.unwrap_or_else(|| stack.get_config(state).table_mode); get_theme_flag(call, state, stack)?.unwrap_or_else(|| stack.get_config(state).table.mode);
let index = get_index_flag(call, state, stack)?; let index = get_index_flag(call, state, stack)?;
let term_width = get_width_param(width_param); let term_width = get_width_param(width_param);
@ -520,7 +520,7 @@ fn handle_record(
} }
} }
let indent = (config.table_indent.left, config.table_indent.right); let indent = (config.table.padding.left, config.table.padding.right);
let opts = TableOpts::new( let opts = TableOpts::new(
&config, &config,
styles, styles,
@ -821,7 +821,7 @@ impl PagingTableCreator {
self.engine_state.signals(), self.engine_state.signals(),
self.head, self.head,
self.cfg.term_width, self.cfg.term_width,
(cfg.table_indent.left, cfg.table_indent.right), (cfg.table.padding.left, cfg.table.padding.right),
self.cfg.theme, self.cfg.theme,
self.cfg.index.unwrap_or(0) + self.row_offset, self.cfg.index.unwrap_or(0) + self.row_offset,
self.cfg.index.is_none(), self.cfg.index.is_none(),
@ -1010,7 +1010,7 @@ fn render_path_name(
ls_colors: &LsColors, ls_colors: &LsColors,
span: Span, span: Span,
) -> Option<Value> { ) -> Option<Value> {
if !config.use_ls_colors { if !config.ls.use_ls_colors {
return None; return None;
} }
@ -1024,10 +1024,10 @@ fn render_path_name(
// clickable links don't work in remote SSH sessions // clickable links don't work in remote SSH sessions
let in_ssh_session = std::env::var("SSH_CLIENT").is_ok(); let in_ssh_session = std::env::var("SSH_CLIENT").is_ok();
//TODO: Deprecated show_clickable_links_in_ls in favor of shell_integration_osc8 //TODO: Deprecated show_clickable_links_in_ls in favor of shell_integration_osc8
let show_clickable_links = config.show_clickable_links_in_ls let show_clickable_links = config.ls.clickable_links
&& !in_ssh_session && !in_ssh_session
&& has_metadata && has_metadata
&& config.shell_integration_osc8; && config.shell_integration.osc8;
let ansi_style = style.map(Style::to_nu_ansi_term_style).unwrap_or_default(); let ansi_style = style.map(Style::to_nu_ansi_term_style).unwrap_or_default();
@ -1074,7 +1074,7 @@ fn create_empty_placeholder(
stack: &Stack, stack: &Stack,
) -> String { ) -> String {
let config = stack.get_config(engine_state); let config = stack.get_config(engine_state);
if !config.table_show_empty { if !config.table.show_empty {
return String::new(); return String::new();
} }

View File

@ -126,7 +126,7 @@ fn derive_struct_from_value(
/// .remove("favorite_toy") /// .remove("favorite_toy")
/// .map(|v| <#ty as nu_protocol::FromValue>::from_value(v)) /// .map(|v| <#ty as nu_protocol::FromValue>::from_value(v))
/// .transpose()? /// .transpose()?
/// .flatten(), /// .flatten(),
/// }) /// })
/// } /// }
/// } /// }
@ -491,7 +491,7 @@ fn enum_from_value(data: &DataEnum, attrs: &[Attribute]) -> Result {
} }
/// Implements `FromValue::expected_type` for enums. /// Implements `FromValue::expected_type` for enums.
/// ///
/// Since it's difficult to name the type of an enum in the current type system, we want to use the /// Since it's difficult to name the type of an enum in the current type system, we want to use the
/// default implementation if `#[nu_value(type_name = "...")]` was *not* given. /// default implementation if `#[nu_value(type_name = "...")]` was *not* given.
/// For that, a `None` value is returned, for a passed type name we return something like this: /// For that, a `None` value is returned, for a passed type name we return something like this:

View File

@ -1,5 +1,6 @@
use proc_macro2::Span; use proc_macro2::Span;
use std::collections::HashMap; use std::collections::HashMap;
use syn::ext::IdentExt;
use syn::Ident; use syn::Ident;
use crate::attributes::{ContainerAttributes, MemberAttributes}; use crate::attributes::{ContainerAttributes, MemberAttributes};
@ -33,18 +34,17 @@ impl NameResolver {
/// If a duplicate identifier is detected, it returns [`DeriveError::NonUniqueName`]. /// If a duplicate identifier is detected, it returns [`DeriveError::NonUniqueName`].
pub fn resolve_ident<M>( pub fn resolve_ident<M>(
&mut self, &mut self,
ident: &'_ Ident, ident: &Ident,
container_attrs: &'_ ContainerAttributes, container_attrs: &ContainerAttributes,
member_attrs: &'_ MemberAttributes, member_attrs: &MemberAttributes,
default: impl Into<Option<Case>>, default: impl Into<Option<Case>>,
) -> Result<String, DeriveError<M>> { ) -> Result<String, DeriveError<M>> {
let span = ident.span(); let span = ident.span();
let rename_all = container_attrs.rename_all; let ident = if let Some(rename) = &member_attrs.rename {
let rename = member_attrs.rename.as_ref(); rename.clone()
let ident = match (rename, rename_all) { } else {
(Some(rename), _) => rename.to_string(), let case = container_attrs.rename_all.or(default.into());
(None, Some(case)) => ident.to_case(case), ident.unraw().to_case(case)
(None, None) => ident.to_case(default),
}; };
if let Some(seen) = self.seen_names.get(&ident) { if let Some(seen) = self.seen_names.get(&ident) {

View File

@ -177,8 +177,8 @@ impl ExploreConfig {
pub fn from_nu_config(config: &Config) -> Self { pub fn from_nu_config(config: &Config) -> Self {
let mut ret = Self::default(); let mut ret = Self::default();
ret.table.column_padding_left = config.table_indent.left; ret.table.column_padding_left = config.table.padding.left;
ret.table.column_padding_right = config.table_indent.right; ret.table.column_padding_right = config.table.padding.right;
let explore_cfg_hash_map = config.explore.clone(); let explore_cfg_hash_map = config.explore.clone();
let colors = get_color_map(&explore_cfg_hash_map); let colors = get_color_map(&explore_cfg_hash_map);

View File

@ -36,8 +36,8 @@ fn try_build_map(
signals, signals,
Span::unknown(), Span::unknown(),
usize::MAX, usize::MAX,
(config.table_indent.left, config.table_indent.right), (config.table.padding.left, config.table.padding.right),
config.table_mode, config.table.mode,
0, 0,
false, false,
); );
@ -63,8 +63,8 @@ fn try_build_list(
signals, signals,
Span::unknown(), Span::unknown(),
usize::MAX, usize::MAX,
(config.table_indent.left, config.table_indent.right), (config.table.padding.left, config.table.padding.right),
config.table_mode, config.table.mode,
0, 0,
false, false,
); );

View File

@ -1,12 +1,8 @@
use std::str::FromStr; use super::prelude::*;
use crate as nu_protocol;
use crate::engine::Closure;
use serde::{Deserialize, Serialize}; #[derive(Clone, Copy, Debug, Default, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
use crate::{record, Config, Span, Value};
use super::helper::ReconstructVal;
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default)]
pub enum CompletionAlgorithm { pub enum CompletionAlgorithm {
#[default] #[default]
Prefix, Prefix,
@ -25,17 +21,7 @@ impl FromStr for CompletionAlgorithm {
} }
} }
impl ReconstructVal for CompletionAlgorithm { #[derive(Clone, Copy, Debug, Default, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
fn reconstruct_value(&self, span: Span) -> Value {
let str = match self {
CompletionAlgorithm::Prefix => "prefix",
CompletionAlgorithm::Fuzzy => "fuzzy",
};
Value::string(str, span)
}
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default, PartialEq)]
pub enum CompletionSort { pub enum CompletionSort {
#[default] #[default]
Smart, Smart,
@ -54,31 +40,44 @@ impl FromStr for CompletionSort {
} }
} }
impl ReconstructVal for CompletionSort { #[derive(Clone, Debug, IntoValue, Serialize, Deserialize)]
fn reconstruct_value(&self, span: Span) -> Value { pub struct ExternalCompleterConfig {
let str = match self { pub enable: bool,
Self::Smart => "smart", pub max_results: i64,
Self::Alphabetical => "alphabetical", pub completer: Option<Closure>,
}; }
Value::string(str, span)
impl Default for ExternalCompleterConfig {
fn default() -> Self {
Self {
enable: true,
max_results: 100,
completer: None,
}
} }
} }
pub(super) fn reconstruct_external_completer(config: &Config, span: Span) -> Value { #[derive(Clone, Debug, IntoValue, Serialize, Deserialize)]
if let Some(closure) = config.external_completer.as_ref() { pub struct CompleterConfig {
Value::closure(closure.clone(), span) pub sort: CompletionSort,
} else { pub case_sensitive: bool,
Value::nothing(span) pub quick: bool,
} pub partial: bool,
pub algorithm: CompletionAlgorithm,
pub external: ExternalCompleterConfig,
pub use_ls_colors: bool,
} }
pub(super) fn reconstruct_external(config: &Config, span: Span) -> Value { impl Default for CompleterConfig {
Value::record( fn default() -> Self {
record! { Self {
"max_results" => Value::int(config.max_external_completion_results, span), sort: CompletionSort::default(),
"completer" => reconstruct_external_completer(config, span), case_sensitive: false,
"enable" => Value::bool(config.enable_external_completion, span), quick: true,
}, partial: true,
span, algorithm: CompletionAlgorithm::default(),
) external: ExternalCompleterConfig::default(),
use_ls_colors: true,
}
}
} }

View File

@ -0,0 +1,8 @@
use super::prelude::*;
use crate as nu_protocol;
#[derive(Clone, Debug, Default, IntoValue, Serialize, Deserialize)]
pub struct DatetimeFormatConfig {
pub normal: Option<String>,
pub table: Option<String>,
}

View File

@ -0,0 +1,17 @@
use super::prelude::*;
use crate as nu_protocol;
#[derive(Clone, Debug, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub struct FilesizeConfig {
pub metric: bool,
pub format: String,
}
impl Default for FilesizeConfig {
fn default() -> Self {
Self {
metric: false,
format: "auto".into(),
}
}
}

View File

@ -1,17 +1,13 @@
use crate::{Record, ShellError, Span, Value}; use crate::{IntoValue, Record, ShellError, Span, Value};
use std::{collections::HashMap, fmt::Display, str::FromStr}; use std::{collections::HashMap, fmt::Display, str::FromStr};
pub(super) trait ReconstructVal {
fn reconstruct_value(&self, span: Span) -> Value;
}
pub(super) fn process_string_enum<T, E>( pub(super) fn process_string_enum<T, E>(
config_point: &mut T, config_point: &mut T,
config_path: &[&str], config_path: &[&str],
value: &mut Value, value: &mut Value,
errors: &mut Vec<ShellError>, errors: &mut Vec<ShellError>,
) where ) where
T: FromStr<Err = E> + ReconstructVal, T: FromStr<Err = E> + Clone + IntoValue,
E: Display, E: Display,
{ {
let span = value.span(); let span = value.span();
@ -32,7 +28,7 @@ pub(super) fn process_string_enum<T, E>(
inner: vec![], inner: vec![],
}); });
// Reconstruct // Reconstruct
*value = config_point.reconstruct_value(span); *value = config_point.clone().into_value(span);
} }
} }
} else { } else {
@ -44,7 +40,7 @@ pub(super) fn process_string_enum<T, E>(
inner: vec![], inner: vec![],
}); });
// Reconstruct // Reconstruct
*value = config_point.reconstruct_value(span); *value = config_point.clone().into_value(span);
} }
} }

View File

@ -0,0 +1,41 @@
use super::prelude::*;
use crate as nu_protocol;
#[derive(Clone, Copy, Debug, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub enum HistoryFileFormat {
/// Store history as an SQLite database with additional context
Sqlite,
/// store history as a plain text file where every line is one command (without any context such as timestamps)
Plaintext,
}
impl FromStr for HistoryFileFormat {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"sqlite" => Ok(Self::Sqlite),
"plaintext" => Ok(Self::Plaintext),
_ => Err("expected either 'sqlite' or 'plaintext'"),
}
}
}
#[derive(Clone, Copy, Debug, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub struct HistoryConfig {
pub max_size: i64,
pub sync_on_enter: bool,
pub file_format: HistoryFileFormat,
pub isolation: bool,
}
impl Default for HistoryConfig {
fn default() -> Self {
Self {
max_size: 100_000,
sync_on_enter: true,
file_format: HistoryFileFormat::Plaintext,
isolation: false,
}
}
}

View File

@ -1,8 +1,9 @@
use crate::{Config, Record, ShellError, Span, Value}; use super::prelude::*;
use serde::{Deserialize, Serialize}; use crate as nu_protocol;
use crate::ShellError;
/// Definition of a parsed hook from the config object /// Definition of a parsed hook from the config object
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Clone, Debug, IntoValue, PartialEq, Serialize, Deserialize)]
pub struct Hooks { pub struct Hooks {
pub pre_prompt: Option<Value>, pub pre_prompt: Option<Value>,
pub pre_execution: Option<Value>, pub pre_execution: Option<Value>,
@ -65,24 +66,3 @@ pub(super) fn create_hooks(value: &Value) -> Result<Hooks, ShellError> {
}), }),
} }
} }
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)
}

View File

@ -0,0 +1,17 @@
use super::prelude::*;
use crate as nu_protocol;
#[derive(Clone, Copy, Debug, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub struct LsConfig {
pub use_ls_colors: bool,
pub clickable_links: bool,
}
impl Default for LsConfig {
fn default() -> Self {
Self {
use_ls_colors: true,
clickable_links: true,
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,7 @@
use super::helper::ReconstructVal; use super::prelude::*;
use crate::{Config, Record, Span, Value}; use crate as nu_protocol;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
#[derive(Serialize, Deserialize, Clone, Debug, Copy)] #[derive(Clone, Copy, Debug, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub enum ErrorStyle { pub enum ErrorStyle {
Plain, Plain,
Fancy, Fancy,
@ -20,26 +18,3 @@ impl FromStr for ErrorStyle {
} }
} }
} }
impl ReconstructVal for ErrorStyle {
fn reconstruct_value(&self, span: Span) -> Value {
Value::string(
match self {
ErrorStyle::Fancy => "fancy",
ErrorStyle::Plain => "plain",
},
span,
)
}
}
pub(super) fn reconstruct_datetime_format(config: &Config, span: Span) -> Value {
let mut record = Record::new();
if let Some(normal) = &config.datetime_normal_format {
record.push("normal", Value::string(normal, span));
}
if let Some(table) = &config.datetime_table_format {
record.push("table", Value::string(table, span));
}
Value::record(record, span)
}

View File

@ -1,15 +1,11 @@
use super::helper::{process_bool_config, report_invalid_key, report_invalid_value};
use super::prelude::*;
use crate as nu_protocol;
use crate::ShellError;
use std::collections::HashMap; use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::{record, ShellError, Span, Value};
use super::helper::{
process_bool_config, report_invalid_key, report_invalid_value, ReconstructVal,
};
/// Configures when plugins should be stopped if inactive /// Configures when plugins should be stopped if inactive
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[derive(Clone, Debug, Default, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub struct PluginGcConfigs { pub struct PluginGcConfigs {
/// The config to use for plugins not otherwise specified /// The config to use for plugins not otherwise specified
pub default: PluginGcConfig, pub default: PluginGcConfig,
@ -61,23 +57,11 @@ impl PluginGcConfigs {
}); });
} else { } else {
report_invalid_value("should be a record", value.span(), errors); report_invalid_value("should be a record", value.span(), errors);
*value = self.reconstruct_value(value.span()); *value = self.clone().into_value(value.span());
} }
} }
} }
impl ReconstructVal for PluginGcConfigs {
fn reconstruct_value(&self, span: Span) -> Value {
Value::record(
record! {
"default" => self.default.reconstruct_value(span),
"plugins" => reconstruct_plugins(&self.plugins, span),
},
span,
)
}
}
fn process_plugins( fn process_plugins(
path: &[&str], path: &[&str],
value: &mut Value, value: &mut Value,
@ -100,7 +84,7 @@ fn process_plugins(
report_invalid_value("should be a record", value.span(), errors); report_invalid_value("should be a record", value.span(), errors);
if let Some(conf) = plugins.get(key) { if let Some(conf) = plugins.get(key) {
// Reconstruct the value if it existed before // Reconstruct the value if it existed before
*value = conf.reconstruct_value(value.span()); *value = conf.clone().into_value(value.span());
true true
} else { } else {
// Remove it if it didn't // Remove it if it didn't
@ -111,18 +95,8 @@ fn process_plugins(
} }
} }
fn reconstruct_plugins(plugins: &HashMap<String, PluginGcConfig>, span: Span) -> Value {
Value::record(
plugins
.iter()
.map(|(key, val)| (key.to_owned(), val.reconstruct_value(span)))
.collect(),
span,
)
}
/// Configures when a plugin should be stopped if inactive /// Configures when a plugin should be stopped if inactive
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PluginGcConfig { pub struct PluginGcConfig {
/// True if the plugin should be stopped automatically /// True if the plugin should be stopped automatically
pub enabled: bool, pub enabled: bool,
@ -139,6 +113,16 @@ impl Default for PluginGcConfig {
} }
} }
impl IntoValue for PluginGcConfig {
fn into_value(self, span: Span) -> Value {
record! {
"enabled" => self.enabled.into_value(span),
"stop_after" => Value::duration(self.stop_after, span),
}
.into_value(span)
}
}
impl PluginGcConfig { impl PluginGcConfig {
fn process(&mut self, path: &[&str], value: &mut Value, errors: &mut Vec<ShellError>) { fn process(&mut self, path: &[&str], value: &mut Value, errors: &mut Vec<ShellError>) {
if let Value::Record { val, .. } = value { if let Value::Record { val, .. } = value {
@ -177,23 +161,11 @@ impl PluginGcConfig {
}) })
} else { } else {
report_invalid_value("should be a record", value.span(), errors); report_invalid_value("should be a record", value.span(), errors);
*value = self.reconstruct_value(value.span()); *value = self.clone().into_value(value.span());
} }
} }
} }
impl ReconstructVal for PluginGcConfig {
fn reconstruct_value(&self, span: Span) -> Value {
Value::record(
record! {
"enabled" => Value::bool(self.enabled, span),
"stop_after" => Value::duration(self.stop_after, span),
},
span,
)
}
}
fn join_path<'a>(a: &[&'a str], b: &[&'a str]) -> Vec<&'a str> { fn join_path<'a>(a: &[&'a str], b: &[&'a str]) -> Vec<&'a str> {
a.iter().copied().chain(b.iter().copied()).collect() a.iter().copied().chain(b.iter().copied()).collect()
} }
@ -201,6 +173,7 @@ fn join_path<'a>(a: &[&'a str], b: &[&'a str]) -> Vec<&'a str> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use nu_protocol::{record, Span};
fn test_pair() -> (PluginGcConfigs, Value) { fn test_pair() -> (PluginGcConfigs, Value) {
( (
@ -247,6 +220,6 @@ mod tests {
#[test] #[test]
fn reconstruct() { fn reconstruct() {
let (input, expected) = test_pair(); let (input, expected) = test_pair();
assert_eq!(expected, input.reconstruct_value(Span::test_data())); assert_eq!(expected, input.into_value(Span::test_data()));
} }
} }

View File

@ -0,0 +1,3 @@
pub use crate::{record, IntoValue, Span, Value};
pub use serde::{Deserialize, Serialize};
pub use std::str::FromStr;

View File

@ -1,11 +1,9 @@
use std::str::FromStr; use super::{extract_value, prelude::*};
use crate as nu_protocol;
use super::{extract_value, helper::ReconstructVal}; use crate::ShellError;
use crate::{record, Config, ShellError, Span, Value};
use serde::{Deserialize, Serialize};
/// Definition of a parsed keybinding from the config object /// Definition of a parsed keybinding from the config object
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Clone, Debug, IntoValue, Serialize, Deserialize)]
pub struct ParsedKeybinding { pub struct ParsedKeybinding {
pub modifier: Value, pub modifier: Value,
pub keycode: Value, pub keycode: Value,
@ -14,23 +12,23 @@ pub struct ParsedKeybinding {
} }
/// Definition of a parsed menu from the config object /// Definition of a parsed menu from the config object
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Clone, Debug, IntoValue, Serialize, Deserialize)]
pub struct ParsedMenu { pub struct ParsedMenu {
pub name: Value, pub name: Value,
pub marker: Value, pub marker: Value,
pub only_buffer_difference: Value, pub only_buffer_difference: Value,
pub style: Value, pub style: Value,
pub menu_type: Value, pub r#type: Value,
pub source: Value, pub source: Value,
} }
/// Definition of a Nushell CursorShape (to be mapped to crossterm::cursor::CursorShape) /// Definition of a Nushell CursorShape (to be mapped to crossterm::cursor::CursorShape)
#[derive(Serialize, Deserialize, Clone, Debug, Copy, Default)] #[derive(Clone, Copy, Debug, Default, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub enum NuCursorShape { pub enum NuCursorShape {
UnderScore, Underscore,
Line, Line,
Block, Block,
BlinkUnderScore, BlinkUnderscore,
BlinkLine, BlinkLine,
BlinkBlock, BlinkBlock,
#[default] #[default]
@ -44,66 +42,24 @@ impl FromStr for NuCursorShape {
match s.to_ascii_lowercase().as_str() { match s.to_ascii_lowercase().as_str() {
"line" => Ok(NuCursorShape::Line), "line" => Ok(NuCursorShape::Line),
"block" => Ok(NuCursorShape::Block), "block" => Ok(NuCursorShape::Block),
"underscore" => Ok(NuCursorShape::UnderScore), "underscore" => Ok(NuCursorShape::Underscore),
"blink_line" => Ok(NuCursorShape::BlinkLine), "blink_line" => Ok(NuCursorShape::BlinkLine),
"blink_block" => Ok(NuCursorShape::BlinkBlock), "blink_block" => Ok(NuCursorShape::BlinkBlock),
"blink_underscore" => Ok(NuCursorShape::BlinkUnderScore), "blink_underscore" => Ok(NuCursorShape::BlinkUnderscore),
"inherit" => Ok(NuCursorShape::Inherit), "inherit" => Ok(NuCursorShape::Inherit),
_ => Err("expected either 'line', 'block', 'underscore', 'blink_line', 'blink_block', 'blink_underscore' or 'inherit'"), _ => Err("expected either 'line', 'block', 'underscore', 'blink_line', 'blink_block', 'blink_underscore' or 'inherit'"),
} }
} }
} }
impl ReconstructVal for NuCursorShape { #[derive(Clone, Copy, Debug, Default, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
fn reconstruct_value(&self, span: Span) -> Value { pub struct CursorShapeConfig {
Value::string( pub emacs: NuCursorShape,
match self { pub vi_insert: NuCursorShape,
NuCursorShape::Line => "line", pub vi_normal: NuCursorShape,
NuCursorShape::Block => "block",
NuCursorShape::UnderScore => "underscore",
NuCursorShape::BlinkLine => "blink_line",
NuCursorShape::BlinkBlock => "blink_block",
NuCursorShape::BlinkUnderScore => "blink_underscore",
NuCursorShape::Inherit => "inherit",
},
span,
)
}
} }
#[derive(Serialize, Deserialize, Clone, Debug, Copy)] #[derive(Clone, Copy, Debug, Default, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub enum HistoryFileFormat {
/// Store history as an SQLite database with additional context
Sqlite,
/// store history as a plain text file where every line is one command (without any context such as timestamps)
PlainText,
}
impl FromStr for HistoryFileFormat {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"sqlite" => Ok(Self::Sqlite),
"plaintext" => Ok(Self::PlainText),
_ => Err("expected either 'sqlite' or 'plaintext'"),
}
}
}
impl ReconstructVal for HistoryFileFormat {
fn reconstruct_value(&self, span: Span) -> Value {
Value::string(
match self {
HistoryFileFormat::Sqlite => "sqlite",
HistoryFileFormat::PlainText => "plaintext",
},
span,
)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default, Copy)]
pub enum EditBindings { pub enum EditBindings {
Vi, Vi,
#[default] #[default]
@ -122,18 +78,6 @@ impl FromStr for EditBindings {
} }
} }
impl ReconstructVal for EditBindings {
fn reconstruct_value(&self, span: Span) -> Value {
Value::string(
match self {
EditBindings::Vi => "vi",
EditBindings::Emacs => "emacs",
},
span,
)
}
}
/// Parses the config object to extract the strings that will compose a keybinding for reedline /// Parses the config object to extract the strings that will compose a keybinding for reedline
pub(super) fn create_keybindings(value: &Value) -> Result<Vec<ParsedKeybinding>, ShellError> { pub(super) fn create_keybindings(value: &Value) -> Result<Vec<ParsedKeybinding>, ShellError> {
let span = value.span(); let span = value.span();
@ -172,34 +116,6 @@ pub(super) fn create_keybindings(value: &Value) -> Result<Vec<ParsedKeybinding>,
} }
} }
pub(super) fn reconstruct_keybindings(config: &Config, span: Span) -> Value {
Value::list(
config
.keybindings
.iter()
.map(
|ParsedKeybinding {
modifier,
keycode,
mode,
event,
}| {
Value::record(
record! {
"modifier" => modifier.clone(),
"keycode" => keycode.clone(),
"mode" => mode.clone(),
"event" => event.clone(),
},
span,
)
},
)
.collect(),
span,
)
}
/// Parses the config object to extract the strings that will compose a keybinding for reedline /// Parses the config object to extract the strings that will compose a keybinding for reedline
pub fn create_menus(value: &Value) -> Result<Vec<ParsedMenu>, ShellError> { pub fn create_menus(value: &Value) -> Result<Vec<ParsedMenu>, ShellError> {
let span = value.span(); let span = value.span();
@ -211,7 +127,7 @@ pub fn create_menus(value: &Value) -> Result<Vec<ParsedMenu>, ShellError> {
let only_buffer_difference = let only_buffer_difference =
extract_value("only_buffer_difference", val, span)?.clone(); extract_value("only_buffer_difference", val, span)?.clone();
let style = extract_value("style", val, span)?.clone(); let style = extract_value("style", val, span)?.clone();
let menu_type = extract_value("type", val, span)?.clone(); let r#type = extract_value("type", val, span)?.clone();
// Source is an optional value // Source is an optional value
let source = match extract_value("source", val, span) { let source = match extract_value("source", val, span) {
@ -224,7 +140,7 @@ pub fn create_menus(value: &Value) -> Result<Vec<ParsedMenu>, ShellError> {
only_buffer_difference, only_buffer_difference,
marker, marker,
style, style,
menu_type, r#type,
source, source,
}; };
@ -243,35 +159,3 @@ pub fn create_menus(value: &Value) -> Result<Vec<ParsedMenu>, ShellError> {
_ => Ok(Vec::new()), _ => Ok(Vec::new()),
} }
} }
pub(super) fn reconstruct_menus(config: &Config, span: Span) -> Value {
Value::list(
config
.menus
.iter()
.map(
|ParsedMenu {
name,
only_buffer_difference,
marker,
style,
menu_type, // WARNING: this is not the same name as what is used in Config.nu! ("type")
source,
}| {
Value::record(
record! {
"name" => name.clone(),
"only_buffer_difference" => only_buffer_difference.clone(),
"marker" => marker.clone(),
"style" => style.clone(),
"type" => menu_type.clone(),
"source" => source.clone(),
},
span,
)
},
)
.collect(),
span,
)
}

View File

@ -0,0 +1,16 @@
use super::prelude::*;
use crate as nu_protocol;
#[derive(Clone, Copy, Debug, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub struct RmConfig {
pub always_trash: bool,
}
#[allow(clippy::derivable_impls)]
impl Default for RmConfig {
fn default() -> Self {
Self {
always_trash: false,
}
}
}

View File

@ -0,0 +1,28 @@
use super::prelude::*;
use crate as nu_protocol;
#[derive(Clone, Copy, Debug, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub struct ShellIntegrationConfig {
pub osc2: bool,
pub osc7: bool,
pub osc8: bool,
pub osc9_9: bool,
pub osc133: bool,
pub osc633: bool,
pub reset_application_mode: bool,
}
#[allow(clippy::derivable_impls)]
impl Default for ShellIntegrationConfig {
fn default() -> Self {
Self {
osc2: false,
osc7: false,
osc8: false,
osc9_9: false,
osc133: false,
osc633: false,
reset_application_mode: false,
}
}
}

View File

@ -1,9 +1,8 @@
use super::helper::ReconstructVal; use super::prelude::*;
use crate::{record, Config, ShellError, Span, Value}; use crate as nu_protocol;
use serde::{Deserialize, Serialize}; use crate::ShellError;
use std::str::FromStr;
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub enum TableMode { pub enum TableMode {
Basic, Basic,
Thin, Thin,
@ -51,33 +50,7 @@ impl FromStr for TableMode {
} }
} }
impl ReconstructVal for TableMode { #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
fn reconstruct_value(&self, span: Span) -> Value {
Value::string(
match self {
TableMode::Basic => "basic",
TableMode::Thin => "thin",
TableMode::Light => "light",
TableMode::Compact => "compact",
TableMode::WithLove => "with_love",
TableMode::CompactDouble => "compact_double",
TableMode::Rounded => "rounded",
TableMode::Reinforced => "reinforced",
TableMode::Heavy => "heavy",
TableMode::None => "none",
TableMode::Psql => "psql",
TableMode::Markdown => "markdown",
TableMode::Dots => "dots",
TableMode::Restructured => "restructured",
TableMode::AsciiRounded => "ascii_rounded",
TableMode::BasicCompact => "basic_compact",
},
span,
)
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum FooterMode { pub enum FooterMode {
/// Never show the footer /// Never show the footer
Never, Never,
@ -108,21 +81,18 @@ impl FromStr for FooterMode {
} }
} }
impl ReconstructVal for FooterMode { impl IntoValue for FooterMode {
fn reconstruct_value(&self, span: Span) -> Value { fn into_value(self, span: Span) -> Value {
Value::string( match self {
match self { FooterMode::Always => "always".into_value(span),
FooterMode::Always => "always".to_string(), FooterMode::Never => "never".into_value(span),
FooterMode::Never => "never".to_string(), FooterMode::Auto => "auto".into_value(span),
FooterMode::Auto => "auto".to_string(), FooterMode::RowCount(c) => c.to_string().into_value(span),
FooterMode::RowCount(c) => c.to_string(), }
},
span,
)
} }
} }
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Clone, Copy, Debug, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
pub enum TableIndexMode { pub enum TableIndexMode {
/// Always show indexes /// Always show indexes
Always, Always,
@ -145,22 +115,9 @@ impl FromStr for TableIndexMode {
} }
} }
impl ReconstructVal for TableIndexMode {
fn reconstruct_value(&self, span: Span) -> Value {
Value::string(
match self {
TableIndexMode::Always => "always",
TableIndexMode::Never => "never",
TableIndexMode::Auto => "auto",
},
span,
)
}
}
/// A Table view configuration, for a situation where /// A Table view configuration, for a situation where
/// we need to limit cell width in order to adjust for a terminal size. /// we need to limit cell width in order to adjust for a terminal size.
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum TrimStrategy { pub enum TrimStrategy {
/// Wrapping strategy. /// Wrapping strategy.
/// ///
@ -196,7 +153,7 @@ impl TrimStrategy {
impl Default for TrimStrategy { impl Default for TrimStrategy {
fn default() -> Self { fn default() -> Self {
TrimStrategy::Wrap { Self::Wrap {
try_to_keep_words: true, try_to_keep_words: true,
} }
} }
@ -289,45 +246,89 @@ fn try_parse_trim_methodology(value: &Value) -> Option<TrimStrategy> {
None None
} }
pub(super) fn reconstruct_trim_strategy(config: &Config, span: Span) -> Value { impl IntoValue for TrimStrategy {
match &config.trim_strategy { fn into_value(self, span: Span) -> Value {
TrimStrategy::Wrap { try_to_keep_words } => Value::record( match self {
record! { TrimStrategy::Wrap { try_to_keep_words } => {
"methodology" => Value::string("wrapping", span), record! {
"wrapping_try_keep_words" => Value::bool(*try_to_keep_words, span), "methodology" => "wrapping".into_value(span),
}, "wrapping_try_keep_words" => try_to_keep_words.into_value(span),
span, }
), }
TrimStrategy::Truncate { suffix } => Value::record( TrimStrategy::Truncate { suffix } => {
match suffix { record! {
Some(s) => record! { "methodology" => "truncating".into_value(span),
"methodology" => Value::string("truncating", span), "truncating_suffix" => suffix.into_value(span),
"truncating_suffix" => Value::string(s.clone(), span), }
}, }
None => record! { }
"methodology" => Value::string("truncating", span), .into_value(span)
"truncating_suffix" => Value::nothing(span),
},
},
span,
),
} }
} }
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct TableIndent { pub struct TableIndent {
pub left: usize, pub left: usize,
pub right: usize, pub right: usize,
} }
pub(super) fn reconstruct_padding(config: &Config, span: Span) -> Value { impl IntoValue for TableIndent {
// For better completions always reconstruct the record version even though unsigned int would fn into_value(self, span: Span) -> Value {
// be supported, `as` conversion is sane as it came from an i64 original record! {
Value::record( "left" => (self.left as i64).into_value(span),
record!( "right" => (self.right as i64).into_value(span),
"left" => Value::int(config.table_indent.left as i64, span), }
"right" => Value::int(config.table_indent.right as i64, span), .into_value(span)
), }
span, }
)
impl Default for TableIndent {
fn default() -> Self {
Self { left: 1, right: 1 }
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct TableConfig {
pub mode: TableMode,
pub index_mode: TableIndexMode,
pub show_empty: bool,
pub padding: TableIndent,
pub trim: TrimStrategy,
pub header_on_separator: bool,
pub abbreviated_row_count: Option<usize>,
}
impl IntoValue for TableConfig {
fn into_value(self, span: Span) -> Value {
let abbv_count = self
.abbreviated_row_count
.map(|t| t as i64)
.into_value(span);
record! {
"mode" => self.mode.into_value(span),
"index_mode" => self.index_mode.into_value(span),
"show_empty" => self.show_empty.into_value(span),
"padding" => self.padding.into_value(span),
"trim" => self.trim.into_value(span),
"header_on_separator" => self.header_on_separator.into_value(span),
"abbreviated_row_count" => abbv_count,
}
.into_value(span)
}
}
impl Default for TableConfig {
fn default() -> Self {
Self {
mode: TableMode::Rounded,
index_mode: TableIndexMode::Always,
show_empty: true,
trim: TrimStrategy::default(),
header_on_separator: false,
padding: TableIndent::default(),
abbreviated_row_count: None,
}
}
} }

View File

@ -95,7 +95,7 @@ pub(crate) fn create_nu_constant(engine_state: &EngineState, span: Span) -> Valu
HistoryFileFormat::Sqlite => { HistoryFileFormat::Sqlite => {
path.push("history.sqlite3"); path.push("history.sqlite3");
} }
HistoryFileFormat::PlainText => { HistoryFileFormat::Plaintext => {
path.push("history.txt"); path.push("history.txt");
} }
} }

View File

@ -8,8 +8,8 @@ pub fn format_filesize_from_conf(num_bytes: i64, config: &Config) -> String {
// and filesize_metric is false, return KiB // and filesize_metric is false, return KiB
format_filesize( format_filesize(
num_bytes, num_bytes,
config.filesize_format.as_str(), &config.filesize.format,
Some(config.filesize_metric), Some(config.filesize.metric),
) )
} }

View File

@ -832,7 +832,7 @@ impl Value {
Value::Float { val, .. } => val.to_string(), Value::Float { val, .. } => val.to_string(),
Value::Filesize { val, .. } => format_filesize_from_conf(*val, config), Value::Filesize { val, .. } => format_filesize_from_conf(*val, config),
Value::Duration { val, .. } => format_duration(*val), Value::Duration { val, .. } => format_duration(*val),
Value::Date { val, .. } => match &config.datetime_normal_format { Value::Date { val, .. } => match &config.datetime_format.normal {
Some(format) => self.format_datetime(val, format), Some(format) => self.format_datetime(val, format),
None => { None => {
format!( format!(
@ -886,7 +886,7 @@ impl Value {
/// - "[record {n} fields]" /// - "[record {n} fields]"
pub fn to_abbreviated_string(&self, config: &Config) -> String { pub fn to_abbreviated_string(&self, config: &Config) -> String {
match self { match self {
Value::Date { val, .. } => match &config.datetime_table_format { Value::Date { val, .. } => match &config.datetime_format.table {
Some(format) => self.format_datetime(val, format), Some(format) => self.format_datetime(val, format),
None => HumanTime::from(*val).to_string(), None => HumanTime::from(*val).to_string(),
}, },

View File

@ -23,8 +23,8 @@ pub fn create_nu_table_config(
with_index: out.with_index, with_index: out.with_index,
with_header: out.with_header, with_header: out.with_header,
split_color: Some(lookup_separator_color(comp)), split_color: Some(lookup_separator_color(comp)),
trim: config.trim_strategy.clone(), trim: config.table.trim.clone(),
header_on_border: config.table_move_header, header_on_border: config.table.header_on_separator,
expand, expand,
} }
} }
@ -62,7 +62,8 @@ pub fn error_sign(style_computer: &StyleComputer) -> (String, TextStyle) {
} }
pub fn wrap_text(text: &str, width: usize, config: &Config) -> String { pub fn wrap_text(text: &str, width: usize, config: &Config) -> String {
string_wrap(text, width, is_cfg_trim_keep_words(config)) let keep_words = config.table.trim == TrimStrategy::wrap(true);
string_wrap(text, width, keep_words)
} }
pub fn get_header_style(style_computer: &StyleComputer) -> TextStyle { pub fn get_header_style(style_computer: &StyleComputer) -> TextStyle {
@ -163,15 +164,6 @@ fn convert_with_precision(val: &str, precision: usize) -> Result<String, ShellEr
Ok(format!("{val_float:.precision$}")) Ok(format!("{val_float:.precision$}"))
} }
fn is_cfg_trim_keep_words(config: &Config) -> bool {
matches!(
config.trim_strategy,
TrimStrategy::Wrap {
try_to_keep_words: true
}
)
}
pub fn load_theme(mode: TableMode) -> TableTheme { pub fn load_theme(mode: TableMode) -> TableTheme {
match mode { match mode {
TableMode::Basic => TableTheme::basic(), TableMode::Basic => TableTheme::basic(),

View File

@ -36,7 +36,7 @@ fn collapsed_table(
return Ok(None); return Ok(None);
} }
let indent = (config.table_indent.left, config.table_indent.right); let indent = (config.table.padding.left, config.table.padding.right);
let table = table.draw(style_computer, &theme, indent); let table = table.draw(style_computer, &theme, indent);
Ok(Some(table)) Ok(Some(table))

View File

@ -26,8 +26,8 @@ impl JustTable {
fn create_table(input: &[Value], opts: TableOpts<'_>) -> Result<Option<String>, ShellError> { fn create_table(input: &[Value], opts: TableOpts<'_>) -> Result<Option<String>, ShellError> {
match table(input, &opts)? { match table(input, &opts)? {
Some(mut out) => { Some(mut out) => {
let left = opts.config.table_indent.left; let left = opts.config.table.padding.left;
let right = opts.config.table_indent.right; let right = opts.config.table.padding.right;
out.table.set_indent(left, right); out.table.set_indent(left, right);
colorize_space(out.table.get_records_mut(), opts.style_computer); colorize_space(out.table.get_records_mut(), opts.style_computer);
@ -59,8 +59,8 @@ fn kv_table(record: &Record, opts: TableOpts<'_>) -> StringResult {
let mut out = TableOutput::new(table, false, true); let mut out = TableOutput::new(table, false, true);
let left = opts.config.table_indent.left; let left = opts.config.table.padding.left;
let right = opts.config.table_indent.right; let right = opts.config.table.padding.right;
out.table.set_indent(left, right); out.table.set_indent(left, right);
let table_config = let table_config =

View File

@ -67,7 +67,7 @@ impl<'a> TableOpts<'a> {
} }
fn has_index(opts: &TableOpts<'_>, headers: &[String]) -> bool { fn has_index(opts: &TableOpts<'_>, headers: &[String]) -> bool {
let with_index = match opts.config.table_index_mode { let with_index = match opts.config.table.index_mode {
TableIndexMode::Always => true, TableIndexMode::Always => true,
TableIndexMode::Never => false, TableIndexMode::Never => false,
TableIndexMode::Auto => headers.iter().any(|header| header == INDEX_COLUMN_NAME), TableIndexMode::Auto => headers.iter().any(|header| header == INDEX_COLUMN_NAME),