Plugin with evaluated call (#393)

* plugin trait

* impl of trait

* record and absolute path

* plugin example crate

* clippy error

* correcting cargo

* evaluated call for plugin
This commit is contained in:
Fernando Herrera
2021-12-02 05:42:56 +00:00
committed by GitHub
parent 2bbba3f5da
commit 56307553ae
29 changed files with 1140 additions and 770 deletions

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use crate::{ast::Call, BlockId, Example, PipelineData, ShellError, Signature};
use super::{EngineState, Stack};
@ -47,7 +49,7 @@ pub trait Command: Send + Sync + CommandClone {
}
// Is a plugin command
fn is_plugin(&self) -> Option<&str> {
fn is_plugin(&self) -> Option<&PathBuf> {
None
}

View File

@ -222,26 +222,27 @@ impl EngineState {
if let Some(plugin_path) = &self.plugin_signatures {
// Always creating the file which will erase previous signatures
let mut plugin_file = std::fs::File::create(plugin_path.as_path())
.map_err(|err| ShellError::PluginError(err.to_string()))?;
.map_err(|err| ShellError::InternalError(err.to_string()))?;
// Plugin definitions with parsed signature
for decl in self.plugin_decls() {
// A successful plugin registration already includes the plugin filename
// No need to check the None option
let file_name = decl.is_plugin().expect("plugin should have file name");
let path = decl.is_plugin().expect("plugin should have file name");
let file_name = path.to_str().expect("path should be a str");
let line = serde_json::to_string_pretty(&decl.signature())
.map(|signature| format!("register {} {}\n", file_name, signature))
.map_err(|err| ShellError::PluginError(err.to_string()))?;
.map_err(|err| ShellError::InternalError(err.to_string()))?;
plugin_file
.write_all(line.as_bytes())
.map_err(|err| ShellError::PluginError(err.to_string()))?;
.map_err(|err| ShellError::InternalError(err.to_string()))?;
}
Ok(())
} else {
Err(ShellError::PluginError("Plugin file not found".into()))
Err(ShellError::InternalError("Plugin file not found".into()))
}
}
@ -510,11 +511,13 @@ pub struct StateDelta {
pub(crate) file_contents: Vec<(Vec<u8>, usize, usize)>,
vars: Vec<Type>, // indexed by VarId
decls: Vec<Box<dyn Command>>, // indexed by DeclId
#[cfg(feature = "plugin")]
plugin_decls: Vec<Box<dyn Command>>, // indexed by DeclId
blocks: Vec<Block>, // indexed by BlockId
overlays: Vec<Overlay>, // indexed by OverlayId
pub scope: Vec<ScopeFrame>,
#[cfg(feature = "plugin")]
pub plugin_signatures: Vec<(PathBuf, Option<Signature>)>,
#[cfg(feature = "plugin")]
plugin_decls: Vec<Box<dyn Command>>,
}
impl StateDelta {
@ -551,11 +554,13 @@ impl<'a> StateWorkingSet<'a> {
file_contents: vec![],
vars: vec![],
decls: vec![],
#[cfg(feature = "plugin")]
plugin_decls: vec![],
blocks: vec![],
overlays: vec![],
scope: vec![ScopeFrame::new()],
#[cfg(feature = "plugin")]
plugin_signatures: vec![],
#[cfg(feature = "plugin")]
plugin_decls: vec![],
},
permanent_state,
}
@ -624,8 +629,20 @@ impl<'a> StateWorkingSet<'a> {
}
#[cfg(feature = "plugin")]
pub fn add_plugin_decl(&mut self, decl: Box<dyn Command>) {
self.delta.plugin_decls.push(decl);
pub fn add_plugin_decls(&mut self, decls: Vec<Box<dyn Command>>) {
for decl in decls {
self.delta.plugin_decls.push(decl);
}
}
#[cfg(feature = "plugin")]
pub fn add_plugin_signature(&mut self, path: PathBuf, signature: Option<Signature>) {
self.delta.plugin_signatures.push((path, signature));
}
#[cfg(feature = "plugin")]
pub fn get_signatures(&self) -> impl Iterator<Item = &(PathBuf, Option<Signature>)> {
self.delta.plugin_signatures.iter()
}
pub fn merge_predecl(&mut self, name: &[u8]) -> Option<DeclId> {

View File

@ -200,9 +200,6 @@ pub enum ShellError {
#[error("No file to be copied")]
NoFileToBeCopied(),
#[error("Plugin error")]
PluginError(String),
#[error("Name not found")]
#[diagnostic(code(nu::shell::name_not_found), url(docsrs))]
DidYouMean(String, #[label("did you mean '{0}'?")] Span),

View File

@ -0,0 +1,339 @@
// use std::path::PathBuf;
use std::path::PathBuf;
use std::str::FromStr;
use chrono::{DateTime, FixedOffset};
// use nu_path::expand_path;
use crate::ast::{CellPath, PathMember};
use crate::ShellError;
use crate::{Range, Spanned, Value};
pub trait FromValue: Sized {
fn from_value(v: &Value) -> Result<Self, ShellError>;
}
impl FromValue for Value {
fn from_value(v: &Value) -> Result<Self, ShellError> {
Ok(v.clone())
}
}
impl FromValue for Spanned<i64> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Int { val, span } => Ok(Spanned {
item: *val,
span: *span,
}),
Value::Filesize { val, span } => Ok(Spanned {
item: *val as i64,
span: *span,
}),
Value::Duration { val, span } => Ok(Spanned {
item: *val as i64,
span: *span,
}),
v => Err(ShellError::CantConvert(
"integer".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for i64 {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Int { val, .. } => Ok(*val),
Value::Filesize { val, .. } => Ok(*val as i64),
Value::Duration { val, .. } => Ok(*val as i64),
v => Err(ShellError::CantConvert(
"integer".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for Spanned<f64> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Int { val, span } => Ok(Spanned {
item: *val as f64,
span: *span,
}),
Value::Float { val, span } => Ok(Spanned {
item: *val,
span: *span,
}),
v => Err(ShellError::CantConvert(
"float".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for f64 {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Float { val, .. } => Ok(*val),
Value::Int { val, .. } => Ok(*val as f64),
v => Err(ShellError::CantConvert(
"float".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for Spanned<usize> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Int { val, span } => Ok(Spanned {
item: *val as usize,
span: *span,
}),
Value::Filesize { val, span } => Ok(Spanned {
item: *val as usize,
span: *span,
}),
Value::Duration { val, span } => Ok(Spanned {
item: *val as usize,
span: *span,
}),
v => Err(ShellError::CantConvert(
"integer".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for usize {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Int { val, .. } => Ok(*val as usize),
Value::Filesize { val, .. } => Ok(*val as usize),
Value::Duration { val, .. } => Ok(*val as usize),
v => Err(ShellError::CantConvert(
"integer".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for String {
fn from_value(v: &Value) -> Result<Self, ShellError> {
// FIXME: we may want to fail a little nicer here
match v {
Value::CellPath { val, .. } => Ok(val.into_string()),
Value::String { val, .. } => Ok(val.clone()),
v => Err(ShellError::CantConvert(
"string".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for Spanned<String> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
Ok(Spanned {
item: match v {
Value::CellPath { val, .. } => val.into_string(),
Value::String { val, .. } => val.clone(),
v => {
return Err(ShellError::CantConvert(
"string".into(),
v.get_type().to_string(),
v.span()?,
))
}
},
span: v.span()?,
})
}
}
impl FromValue for Vec<String> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
// FIXME: we may want to fail a little nicer here
match v {
Value::List { vals, .. } => vals
.iter()
.map(|val| match val {
Value::String { val, .. } => Ok(val.clone()),
c => Err(ShellError::CantConvert(
"string".into(),
c.get_type().to_string(),
c.span()?,
)),
})
.collect::<Result<Vec<String>, ShellError>>(),
v => Err(ShellError::CantConvert(
"string".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for CellPath {
fn from_value(v: &Value) -> Result<Self, ShellError> {
let span = v.span()?;
match v {
Value::CellPath { val, .. } => Ok(val.clone()),
Value::String { val, .. } => Ok(CellPath {
members: vec![PathMember::String {
val: val.clone(),
span,
}],
}),
Value::Int { val, .. } => Ok(CellPath {
members: vec![PathMember::Int {
val: *val as usize,
span,
}],
}),
x => Err(ShellError::CantConvert(
"cell path".into(),
x.get_type().to_string(),
span,
)),
}
}
}
impl FromValue for bool {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Bool { val, .. } => Ok(*val),
v => Err(ShellError::CantConvert(
"bool".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for Spanned<bool> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Bool { val, span } => Ok(Spanned {
item: *val,
span: *span,
}),
v => Err(ShellError::CantConvert(
"bool".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for DateTime<FixedOffset> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Date { val, .. } => Ok(*val),
v => Err(ShellError::CantConvert(
"date".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for Spanned<DateTime<FixedOffset>> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Date { val, span } => Ok(Spanned {
item: *val,
span: *span,
}),
v => Err(ShellError::CantConvert(
"date".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for Range {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Range { val, .. } => Ok((**val).clone()),
v => Err(ShellError::CantConvert(
"range".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for Spanned<Range> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Range { val, span } => Ok(Spanned {
item: (**val).clone(),
span: *span,
}),
v => Err(ShellError::CantConvert(
"range".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for Vec<u8> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::Binary { val, .. } => Ok(val.clone()),
Value::String { val, .. } => Ok(val.bytes().collect()),
v => Err(ShellError::CantConvert(
"binary data".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}
impl FromValue for Spanned<PathBuf> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
match v {
Value::String { val, span } => Ok(Spanned {
item: PathBuf::from_str(val)
.map_err(|err| ShellError::FileNotFoundCustom(err.to_string(), *span))?,
span: *span,
}),
v => Err(ShellError::CantConvert(
"range".into(),
v.get_type().to_string(),
v.span()?,
)),
}
}
}

View File

@ -1,11 +1,13 @@
mod custom_value;
mod from;
mod from_value;
mod range;
mod stream;
mod unit;
use chrono::{DateTime, FixedOffset};
use chrono_humanize::HumanTime;
pub use from_value::FromValue;
use indexmap::map::IndexMap;
pub use range::*;
use serde::{Deserialize, Serialize};