diff --git a/src/error.rs b/src/error.rs index 21f6e52..3b4080f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,10 @@ +use nu_protocol::ShellError; +use thiserror::Error; + pub type CrateResult = std::result::Result; -pub enum CrateError {} +#[derive(Clone, Debug, Error)] +pub enum CrateError { + #[error("Shell Error {0}")] + NuShellError(#[from] ShellError), +} diff --git a/src/lib.rs b/src/lib.rs index b75881e..d715116 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ -use state_builder::StateBuilder; - pub(crate) mod error; pub mod state_builder; +pub(crate) mod utils; pub type Error = error::CrateError; diff --git a/src/state_builder/bindings.rs b/src/state_builder/bindings.rs index c377a56..4f342b1 100644 --- a/src/state_builder/bindings.rs +++ b/src/state_builder/bindings.rs @@ -449,7 +449,7 @@ pub fn bind_experimental_commands(engine_state: &mut EngineState) { #[inline] fn bind(engine_state: &mut EngineState, bind_fn: F) { - let mut working_set = StateWorkingSet::new(&engine_state); + let mut working_set = StateWorkingSet::new(engine_state); bind_fn(&mut working_set); let delta = working_set.render(); engine_state diff --git a/src/state_builder/mod.rs b/src/state_builder/mod.rs index 11b49fc..61eeb00 100644 --- a/src/state_builder/mod.rs +++ b/src/state_builder/mod.rs @@ -1,9 +1,19 @@ -use nu_protocol::engine::{EngineState, Stack}; +use std::env; + +use nu_protocol::{ + engine::{EngineState, Stack, StateWorkingSet}, + Span, +}; mod bindings; mod command_group_config; pub use command_group_config::CommandGroupConfig; +use crate::{ + error::CrateResult, + utils::{IntoValue, SpanEmpty}, +}; + /// Builder to create a new nu engine state pub struct StateBuilder { engine_state: EngineState, @@ -61,4 +71,42 @@ impl StateBuilder { ); self } + + /// Adds a variable to the state + pub fn add_var( + &mut self, + name: S, + value: V, + ) -> CrateResult<&mut Self> { + let mut working_set = StateWorkingSet::new(&self.engine_state); + + let var_id = working_set.add_variable( + name.to_string().into_bytes(), + Span::empty(), + nu_protocol::Type::Any, + ); + self.stack.add_var(var_id, value.into_value()); + let delta = working_set.render(); + self.engine_state.merge_delta(delta)?; + + Ok(self) + } + + /// Adds an environment variable to the state + pub fn add_env_var(&mut self, name: S, value: V) -> &mut Self { + self.engine_state + .add_env_var(name.to_string(), value.into_value()); + + self + } + + /// Adds the environment variables of the parent process to the + /// states env variables + pub fn add_parent_env_vars(&mut self) -> &mut Self { + for (name, val) in env::vars() { + self.add_env_var(name, val); + } + + self + } } diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..1dc9c9c --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,95 @@ +use std::collections::HashMap; + +use nu_protocol::{Span, Value}; + +pub trait SpanEmpty { + fn empty() -> Self; +} + +impl SpanEmpty for Span { + fn empty() -> Self { + Span::new(0, 0) + } +} + +pub trait IntoValue { + fn into_value(self) -> Value; +} + +impl IntoValue for Value { + fn into_value(self) -> Value { + self + } +} + +impl IntoValue for String { + fn into_value(self) -> Value { + Value::String { + val: self, + span: Span::empty(), + } + } +} + +impl IntoValue for i64 { + fn into_value(self) -> Value { + Value::Int { + val: self, + span: Span::empty(), + } + } +} + +impl IntoValue for bool { + fn into_value(self) -> Value { + Value::Bool { + val: self, + span: Span::empty(), + } + } +} + +impl IntoValue for f64 { + fn into_value(self) -> Value { + Value::Float { + val: self, + span: Span::empty(), + } + } +} + +impl IntoValue for char { + fn into_value(self) -> Value { + Value::String { + val: self.to_string(), + span: Span::empty(), + } + } +} + +impl<'a> IntoValue for &'a str { + fn into_value(self) -> Value { + self.to_string().into_value() + } +} + +impl IntoValue for HashMap { + fn into_value(self) -> Value { + let (cols, vals) = self.into_iter().unzip(); + + Value::Record { + cols, + vals, + span: Span::empty(), + } + } +} + +impl IntoValue for Vec { + fn into_value(self) -> Value { + Value::List { + vals: self, + span: Span::empty(), + } + } +}