use crate::{evaluate::scope::Scope, EvaluationContext}; use indexmap::IndexMap; use nu_data::config::path::{default_history_path, history_path}; use nu_errors::ShellError; use nu_protocol::{Dictionary, ShellTypeName, Signature, TaggedDictBuilder, UntaggedValue, Value}; use nu_source::{Spanned, Tag}; pub fn nu( scope: &Scope, tag: impl Into, ctx: &EvaluationContext, ) -> Result { let env = &scope.get_env_vars(); let tag = tag.into(); let mut nu_dict = TaggedDictBuilder::new(&tag); let mut dict = TaggedDictBuilder::new(&tag); for v in env.iter() { if v.0 != "PATH" && v.0 != "Path" { dict.insert_untagged(v.0, UntaggedValue::string(v.1)); } } nu_dict.insert_value("env", dict.into_value()); nu_dict.insert_value( "history-path", UntaggedValue::filepath(default_history_path()).into_value(&tag), ); if let Some(global_cfg) = &ctx.configs().lock().global_config { nu_dict.insert_value( "config", UntaggedValue::row(global_cfg.vars.clone()).into_value(&tag), ); nu_dict.insert_value( "config-path", UntaggedValue::filepath(global_cfg.file_path.clone()).into_value(&tag), ); // overwrite hist-path if present if let Some(hist_path) = history_path(global_cfg) { nu_dict.insert_value( "history-path", UntaggedValue::filepath(hist_path).into_value(&tag), ); } } // A note about environment variables: // // Environment variables in Unix platforms are case-sensitive. On Windows, case-sensitivity is context-dependent. // In cmd.exe, running `SET` will show you the list of environment variables and their names will be mixed case. // In PowerShell, running `Get-ChildItem Env:` will show you a list of environment variables, and they will match // the case in the environment variable section of the user configuration // // Rust currently returns the DOS-style, all-uppercase environment variables on Windows (as of 1.52) when running // std::env::vars(), rather than the case-sensitive Environment.GetEnvironmentVariables() of .NET that PowerShell // uses. // // For now, we work around the discrepency as best we can by merging the two into what is shown to the user as the // 'path' column of `$nu` let mut table = vec![]; for v in env.iter() { if v.0 == "PATH" || v.0 == "Path" { for path in std::env::split_paths(&v.1) { table.push(UntaggedValue::filepath(path).into_value(&tag)); } } } nu_dict.insert_value("path", UntaggedValue::table(&table).into_value(&tag)); let path = std::env::current_dir()?; nu_dict.insert_value("cwd", UntaggedValue::filepath(path).into_value(&tag)); if let Some(home) = crate::filesystem::filesystem_shell::homedir_if_possible() { nu_dict.insert_value("home-dir", UntaggedValue::filepath(home).into_value(&tag)); } let temp = std::env::temp_dir(); nu_dict.insert_value("temp-dir", UntaggedValue::filepath(temp).into_value(&tag)); #[cfg(feature = "rustyline-support")] { let keybinding_path = nu_data::keybinding::keybinding_path()?; nu_dict.insert_value( "keybinding-path", UntaggedValue::filepath(keybinding_path).into_value(&tag), ); } Ok(nu_dict.into_value()) } pub fn scope( aliases: &IndexMap>>, commands: &IndexMap, variables: &IndexMap, tag: impl Into, ) -> Result { let tag = tag.into(); let mut scope_dict = TaggedDictBuilder::new(&tag); let mut aliases_dict = TaggedDictBuilder::new(&tag); for v in aliases.iter() { let values = v.1.clone(); let mut vec = Vec::new(); for k in values.iter() { vec.push(k.to_string()); } let alias = vec.join(" "); aliases_dict.insert_untagged(v.0, UntaggedValue::string(alias)); } let mut commands_dict = TaggedDictBuilder::new(&tag); for (name, signature) in commands.iter() { commands_dict.insert_untagged(name, UntaggedValue::string(&signature.allowed().join(" "))) } let var_list: Vec = variables .iter() .map(|var| { let mut entries: IndexMap = IndexMap::new(); let name = var.0.trim_start_matches('$'); entries.insert( "name".to_string(), UntaggedValue::string(name).into_value(&tag), ); entries.insert( "value".to_string(), UntaggedValue::string(var.1.convert_to_string()).into_value(&tag), ); entries.insert( "type".to_string(), UntaggedValue::string(ShellTypeName::type_name(&var.1)).into_value(&tag), ); UntaggedValue::Row(Dictionary { entries }).into_value(&tag) }) .collect(); scope_dict.insert_value("aliases", aliases_dict.into_value()); scope_dict.insert_value("commands", commands_dict.into_value()); scope_dict.insert_value("variables", UntaggedValue::Table(var_list).into_value(&tag)); Ok(scope_dict.into_value()) }