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-protocol",
"nu-protocol",
"nu-utils",
"serde",
"thiserror",
"typetag",
@ -3286,6 +3287,7 @@ dependencies = [
"nu-plugin-protocol",
"nu-protocol",
"nu-system",
"nu-utils",
"serde",
"typetag",
"windows 0.54.0",

View File

@ -53,9 +53,8 @@ pub fn evaluate_commands(
// Parse the source code
let (block, delta) = {
if let Some(ref t_mode) = table_mode {
let mut config = engine_state.get_config().clone();
config.table_mode = t_mode.coerce_str()?.parse().unwrap_or_default();
engine_state.set_config(config);
Arc::make_mut(&mut engine_state.config).table_mode =
t_mode.coerce_str()?.parse().unwrap_or_default();
}
let mut working_set = StateWorkingSet::new(engine_state);

View File

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

View File

@ -1,3 +1,5 @@
use std::sync::Arc;
use nu_engine::command_prelude::*;
use reedline::{Highlighter, StyledText};
@ -33,13 +35,10 @@ impl Command for NuHighlight {
let head = call.head;
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 {
engine_state,
stack: std::sync::Arc::new(stack.clone()),
config,
engine_state: Arc::new(engine_state.clone()),
stack: Arc::new(stack.clone()),
};
input.map(

View File

@ -77,13 +77,19 @@ pub(crate) fn add_menus(
mut line_editor: Reedline,
engine_state_ref: Arc<EngineState>,
stack: &Stack,
config: &Config,
config: Arc<Config>,
) -> Result<Reedline, ShellError> {
//log::trace!("add_menus: config: {:#?}", &config);
line_editor = line_editor.clear_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
@ -100,7 +106,7 @@ pub(crate) fn add_menus(
if !config
.menus
.iter()
.any(|menu| menu.name.to_expanded_string("", config) == name)
.any(|menu| menu.name.to_expanded_string("", &config) == name)
{
let (block, delta) = {
let mut working_set = StateWorkingSet::new(&engine_state);
@ -137,7 +143,7 @@ pub(crate) fn add_menus(
&menu,
new_engine_state_ref.clone(),
stack,
config,
config.clone(),
)?;
}
}
@ -151,27 +157,27 @@ fn add_menu(
menu: &ParsedMenu,
engine_state: Arc<EngineState>,
stack: &Stack,
config: &Config,
config: Arc<Config>,
) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span();
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() {
"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),
"ide" => add_ide_menu(line_editor, menu, engine_state, stack, config),
"description" => add_description_menu(line_editor, menu, engine_state, stack, config),
_ => Err(ShellError::UnsupportedConfigValue {
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(),
}),
}
} else {
Err(ShellError::UnsupportedConfigValue {
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(),
})
}
@ -282,9 +288,9 @@ pub(crate) fn add_list_menu(
menu: &ParsedMenu,
engine_state: Arc<EngineState>,
stack: &Stack,
config: &Config,
config: Arc<Config>,
) -> 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 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);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -337,7 +343,7 @@ pub(crate) fn add_list_menu(
}
_ => Err(ShellError::UnsupportedConfigValue {
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(),
}),
}
@ -349,10 +355,10 @@ pub(crate) fn add_ide_menu(
menu: &ParsedMenu,
engine_state: Arc<EngineState>,
stack: &Stack,
config: &Config,
config: Arc<Config>,
) -> Result<Reedline, ShellError> {
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);
if let Value::Record { val, .. } = &menu.menu_type {
@ -417,7 +423,7 @@ pub(crate) fn add_ide_menu(
} else {
return Err(ShellError::UnsupportedConfigValue {
expected: "bool or record".to_string(),
value: border.to_abbreviated_string(config),
value: border.to_abbreviated_string(&config),
span: border.span(),
});
}
@ -441,7 +447,7 @@ pub(crate) fn add_ide_menu(
_ => {
return Err(ShellError::UnsupportedConfigValue {
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(),
});
}
@ -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);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -535,7 +541,7 @@ pub(crate) fn add_ide_menu(
}
_ => Err(ShellError::UnsupportedConfigValue {
expected: "block or omitted value".to_string(),
value: menu.source.to_abbreviated_string(config),
value: menu.source.to_abbreviated_string(&config),
span,
}),
}
@ -547,9 +553,9 @@ pub(crate) fn add_description_menu(
menu: &ParsedMenu,
engine_state: Arc<EngineState>,
stack: &Stack,
config: &Config,
config: Arc<Config>,
) -> 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 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);
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();
match &menu.source {
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 {
menu: Box::new(description_menu),
completer,
@ -638,7 +644,7 @@ pub(crate) fn add_description_menu(
}
_ => Err(ShellError::UnsupportedConfigValue {
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(),
}),
}

View File

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

View File

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

View File

@ -239,7 +239,7 @@ fn to_html(
let partial = call.has_flag(engine_state, stack, "partial")?;
let list = call.has_flag(engine_state, stack, "list")?;
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 headers = merge_descriptors(&vec_of_values);

View File

@ -1,5 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::{ast::PathMember, engine::StateWorkingSet, ListStream};
use nu_protocol::{ast::PathMember, engine::StateWorkingSet, Config, ListStream};
#[derive(Clone)]
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);
stack.add_var(it_id, input_val.clone());
let config = stack.get_config(engine_state);
match specified_pattern {
Err(e) => Err(e),
Ok(pattern) => {
@ -56,7 +58,7 @@ impl Command for FormatPattern {
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,
format_operations: &[FormatOperation],
engine_state: &EngineState,
config: &Config,
head_span: Span,
) -> Result<PipelineData, ShellError> {
let data_as_value = input_data;
// We can only handle a Record or a List of Records
match data_as_value {
Value::Record { .. } => {
match format_record(format_operations, &data_as_value, engine_state) {
Ok(value) => Ok(PipelineData::Value(Value::string(value, head_span), None)),
Err(value) => Err(value),
}
}
Value::Record { .. } => match format_record(format_operations, &data_as_value, config) {
Ok(value) => Ok(PipelineData::Value(Value::string(value, head_span), None)),
Err(value) => Err(value),
},
Value::List { vals, .. } => {
let mut list = vec![];
for val in vals.iter() {
match val {
Value::Record { .. } => {
match format_record(format_operations, val, engine_state) {
Ok(value) => {
list.push(Value::string(value, head_span));
}
Err(value) => {
return Err(value);
}
Value::Record { .. } => match format_record(format_operations, val, config) {
Ok(value) => {
list.push(Value::string(value, head_span));
}
}
Err(value) => {
return Err(value);
}
},
Value::Error { error, .. } => return Err(*error.clone()),
_ => {
return Err(ShellError::OnlySupportsThisInputType {
@ -237,9 +236,8 @@ fn format(
fn format_record(
format_operations: &[FormatOperation],
data_as_value: &Value,
engine_state: &EngineState,
config: &Config,
) -> Result<String, ShellError> {
let config = engine_state.get_config();
let mut output = String::new();
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 nu_ansi_term::{Color, Style};
use nu_engine::{env::get_config, ClosureEvalOnce};
use nu_engine::ClosureEvalOnce;
use nu_protocol::{
cli_error::CliError,
engine::{Closure, EngineState, Stack, StateWorkingSet},
@ -114,7 +114,7 @@ impl<'a> StyleComputer<'a> {
// The main constructor.
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
#[rustfmt::skip]

View File

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

View File

@ -33,7 +33,7 @@ impl Command for Debug {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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")?;
// Should PipelineData::Empty result in an error here?

View File

@ -170,7 +170,7 @@ fn rm(
}
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 rm_always_trash {

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::Config;
use url::Url;
#[derive(Clone)]
@ -38,11 +39,15 @@ impl Command for SubCommand {
fn run(
&self,
engine_state: &EngineState,
_: &mut Stack,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> 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> {
@ -68,12 +73,12 @@ impl Command for SubCommand {
}
}
fn get_url_string(value: &Value, engine_state: &EngineState) -> String {
value.to_expanded_string("", engine_state.get_config())
fn get_url_string(value: &Value, config: &Config) -> String {
value.to_expanded_string("", config)
}
fn parse(value: Value, head: Span, engine_state: &EngineState) -> Result<PipelineData, ShellError> {
let url_string = get_url_string(&value, engine_state);
fn parse(value: Value, head: Span, config: &Config) -> Result<PipelineData, ShellError> {
let url_string = get_url_string(&value, config);
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 escape: bool = call.has_flag(engine_state, stack, "escape")?;
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 {
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_engine::command_prelude::*;
use nu_protocol::Config;
pub struct Arguments {
cell_paths: Option<Vec<CellPath>>,
config: Config,
config: Arc<Config>,
}
impl CmdArgument for Arguments {
@ -51,11 +53,8 @@ impl Command for SubCommand {
) -> Result<PipelineData, ShellError> {
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let config = engine_state.get_config();
let args = Arguments {
cell_paths,
config: config.clone(),
};
let config = stack.get_config(engine_state);
let args = Arguments { cell_paths, config };
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 index = call.has_flag(engine_state, stack, "index")?;
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 {
PipelineData::Value(Value::Range { .. }, ..)
@ -89,9 +90,9 @@ impl Command for InputList {
let display_value = if let Some(ref cellpath) = display_path {
val.clone()
.follow_cell_path(&cellpath.members, false)?
.to_expanded_string(", ", engine_state.get_config())
.to_expanded_string(", ", &config)
} else {
val.to_expanded_string(", ", engine_state.get_config())
val.to_expanded_string(", ", &config)
};
Ok(Options {
name: display_value,

View File

@ -65,7 +65,7 @@ impl Command for StorInsert {
let span = call.head;
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 config = engine_state.get_config();
// let config = stack.get_config(engine_state);
let db = Box::new(SQLiteDatabase::new(
std::path::Path::new(MEMORY_DB),
Signals::empty(),

View File

@ -1,7 +1,7 @@
use itertools::Itertools;
use nu_engine::command_prelude::*;
use nu_protocol::Range;
use std::{io::Cursor, iter::Peekable, str::CharIndices};
use nu_protocol::{Config, Range};
use std::{io::Cursor, iter::Peekable, str::CharIndices, sync::Arc};
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 noheader = call.has_flag(engine_state, stack, "no-headers")?;
let range: Option<Range> = call.get_flag(engine_state, stack, "combine-columns")?;
let config = stack.get_config(engine_state);
let args = Arguments {
noheader,
num_rows_to_skip,
range,
config,
};
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 noheader = call.has_flag_const(working_set, "no-headers")?;
let range: Option<Range> = call.get_flag_const(working_set, "combine-columns")?;
let config = working_set.get_config().clone();
let args = Arguments {
noheader,
num_rows_to_skip,
range,
config,
};
if call.has_flag_const(working_set, "guess")? {
@ -152,6 +156,7 @@ struct Arguments {
num_rows_to_skip: Option<usize>,
noheader: bool,
range: Option<Range>,
config: Arc<Config>,
}
fn guess_width(
@ -163,7 +168,7 @@ fn guess_width(
use super::guess_width::GuessWidth;
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 {
input = input.lines().skip(rows).map(|x| x.to_string()).join("\n");
}
@ -235,8 +240,7 @@ fn detect_columns(
args: Arguments,
) -> Result<PipelineData, ShellError> {
let name_span = call.head;
let config = engine_state.get_config();
let input = input.collect_string("", config)?;
let input = input.collect_string("", &args.config)?;
let input: Vec<_> = input
.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_protocol::engine::{FileStack, StateWorkingSet};
use std::path::Path;
@ -59,7 +59,7 @@ impl Command for NuCheck {
}
}
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 contents = Vec::from(list_stream);

View File

@ -366,7 +366,7 @@ pub fn command_not_found(
stack: &mut Stack,
) -> ShellError {
// 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();
// Set a special environment variable to avoid infinite loops when the
// `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 color_param: bool = call.has_flag(engine_state, stack, "color")?;
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") {
Some(v) => Some(env_to_string("LS_COLORS", &v, engine_state, stack)?),
None => None,

View File

@ -4,7 +4,7 @@
use lscolors::{LsColors, Style};
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_protocol::{
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 abbrivation: Option<usize> = call
.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) {
(false, false) => TableView::General,
(_, true) => TableView::Collapsed,
@ -269,7 +269,7 @@ fn parse_table_config(
},
};
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 term_width = get_width_param(width_param);
@ -493,7 +493,11 @@ fn handle_record(
cfg: TableConfig,
mut record: Record,
) -> 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 styles = &StyleComputer::from_config(input.engine_state, input.stack);
@ -608,7 +612,11 @@ fn handle_row_stream(
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") {
Some(v) => Some(env_to_string(
"LS_COLORS",
@ -758,7 +766,11 @@ impl PagingTableCreator {
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 opts = self.create_table_opts(&cfg, &style_comp);
let view = TableView::Expanded {
@ -775,7 +787,11 @@ impl PagingTableCreator {
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 opts = self.create_table_opts(&cfg, &style_comp);
@ -783,7 +799,11 @@ impl PagingTableCreator {
}
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 opts = self.create_table_opts(&cfg, &style_comp);
@ -872,7 +892,11 @@ impl Iterator for PagingTableCreator {
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(
table,
&config,
@ -1049,7 +1073,7 @@ fn create_empty_placeholder(
engine_state: &EngineState,
stack: &Stack,
) -> String {
let config = get_config(engine_state, stack);
let config = stack.get_config(engine_state);
if !config.table_show_empty {
return String::new();
}

View File

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

View File

@ -3,7 +3,7 @@ use nu_path::canonicalize_with;
use nu_protocol::{
ast::Expr,
engine::{Call, EngineState, Stack, StateWorkingSet},
Config, ShellError, Span, Value, VarId,
ShellError, Span, Value, VarId,
};
use std::{
collections::HashMap,
@ -323,18 +323,6 @@ pub fn find_in_dirs_env(
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(
engine_state: &EngineState,
stack: &Stack,

View File

@ -1,6 +1,6 @@
use crate::eval_ir_block;
#[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_protocol::{
ast::{
@ -14,7 +14,7 @@ use nu_protocol::{
Spanned, Type, Value, VarId, ENV_VARIABLE_ID,
};
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>(
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() {
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(
@ -652,8 +655,8 @@ impl Eval for EvalRuntime {
type MutState = Stack;
fn get_config<'a>(engine_state: Self::State<'a>, stack: &mut Stack) -> Cow<'a, Config> {
Cow::Owned(get_config(engine_state, stack))
fn get_config(engine_state: Self::State<'_>, stack: &mut Stack) -> Arc<Config> {
stack.get_config(engine_state)
}
fn eval_filepath(
@ -843,7 +846,14 @@ impl Eval for EvalRuntime {
});
}
let is_config = original_key == "config";
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 {
lhs.upsert_data_at_cell_path(&cell_path.tail, rhs)?;
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_single_value = vals.len() == 1 && vals[0].len() == 1;
if !has_no_head && has_single_value {
let config = engine_state.get_config();
Ok(vals[0][0].to_abbreviated_string(config))
let config = stack.get_config(engine_state);
Ok(vals[0][0].to_abbreviated_string(&config))
} else {
let config = engine_state.get_config();
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 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 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_index = show_index;
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 config = PagerConfig::new(
nu_config,
&nu_config,
&explore_config,
&style_computer,
&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-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-utils = { path = "../nu-utils", version = "0.95.1" }
serde = { workspace = true }
log = { workspace = true }

View File

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

View File

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

View File

@ -25,6 +25,7 @@ use nu_protocol::{
ast::Operator, engine::Closure, ByteStreamType, Config, LabeledError, PipelineData,
PluginMetadata, PluginSignature, ShellError, Span, Spanned, Value,
};
use nu_utils::SharedCow;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
@ -553,7 +554,7 @@ impl<D> EngineCall<D> {
pub enum EngineCallResponse<D> {
Error(ShellError),
PipelineData(D),
Config(Box<Config>),
Config(SharedCow<Config>),
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-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-utils = { path = "../nu-utils", version = "0.95.1" }
log = { workspace = true }
thiserror = "1.0"

View File

@ -14,6 +14,7 @@ use nu_protocol::{
engine::Closure, Config, LabeledError, PipelineData, PluginMetadata, PluginSignature,
ShellError, Signals, Span, Spanned, Value,
};
use nu_utils::SharedCow;
use std::{
collections::{btree_map, BTreeMap, HashMap},
sync::{mpsc, Arc},
@ -525,9 +526,9 @@ impl EngineInterface {
/// # 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)? {
EngineCallResponse::Config(config) => Ok(config),
EngineCallResponse::Config(config) => Ok(SharedCow::into_arc(config)),
EngineCallResponse::Error(err) => Err(err),
_ => Err(ShellError::PluginFailedToDecode {
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(|_| {
let flags = get_flags_section(None, &signature, |v| format!("{:#?}", v));
let flags = get_flags_section(None, None, &signature, |v| format!("{:#?}", v));
write!(help, "{flags}")
})
.and_then(|_| writeln!(help, "\nParameters:"))

View File

@ -301,28 +301,11 @@ impl EngineState {
stack: &mut Stack,
cwd: impl AsRef<Path>,
) -> Result<(), ShellError> {
let mut config_updated = false;
for mut scope in stack.env_vars.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) {
// Updating existing overlay
for (k, v) in 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);
}
}
env_vars.extend(env.drain());
} else {
// Pushing a new overlay
Arc::make_mut(&mut self.env_vars).insert(overlay_name, env);
@ -333,7 +316,10 @@ impl EngineState {
// TODO: better error
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.
#[cfg(feature = "plugin")]
self.update_plugin_gc_configs(&self.config.plugin_gc);
@ -738,18 +724,24 @@ impl EngineState {
&[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
}
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")]
if conf.plugin_gc != self.config.plugin_gc {
// Make plugin GC config changes take effect immediately.
self.update_plugin_gc_configs(&conf.plugin_gc);
}
self.config = Arc::new(conf);
self.config = conf;
}
/// Fetch the configuration for a plugin
@ -1137,7 +1129,7 @@ mod engine_state_tests {
let mut plugins = HashMap::new();
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;
engine_state.set_config(config);

View File

@ -3,7 +3,7 @@ use crate::{
ArgumentStack, EngineState, ErrorHandlerStack, Redirection, StackCallArgGuard,
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::{
collections::{HashMap, HashSet},
@ -51,6 +51,8 @@ pub struct Stack {
pub parent_stack: Option<Arc<Stack>>,
/// Variables that have been deleted (this is used to hide values from parent stack lookups)
pub parent_deletions: Vec<VarId>,
/// Locally updated config. Use [`.get_config()`] to access correctly.
pub config: Option<Arc<Config>>,
pub(crate) out_dest: StackOutDest,
}
@ -80,6 +82,7 @@ impl Stack {
recursion_count: 0,
parent_stack: None,
parent_deletions: vec![],
config: None,
out_dest: StackOutDest::new(),
}
}
@ -100,6 +103,7 @@ impl Stack {
recursion_count: parent.recursion_count,
vars: vec![],
parent_deletions: vec![],
config: parent.config.clone(),
out_dest: parent.out_dest.clone(),
parent_stack: Some(parent),
}
@ -126,6 +130,7 @@ impl Stack {
unique_stack.env_vars = child.env_vars;
unique_stack.env_hidden = child.env_hidden;
unique_stack.active_overlays = child.active_overlays;
unique_stack.config = child.config;
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) {
//self.vars.insert(var_id, value);
for (id, val) in &mut self.vars {
@ -272,6 +307,7 @@ impl Stack {
recursion_count: self.recursion_count,
parent_stack: None,
parent_deletions: vec![],
config: self.config.clone(),
out_dest: self.out_dest.clone(),
}
}
@ -305,6 +341,7 @@ impl Stack {
recursion_count: self.recursion_count,
parent_stack: None,
parent_deletions: vec![],
config: self.config.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
///
/// At runtime, you most likely want to call nu_engine::env::get_config because this method
/// does not capture environment updates during runtime.
pub fn get_config(&self) -> &Config {
/// At runtime, you most likely want to call [`Stack::get_config()`][super::Stack::get_config()]
/// because this method does not capture environment updates during runtime.
pub fn get_config(&self) -> &Arc<Config> {
&self.permanent_state.config
}

View File

@ -7,7 +7,7 @@ use crate::{
debugger::DebugContext,
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
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(
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 std::{
borrow::Cow,
path::{Path, PathBuf},
sync::Arc,
};
/// Create a Value for `$nu`.
@ -364,8 +364,8 @@ impl Eval for EvalConst {
type MutState = ();
fn get_config<'a>(state: Self::State<'a>, _: &mut ()) -> Cow<'a, Config> {
Cow::Borrowed(state.get_config())
fn get_config(state: Self::State<'_>, _: &mut ()) -> Arc<Config> {
state.get_config().clone()
}
fn eval_filepath(