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

@ -6,10 +6,9 @@ edition = "2018"
[dependencies]
miette = "3.0.0"
thiserror = "1.0.29"
nu-protocol = { path = "../nu-protocol"}
nu-plugin = { path = "../nu-plugin", optional=true}
serde_json = "1.0"
nu-path = {path = "../nu-path"}
nu-protocol = { path = "../nu-protocol"}
[features]
plugin = ["nu-plugin"]
plugin = []

View File

@ -191,7 +191,7 @@ pub enum ParseError {
#[diagnostic(code(nu::parser::export_not_found), url(docsrs))]
FileNotFound(String),
#[error("Plugin error")]
#[diagnostic(code(nu::parser::plugin_error), url(docsrs))]
PluginError(String),
#[error("{0}")]
#[diagnostic()]
LabeledError(String, String, #[label("{1}")] Span),
}

View File

@ -9,9 +9,6 @@ use nu_protocol::{
use std::collections::{HashMap, HashSet};
use std::path::Path;
#[cfg(feature = "plugin")]
use nu_plugin::plugin::{get_signature, PluginDeclaration};
use crate::{
lex, lite_parse,
parser::{
@ -1091,6 +1088,9 @@ pub fn parse_plugin(
working_set: &mut StateWorkingSet,
spans: &[Span],
) -> (Statement, Option<ParseError>) {
use std::{path::PathBuf, str::FromStr};
use nu_path::canonicalize;
use nu_protocol::Signature;
let name = working_set.get_span_contents(spans[0]);
@ -1117,51 +1117,55 @@ pub fn parse_plugin(
)),
2 => {
let name_expr = working_set.get_span_contents(spans[1]);
if let Ok(filename) = String::from_utf8(name_expr.to_vec()) {
let source_file = Path::new(&filename);
if source_file.exists() & source_file.is_file() {
// get signature from plugin
match get_signature(source_file) {
Err(err) => Some(ParseError::PluginError(format!("{}", err))),
Ok(signatures) => {
for signature in signatures {
// create plugin command declaration (need struct impl Command)
// store declaration in working set
let plugin_decl =
PluginDeclaration::new(filename.clone(), signature);
working_set.add_plugin_decl(Box::new(plugin_decl));
}
None
}
String::from_utf8(name_expr.to_vec())
.map_err(|_| ParseError::NonUtf8(spans[1]))
.and_then(|name| {
canonicalize(&name).map_err(|e| ParseError::FileNotFound(e.to_string()))
})
.and_then(|path| {
if path.exists() & path.is_file() {
working_set.add_plugin_signature(path, None);
Ok(())
} else {
Err(ParseError::FileNotFound(format!("{:?}", path)))
}
} else {
Some(ParseError::FileNotFound(filename))
}
} else {
Some(ParseError::NonUtf8(spans[1]))
}
})
.err()
}
3 => {
let filename = working_set.get_span_contents(spans[1]);
let filename_slice = working_set.get_span_contents(spans[1]);
let signature = working_set.get_span_contents(spans[2]);
let mut path = PathBuf::new();
if let Ok(filename) = String::from_utf8(filename.to_vec()) {
if let Ok(signature) = serde_json::from_slice::<Signature>(signature) {
let plugin_decl = PluginDeclaration::new(filename, signature);
working_set.add_plugin_decl(Box::new(plugin_decl));
None
} else {
Some(ParseError::PluginError(
"unable to deserialize signature".into(),
))
}
} else {
Some(ParseError::NonUtf8(spans[1]))
}
String::from_utf8(filename_slice.to_vec())
.map_err(|_| ParseError::NonUtf8(spans[1]))
.and_then(|name| {
PathBuf::from_str(name.as_str()).map_err(|_| {
ParseError::InternalError(
format!("Unable to create path from string {}", name),
spans[0],
)
})
})
.and_then(|path_inner| {
path = path_inner;
serde_json::from_slice::<Signature>(signature).map_err(|_| {
ParseError::LabeledError(
"Signature deserialization error".into(),
"unable to deserialize signature".into(),
spans[0],
)
})
})
.and_then(|signature| {
if path.exists() & path.is_file() {
working_set.add_plugin_signature(path, Some(signature));
Ok(())
} else {
Err(ParseError::FileNotFound(format!("{:?}", path)))
}
})
.err()
}
_ => {
let span = spans[3..].iter().fold(spans[3], |acc, next| Span {