You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
4.2 KiB
Rust
146 lines
4.2 KiB
Rust
mod bindings;
|
|
mod builder;
|
|
mod command_group_config;
|
|
pub use builder::*;
|
|
pub use command_group_config::CommandGroupConfig;
|
|
use nu_protocol::{
|
|
ast::{Block, Call},
|
|
engine::{EngineState, Stack, StateWorkingSet},
|
|
PipelineData, Span,
|
|
};
|
|
|
|
use crate::{
|
|
argument::IntoArgument,
|
|
error::{CrateError, CrateResult},
|
|
utils::parse_nu_script,
|
|
IntoValue, NewEmpty,
|
|
};
|
|
|
|
/// Represents the evaluation context of nu scripts and commands
|
|
/// This context is the state of the engine itself plus the stack
|
|
/// It stores variables on
|
|
#[derive(Clone)]
|
|
pub struct Context {
|
|
engine_state: EngineState,
|
|
stack: Stack,
|
|
}
|
|
|
|
impl Context {
|
|
pub fn builder() -> ContextBuilder {
|
|
ContextBuilder::default()
|
|
}
|
|
|
|
/// Evaluates the given block with the current engine context (stack plus engine state)
|
|
pub fn eval_block(&mut self, block: &Block, input: PipelineData) -> CrateResult<PipelineData> {
|
|
nu_engine::eval_block(
|
|
&self.engine_state,
|
|
&mut self.stack,
|
|
block,
|
|
input,
|
|
false,
|
|
false,
|
|
)
|
|
.map_err(CrateError::from)
|
|
}
|
|
|
|
/// Evals nu script as string with the current engine context
|
|
pub fn eval_raw<S: ToString>(
|
|
&mut self,
|
|
contents: S,
|
|
input: PipelineData,
|
|
) -> CrateResult<PipelineData> {
|
|
let block = parse_nu_script(&mut self.engine_state, contents.to_string())?;
|
|
|
|
self.eval_block(&block, input)
|
|
}
|
|
|
|
/// Returns a variable defined in the stack
|
|
pub fn get_var<S: AsRef<str>>(&self, name: S) -> Option<nu_protocol::Value> {
|
|
let name = name.as_ref();
|
|
let dollar_name = format!("${name}");
|
|
let var_id = self
|
|
.engine_state
|
|
.active_overlays(&vec![])
|
|
.iter()
|
|
.find_map(|o| {
|
|
o.vars
|
|
.get(dollar_name.as_bytes())
|
|
.or(o.vars.get(name.as_bytes()))
|
|
})?;
|
|
self.stack.get_var(*var_id, Span::new(0, 0)).ok()
|
|
}
|
|
|
|
/// Returns if the given function exists in the context
|
|
pub fn has_fn<S: AsRef<str>>(&mut self, name: S) -> bool {
|
|
self.engine_state
|
|
.find_decl(name.as_ref().as_bytes(), &vec![])
|
|
.is_some()
|
|
}
|
|
|
|
/// Calls a function by the given name
|
|
/// Errs if the function doesn't exist
|
|
pub fn call_fn<S: AsRef<str>, I: IntoIterator<Item = A>, A: IntoArgument>(
|
|
&mut self,
|
|
name: S,
|
|
args: I,
|
|
) -> CrateResult<PipelineData> {
|
|
let args = args
|
|
.into_iter()
|
|
.map(|a| a.into_argument().into_nu_argument())
|
|
.collect::<Vec<_>>();
|
|
|
|
let decl_id = self
|
|
.engine_state
|
|
.find_decl(name.as_ref().as_bytes(), &vec![])
|
|
.ok_or_else(|| CrateError::FunctionNotFound(name.as_ref().to_string()))?;
|
|
let call = Call {
|
|
decl_id,
|
|
head: Span::empty(),
|
|
arguments: args,
|
|
redirect_stdout: true,
|
|
redirect_stderr: true,
|
|
parser_info: Vec::new(),
|
|
};
|
|
|
|
let data = nu_engine::eval_call(
|
|
&self.engine_state,
|
|
&mut self.stack,
|
|
&call,
|
|
PipelineData::empty(),
|
|
)?;
|
|
|
|
Ok(data)
|
|
}
|
|
|
|
/// Prints the data of the given pipeline to stdout
|
|
pub fn print_pipeline(&mut self, pipeline: PipelineData) -> CrateResult<()> {
|
|
pipeline.print(&self.engine_state, &mut self.stack, false, false)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Prints the data of the given pipeline to stderr
|
|
pub fn print_pipeline_stderr(&mut self, pipeline: PipelineData) -> CrateResult<()> {
|
|
pipeline.print(&self.engine_state, &mut self.stack, false, true)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Adds a variable to the context
|
|
pub fn add_var<S: ToString, V: IntoValue>(&mut self, name: S, value: V) -> CrateResult<()> {
|
|
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,
|
|
false,
|
|
);
|
|
self.stack.add_var(var_id, value.into_value());
|
|
let delta = working_set.render();
|
|
self.engine_state.merge_delta(delta)?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|