diff --git a/benches/benchmarks.rs b/benches/benchmarks.rs index 859e3e2d2d..e291eeebcc 100644 --- a/benches/benchmarks.rs +++ b/benches/benchmarks.rs @@ -23,8 +23,7 @@ fn load_bench_commands() -> EngineState { } fn canonicalize_path(engine_state: &EngineState, path: &Path) -> PathBuf { - #[allow(deprecated)] - let cwd = engine_state.current_work_dir(); + let cwd = engine_state.cwd_as_string(None).unwrap(); if path.exists() { match nu_path::canonicalize_with(path, cwd) { diff --git a/crates/nu-cli/src/config_files.rs b/crates/nu-cli/src/config_files.rs index 775d76382b..091fe7daa3 100644 --- a/crates/nu-cli/src/config_files.rs +++ b/crates/nu-cli/src/config_files.rs @@ -177,36 +177,36 @@ pub fn add_plugin_file( use std::path::Path; let working_set = StateWorkingSet::new(engine_state); - #[allow(deprecated)] - let cwd = working_set.get_cwd(); - if let Some(plugin_file) = plugin_file { - let path = Path::new(&plugin_file.item); - let path_dir = path.parent().unwrap_or(path); - // Just try to canonicalize the directory of the plugin file first. - if let Ok(path_dir) = canonicalize_with(path_dir, &cwd) { - // Try to canonicalize the actual filename, but it's ok if that fails. The file doesn't - // have to exist. - let path = path_dir.join(path.file_name().unwrap_or(path.as_os_str())); - let path = canonicalize_with(&path, &cwd).unwrap_or(path); - engine_state.plugin_path = Some(path) - } else { - // It's an error if the directory for the plugin file doesn't exist. - report_error( - &working_set, - &ParseError::FileNotFound( - path_dir.to_string_lossy().into_owned(), - plugin_file.span, - ), - ); + if let Ok(cwd) = engine_state.cwd_as_string(None) { + if let Some(plugin_file) = plugin_file { + let path = Path::new(&plugin_file.item); + let path_dir = path.parent().unwrap_or(path); + // Just try to canonicalize the directory of the plugin file first. + if let Ok(path_dir) = canonicalize_with(path_dir, &cwd) { + // Try to canonicalize the actual filename, but it's ok if that fails. The file doesn't + // have to exist. + let path = path_dir.join(path.file_name().unwrap_or(path.as_os_str())); + let path = canonicalize_with(&path, &cwd).unwrap_or(path); + engine_state.plugin_path = Some(path) + } else { + // It's an error if the directory for the plugin file doesn't exist. + report_error( + &working_set, + &ParseError::FileNotFound( + path_dir.to_string_lossy().into_owned(), + plugin_file.span, + ), + ); + } + } else if let Some(mut plugin_path) = nu_path::config_dir() { + // Path to store plugins signatures + plugin_path.push(storage_path); + let mut plugin_path = canonicalize_with(&plugin_path, &cwd).unwrap_or(plugin_path); + plugin_path.push(PLUGIN_FILE); + let plugin_path = canonicalize_with(&plugin_path, &cwd).unwrap_or(plugin_path); + engine_state.plugin_path = Some(plugin_path); } - } else if let Some(mut plugin_path) = nu_path::config_dir() { - // Path to store plugins signatures - plugin_path.push(storage_path); - let mut plugin_path = canonicalize_with(&plugin_path, &cwd).unwrap_or(plugin_path); - plugin_path.push(PLUGIN_FILE); - let plugin_path = canonicalize_with(&plugin_path, &cwd).unwrap_or(plugin_path); - engine_state.plugin_path = Some(plugin_path); } } @@ -236,8 +236,7 @@ pub fn eval_config_contents( engine_state.file = prev_file; // Merge the environment in case env vars changed in the config - #[allow(deprecated)] - match nu_engine::env::current_dir(engine_state, stack) { + match engine_state.cwd(Some(stack)) { Ok(cwd) => { if let Err(e) = engine_state.merge_env(stack, cwd) { let working_set = StateWorkingSet::new(engine_state); @@ -274,8 +273,9 @@ pub fn migrate_old_plugin_file(engine_state: &EngineState, storage_path: &str) - let start_time = std::time::Instant::now(); - #[allow(deprecated)] - let cwd = engine_state.current_work_dir(); + let Ok(cwd) = engine_state.cwd_as_string(None) else { + return false; + }; let Some(config_dir) = nu_path::config_dir().and_then(|mut dir| { dir.push(storage_path); diff --git a/crates/nu-cli/src/eval_file.rs b/crates/nu-cli/src/eval_file.rs index 90b1e840ee..8107de71a5 100644 --- a/crates/nu-cli/src/eval_file.rs +++ b/crates/nu-cli/src/eval_file.rs @@ -1,8 +1,7 @@ use crate::util::eval_source; use log::{info, trace}; use miette::{IntoDiagnostic, Result}; -#[allow(deprecated)] -use nu_engine::{convert_env_values, current_dir, eval_block}; +use nu_engine::{convert_env_values, eval_block}; use nu_parser::parse; use nu_path::canonicalize_with; use nu_protocol::{ @@ -30,8 +29,7 @@ pub fn evaluate_file( std::process::exit(1); } - #[allow(deprecated)] - let cwd = current_dir(engine_state, stack)?; + let cwd = engine_state.cwd_as_string(Some(stack))?; let file_path = canonicalize_with(&path, cwd).unwrap_or_else(|e| { let working_set = StateWorkingSet::new(engine_state); diff --git a/crates/nu-cmd-base/src/util.rs b/crates/nu-cmd-base/src/util.rs index 8654975c2b..619237a21c 100644 --- a/crates/nu-cmd-base/src/util.rs +++ b/crates/nu-cmd-base/src/util.rs @@ -13,8 +13,7 @@ pub fn get_init_cwd() -> PathBuf { } pub fn get_guaranteed_cwd(engine_state: &EngineState, stack: &Stack) -> PathBuf { - #[allow(deprecated)] - nu_engine::env::current_dir(engine_state, stack).unwrap_or_else(|e| { + engine_state.cwd(Some(stack)).unwrap_or_else(|e| { let working_set = StateWorkingSet::new(engine_state); report_error(&working_set, &e); crate::util::get_init_cwd() diff --git a/crates/nu-cmd-plugin/src/commands/plugin/add.rs b/crates/nu-cmd-plugin/src/commands/plugin/add.rs index 70f1f417b6..e2c1c31151 100644 --- a/crates/nu-cmd-plugin/src/commands/plugin/add.rs +++ b/crates/nu-cmd-plugin/src/commands/plugin/add.rs @@ -1,5 +1,4 @@ -#[allow(deprecated)] -use nu_engine::{command_prelude::*, current_dir}; +use nu_engine::command_prelude::*; use nu_plugin_engine::{GetPlugin, PersistentPlugin}; use nu_protocol::{PluginGcConfig, PluginIdentity, PluginRegistryItem, RegisteredPlugin}; use std::sync::Arc; @@ -82,8 +81,7 @@ apparent the next time `nu` is next launched with that plugin registry file. let filename: Spanned = call.req(engine_state, stack, 0)?; let shell: Option> = call.get_flag(engine_state, stack, "shell")?; - #[allow(deprecated)] - let cwd = current_dir(engine_state, stack)?; + let cwd = engine_state.cwd(Some(stack))?; // Check the current directory, or fall back to NU_PLUGIN_DIRS let filename_expanded = nu_path::locate_in_dirs(&filename.item, &cwd, || { diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index d8307be84d..ba55472e15 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -125,6 +125,7 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState { SysMem, SysNet, SysTemp, + SysUsers, UName, }; diff --git a/crates/nu-command/src/filesystem/glob.rs b/crates/nu-command/src/filesystem/glob.rs index c5f4bc08b4..b10e8893a0 100644 --- a/crates/nu-command/src/filesystem/glob.rs +++ b/crates/nu-command/src/filesystem/glob.rs @@ -1,5 +1,4 @@ -#[allow(deprecated)] -use nu_engine::{command_prelude::*, env::current_dir}; +use nu_engine::command_prelude::*; use std::sync::{atomic::AtomicBool, Arc}; use wax::{Glob as WaxGlob, WalkBehavior, WalkEntry}; @@ -179,8 +178,7 @@ impl Command for Glob { } }; - #[allow(deprecated)] - let path = current_dir(engine_state, stack)?; + let path = engine_state.cwd_as_string(Some(stack))?; let path = match nu_path::canonicalize_with(prefix, path) { Ok(path) => path, Err(e) if e.to_string().contains("os error 2") => diff --git a/crates/nu-command/src/filesystem/watch.rs b/crates/nu-command/src/filesystem/watch.rs index 224d58d0d0..fda542c8a8 100644 --- a/crates/nu-command/src/filesystem/watch.rs +++ b/crates/nu-command/src/filesystem/watch.rs @@ -5,8 +5,7 @@ use notify_debouncer_full::{ EventKind, RecursiveMode, Watcher, }, }; -#[allow(deprecated)] -use nu_engine::{command_prelude::*, current_dir, ClosureEval}; +use nu_engine::{command_prelude::*, ClosureEval}; use nu_protocol::{ engine::{Closure, StateWorkingSet}, format_error, @@ -74,8 +73,7 @@ impl Command for Watch { _input: PipelineData, ) -> Result { let head = call.head; - #[allow(deprecated)] - let cwd = current_dir(engine_state, stack)?; + let cwd = engine_state.cwd_as_string(Some(stack))?; let path_arg: Spanned = call.req(engine_state, stack, 0)?; let path_no_whitespace = &path_arg diff --git a/crates/nu-command/src/system/sys/host.rs b/crates/nu-command/src/system/sys/host.rs index 23508b5b6e..969f59ef99 100644 --- a/crates/nu-command/src/system/sys/host.rs +++ b/crates/nu-command/src/system/sys/host.rs @@ -26,7 +26,8 @@ impl Command for SysHost { call: &Call, _input: PipelineData, ) -> Result { - Ok(super::host(call.head).into_pipeline_data()) + let host = super::host(call.head); + Ok(Value::record(host, call.head).into_pipeline_data()) } fn examples(&self) -> Vec { diff --git a/crates/nu-command/src/system/sys/mod.rs b/crates/nu-command/src/system/sys/mod.rs index 0c61543e7d..5e0467c251 100644 --- a/crates/nu-command/src/system/sys/mod.rs +++ b/crates/nu-command/src/system/sys/mod.rs @@ -5,6 +5,7 @@ mod mem; mod net; mod sys_; mod temp; +mod users; pub use cpu::SysCpu; pub use disks::SysDisks; @@ -13,6 +14,7 @@ pub use mem::SysMem; pub use net::SysNet; pub use sys_::Sys; pub use temp::SysTemp; +pub use users::SysUsers; use chrono::{DateTime, Local}; use nu_protocol::{record, Record, Span, Value}; @@ -122,7 +124,29 @@ pub fn mem(span: Span) -> Value { Value::record(record, span) } -pub fn host(span: Span) -> Value { +pub fn users(span: Span) -> Value { + let users = Users::new_with_refreshed_list() + .iter() + .map(|user| { + let groups = user + .groups() + .iter() + .map(|group| Value::string(trim_cstyle_null(group.name()), span)) + .collect(); + + let record = record! { + "name" => Value::string(trim_cstyle_null(user.name()), span), + "groups" => Value::list(groups, span), + }; + + Value::record(record, span) + }) + .collect(); + + Value::list(users, span) +} + +pub fn host(span: Span) -> Record { let mut record = Record::new(); if let Some(name) = System::name() { @@ -160,27 +184,7 @@ pub fn host(span: Span) -> Value { let timestamp_str = datetime.with_timezone(datetime.offset()).to_rfc3339(); record.push("boot_time", Value::string(timestamp_str, span)); - let users = Users::new_with_refreshed_list() - .iter() - .map(|user| { - let groups = user - .groups() - .iter() - .map(|group| Value::string(trim_cstyle_null(group.name()), span)) - .collect(); - - let record = record! { - "name" => Value::string(trim_cstyle_null(user.name()), span), - "groups" => Value::list(groups, span), - }; - - Value::record(record, span) - }) - .collect(); - - record.push("sessions", Value::list(users, span)); - - Value::record(record, span) + record } pub fn temp(span: Span) -> Value { diff --git a/crates/nu-command/src/system/sys/sys_.rs b/crates/nu-command/src/system/sys/sys_.rs index 39dc2d419b..2886836be9 100644 --- a/crates/nu-command/src/system/sys/sys_.rs +++ b/crates/nu-command/src/system/sys/sys_.rs @@ -43,8 +43,11 @@ impl Command for Sys { ); let head = call.head; + + let mut host = super::host(head); + host.push("sessions", super::users(head)); let record = record! { - "host" => super::host(head), + "host" => Value::record(host, head), "cpu" => super::cpu(head), "disks" => super::disks(head), "mem" => super::mem(head), diff --git a/crates/nu-command/src/system/sys/users.rs b/crates/nu-command/src/system/sys/users.rs new file mode 100644 index 0000000000..9aab2b9b7b --- /dev/null +++ b/crates/nu-command/src/system/sys/users.rs @@ -0,0 +1,38 @@ +use nu_engine::command_prelude::*; + +#[derive(Clone)] +pub struct SysUsers; + +impl Command for SysUsers { + fn name(&self) -> &str { + "sys users" + } + + fn signature(&self) -> Signature { + Signature::build("sys users") + .category(Category::System) + .input_output_types(vec![(Type::Nothing, Type::record())]) + } + + fn usage(&self) -> &str { + "View information about the users on the system." + } + + fn run( + &self, + _engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + _input: PipelineData, + ) -> Result { + Ok(super::users(call.head).into_pipeline_data()) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Show info about the system users", + example: "sys users", + result: None, + }] + } +} diff --git a/crates/nu-engine/src/env.rs b/crates/nu-engine/src/env.rs index 19ed589dcf..ae226c4421 100644 --- a/crates/nu-engine/src/env.rs +++ b/crates/nu-engine/src/env.rs @@ -286,8 +286,7 @@ pub fn find_in_dirs_env( Err(e) => return Err(e), } } else { - #[allow(deprecated)] - current_dir_str(engine_state, stack)? + engine_state.cwd_as_string(Some(stack))? }; let check_dir = |lib_dirs: Option| -> Option { diff --git a/crates/nu-parser/src/flatten.rs b/crates/nu-parser/src/flatten.rs index 3484c53d0f..e70a48e9f1 100644 --- a/crates/nu-parser/src/flatten.rs +++ b/crates/nu-parser/src/flatten.rs @@ -385,12 +385,23 @@ fn flatten_expression_into( output.extend(flattened); } - ListItem::Spread(_, expr) => { - output.push(( - Span::new(expr.span.start, expr.span.start + 3), - FlatShape::Operator, - )); - flatten_expression_into(working_set, expr, output); + ListItem::Spread(op_span, expr) => { + if op_span.start > last_end { + output.push((Span::new(last_end, op_span.start), FlatShape::List)); + } + output.push((*op_span, FlatShape::Operator)); + last_end = op_span.end; + + let flattened_inner = flatten_expression(working_set, expr); + if let Some(first) = flattened_inner.first() { + if first.0.start > last_end { + output.push((Span::new(last_end, first.0.start), FlatShape::List)); + } + } + if let Some(last) = flattened_inner.last() { + last_end = last.0.end; + } + output.extend(flattened_inner); } } } diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 19b84c1e75..7dfccf7bad 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -3895,7 +3895,7 @@ pub fn parse_list_expression( Type::List(elem_ty) => *elem_ty.clone(), _ => Type::Any, }; - let span = Span::new(curr_span.start, spread_arg.span.end); + let span = Span::new(curr_span.start, curr_span.start + 3); (ListItem::Spread(span, spread_arg), elem_ty) } else { let arg = parse_multispan_value( diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index 5012754b3b..1593b3341a 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -984,6 +984,20 @@ impl EngineState { } } + /// Like `EngineState::cwd()`, but returns a String instead of a PathBuf for convenience. + pub fn cwd_as_string(&self, stack: Option<&Stack>) -> Result { + let cwd = self.cwd(stack)?; + cwd.into_os_string() + .into_string() + .map_err(|err| ShellError::NonUtf8Custom { + msg: format!( + "The current working directory is not a valid utf-8 string: {:?}", + err + ), + span: Span::unknown(), + }) + } + // TODO: see if we can completely get rid of this pub fn get_file_contents(&self) -> &[CachedFile] { &self.files diff --git a/crates/nu-std/src/lib.rs b/crates/nu-std/src/lib.rs index a3cf9271a5..a20e3fc5da 100644 --- a/crates/nu-std/src/lib.rs +++ b/crates/nu-std/src/lib.rs @@ -1,6 +1,5 @@ use log::trace; -#[allow(deprecated)] -use nu_engine::{env::current_dir, eval_block}; +use nu_engine::eval_block; use nu_parser::parse; use nu_protocol::{ debugger::WithoutDebug, @@ -99,8 +98,7 @@ use std pwd eval_block::(engine_state, &mut stack, &block, pipeline_data)?; - #[allow(deprecated)] - let cwd = current_dir(engine_state, &stack)?; + let cwd = engine_state.cwd(Some(&stack))?; engine_state.merge_env(&mut stack, cwd)?; Ok(()) diff --git a/src/config_files.rs b/src/config_files.rs index e67af7f2e1..6b2e5bb16d 100644 --- a/src/config_files.rs +++ b/src/config_files.rs @@ -31,14 +31,19 @@ pub(crate) fn read_config_file( // Load config startup file if let Some(file) = config_file { let working_set = StateWorkingSet::new(engine_state); - #[allow(deprecated)] - let cwd = working_set.get_cwd(); - if let Ok(path) = canonicalize_with(&file.item, cwd) { - eval_config_contents(path, engine_state, stack); - } else { - let e = ParseError::FileNotFound(file.item, file.span); - report_error(&working_set, &e); + match engine_state.cwd_as_string(Some(stack)) { + Ok(cwd) => { + if let Ok(path) = canonicalize_with(&file.item, cwd) { + eval_config_contents(path, engine_state, stack); + } else { + let e = ParseError::FileNotFound(file.item, file.span); + report_error(&working_set, &e); + } + } + Err(e) => { + report_error(&working_set, &e); + } } } else if let Some(mut config_path) = nu_path::config_dir() { config_path.push(NUSHELL_FOLDER); @@ -144,8 +149,7 @@ pub(crate) fn read_default_env_file(engine_state: &mut EngineState, stack: &mut info!("read_config_file {}:{}:{}", file!(), line!(), column!()); // Merge the environment in case env vars changed in the config - #[allow(deprecated)] - match nu_engine::env::current_dir(engine_state, stack) { + match engine_state.cwd(Some(stack)) { Ok(cwd) => { if let Err(e) = engine_state.merge_env(stack, cwd) { let working_set = StateWorkingSet::new(engine_state); @@ -186,8 +190,7 @@ fn eval_default_config( ); // Merge the environment in case env vars changed in the config - #[allow(deprecated)] - match nu_engine::env::current_dir(engine_state, stack) { + match engine_state.cwd(Some(stack)) { Ok(cwd) => { if let Err(e) = engine_state.merge_env(stack, cwd) { let working_set = StateWorkingSet::new(engine_state); diff --git a/src/test_bins.rs b/src/test_bins.rs index 5fef4976a7..73a760ada1 100644 --- a/src/test_bins.rs +++ b/src/test_bins.rs @@ -249,8 +249,9 @@ pub fn nu_repl() { for (i, line) in source_lines.iter().enumerate() { let mut stack = Stack::with_parent(top_stack.clone()); - #[allow(deprecated)] - let cwd = nu_engine::env::current_dir(&engine_state, &stack) + + let cwd = engine_state + .cwd(Some(&stack)) .unwrap_or_else(|err| outcome_err(&engine_state, &err)); // Before doing anything, merge the environment from the previous REPL iteration into the