Update config directly at assignment (#13332)

# Description

Allows `Stack` to have a modified local `Config`, which is updated
immediately when `$env.config` is assigned to. This means that even
within a script, commands that come after `$env.config` changes will
always see those changes in `Stack::get_config()`.

Also fixed a lot of cases where `engine_state.get_config()` was used
even when `Stack` was available.

Closes #13324.

# User-Facing Changes
- Config changes apply immediately after the assignment is executed,
rather than whenever config is read by a command that needs it.
- Potentially slower performance when executing a lot of lines that
change `$env.config` one after another. Recommended to get `$env.config`
into a `mut` variable first and do modifications, then assign it back.
- Much faster performance when executing a script that made
modifications to `$env.config`, as the changes are only parsed once.

# Tests + Formatting
All passing.

# After Submitting
- [ ] release notes
This commit is contained in:
Devyn Cairns 2024-07-11 06:09:33 -07:00 committed by GitHub
parent deaa711ca6
commit f65bc97a54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 327 additions and 222 deletions

2
Cargo.lock generated
View file

@ -3257,6 +3257,7 @@ dependencies = [
"nu-plugin-core", "nu-plugin-core",
"nu-plugin-protocol", "nu-plugin-protocol",
"nu-protocol", "nu-protocol",
"nu-utils",
"serde", "serde",
"thiserror", "thiserror",
"typetag", "typetag",
@ -3286,6 +3287,7 @@ dependencies = [
"nu-plugin-protocol", "nu-plugin-protocol",
"nu-protocol", "nu-protocol",
"nu-system", "nu-system",
"nu-utils",
"serde", "serde",
"typetag", "typetag",
"windows 0.54.0", "windows 0.54.0",

View file

@ -53,9 +53,8 @@ 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 {
let mut config = engine_state.get_config().clone(); Arc::make_mut(&mut engine_state.config).table_mode =
config.table_mode = t_mode.coerce_str()?.parse().unwrap_or_default(); t_mode.coerce_str()?.parse().unwrap_or_default();
engine_state.set_config(config);
} }
let mut working_set = StateWorkingSet::new(engine_state); let mut working_set = StateWorkingSet::new(engine_state);

View file

@ -1,25 +1,31 @@
use nu_engine::documentation::get_flags_section; use nu_engine::documentation::get_flags_section;
use nu_protocol::{engine::EngineState, levenshtein_distance}; use nu_protocol::{engine::EngineState, levenshtein_distance, Config};
use nu_utils::IgnoreCaseExt; use nu_utils::IgnoreCaseExt;
use reedline::{Completer, Suggestion}; use reedline::{Completer, Suggestion};
use std::{fmt::Write, sync::Arc}; use std::{fmt::Write, sync::Arc};
pub struct NuHelpCompleter(Arc<EngineState>); pub struct NuHelpCompleter {
engine_state: Arc<EngineState>,
config: Arc<Config>,
}
impl NuHelpCompleter { impl NuHelpCompleter {
pub fn new(engine_state: Arc<EngineState>) -> Self { pub fn new(engine_state: Arc<EngineState>, config: Arc<Config>) -> Self {
Self(engine_state) Self {
engine_state,
config,
}
} }
fn completion_helper(&self, line: &str, pos: usize) -> Vec<Suggestion> { fn completion_helper(&self, line: &str, pos: usize) -> Vec<Suggestion> {
let folded_line = line.to_folded_case(); let folded_line = line.to_folded_case();
let mut commands = self let mut commands = self
.0 .engine_state
.get_decls_sorted(false) .get_decls_sorted(false)
.into_iter() .into_iter()
.filter_map(|(_, decl_id)| { .filter_map(|(_, decl_id)| {
let decl = self.0.get_decl(decl_id); let decl = self.engine_state.get_decl(decl_id);
(decl.name().to_folded_case().contains(&folded_line) (decl.name().to_folded_case().contains(&folded_line)
|| decl.usage().to_folded_case().contains(&folded_line) || decl.usage().to_folded_case().contains(&folded_line)
|| decl || decl
@ -54,9 +60,12 @@ impl NuHelpCompleter {
let _ = write!(long_desc, "Usage:\r\n > {}\r\n", sig.call_signature()); let _ = write!(long_desc, "Usage:\r\n > {}\r\n", sig.call_signature());
if !sig.named.is_empty() { if !sig.named.is_empty() {
long_desc.push_str(&get_flags_section(Some(&*self.0.clone()), &sig, |v| { long_desc.push_str(&get_flags_section(
v.to_parsable_string(", ", &self.0.config) Some(&self.engine_state),
})) Some(&self.config),
&sig,
|v| v.to_parsable_string(", ", &self.config),
))
} }
if !sig.required_positional.is_empty() if !sig.required_positional.is_empty()
@ -71,7 +80,7 @@ impl NuHelpCompleter {
let opt_suffix = if let Some(value) = &positional.default_value { let opt_suffix = if let Some(value) = &positional.default_value {
format!( format!(
" (optional, default: {})", " (optional, default: {})",
&value.to_parsable_string(", ", &self.0.config), &value.to_parsable_string(", ", &self.config),
) )
} else { } else {
(" (optional)").to_string() (" (optional)").to_string()
@ -138,7 +147,8 @@ mod test {
) { ) {
let engine_state = let engine_state =
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context()); nu_command::add_shell_command_context(nu_cmd_lang::create_default_context());
let mut completer = NuHelpCompleter::new(engine_state.into()); let config = engine_state.get_config().clone();
let mut completer = NuHelpCompleter::new(engine_state.into(), config);
let suggestions = completer.complete(line, end); let suggestions = completer.complete(line, end);
assert_eq!( assert_eq!(

View file

@ -1,3 +1,5 @@
use std::sync::Arc;
use nu_engine::command_prelude::*; use nu_engine::command_prelude::*;
use reedline::{Highlighter, StyledText}; use reedline::{Highlighter, StyledText};
@ -33,13 +35,10 @@ impl Command for NuHighlight {
let head = call.head; let head = call.head;
let signals = engine_state.signals(); let signals = engine_state.signals();
let engine_state = std::sync::Arc::new(engine_state.clone());
let config = engine_state.get_config().clone();
let highlighter = crate::NuHighlighter { let highlighter = crate::NuHighlighter {
engine_state, engine_state: Arc::new(engine_state.clone()),
stack: std::sync::Arc::new(stack.clone()), stack: Arc::new(stack.clone()),
config,
}; };
input.map( input.map(

View file

@ -77,13 +77,19 @@ pub(crate) fn add_menus(
mut line_editor: Reedline, mut line_editor: Reedline,
engine_state_ref: Arc<EngineState>, engine_state_ref: Arc<EngineState>,
stack: &Stack, stack: &Stack,
config: &Config, config: Arc<Config>,
) -> Result<Reedline, ShellError> { ) -> Result<Reedline, ShellError> {
//log::trace!("add_menus: config: {:#?}", &config); //log::trace!("add_menus: config: {:#?}", &config);
line_editor = line_editor.clear_menus(); line_editor = line_editor.clear_menus();
for menu in &config.menus { for menu in &config.menus {
line_editor = add_menu(line_editor, menu, engine_state_ref.clone(), stack, config)? line_editor = add_menu(
line_editor,
menu,
engine_state_ref.clone(),
stack,
config.clone(),
)?
} }
// Checking if the default menus have been added from the config file // Checking if the default menus have been added from the config file
@ -100,7 +106,7 @@ pub(crate) fn add_menus(
if !config if !config
.menus .menus
.iter() .iter()
.any(|menu| menu.name.to_expanded_string("", config) == name) .any(|menu| menu.name.to_expanded_string("", &config) == name)
{ {
let (block, delta) = { let (block, delta) = {
let mut working_set = StateWorkingSet::new(&engine_state); let mut working_set = StateWorkingSet::new(&engine_state);
@ -137,7 +143,7 @@ pub(crate) fn add_menus(
&menu, &menu,
new_engine_state_ref.clone(), new_engine_state_ref.clone(),
stack, stack,
config, config.clone(),
)?; )?;
} }
} }
@ -151,27 +157,27 @@ fn add_menu(
menu: &ParsedMenu, menu: &ParsedMenu,
engine_state: Arc<EngineState>, engine_state: Arc<EngineState>,
stack: &Stack, stack: &Stack,
config: &Config, config: Arc<Config>,
) -> Result<Reedline, ShellError> { ) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span(); let span = menu.menu_type.span();
if let Value::Record { val, .. } = &menu.menu_type { if let Value::Record { val, .. } = &menu.menu_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() {
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config), "columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, &config),
"list" => add_list_menu(line_editor, menu, engine_state, stack, config), "list" => add_list_menu(line_editor, menu, engine_state, stack, config),
"ide" => add_ide_menu(line_editor, menu, engine_state, stack, config), "ide" => add_ide_menu(line_editor, menu, engine_state, stack, config),
"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.menu_type.to_abbreviated_string(&config),
span: menu.menu_type.span(), span: menu.menu_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.menu_type.to_abbreviated_string(&config),
span: menu.menu_type.span(), span: menu.menu_type.span(),
}) })
} }
@ -282,9 +288,9 @@ pub(crate) fn add_list_menu(
menu: &ParsedMenu, menu: &ParsedMenu,
engine_state: Arc<EngineState>, engine_state: Arc<EngineState>,
stack: &Stack, stack: &Stack,
config: &Config, config: Arc<Config>,
) -> Result<Reedline, ShellError> { ) -> Result<Reedline, ShellError> {
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.menu_type.span();
@ -311,7 +317,7 @@ pub(crate) fn add_list_menu(
} }
} }
let marker = menu.marker.to_expanded_string("", config); let marker = menu.marker.to_expanded_string("", &config);
list_menu = list_menu.with_marker(&marker); list_menu = list_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?; let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -337,7 +343,7 @@ pub(crate) fn add_list_menu(
} }
_ => Err(ShellError::UnsupportedConfigValue { _ => Err(ShellError::UnsupportedConfigValue {
expected: "block or omitted value".to_string(), expected: "block or omitted value".to_string(),
value: menu.source.to_abbreviated_string(config), value: menu.source.to_abbreviated_string(&config),
span: menu.source.span(), span: menu.source.span(),
}), }),
} }
@ -349,10 +355,10 @@ pub(crate) fn add_ide_menu(
menu: &ParsedMenu, menu: &ParsedMenu,
engine_state: Arc<EngineState>, engine_state: Arc<EngineState>,
stack: &Stack, stack: &Stack,
config: &Config, config: Arc<Config>,
) -> Result<Reedline, ShellError> { ) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span(); let span = menu.menu_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.menu_type {
@ -417,7 +423,7 @@ pub(crate) fn add_ide_menu(
} else { } else {
return Err(ShellError::UnsupportedConfigValue { return Err(ShellError::UnsupportedConfigValue {
expected: "bool or record".to_string(), expected: "bool or record".to_string(),
value: border.to_abbreviated_string(config), value: border.to_abbreviated_string(&config),
span: border.span(), span: border.span(),
}); });
} }
@ -441,7 +447,7 @@ pub(crate) fn add_ide_menu(
_ => { _ => {
return Err(ShellError::UnsupportedConfigValue { return Err(ShellError::UnsupportedConfigValue {
expected: "\"left\", \"right\" or \"prefer_right\"".to_string(), expected: "\"left\", \"right\" or \"prefer_right\"".to_string(),
value: description_mode.to_abbreviated_string(config), value: description_mode.to_abbreviated_string(&config),
span: description_mode.span(), span: description_mode.span(),
}); });
} }
@ -509,7 +515,7 @@ pub(crate) fn add_ide_menu(
} }
} }
let marker = menu.marker.to_expanded_string("", config); let marker = menu.marker.to_expanded_string("", &config);
ide_menu = ide_menu.with_marker(&marker); ide_menu = ide_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?; let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -535,7 +541,7 @@ pub(crate) fn add_ide_menu(
} }
_ => Err(ShellError::UnsupportedConfigValue { _ => Err(ShellError::UnsupportedConfigValue {
expected: "block or omitted value".to_string(), expected: "block or omitted value".to_string(),
value: menu.source.to_abbreviated_string(config), value: menu.source.to_abbreviated_string(&config),
span, span,
}), }),
} }
@ -547,9 +553,9 @@ pub(crate) fn add_description_menu(
menu: &ParsedMenu, menu: &ParsedMenu,
engine_state: Arc<EngineState>, engine_state: Arc<EngineState>,
stack: &Stack, stack: &Stack,
config: &Config, config: Arc<Config>,
) -> Result<Reedline, ShellError> { ) -> Result<Reedline, ShellError> {
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.menu_type.span();
@ -608,7 +614,7 @@ pub(crate) fn add_description_menu(
} }
} }
let marker = menu.marker.to_expanded_string("", config); let marker = menu.marker.to_expanded_string("", &config);
description_menu = description_menu.with_marker(&marker); description_menu = description_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?; let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -617,7 +623,7 @@ pub(crate) fn add_description_menu(
let span = menu.source.span(); let span = menu.source.span();
match &menu.source { match &menu.source {
Value::Nothing { .. } => { Value::Nothing { .. } => {
let completer = Box::new(NuHelpCompleter::new(engine_state)); let completer = Box::new(NuHelpCompleter::new(engine_state, config));
Ok(line_editor.with_menu(ReedlineMenu::WithCompleter { Ok(line_editor.with_menu(ReedlineMenu::WithCompleter {
menu: Box::new(description_menu), menu: Box::new(description_menu),
completer, completer,
@ -638,7 +644,7 @@ pub(crate) fn add_description_menu(
} }
_ => Err(ShellError::UnsupportedConfigValue { _ => Err(ShellError::UnsupportedConfigValue {
expected: "closure or omitted value".to_string(), expected: "closure or omitted value".to_string(),
value: menu.source.to_abbreviated_string(config), value: menu.source.to_abbreviated_string(&config),
span: menu.source.span(), span: menu.source.span(),
}), }),
} }

View file

@ -297,7 +297,7 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
perf!("env-change hook", start_time, use_color); perf!("env-change hook", start_time, use_color);
let engine_reference = Arc::new(engine_state.clone()); let engine_reference = Arc::new(engine_state.clone());
let config = engine_state.get_config(); let config = stack.get_config(engine_state);
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
@ -323,7 +323,6 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
engine_state: engine_reference.clone(), engine_state: engine_reference.clone(),
// STACK-REFERENCE 1 // STACK-REFERENCE 1
stack: stack_arc.clone(), stack: stack_arc.clone(),
config: config.clone(),
})) }))
.with_validator(Box::new(NuValidator { .with_validator(Box::new(NuValidator {
engine_state: engine_reference.clone(), engine_state: engine_reference.clone(),

View file

@ -6,7 +6,7 @@ use nu_parser::{flatten_block, parse, FlatShape};
use nu_protocol::{ use nu_protocol::{
ast::{Block, Expr, Expression, PipelineRedirection, RecordItem}, ast::{Block, Expr, Expression, PipelineRedirection, RecordItem},
engine::{EngineState, Stack, StateWorkingSet}, engine::{EngineState, Stack, StateWorkingSet},
Config, Span, Span,
}; };
use reedline::{Highlighter, StyledText}; use reedline::{Highlighter, StyledText};
use std::sync::Arc; use std::sync::Arc;
@ -14,15 +14,14 @@ use std::sync::Arc;
pub struct NuHighlighter { pub struct NuHighlighter {
pub engine_state: Arc<EngineState>, pub engine_state: Arc<EngineState>,
pub stack: Arc<Stack>, pub stack: Arc<Stack>,
pub config: Config,
} }
impl Highlighter for NuHighlighter { impl Highlighter for NuHighlighter {
fn highlight(&self, line: &str, _cursor: usize) -> StyledText { fn highlight(&self, line: &str, _cursor: usize) -> StyledText {
trace!("highlighting: {}", line); trace!("highlighting: {}", line);
let highlight_resolved_externals = let config = self.stack.get_config(&self.engine_state);
self.engine_state.get_config().highlight_resolved_externals; let highlight_resolved_externals = config.highlight_resolved_externals;
let mut working_set = StateWorkingSet::new(&self.engine_state); let mut working_set = StateWorkingSet::new(&self.engine_state);
let block = parse(&mut working_set, None, line.as_bytes(), false); let block = parse(&mut working_set, None, line.as_bytes(), false);
let (shapes, global_span_offset) = { let (shapes, global_span_offset) = {
@ -88,7 +87,7 @@ impl Highlighter for NuHighlighter {
.to_string(); .to_string();
let mut add_colored_token = |shape: &FlatShape, text: String| { let mut add_colored_token = |shape: &FlatShape, text: String| {
output.push((get_shape_color(shape.as_str(), &self.config), text)); output.push((get_shape_color(shape.as_str(), &config), text));
}; };
match shape.1 { match shape.1 {
@ -128,9 +127,9 @@ impl Highlighter for NuHighlighter {
let start = part.start - span.start; let start = part.start - span.start;
let end = part.end - span.start; let end = part.end - span.start;
let text = next_token[start..end].to_string(); let text = next_token[start..end].to_string();
let mut style = get_shape_color(shape.as_str(), &self.config); let mut style = get_shape_color(shape.as_str(), &config);
if highlight { if highlight {
style = get_matching_brackets_style(style, &self.config); style = get_matching_brackets_style(style, &config);
} }
output.push((style, text)); output.push((style, text));
} }

View file

@ -239,7 +239,7 @@ fn to_html(
let partial = call.has_flag(engine_state, stack, "partial")?; let partial = call.has_flag(engine_state, stack, "partial")?;
let list = call.has_flag(engine_state, stack, "list")?; let list = call.has_flag(engine_state, stack, "list")?;
let theme: Option<Spanned<String>> = call.get_flag(engine_state, stack, "theme")?; let theme: Option<Spanned<String>> = call.get_flag(engine_state, stack, "theme")?;
let config = engine_state.get_config(); let config = &stack.get_config(engine_state);
let vec_of_values = input.into_iter().collect::<Vec<Value>>(); let vec_of_values = input.into_iter().collect::<Vec<Value>>();
let headers = merge_descriptors(&vec_of_values); let headers = merge_descriptors(&vec_of_values);

View file

@ -1,5 +1,5 @@
use nu_engine::command_prelude::*; use nu_engine::command_prelude::*;
use nu_protocol::{ast::PathMember, engine::StateWorkingSet, ListStream}; use nu_protocol::{ast::PathMember, engine::StateWorkingSet, Config, ListStream};
#[derive(Clone)] #[derive(Clone)]
pub struct FormatPattern; pub struct FormatPattern;
@ -43,6 +43,8 @@ impl Command for FormatPattern {
let it_id = working_set.add_variable(b"$it".to_vec(), call.head, Type::Any, false); let it_id = working_set.add_variable(b"$it".to_vec(), call.head, Type::Any, false);
stack.add_var(it_id, input_val.clone()); stack.add_var(it_id, input_val.clone());
let config = stack.get_config(engine_state);
match specified_pattern { match specified_pattern {
Err(e) => Err(e), Err(e) => Err(e),
Ok(pattern) => { Ok(pattern) => {
@ -56,7 +58,7 @@ impl Command for FormatPattern {
string_span.start + 1, string_span.start + 1,
)?; )?;
format(input_val, &ops, engine_state, call.head) format(input_val, &ops, engine_state, &config, call.head)
} }
} }
} }
@ -181,33 +183,30 @@ fn format(
input_data: Value, input_data: Value,
format_operations: &[FormatOperation], format_operations: &[FormatOperation],
engine_state: &EngineState, engine_state: &EngineState,
config: &Config,
head_span: Span, head_span: Span,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let data_as_value = input_data; let data_as_value = input_data;
// We can only handle a Record or a List of Records // We can only handle a Record or a List of Records
match data_as_value { match data_as_value {
Value::Record { .. } => { Value::Record { .. } => match format_record(format_operations, &data_as_value, config) {
match format_record(format_operations, &data_as_value, engine_state) { Ok(value) => Ok(PipelineData::Value(Value::string(value, head_span), None)),
Ok(value) => Ok(PipelineData::Value(Value::string(value, head_span), None)), Err(value) => Err(value),
Err(value) => Err(value), },
}
}
Value::List { vals, .. } => { Value::List { vals, .. } => {
let mut list = vec![]; let mut list = vec![];
for val in vals.iter() { for val in vals.iter() {
match val { match val {
Value::Record { .. } => { Value::Record { .. } => match format_record(format_operations, val, config) {
match format_record(format_operations, val, engine_state) { Ok(value) => {
Ok(value) => { list.push(Value::string(value, head_span));
list.push(Value::string(value, head_span));
}
Err(value) => {
return Err(value);
}
} }
} Err(value) => {
return Err(value);
}
},
Value::Error { error, .. } => return Err(*error.clone()), Value::Error { error, .. } => return Err(*error.clone()),
_ => { _ => {
return Err(ShellError::OnlySupportsThisInputType { return Err(ShellError::OnlySupportsThisInputType {
@ -237,9 +236,8 @@ fn format(
fn format_record( fn format_record(
format_operations: &[FormatOperation], format_operations: &[FormatOperation],
data_as_value: &Value, data_as_value: &Value,
engine_state: &EngineState, config: &Config,
) -> Result<String, ShellError> { ) -> Result<String, ShellError> {
let config = engine_state.get_config();
let mut output = String::new(); let mut output = String::new();
for op in format_operations { for op in format_operations {

View file

@ -1,6 +1,6 @@
use crate::{color_record_to_nustyle, lookup_ansi_color_style, text_style::Alignment, TextStyle}; use crate::{color_record_to_nustyle, lookup_ansi_color_style, text_style::Alignment, TextStyle};
use nu_ansi_term::{Color, Style}; use nu_ansi_term::{Color, Style};
use nu_engine::{env::get_config, ClosureEvalOnce}; use nu_engine::ClosureEvalOnce;
use nu_protocol::{ use nu_protocol::{
cli_error::CliError, cli_error::CliError,
engine::{Closure, EngineState, Stack, StateWorkingSet}, engine::{Closure, EngineState, Stack, StateWorkingSet},
@ -114,7 +114,7 @@ impl<'a> StyleComputer<'a> {
// The main constructor. // The main constructor.
pub fn from_config(engine_state: &'a EngineState, stack: &'a Stack) -> StyleComputer<'a> { pub fn from_config(engine_state: &'a EngineState, stack: &'a Stack) -> StyleComputer<'a> {
let config = get_config(engine_state, stack); let config = stack.get_config(engine_state);
// Create the hashmap // Create the hashmap
#[rustfmt::skip] #[rustfmt::skip]

View file

@ -1,3 +1,5 @@
use std::sync::Arc;
use nu_cmd_base::input_handler::{operate, CmdArgument}; use nu_cmd_base::input_handler::{operate, CmdArgument};
use nu_engine::command_prelude::*; use nu_engine::command_prelude::*;
use nu_protocol::{into_code, Config}; use nu_protocol::{into_code, Config};
@ -7,7 +9,7 @@ use num_format::ToFormattedString;
struct Arguments { struct Arguments {
decimals_value: Option<i64>, decimals_value: Option<i64>,
cell_paths: Option<Vec<CellPath>>, cell_paths: Option<Vec<CellPath>>,
config: Config, config: Arc<Config>,
} }
impl CmdArgument for Arguments { impl CmdArgument for Arguments {
@ -174,7 +176,7 @@ fn string_helper(
}) })
} }
} else { } else {
let config = engine_state.get_config().clone(); let config = stack.get_config(engine_state);
let args = Arguments { let args = Arguments {
decimals_value, decimals_value,
cell_paths, cell_paths,

View file

@ -33,7 +33,7 @@ impl Command for Debug {
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let head = call.head; let head = call.head;
let config = engine_state.get_config().clone(); let config = stack.get_config(engine_state);
let raw = call.has_flag(engine_state, stack, "raw")?; let raw = call.has_flag(engine_state, stack, "raw")?;
// Should PipelineData::Empty result in an error here? // Should PipelineData::Empty result in an error here?

View file

@ -170,7 +170,7 @@ fn rm(
} }
let span = call.head; let span = call.head;
let rm_always_trash = engine_state.get_config().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

@ -213,7 +213,7 @@ fn find_with_regex(
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let span = call.head; let span = call.head;
let config = engine_state.get_config().clone(); let config = stack.get_config(engine_state);
let insensitive = call.has_flag(engine_state, stack, "ignore-case")?; let insensitive = call.has_flag(engine_state, stack, "ignore-case")?;
let multiline = call.has_flag(engine_state, stack, "multiline")?; let multiline = call.has_flag(engine_state, stack, "multiline")?;
@ -348,8 +348,8 @@ fn find_with_rest_and_highlight(
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let span = call.head; let span = call.head;
let config = engine_state.get_config().clone(); let config = stack.get_config(engine_state);
let filter_config = engine_state.get_config().clone(); let filter_config = config.clone();
let invert = call.has_flag(engine_state, stack, "invert")?; let invert = call.has_flag(engine_state, stack, "invert")?;
let terms = call.rest::<Value>(engine_state, stack, 0)?; let terms = call.rest::<Value>(engine_state, stack, 0)?;
let lower_terms = terms let lower_terms = terms

View file

@ -70,8 +70,8 @@ impl Command for ToMd {
let head = call.head; let head = call.head;
let pretty = call.has_flag(engine_state, stack, "pretty")?; let pretty = call.has_flag(engine_state, stack, "pretty")?;
let per_element = call.has_flag(engine_state, stack, "per-element")?; let per_element = call.has_flag(engine_state, stack, "per-element")?;
let config = engine_state.get_config(); let config = stack.get_config(engine_state);
to_md(input, pretty, per_element, config, head) to_md(input, pretty, per_element, &config, head)
} }
} }

View file

@ -31,18 +31,19 @@ impl Command for ToText {
fn run( fn run(
&self, &self,
engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let span = call.head; let span = call.head;
let input = input.try_expand_range()?; let input = input.try_expand_range()?;
let config = stack.get_config(engine_state);
match input { match input {
PipelineData::Empty => Ok(Value::string(String::new(), span) PipelineData::Empty => Ok(Value::string(String::new(), span)
.into_pipeline_data_with_metadata(update_metadata(None))), .into_pipeline_data_with_metadata(update_metadata(None))),
PipelineData::Value(value, ..) => { PipelineData::Value(value, ..) => {
let str = local_into_string(value, LINE_ENDING, engine_state.get_config()); let str = local_into_string(value, LINE_ENDING, &config);
Ok( Ok(
Value::string(str, span) Value::string(str, span)
.into_pipeline_data_with_metadata(update_metadata(None)), .into_pipeline_data_with_metadata(update_metadata(None)),
@ -50,7 +51,6 @@ impl Command for ToText {
} }
PipelineData::ListStream(stream, meta) => { PipelineData::ListStream(stream, meta) => {
let span = stream.span(); let span = stream.span();
let config = engine_state.get_config().clone();
let iter = stream.into_inner().map(move |value| { let iter = stream.into_inner().map(move |value| {
let mut str = local_into_string(value, LINE_ENDING, &config); let mut str = local_into_string(value, LINE_ENDING, &config);
str.push_str(LINE_ENDING); str.push_str(LINE_ENDING);

View file

@ -143,7 +143,7 @@ pub fn help_aliases(
long_desc.push_str("\n\n"); long_desc.push_str("\n\n");
long_desc.push_str(&format!("{G}Expansion{RESET}:\n {alias_expansion}")); long_desc.push_str(&format!("{G}Expansion{RESET}:\n {alias_expansion}"));
let config = engine_state.get_config(); let config = stack.get_config(engine_state);
if !config.use_ansi_coloring { if !config.use_ansi_coloring {
long_desc = nu_utils::strip_ansi_string_likely(long_desc); long_desc = nu_utils::strip_ansi_string_likely(long_desc);
} }

View file

@ -230,7 +230,7 @@ pub fn help_modules(
)); ));
} }
let config = engine_state.get_config(); let config = stack.get_config(engine_state);
if !config.use_ansi_coloring { if !config.use_ansi_coloring {
long_desc = nu_utils::strip_ansi_string_likely(long_desc); long_desc = nu_utils::strip_ansi_string_likely(long_desc);
} }

View file

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*; use nu_engine::command_prelude::*;
use nu_protocol::Config;
use url::Url; use url::Url;
#[derive(Clone)] #[derive(Clone)]
@ -38,11 +39,15 @@ impl Command for SubCommand {
fn run( fn run(
&self, &self,
engine_state: &EngineState, engine_state: &EngineState,
_: &mut Stack, stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
parse(input.into_value(call.head)?, call.head, engine_state) parse(
input.into_value(call.head)?,
call.head,
&stack.get_config(engine_state),
)
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
@ -68,12 +73,12 @@ impl Command for SubCommand {
} }
} }
fn get_url_string(value: &Value, engine_state: &EngineState) -> String { fn get_url_string(value: &Value, config: &Config) -> String {
value.to_expanded_string("", engine_state.get_config()) value.to_expanded_string("", config)
} }
fn parse(value: Value, head: Span, engine_state: &EngineState) -> Result<PipelineData, ShellError> { fn parse(value: Value, head: Span, config: &Config) -> Result<PipelineData, ShellError> {
let url_string = get_url_string(&value, engine_state); let url_string = get_url_string(&value, config);
let result_url = Url::parse(url_string.as_str()); let result_url = Url::parse(url_string.as_str());

View file

@ -653,7 +653,7 @@ Operating system commands:
let list: bool = call.has_flag(engine_state, stack, "list")?; let list: bool = call.has_flag(engine_state, stack, "list")?;
let escape: bool = call.has_flag(engine_state, stack, "escape")?; let escape: bool = call.has_flag(engine_state, stack, "escape")?;
let osc: bool = call.has_flag(engine_state, stack, "osc")?; let osc: bool = call.has_flag(engine_state, stack, "osc")?;
let use_ansi_coloring = engine_state.get_config().use_ansi_coloring; let use_ansi_coloring = stack.get_config(engine_state).use_ansi_coloring;
if list { if list {
return Ok(generate_ansi_code_list( return Ok(generate_ansi_code_list(

View file

@ -1,10 +1,12 @@
use std::sync::Arc;
use nu_cmd_base::input_handler::{operate, CmdArgument}; use nu_cmd_base::input_handler::{operate, CmdArgument};
use nu_engine::command_prelude::*; use nu_engine::command_prelude::*;
use nu_protocol::Config; use nu_protocol::Config;
pub struct Arguments { pub struct Arguments {
cell_paths: Option<Vec<CellPath>>, cell_paths: Option<Vec<CellPath>>,
config: Config, config: Arc<Config>,
} }
impl CmdArgument for Arguments { impl CmdArgument for Arguments {
@ -51,11 +53,8 @@ impl Command for SubCommand {
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?; let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths); let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let config = engine_state.get_config(); let config = stack.get_config(engine_state);
let args = Arguments { let args = Arguments { cell_paths, config };
cell_paths,
config: config.clone(),
};
operate(action, args, input, call.head, engine_state.signals()) operate(action, args, input, call.head, engine_state.signals())
} }

View file

@ -79,6 +79,7 @@ impl Command for InputList {
let fuzzy = call.has_flag(engine_state, stack, "fuzzy")?; let fuzzy = call.has_flag(engine_state, stack, "fuzzy")?;
let index = call.has_flag(engine_state, stack, "index")?; let index = call.has_flag(engine_state, stack, "index")?;
let display_path: Option<CellPath> = call.get_flag(engine_state, stack, "display")?; let display_path: Option<CellPath> = call.get_flag(engine_state, stack, "display")?;
let config = stack.get_config(engine_state);
let options: Vec<Options> = match input { let options: Vec<Options> = match input {
PipelineData::Value(Value::Range { .. }, ..) PipelineData::Value(Value::Range { .. }, ..)
@ -89,9 +90,9 @@ impl Command for InputList {
let display_value = if let Some(ref cellpath) = display_path { let display_value = if let Some(ref cellpath) = display_path {
val.clone() val.clone()
.follow_cell_path(&cellpath.members, false)? .follow_cell_path(&cellpath.members, false)?
.to_expanded_string(", ", engine_state.get_config()) .to_expanded_string(", ", &config)
} else { } else {
val.to_expanded_string(", ", engine_state.get_config()) val.to_expanded_string(", ", &config)
}; };
Ok(Options { Ok(Options {
name: display_value, name: display_value,

View file

@ -65,7 +65,7 @@ impl Command for StorInsert {
let span = call.head; let span = call.head;
let table_name: Option<String> = call.get_flag(engine_state, stack, "table-name")?; let table_name: Option<String> = call.get_flag(engine_state, stack, "table-name")?;
let data_record: Option<Record> = call.get_flag(engine_state, stack, "data-record")?; let data_record: Option<Record> = call.get_flag(engine_state, stack, "data-record")?;
// let config = engine_state.get_config(); // let config = stack.get_config(engine_state);
let db = Box::new(SQLiteDatabase::new( let db = Box::new(SQLiteDatabase::new(
std::path::Path::new(MEMORY_DB), std::path::Path::new(MEMORY_DB),
Signals::empty(), Signals::empty(),

View file

@ -1,7 +1,7 @@
use itertools::Itertools; use itertools::Itertools;
use nu_engine::command_prelude::*; use nu_engine::command_prelude::*;
use nu_protocol::Range; use nu_protocol::{Config, Range};
use std::{io::Cursor, iter::Peekable, str::CharIndices}; use std::{io::Cursor, iter::Peekable, str::CharIndices, sync::Arc};
type Input<'t> = Peekable<CharIndices<'t>>; type Input<'t> = Peekable<CharIndices<'t>>;
@ -110,11 +110,13 @@ none 8150224 4 8150220 1% /mnt/c' | detect columns --gue
let num_rows_to_skip: Option<usize> = call.get_flag(engine_state, stack, "skip")?; let num_rows_to_skip: Option<usize> = call.get_flag(engine_state, stack, "skip")?;
let noheader = call.has_flag(engine_state, stack, "no-headers")?; let noheader = call.has_flag(engine_state, stack, "no-headers")?;
let range: Option<Range> = call.get_flag(engine_state, stack, "combine-columns")?; let range: Option<Range> = call.get_flag(engine_state, stack, "combine-columns")?;
let config = stack.get_config(engine_state);
let args = Arguments { let args = Arguments {
noheader, noheader,
num_rows_to_skip, num_rows_to_skip,
range, range,
config,
}; };
if call.has_flag(engine_state, stack, "guess")? { if call.has_flag(engine_state, stack, "guess")? {
@ -133,11 +135,13 @@ none 8150224 4 8150220 1% /mnt/c' | detect columns --gue
let num_rows_to_skip: Option<usize> = call.get_flag_const(working_set, "skip")?; let num_rows_to_skip: Option<usize> = call.get_flag_const(working_set, "skip")?;
let noheader = call.has_flag_const(working_set, "no-headers")?; let noheader = call.has_flag_const(working_set, "no-headers")?;
let range: Option<Range> = call.get_flag_const(working_set, "combine-columns")?; let range: Option<Range> = call.get_flag_const(working_set, "combine-columns")?;
let config = working_set.get_config().clone();
let args = Arguments { let args = Arguments {
noheader, noheader,
num_rows_to_skip, num_rows_to_skip,
range, range,
config,
}; };
if call.has_flag_const(working_set, "guess")? { if call.has_flag_const(working_set, "guess")? {
@ -152,6 +156,7 @@ struct Arguments {
num_rows_to_skip: Option<usize>, num_rows_to_skip: Option<usize>,
noheader: bool, noheader: bool,
range: Option<Range>, range: Option<Range>,
config: Arc<Config>,
} }
fn guess_width( fn guess_width(
@ -163,7 +168,7 @@ fn guess_width(
use super::guess_width::GuessWidth; use super::guess_width::GuessWidth;
let input_span = input.span().unwrap_or(call.head); let input_span = input.span().unwrap_or(call.head);
let mut input = input.collect_string("", engine_state.get_config())?; let mut input = input.collect_string("", &args.config)?;
if let Some(rows) = args.num_rows_to_skip { if let Some(rows) = args.num_rows_to_skip {
input = input.lines().skip(rows).map(|x| x.to_string()).join("\n"); input = input.lines().skip(rows).map(|x| x.to_string()).join("\n");
} }
@ -235,8 +240,7 @@ fn detect_columns(
args: Arguments, args: Arguments,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let name_span = call.head; let name_span = call.head;
let config = engine_state.get_config(); let input = input.collect_string("", &args.config)?;
let input = input.collect_string("", config)?;
let input: Vec<_> = input let input: Vec<_> = input
.lines() .lines()

View file

@ -1,4 +1,4 @@
use nu_engine::{command_prelude::*, env::get_config, find_in_dirs_env, get_dirs_var_from_call}; use nu_engine::{command_prelude::*, find_in_dirs_env, get_dirs_var_from_call};
use nu_parser::{parse, parse_module_block, parse_module_file_or_dir, unescape_unquote_string}; use nu_parser::{parse, parse_module_block, parse_module_file_or_dir, unescape_unquote_string};
use nu_protocol::engine::{FileStack, StateWorkingSet}; use nu_protocol::engine::{FileStack, StateWorkingSet};
use std::path::Path; use std::path::Path;
@ -59,7 +59,7 @@ impl Command for NuCheck {
} }
} }
PipelineData::ListStream(stream, ..) => { PipelineData::ListStream(stream, ..) => {
let config = get_config(engine_state, stack); let config = stack.get_config(engine_state);
let list_stream = stream.into_string("\n", &config); let list_stream = stream.into_string("\n", &config);
let contents = Vec::from(list_stream); let contents = Vec::from(list_stream);

View file

@ -366,7 +366,7 @@ pub fn command_not_found(
stack: &mut Stack, stack: &mut Stack,
) -> ShellError { ) -> ShellError {
// Run the `command_not_found` hook if there is one. // Run the `command_not_found` hook if there is one.
if let Some(hook) = &engine_state.config.hooks.command_not_found { if let Some(hook) = &stack.get_config(engine_state).hooks.command_not_found {
let mut stack = stack.start_capture(); let mut stack = stack.start_capture();
// Set a special environment variable to avoid infinite loops when the // Set a special environment variable to avoid infinite loops when the
// `command_not_found` hook triggers itself. // `command_not_found` hook triggers itself.

View file

@ -61,7 +61,7 @@ prints out the list properly."#
let width_param: Option<i64> = call.get_flag(engine_state, stack, "width")?; let width_param: Option<i64> = call.get_flag(engine_state, stack, "width")?;
let color_param: bool = call.has_flag(engine_state, stack, "color")?; let color_param: bool = call.has_flag(engine_state, stack, "color")?;
let separator_param: Option<String> = call.get_flag(engine_state, stack, "separator")?; let separator_param: Option<String> = call.get_flag(engine_state, stack, "separator")?;
let config = engine_state.get_config(); let config = &stack.get_config(engine_state);
let env_str = match stack.get_env_var(engine_state, "LS_COLORS") { let env_str = match stack.get_env_var(engine_state, "LS_COLORS") {
Some(v) => Some(env_to_string("LS_COLORS", &v, engine_state, stack)?), Some(v) => Some(env_to_string("LS_COLORS", &v, engine_state, stack)?),
None => None, None => None,

View file

@ -4,7 +4,7 @@
use lscolors::{LsColors, Style}; use lscolors::{LsColors, Style};
use nu_color_config::{color_from_hex, StyleComputer, TextStyle}; use nu_color_config::{color_from_hex, StyleComputer, TextStyle};
use nu_engine::{command_prelude::*, env::get_config, env_to_string}; use nu_engine::{command_prelude::*, env_to_string};
use nu_pretty_hex::HexConfig; use nu_pretty_hex::HexConfig;
use nu_protocol::{ use nu_protocol::{
ByteStream, Config, DataSource, ListStream, PipelineMetadata, Signals, TableMode, ValueIterator, ByteStream, Config, DataSource, ListStream, PipelineMetadata, Signals, TableMode, ValueIterator,
@ -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(|| get_config(state, stack).table_abbreviation_threshold); .or_else(|| stack.get_config(state).table_abbreviation_threshold);
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(|| get_config(state, stack).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);
@ -493,7 +493,11 @@ fn handle_record(
cfg: TableConfig, cfg: TableConfig,
mut record: Record, mut record: Record,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let config = get_config(input.engine_state, input.stack); let config = {
let state = input.engine_state;
let stack: &Stack = input.stack;
stack.get_config(state)
};
let span = input.data.span().unwrap_or(input.call.head); let span = input.data.span().unwrap_or(input.call.head);
let styles = &StyleComputer::from_config(input.engine_state, input.stack); let styles = &StyleComputer::from_config(input.engine_state, input.stack);
@ -608,7 +612,11 @@ fn handle_row_stream(
data_source: DataSource::Ls, data_source: DataSource::Ls,
.. ..
}) => { }) => {
let config = get_config(input.engine_state, input.stack); let config = {
let state = input.engine_state;
let stack: &Stack = input.stack;
stack.get_config(state)
};
let ls_colors_env_str = match input.stack.get_env_var(input.engine_state, "LS_COLORS") { let ls_colors_env_str = match input.stack.get_env_var(input.engine_state, "LS_COLORS") {
Some(v) => Some(env_to_string( Some(v) => Some(env_to_string(
"LS_COLORS", "LS_COLORS",
@ -758,7 +766,11 @@ impl PagingTableCreator {
return Ok(None); return Ok(None);
} }
let cfg = get_config(&self.engine_state, &self.stack); let cfg = {
let state = &self.engine_state;
let stack = &self.stack;
stack.get_config(state)
};
let style_comp = StyleComputer::from_config(&self.engine_state, &self.stack); let style_comp = StyleComputer::from_config(&self.engine_state, &self.stack);
let opts = self.create_table_opts(&cfg, &style_comp); let opts = self.create_table_opts(&cfg, &style_comp);
let view = TableView::Expanded { let view = TableView::Expanded {
@ -775,7 +787,11 @@ impl PagingTableCreator {
return Ok(None); return Ok(None);
} }
let cfg = get_config(&self.engine_state, &self.stack); let cfg = {
let state = &self.engine_state;
let stack = &self.stack;
stack.get_config(state)
};
let style_comp = StyleComputer::from_config(&self.engine_state, &self.stack); let style_comp = StyleComputer::from_config(&self.engine_state, &self.stack);
let opts = self.create_table_opts(&cfg, &style_comp); let opts = self.create_table_opts(&cfg, &style_comp);
@ -783,7 +799,11 @@ impl PagingTableCreator {
} }
fn build_general(&mut self, batch: Vec<Value>) -> StringResult { fn build_general(&mut self, batch: Vec<Value>) -> StringResult {
let cfg = get_config(&self.engine_state, &self.stack); let cfg = {
let state = &self.engine_state;
let stack = &self.stack;
stack.get_config(state)
};
let style_comp = StyleComputer::from_config(&self.engine_state, &self.stack); let style_comp = StyleComputer::from_config(&self.engine_state, &self.stack);
let opts = self.create_table_opts(&cfg, &style_comp); let opts = self.create_table_opts(&cfg, &style_comp);
@ -872,7 +892,11 @@ impl Iterator for PagingTableCreator {
self.row_offset += batch_size; self.row_offset += batch_size;
let config = get_config(&self.engine_state, &self.stack); let config = {
let state = &self.engine_state;
let stack = &self.stack;
stack.get_config(state)
};
convert_table_to_output( convert_table_to_output(
table, table,
&config, &config,
@ -1049,7 +1073,7 @@ fn create_empty_placeholder(
engine_state: &EngineState, engine_state: &EngineState,
stack: &Stack, stack: &Stack,
) -> String { ) -> String {
let config = get_config(engine_state, stack); 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

@ -3,8 +3,8 @@ use nu_protocol::{
ast::{Argument, Call, Expr, Expression, RecordItem}, ast::{Argument, Call, Expr, Expression, RecordItem},
debugger::WithoutDebug, debugger::WithoutDebug,
engine::{Command, EngineState, Stack, UNKNOWN_SPAN_ID}, engine::{Command, EngineState, Stack, UNKNOWN_SPAN_ID},
record, Category, Example, IntoPipelineData, PipelineData, Signature, Span, SpanId, Spanned, record, Category, Config, Example, IntoPipelineData, PipelineData, Signature, Span, SpanId,
SyntaxShape, Type, Value, Spanned, SyntaxShape, Type, Value,
}; };
use std::{collections::HashMap, fmt::Write}; use std::{collections::HashMap, fmt::Write};
@ -13,7 +13,7 @@ pub fn get_full_help(
engine_state: &EngineState, engine_state: &EngineState,
stack: &mut Stack, stack: &mut Stack,
) -> String { ) -> String {
let config = engine_state.get_config(); let config = stack.get_config(engine_state);
let doc_config = DocumentationConfig { let doc_config = DocumentationConfig {
no_subcommands: false, no_subcommands: false,
no_color: !config.use_ansi_coloring, no_color: !config.use_ansi_coloring,
@ -70,16 +70,30 @@ fn get_documentation(
config: &DocumentationConfig, config: &DocumentationConfig,
is_parser_keyword: bool, is_parser_keyword: bool,
) -> String { ) -> String {
let nu_config = stack.get_config(engine_state);
// Create ansi colors // Create ansi colors
//todo make these configurable -- pull from enginestate.config //todo make these configurable -- pull from enginestate.config
let help_section_name: String = let help_section_name: String = get_ansi_color_for_component_or_default(
get_ansi_color_for_component_or_default(engine_state, "shape_string", "\x1b[32m"); // default: green engine_state,
&nu_config,
"shape_string",
"\x1b[32m",
); // default: green
let help_subcolor_one: String = let help_subcolor_one: String = get_ansi_color_for_component_or_default(
get_ansi_color_for_component_or_default(engine_state, "shape_external", "\x1b[36m"); // default: cyan engine_state,
// was const bb: &str = "\x1b[1;34m"; // bold blue &nu_config,
let help_subcolor_two: String = "shape_external",
get_ansi_color_for_component_or_default(engine_state, "shape_block", "\x1b[94m"); // default: light blue (nobold, should be bolding the *names*) "\x1b[36m",
); // default: cyan
// was const bb: &str = "\x1b[1;34m"; // bold blue
let help_subcolor_two: String = get_ansi_color_for_component_or_default(
engine_state,
&nu_config,
"shape_block",
"\x1b[94m",
); // default: light blue (nobold, should be bolding the *names*)
const RESET: &str = "\x1b[0m"; // reset const RESET: &str = "\x1b[0m"; // reset
@ -139,13 +153,12 @@ fn get_documentation(
} }
if !sig.named.is_empty() { if !sig.named.is_empty() {
long_desc.push_str(&get_flags_section(Some(engine_state), sig, |v| { long_desc.push_str(&get_flags_section(
nu_highlight_string( Some(engine_state),
&v.to_parsable_string(", ", &engine_state.config), Some(&nu_config),
engine_state, sig,
stack, |v| nu_highlight_string(&v.to_parsable_string(", ", &nu_config), engine_state, stack),
) ))
}))
} }
if !sig.required_positional.is_empty() if !sig.required_positional.is_empty()
@ -189,7 +202,7 @@ fn get_documentation(
format!( format!(
" (optional, default: {})", " (optional, default: {})",
nu_highlight_string( nu_highlight_string(
&value.to_parsable_string(", ", &engine_state.config), &value.to_parsable_string(", ", &nu_config),
engine_state, engine_state,
stack stack
) )
@ -339,7 +352,7 @@ fn get_documentation(
let _ = writeln!( let _ = writeln!(
long_desc, long_desc,
" {}", " {}",
item.to_expanded_string("", engine_state.get_config()) item.to_expanded_string("", &nu_config)
.replace('\n', "\n ") .replace('\n', "\n ")
.trim() .trim()
); );
@ -358,15 +371,16 @@ fn get_documentation(
fn get_ansi_color_for_component_or_default( fn get_ansi_color_for_component_or_default(
engine_state: &EngineState, engine_state: &EngineState,
nu_config: &Config,
theme_component: &str, theme_component: &str,
default: &str, default: &str,
) -> String { ) -> String {
if let Some(color) = &engine_state.get_config().color_config.get(theme_component) { if let Some(color) = &nu_config.color_config.get(theme_component) {
let caller_stack = &mut Stack::new().capture(); let caller_stack = &mut Stack::new().capture();
let span = Span::unknown(); let span = Span::unknown();
let span_id = UNKNOWN_SPAN_ID; let span_id = UNKNOWN_SPAN_ID;
let argument_opt = get_argument_for_color_value(engine_state, color, span, span_id); let argument_opt = get_argument_for_color_value(nu_config, color, span, span_id);
// Call ansi command using argument // Call ansi command using argument
if let Some(argument) = argument_opt { if let Some(argument) = argument_opt {
@ -394,8 +408,8 @@ fn get_ansi_color_for_component_or_default(
} }
fn get_argument_for_color_value( fn get_argument_for_color_value(
engine_state: &EngineState, nu_config: &Config,
color: &&Value, color: &Value,
span: Span, span: Span,
span_id: SpanId, span_id: SpanId,
) -> Option<Argument> { ) -> Option<Argument> {
@ -412,9 +426,7 @@ fn get_argument_for_color_value(
Type::String, Type::String,
), ),
Expression::new_existing( Expression::new_existing(
Expr::String( Expr::String(v.clone().to_expanded_string("", nu_config)),
v.clone().to_expanded_string("", engine_state.get_config()),
),
span, span,
span_id, span_id,
Type::String, Type::String,
@ -456,6 +468,7 @@ pub fn document_shape(shape: SyntaxShape) -> SyntaxShape {
pub fn get_flags_section<F>( pub fn get_flags_section<F>(
engine_state_opt: Option<&EngineState>, engine_state_opt: Option<&EngineState>,
nu_config_opt: Option<&Config>,
signature: &Signature, signature: &Signature,
mut value_formatter: F, // format default Value (because some calls cant access config or nu-highlight) mut value_formatter: F, // format default Value (because some calls cant access config or nu-highlight)
) -> String ) -> String
@ -470,13 +483,26 @@ where
// Sometimes we want to get the flags without engine_state // Sometimes we want to get the flags without engine_state
// For example, in nu-plugin. In that case, we fall back on default values // For example, in nu-plugin. In that case, we fall back on default values
if let Some(engine_state) = engine_state_opt { if let Some(engine_state) = engine_state_opt {
help_section_name = let nu_config = nu_config_opt.unwrap_or_else(|| engine_state.get_config());
get_ansi_color_for_component_or_default(engine_state, "shape_string", "\x1b[32m"); // default: green help_section_name = get_ansi_color_for_component_or_default(
help_subcolor_one = engine_state,
get_ansi_color_for_component_or_default(engine_state, "shape_external", "\x1b[36m"); // default: cyan nu_config,
// was const bb: &str = "\x1b[1;34m"; // bold blue "shape_string",
help_subcolor_two = "\x1b[32m",
get_ansi_color_for_component_or_default(engine_state, "shape_block", "\x1b[94m"); ); // default: green
help_subcolor_one = get_ansi_color_for_component_or_default(
engine_state,
nu_config,
"shape_external",
"\x1b[36m",
); // default: cyan
// was const bb: &str = "\x1b[1;34m"; // bold blue
help_subcolor_two = get_ansi_color_for_component_or_default(
engine_state,
nu_config,
"shape_block",
"\x1b[94m",
);
// default: light blue (nobold, should be bolding the *names*) // default: light blue (nobold, should be bolding the *names*)
} else { } else {
help_section_name = "\x1b[32m".to_string(); help_section_name = "\x1b[32m".to_string();

View file

@ -3,7 +3,7 @@ use nu_path::canonicalize_with;
use nu_protocol::{ use nu_protocol::{
ast::Expr, ast::Expr,
engine::{Call, EngineState, Stack, StateWorkingSet}, engine::{Call, EngineState, Stack, StateWorkingSet},
Config, ShellError, Span, Value, VarId, ShellError, Span, Value, VarId,
}; };
use std::{ use std::{
collections::HashMap, collections::HashMap,
@ -323,18 +323,6 @@ pub fn find_in_dirs_env(
Ok(check_dir(lib_dirs).or_else(|| check_dir(lib_dirs_fallback))) Ok(check_dir(lib_dirs).or_else(|| check_dir(lib_dirs_fallback)))
} }
/// Get config
///
/// This combines config stored in permanent state and any runtime updates to the environment. This
/// is the canonical way to fetch config at runtime when you have Stack available.
pub fn get_config(engine_state: &EngineState, stack: &Stack) -> Config {
if let Some(mut config_record) = stack.get_env_var(engine_state, "config") {
config_record.parse_as_config(engine_state.get_config()).0
} else {
engine_state.get_config().clone()
}
}
fn get_converted_value( fn get_converted_value(
engine_state: &EngineState, engine_state: &EngineState,
stack: &Stack, stack: &Stack,

View file

@ -1,6 +1,6 @@
use crate::eval_ir_block; use crate::eval_ir_block;
#[allow(deprecated)] #[allow(deprecated)]
use crate::{current_dir, get_config, get_full_help}; use crate::{current_dir, get_full_help};
use nu_path::{expand_path_with, AbsolutePathBuf}; use nu_path::{expand_path_with, AbsolutePathBuf};
use nu_protocol::{ use nu_protocol::{
ast::{ ast::{
@ -14,7 +14,7 @@ use nu_protocol::{
Spanned, Type, Value, VarId, ENV_VARIABLE_ID, Spanned, Type, Value, VarId, ENV_VARIABLE_ID,
}; };
use nu_utils::IgnoreCaseExt; use nu_utils::IgnoreCaseExt;
use std::{borrow::Cow, fs::OpenOptions, path::PathBuf}; use std::{fs::OpenOptions, path::PathBuf, sync::Arc};
pub fn eval_call<D: DebugContext>( pub fn eval_call<D: DebugContext>(
engine_state: &EngineState, engine_state: &EngineState,
@ -196,6 +196,9 @@ pub fn redirect_env(engine_state: &EngineState, caller_stack: &mut Stack, callee
for (var, value) in callee_stack.get_stack_env_vars() { for (var, value) in callee_stack.get_stack_env_vars() {
caller_stack.add_env_var(var, value); caller_stack.add_env_var(var, value);
} }
// set config to callee config, to capture any updates to that
caller_stack.config = callee_stack.config.clone();
} }
fn eval_external( fn eval_external(
@ -652,8 +655,8 @@ impl Eval for EvalRuntime {
type MutState = Stack; type MutState = Stack;
fn get_config<'a>(engine_state: Self::State<'a>, stack: &mut Stack) -> Cow<'a, Config> { fn get_config(engine_state: Self::State<'_>, stack: &mut Stack) -> Arc<Config> {
Cow::Owned(get_config(engine_state, stack)) stack.get_config(engine_state)
} }
fn eval_filepath( fn eval_filepath(
@ -843,7 +846,14 @@ impl Eval for EvalRuntime {
}); });
} }
let is_config = original_key == "config";
stack.add_env_var(original_key, value); stack.add_env_var(original_key, value);
// Trigger the update to config, if we modified that.
if is_config {
stack.update_config(engine_state)?;
}
} else { } else {
lhs.upsert_data_at_cell_path(&cell_path.tail, rhs)?; lhs.upsert_data_at_cell_path(&cell_path.tail, rhs)?;
stack.add_var(*var_id, lhs); stack.add_var(*var_id, lhs);

View file

@ -64,8 +64,8 @@ fn convert_value_to_string(
let has_no_head = cols.is_empty() || (cols.len() == 1 && cols[0].is_empty()); let has_no_head = cols.is_empty() || (cols.len() == 1 && cols[0].is_empty());
let has_single_value = vals.len() == 1 && vals[0].len() == 1; let has_single_value = vals.len() == 1 && vals[0].len() == 1;
if !has_no_head && has_single_value { if !has_no_head && has_single_value {
let config = engine_state.get_config(); let config = stack.get_config(engine_state);
Ok(vals[0][0].to_abbreviated_string(config)) Ok(vals[0][0].to_abbreviated_string(&config))
} else { } else {
let config = engine_state.get_config(); let config = engine_state.get_config();
let style_computer = StyleComputer::from_config(engine_state, stack); let style_computer = StyleComputer::from_config(engine_state, stack);

View file

@ -63,10 +63,10 @@ impl Command for Explore {
let tail: bool = call.has_flag(engine_state, stack, "tail")?; let tail: bool = call.has_flag(engine_state, stack, "tail")?;
let peek_value: bool = call.has_flag(engine_state, stack, "peek")?; let peek_value: bool = call.has_flag(engine_state, stack, "peek")?;
let nu_config = engine_state.get_config(); let nu_config = stack.get_config(engine_state);
let style_computer = StyleComputer::from_config(engine_state, stack); let style_computer = StyleComputer::from_config(engine_state, stack);
let mut explore_config = ExploreConfig::from_nu_config(nu_config); let mut explore_config = ExploreConfig::from_nu_config(&nu_config);
explore_config.table.show_header = show_head; explore_config.table.show_header = show_head;
explore_config.table.show_index = show_index; explore_config.table.show_index = show_index;
explore_config.table.separator_style = lookup_color(&style_computer, "separator"); explore_config.table.separator_style = lookup_color(&style_computer, "separator");
@ -74,7 +74,7 @@ impl Command for Explore {
let lscolors = create_lscolors(engine_state, stack); let lscolors = create_lscolors(engine_state, stack);
let config = PagerConfig::new( let config = PagerConfig::new(
nu_config, &nu_config,
&explore_config, &explore_config,
&style_computer, &style_computer,
&lscolors, &lscolors,

View file

@ -16,6 +16,7 @@ nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
nu-system = { path = "../nu-system", version = "0.95.1" } nu-system = { path = "../nu-system", version = "0.95.1" }
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.95.1" } nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.95.1" }
nu-plugin-core = { path = "../nu-plugin-core", version = "0.95.1", default-features = false } nu-plugin-core = { path = "../nu-plugin-core", version = "0.95.1", default-features = false }
nu-utils = { path = "../nu-utils", version = "0.95.1" }
serde = { workspace = true } serde = { workspace = true }
log = { workspace = true } log = { workspace = true }
@ -31,4 +32,4 @@ local-socket = ["nu-plugin-core/local-socket"]
windows = { workspace = true, features = [ windows = { workspace = true, features = [
# For setting process creation flags # For setting process creation flags
"Win32_System_Threading", "Win32_System_Threading",
] } ] }

View file

@ -20,7 +20,7 @@ pub trait PluginExecutionContext: Send + Sync {
/// The pipeline externals state, for tracking the foreground process group, if present /// The pipeline externals state, for tracking the foreground process group, if present
fn pipeline_externals_state(&self) -> Option<&Arc<(AtomicU32, AtomicU32)>>; fn pipeline_externals_state(&self) -> Option<&Arc<(AtomicU32, AtomicU32)>>;
/// Get engine configuration /// Get engine configuration
fn get_config(&self) -> Result<Config, ShellError>; fn get_config(&self) -> Result<Arc<Config>, ShellError>;
/// Get plugin configuration /// Get plugin configuration
fn get_plugin_config(&self) -> Result<Option<Value>, ShellError>; fn get_plugin_config(&self) -> Result<Option<Value>, ShellError>;
/// Get an environment variable from `$env` /// Get an environment variable from `$env`
@ -85,8 +85,8 @@ impl<'a> PluginExecutionContext for PluginExecutionCommandContext<'a> {
Some(&self.engine_state.pipeline_externals_state) Some(&self.engine_state.pipeline_externals_state)
} }
fn get_config(&self) -> Result<Config, ShellError> { fn get_config(&self) -> Result<Arc<Config>, ShellError> {
Ok(nu_engine::get_config(&self.engine_state, &self.stack)) Ok(self.stack.get_config(&self.engine_state))
} }
fn get_plugin_config(&self) -> Result<Option<Value>, ShellError> { fn get_plugin_config(&self) -> Result<Option<Value>, ShellError> {
@ -239,7 +239,7 @@ impl PluginExecutionContext for PluginExecutionBogusContext {
None None
} }
fn get_config(&self) -> Result<Config, ShellError> { fn get_config(&self) -> Result<Arc<Config>, ShellError> {
Err(ShellError::NushellFailed { Err(ShellError::NushellFailed {
msg: "get_config not implemented on bogus".into(), msg: "get_config not implemented on bogus".into(),
}) })

View file

@ -76,7 +76,7 @@ impl Command for PluginDeclaration {
EvaluatedCall::try_from_call(call, engine_state, stack, eval_expression)?; EvaluatedCall::try_from_call(call, engine_state, stack, eval_expression)?;
// Get the engine config // Get the engine config
let engine_config = nu_engine::get_config(engine_state, stack); let engine_config = stack.get_config(engine_state);
// Get, or start, the plugin. // Get, or start, the plugin.
let plugin = self let plugin = self

View file

@ -14,6 +14,7 @@ use nu_protocol::{
ast::Operator, CustomValue, IntoSpanned, PipelineData, PluginMetadata, PluginSignature, ast::Operator, CustomValue, IntoSpanned, PipelineData, PluginMetadata, PluginSignature,
ShellError, Signals, Span, Spanned, Value, ShellError, Signals, Span, Spanned, Value,
}; };
use nu_utils::SharedCow;
use std::{ use std::{
collections::{btree_map, BTreeMap}, collections::{btree_map, BTreeMap},
sync::{mpsc, Arc, OnceLock}, sync::{mpsc, Arc, OnceLock},
@ -1260,7 +1261,7 @@ pub(crate) fn handle_engine_call(
match call { match call {
EngineCall::GetConfig => { EngineCall::GetConfig => {
let config = Box::new(context.get_config()?); let config = SharedCow::from(context.get_config()?);
Ok(EngineCallResponse::Config(config)) Ok(EngineCallResponse::Config(config))
} }
EngineCall::GetPluginConfig => { EngineCall::GetPluginConfig => {

View file

@ -25,6 +25,7 @@ use nu_protocol::{
ast::Operator, engine::Closure, ByteStreamType, Config, LabeledError, PipelineData, ast::Operator, engine::Closure, ByteStreamType, Config, LabeledError, PipelineData,
PluginMetadata, PluginSignature, ShellError, Span, Spanned, Value, PluginMetadata, PluginSignature, ShellError, Span, Spanned, Value,
}; };
use nu_utils::SharedCow;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
@ -553,7 +554,7 @@ impl<D> EngineCall<D> {
pub enum EngineCallResponse<D> { pub enum EngineCallResponse<D> {
Error(ShellError), Error(ShellError),
PipelineData(D), PipelineData(D),
Config(Box<Config>), Config(SharedCow<Config>),
ValueMap(HashMap<String, Value>), ValueMap(HashMap<String, Value>),
} }

View file

@ -15,6 +15,7 @@ nu-engine = { path = "../nu-engine", version = "0.95.1" }
nu-protocol = { path = "../nu-protocol", version = "0.95.1" } nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.95.1" } nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.95.1" }
nu-plugin-core = { path = "../nu-plugin-core", version = "0.95.1", default-features = false } nu-plugin-core = { path = "../nu-plugin-core", version = "0.95.1", default-features = false }
nu-utils = { path = "../nu-utils", version = "0.95.1" }
log = { workspace = true } log = { workspace = true }
thiserror = "1.0" thiserror = "1.0"
@ -29,4 +30,4 @@ local-socket = ["nu-plugin-core/local-socket"]
[target.'cfg(target_family = "unix")'.dependencies] [target.'cfg(target_family = "unix")'.dependencies]
# For setting the process group ID (EnterForeground / LeaveForeground) # For setting the process group ID (EnterForeground / LeaveForeground)
nix = { workspace = true, default-features = false, features = ["process"] } nix = { workspace = true, default-features = false, features = ["process"] }

View file

@ -14,6 +14,7 @@ use nu_protocol::{
engine::Closure, Config, LabeledError, PipelineData, PluginMetadata, PluginSignature, engine::Closure, Config, LabeledError, PipelineData, PluginMetadata, PluginSignature,
ShellError, Signals, Span, Spanned, Value, ShellError, Signals, Span, Spanned, Value,
}; };
use nu_utils::SharedCow;
use std::{ use std::{
collections::{btree_map, BTreeMap, HashMap}, collections::{btree_map, BTreeMap, HashMap},
sync::{mpsc, Arc}, sync::{mpsc, Arc},
@ -525,9 +526,9 @@ impl EngineInterface {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
pub fn get_config(&self) -> Result<Box<Config>, ShellError> { pub fn get_config(&self) -> Result<Arc<Config>, ShellError> {
match self.engine_call(EngineCall::GetConfig)? { match self.engine_call(EngineCall::GetConfig)? {
EngineCallResponse::Config(config) => Ok(config), EngineCallResponse::Config(config) => Ok(SharedCow::into_arc(config)),
EngineCallResponse::Error(err) => Err(err), EngineCallResponse::Error(err) => Err(err),
_ => Err(ShellError::PluginFailedToDecode { _ => Err(ShellError::PluginFailedToDecode {
msg: "Received unexpected response for EngineCall::GetConfig".into(), msg: "Received unexpected response for EngineCall::GetConfig".into(),

View file

@ -670,7 +670,7 @@ fn print_help(plugin: &impl Plugin, encoder: impl PluginEncoder) {
} }
}) })
.and_then(|_| { .and_then(|_| {
let flags = get_flags_section(None, &signature, |v| format!("{:#?}", v)); let flags = get_flags_section(None, None, &signature, |v| format!("{:#?}", v));
write!(help, "{flags}") write!(help, "{flags}")
}) })
.and_then(|_| writeln!(help, "\nParameters:")) .and_then(|_| writeln!(help, "\nParameters:"))

View file

@ -301,28 +301,11 @@ impl EngineState {
stack: &mut Stack, stack: &mut Stack,
cwd: impl AsRef<Path>, cwd: impl AsRef<Path>,
) -> Result<(), ShellError> { ) -> Result<(), ShellError> {
let mut config_updated = false;
for mut scope in stack.env_vars.drain(..) { for mut scope in stack.env_vars.drain(..) {
for (overlay_name, mut env) in Arc::make_mut(&mut scope).drain() { for (overlay_name, mut env) in Arc::make_mut(&mut scope).drain() {
if let Some(env_vars) = Arc::make_mut(&mut self.env_vars).get_mut(&overlay_name) { if let Some(env_vars) = Arc::make_mut(&mut self.env_vars).get_mut(&overlay_name) {
// Updating existing overlay // Updating existing overlay
for (k, v) in env.drain() { env_vars.extend(env.drain());
if k == "config" {
// Don't insert the record as the "config" env var as-is.
// Instead, mutate a clone of it with into_config(), and put THAT in env_vars.
let mut new_record = v.clone();
let (config, error) = new_record.parse_as_config(&self.config);
self.config = Arc::new(config);
config_updated = true;
env_vars.insert(k, new_record);
if let Some(e) = error {
return Err(e);
}
} else {
env_vars.insert(k, v);
}
}
} else { } else {
// Pushing a new overlay // Pushing a new overlay
Arc::make_mut(&mut self.env_vars).insert(overlay_name, env); Arc::make_mut(&mut self.env_vars).insert(overlay_name, env);
@ -333,7 +316,10 @@ impl EngineState {
// TODO: better error // TODO: better error
std::env::set_current_dir(cwd)?; std::env::set_current_dir(cwd)?;
if config_updated { if let Some(config) = stack.config.take() {
// If config was updated in the stack, replace it.
self.config = config;
// Make plugin GC config changes take effect immediately. // Make plugin GC config changes take effect immediately.
#[cfg(feature = "plugin")] #[cfg(feature = "plugin")]
self.update_plugin_gc_configs(&self.config.plugin_gc); self.update_plugin_gc_configs(&self.config.plugin_gc);
@ -738,18 +724,24 @@ impl EngineState {
&[0u8; 0] &[0u8; 0]
} }
pub fn get_config(&self) -> &Config { /// Get the global config from the engine state.
///
/// Use [`Stack::get_config()`] instead whenever the `Stack` is available, as it takes into
/// account local changes to `$env.config`.
pub fn get_config(&self) -> &Arc<Config> {
&self.config &self.config
} }
pub fn set_config(&mut self, conf: Config) { pub fn set_config(&mut self, conf: impl Into<Arc<Config>>) {
let conf = conf.into();
#[cfg(feature = "plugin")] #[cfg(feature = "plugin")]
if conf.plugin_gc != self.config.plugin_gc { if conf.plugin_gc != self.config.plugin_gc {
// Make plugin GC config changes take effect immediately. // Make plugin GC config changes take effect immediately.
self.update_plugin_gc_configs(&conf.plugin_gc); self.update_plugin_gc_configs(&conf.plugin_gc);
} }
self.config = Arc::new(conf); self.config = conf;
} }
/// Fetch the configuration for a plugin /// Fetch the configuration for a plugin
@ -1137,7 +1129,7 @@ mod engine_state_tests {
let mut plugins = HashMap::new(); let mut plugins = HashMap::new();
plugins.insert("example".into(), Value::string("value", Span::test_data())); plugins.insert("example".into(), Value::string("value", Span::test_data()));
let mut config = engine_state.get_config().clone(); let mut config = Config::clone(engine_state.get_config());
config.plugins = plugins; config.plugins = plugins;
engine_state.set_config(config); engine_state.set_config(config);

View file

@ -3,7 +3,7 @@ use crate::{
ArgumentStack, EngineState, ErrorHandlerStack, Redirection, StackCallArgGuard, ArgumentStack, EngineState, ErrorHandlerStack, Redirection, StackCallArgGuard,
StackCaptureGuard, StackIoGuard, StackOutDest, DEFAULT_OVERLAY_NAME, StackCaptureGuard, StackIoGuard, StackOutDest, DEFAULT_OVERLAY_NAME,
}, },
OutDest, ShellError, Span, Value, VarId, ENV_VARIABLE_ID, NU_VARIABLE_ID, Config, OutDest, ShellError, Span, Value, VarId, ENV_VARIABLE_ID, NU_VARIABLE_ID,
}; };
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
@ -51,6 +51,8 @@ pub struct Stack {
pub parent_stack: Option<Arc<Stack>>, pub parent_stack: Option<Arc<Stack>>,
/// Variables that have been deleted (this is used to hide values from parent stack lookups) /// Variables that have been deleted (this is used to hide values from parent stack lookups)
pub parent_deletions: Vec<VarId>, pub parent_deletions: Vec<VarId>,
/// Locally updated config. Use [`.get_config()`] to access correctly.
pub config: Option<Arc<Config>>,
pub(crate) out_dest: StackOutDest, pub(crate) out_dest: StackOutDest,
} }
@ -80,6 +82,7 @@ impl Stack {
recursion_count: 0, recursion_count: 0,
parent_stack: None, parent_stack: None,
parent_deletions: vec![], parent_deletions: vec![],
config: None,
out_dest: StackOutDest::new(), out_dest: StackOutDest::new(),
} }
} }
@ -100,6 +103,7 @@ impl Stack {
recursion_count: parent.recursion_count, recursion_count: parent.recursion_count,
vars: vec![], vars: vec![],
parent_deletions: vec![], parent_deletions: vec![],
config: parent.config.clone(),
out_dest: parent.out_dest.clone(), out_dest: parent.out_dest.clone(),
parent_stack: Some(parent), parent_stack: Some(parent),
} }
@ -126,6 +130,7 @@ impl Stack {
unique_stack.env_vars = child.env_vars; unique_stack.env_vars = child.env_vars;
unique_stack.env_hidden = child.env_hidden; unique_stack.env_hidden = child.env_hidden;
unique_stack.active_overlays = child.active_overlays; unique_stack.active_overlays = child.active_overlays;
unique_stack.config = child.config;
unique_stack unique_stack
} }
@ -192,6 +197,36 @@ impl Stack {
} }
} }
/// Get the local config if set, otherwise the config from the engine state.
///
/// This is the canonical way to get [`Config`] when [`Stack`] is available.
pub fn get_config(&self, engine_state: &EngineState) -> Arc<Config> {
self.config
.clone()
.unwrap_or_else(|| engine_state.config.clone())
}
/// Update the local config with the config stored in the `config` environment variable. Run
/// this after assigning to `$env.config`.
///
/// The config will be updated with successfully parsed values even if an error occurs.
pub fn update_config(&mut self, engine_state: &EngineState) -> Result<(), ShellError> {
if let Some(mut config) = self.get_env_var(engine_state, "config") {
let existing_config = self.get_config(engine_state);
let (new_config, error) = config.parse_as_config(&existing_config);
self.config = Some(new_config.into());
// The config value is modified by the update, so we should add it again
self.add_env_var("config".into(), config);
match error {
None => Ok(()),
Some(err) => Err(err),
}
} else {
self.config = None;
Ok(())
}
}
pub fn add_var(&mut self, var_id: VarId, value: Value) { pub fn add_var(&mut self, var_id: VarId, value: Value) {
//self.vars.insert(var_id, value); //self.vars.insert(var_id, value);
for (id, val) in &mut self.vars { for (id, val) in &mut self.vars {
@ -272,6 +307,7 @@ impl Stack {
recursion_count: self.recursion_count, recursion_count: self.recursion_count,
parent_stack: None, parent_stack: None,
parent_deletions: vec![], parent_deletions: vec![],
config: self.config.clone(),
out_dest: self.out_dest.clone(), out_dest: self.out_dest.clone(),
} }
} }
@ -305,6 +341,7 @@ impl Stack {
recursion_count: self.recursion_count, recursion_count: self.recursion_count,
parent_stack: None, parent_stack: None,
parent_deletions: vec![], parent_deletions: vec![],
config: self.config.clone(),
out_dest: self.out_dest.clone(), out_dest: self.out_dest.clone(),
} }
} }

View file

@ -627,9 +627,9 @@ impl<'a> StateWorkingSet<'a> {
/// Returns a reference to the config stored at permanent state /// Returns a reference to the config stored at permanent state
/// ///
/// At runtime, you most likely want to call nu_engine::env::get_config because this method /// At runtime, you most likely want to call [`Stack::get_config()`][super::Stack::get_config()]
/// does not capture environment updates during runtime. /// because this method does not capture environment updates during runtime.
pub fn get_config(&self) -> &Config { pub fn get_config(&self) -> &Arc<Config> {
&self.permanent_state.config &self.permanent_state.config
} }

View file

@ -7,7 +7,7 @@ use crate::{
debugger::DebugContext, debugger::DebugContext,
Config, GetSpan, Range, Record, ShellError, Span, Value, VarId, ENV_VARIABLE_ID, Config, GetSpan, Range, Record, ShellError, Span, Value, VarId, ENV_VARIABLE_ID,
}; };
use std::{borrow::Cow, collections::HashMap}; use std::{collections::HashMap, sync::Arc};
/// To share implementations for regular eval and const eval /// To share implementations for regular eval and const eval
pub trait Eval { pub trait Eval {
@ -316,7 +316,7 @@ pub trait Eval {
} }
} }
fn get_config<'a>(state: Self::State<'a>, mut_state: &mut Self::MutState) -> Cow<'a, Config>; fn get_config(state: Self::State<'_>, mut_state: &mut Self::MutState) -> Arc<Config>;
fn eval_filepath( fn eval_filepath(
state: Self::State<'_>, state: Self::State<'_>,

View file

@ -11,8 +11,8 @@ use crate::{
}; };
use nu_system::os_info::{get_kernel_version, get_os_arch, get_os_family, get_os_name}; use nu_system::os_info::{get_kernel_version, get_os_arch, get_os_family, get_os_name};
use std::{ use std::{
borrow::Cow,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc,
}; };
/// Create a Value for `$nu`. /// Create a Value for `$nu`.
@ -364,8 +364,8 @@ impl Eval for EvalConst {
type MutState = (); type MutState = ();
fn get_config<'a>(state: Self::State<'a>, _: &mut ()) -> Cow<'a, Config> { fn get_config(state: Self::State<'_>, _: &mut ()) -> Arc<Config> {
Cow::Borrowed(state.get_config()) state.get_config().clone()
} }
fn eval_filepath( fn eval_filepath(