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
46 changed files with 327 additions and 222 deletions

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();
}