forked from extern/nushell
Treating environment variables as Values (#497)
* Proof of concept treating env vars as Values * Refactor env var collection and method name * Remove unnecessary pub * Move env translations into a new file * Fix LS_COLORS to support any Value * Fix spans during env var translation * Add span to env var in cd * Improve error diagnostics * Fix non-string env vars failing string conversion * Make PROMPT_COMMAND a Block instead of String * Record host env vars to a fake file This will give spans to env vars that would otherwise be without one. Makes errors less confusing. * Add 'env' command to list env vars It will list also their values translated to strings * Sort env command by name; Add env var type * Remove obsolete test
This commit is contained in:
61
crates/nu-command/src/env/env_command.rs
vendored
Normal file
61
crates/nu-command/src/env/env_command.rs
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
use nu_engine::env_to_string;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{Category, IntoPipelineData, PipelineData, Signature, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Env;
|
||||
|
||||
impl Command for Env {
|
||||
fn name(&self) -> &str {
|
||||
"env"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Display current environment"
|
||||
}
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("env").category(Category::Env)
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
let span = call.head;
|
||||
let config = stack.get_config().unwrap_or_default();
|
||||
|
||||
let mut env_vars: Vec<(String, Value)> = stack.get_env_vars().into_iter().collect();
|
||||
env_vars.sort_by(|(name1, _), (name2, _)| name1.cmp(name2));
|
||||
|
||||
let mut values = vec![];
|
||||
|
||||
for (name, val) in env_vars {
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
|
||||
let raw = env_to_string(&name, val.clone(), engine_state, stack, &config)?;
|
||||
let val_type = val.get_type();
|
||||
|
||||
cols.push("name".into());
|
||||
vals.push(Value::string(name, span));
|
||||
|
||||
cols.push("type".into());
|
||||
vals.push(Value::string(format!("{}", val_type), span));
|
||||
|
||||
cols.push("value".into());
|
||||
vals.push(val);
|
||||
|
||||
cols.push("raw".into());
|
||||
vals.push(Value::string(raw, span));
|
||||
|
||||
values.push(Value::Record { cols, vals, span });
|
||||
}
|
||||
|
||||
Ok(Value::List { vals: values, span }.into_pipeline_data())
|
||||
}
|
||||
}
|
5
crates/nu-command/src/env/let_env.rs
vendored
5
crates/nu-command/src/env/let_env.rs
vendored
@ -20,7 +20,7 @@ impl Command for LetEnv {
|
||||
.required("var_name", SyntaxShape::String, "variable name")
|
||||
.required(
|
||||
"initial_value",
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::String)),
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Any)),
|
||||
"equals sign followed by value",
|
||||
)
|
||||
.category(Category::Env)
|
||||
@ -42,9 +42,6 @@ impl Command for LetEnv {
|
||||
.expect("internal error: missing keyword");
|
||||
|
||||
let rhs = eval_expression(engine_state, stack, keyword_expr)?;
|
||||
let rhs = rhs.as_string()?;
|
||||
|
||||
//println!("Adding: {:?} to {}", rhs, var_id);
|
||||
|
||||
stack.add_env_var(env_var, rhs);
|
||||
Ok(PipelineData::new(call.head))
|
||||
|
2
crates/nu-command/src/env/mod.rs
vendored
2
crates/nu-command/src/env/mod.rs
vendored
@ -1,5 +1,7 @@
|
||||
mod env_command;
|
||||
mod let_env;
|
||||
mod with_env;
|
||||
|
||||
pub use env_command::Env;
|
||||
pub use let_env::LetEnv;
|
||||
pub use with_env::WithEnv;
|
||||
|
51
crates/nu-command/src/env/with_env.rs
vendored
51
crates/nu-command/src/env/with_env.rs
vendored
@ -1,7 +1,4 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
convert::{TryFrom, TryInto},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_protocol::{
|
||||
@ -73,34 +70,6 @@ impl Command for WithEnv {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum EnvVar {
|
||||
Proper(String),
|
||||
Nothing,
|
||||
}
|
||||
|
||||
impl TryFrom<&Value> for EnvVar {
|
||||
type Error = ShellError;
|
||||
|
||||
fn try_from(value: &Value) -> Result<Self, Self::Error> {
|
||||
if matches!(value, Value::Nothing { .. }) {
|
||||
Ok(EnvVar::Nothing)
|
||||
} else if let Ok(s) = value.as_string() {
|
||||
if s.is_empty() {
|
||||
Ok(EnvVar::Nothing)
|
||||
} else {
|
||||
Ok(EnvVar::Proper(s))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::CantConvert(
|
||||
"string".into(),
|
||||
value.get_type().to_string(),
|
||||
value.span()?,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn with_env(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
@ -116,7 +85,7 @@ fn with_env(
|
||||
let block = engine_state.get_block(block_id).clone();
|
||||
let mut stack = stack.collect_captures(&block.captures);
|
||||
|
||||
let mut env: HashMap<String, EnvVar> = HashMap::new();
|
||||
let mut env: HashMap<String, Value> = HashMap::new();
|
||||
|
||||
match &variable {
|
||||
Value::List { vals: table, .. } => {
|
||||
@ -125,7 +94,7 @@ fn with_env(
|
||||
match &table[0] {
|
||||
Value::Record { cols, vals, .. } => {
|
||||
for (k, v) in cols.iter().zip(vals.iter()) {
|
||||
env.insert(k.to_string(), v.try_into()?);
|
||||
env.insert(k.to_string(), v.clone());
|
||||
}
|
||||
}
|
||||
x => {
|
||||
@ -140,15 +109,16 @@ fn with_env(
|
||||
// primitive values([X Y W Z])
|
||||
for row in table.chunks(2) {
|
||||
if row.len() == 2 {
|
||||
env.insert(row[0].as_string()?, (&row[1]).try_into()?);
|
||||
env.insert(row[0].as_string()?, (&row[1]).clone());
|
||||
}
|
||||
// TODO: else error?
|
||||
}
|
||||
}
|
||||
}
|
||||
// when get object by `open x.json` or `from json`
|
||||
Value::Record { cols, vals, .. } => {
|
||||
for (k, v) in cols.iter().zip(vals) {
|
||||
env.insert(k.clone(), v.try_into()?);
|
||||
env.insert(k.clone(), v.clone());
|
||||
}
|
||||
}
|
||||
x => {
|
||||
@ -161,14 +131,7 @@ fn with_env(
|
||||
};
|
||||
|
||||
for (k, v) in env {
|
||||
match v {
|
||||
EnvVar::Nothing => {
|
||||
stack.remove_env_var(&k);
|
||||
}
|
||||
EnvVar::Proper(s) => {
|
||||
stack.add_env_var(k, s);
|
||||
}
|
||||
}
|
||||
stack.add_env_var(k, v);
|
||||
}
|
||||
|
||||
eval_block(engine_state, &mut stack, &block, input)
|
||||
|
Reference in New Issue
Block a user