mirror of
https://github.com/nushell/nushell
synced 2024-12-28 14:03:09 +00:00
Merge pull request #170 from nushell/argument-error
Add deeper support for spans in streams of values (by @wycats)
This commit is contained in:
commit
5ec5167cb9
71 changed files with 2032 additions and 1218 deletions
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
lkg-rust-nightly: "2019-06-28"
|
||||
lkg-rust-nightly: "2019-07-04"
|
||||
|
||||
trigger:
|
||||
- master
|
||||
|
|
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -1278,12 +1278,14 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "language-reporting"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/jonathandturner/language-reporting#0a6c284a19a00b5b6b680480c0ad5f241fc5edac"
|
||||
dependencies = [
|
||||
"derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"render-tree 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"render-tree 0.1.1 (git+https://github.com/jonathandturner/language-reporting)",
|
||||
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1649,7 +1651,7 @@ dependencies = [
|
|||
"image 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"language-reporting 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"language-reporting 0.3.0 (git+https://github.com/jonathandturner/language-reporting)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"logos 0.10.0-rc2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2354,7 +2356,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "render-tree"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/jonathandturner/language-reporting#0a6c284a19a00b5b6b680480c0ad5f241fc5edac"
|
||||
dependencies = [
|
||||
"itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3497,7 +3499,7 @@ dependencies = [
|
|||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||
"checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum language-reporting 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61e5d4e5c7a76724d544bb5652a8a3ded29475a1b260a263b5d6743f5871ac83"
|
||||
"checksum language-reporting 0.3.0 (git+https://github.com/jonathandturner/language-reporting)" = "<none>"
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
|
@ -3606,7 +3608,7 @@ dependencies = [
|
|||
"checksum regex 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1325e8a57b7da4cbcb38b3957112f729990bad0a18420e7e250ef6b1d9a15763"
|
||||
"checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48"
|
||||
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||
"checksum render-tree 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "68ed587df09cfb7ce1bc6fe8f77e24db219f222c049326ccbfb948ec67e31664"
|
||||
"checksum render-tree 0.1.1 (git+https://github.com/jonathandturner/language-reporting)" = "<none>"
|
||||
"checksum reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)" = "00eb63f212df0e358b427f0f40aa13aaea010b470be642ad422bcbca2feff2e4"
|
||||
"checksum result 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "194d8e591e405d1eecf28819740abed6d719d1a2db87fc0bcdedee9a26d55560"
|
||||
"checksum roxmltree 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "330d8f80a274bc3cb608908ee345970e7e24b96907f1ad69615a498bec57871c"
|
||||
|
|
|
@ -40,7 +40,7 @@ serde_derive = "1.0.94"
|
|||
getset = "0.0.7"
|
||||
logos = "0.10.0-rc2"
|
||||
logos-derive = "0.10.0-rc2"
|
||||
language-reporting = "0.3.0"
|
||||
language-reporting = {git = "https://github.com/jonathandturner/language-reporting"}
|
||||
app_dirs = "1.2.1"
|
||||
toml = "0.5.1"
|
||||
toml-query = "0.9.2"
|
||||
|
|
11
src/cli.rs
11
src/cli.rs
|
@ -159,6 +159,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
command("sysinfo", Box::new(sysinfo::sysinfo)),
|
||||
command("cd", Box::new(cd::cd)),
|
||||
command("view", Box::new(view::view)),
|
||||
// command("skip", skip::Skip),
|
||||
command("first", Box::new(first::first)),
|
||||
command("size", Box::new(size::size)),
|
||||
command("from-ini", Box::new(from_ini::from_ini)),
|
||||
|
@ -167,7 +168,6 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
command("from-xml", Box::new(from_xml::from_xml)),
|
||||
command("from-yaml", Box::new(from_yaml::from_yaml)),
|
||||
command("get", Box::new(get::get)),
|
||||
command("enter", Box::new(enter::enter)),
|
||||
command("exit", Box::new(exit::exit)),
|
||||
command("lines", Box::new(lines::lines)),
|
||||
command("pick", Box::new(pick::pick)),
|
||||
|
@ -180,11 +180,12 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
command("to-json", Box::new(to_json::to_json)),
|
||||
command("to-toml", Box::new(to_toml::to_toml)),
|
||||
command("sort-by", Box::new(sort_by::sort_by)),
|
||||
command("sort-by", Box::new(sort_by::sort_by)),
|
||||
Arc::new(Open),
|
||||
Arc::new(Where),
|
||||
Arc::new(Config),
|
||||
Arc::new(SkipWhile),
|
||||
command("sort-by", Box::new(sort_by::sort_by)),
|
||||
Arc::new(Enter),
|
||||
]);
|
||||
|
||||
context.add_sinks(vec![
|
||||
|
@ -227,7 +228,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
let last = env.back().unwrap();
|
||||
(last.obj().clone(), last.path().display().to_string())
|
||||
};
|
||||
let readline = match obj {
|
||||
let readline = match obj.item {
|
||||
Value::Filesystem => rl.readline(&format!(
|
||||
"{}{}> ",
|
||||
cwd,
|
||||
|
@ -392,7 +393,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
|||
}
|
||||
|
||||
(Some(ClassifiedCommand::Sink(left)), None) => {
|
||||
let input_vec: Vec<Value> = input.objects.collect().await;
|
||||
let input_vec: Vec<Spanned<Value>> = input.objects.into_vec().await;
|
||||
if let Err(err) = left.run(ctx, input_vec) {
|
||||
return LineResult::Error(line.clone(), err);
|
||||
}
|
||||
|
@ -496,7 +497,7 @@ fn classify_command(
|
|||
let config = command.config();
|
||||
let scope = Scope::empty();
|
||||
|
||||
trace!("classifying {:?}", config);
|
||||
trace!(target: "nu::build_pipeline", "classifying {:?}", config);
|
||||
|
||||
let args = config.evaluate_args(call, context, &scope, source)?;
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#[macro_use]
|
||||
crate mod macros;
|
||||
|
||||
crate mod args;
|
||||
crate mod autoview;
|
||||
crate mod cd;
|
||||
|
@ -39,6 +42,7 @@ crate mod where_;
|
|||
|
||||
crate use command::command;
|
||||
crate use config::Config;
|
||||
crate use enter::Enter;
|
||||
crate use open::Open;
|
||||
crate use skip_while::SkipWhile;
|
||||
crate use where_::Where;
|
||||
|
|
|
@ -5,7 +5,11 @@ use crate::prelude::*;
|
|||
|
||||
pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
if args.input.len() > 0 {
|
||||
if let Value::Binary(_) = args.input[0] {
|
||||
if let Spanned {
|
||||
item: Value::Binary(_),
|
||||
..
|
||||
} = args.input[0]
|
||||
{
|
||||
args.ctx.get_sink("binaryview").run(args)?;
|
||||
} else if equal_shapes(&args.input) {
|
||||
args.ctx.get_sink("table").run(args)?;
|
||||
|
@ -22,7 +26,7 @@ pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn equal_shapes(input: &Vec<Value>) -> bool {
|
||||
fn equal_shapes(input: &Vec<Spanned<Value>>) -> bool {
|
||||
let mut items = input.iter();
|
||||
|
||||
let item = match items.next() {
|
||||
|
|
|
@ -6,8 +6,9 @@ use std::path::PathBuf;
|
|||
pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let env = args.env.lock().unwrap();
|
||||
let latest = env.back().unwrap();
|
||||
let obj = &latest.obj;
|
||||
|
||||
match latest.obj {
|
||||
match obj.item() {
|
||||
Value::Filesystem => {
|
||||
let cwd = latest.path().to_path_buf();
|
||||
|
||||
|
@ -52,14 +53,14 @@ pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
}
|
||||
}
|
||||
}
|
||||
stream.push_back(ReturnValue::change_cwd(path));
|
||||
Ok(stream.boxed())
|
||||
stream.push_back(ReturnSuccess::change_cwd(path));
|
||||
Ok(stream.into())
|
||||
}
|
||||
_ => {
|
||||
let mut stream = VecDeque::new();
|
||||
match args.nth(0) {
|
||||
None => {
|
||||
stream.push_back(ReturnValue::change_cwd(PathBuf::from("/")));
|
||||
stream.push_back(ReturnSuccess::change_cwd(PathBuf::from("/")));
|
||||
}
|
||||
Some(v) => {
|
||||
let mut cwd = latest.path().to_path_buf();
|
||||
|
@ -75,10 +76,10 @@ pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
}
|
||||
},
|
||||
}
|
||||
stream.push_back(ReturnValue::change_cwd(cwd));
|
||||
stream.push_back(ReturnSuccess::change_cwd(cwd));
|
||||
}
|
||||
};
|
||||
Ok(stream.boxed())
|
||||
Ok(stream.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,21 +54,21 @@ crate struct ClassifiedInputStream {
|
|||
impl ClassifiedInputStream {
|
||||
crate fn new() -> ClassifiedInputStream {
|
||||
ClassifiedInputStream {
|
||||
objects: VecDeque::new().boxed(),
|
||||
objects: VecDeque::new().into(),
|
||||
stdin: None,
|
||||
}
|
||||
}
|
||||
|
||||
crate fn from_input_stream(stream: InputStream) -> ClassifiedInputStream {
|
||||
crate fn from_input_stream(stream: impl Into<InputStream>) -> ClassifiedInputStream {
|
||||
ClassifiedInputStream {
|
||||
objects: stream,
|
||||
objects: stream.into(),
|
||||
stdin: None,
|
||||
}
|
||||
}
|
||||
|
||||
crate fn from_stdout(stdout: std::fs::File) -> ClassifiedInputStream {
|
||||
ClassifiedInputStream {
|
||||
objects: VecDeque::new().boxed(),
|
||||
objects: VecDeque::new().into(),
|
||||
stdin: Some(stdout),
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +86,18 @@ crate enum ClassifiedCommand {
|
|||
External(ExternalCommand),
|
||||
}
|
||||
|
||||
impl ClassifiedCommand {
|
||||
#[allow(unused)]
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
ClassifiedCommand::Expr(token) => token.span(),
|
||||
ClassifiedCommand::Internal(internal) => internal.name_span.into(),
|
||||
ClassifiedCommand::Sink(sink) => sink.name_span.into(),
|
||||
ClassifiedCommand::External(external) => external.name_span.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate struct SinkCommand {
|
||||
crate command: Arc<dyn Sink>,
|
||||
crate name_span: Option<Span>,
|
||||
|
@ -93,7 +105,11 @@ crate struct SinkCommand {
|
|||
}
|
||||
|
||||
impl SinkCommand {
|
||||
crate fn run(self, context: &mut Context, input: Vec<Value>) -> Result<(), ShellError> {
|
||||
crate fn run(
|
||||
self,
|
||||
context: &mut Context,
|
||||
input: Vec<Spanned<Value>>,
|
||||
) -> Result<(), ShellError> {
|
||||
context.run_sink(self.command, self.name_span.clone(), self.args, input)
|
||||
}
|
||||
}
|
||||
|
@ -110,31 +126,24 @@ impl InternalCommand {
|
|||
context: &mut Context,
|
||||
input: ClassifiedInputStream,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
let objects = if log_enabled!(log::Level::Trace) {
|
||||
trace!("->");
|
||||
trace!("{}", self.command.name());
|
||||
trace!("{:?}", self.args.debug());
|
||||
let objects: Vec<_> = input.objects.collect().await;
|
||||
trace!(
|
||||
"input = {:#?}",
|
||||
objects.iter().map(|o| o.debug()).collect::<Vec<_>>(),
|
||||
);
|
||||
VecDeque::from(objects).boxed()
|
||||
} else {
|
||||
input.objects
|
||||
};
|
||||
if log_enabled!(log::Level::Trace) {
|
||||
trace!(target: "nu::run::internal", "->");
|
||||
trace!(target: "nu::run::internal", "{}", self.command.name());
|
||||
trace!(target: "nu::run::internal", "{:?}", self.args.debug());
|
||||
}
|
||||
|
||||
let mut result =
|
||||
let objects: InputStream =
|
||||
trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects);
|
||||
|
||||
let result =
|
||||
context.run_command(self.command, self.name_span.clone(), self.args, objects)?;
|
||||
|
||||
let mut result = result.values;
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
while let Some(item) = result.next().await {
|
||||
match item {
|
||||
ReturnValue::Value(Value::Error(err)) => {
|
||||
return Err(*err);
|
||||
}
|
||||
|
||||
ReturnValue::Action(action) => match action {
|
||||
match item? {
|
||||
ReturnSuccess::Action(action) => match action {
|
||||
CommandAction::ChangePath(path) => {
|
||||
context.env.lock().unwrap().back_mut().map(|x| {
|
||||
x.path = path;
|
||||
|
@ -150,7 +159,11 @@ impl InternalCommand {
|
|||
}
|
||||
CommandAction::Exit => match context.env.lock().unwrap().pop_back() {
|
||||
Some(Environment {
|
||||
obj: Value::Filesystem,
|
||||
obj:
|
||||
Spanned {
|
||||
item: Value::Filesystem,
|
||||
..
|
||||
},
|
||||
..
|
||||
}) => std::process::exit(0),
|
||||
None => std::process::exit(-1),
|
||||
|
@ -158,12 +171,13 @@ impl InternalCommand {
|
|||
},
|
||||
},
|
||||
|
||||
ReturnValue::Value(v) => {
|
||||
ReturnSuccess::Value(v) => {
|
||||
stream.push_back(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(stream.boxed() as InputStream)
|
||||
|
||||
Ok(stream.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,9 +201,12 @@ impl ExternalCommand {
|
|||
input: ClassifiedInputStream,
|
||||
stream_next: StreamNext,
|
||||
) -> Result<ClassifiedInputStream, ShellError> {
|
||||
let inputs: Vec<Value> = input.objects.collect().await;
|
||||
let stdin = input.stdin;
|
||||
let inputs: Vec<Spanned<Value>> = input.objects.into_vec().await;
|
||||
let name_span = self.name_span.clone();
|
||||
|
||||
trace!("{:?} -> {}", inputs, self.name);
|
||||
trace!(target: "nu::run::external", "-> {}", self.name);
|
||||
trace!(target: "nu::run::external", "inputs = {:?}", inputs);
|
||||
|
||||
let mut arg_string = format!("{}", self.name);
|
||||
for arg in &self.args {
|
||||
|
@ -298,7 +315,7 @@ impl ExternalCommand {
|
|||
}
|
||||
};
|
||||
|
||||
if let Some(stdin) = input.stdin {
|
||||
if let Some(stdin) = stdin {
|
||||
process = process.stdin(stdin);
|
||||
}
|
||||
|
||||
|
@ -317,8 +334,11 @@ impl ExternalCommand {
|
|||
let stdout = popen.stdout.take().unwrap();
|
||||
let file = futures::io::AllowStdIo::new(stdout);
|
||||
let stream = Framed::new(file, LinesCodec {});
|
||||
let stream = stream.map(|line| Value::string(line.unwrap()));
|
||||
Ok(ClassifiedInputStream::from_input_stream(stream.boxed()))
|
||||
let stream =
|
||||
stream.map(move |line| Value::string(line.unwrap()).spanned(name_span));
|
||||
Ok(ClassifiedInputStream::from_input_stream(
|
||||
stream.boxed() as BoxStream<'static, Spanned<Value>>
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::commands::command::SinkCommandArgs;
|
||||
use crate::errors::ShellError;
|
||||
use crate::errors::{labelled, ShellError};
|
||||
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||
|
||||
pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap();
|
||||
let mut new_copy_data = String::new();
|
||||
|
||||
if args.input.len() > 0 {
|
||||
let mut first = true;
|
||||
for i in args.input.iter() {
|
||||
|
@ -13,18 +14,17 @@ pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> {
|
|||
} else {
|
||||
first = false;
|
||||
}
|
||||
match i.as_string() {
|
||||
Ok(s) => new_copy_data.push_str(&s),
|
||||
Err(_) => {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
|
||||
let string = i.as_string().map_err(labelled(
|
||||
args.name_span,
|
||||
"Given non-string data",
|
||||
"expected strings from pipeline",
|
||||
args.name_span,
|
||||
))
|
||||
}
|
||||
}
|
||||
))?;
|
||||
|
||||
new_copy_data.push_str(&string);
|
||||
}
|
||||
}
|
||||
|
||||
clip_context.set_contents(new_copy_data).unwrap();
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -49,25 +49,41 @@ pub struct SinkCommandArgs {
|
|||
pub ctx: Context,
|
||||
pub name_span: Option<Span>,
|
||||
pub args: Args,
|
||||
pub input: Vec<Value>,
|
||||
pub input: Vec<Spanned<Value>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum CommandAction {
|
||||
ChangePath(PathBuf),
|
||||
Enter(Value),
|
||||
Enter(Spanned<Value>),
|
||||
Exit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum ReturnValue {
|
||||
Value(Value),
|
||||
pub enum ReturnSuccess {
|
||||
Value(Spanned<Value>),
|
||||
Action(CommandAction),
|
||||
}
|
||||
|
||||
impl ReturnValue {
|
||||
crate fn change_cwd(path: PathBuf) -> ReturnValue {
|
||||
ReturnValue::Action(CommandAction::ChangePath(path))
|
||||
pub type ReturnValue = Result<ReturnSuccess, ShellError>;
|
||||
|
||||
impl From<Spanned<Value>> for ReturnValue {
|
||||
fn from(input: Spanned<Value>) -> ReturnValue {
|
||||
Ok(ReturnSuccess::Value(input))
|
||||
}
|
||||
}
|
||||
|
||||
impl ReturnSuccess {
|
||||
pub fn change_cwd(path: PathBuf) -> ReturnValue {
|
||||
Ok(ReturnSuccess::Action(CommandAction::ChangePath(path)))
|
||||
}
|
||||
|
||||
pub fn value(input: impl Into<Spanned<Value>>) -> ReturnValue {
|
||||
Ok(ReturnSuccess::Value(input.into()))
|
||||
}
|
||||
|
||||
pub fn spanned_value(input: Value, span: Span) -> ReturnValue {
|
||||
Ok(ReturnSuccess::Value(Spanned::from_item(input, span)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,14 +94,11 @@ pub trait Command {
|
|||
fn config(&self) -> registry::CommandConfig {
|
||||
registry::CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
mandatory_positional: vec![],
|
||||
optional_positional: vec![],
|
||||
positional: vec![],
|
||||
rest_positional: true,
|
||||
named: indexmap::IndexMap::new(),
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
can_load: vec![],
|
||||
can_save: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,14 +110,11 @@ pub trait Sink {
|
|||
fn config(&self) -> registry::CommandConfig {
|
||||
registry::CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
mandatory_positional: vec![],
|
||||
optional_positional: vec![],
|
||||
positional: vec![],
|
||||
rest_positional: true,
|
||||
named: indexmap::IndexMap::new(),
|
||||
is_filter: false,
|
||||
is_sink: true,
|
||||
can_load: vec![],
|
||||
can_save: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::config;
|
||||
use crate::object::Value;
|
||||
use crate::parser::registry::{CommandConfig, NamedType, NamedValue};
|
||||
use crate::prelude::*;
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
pub struct Config;
|
||||
|
||||
|
@ -29,20 +31,17 @@ impl Command for Config {
|
|||
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
mandatory_positional: vec![],
|
||||
optional_positional: vec![],
|
||||
positional: vec![],
|
||||
rest_positional: false,
|
||||
named,
|
||||
is_sink: true,
|
||||
is_filter: false,
|
||||
can_load: vec![],
|
||||
can_save: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut result = crate::object::config::config()?;
|
||||
let mut result = crate::object::config::config(args.name_span)?;
|
||||
|
||||
trace!("{:#?}", args.args.positional);
|
||||
trace!("{:#?}", args.args.named);
|
||||
|
@ -54,8 +53,7 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
.ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?;
|
||||
|
||||
return Ok(
|
||||
futures::stream::once(futures::future::ready(ReturnValue::Value(value.clone())))
|
||||
.boxed(),
|
||||
stream![value.clone()].into(), // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -66,24 +64,19 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
config::write_config(&result)?;
|
||||
|
||||
return Ok(
|
||||
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
||||
result.into(),
|
||||
))))
|
||||
.boxed(),
|
||||
stream![Spanned::from_item(Value::Object(result.into()), v.span())]
|
||||
.from_input_stream(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(_) = args.get("clear") {
|
||||
if let Some(c) = args.get("clear") {
|
||||
result.clear();
|
||||
|
||||
config::write_config(&result)?;
|
||||
|
||||
return Ok(
|
||||
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
||||
result.into(),
|
||||
))))
|
||||
.boxed(),
|
||||
stream![Spanned::from_item(Value::Object(result.into()), c.span())].from_input_stream(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -99,21 +92,12 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
)));
|
||||
}
|
||||
|
||||
return Ok(
|
||||
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
||||
result.into(),
|
||||
))))
|
||||
.boxed(),
|
||||
);
|
||||
let obj = VecDeque::from_iter(vec![Value::Object(result.into()).spanned(v)]);
|
||||
return Ok(obj.from_input_stream());
|
||||
}
|
||||
|
||||
if args.len() == 0 {
|
||||
return Ok(
|
||||
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
||||
result.into(),
|
||||
))))
|
||||
.boxed(),
|
||||
);
|
||||
return Ok(vec![Value::Object(result.into()).spanned(args.name_span)].into());
|
||||
}
|
||||
|
||||
Err(ShellError::string(format!("Unimplemented")))
|
||||
|
|
|
@ -2,9 +2,33 @@ use crate::commands::command::CommandAction;
|
|||
use crate::commands::open::{fetch, parse_as_value};
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::{Primitive, Value};
|
||||
use crate::parser::registry::{CommandConfig, PositionalType};
|
||||
use crate::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct Enter;
|
||||
|
||||
impl Command for Enter {
|
||||
fn config(&self) -> CommandConfig {
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![PositionalType::mandatory_block("path")],
|
||||
rest_positional: false,
|
||||
is_filter: false,
|
||||
is_sink: false,
|
||||
named: indexmap::IndexMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"enter"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
enter(args)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
|
@ -27,7 +51,7 @@ pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
|
||||
let full_path = PathBuf::from(cwd);
|
||||
|
||||
let (file_extension, contents) = match &args.expect_nth(0)?.item {
|
||||
let (file_extension, contents, contents_span) = match &args.expect_nth(0)?.item {
|
||||
Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?,
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
|
@ -68,15 +92,14 @@ pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
};
|
||||
|
||||
match contents {
|
||||
Value::Primitive(Primitive::String(x)) => {
|
||||
stream.push_back(ReturnValue::Action(CommandAction::Enter(parse_as_value(
|
||||
file_extension,
|
||||
x,
|
||||
span,
|
||||
)?)));
|
||||
}
|
||||
x => stream.push_back(ReturnValue::Action(CommandAction::Enter(x))),
|
||||
Value::Primitive(Primitive::String(string)) => {
|
||||
stream.push_back(Ok(ReturnSuccess::Action(CommandAction::Enter(
|
||||
parse_as_value(file_extension, string, contents_span, span)?,
|
||||
))));
|
||||
}
|
||||
|
||||
Ok(stream.boxed())
|
||||
other => stream.push_back(ReturnSuccess::value(other.spanned(contents_span))),
|
||||
};
|
||||
|
||||
Ok(stream.into())
|
||||
}
|
||||
|
|
|
@ -3,7 +3,5 @@ use crate::errors::ShellError;
|
|||
use crate::prelude::*;
|
||||
|
||||
pub fn exit(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(ReturnValue::Action(CommandAction::Exit));
|
||||
Ok(stream.boxed())
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into())
|
||||
}
|
||||
|
|
|
@ -27,8 +27,5 @@ pub fn first(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
|
||||
let input = args.input;
|
||||
|
||||
Ok(input
|
||||
.take(amount as u64)
|
||||
.map(|v| ReturnValue::Value(v))
|
||||
.boxed())
|
||||
Ok(OutputStream::from_input(input.values.take(amount as u64)))
|
||||
}
|
||||
|
|
|
@ -1,51 +1,61 @@
|
|||
use crate::object::{Dictionary, Primitive, Value};
|
||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
use indexmap::IndexMap;
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn convert_ini_second_to_nu_value(v: &HashMap<String, String>) -> Value {
|
||||
let mut second = Dictionary::new(IndexMap::new());
|
||||
fn convert_ini_second_to_nu_value(
|
||||
v: &HashMap<String, String>,
|
||||
span: impl Into<Span>,
|
||||
) -> Spanned<Value> {
|
||||
let mut second = SpannedDictBuilder::new(span);
|
||||
|
||||
for (key, value) in v.into_iter() {
|
||||
second.add(
|
||||
key.clone(),
|
||||
Value::Primitive(Primitive::String(value.clone())),
|
||||
);
|
||||
}
|
||||
Value::Object(second)
|
||||
}
|
||||
fn convert_ini_top_to_nu_value(v: &HashMap<String, HashMap<String, String>>) -> Value {
|
||||
let mut top_level = Dictionary::new(IndexMap::new());
|
||||
for (key, value) in v.iter() {
|
||||
top_level.add(key.clone(), convert_ini_second_to_nu_value(value));
|
||||
}
|
||||
Value::Object(top_level)
|
||||
second.insert(key.clone(), Primitive::String(value.clone()));
|
||||
}
|
||||
|
||||
pub fn from_ini_string_to_value(s: String) -> Result<Value, Box<dyn std::error::Error>> {
|
||||
second.into_spanned_value()
|
||||
}
|
||||
|
||||
fn convert_ini_top_to_nu_value(
|
||||
v: &HashMap<String, HashMap<String, String>>,
|
||||
span: impl Into<Span>,
|
||||
) -> Spanned<Value> {
|
||||
let span = span.into();
|
||||
let mut top_level = SpannedDictBuilder::new(span);
|
||||
|
||||
for (key, value) in v.iter() {
|
||||
top_level.insert_spanned(key.clone(), convert_ini_second_to_nu_value(value, span));
|
||||
}
|
||||
|
||||
top_level.into_spanned_value()
|
||||
}
|
||||
|
||||
pub fn from_ini_string_to_value(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
||||
let v: HashMap<String, HashMap<String, String>> = serde_ini::from_str(&s)?;
|
||||
Ok(convert_ini_top_to_nu_value(&v))
|
||||
Ok(convert_ini_top_to_nu_value(&v, span))
|
||||
}
|
||||
|
||||
pub fn from_ini(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
let span = args.name_span;
|
||||
Ok(out
|
||||
.map(move |a| match a {
|
||||
Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s) {
|
||||
Ok(x) => ReturnValue::Value(x),
|
||||
Err(e) => {
|
||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s, span) {
|
||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
||||
Err(e) => Err(ShellError::maybe_labeled_error(
|
||||
"Could not parse as INI",
|
||||
format!("{:#?}", e),
|
||||
span,
|
||||
))))
|
||||
}
|
||||
)),
|
||||
},
|
||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)))),
|
||||
)),
|
||||
})
|
||||
.boxed())
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -1,55 +1,67 @@
|
|||
use crate::object::base::OF64;
|
||||
use crate::object::{Dictionary, Primitive, Value};
|
||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
fn convert_json_value_to_nu_value(v: &serde_hjson::Value) -> Value {
|
||||
fn convert_json_value_to_nu_value(v: &serde_hjson::Value, span: impl Into<Span>) -> Spanned<Value> {
|
||||
let span = span.into();
|
||||
|
||||
match v {
|
||||
serde_hjson::Value::Null => Value::Primitive(Primitive::String(String::from(""))),
|
||||
serde_hjson::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)),
|
||||
serde_hjson::Value::F64(n) => Value::Primitive(Primitive::Float(OF64::from(*n))),
|
||||
serde_hjson::Value::U64(n) => Value::Primitive(Primitive::Int(*n as i64)),
|
||||
serde_hjson::Value::I64(n) => Value::Primitive(Primitive::Int(*n as i64)),
|
||||
serde_hjson::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))),
|
||||
serde_hjson::Value::Null => {
|
||||
Value::Primitive(Primitive::String(String::from(""))).spanned(span)
|
||||
}
|
||||
serde_hjson::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span),
|
||||
serde_hjson::Value::F64(n) => {
|
||||
Value::Primitive(Primitive::Float(OF64::from(*n))).spanned(span)
|
||||
}
|
||||
serde_hjson::Value::U64(n) => Value::Primitive(Primitive::Int(*n as i64)).spanned(span),
|
||||
serde_hjson::Value::I64(n) => Value::Primitive(Primitive::Int(*n as i64)).spanned(span),
|
||||
serde_hjson::Value::String(s) => {
|
||||
Value::Primitive(Primitive::String(String::from(s))).spanned(span)
|
||||
}
|
||||
serde_hjson::Value::Array(a) => Value::List(
|
||||
a.iter()
|
||||
.map(|x| convert_json_value_to_nu_value(x))
|
||||
.map(|x| convert_json_value_to_nu_value(x, span))
|
||||
.collect(),
|
||||
),
|
||||
)
|
||||
.spanned(span),
|
||||
serde_hjson::Value::Object(o) => {
|
||||
let mut collected = Dictionary::default();
|
||||
let mut collected = SpannedDictBuilder::new(span);
|
||||
for (k, v) in o.iter() {
|
||||
collected.add(k.clone(), convert_json_value_to_nu_value(v));
|
||||
collected.insert_spanned(k.clone(), convert_json_value_to_nu_value(v, span));
|
||||
}
|
||||
Value::Object(collected)
|
||||
|
||||
collected.into_spanned_value()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_json_string_to_value(s: String) -> serde_hjson::Result<Value> {
|
||||
pub fn from_json_string_to_value(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> serde_hjson::Result<Spanned<Value>> {
|
||||
let v: serde_hjson::Value = serde_hjson::from_str(&s)?;
|
||||
Ok(convert_json_value_to_nu_value(&v))
|
||||
Ok(convert_json_value_to_nu_value(&v, span))
|
||||
}
|
||||
|
||||
pub fn from_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
let span = args.name_span;
|
||||
Ok(out
|
||||
.map(move |a| match a {
|
||||
Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s) {
|
||||
Ok(x) => ReturnValue::Value(x),
|
||||
Err(_) => {
|
||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s, span) {
|
||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Could not parse as JSON",
|
||||
"piped data failed JSON parse",
|
||||
span,
|
||||
))))
|
||||
}
|
||||
)),
|
||||
},
|
||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)))),
|
||||
)),
|
||||
})
|
||||
.boxed())
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -1,54 +1,65 @@
|
|||
use crate::object::base::OF64;
|
||||
use crate::object::{Dictionary, Primitive, Value};
|
||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
fn convert_toml_value_to_nu_value(v: &toml::Value) -> Value {
|
||||
fn convert_toml_value_to_nu_value(v: &toml::Value, span: impl Into<Span>) -> Spanned<Value> {
|
||||
let span = span.into();
|
||||
|
||||
match v {
|
||||
toml::Value::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)),
|
||||
toml::Value::Integer(n) => Value::Primitive(Primitive::Int(*n)),
|
||||
toml::Value::Float(n) => Value::Primitive(Primitive::Float(OF64::from(*n))),
|
||||
toml::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))),
|
||||
toml::Value::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span),
|
||||
toml::Value::Integer(n) => Value::Primitive(Primitive::Int(*n)).spanned(span),
|
||||
toml::Value::Float(n) => Value::Primitive(Primitive::Float(OF64::from(*n))).spanned(span),
|
||||
toml::Value::String(s) => {
|
||||
Value::Primitive(Primitive::String(String::from(s))).spanned(span)
|
||||
}
|
||||
toml::Value::Array(a) => Value::List(
|
||||
a.iter()
|
||||
.map(|x| convert_toml_value_to_nu_value(x))
|
||||
.map(|x| convert_toml_value_to_nu_value(x, span))
|
||||
.collect(),
|
||||
),
|
||||
toml::Value::Datetime(dt) => Value::Primitive(Primitive::String(dt.to_string())),
|
||||
toml::Value::Table(t) => {
|
||||
let mut collected = Dictionary::default();
|
||||
for (k, v) in t.iter() {
|
||||
collected.add(k.clone(), convert_toml_value_to_nu_value(v));
|
||||
)
|
||||
.spanned(span),
|
||||
toml::Value::Datetime(dt) => {
|
||||
Value::Primitive(Primitive::String(dt.to_string())).spanned(span)
|
||||
}
|
||||
Value::Object(collected)
|
||||
toml::Value::Table(t) => {
|
||||
let mut collected = SpannedDictBuilder::new(span);
|
||||
|
||||
for (k, v) in t.iter() {
|
||||
collected.insert_spanned(k.clone(), convert_toml_value_to_nu_value(v, span));
|
||||
}
|
||||
|
||||
collected.into_spanned_value()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_toml_string_to_value(s: String) -> Result<Value, Box<dyn std::error::Error>> {
|
||||
pub fn from_toml_string_to_value(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
||||
let v: toml::Value = s.parse::<toml::Value>()?;
|
||||
Ok(convert_toml_value_to_nu_value(&v))
|
||||
Ok(convert_toml_value_to_nu_value(&v, span))
|
||||
}
|
||||
|
||||
pub fn from_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
let span = args.name_span;
|
||||
Ok(out
|
||||
.map(move |a| match a {
|
||||
Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s) {
|
||||
Ok(x) => ReturnValue::Value(x),
|
||||
Err(_) => {
|
||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s, span) {
|
||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Could not parse as TOML",
|
||||
"piped data failed TOML parse",
|
||||
span,
|
||||
))))
|
||||
}
|
||||
)),
|
||||
},
|
||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)))),
|
||||
)),
|
||||
})
|
||||
.boxed())
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -1,19 +1,27 @@
|
|||
use crate::object::{Dictionary, Primitive, Value};
|
||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value {
|
||||
fn from_node_to_value<'a, 'd>(
|
||||
n: &roxmltree::Node<'a, 'd>,
|
||||
span: impl Into<Span>,
|
||||
) -> Spanned<Value> {
|
||||
let span = span.into();
|
||||
|
||||
if n.is_element() {
|
||||
let name = n.tag_name().name().trim().to_string();
|
||||
|
||||
let mut children_values = vec![];
|
||||
for c in n.children() {
|
||||
children_values.push(from_node_to_value(&c));
|
||||
children_values.push(from_node_to_value(&c, span));
|
||||
}
|
||||
|
||||
let children_values: Vec<Value> = children_values
|
||||
let children_values: Vec<Spanned<Value>> = children_values
|
||||
.into_iter()
|
||||
.filter(|x| match x {
|
||||
Value::Primitive(Primitive::String(f)) => {
|
||||
Spanned {
|
||||
item: Value::Primitive(Primitive::String(f)),
|
||||
..
|
||||
} => {
|
||||
if f.trim() == "" {
|
||||
false
|
||||
} else {
|
||||
|
@ -24,50 +32,52 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value {
|
|||
})
|
||||
.collect();
|
||||
|
||||
let mut collected = Dictionary::default();
|
||||
collected.add(name.clone(), Value::List(children_values));
|
||||
let mut collected = SpannedDictBuilder::new(span);
|
||||
collected.insert(name.clone(), Value::List(children_values));
|
||||
|
||||
Value::Object(collected)
|
||||
collected.into_spanned_value()
|
||||
} else if n.is_comment() {
|
||||
Value::string("<comment>")
|
||||
Value::string("<comment>").spanned(span)
|
||||
} else if n.is_pi() {
|
||||
Value::string("<processing_instruction>")
|
||||
Value::string("<processing_instruction>").spanned(span)
|
||||
} else if n.is_text() {
|
||||
Value::string(n.text().unwrap())
|
||||
Value::string(n.text().unwrap()).spanned(span)
|
||||
} else {
|
||||
Value::string("<unknown>")
|
||||
Value::string("<unknown>").spanned(span)
|
||||
}
|
||||
}
|
||||
|
||||
fn from_document_to_value(d: &roxmltree::Document) -> Value {
|
||||
from_node_to_value(&d.root_element())
|
||||
fn from_document_to_value(d: &roxmltree::Document, span: impl Into<Span>) -> Spanned<Value> {
|
||||
from_node_to_value(&d.root_element(), span)
|
||||
}
|
||||
|
||||
pub fn from_xml_string_to_value(s: String) -> Result<Value, Box<dyn std::error::Error>> {
|
||||
pub fn from_xml_string_to_value(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
||||
let parsed = roxmltree::Document::parse(&s)?;
|
||||
Ok(from_document_to_value(&parsed))
|
||||
Ok(from_document_to_value(&parsed, span))
|
||||
}
|
||||
|
||||
pub fn from_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
let span = args.name_span;
|
||||
Ok(out
|
||||
.map(move |a| match a {
|
||||
Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s) {
|
||||
Ok(x) => ReturnValue::Value(x),
|
||||
Err(_) => {
|
||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s, span) {
|
||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Could not parse as XML",
|
||||
"piped data failed XML parse",
|
||||
span,
|
||||
))))
|
||||
}
|
||||
)),
|
||||
},
|
||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)))),
|
||||
)),
|
||||
})
|
||||
.boxed())
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -1,64 +1,72 @@
|
|||
use crate::object::base::OF64;
|
||||
use crate::object::{Dictionary, Primitive, Value};
|
||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value) -> Value {
|
||||
fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, span: impl Into<Span>) -> Spanned<Value> {
|
||||
let span = span.into();
|
||||
|
||||
match v {
|
||||
serde_yaml::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)),
|
||||
serde_yaml::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span),
|
||||
serde_yaml::Value::Number(n) if n.is_i64() => {
|
||||
Value::Primitive(Primitive::Int(n.as_i64().unwrap()))
|
||||
Value::Primitive(Primitive::Int(n.as_i64().unwrap())).spanned(span)
|
||||
}
|
||||
serde_yaml::Value::Number(n) if n.is_f64() => {
|
||||
Value::Primitive(Primitive::Float(OF64::from(n.as_f64().unwrap())))
|
||||
Value::Primitive(Primitive::Float(OF64::from(n.as_f64().unwrap()))).spanned(span)
|
||||
}
|
||||
serde_yaml::Value::String(s) => Value::string(s),
|
||||
serde_yaml::Value::String(s) => Value::string(s).spanned(span),
|
||||
serde_yaml::Value::Sequence(a) => Value::List(
|
||||
a.iter()
|
||||
.map(|x| convert_yaml_value_to_nu_value(x))
|
||||
.map(|x| convert_yaml_value_to_nu_value(x, span))
|
||||
.collect(),
|
||||
),
|
||||
)
|
||||
.spanned(span),
|
||||
serde_yaml::Value::Mapping(t) => {
|
||||
let mut collected = Dictionary::default();
|
||||
let mut collected = SpannedDictBuilder::new(span);
|
||||
|
||||
for (k, v) in t.iter() {
|
||||
match k {
|
||||
serde_yaml::Value::String(k) => {
|
||||
collected.add(k.clone(), convert_yaml_value_to_nu_value(v));
|
||||
collected
|
||||
.insert_spanned(k.clone(), convert_yaml_value_to_nu_value(v, span));
|
||||
}
|
||||
_ => unimplemented!("Unknown key type"),
|
||||
}
|
||||
}
|
||||
Value::Object(collected)
|
||||
|
||||
collected.into_spanned_value()
|
||||
}
|
||||
serde_yaml::Value::Null => Value::Primitive(Primitive::Nothing),
|
||||
serde_yaml::Value::Null => Value::Primitive(Primitive::Nothing).spanned(span),
|
||||
x => unimplemented!("Unsupported yaml case: {:?}", x),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_yaml_string_to_value(s: String) -> serde_yaml::Result<Value> {
|
||||
pub fn from_yaml_string_to_value(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> serde_yaml::Result<Spanned<Value>> {
|
||||
let v: serde_yaml::Value = serde_yaml::from_str(&s)?;
|
||||
Ok(convert_yaml_value_to_nu_value(&v))
|
||||
Ok(convert_yaml_value_to_nu_value(&v, span))
|
||||
}
|
||||
|
||||
pub fn from_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
let span = args.name_span;
|
||||
Ok(out
|
||||
.map(move |a| match a {
|
||||
Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s) {
|
||||
Ok(x) => ReturnValue::Value(x),
|
||||
Err(_) => {
|
||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s, span) {
|
||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Could not parse as YAML",
|
||||
"piped data failed YAML parse",
|
||||
span,
|
||||
))))
|
||||
}
|
||||
)),
|
||||
},
|
||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)))),
|
||||
)),
|
||||
})
|
||||
.boxed())
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -3,22 +3,22 @@ use crate::object::Value;
|
|||
use crate::parser::Span;
|
||||
use crate::prelude::*;
|
||||
|
||||
fn get_member(path: &str, span: Span, obj: &Value) -> Option<Value> {
|
||||
fn get_member(path: &str, span: Span, obj: &Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
|
||||
let mut current = obj;
|
||||
for p in path.split(".") {
|
||||
match current.get_data_by_key(p) {
|
||||
Some(v) => current = v,
|
||||
None => {
|
||||
return Some(Value::Error(Box::new(ShellError::labeled_error(
|
||||
return Err(ShellError::labeled_error(
|
||||
"Unknown field",
|
||||
"object missing field",
|
||||
span,
|
||||
))));
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(current.copy())
|
||||
Ok(current.clone())
|
||||
}
|
||||
|
||||
pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -36,10 +36,10 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
if let Ok(amount) = amount {
|
||||
return Ok(args
|
||||
.input
|
||||
.values
|
||||
.skip(amount as u64)
|
||||
.take(1)
|
||||
.map(|v| ReturnValue::Value(v))
|
||||
.boxed());
|
||||
.from_input_stream());
|
||||
}
|
||||
|
||||
let fields: Result<Vec<(String, Span)>, _> = args
|
||||
|
@ -51,17 +51,21 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
|
||||
let stream = args
|
||||
.input
|
||||
.values
|
||||
.map(move |item| {
|
||||
let mut result = VecDeque::new();
|
||||
for field in &fields {
|
||||
match get_member(&field.0, field.1, &item) {
|
||||
Some(Value::List(l)) => {
|
||||
Ok(Spanned {
|
||||
item: Value::List(l),
|
||||
..
|
||||
}) => {
|
||||
for item in l {
|
||||
result.push_back(ReturnValue::Value(item.copy()));
|
||||
result.push_back(ReturnSuccess::value(item.clone()));
|
||||
}
|
||||
}
|
||||
Some(x) => result.push_back(ReturnValue::Value(x.copy())),
|
||||
None => {}
|
||||
Ok(x) => result.push_back(ReturnSuccess::value(x.clone())),
|
||||
Err(x) => result.push_back(Err(x)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,5 +73,5 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
})
|
||||
.flatten();
|
||||
|
||||
Ok(stream.boxed())
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -10,7 +10,8 @@ pub fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
let span = args.name_span;
|
||||
|
||||
let stream = input
|
||||
.map(move |v| match v {
|
||||
.values
|
||||
.map(move |v| match v.item {
|
||||
Value::Primitive(Primitive::String(s)) => {
|
||||
let split_result: Vec<_> = s.lines().filter(|s| s.trim() != "").collect();
|
||||
|
||||
|
@ -18,25 +19,23 @@ pub fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
|
||||
let mut result = VecDeque::new();
|
||||
for s in split_result {
|
||||
result.push_back(ReturnValue::Value(Value::Primitive(Primitive::String(
|
||||
s.into(),
|
||||
))));
|
||||
result.push_back(ReturnSuccess::value(
|
||||
Value::Primitive(Primitive::String(s.into())).spanned_unknown(),
|
||||
));
|
||||
}
|
||||
result
|
||||
}
|
||||
_ => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(ReturnValue::Value(Value::Error(Box::new(
|
||||
ShellError::maybe_labeled_error(
|
||||
result.push_back(Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
),
|
||||
))));
|
||||
)));
|
||||
result
|
||||
}
|
||||
})
|
||||
.flatten();
|
||||
|
||||
Ok(stream.boxed())
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
match obj {
|
||||
match obj.item {
|
||||
Value::Filesystem => {
|
||||
let entries = std::fs::read_dir(&full_path);
|
||||
|
||||
|
@ -44,10 +44,10 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
let mut shell_entries = VecDeque::new();
|
||||
|
||||
for entry in entries {
|
||||
let value = Value::Object(dir_entry_dict(&entry?)?);
|
||||
shell_entries.push_back(ReturnValue::Value(value))
|
||||
let value = dir_entry_dict(&entry?, args.name_span)?;
|
||||
shell_entries.push_back(ReturnSuccess::value(value))
|
||||
}
|
||||
Ok(shell_entries.boxed())
|
||||
Ok(shell_entries.to_output_stream())
|
||||
}
|
||||
_ => {
|
||||
let mut entries = VecDeque::new();
|
||||
|
@ -97,7 +97,11 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
return Err(ShellError::maybe_labeled_error(
|
||||
"Index not closed",
|
||||
format!("path missing closing ']'"),
|
||||
if args.len() > 0 { Some(args.nth(0).unwrap().span) } else { args.name_span },
|
||||
if args.len() > 0 {
|
||||
Some(args.nth(0).unwrap().span)
|
||||
} else {
|
||||
args.name_span
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -121,16 +125,19 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
}
|
||||
}
|
||||
match viewed {
|
||||
Value::List(l) => {
|
||||
Spanned {
|
||||
item: Value::List(l),
|
||||
..
|
||||
} => {
|
||||
for item in l {
|
||||
entries.push_back(ReturnValue::Value(item.copy()));
|
||||
entries.push_back(ReturnSuccess::value(item.clone()));
|
||||
}
|
||||
}
|
||||
x => {
|
||||
entries.push_back(ReturnValue::Value(x.clone()));
|
||||
entries.push_back(ReturnSuccess::value(x.clone()));
|
||||
}
|
||||
}
|
||||
Ok(entries.boxed())
|
||||
Ok(entries.to_output_stream())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
386
src/commands/macros.rs
Normal file
386
src/commands/macros.rs
Normal file
|
@ -0,0 +1,386 @@
|
|||
#[macro_export]
|
||||
macro_rules! command {
|
||||
(
|
||||
Named { $export:tt $args:ident $body:block }
|
||||
Positional { $($number:tt)* }
|
||||
Rest {}
|
||||
CommandConfig {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
rest_positional: $rest_positional:tt,
|
||||
named: {
|
||||
$(
|
||||
($named_param:tt : $named_type:tt)
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
Function {
|
||||
$( ( $param_name:tt : $param_type:tt ) )*
|
||||
}
|
||||
|
||||
Extract {
|
||||
$($extract:tt)*
|
||||
}
|
||||
) => {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct $export;
|
||||
|
||||
impl Command for $export {
|
||||
fn run(&self, $args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
fn command($args: CommandArgs, ( $($param_name),*, ): ( $($param_type),*, )) -> Result<OutputStream, ShellError> {
|
||||
let output = $body;
|
||||
|
||||
Ok(output.boxed().to_output_stream())
|
||||
}
|
||||
|
||||
let tuple = ( $($extract),*, );
|
||||
command( $args, tuple )
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
stringify!($config_name)
|
||||
}
|
||||
|
||||
fn config(&self) -> $crate::parser::registry::CommandConfig {
|
||||
$crate::parser::registry::CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![$($mandatory_positional)*],
|
||||
rest_positional: false,
|
||||
is_filter: false,
|
||||
is_sink: false,
|
||||
|
||||
named: {
|
||||
use $crate::parser::registry::NamedType;
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut named: indexmap::IndexMap<String, NamedType> = indexmap::IndexMap::new();
|
||||
|
||||
$(
|
||||
named.insert(stringify!($named_param).to_string(), NamedType::$named_type);
|
||||
)*
|
||||
|
||||
named
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// switch
|
||||
(
|
||||
Named { $export:tt $args:ident $body:block }
|
||||
Positional { $($positional_count:tt)* }
|
||||
Rest { , -- $param_name:ident : Switch $($rest:tt)* }
|
||||
CommandConfig {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
rest_positional: $rest_positional:tt,
|
||||
named: {
|
||||
$($config_named:tt)*
|
||||
}
|
||||
}
|
||||
Function {
|
||||
$($function:tt)*
|
||||
}
|
||||
Extract {
|
||||
$($extract:tt)*
|
||||
}
|
||||
) => {
|
||||
command!(
|
||||
Named { $export $args $body }
|
||||
Positional { $($positional_count)* + 1 }
|
||||
Rest { $($rest)* }
|
||||
CommandConfig {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![ $($mandatory_positional)* ],
|
||||
optional_positional: vec![ $($optional_positional)* ],
|
||||
rest_positional: $rest_positional,
|
||||
named: {
|
||||
$($config_named)*
|
||||
($param_name : Switch)
|
||||
}
|
||||
}
|
||||
|
||||
Function {
|
||||
$($function)* ($param_name : Switch)
|
||||
}
|
||||
|
||||
Extract {
|
||||
($($extract)* {
|
||||
use std::convert::TryInto;
|
||||
|
||||
$args.get(stringify!($param_name)).clone().try_into()?
|
||||
})
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// mandatory named arguments
|
||||
(
|
||||
Named { $export:tt $args:ident $body:block }
|
||||
Positional { $($positional_count:tt)* }
|
||||
Rest { , -- $param_name:ident : $param_kind:tt $($rest:tt)* }
|
||||
CommandConfig {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
rest_positional: $rest_positional:tt,
|
||||
named: {
|
||||
$($config_named:tt)*
|
||||
}
|
||||
}
|
||||
Function {
|
||||
$($function:tt)*
|
||||
}
|
||||
Extract {
|
||||
$($extract:tt)*
|
||||
}
|
||||
) => {
|
||||
command!(
|
||||
Named { $export $args $body }
|
||||
Positional { $($positional_count)* + 1 }
|
||||
Rest { $($rest)* }
|
||||
CommandConfig {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![ $($mandatory_positional)* ],
|
||||
optional_positional: vec![ $($optional_positional)* ],
|
||||
rest_positional: $rest_positional,
|
||||
named: {
|
||||
$($config_named)*
|
||||
($param_name : Mandatory(NamedValue::Single))
|
||||
}
|
||||
}
|
||||
|
||||
Function {
|
||||
$($function)* ($param_name : $param_kind)
|
||||
}
|
||||
|
||||
Extract {
|
||||
($($extract)* {
|
||||
use std::convert::TryInto;
|
||||
|
||||
$args.get(stringify!($param_name)).clone().try_into()?
|
||||
})
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// optional named arguments
|
||||
(
|
||||
Named { $export:tt $args:ident $body:block }
|
||||
Positional { $($positional_count:tt)* }
|
||||
Rest { , -- $param_name:ident ? : $param_kind:tt $($rest:tt)* }
|
||||
CommandConfig {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
rest_positional: $rest_positional:tt,
|
||||
named: {
|
||||
$($config_named:tt)*
|
||||
}
|
||||
}
|
||||
Function {
|
||||
$($function:tt)*
|
||||
}
|
||||
Extract {
|
||||
$($extract:tt)*
|
||||
}
|
||||
) => {
|
||||
command!(
|
||||
Named { $export $args $body }
|
||||
Positional { $($positional_count)* + 1 }
|
||||
Rest { $($rest)* }
|
||||
CommandConfig {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![ $($mandatory_positional)* ],
|
||||
optional_positional: vec![ $($optional_positional)* ],
|
||||
rest_positional: $rest_positional,
|
||||
named: {
|
||||
$($config_named)*
|
||||
($param_name : Optional(NamedValue::Single))
|
||||
}
|
||||
}
|
||||
|
||||
Function {
|
||||
$($function)* ($param_name : $param_kind)
|
||||
}
|
||||
|
||||
Extract {
|
||||
($($extract)* {
|
||||
use std::convert::TryInto;
|
||||
|
||||
$args.get(stringify!($param_name)).clone().try_into()?
|
||||
})
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// mandatory positional block
|
||||
(
|
||||
Named { $export:ident $args:ident $body:block }
|
||||
Positional { $($positional_count:tt)* }
|
||||
Rest { , $param_name:ident : Block $($rest:tt)* }
|
||||
CommandConfig {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
rest_positional: $rest_positional:tt,
|
||||
named: {
|
||||
$($config_named:tt)*
|
||||
}
|
||||
}
|
||||
|
||||
Function {
|
||||
$($function:tt)*
|
||||
}
|
||||
|
||||
Extract {
|
||||
$($extract:tt)*
|
||||
}
|
||||
|
||||
) => {
|
||||
command!(
|
||||
Named { $export $args $body }
|
||||
Positional { $($positional_count)* + 1 }
|
||||
Rest { $($rest)* }
|
||||
CommandConfig {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![ $($mandatory_positional)* $crate::parser::registry::PositionalType::mandatory_block(
|
||||
stringify!($param_name)
|
||||
), ],
|
||||
optional_positional: vec![ $($optional_positional)* ],
|
||||
rest_positional: $rest_positional,
|
||||
named: {
|
||||
$($config_named)*
|
||||
}
|
||||
}
|
||||
|
||||
Function {
|
||||
$($function)* ($param_name : Block)
|
||||
}
|
||||
|
||||
Extract {
|
||||
$($extract:tt)* {
|
||||
use $crate::object::types::ExtractType;
|
||||
let value = $args.expect_nth($($positional_count)*)?;
|
||||
Block::extract(value)?
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// mandatory positional argument
|
||||
(
|
||||
Named { $export:ident $args:ident $body:block }
|
||||
Positional { $($positional_count:tt)* }
|
||||
Rest { , $param_name:ident : $param_kind:tt $($rest:tt)* }
|
||||
CommandConfig {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
rest_positional: $rest_positional:tt,
|
||||
named: {
|
||||
$($config_named:tt)*
|
||||
}
|
||||
}
|
||||
|
||||
Function {
|
||||
$($function:tt)*
|
||||
}
|
||||
|
||||
Extract {
|
||||
$($extract:tt)*
|
||||
}
|
||||
|
||||
) => {
|
||||
command!(
|
||||
Named { $export $args $body }
|
||||
Positional { $($positional_count)* + 1 }
|
||||
Rest { $($rest)* }
|
||||
CommandConfig {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![ $($mandatory_positional)* $crate::parser::registry::PositionalType::mandatory(
|
||||
stringify!($param_name)
|
||||
), ],
|
||||
optional_positional: vec![ $($optional_positional)* ],
|
||||
rest_positional: $rest_positional,
|
||||
named: {
|
||||
$($config_named)*
|
||||
}
|
||||
}
|
||||
|
||||
Function {
|
||||
$($function)* ($param_name : $param_kind)
|
||||
}
|
||||
|
||||
Extract {
|
||||
$($extract:tt)* {
|
||||
use $crate::object::types::ExtractType;
|
||||
let value = $args.expect_nth($($positional_count)*)?;
|
||||
// let value = $param_kind.check(value)?;
|
||||
$param_kind::extract(value)?
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
($export:ident as $config_name:tt ( $args:ident $($command_rest:tt)* ) $body:block) => {
|
||||
command!(
|
||||
Named { $export $args $body }
|
||||
Positional { 0 }
|
||||
Rest { $($command_rest)* }
|
||||
CommandConfig {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![],
|
||||
optional_positional: vec![],
|
||||
rest_positional: false,
|
||||
named: {}
|
||||
}
|
||||
|
||||
Function {
|
||||
}
|
||||
|
||||
Extract {
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// ($export:ident as $name:tt ( $args:ident, -- $param:ident : $kind:ident ) $body:block) => {
|
||||
// #[allow(non_camel_case_types)]
|
||||
// pub struct $export;
|
||||
|
||||
// impl Command for $export {
|
||||
// fn run(&self, $args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
// fn command($args: CommandArgs, $param: $kind) -> Result<OutputStream, ShellError> {
|
||||
// $body
|
||||
// }
|
||||
|
||||
// use std::convert::TryInto;
|
||||
|
||||
// let param = $args.get(stringify!($param)).try_into()?;
|
||||
// command($args, param)
|
||||
// }
|
||||
|
||||
// fn name(&self) -> &str {
|
||||
// stringify!($name)
|
||||
// }
|
||||
|
||||
// fn config(&self) -> CommandConfig {
|
||||
// let mut named: IndexMap<String, NamedType> = IndexMap::new();
|
||||
// named.insert(stringify!($param).to_string(), NamedType::$kind);
|
||||
|
||||
// CommandConfig {
|
||||
// name: self.name().to_string(),
|
||||
// mandatory_positional: vec![],
|
||||
// optional_positional: vec![],
|
||||
// rest_positional: false,
|
||||
// named,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
}
|
|
@ -1,38 +1,80 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::{Primitive, Value};
|
||||
use crate::object::{Primitive, Switch, Value};
|
||||
use crate::parser::parse::span::Span;
|
||||
use crate::parser::registry::{CommandConfig, NamedType};
|
||||
use crate::prelude::*;
|
||||
use indexmap::IndexMap;
|
||||
use mime::Mime;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub struct Open;
|
||||
command! {
|
||||
Open as open(args, --raw: Switch) {
|
||||
let span = args.name_span;
|
||||
|
||||
impl Command for Open {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
open(args)
|
||||
}
|
||||
fn name(&self) -> &str {
|
||||
"open"
|
||||
}
|
||||
let cwd = args
|
||||
.env
|
||||
.lock()
|
||||
.unwrap()
|
||||
.front()
|
||||
.unwrap()
|
||||
.path()
|
||||
.to_path_buf();
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
let mut named: IndexMap<String, NamedType> = IndexMap::new();
|
||||
named.insert("raw".to_string(), NamedType::Switch);
|
||||
let full_path = PathBuf::from(cwd);
|
||||
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
mandatory_positional: vec![],
|
||||
optional_positional: vec![],
|
||||
rest_positional: false,
|
||||
named,
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
can_load: vec![],
|
||||
can_save: vec![],
|
||||
let (file_extension, contents, contents_span) = match &args.expect_nth(0)?.item {
|
||||
Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?,
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected string value for filename",
|
||||
"expected filename",
|
||||
args.expect_nth(0)?.span,
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
|
||||
let file_extension = if raw.is_present() {
|
||||
None
|
||||
} else if args.has("json") {
|
||||
Some("json".to_string())
|
||||
} else if args.has("xml") {
|
||||
Some("xml".to_string())
|
||||
} else if args.has("ini") {
|
||||
Some("ini".to_string())
|
||||
} else if args.has("yaml") {
|
||||
Some("yaml".to_string())
|
||||
} else if args.has("toml") {
|
||||
Some("toml".to_string())
|
||||
} else {
|
||||
if let Some(ref named_args) = args.args.named {
|
||||
for named in named_args.iter() {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Unknown flag for open",
|
||||
"unknown flag",
|
||||
named.1.span.clone(),
|
||||
));
|
||||
}
|
||||
file_extension
|
||||
} else {
|
||||
file_extension
|
||||
}
|
||||
};
|
||||
|
||||
match contents {
|
||||
Value::Primitive(Primitive::String(string)) =>
|
||||
stream.push_back(ReturnSuccess::value(parse_as_value(
|
||||
file_extension,
|
||||
string,
|
||||
contents_span,
|
||||
span,
|
||||
)?)
|
||||
),
|
||||
|
||||
other => stream.push_back(ReturnSuccess::value(other.spanned(span))),
|
||||
};
|
||||
|
||||
stream
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +82,7 @@ pub fn fetch(
|
|||
cwd: &PathBuf,
|
||||
location: &str,
|
||||
span: Span,
|
||||
) -> Result<(Option<String>, Value), ShellError> {
|
||||
) -> Result<(Option<String>, Value, Span), ShellError> {
|
||||
let mut cwd = cwd.clone();
|
||||
if location.starts_with("http:") || location.starts_with("https:") {
|
||||
let response = reqwest::get(location);
|
||||
|
@ -71,7 +113,7 @@ pub fn fetch(
|
|||
None => path_extension,
|
||||
};
|
||||
|
||||
Ok((extension, Value::string(s)))
|
||||
Ok((extension, Value::string(s), span))
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
|
@ -97,8 +139,9 @@ pub fn fetch(
|
|||
cwd.extension()
|
||||
.map(|name| name.to_string_lossy().to_string()),
|
||||
Value::string(s),
|
||||
span,
|
||||
)),
|
||||
Err(_) => Ok((None, Value::Binary(bytes))),
|
||||
Err(_) => Ok((None, Value::Binary(bytes), span)),
|
||||
},
|
||||
Err(_) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
|
@ -114,128 +157,76 @@ pub fn fetch(
|
|||
pub fn parse_as_value(
|
||||
extension: Option<String>,
|
||||
contents: String,
|
||||
contents_span: Span,
|
||||
name_span: Option<Span>,
|
||||
) -> Result<Value, ShellError> {
|
||||
) -> Result<Spanned<Value>, ShellError> {
|
||||
match extension {
|
||||
Some(x) if x == "toml" => crate::commands::from_toml::from_toml_string_to_value(contents)
|
||||
Some(x) if x == "toml" => {
|
||||
crate::commands::from_toml::from_toml_string_to_value(contents, contents_span)
|
||||
.map(|c| c.spanned(contents_span))
|
||||
.map_err(move |_| {
|
||||
ShellError::maybe_labeled_error(
|
||||
"Could not open as TOML",
|
||||
"could not open as TOML",
|
||||
name_span,
|
||||
)
|
||||
}),
|
||||
Some(x) if x == "json" => crate::commands::from_json::from_json_string_to_value(contents)
|
||||
})
|
||||
}
|
||||
Some(x) if x == "json" => {
|
||||
crate::commands::from_json::from_json_string_to_value(contents, contents_span)
|
||||
.map(|c| c.spanned(contents_span))
|
||||
.map_err(move |_| {
|
||||
ShellError::maybe_labeled_error(
|
||||
"Could not open as JSON",
|
||||
"could not open as JSON",
|
||||
name_span,
|
||||
)
|
||||
}),
|
||||
Some(x) if x == "ini" => crate::commands::from_ini::from_ini_string_to_value(contents)
|
||||
})
|
||||
}
|
||||
Some(x) if x == "ini" => {
|
||||
crate::commands::from_ini::from_ini_string_to_value(contents, contents_span)
|
||||
.map(|c| c.spanned(contents_span))
|
||||
.map_err(move |_| {
|
||||
ShellError::maybe_labeled_error(
|
||||
"Could not open as INI",
|
||||
"could not open as INI",
|
||||
name_span,
|
||||
)
|
||||
}),
|
||||
Some(x) if x == "xml" => crate::commands::from_xml::from_xml_string_to_value(contents)
|
||||
.map_err(move |_| {
|
||||
})
|
||||
}
|
||||
Some(x) if x == "xml" => {
|
||||
crate::commands::from_xml::from_xml_string_to_value(contents, contents_span).map_err(
|
||||
move |_| {
|
||||
ShellError::maybe_labeled_error(
|
||||
"Could not open as XML",
|
||||
"could not open as XML",
|
||||
name_span,
|
||||
)
|
||||
}),
|
||||
Some(x) if x == "yml" => crate::commands::from_yaml::from_yaml_string_to_value(contents)
|
||||
.map_err(move |_| {
|
||||
},
|
||||
)
|
||||
}
|
||||
Some(x) if x == "yml" => {
|
||||
crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_span).map_err(
|
||||
move |_| {
|
||||
ShellError::maybe_labeled_error(
|
||||
"Could not open as YAML",
|
||||
"could not open as YAML",
|
||||
name_span,
|
||||
)
|
||||
}),
|
||||
Some(x) if x == "yaml" => crate::commands::from_yaml::from_yaml_string_to_value(contents)
|
||||
.map_err(move |_| {
|
||||
},
|
||||
)
|
||||
}
|
||||
Some(x) if x == "yaml" => {
|
||||
crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_span).map_err(
|
||||
move |_| {
|
||||
ShellError::maybe_labeled_error(
|
||||
"Could not open as YAML",
|
||||
"could not open as YAML",
|
||||
name_span,
|
||||
)
|
||||
}),
|
||||
_ => Ok(Value::string(contents)),
|
||||
},
|
||||
)
|
||||
}
|
||||
_ => Ok(Value::string(contents).spanned(contents_span)),
|
||||
}
|
||||
}
|
||||
|
||||
fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Open requires a path or url",
|
||||
"needs path or url",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let span = args.name_span;
|
||||
|
||||
let cwd = args
|
||||
.env
|
||||
.lock()
|
||||
.unwrap()
|
||||
.front()
|
||||
.unwrap()
|
||||
.path()
|
||||
.to_path_buf();
|
||||
let full_path = PathBuf::from(cwd);
|
||||
|
||||
let (file_extension, contents) = match &args.expect_nth(0)?.item {
|
||||
Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?,
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected string value for filename",
|
||||
"expected filename",
|
||||
args.expect_nth(0)?.span,
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
|
||||
let file_extension = if args.has("raw") {
|
||||
None
|
||||
} else if args.has("json") {
|
||||
Some("json".to_string())
|
||||
} else if args.has("xml") {
|
||||
Some("xml".to_string())
|
||||
} else if args.has("ini") {
|
||||
Some("ini".to_string())
|
||||
} else if args.has("yaml") {
|
||||
Some("yaml".to_string())
|
||||
} else if args.has("toml") {
|
||||
Some("toml".to_string())
|
||||
} else {
|
||||
if let Some(ref named_args) = args.args.named {
|
||||
for named in named_args.iter() {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Unknown flag for open",
|
||||
"unknown flag",
|
||||
named.1.span.clone(),
|
||||
));
|
||||
}
|
||||
file_extension
|
||||
} else {
|
||||
file_extension
|
||||
}
|
||||
};
|
||||
|
||||
match contents {
|
||||
Value::Primitive(Primitive::String(x)) => {
|
||||
stream.push_back(ReturnValue::Value(parse_as_value(file_extension, x, span)?));
|
||||
}
|
||||
x => stream.push_back(ReturnValue::Value(x)),
|
||||
}
|
||||
|
||||
Ok(stream.boxed())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::base::select_fields;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn pick(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -14,12 +13,11 @@ pub fn pick(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
|
||||
let fields: Result<Vec<String>, _> = args.positional_iter().map(|a| a.as_string()).collect();
|
||||
let fields = fields?;
|
||||
let input = args.input;
|
||||
|
||||
let objects = args
|
||||
.input
|
||||
.map(move |item| Value::Object(select_fields(&item, &fields)))
|
||||
.map(|item| ReturnValue::Value(item));
|
||||
let objects = input
|
||||
.values
|
||||
.map(move |value| select_fields(&value.item, &fields, value.span));
|
||||
|
||||
let stream = Pin::new(Box::new(objects));
|
||||
Ok(stream)
|
||||
Ok(objects.from_input_stream())
|
||||
}
|
||||
|
|
|
@ -43,21 +43,46 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
|||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||
|
||||
let _reader = BufReader::new(stdout);
|
||||
let mut reader = BufReader::new(stdout);
|
||||
|
||||
let request = JsonRpc::new("begin_filter", args.args);
|
||||
let request_raw = serde_json::to_string(&request).unwrap();
|
||||
stdin.write(format!("{}\n", request_raw).as_bytes())?;
|
||||
let mut input = String::new();
|
||||
match reader.read_line(&mut input) {
|
||||
Ok(_) => {
|
||||
let response = serde_json::from_str::<NuResult>(&input);
|
||||
match response {
|
||||
Ok(NuResult::response { params }) => match params {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
return Err(ShellError::string(format!(
|
||||
"Error while processing input: {:?} {}",
|
||||
e, input
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut eos = VecDeque::new();
|
||||
eos.push_back(Value::Primitive(Primitive::EndOfStream));
|
||||
let mut eos: VecDeque<Spanned<Value>> = VecDeque::new();
|
||||
eos.push_back(Value::Primitive(Primitive::EndOfStream).spanned_unknown());
|
||||
|
||||
let stream = args
|
||||
.input
|
||||
.values
|
||||
.chain(eos)
|
||||
.map(move |v| match v {
|
||||
Value::Primitive(Primitive::EndOfStream) => {
|
||||
Spanned {
|
||||
item: Value::Primitive(Primitive::EndOfStream),
|
||||
..
|
||||
} => {
|
||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||
|
||||
|
@ -87,17 +112,15 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
|||
Ok(params) => params,
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(ReturnValue::Value(Value::Error(Box::new(e))));
|
||||
result.push_back(ReturnValue::Err(e));
|
||||
result
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(ReturnValue::Value(Value::Error(Box::new(
|
||||
ShellError::string(format!(
|
||||
result.push_back(Err(ShellError::string(format!(
|
||||
"Error while processing input: {:?} {}",
|
||||
e, input
|
||||
)),
|
||||
))));
|
||||
result
|
||||
}
|
||||
|
@ -105,8 +128,9 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
|||
}
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(ReturnValue::Value(Value::Error(Box::new(
|
||||
ShellError::string(format!("Error while processing input: {:?}", e)),
|
||||
result.push_back(Err(ShellError::string(format!(
|
||||
"Error while processing input: {:?}",
|
||||
e
|
||||
))));
|
||||
result
|
||||
}
|
||||
|
@ -115,7 +139,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
|||
})
|
||||
.flatten();
|
||||
|
||||
Ok(stream.boxed())
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
||||
pub fn sink_plugin(path: String, args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::process::process_dict;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
use sysinfo::{RefreshKind, SystemExt};
|
||||
|
||||
pub fn ps(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn ps(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut system = sysinfo::System::new_with_specifics(RefreshKind::new().with_processes());
|
||||
system.refresh_processes();
|
||||
let list = system.get_process_list();
|
||||
|
||||
let list = list
|
||||
.into_iter()
|
||||
.map(|(_, process)| ReturnValue::Value(Value::Object(process_dict(process))))
|
||||
.map(|(_, process)| process_dict(process, args.name_span))
|
||||
.collect::<VecDeque<_>>();
|
||||
|
||||
Ok(list.boxed())
|
||||
Ok(list.from_input_stream())
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::base::reject_fields;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.name_span;
|
||||
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Reject requires fields",
|
||||
|
@ -15,10 +16,11 @@ pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
let fields: Result<Vec<String>, _> = args.positional_iter().map(|a| a.as_string()).collect();
|
||||
let fields = fields?;
|
||||
|
||||
let stream = args
|
||||
.input
|
||||
.map(move |item| Value::Object(reject_fields(&item, &fields)))
|
||||
.map(|item| ReturnValue::Value(item));
|
||||
let stream = args.input.values.map(move |item| {
|
||||
reject_fields(&item, &fields, item.span)
|
||||
.into_spanned_value()
|
||||
.spanned(name_span)
|
||||
});
|
||||
|
||||
Ok(stream.boxed())
|
||||
Ok(stream.from_input_stream())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::dict::Dictionary;
|
||||
use crate::object::Value;
|
||||
use crate::object::{SpannedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
|
@ -24,20 +23,20 @@ pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
|
||||
let mut contents = String::new();
|
||||
|
||||
let mut list = VecDeque::new();
|
||||
for name in args.positional_iter() {
|
||||
let name = name.as_string()?;
|
||||
let mut list: VecDeque<ReturnValue> = VecDeque::new();
|
||||
for spanned_name in args.positional_iter() {
|
||||
let name = spanned_name.as_string()?;
|
||||
let path = cwd.join(&name);
|
||||
let mut file = File::open(path)?;
|
||||
file.read_to_string(&mut contents)?;
|
||||
list.push_back(count(&name, &contents));
|
||||
list.push_back(count(&name, &contents, spanned_name).into());
|
||||
contents.clear();
|
||||
}
|
||||
|
||||
Ok(list.boxed())
|
||||
Ok(list.to_output_stream())
|
||||
}
|
||||
|
||||
fn count(name: &str, contents: &str) -> ReturnValue {
|
||||
fn count(name: &str, contents: &str, span: impl Into<Span>) -> Spanned<Value> {
|
||||
let mut lines: i64 = 0;
|
||||
let mut words: i64 = 0;
|
||||
let mut chars: i64 = 0;
|
||||
|
@ -62,12 +61,12 @@ fn count(name: &str, contents: &str) -> ReturnValue {
|
|||
}
|
||||
}
|
||||
|
||||
let mut dict = Dictionary::default();
|
||||
dict.add("name", Value::string(name));
|
||||
dict.add("lines", Value::int(lines));
|
||||
dict.add("words", Value::int(words));
|
||||
dict.add("chars", Value::int(chars));
|
||||
dict.add("max length", Value::int(bytes));
|
||||
let mut dict = SpannedDictBuilder::new(span);
|
||||
dict.insert("name", Value::string(name));
|
||||
dict.insert("lines", Value::int(lines));
|
||||
dict.insert("words", Value::int(words));
|
||||
dict.insert("chars", Value::int(chars));
|
||||
dict.insert("max length", Value::int(bytes));
|
||||
|
||||
ReturnValue::Value(Value::Object(dict))
|
||||
dict.into_spanned_value()
|
||||
}
|
||||
|
|
|
@ -16,14 +16,11 @@ impl Command for SkipWhile {
|
|||
fn config(&self) -> CommandConfig {
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
mandatory_positional: vec![PositionalType::Block("condition".to_string())],
|
||||
optional_positional: vec![],
|
||||
positional: vec![PositionalType::mandatory_block("condition")],
|
||||
rest_positional: false,
|
||||
named: indexmap::IndexMap::new(),
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
can_load: vec![],
|
||||
can_save: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +37,7 @@ pub fn skip_while(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
let block = args.nth(0).unwrap().as_block()?;
|
||||
let input = args.input;
|
||||
|
||||
let objects = input.skip_while(move |item| {
|
||||
let objects = input.values.skip_while(move |item| {
|
||||
let result = block.invoke(&item);
|
||||
|
||||
let return_value = match result {
|
||||
|
@ -51,5 +48,5 @@ pub fn skip_while(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
futures::future::ready(return_value)
|
||||
});
|
||||
|
||||
Ok(objects.map(|x| ReturnValue::Value(x)).boxed())
|
||||
Ok(objects.from_input_stream())
|
||||
}
|
||||
|
|
|
@ -5,21 +5,18 @@ pub fn sort_by(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
let fields: Result<Vec<_>, _> = args.positional_iter().map(|a| a.as_string()).collect();
|
||||
let fields = fields?;
|
||||
|
||||
let output = args.input.collect::<Vec<_>>();
|
||||
let output = args.input.values.collect::<Vec<_>>();
|
||||
|
||||
let output = output.map(move |mut vec| {
|
||||
vec.sort_by_key(|item| {
|
||||
fields
|
||||
.iter()
|
||||
.map(|f| item.get_data_by_key(f).map(|i| i.copy()))
|
||||
.collect::<Vec<Option<Value>>>()
|
||||
.map(|f| item.get_data_by_key(f).map(|i| i.clone()))
|
||||
.collect::<Vec<Option<Spanned<Value>>>>()
|
||||
});
|
||||
|
||||
vec.into_iter()
|
||||
.map(|v| ReturnValue::Value(v.copy()))
|
||||
.collect::<VecDeque<_>>()
|
||||
.boxed()
|
||||
vec.into_iter().collect::<VecDeque<_>>()
|
||||
});
|
||||
|
||||
Ok(output.flatten_stream().boxed())
|
||||
Ok(output.flatten_stream().from_input_stream())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::{Primitive, Value};
|
||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
use log::trace;
|
||||
|
||||
|
@ -20,7 +20,8 @@ pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
let input = args.input;
|
||||
|
||||
Ok(input
|
||||
.map(move |v| match v {
|
||||
.values
|
||||
.map(move |v| match v.item {
|
||||
Value::Primitive(Primitive::String(s)) => {
|
||||
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n");
|
||||
trace!("splitting with {:?}", splitter);
|
||||
|
@ -35,36 +36,34 @@ pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
gen_columns.push(format!("Column{}", i + 1));
|
||||
}
|
||||
|
||||
let mut dict = crate::object::Dictionary::default();
|
||||
let mut dict = SpannedDictBuilder::new(v.span);
|
||||
for (&k, v) in split_result.iter().zip(gen_columns.iter()) {
|
||||
dict.add(v.clone(), Value::Primitive(Primitive::String(k.into())));
|
||||
dict.insert(v.clone(), Primitive::String(k.into()));
|
||||
}
|
||||
ReturnValue::Value(Value::Object(dict))
|
||||
|
||||
ReturnSuccess::value(dict.into_spanned_value())
|
||||
} else if split_result.len() == (positional.len() - 1) {
|
||||
let mut dict = crate::object::Dictionary::default();
|
||||
let mut dict = SpannedDictBuilder::new(v.span);
|
||||
for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) {
|
||||
dict.add(
|
||||
dict.insert(
|
||||
v.as_string().unwrap(),
|
||||
Value::Primitive(Primitive::String(k.into())),
|
||||
);
|
||||
}
|
||||
ReturnValue::Value(Value::Object(dict))
|
||||
ReturnSuccess::value(dict.into_spanned_value())
|
||||
} else {
|
||||
let mut dict = crate::object::Dictionary::default();
|
||||
let mut dict = SpannedDictBuilder::new(v.span);
|
||||
for k in positional.iter().skip(1) {
|
||||
dict.add(
|
||||
k.as_string().unwrap().trim(),
|
||||
Value::Primitive(Primitive::String("".into())),
|
||||
);
|
||||
dict.insert(k.as_string().unwrap().trim(), Primitive::String("".into()));
|
||||
}
|
||||
ReturnValue::Value(Value::Object(dict))
|
||||
ReturnSuccess::value(dict.into_spanned_value())
|
||||
}
|
||||
}
|
||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)))),
|
||||
)),
|
||||
})
|
||||
.boxed())
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
let input = args.input;
|
||||
|
||||
let stream = input
|
||||
.map(move |v| match v {
|
||||
.values
|
||||
.map(move |v| match v.item {
|
||||
Value::Primitive(Primitive::String(s)) => {
|
||||
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n");
|
||||
trace!("splitting with {:?}", splitter);
|
||||
|
@ -31,25 +32,23 @@ pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
|
||||
let mut result = VecDeque::new();
|
||||
for s in split_result {
|
||||
result.push_back(ReturnValue::Value(Value::Primitive(Primitive::String(
|
||||
s.into(),
|
||||
))));
|
||||
result.push_back(ReturnSuccess::value(
|
||||
Value::Primitive(Primitive::String(s.into())).spanned(v.span),
|
||||
));
|
||||
}
|
||||
result
|
||||
}
|
||||
_ => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(ReturnValue::Value(Value::Error(Box::new(
|
||||
ShellError::maybe_labeled_error(
|
||||
result.push_back(Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
),
|
||||
))));
|
||||
)));
|
||||
result
|
||||
}
|
||||
})
|
||||
.flatten();
|
||||
|
||||
Ok(stream.boxed())
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -1,95 +1,52 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::base::OF64;
|
||||
use crate::object::Dictionary;
|
||||
use crate::object::SpannedDictBuilder;
|
||||
use crate::object::{Primitive, Value};
|
||||
use crate::prelude::*;
|
||||
use sys_info::*;
|
||||
use sysinfo::{ComponentExt, DiskExt, NetworkExt, RefreshKind, SystemExt};
|
||||
|
||||
pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut idx = indexmap::IndexMap::new();
|
||||
pub fn sysinfo(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut idx = SpannedDictBuilder::new(args.name_span);
|
||||
|
||||
if let (Ok(name), Ok(version)) = (os_type(), os_release()) {
|
||||
let mut os_idx = indexmap::IndexMap::new();
|
||||
os_idx.insert(
|
||||
"name".to_string(),
|
||||
Value::Primitive(Primitive::String(name)),
|
||||
);
|
||||
os_idx.insert(
|
||||
"version".to_string(),
|
||||
Value::Primitive(Primitive::String(version)),
|
||||
);
|
||||
let mut os_idx = SpannedDictBuilder::new(args.name_span);
|
||||
os_idx.insert("name", Primitive::String(name));
|
||||
os_idx.insert("version", Primitive::String(version));
|
||||
|
||||
idx.insert("os".to_string(), Value::Object(Dictionary::from(os_idx)));
|
||||
idx.insert_spanned("os", os_idx.into_spanned_value());
|
||||
}
|
||||
|
||||
if let (Ok(num_cpu), Ok(cpu_speed)) = (cpu_num(), cpu_speed()) {
|
||||
let mut cpu_idx = indexmap::IndexMap::new();
|
||||
cpu_idx.insert(
|
||||
"num".to_string(),
|
||||
Value::Primitive(Primitive::Int(num_cpu as i64)),
|
||||
);
|
||||
cpu_idx.insert(
|
||||
"speed".to_string(),
|
||||
Value::Primitive(Primitive::Int(cpu_speed as i64)),
|
||||
);
|
||||
let mut cpu_idx = SpannedDictBuilder::new(args.name_span);
|
||||
cpu_idx.insert("num", Primitive::Int(num_cpu as i64));
|
||||
cpu_idx.insert("speed", Primitive::Int(cpu_speed as i64));
|
||||
|
||||
idx.insert("cpu".to_string(), Value::Object(Dictionary::from(cpu_idx)));
|
||||
idx.insert_spanned("cpu", cpu_idx);
|
||||
}
|
||||
|
||||
if let Ok(x) = loadavg() {
|
||||
let mut load_idx = indexmap::IndexMap::new();
|
||||
load_idx.insert(
|
||||
"1min".to_string(),
|
||||
Value::Primitive(Primitive::Float(OF64::from(x.one))),
|
||||
);
|
||||
load_idx.insert(
|
||||
"5min".to_string(),
|
||||
Value::Primitive(Primitive::Float(OF64::from(x.five))),
|
||||
);
|
||||
load_idx.insert(
|
||||
"15min".to_string(),
|
||||
Value::Primitive(Primitive::Float(OF64::from(x.fifteen))),
|
||||
);
|
||||
let mut load_idx = SpannedDictBuilder::new(args.name_span);
|
||||
|
||||
idx.insert(
|
||||
"load avg".to_string(),
|
||||
Value::Object(Dictionary::from(load_idx)),
|
||||
);
|
||||
load_idx.insert("1min", Primitive::Float(OF64::from(x.one)));
|
||||
load_idx.insert("5min", Primitive::Float(OF64::from(x.five)));
|
||||
load_idx.insert("15min", Primitive::Float(OF64::from(x.fifteen)));
|
||||
|
||||
idx.insert_spanned("load avg", load_idx);
|
||||
}
|
||||
|
||||
if let Ok(x) = mem_info() {
|
||||
let mut mem_idx = indexmap::IndexMap::new();
|
||||
mem_idx.insert(
|
||||
"total".to_string(),
|
||||
Value::Primitive(Primitive::Bytes(x.total as u64 * 1024)),
|
||||
);
|
||||
mem_idx.insert(
|
||||
"free".to_string(),
|
||||
Value::Primitive(Primitive::Bytes(x.free as u64 * 1024)),
|
||||
);
|
||||
mem_idx.insert(
|
||||
"avail".to_string(),
|
||||
Value::Primitive(Primitive::Bytes(x.avail as u64 * 1024)),
|
||||
);
|
||||
mem_idx.insert(
|
||||
"buffers".to_string(),
|
||||
Value::Primitive(Primitive::Bytes(x.buffers as u64 * 1024)),
|
||||
);
|
||||
mem_idx.insert(
|
||||
"cached".to_string(),
|
||||
Value::Primitive(Primitive::Bytes(x.cached as u64 * 1024)),
|
||||
);
|
||||
mem_idx.insert(
|
||||
"swap total".to_string(),
|
||||
Value::Primitive(Primitive::Bytes(x.swap_total as u64 * 1024)),
|
||||
);
|
||||
mem_idx.insert(
|
||||
"swap free".to_string(),
|
||||
Value::Primitive(Primitive::Bytes(x.swap_free as u64 * 1024)),
|
||||
);
|
||||
let mut mem_idx = SpannedDictBuilder::new(args.name_span);
|
||||
|
||||
idx.insert("mem".to_string(), Value::Object(Dictionary::from(mem_idx)));
|
||||
mem_idx.insert("total", Primitive::Bytes(x.total as u64 * 1024));
|
||||
mem_idx.insert("free", Primitive::Bytes(x.free as u64 * 1024));
|
||||
mem_idx.insert("avail", Primitive::Bytes(x.avail as u64 * 1024));
|
||||
mem_idx.insert("buffers", Primitive::Bytes(x.buffers as u64 * 1024));
|
||||
mem_idx.insert("cached", Primitive::Bytes(x.cached as u64 * 1024));
|
||||
mem_idx.insert("swap total", Primitive::Bytes(x.swap_total as u64 * 1024));
|
||||
mem_idx.insert("swap free", Primitive::Bytes(x.swap_free as u64 * 1024));
|
||||
|
||||
idx.insert_spanned("mem", mem_idx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -107,57 +64,42 @@ pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
*/
|
||||
|
||||
if let Ok(x) = hostname() {
|
||||
idx.insert(
|
||||
"hostname".to_string(),
|
||||
Value::Primitive(Primitive::String(x)),
|
||||
);
|
||||
idx.insert("hostname", Primitive::String(x));
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
if let Ok(x) = boottime() {
|
||||
let mut boottime_idx = indexmap::IndexMap::new();
|
||||
boottime_idx.insert(
|
||||
"days".to_string(),
|
||||
Value::Primitive(Primitive::Int(x.tv_sec / (24 * 3600))),
|
||||
);
|
||||
boottime_idx.insert(
|
||||
"hours".to_string(),
|
||||
Value::Primitive(Primitive::Int((x.tv_sec / 3600) % 24)),
|
||||
);
|
||||
boottime_idx.insert(
|
||||
"mins".to_string(),
|
||||
Value::Primitive(Primitive::Int((x.tv_sec / 60) % 60)),
|
||||
);
|
||||
let mut boottime_idx = SpannedDictBuilder::new(args.name_span);
|
||||
boottime_idx.insert("days", Primitive::Int(x.tv_sec / (24 * 3600)));
|
||||
boottime_idx.insert("hours", Primitive::Int((x.tv_sec / 3600) % 24));
|
||||
boottime_idx.insert("mins", Primitive::Int((x.tv_sec / 60) % 60));
|
||||
|
||||
idx.insert(
|
||||
"uptime".to_string(),
|
||||
Value::Object(Dictionary::from(boottime_idx)),
|
||||
);
|
||||
idx.insert_spanned("uptime", boottime_idx);
|
||||
}
|
||||
}
|
||||
|
||||
let system = sysinfo::System::new_with_specifics(RefreshKind::everything().without_processes());
|
||||
let components_list = system.get_components_list();
|
||||
if components_list.len() > 0 {
|
||||
let mut v = vec![];
|
||||
let mut v: Vec<Spanned<Value>> = vec![];
|
||||
for component in components_list {
|
||||
let mut component_idx = indexmap::IndexMap::new();
|
||||
let mut component_idx = SpannedDictBuilder::new(args.name_span);
|
||||
component_idx.insert("name", Primitive::String(component.get_label().to_string()));
|
||||
component_idx.insert(
|
||||
"name".to_string(),
|
||||
Value::string(component.get_label().to_string()),
|
||||
"temp",
|
||||
Primitive::Float(OF64::from(component.get_temperature() as f64)),
|
||||
);
|
||||
component_idx.insert(
|
||||
"temp".to_string(),
|
||||
Value::float(component.get_temperature() as f64),
|
||||
"max",
|
||||
Primitive::Float(OF64::from(component.get_max() as f64)),
|
||||
);
|
||||
component_idx.insert("max".to_string(), Value::float(component.get_max() as f64));
|
||||
if let Some(critical) = component.get_critical() {
|
||||
component_idx.insert("critical".to_string(), Value::float(critical as f64));
|
||||
component_idx.insert("critical", Primitive::Float(OF64::from(critical as f64)));
|
||||
}
|
||||
v.push(Value::Object(Dictionary::from(component_idx)));
|
||||
v.push(component_idx.into());
|
||||
}
|
||||
idx.insert("temps".to_string(), Value::List(v));
|
||||
idx.insert("temps", Value::List(v));
|
||||
}
|
||||
|
||||
let disks = system.get_disks();
|
||||
|
@ -165,38 +107,26 @@ pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
let mut v = vec![];
|
||||
|
||||
for disk in disks {
|
||||
let mut disk_idx = indexmap::IndexMap::new();
|
||||
disk_idx.insert(
|
||||
"name".to_string(),
|
||||
Value::string(disk.get_name().to_string_lossy()),
|
||||
);
|
||||
disk_idx.insert(
|
||||
"available".to_string(),
|
||||
Value::bytes(disk.get_available_space()),
|
||||
);
|
||||
disk_idx.insert("total".to_string(), Value::bytes(disk.get_total_space()));
|
||||
v.push(Value::Object(Dictionary::from(disk_idx)));
|
||||
let mut disk_idx = SpannedDictBuilder::new(args.name_span);
|
||||
disk_idx.insert("name", Value::string(disk.get_name().to_string_lossy()));
|
||||
disk_idx.insert("available", Value::bytes(disk.get_available_space()));
|
||||
disk_idx.insert("total", Value::bytes(disk.get_total_space()));
|
||||
v.push(disk_idx.into());
|
||||
}
|
||||
|
||||
idx.insert("disks".to_string(), Value::List(v));
|
||||
idx.insert("disks", Value::List(v));
|
||||
}
|
||||
|
||||
let network = system.get_network();
|
||||
let incoming = network.get_income();
|
||||
let outgoing = network.get_outcome();
|
||||
|
||||
let mut network_idx = indexmap::IndexMap::new();
|
||||
network_idx.insert("incoming".to_string(), Value::bytes(incoming));
|
||||
network_idx.insert("outgoing".to_string(), Value::bytes(outgoing));
|
||||
idx.insert(
|
||||
"network".to_string(),
|
||||
Value::Object(Dictionary::from(network_idx)),
|
||||
);
|
||||
let mut network_idx = SpannedDictBuilder::new(args.name_span);
|
||||
network_idx.insert("incoming", Value::bytes(incoming));
|
||||
network_idx.insert("outgoing", Value::bytes(outgoing));
|
||||
idx.insert_spanned("network", network_idx);
|
||||
|
||||
// println!("{:#?}", system.get_network());
|
||||
let stream = stream![idx.into_spanned_value()];
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(ReturnValue::Value(Value::Object(Dictionary::from(idx))));
|
||||
|
||||
Ok(stream.boxed())
|
||||
Ok(stream.from_input_stream())
|
||||
}
|
||||
|
|
|
@ -2,9 +2,10 @@ use crate::object::Value;
|
|||
use crate::prelude::*;
|
||||
|
||||
pub fn to_array(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input.collect();
|
||||
let out = args.input.values.collect();
|
||||
|
||||
Ok(out
|
||||
.map(|vec: Vec<_>| single_output(Value::List(vec)))
|
||||
.map(|vec: Vec<_>| stream![Value::List(vec).spanned_unknown()]) // TODO: args.input should have a span
|
||||
.flatten_stream()
|
||||
.boxed())
|
||||
.from_input_stream())
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value {
|
|||
Value::List(l) => {
|
||||
serde_json::Value::Array(l.iter().map(|x| value_to_json_value(x)).collect())
|
||||
}
|
||||
Value::Error(e) => serde_json::Value::String(e.to_string()),
|
||||
Value::Block(_) => serde_json::Value::Null,
|
||||
Value::Binary(b) => serde_json::Value::Array(
|
||||
b.iter()
|
||||
|
@ -43,19 +42,20 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value {
|
|||
|
||||
pub fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
let span = args.name_span;
|
||||
let name_span = args.name_span;
|
||||
Ok(out
|
||||
.values
|
||||
.map(
|
||||
move |a| match serde_json::to_string(&value_to_json_value(&a)) {
|
||||
Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))),
|
||||
Err(_) => {
|
||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
Ok(x) => {
|
||||
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
|
||||
}
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Can not convert to JSON string",
|
||||
"can not convert piped data to JSON string",
|
||||
span,
|
||||
))))
|
||||
}
|
||||
name_span,
|
||||
)),
|
||||
},
|
||||
)
|
||||
.boxed())
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value {
|
|||
|
||||
Value::Filesystem => toml::Value::String("<Filesystem>".to_string()),
|
||||
Value::List(l) => toml::Value::Array(l.iter().map(|x| value_to_toml_value(x)).collect()),
|
||||
Value::Error(e) => toml::Value::String(e.to_string()),
|
||||
Value::Block(_) => toml::Value::String("<Block>".to_string()),
|
||||
Value::Binary(b) => {
|
||||
toml::Value::Array(b.iter().map(|x| toml::Value::Integer(*x as i64)).collect())
|
||||
|
@ -33,15 +32,40 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value {
|
|||
|
||||
pub fn to_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
let span = args.name_span;
|
||||
let name_span = args.name_span;
|
||||
|
||||
Ok(out
|
||||
.map(move |a| match toml::to_string(&value_to_toml_value(&a)) {
|
||||
Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))),
|
||||
Err(_) => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
"Can not convert to TOML string",
|
||||
"can not convert piped data to TOML string",
|
||||
span,
|
||||
)))),
|
||||
})
|
||||
.boxed())
|
||||
.values
|
||||
.map(move |a| {
|
||||
match toml::to_string(&value_to_toml_value(&a)) {
|
||||
Ok(val) => {
|
||||
return ReturnSuccess::value(
|
||||
Value::Primitive(Primitive::String(val)).spanned(name_span),
|
||||
)
|
||||
}
|
||||
|
||||
Err(err) => Err(ShellError::type_error(
|
||||
"serializable to toml",
|
||||
format!("{:?} - {:?}", a.type_name(), err).spanned(name_span),
|
||||
)), // toml::Value::String(String) => {
|
||||
// return ReturnSuccess::value(
|
||||
// Value::Primitive(Primitive::String(x)).spanned(name_span),
|
||||
// )
|
||||
// }
|
||||
// toml::Value::Integer(i64) => "Integer",
|
||||
// toml::Value::Float(f64) => "Decimal",
|
||||
// toml::Value::Boolean(bool) => "Boolean",
|
||||
// toml::Value::Datetime(Datetime) => "Date",
|
||||
// toml::Value::Array(Array) => "Array",
|
||||
// toml::Value::Table(Table) => "Table",
|
||||
}
|
||||
// return Err(ShellError::type_error("String", ty.spanned(name_span)));
|
||||
|
||||
// Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
// "Can not convert to TOML string",
|
||||
// "can not convert piped data to TOML string",
|
||||
// name_span,
|
||||
// )),
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::{Primitive, Value};
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
|
||||
// TODO: "Amount remaining" wrapper
|
||||
|
||||
pub fn trim(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let input = args.input;
|
||||
let span = args.name_span;
|
||||
|
||||
Ok(input
|
||||
.map(move |v| match v {
|
||||
Value::Primitive(Primitive::String(s)) => {
|
||||
ReturnValue::Value(Value::Primitive(Primitive::String(s.trim().into())))
|
||||
}
|
||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)))),
|
||||
.values
|
||||
.map(move |v| {
|
||||
let string = String::extract(&v)?;
|
||||
ReturnSuccess::value(Value::string(string.trim()).spanned(v.span))
|
||||
})
|
||||
.boxed())
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -46,5 +46,5 @@ pub fn view(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
|
||||
let _ = printer.file(file.display().to_string());
|
||||
|
||||
Ok(VecDeque::new().boxed())
|
||||
Ok(OutputStream::empty())
|
||||
}
|
||||
|
|
|
@ -1,55 +1,23 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::parser::registry::{CommandConfig, PositionalType};
|
||||
use crate::object::Block;
|
||||
use crate::prelude::*;
|
||||
use futures::future::ready;
|
||||
use log::trace;
|
||||
|
||||
pub struct Where;
|
||||
command! {
|
||||
Where as where(args, condition: Block) {
|
||||
let input: InputStream = trace_stream!(target: "nu::trace_stream::where", "where input" = args.input);
|
||||
|
||||
impl Command for Where {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
r#where(args)
|
||||
}
|
||||
fn name(&self) -> &str {
|
||||
"where"
|
||||
}
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
mandatory_positional: vec![PositionalType::Block("condition".to_string())],
|
||||
optional_positional: vec![],
|
||||
rest_positional: false,
|
||||
named: indexmap::IndexMap::new(),
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
can_load: vec![],
|
||||
can_save: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn r#where(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Where requires a condition",
|
||||
"needs condition",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let block = args.expect_nth(0)?.as_block()?;
|
||||
let input = args.input;
|
||||
|
||||
let objects = input.filter_map(move |item| {
|
||||
let result = block.invoke(&item);
|
||||
input.values.filter_map(move |item| {
|
||||
let result = condition.invoke(&item);
|
||||
|
||||
let return_value = match result {
|
||||
Err(err) => Some(ReturnValue::Value(Value::Error(Box::new(err)))),
|
||||
Ok(v) if v.is_true() => Some(ReturnValue::Value(item.copy())),
|
||||
Err(err) => Some(Err(err)),
|
||||
Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.clone()))),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
futures::future::ready(return_value)
|
||||
});
|
||||
|
||||
Ok(objects.boxed())
|
||||
ready(return_value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ impl Context {
|
|||
command: Arc<dyn Sink>,
|
||||
name_span: Option<Span>,
|
||||
args: Args,
|
||||
input: Vec<Value>,
|
||||
input: Vec<Spanned<Value>>,
|
||||
) -> Result<(), ShellError> {
|
||||
let command_args = SinkCommandArgs {
|
||||
ctx: self.clone(),
|
||||
|
|
7
src/env/environment.rs
vendored
7
src/env/environment.rs
vendored
|
@ -1,9 +1,10 @@
|
|||
use crate::object::base::Value;
|
||||
use crate::prelude::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Environment {
|
||||
crate obj: Value,
|
||||
crate obj: Spanned<Value>,
|
||||
crate path: PathBuf,
|
||||
}
|
||||
|
||||
|
@ -12,7 +13,7 @@ impl Environment {
|
|||
let path = std::env::current_dir()?;
|
||||
|
||||
Ok(Environment {
|
||||
obj: Value::Filesystem,
|
||||
obj: Value::Filesystem.spanned_unknown(),
|
||||
path,
|
||||
})
|
||||
}
|
||||
|
@ -21,7 +22,7 @@ impl Environment {
|
|||
self.path.as_path()
|
||||
}
|
||||
|
||||
pub fn obj(&self) -> &Value {
|
||||
pub fn obj(&self) -> &Spanned<Value> {
|
||||
&self.obj
|
||||
}
|
||||
}
|
||||
|
|
225
src/errors.rs
225
src/errors.rs
|
@ -5,7 +5,7 @@ use crate::parser::{Span, Spanned};
|
|||
use ansi_term::Color;
|
||||
use derive_new::new;
|
||||
use language_reporting::{Diagnostic, Label, Severity};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
||||
pub enum Description {
|
||||
|
@ -41,26 +41,20 @@ pub enum ArgumentError {
|
|||
MissingValueForName(String),
|
||||
}
|
||||
|
||||
pub fn labelled(
|
||||
span: impl Into<Option<Span>>,
|
||||
heading: &'a str,
|
||||
span_message: &'a str,
|
||||
) -> impl FnOnce(ShellError) -> ShellError + 'a {
|
||||
let span = span.into();
|
||||
|
||||
move |_| ShellError::maybe_labeled_error(heading, span_message, span)
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
||||
pub enum ShellError {
|
||||
String(StringError),
|
||||
TypeError {
|
||||
expected: String,
|
||||
actual: Spanned<Option<String>>,
|
||||
},
|
||||
MissingProperty {
|
||||
subpath: Description,
|
||||
expr: Description,
|
||||
},
|
||||
ArgumentError {
|
||||
error: ArgumentError,
|
||||
span: Span,
|
||||
},
|
||||
Diagnostic(ShellDiagnostic),
|
||||
CoerceError {
|
||||
left: Spanned<String>,
|
||||
right: Spanned<String>,
|
||||
},
|
||||
pub struct ShellError {
|
||||
error: ProximateShellError,
|
||||
cause: Option<Box<ProximateShellError>>,
|
||||
}
|
||||
|
||||
impl ShellError {
|
||||
|
@ -68,10 +62,39 @@ impl ShellError {
|
|||
expected: impl Into<String>,
|
||||
actual: Spanned<impl Into<String>>,
|
||||
) -> ShellError {
|
||||
ShellError::TypeError {
|
||||
ProximateShellError::TypeError {
|
||||
expected: expected.into(),
|
||||
actual: actual.map(|i| Some(i.into())),
|
||||
}
|
||||
.start()
|
||||
}
|
||||
|
||||
crate fn coerce_error(
|
||||
left: Spanned<impl Into<String>>,
|
||||
right: Spanned<impl Into<String>>,
|
||||
) -> ShellError {
|
||||
ProximateShellError::CoerceError {
|
||||
left: left.map(|l| l.into()),
|
||||
right: right.map(|r| r.into()),
|
||||
}
|
||||
.start()
|
||||
}
|
||||
|
||||
crate fn missing_property(subpath: Description, expr: Description) -> ShellError {
|
||||
ProximateShellError::MissingProperty { subpath, expr }.start()
|
||||
}
|
||||
|
||||
crate fn argument_error(
|
||||
command: impl Into<String>,
|
||||
kind: ArgumentError,
|
||||
span: Span,
|
||||
) -> ShellError {
|
||||
ProximateShellError::ArgumentError {
|
||||
command: command.into(),
|
||||
error: kind,
|
||||
span: span,
|
||||
}
|
||||
.start()
|
||||
}
|
||||
|
||||
crate fn parse_error(
|
||||
|
@ -86,66 +109,56 @@ impl ShellError {
|
|||
.with_label(Label::new_primary(Span::from(span.0)));
|
||||
|
||||
ShellError::diagnostic(diagnostic)
|
||||
// nom::Context::Code(span, kind) => {
|
||||
// let diagnostic =
|
||||
// Diagnostic::new(Severity::Error, format!("{}", kind.description()))
|
||||
// .with_label(Label::new_primary(Span::from(span)));
|
||||
|
||||
// ShellError::diagnostic(diagnostic)
|
||||
// }
|
||||
} // ParseError::UnrecognizedToken {
|
||||
// token: (start, SpannedToken { token, .. }, end),
|
||||
// expected,
|
||||
// } => {
|
||||
// let diagnostic = Diagnostic::new(
|
||||
// Severity::Error,
|
||||
// format!("Unexpected {:?}, expected {:?}", token, expected),
|
||||
// )
|
||||
// .with_label(Label::new_primary(Span::from((start, end))));
|
||||
|
||||
// ShellError::diagnostic(diagnostic)
|
||||
// }
|
||||
// ParseError::User { error } => error,
|
||||
// other => ShellError::string(format!("{:?}", other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate fn diagnostic(diagnostic: Diagnostic<Span>) -> ShellError {
|
||||
ShellError::Diagnostic(ShellDiagnostic { diagnostic })
|
||||
ProximateShellError::Diagnostic(ShellDiagnostic { diagnostic }).start()
|
||||
}
|
||||
|
||||
crate fn to_diagnostic(self) -> Diagnostic<Span> {
|
||||
match self {
|
||||
ShellError::String(StringError { title, .. }) => {
|
||||
match self.error {
|
||||
ProximateShellError::String(StringError { title, .. }) => {
|
||||
Diagnostic::new(Severity::Error, title)
|
||||
}
|
||||
ShellError::ArgumentError { error, span } => match error {
|
||||
ProximateShellError::ArgumentError {
|
||||
command,
|
||||
error,
|
||||
span,
|
||||
} => match error {
|
||||
ArgumentError::MissingMandatoryFlag(name) => Diagnostic::new(
|
||||
Severity::Error,
|
||||
format!(
|
||||
"Command requires {}{}",
|
||||
Color::Cyan.paint("--"),
|
||||
Color::Cyan.paint(name)
|
||||
"{} requires {}{}",
|
||||
Color::Cyan.paint(command),
|
||||
Color::Black.bold().paint("--"),
|
||||
Color::Black.bold().paint(name)
|
||||
),
|
||||
)
|
||||
.with_label(Label::new_primary(span)),
|
||||
ArgumentError::MissingMandatoryPositional(name) => Diagnostic::new(
|
||||
Severity::Error,
|
||||
format!("Command requires {}", Color::Cyan.paint(name)),
|
||||
format!(
|
||||
"{} requires {}",
|
||||
Color::Cyan.paint(command),
|
||||
Color::Green.bold().paint(name)
|
||||
),
|
||||
)
|
||||
.with_label(Label::new_primary(span)),
|
||||
|
||||
ArgumentError::MissingValueForName(name) => Diagnostic::new(
|
||||
Severity::Error,
|
||||
format!(
|
||||
"Missing value for flag {}{}",
|
||||
Color::Cyan.paint("--"),
|
||||
Color::Cyan.paint(name)
|
||||
"{} is missing value for flag {}{}",
|
||||
Color::Cyan.paint(command),
|
||||
Color::Black.bold().paint("--"),
|
||||
Color::Black.bold().paint(name)
|
||||
),
|
||||
)
|
||||
.with_label(Label::new_primary(span)),
|
||||
},
|
||||
ShellError::TypeError {
|
||||
ProximateShellError::TypeError {
|
||||
expected,
|
||||
actual:
|
||||
Spanned {
|
||||
|
@ -157,13 +170,13 @@ impl ShellError {
|
|||
.with_message(format!("Expected {}, found {}", expected, actual)),
|
||||
),
|
||||
|
||||
ShellError::TypeError {
|
||||
ProximateShellError::TypeError {
|
||||
expected,
|
||||
actual: Spanned { item: None, span },
|
||||
} => Diagnostic::new(Severity::Error, "Type Error")
|
||||
.with_label(Label::new_primary(span).with_message(expected)),
|
||||
|
||||
ShellError::MissingProperty { subpath, expr } => {
|
||||
ProximateShellError::MissingProperty { subpath, expr } => {
|
||||
let subpath = subpath.into_label();
|
||||
let expr = expr.into_label();
|
||||
|
||||
|
@ -181,8 +194,8 @@ impl ShellError {
|
|||
diag
|
||||
}
|
||||
|
||||
ShellError::Diagnostic(diag) => diag.diagnostic,
|
||||
ShellError::CoerceError { left, right } => {
|
||||
ProximateShellError::Diagnostic(diag) => diag.diagnostic,
|
||||
ProximateShellError::CoerceError { left, right } => {
|
||||
Diagnostic::new(Severity::Error, "Coercion error")
|
||||
.with_label(Label::new_primary(left.span).with_message(left.item))
|
||||
.with_label(Label::new_secondary(right.span).with_message(right.item))
|
||||
|
@ -190,7 +203,7 @@ impl ShellError {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn labeled_error(
|
||||
pub fn labeled_error(
|
||||
msg: impl Into<String>,
|
||||
label: impl Into<String>,
|
||||
span: Span,
|
||||
|
@ -201,7 +214,7 @@ impl ShellError {
|
|||
)
|
||||
}
|
||||
|
||||
crate fn maybe_labeled_error(
|
||||
pub fn maybe_labeled_error(
|
||||
msg: impl Into<String>,
|
||||
label: impl Into<String>,
|
||||
span: Option<Span>,
|
||||
|
@ -216,7 +229,7 @@ impl ShellError {
|
|||
}
|
||||
|
||||
pub fn string(title: impl Into<String>) -> ShellError {
|
||||
ShellError::String(StringError::new(title.into(), Value::nothing()))
|
||||
ProximateShellError::String(StringError::new(title.into(), Value::nothing())).start()
|
||||
}
|
||||
|
||||
crate fn unimplemented(title: impl Into<String>) -> ShellError {
|
||||
|
@ -226,13 +239,40 @@ impl ShellError {
|
|||
crate fn unexpected(title: impl Into<String>) -> ShellError {
|
||||
ShellError::string(&format!("Unexpected: {}", title.into()))
|
||||
}
|
||||
}
|
||||
|
||||
crate fn copy_error(&self) -> ShellError {
|
||||
self.clone()
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
||||
pub enum ProximateShellError {
|
||||
String(StringError),
|
||||
TypeError {
|
||||
expected: String,
|
||||
actual: Spanned<Option<String>>,
|
||||
},
|
||||
MissingProperty {
|
||||
subpath: Description,
|
||||
expr: Description,
|
||||
},
|
||||
ArgumentError {
|
||||
command: String,
|
||||
error: ArgumentError,
|
||||
span: Span,
|
||||
},
|
||||
Diagnostic(ShellDiagnostic),
|
||||
CoerceError {
|
||||
left: Spanned<String>,
|
||||
right: Spanned<String>,
|
||||
},
|
||||
}
|
||||
impl ProximateShellError {
|
||||
fn start(self) -> ShellError {
|
||||
ShellError {
|
||||
cause: None,
|
||||
error: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ShellDiagnostic {
|
||||
crate diagnostic: Diagnostic<Span>,
|
||||
}
|
||||
|
@ -275,28 +315,6 @@ impl std::cmp::Ord for ShellDiagnostic {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for ShellDiagnostic {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
"<diagnostic>".serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize<'de> for ShellDiagnostic {
|
||||
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(ShellDiagnostic {
|
||||
diagnostic: Diagnostic::new(
|
||||
language_reporting::Severity::Error,
|
||||
"deserialize not implemented for ShellDiagnostic",
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, new, Clone, Serialize, Deserialize)]
|
||||
pub struct StringError {
|
||||
title: String,
|
||||
|
@ -305,13 +323,13 @@ pub struct StringError {
|
|||
|
||||
impl std::fmt::Display for ShellError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
ShellError::String(s) => write!(f, "{}", &s.title),
|
||||
ShellError::TypeError { .. } => write!(f, "TypeError"),
|
||||
ShellError::MissingProperty { .. } => write!(f, "MissingProperty"),
|
||||
ShellError::ArgumentError { .. } => write!(f, "ArgumentError"),
|
||||
ShellError::Diagnostic(_) => write!(f, "<diagnostic>"),
|
||||
ShellError::CoerceError { .. } => write!(f, "CoerceError"),
|
||||
match &self.error {
|
||||
ProximateShellError::String(s) => write!(f, "{}", &s.title),
|
||||
ProximateShellError::TypeError { .. } => write!(f, "TypeError"),
|
||||
ProximateShellError::MissingProperty { .. } => write!(f, "MissingProperty"),
|
||||
ProximateShellError::ArgumentError { .. } => write!(f, "ArgumentError"),
|
||||
ProximateShellError::Diagnostic(_) => write!(f, "<diagnostic>"),
|
||||
ProximateShellError::CoerceError { .. } => write!(f, "CoerceError"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -320,45 +338,40 @@ impl std::error::Error for ShellError {}
|
|||
|
||||
impl std::convert::From<std::io::Error> for ShellError {
|
||||
fn from(input: std::io::Error) -> ShellError {
|
||||
ShellError::String(StringError {
|
||||
ProximateShellError::String(StringError {
|
||||
title: format!("{}", input),
|
||||
error: Value::nothing(),
|
||||
})
|
||||
.start()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<futures_sink::VecSinkError> for ShellError {
|
||||
fn from(_input: futures_sink::VecSinkError) -> ShellError {
|
||||
ShellError::String(StringError {
|
||||
ProximateShellError::String(StringError {
|
||||
title: format!("Unexpected Vec Sink Error"),
|
||||
error: Value::nothing(),
|
||||
})
|
||||
.start()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<subprocess::PopenError> for ShellError {
|
||||
fn from(input: subprocess::PopenError) -> ShellError {
|
||||
ShellError::String(StringError {
|
||||
ProximateShellError::String(StringError {
|
||||
title: format!("{}", input),
|
||||
error: Value::nothing(),
|
||||
})
|
||||
.start()
|
||||
}
|
||||
}
|
||||
|
||||
// impl std::convert::From<nom::Err<(&str, nom::ErrorKind)>> for ShellError {
|
||||
// fn from(input: nom::Err<(&str, nom::ErrorKind)>) -> ShellError {
|
||||
// ShellError::String(StringError {
|
||||
// title: format!("{:?}", input),
|
||||
// error: Value::nothing(),
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
impl std::convert::From<toml::ser::Error> for ShellError {
|
||||
fn from(input: toml::ser::Error) -> ShellError {
|
||||
ShellError::String(StringError {
|
||||
ProximateShellError::String(StringError {
|
||||
title: format!("{:?}", input),
|
||||
error: Value::nothing(),
|
||||
})
|
||||
.start()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,15 +10,15 @@ use indexmap::IndexMap;
|
|||
|
||||
#[derive(new)]
|
||||
crate struct Scope {
|
||||
it: Value,
|
||||
it: Spanned<Value>,
|
||||
#[new(default)]
|
||||
vars: IndexMap<String, Value>,
|
||||
vars: IndexMap<String, Spanned<Value>>,
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
crate fn empty() -> Scope {
|
||||
Scope {
|
||||
it: Value::nothing(),
|
||||
it: Value::nothing().spanned_unknown(),
|
||||
vars: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
|
@ -39,10 +39,10 @@ crate fn evaluate_baseline_expr(
|
|||
|
||||
match left.compare(binary.op(), &*right) {
|
||||
Ok(result) => Ok(Spanned::from_item(Value::boolean(result), *expr.span())),
|
||||
Err((left_type, right_type)) => Err(ShellError::CoerceError {
|
||||
left: binary.left().copy_span(left_type),
|
||||
right: binary.right().copy_span(right_type),
|
||||
}),
|
||||
Err((left_type, right_type)) => Err(ShellError::coerce_error(
|
||||
binary.left().copy_span(left_type),
|
||||
binary.right().copy_span(right_type),
|
||||
)),
|
||||
}
|
||||
}
|
||||
RawExpression::Block(block) => Ok(Spanned::from_item(
|
||||
|
@ -58,14 +58,16 @@ crate fn evaluate_baseline_expr(
|
|||
|
||||
match next {
|
||||
None => {
|
||||
return Err(ShellError::MissingProperty {
|
||||
subpath: Description::from(item.spanned_type_name()),
|
||||
expr: Description::from(name.clone()),
|
||||
})
|
||||
return Err(ShellError::missing_property(
|
||||
Description::from(item.spanned_type_name()),
|
||||
Description::from(name.clone()),
|
||||
))
|
||||
}
|
||||
Some(next) => {
|
||||
item =
|
||||
Spanned::from_item(next.clone(), (expr.span().start, name.span().end))
|
||||
item = Spanned::from_item(
|
||||
next.clone().item,
|
||||
(expr.span().start, name.span().end),
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -93,14 +95,11 @@ fn evaluate_reference(
|
|||
source: &Text,
|
||||
) -> Result<Spanned<Value>, ShellError> {
|
||||
match name {
|
||||
hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.copy(), span)),
|
||||
hir::Variable::Other(span) => Ok(Spanned::from_item(
|
||||
scope
|
||||
hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.item.clone(), span)),
|
||||
hir::Variable::Other(span) => Ok(scope
|
||||
.vars
|
||||
.get(span.slice(source))
|
||||
.map(|v| v.copy())
|
||||
.unwrap_or_else(|| Value::nothing()),
|
||||
span,
|
||||
)),
|
||||
.map(|v| v.clone())
|
||||
.unwrap_or_else(|| Value::nothing().spanned(span))),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ crate mod entries;
|
|||
crate mod generic;
|
||||
crate mod list;
|
||||
crate mod table;
|
||||
crate mod tree;
|
||||
crate mod vtable;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
@ -10,7 +9,6 @@ use crate::prelude::*;
|
|||
crate use entries::EntriesView;
|
||||
crate use generic::GenericView;
|
||||
crate use table::TableView;
|
||||
crate use tree::TreeView;
|
||||
crate use vtable::VTableView;
|
||||
|
||||
crate trait RenderView {
|
||||
|
|
|
@ -36,11 +36,6 @@ impl RenderView for GenericView<'value> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
Value::Error(e) => {
|
||||
host.stdout(&format!("{:?}", e));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Value::Binary(_) => {
|
||||
host.stdout("<Binary>");
|
||||
Ok(())
|
||||
|
|
|
@ -13,7 +13,7 @@ pub struct TableView {
|
|||
}
|
||||
|
||||
impl TableView {
|
||||
fn merge_descriptors(values: &[Value]) -> Vec<String> {
|
||||
fn merge_descriptors(values: &[Spanned<Value>]) -> Vec<String> {
|
||||
let mut ret = vec![];
|
||||
for value in values {
|
||||
for desc in value.data_descriptors() {
|
||||
|
@ -25,7 +25,7 @@ impl TableView {
|
|||
ret
|
||||
}
|
||||
|
||||
pub fn from_list(values: &[Value]) -> Option<TableView> {
|
||||
pub fn from_list(values: &[Spanned<Value>]) -> Option<TableView> {
|
||||
if values.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
use crate::format::RenderView;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use ptree::item::StringItem;
|
||||
use ptree::output::print_tree_with;
|
||||
use ptree::print_config::PrintConfig;
|
||||
use ptree::style::{Color, Style};
|
||||
use ptree::TreeBuilder;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct TreeView {
|
||||
tree: StringItem,
|
||||
}
|
||||
|
||||
impl TreeView {
|
||||
fn from_value_helper(value: &Value, mut builder: &mut TreeBuilder) {
|
||||
match value {
|
||||
Value::Primitive(p) => {
|
||||
let _ = builder.add_empty_child(p.format(None));
|
||||
}
|
||||
Value::Object(o) => {
|
||||
for (k, v) in o.entries.iter() {
|
||||
builder = builder.begin_child(k.clone());
|
||||
Self::from_value_helper(v, builder);
|
||||
builder = builder.end_child();
|
||||
}
|
||||
}
|
||||
Value::List(l) => {
|
||||
for elem in l.iter() {
|
||||
Self::from_value_helper(elem, builder);
|
||||
}
|
||||
}
|
||||
Value::Block(_) => {}
|
||||
Value::Error(_) => {}
|
||||
Value::Filesystem => {}
|
||||
Value::Binary(_) => {}
|
||||
}
|
||||
}
|
||||
crate fn from_value(value: &Value) -> TreeView {
|
||||
let descs = value.data_descriptors();
|
||||
|
||||
let mut tree = TreeBuilder::new("".to_string());
|
||||
let mut builder = &mut tree;
|
||||
|
||||
for desc in descs {
|
||||
let value = value.get_data(&desc);
|
||||
builder = builder.begin_child(desc.clone());
|
||||
Self::from_value_helper(value.borrow(), &mut builder);
|
||||
builder = builder.end_child();
|
||||
//entries.push((desc.name.clone(), value.borrow().copy()))
|
||||
}
|
||||
|
||||
TreeView::new(builder.build())
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderView for TreeView {
|
||||
fn render_view(&self, _host: &mut dyn Host) -> Result<(), ShellError> {
|
||||
// Set up the print configuration
|
||||
let config = {
|
||||
let mut config = PrintConfig::from_env();
|
||||
config.branch = Style {
|
||||
foreground: Some(Color::Green),
|
||||
dimmed: true,
|
||||
..Style::default()
|
||||
};
|
||||
config.leaf = Style {
|
||||
bold: true,
|
||||
..Style::default()
|
||||
};
|
||||
config.indent = 4;
|
||||
config
|
||||
};
|
||||
|
||||
// Print out the tree using custom formatting
|
||||
print_tree_with(&self.tree, &config)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ pub struct VTableView {
|
|||
}
|
||||
|
||||
impl VTableView {
|
||||
pub fn from_list(values: &[Value]) -> Option<VTableView> {
|
||||
pub fn from_list(values: &[Spanned<Value>]) -> Option<VTableView> {
|
||||
if values.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
#![feature(try_trait)]
|
||||
#![feature(bind_by_move_pattern_guards)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(type_ascription)]
|
||||
|
||||
#[macro_use]
|
||||
mod prelude;
|
||||
|
||||
mod cli;
|
||||
mod commands;
|
||||
|
@ -16,11 +20,10 @@ mod git;
|
|||
mod object;
|
||||
mod parser;
|
||||
mod plugin;
|
||||
mod prelude;
|
||||
mod shell;
|
||||
mod stream;
|
||||
|
||||
pub use crate::commands::command::ReturnValue;
|
||||
pub use crate::commands::command::{ReturnSuccess, ReturnValue};
|
||||
pub use crate::env::host::BasicHost;
|
||||
pub use crate::parser::parse::span::SpannedItem;
|
||||
pub use crate::parser::Spanned;
|
||||
|
|
|
@ -2,9 +2,10 @@ crate mod base;
|
|||
crate mod config;
|
||||
crate mod dict;
|
||||
crate mod files;
|
||||
crate mod into;
|
||||
crate mod process;
|
||||
crate mod types;
|
||||
|
||||
crate use base::{Primitive, Value};
|
||||
crate use dict::Dictionary;
|
||||
crate use base::{Block, Primitive, Switch, Value};
|
||||
crate use dict::{Dictionary, SpannedDictBuilder};
|
||||
crate use files::dir_entry_dict;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
||||
use crate::object::SpannedDictBuilder;
|
||||
use crate::parser::{hir, Operator, Span, Spanned};
|
||||
use crate::prelude::*;
|
||||
use crate::Text;
|
||||
|
@ -149,17 +150,12 @@ impl Deserialize<'de> for Block {
|
|||
D: Deserializer<'de>,
|
||||
{
|
||||
unimplemented!("deserialize block")
|
||||
// let s = "\"unimplemented deserialize block\"";
|
||||
// Ok(Block::new(
|
||||
// TokenTreeBuilder::spanned_string((1, s.len() - 1), (0, s.len())),
|
||||
// Text::from(s),
|
||||
// ))
|
||||
}
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn invoke(&self, value: &Value) -> Result<Spanned<Value>, ShellError> {
|
||||
let scope = Scope::new(value.copy());
|
||||
pub fn invoke(&self, value: &Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
|
||||
let scope = Scope::new(value.clone());
|
||||
|
||||
if self.expressions.len() == 0 {
|
||||
return Ok(Spanned::from_item(Value::nothing(), self.span));
|
||||
|
@ -179,23 +175,19 @@ impl Block {
|
|||
pub enum Value {
|
||||
Primitive(Primitive),
|
||||
Object(crate::object::Dictionary),
|
||||
List(Vec<Value>),
|
||||
Binary(Vec<u8>),
|
||||
|
||||
List(Vec<Spanned<Value>>),
|
||||
#[allow(unused)]
|
||||
Block(Block),
|
||||
Filesystem,
|
||||
|
||||
#[allow(unused)]
|
||||
Error(Box<ShellError>),
|
||||
}
|
||||
|
||||
pub fn debug_list(values: &'a Vec<Value>) -> ValuesDebug<'a> {
|
||||
pub fn debug_list(values: &'a Vec<Spanned<Value>>) -> ValuesDebug<'a> {
|
||||
ValuesDebug { values }
|
||||
}
|
||||
|
||||
pub struct ValuesDebug<'a> {
|
||||
values: &'a Vec<Value>,
|
||||
values: &'a Vec<Spanned<Value>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ValuesDebug<'a> {
|
||||
|
@ -207,17 +199,16 @@ impl fmt::Debug for ValuesDebug<'a> {
|
|||
}
|
||||
|
||||
pub struct ValueDebug<'a> {
|
||||
value: &'a Value,
|
||||
value: &'a Spanned<Value>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ValueDebug<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.value {
|
||||
match self.value.item() {
|
||||
Value::Primitive(p) => p.debug(f),
|
||||
Value::Object(o) => o.debug(f),
|
||||
Value::List(l) => debug_list(l).fmt(f),
|
||||
Value::Block(_) => write!(f, "[[block]]"),
|
||||
Value::Error(err) => write!(f, "[[error :: {} ]]", err),
|
||||
Value::Filesystem => write!(f, "[[filesystem]]"),
|
||||
Value::Binary(_) => write!(f, "[[binary]]"),
|
||||
}
|
||||
|
@ -231,6 +222,71 @@ impl Spanned<Value> {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&'a Spanned<Value>> for Block {
|
||||
type Error = ShellError;
|
||||
|
||||
fn try_from(value: &'a Spanned<Value>) -> Result<Block, ShellError> {
|
||||
match value.item() {
|
||||
Value::Block(block) => Ok(block.clone()),
|
||||
v => Err(ShellError::type_error(
|
||||
"Block",
|
||||
value.copy_span(v.type_name()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&'a Spanned<Value>> for i64 {
|
||||
type Error = ShellError;
|
||||
|
||||
fn try_from(value: &'a Spanned<Value>) -> Result<i64, ShellError> {
|
||||
match value.item() {
|
||||
Value::Primitive(Primitive::Int(int)) => Ok(*int),
|
||||
v => Err(ShellError::type_error(
|
||||
"Integer",
|
||||
value.copy_span(v.type_name()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Switch {
|
||||
Present,
|
||||
Absent,
|
||||
}
|
||||
|
||||
impl Switch {
|
||||
pub fn is_present(&self) -> bool {
|
||||
match self {
|
||||
Switch::Present => true,
|
||||
Switch::Absent => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<Option<&'a Spanned<Value>>> for Switch {
|
||||
type Error = ShellError;
|
||||
|
||||
fn try_from(value: Option<&'a Spanned<Value>>) -> Result<Switch, ShellError> {
|
||||
match value {
|
||||
None => Ok(Switch::Absent),
|
||||
Some(value) => match value.item() {
|
||||
Value::Primitive(Primitive::Boolean(true)) => Ok(Switch::Present),
|
||||
v => Err(ShellError::type_error(
|
||||
"Boolean",
|
||||
value.copy_span(v.type_name()),
|
||||
)),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Spanned<Value> {
|
||||
crate fn debug(&'a self) -> ValueDebug<'a> {
|
||||
ValueDebug { value: self }
|
||||
}
|
||||
}
|
||||
|
||||
impl Value {
|
||||
crate fn type_name(&self) -> String {
|
||||
match self {
|
||||
|
@ -238,16 +294,11 @@ impl Value {
|
|||
Value::Object(_) => format!("object"),
|
||||
Value::List(_) => format!("list"),
|
||||
Value::Block(_) => format!("block"),
|
||||
Value::Error(_) => format!("error"),
|
||||
Value::Filesystem => format!("filesystem"),
|
||||
Value::Binary(_) => format!("binary"),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn debug(&'a self) -> ValueDebug<'a> {
|
||||
ValueDebug { value: self }
|
||||
}
|
||||
|
||||
pub fn data_descriptors(&self) -> Vec<String> {
|
||||
match self {
|
||||
Value::Primitive(_) => vec![],
|
||||
|
@ -259,19 +310,21 @@ impl Value {
|
|||
.collect(),
|
||||
Value::Block(_) => vec![],
|
||||
Value::List(_) => vec![],
|
||||
Value::Error(_) => vec![],
|
||||
Value::Filesystem => vec![],
|
||||
Value::Binary(_) => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
crate fn get_data_by_key(&'a self, name: &str) -> Option<&Value> {
|
||||
crate fn get_data_by_key(&'a self, name: &str) -> Option<&Spanned<Value>> {
|
||||
match self {
|
||||
Value::Object(o) => o.get_data_by_key(name),
|
||||
Value::List(l) => {
|
||||
for item in l {
|
||||
match item {
|
||||
Value::Object(o) => match o.get_data_by_key(name) {
|
||||
Spanned {
|
||||
item: Value::Object(o),
|
||||
..
|
||||
} => match o.get_data_by_key(name) {
|
||||
Some(v) => return Some(v),
|
||||
None => {}
|
||||
},
|
||||
|
@ -284,7 +337,7 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn get_data_by_index(&'a self, idx: usize) -> Option<&Value> {
|
||||
crate fn get_data_by_index(&'a self, idx: usize) -> Option<&Spanned<Value>> {
|
||||
match self {
|
||||
Value::List(l) => l.iter().nth(idx),
|
||||
_ => None,
|
||||
|
@ -298,26 +351,10 @@ impl Value {
|
|||
Value::Object(o) => o.get_data(desc),
|
||||
Value::Block(_) => MaybeOwned::Owned(Value::nothing()),
|
||||
Value::List(_) => MaybeOwned::Owned(Value::nothing()),
|
||||
Value::Error(e) => MaybeOwned::Owned(Value::string(&format!("{:#?}", e))),
|
||||
Value::Binary(_) => MaybeOwned::Owned(Value::nothing()),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn copy(&self) -> Value {
|
||||
match self {
|
||||
Value::Primitive(p) => Value::Primitive(p.clone()),
|
||||
Value::Object(o) => Value::Object(o.copy_dict()),
|
||||
Value::Block(b) => Value::Block(b.clone()),
|
||||
Value::List(l) => {
|
||||
let list = l.iter().map(|i| i.copy()).collect();
|
||||
Value::List(list)
|
||||
}
|
||||
Value::Error(e) => Value::Error(Box::new(e.copy_error())),
|
||||
Value::Filesystem => Value::Filesystem,
|
||||
Value::Binary(b) => Value::Binary(b.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn format_leaf(&self, desc: Option<&String>) -> String {
|
||||
match self {
|
||||
Value::Primitive(p) => p.format(desc),
|
||||
|
@ -329,7 +366,6 @@ impl Value {
|
|||
),
|
||||
Value::Object(_) => format!("[object Object]"),
|
||||
Value::List(_) => format!("[list List]"),
|
||||
Value::Error(e) => format!("{}", e),
|
||||
Value::Filesystem => format!("<filesystem>"),
|
||||
Value::Binary(_) => format!("<binary>"),
|
||||
}
|
||||
|
@ -370,7 +406,7 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn as_pair(&self) -> Result<(Value, Value), ShellError> {
|
||||
crate fn as_pair(&self) -> Result<(Spanned<Value>, Spanned<Value>), ShellError> {
|
||||
match self {
|
||||
Value::List(list) if list.len() == 2 => Ok((list[0].clone(), list[1].clone())),
|
||||
other => Err(ShellError::string(format!(
|
||||
|
@ -459,52 +495,39 @@ impl Value {
|
|||
Ok(Value::Primitive(Primitive::Date(date)))
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn system_date_result(s: Result<SystemTime, std::io::Error>) -> Value {
|
||||
match s {
|
||||
Ok(time) => Value::Primitive(Primitive::Date(time.into())),
|
||||
Err(err) => Value::Error(Box::new(ShellError::string(format!("{}", err)))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nothing() -> Value {
|
||||
Value::Primitive(Primitive::Nothing)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn list(values: impl Into<Vec<Value>>) -> Value {
|
||||
Value::List(values.into())
|
||||
}
|
||||
}
|
||||
|
||||
crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Dictionary {
|
||||
let mut out = crate::object::Dictionary::default();
|
||||
crate fn select_fields(obj: &Value, fields: &[String], span: impl Into<Span>) -> Spanned<Value> {
|
||||
let mut out = SpannedDictBuilder::new(span);
|
||||
|
||||
let descs = obj.data_descriptors();
|
||||
|
||||
for field in fields {
|
||||
match descs.iter().find(|d| *d == field) {
|
||||
None => out.add(field, Value::nothing()),
|
||||
Some(desc) => out.add(desc.clone(), obj.get_data(desc).borrow().copy()),
|
||||
None => out.insert(field, Value::nothing()),
|
||||
Some(desc) => out.insert(desc.clone(), obj.get_data(desc).borrow().clone()),
|
||||
}
|
||||
}
|
||||
|
||||
out
|
||||
out.into_spanned_value()
|
||||
}
|
||||
|
||||
crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Dictionary {
|
||||
let mut out = crate::object::Dictionary::default();
|
||||
crate fn reject_fields(obj: &Value, fields: &[String], span: impl Into<Span>) -> Spanned<Value> {
|
||||
let mut out = SpannedDictBuilder::new(span);
|
||||
|
||||
let descs = obj.data_descriptors();
|
||||
|
||||
for desc in descs {
|
||||
match desc {
|
||||
x if fields.iter().any(|field| *field == x) => continue,
|
||||
_ => out.add(desc.clone(), obj.get_data(&desc).borrow().copy()),
|
||||
_ => out.insert(desc.clone(), obj.get_data(&desc).borrow().clone()),
|
||||
}
|
||||
}
|
||||
|
||||
out
|
||||
out.into_spanned_value()
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
|
@ -513,7 +536,7 @@ crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
|
|||
match descs.iter().find(|d| *d == field) {
|
||||
None => false,
|
||||
Some(desc) => {
|
||||
let v = obj.get_data(desc).borrow().copy();
|
||||
let v = obj.get_data(desc).borrow().clone();
|
||||
|
||||
match v {
|
||||
Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) {
|
||||
|
|
|
@ -16,24 +16,28 @@ const APP_INFO: AppInfo = AppInfo {
|
|||
#[derive(Deserialize, Serialize)]
|
||||
struct Config {
|
||||
#[serde(flatten)]
|
||||
extra: IndexMap<String, Value>,
|
||||
extra: IndexMap<String, Spanned<Value>>,
|
||||
}
|
||||
|
||||
crate fn write_config(map: &IndexMap<String, Value>) -> Result<(), ShellError> {
|
||||
crate fn write_config(config: &IndexMap<String, Spanned<Value>>) -> Result<(), ShellError> {
|
||||
let location = app_root(AppDataType::UserConfig, &APP_INFO)
|
||||
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
|
||||
|
||||
let filename = location.join("config.toml");
|
||||
touch(&filename)?;
|
||||
|
||||
let contents = toml::to_string(&Config { extra: map.clone() })?;
|
||||
let contents = toml::to_string(&Config {
|
||||
extra: config.iter().map(|(k, v)| (k.clone(), v.clone())).collect(),
|
||||
})?;
|
||||
|
||||
fs::write(&filename, &contents)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
crate fn config() -> Result<IndexMap<String, Value>, ShellError> {
|
||||
crate fn config(span: impl Into<Span>) -> Result<IndexMap<String, Spanned<Value>>, ShellError> {
|
||||
let span = span.into();
|
||||
|
||||
let location = app_root(AppDataType::UserConfig, &APP_INFO)
|
||||
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
|
||||
|
||||
|
@ -43,6 +47,7 @@ crate fn config() -> Result<IndexMap<String, Value>, ShellError> {
|
|||
trace!("config file = {}", filename.display());
|
||||
|
||||
let contents = fs::read_to_string(filename)
|
||||
.map(|v| v.spanned(span))
|
||||
.map_err(|err| ShellError::string(&format!("Couldn't read config file:\n{}", err)))?;
|
||||
|
||||
let parsed: Config = toml::from_str(&contents)
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::fmt;
|
|||
|
||||
#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, new)]
|
||||
pub struct Dictionary {
|
||||
pub entries: IndexMap<String, Value>,
|
||||
pub entries: IndexMap<String, Spanned<Value>>,
|
||||
}
|
||||
|
||||
impl PartialOrd for Dictionary {
|
||||
|
@ -21,15 +21,15 @@ impl PartialOrd for Dictionary {
|
|||
return this.partial_cmp(&that);
|
||||
}
|
||||
|
||||
let this: Vec<&Value> = self.entries.values().collect();
|
||||
let that: Vec<&Value> = self.entries.values().collect();
|
||||
let this: Vec<&Value> = self.entries.values().map(|v| v.item()).collect();
|
||||
let that: Vec<&Value> = self.entries.values().map(|v| v.item()).collect();
|
||||
|
||||
this.partial_cmp(&that)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IndexMap<String, Value>> for Dictionary {
|
||||
fn from(input: IndexMap<String, Value>) -> Dictionary {
|
||||
impl From<IndexMap<String, Spanned<Value>>> for Dictionary {
|
||||
fn from(input: IndexMap<String, Spanned<Value>>) -> Dictionary {
|
||||
let mut out = IndexMap::default();
|
||||
|
||||
for (key, value) in input {
|
||||
|
@ -49,8 +49,8 @@ impl Ord for Dictionary {
|
|||
return this.cmp(&that);
|
||||
}
|
||||
|
||||
let this: Vec<&Value> = self.entries.values().collect();
|
||||
let that: Vec<&Value> = self.entries.values().collect();
|
||||
let this: Vec<&Value> = self.entries.values().map(|v| v.item()).collect();
|
||||
let that: Vec<&Value> = self.entries.values().map(|v| v.item()).collect();
|
||||
|
||||
this.cmp(&that)
|
||||
}
|
||||
|
@ -72,20 +72,6 @@ impl PartialEq<Value> for Dictionary {
|
|||
}
|
||||
|
||||
impl Dictionary {
|
||||
crate fn add(&mut self, name: impl Into<String>, value: Value) {
|
||||
self.entries.insert(name.into(), value);
|
||||
}
|
||||
|
||||
crate fn copy_dict(&self) -> Dictionary {
|
||||
let mut out = Dictionary::default();
|
||||
|
||||
for (key, value) in self.entries.iter() {
|
||||
out.add(key.clone(), value.copy());
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
pub fn get_data(&'a self, desc: &String) -> MaybeOwned<'a, Value> {
|
||||
match self.entries.get(desc) {
|
||||
Some(v) => MaybeOwned::Borrowed(v),
|
||||
|
@ -93,7 +79,7 @@ impl Dictionary {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn get_data_by_key(&self, name: &str) -> Option<&Value> {
|
||||
crate fn get_data_by_key(&self, name: &str) -> Option<&Spanned<Value>> {
|
||||
match self
|
||||
.entries
|
||||
.iter()
|
||||
|
@ -114,3 +100,73 @@ impl Dictionary {
|
|||
debug.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SpannedListBuilder {
|
||||
span: Span,
|
||||
list: Vec<Spanned<Value>>,
|
||||
}
|
||||
|
||||
impl SpannedListBuilder {
|
||||
pub fn new(span: impl Into<Span>) -> SpannedListBuilder {
|
||||
SpannedListBuilder {
|
||||
span: span.into(),
|
||||
list: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: impl Into<Value>) {
|
||||
self.list.push(value.into().spanned(self.span));
|
||||
}
|
||||
|
||||
pub fn insert_spanned(&mut self, value: impl Into<Spanned<Value>>) {
|
||||
self.list.push(value.into());
|
||||
}
|
||||
|
||||
pub fn into_spanned_value(self) -> Spanned<Value> {
|
||||
Value::List(self.list).spanned(self.span)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpannedListBuilder> for Spanned<Value> {
|
||||
fn from(input: SpannedListBuilder) -> Spanned<Value> {
|
||||
input.into_spanned_value()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SpannedDictBuilder {
|
||||
span: Span,
|
||||
dict: IndexMap<String, Spanned<Value>>,
|
||||
}
|
||||
|
||||
impl SpannedDictBuilder {
|
||||
pub fn new(span: impl Into<Span>) -> SpannedDictBuilder {
|
||||
SpannedDictBuilder {
|
||||
span: span.into(),
|
||||
dict: IndexMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Value>) {
|
||||
self.dict
|
||||
.insert(key.into(), value.into().spanned(self.span));
|
||||
}
|
||||
|
||||
pub fn insert_spanned(&mut self, key: impl Into<String>, value: impl Into<Spanned<Value>>) {
|
||||
self.dict.insert(key.into(), value.into());
|
||||
}
|
||||
|
||||
pub fn into_spanned_value(self) -> Spanned<Value> {
|
||||
self.into_spanned_dict().map(Value::Object)
|
||||
}
|
||||
|
||||
pub fn into_spanned_dict(self) -> Spanned<Dictionary> {
|
||||
Dictionary { entries: self.dict }.spanned(self.span)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpannedDictBuilder> for Spanned<Value> {
|
||||
fn from(input: SpannedDictBuilder) -> Spanned<Value> {
|
||||
input.into_spanned_value()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::{Dictionary, Value};
|
||||
use crate::object::{SpannedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FileType {
|
||||
|
@ -8,10 +9,13 @@ pub enum FileType {
|
|||
Symlink,
|
||||
}
|
||||
|
||||
crate fn dir_entry_dict(entry: &std::fs::DirEntry) -> Result<Dictionary, ShellError> {
|
||||
let mut dict = Dictionary::default();
|
||||
crate fn dir_entry_dict(
|
||||
entry: &std::fs::DirEntry,
|
||||
span: impl Into<Span>,
|
||||
) -> Result<Spanned<Value>, ShellError> {
|
||||
let mut dict = SpannedDictBuilder::new(span);
|
||||
let filename = entry.file_name();
|
||||
dict.add("file name", Value::string(filename.to_string_lossy()));
|
||||
dict.insert("file name", Value::string(filename.to_string_lossy()));
|
||||
|
||||
let metadata = entry.metadata()?;
|
||||
|
||||
|
@ -23,28 +27,28 @@ crate fn dir_entry_dict(entry: &std::fs::DirEntry) -> Result<Dictionary, ShellEr
|
|||
FileType::Symlink
|
||||
};
|
||||
|
||||
dict.add("file type", Value::string(format!("{:?}", kind)));
|
||||
dict.add(
|
||||
dict.insert("file type", Value::string(format!("{:?}", kind)));
|
||||
dict.insert(
|
||||
"readonly",
|
||||
Value::boolean(metadata.permissions().readonly()),
|
||||
);
|
||||
|
||||
dict.add("size", Value::bytes(metadata.len() as u64));
|
||||
dict.insert("size", Value::bytes(metadata.len() as u64));
|
||||
|
||||
match metadata.created() {
|
||||
Ok(c) => dict.add("created", Value::system_date(c)),
|
||||
Ok(c) => dict.insert("created", Value::system_date(c)),
|
||||
Err(_) => {}
|
||||
}
|
||||
|
||||
match metadata.accessed() {
|
||||
Ok(a) => dict.add("accessed", Value::system_date(a)),
|
||||
Ok(a) => dict.insert("accessed", Value::system_date(a)),
|
||||
Err(_) => {}
|
||||
}
|
||||
|
||||
match metadata.modified() {
|
||||
Ok(m) => dict.add("modified", Value::system_date(m)),
|
||||
Ok(m) => dict.insert("modified", Value::system_date(m)),
|
||||
Err(_) => {}
|
||||
}
|
||||
|
||||
Ok(dict)
|
||||
Ok(dict.into_spanned_value())
|
||||
}
|
||||
|
|
23
src/object/into.rs
Normal file
23
src/object/into.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use crate::object::{Primitive, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
impl From<Primitive> for Value {
|
||||
fn from(input: Primitive) -> Value {
|
||||
Value::Primitive(input)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Value {
|
||||
fn from(input: String) -> Value {
|
||||
Value::Primitive(Primitive::String(input))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<Value>> Spanned<T> {
|
||||
pub fn into_spanned_value(self) -> Spanned<Value> {
|
||||
let Spanned { item, span } = self;
|
||||
|
||||
let value = item.into();
|
||||
value.spanned(span)
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
use crate::object::base::Value;
|
||||
use crate::object::dict::Dictionary;
|
||||
use crate::object::{SpannedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
use itertools::join;
|
||||
use sysinfo::ProcessExt;
|
||||
|
||||
crate fn process_dict(proc: &sysinfo::Process) -> Dictionary {
|
||||
let mut dict = Dictionary::default();
|
||||
dict.add("name", Value::string(proc.name()));
|
||||
crate fn process_dict(proc: &sysinfo::Process, span: impl Into<Span>) -> Spanned<Value> {
|
||||
let mut dict = SpannedDictBuilder::new(span);
|
||||
dict.insert("name", Value::string(proc.name()));
|
||||
|
||||
let cmd = proc.cmd();
|
||||
|
||||
|
@ -15,10 +15,10 @@ crate fn process_dict(proc: &sysinfo::Process) -> Dictionary {
|
|||
Value::string(join(cmd, ""))
|
||||
};
|
||||
|
||||
dict.add("cmd", cmd_value);
|
||||
dict.add("cpu", Value::float(proc.cpu_usage() as f64));
|
||||
dict.add("pid", Value::int(proc.pid() as i64));
|
||||
dict.add("status", Value::string(proc.status().to_string()));
|
||||
dict.insert("cmd", cmd_value);
|
||||
dict.insert("cpu", Value::float(proc.cpu_usage() as f64));
|
||||
dict.insert("pid", Value::int(proc.pid() as i64));
|
||||
dict.insert("status", Value::string(proc.status().to_string()));
|
||||
|
||||
dict
|
||||
dict.into_spanned_value()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,139 @@
|
|||
use crate::object::base as value;
|
||||
use crate::parser::hir;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)]
|
||||
pub enum Type {
|
||||
Any,
|
||||
pub trait Type: std::fmt::Debug + Send {
|
||||
type Extractor: ExtractType;
|
||||
|
||||
fn name(&self) -> &'static str;
|
||||
fn coerce(&self) -> Option<hir::ExpressionKindHint> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ExtractType: Sized {
|
||||
fn extract(value: &Spanned<Value>) -> Result<Self, ShellError>;
|
||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)]
|
||||
pub struct Any;
|
||||
|
||||
impl Type for Any {
|
||||
type Extractor = Spanned<Value>;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"Any"
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractType for Spanned<Value> {
|
||||
fn extract(value: &Spanned<Value>) -> Result<Self, ShellError> {
|
||||
Ok(value.clone())
|
||||
}
|
||||
|
||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)]
|
||||
pub struct Integer;
|
||||
|
||||
impl Type for Integer {
|
||||
type Extractor = i64;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"Integer"
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractType for i64 {
|
||||
fn extract(value: &Spanned<Value>) -> Result<i64, ShellError> {
|
||||
match value {
|
||||
&Spanned {
|
||||
item: Value::Primitive(Primitive::Int(int)),
|
||||
..
|
||||
} => Ok(int),
|
||||
other => Err(ShellError::type_error("Integer", other.spanned_type_name())),
|
||||
}
|
||||
}
|
||||
|
||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
||||
match value {
|
||||
v @ Spanned {
|
||||
item: Value::Primitive(Primitive::Int(_)),
|
||||
..
|
||||
} => Ok(v),
|
||||
other => Err(ShellError::type_error("Integer", other.spanned_type_name())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)]
|
||||
pub struct NuString;
|
||||
|
||||
impl Type for NuString {
|
||||
type Extractor = String;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"Integer"
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractType for String {
|
||||
fn extract(value: &Spanned<Value>) -> Result<String, ShellError> {
|
||||
match value {
|
||||
Spanned {
|
||||
item: Value::Primitive(Primitive::String(string)),
|
||||
..
|
||||
} => Ok(string.clone()),
|
||||
other => Err(ShellError::type_error("String", other.spanned_type_name())),
|
||||
}
|
||||
}
|
||||
|
||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
||||
match value {
|
||||
v @ Spanned {
|
||||
item: Value::Primitive(Primitive::String(_)),
|
||||
..
|
||||
} => Ok(v),
|
||||
other => Err(ShellError::type_error("String", other.spanned_type_name())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)]
|
||||
pub struct Block;
|
||||
|
||||
impl Type for Block {
|
||||
type Extractor = value::Block;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"Block"
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractType for value::Block {
|
||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
||||
match value {
|
||||
v @ Spanned {
|
||||
item: Value::Block(_),
|
||||
..
|
||||
} => Ok(v),
|
||||
other => Err(ShellError::type_error("Block", other.spanned_type_name())),
|
||||
}
|
||||
}
|
||||
|
||||
fn extract(value: &Spanned<Value>) -> Result<value::Block, ShellError> {
|
||||
match value {
|
||||
Spanned {
|
||||
item: Value::Block(block),
|
||||
..
|
||||
} => Ok(block.clone()),
|
||||
other => Err(ShellError::type_error("Block", other.spanned_type_name())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ crate use parse::flag::Flag;
|
|||
crate use parse::operator::Operator;
|
||||
crate use parse::parser::{nom_input, pipeline};
|
||||
crate use parse::pipeline::{Pipeline, PipelineElement};
|
||||
pub use parse::span::{Span, Spanned};
|
||||
pub use parse::span::{Span, Spanned, SpannedItem};
|
||||
crate use parse::text::Text;
|
||||
crate use parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode};
|
||||
crate use parse::tokens::{RawToken, Token};
|
||||
|
|
|
@ -23,7 +23,7 @@ impl language_reporting::ReportingFiles for Files {
|
|||
0
|
||||
}
|
||||
fn file_name(&self, _file: Self::FileId) -> FileName {
|
||||
FileName::Verbatim(format!("<eval>"))
|
||||
FileName::Verbatim(format!("shell"))
|
||||
}
|
||||
fn byte_index(&self, _file: Self::FileId, _line: usize, _column: usize) -> Option<usize> {
|
||||
unimplemented!("byte_index")
|
||||
|
|
|
@ -53,15 +53,15 @@ fn trace_step<'a, T: Debug>(
|
|||
name: &str,
|
||||
block: impl FnOnce(NomSpan<'a>) -> IResult<NomSpan<'a>, T>,
|
||||
) -> IResult<NomSpan<'a>, T> {
|
||||
trace!("+ before {} @ {:?}", name, input);
|
||||
trace!(target: "nu::lite_parse", "+ before {} @ {:?}", name, input);
|
||||
match block(input) {
|
||||
Ok((input, result)) => {
|
||||
trace!("after {} @ {:?} -> {:?}", name, input, result);
|
||||
trace!(target: "nu::lite_parse", "after {} @ {:?} -> {:?}", name, input, result);
|
||||
Ok((input, result))
|
||||
}
|
||||
|
||||
Err(e) => {
|
||||
trace!("- failed {} :: {:?}", name, e);
|
||||
trace!(target: "nu::lite_parse", "- failed {} :: {:?}", name, e);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::Text;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
#[derive(
|
||||
new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash, Getters,
|
||||
|
@ -12,10 +13,23 @@ pub struct Spanned<T> {
|
|||
pub item: T,
|
||||
}
|
||||
|
||||
impl<T> Spanned<T> {
|
||||
pub fn spanned(self, span: impl Into<Span>) -> Spanned<T> {
|
||||
Spanned::from_item(self.item, span.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SpannedItem: Sized {
|
||||
fn spanned(self, span: impl Into<Span>) -> Spanned<Self> {
|
||||
Spanned::from_item(self, span.into())
|
||||
}
|
||||
|
||||
// For now, this is a temporary facility. In many cases, there are other useful spans that we
|
||||
// could be using, such as the original source spans of JSON or Toml files, but we don't yet
|
||||
// have the infrastructure to make that work.
|
||||
fn spanned_unknown(self) -> Spanned<Self> {
|
||||
Spanned::from_item(self, (0, 0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SpannedItem for T {}
|
||||
|
@ -64,6 +78,15 @@ pub struct Span {
|
|||
// source: &'source str,
|
||||
}
|
||||
|
||||
impl From<Option<Span>> for Span {
|
||||
fn from(input: Option<Span>) -> Span {
|
||||
match input {
|
||||
None => Span { start: 0, end: 0 },
|
||||
Some(span) => span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<&Spanned<T>> for Span {
|
||||
fn from(input: &Spanned<T>) -> Span {
|
||||
input.span
|
||||
|
@ -113,6 +136,14 @@ impl From<&std::ops::Range<usize>> for Span {
|
|||
}
|
||||
|
||||
impl Span {
|
||||
pub fn unknown() -> Span {
|
||||
Span { start: 0, end: 0 }
|
||||
}
|
||||
|
||||
pub fn is_unknown(&self) -> bool {
|
||||
self.start == 0 && self.end == 0
|
||||
}
|
||||
|
||||
pub fn slice(&self, source: &'a str) -> &'a str {
|
||||
&source[self.start..self.end]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::errors::{ArgumentError, ShellError};
|
||||
use crate::parser::registry::{CommandConfig, CommandRegistry, NamedType};
|
||||
use crate::parser::registry::{CommandConfig, CommandRegistry, NamedType, PositionalType};
|
||||
use crate::parser::{baseline_parse_tokens, CallNode, Span, Spanned};
|
||||
use crate::parser::{
|
||||
hir::{self, NamedArguments},
|
||||
|
@ -78,7 +78,7 @@ fn parse_command_tail(
|
|||
trace_remaining("nodes", tail.clone(), source);
|
||||
|
||||
for (name, kind) in config.named() {
|
||||
trace!("looking for {} : {:?}", name, kind);
|
||||
trace!(target: "nu::parse", "looking for {} : {:?}", name, kind);
|
||||
|
||||
match kind {
|
||||
NamedType::Switch => {
|
||||
|
@ -86,17 +86,18 @@ fn parse_command_tail(
|
|||
|
||||
named.insert_switch(name, flag);
|
||||
}
|
||||
NamedType::Mandatory(kind) => match extract_mandatory(name, tail, source, command_span)
|
||||
{
|
||||
NamedType::Mandatory(kind) => {
|
||||
match extract_mandatory(config, name, tail, source, command_span) {
|
||||
Err(err) => return Err(err), // produce a correct diagnostic
|
||||
Ok((pos, flag)) => {
|
||||
tail.move_to(pos);
|
||||
|
||||
if tail.at_end() {
|
||||
return Err(ShellError::ArgumentError {
|
||||
error: ArgumentError::MissingValueForName(name.to_string()),
|
||||
span: flag.span,
|
||||
});
|
||||
return Err(ShellError::argument_error(
|
||||
config.name.clone(),
|
||||
ArgumentError::MissingValueForName(name.to_string()),
|
||||
flag.span,
|
||||
));
|
||||
}
|
||||
|
||||
let expr = hir::baseline_parse_next_expr(
|
||||
|
@ -109,17 +110,19 @@ fn parse_command_tail(
|
|||
tail.restart();
|
||||
named.insert_mandatory(name, expr);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
NamedType::Optional(kind) => match extract_optional(name, tail, source) {
|
||||
Err(err) => return Err(err), // produce a correct diagnostic
|
||||
Ok(Some((pos, flag))) => {
|
||||
tail.move_to(pos);
|
||||
|
||||
if tail.at_end() {
|
||||
return Err(ShellError::ArgumentError {
|
||||
error: ArgumentError::MissingValueForName(name.to_string()),
|
||||
span: flag.span,
|
||||
});
|
||||
return Err(ShellError::argument_error(
|
||||
config.name().clone(),
|
||||
ArgumentError::MissingValueForName(name.to_string()),
|
||||
flag.span,
|
||||
));
|
||||
}
|
||||
|
||||
let expr = hir::baseline_parse_next_expr(
|
||||
|
@ -144,38 +147,34 @@ fn parse_command_tail(
|
|||
trace_remaining("after named", tail.clone(), source);
|
||||
|
||||
let mut positional = vec![];
|
||||
let mandatory = config.mandatory_positional();
|
||||
|
||||
for arg in mandatory {
|
||||
trace!("Processing mandatory {:?}", arg);
|
||||
for arg in config.positional() {
|
||||
trace!("Processing positional {:?}", arg);
|
||||
|
||||
match arg {
|
||||
PositionalType::Mandatory(..) => {
|
||||
if tail.len() == 0 {
|
||||
return Err(ShellError::ArgumentError {
|
||||
error: ArgumentError::MissingMandatoryPositional(arg.name().to_string()),
|
||||
span: command_span,
|
||||
});
|
||||
return Err(ShellError::argument_error(
|
||||
config.name().clone(),
|
||||
ArgumentError::MissingMandatoryPositional(arg.name().to_string()),
|
||||
command_span,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let result = hir::baseline_parse_next_expr(tail, registry, source, arg.to_coerce_hint())?;
|
||||
|
||||
positional.push(result);
|
||||
}
|
||||
|
||||
trace_remaining("after mandatory", tail.clone(), source);
|
||||
|
||||
let optional = config.optional_positional();
|
||||
|
||||
for arg in optional {
|
||||
PositionalType::Optional(..) => {
|
||||
if tail.len() == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = hir::baseline_parse_next_expr(tail, registry, source, arg.to_coerce_hint())?;
|
||||
|
||||
positional.push(result);
|
||||
}
|
||||
|
||||
trace_remaining("after optional", tail.clone(), source);
|
||||
trace_remaining("after positional", tail.clone(), source);
|
||||
|
||||
// TODO: Only do this if rest params are specified
|
||||
let remainder = baseline_parse_tokens(tail, registry, source)?;
|
||||
|
@ -207,6 +206,7 @@ fn extract_switch(name: &str, tokens: &mut hir::TokensIterator<'_>, source: &Tex
|
|||
}
|
||||
|
||||
fn extract_mandatory(
|
||||
config: &CommandConfig,
|
||||
name: &str,
|
||||
tokens: &mut hir::TokensIterator<'a>,
|
||||
source: &Text,
|
||||
|
@ -215,10 +215,11 @@ fn extract_mandatory(
|
|||
let flag = tokens.extract(|t| t.as_flag(name, source));
|
||||
|
||||
match flag {
|
||||
None => Err(ShellError::ArgumentError {
|
||||
error: ArgumentError::MissingMandatoryFlag(name.to_string()),
|
||||
None => Err(ShellError::argument_error(
|
||||
config.name().clone(),
|
||||
ArgumentError::MissingMandatoryFlag(name.to_string()),
|
||||
span,
|
||||
}),
|
||||
)),
|
||||
|
||||
Some((pos, flag)) => {
|
||||
tokens.remove(pos);
|
||||
|
|
|
@ -36,22 +36,39 @@ impl NamedValue {
|
|||
#[allow(unused)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PositionalType {
|
||||
Value(String),
|
||||
Block(String),
|
||||
Mandatory(String, PositionalValue),
|
||||
Optional(String, PositionalValue),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PositionalValue {
|
||||
Value,
|
||||
Block,
|
||||
}
|
||||
|
||||
impl PositionalType {
|
||||
pub fn mandatory(name: &str) -> PositionalType {
|
||||
PositionalType::Mandatory(name.to_string(), PositionalValue::Value)
|
||||
}
|
||||
|
||||
pub fn mandatory_block(name: &str) -> PositionalType {
|
||||
PositionalType::Mandatory(name.to_string(), PositionalValue::Block)
|
||||
}
|
||||
|
||||
crate fn to_coerce_hint(&self) -> Option<ExpressionKindHint> {
|
||||
match self {
|
||||
PositionalType::Value(_) => None,
|
||||
PositionalType::Block(_) => Some(ExpressionKindHint::Block),
|
||||
PositionalType::Mandatory(_, PositionalValue::Block)
|
||||
| PositionalType::Optional(_, PositionalValue::Block) => {
|
||||
Some(ExpressionKindHint::Block)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
crate fn name(&self) -> &str {
|
||||
match self {
|
||||
PositionalType::Value(s) => s,
|
||||
PositionalType::Block(s) => s,
|
||||
PositionalType::Mandatory(s, _) => s,
|
||||
PositionalType::Optional(s, _) => s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,14 +77,11 @@ impl PositionalType {
|
|||
#[get = "crate"]
|
||||
pub struct CommandConfig {
|
||||
pub name: String,
|
||||
pub mandatory_positional: Vec<PositionalType>,
|
||||
pub optional_positional: Vec<PositionalType>,
|
||||
pub positional: Vec<PositionalType>,
|
||||
pub rest_positional: bool,
|
||||
pub named: IndexMap<String, NamedType>,
|
||||
pub is_filter: bool,
|
||||
pub is_sink: bool,
|
||||
pub can_load: Vec<String>,
|
||||
pub can_save: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, new, Serialize, Deserialize)]
|
||||
|
@ -87,7 +101,7 @@ impl fmt::Debug for DebugPositional<'a> {
|
|||
None => write!(f, "None"),
|
||||
Some(positional) => f
|
||||
.debug_list()
|
||||
.entries(positional.iter().map(|p| p.item().debug()))
|
||||
.entries(positional.iter().map(|p| p.debug()))
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +118,7 @@ impl fmt::Debug for DebugNamed<'a> {
|
|||
None => write!(f, "None"),
|
||||
Some(named) => f
|
||||
.debug_map()
|
||||
.entries(named.iter().map(|(k, v)| (k, v.item().debug())))
|
||||
.entries(named.iter().map(|(k, v)| (k, v.debug())))
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{Args, CommandConfig, ReturnValue, ShellError, Value};
|
||||
use crate::{Args, CommandConfig, ReturnValue, ShellError, Spanned, Value};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io;
|
||||
|
||||
|
@ -11,11 +11,11 @@ pub trait Plugin {
|
|||
))
|
||||
}
|
||||
#[allow(unused)]
|
||||
fn filter(&mut self, input: Value) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
Err(ShellError::string("`filter` not implemented in plugin"))
|
||||
}
|
||||
#[allow(unused)]
|
||||
fn sink(&mut self, args: Args, input: Vec<Value>) {}
|
||||
fn sink(&mut self, args: Args, input: Vec<Spanned<Value>>) {}
|
||||
|
||||
fn quit(&mut self) {
|
||||
return;
|
||||
|
@ -33,7 +33,11 @@ pub fn serve_plugin(plugin: &mut dyn Plugin) {
|
|||
send_response(plugin.config());
|
||||
}
|
||||
Ok(NuCommand::begin_filter { params }) => {
|
||||
let _ = plugin.begin_filter(params);
|
||||
send_response(
|
||||
plugin
|
||||
.begin_filter(params)
|
||||
.map(|_| Vec::<ReturnValue>::new()),
|
||||
);
|
||||
}
|
||||
Ok(NuCommand::filter { params }) => {
|
||||
send_response(plugin.filter(params));
|
||||
|
@ -66,7 +70,11 @@ pub fn serve_plugin(plugin: &mut dyn Plugin) {
|
|||
send_response(plugin.config());
|
||||
}
|
||||
Ok(NuCommand::begin_filter { params }) => {
|
||||
let _ = plugin.begin_filter(params);
|
||||
send_response(
|
||||
plugin
|
||||
.begin_filter(params)
|
||||
.map(|_| Vec::<ReturnValue>::new()),
|
||||
);
|
||||
}
|
||||
Ok(NuCommand::filter { params }) => {
|
||||
send_response(plugin.filter(params));
|
||||
|
@ -127,7 +135,7 @@ fn send_response<T: Serialize>(result: T) {
|
|||
pub enum NuCommand {
|
||||
config,
|
||||
begin_filter { params: Args },
|
||||
filter { params: Value },
|
||||
sink { params: (Args, Vec<Value>) },
|
||||
filter { params: Spanned<Value> },
|
||||
sink { params: (Args, Vec<Spanned<Value>>) },
|
||||
quit,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crossterm::{cursor, terminal, Attribute, RawScreen};
|
||||
use indexmap::IndexMap;
|
||||
use nu::{serve_plugin, Args, CommandConfig, Plugin, ShellError, Value};
|
||||
use nu::{serve_plugin, Args, CommandConfig, Plugin, ShellError, Spanned, Value};
|
||||
use pretty_hex::*;
|
||||
|
||||
struct BinaryView;
|
||||
|
@ -15,10 +15,7 @@ impl Plugin for BinaryView {
|
|||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
name: "binaryview".to_string(),
|
||||
mandatory_positional: vec![],
|
||||
optional_positional: vec![],
|
||||
can_load: vec![],
|
||||
can_save: vec![],
|
||||
positional: vec![],
|
||||
is_filter: false,
|
||||
is_sink: true,
|
||||
named: IndexMap::new(),
|
||||
|
@ -26,10 +23,13 @@ impl Plugin for BinaryView {
|
|||
})
|
||||
}
|
||||
|
||||
fn sink(&mut self, _args: Args, input: Vec<Value>) {
|
||||
fn sink(&mut self, _args: Args, input: Vec<Spanned<Value>>) {
|
||||
for v in input {
|
||||
match v {
|
||||
Value::Binary(b) => {
|
||||
Spanned {
|
||||
item: Value::Binary(b),
|
||||
..
|
||||
} => {
|
||||
let _ = view_binary(&b);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, Args, CommandConfig, Plugin, PositionalType, Primitive, ReturnValue, ShellError,
|
||||
Spanned, Value,
|
||||
serve_plugin, Args, CommandConfig, Plugin, PositionalType, Primitive, ReturnSuccess,
|
||||
ReturnValue, ShellError, Spanned, SpannedItem, Value,
|
||||
};
|
||||
|
||||
struct Inc {
|
||||
|
@ -17,10 +17,7 @@ impl Plugin for Inc {
|
|||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
name: "inc".to_string(),
|
||||
mandatory_positional: vec![],
|
||||
optional_positional: vec![PositionalType::Value("Increment".into())],
|
||||
can_load: vec![],
|
||||
can_save: vec![],
|
||||
positional: vec![PositionalType::mandatory("Increment")],
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
named: IndexMap::new(),
|
||||
|
@ -45,14 +42,16 @@ impl Plugin for Inc {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Value) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
match input {
|
||||
Value::Primitive(Primitive::Int(i)) => {
|
||||
Ok(vec![ReturnValue::Value(Value::int(i + self.inc_by))])
|
||||
}
|
||||
Value::Primitive(Primitive::Bytes(b)) => Ok(vec![ReturnValue::Value(Value::bytes(
|
||||
b + self.inc_by as u64,
|
||||
))]),
|
||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
let span = input.span;
|
||||
|
||||
match input.item {
|
||||
Value::Primitive(Primitive::Int(i)) => Ok(vec![ReturnSuccess::value(
|
||||
Value::int(i + self.inc_by).spanned(span),
|
||||
)]),
|
||||
Value::Primitive(Primitive::Bytes(b)) => Ok(vec![ReturnSuccess::value(
|
||||
Value::bytes(b + self.inc_by as u64).spanned(span),
|
||||
)]),
|
||||
x => Err(ShellError::string(format!(
|
||||
"Unrecognized type in stream: {:?}",
|
||||
x
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, Args, CommandConfig, Plugin, Primitive, ReturnValue, ShellError, Spanned, Value,
|
||||
serve_plugin, Args, CommandConfig, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError,
|
||||
Spanned, Value,
|
||||
};
|
||||
|
||||
struct NewSkip {
|
||||
|
@ -16,10 +17,7 @@ impl Plugin for NewSkip {
|
|||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
name: "skip".to_string(),
|
||||
mandatory_positional: vec![],
|
||||
optional_positional: vec![],
|
||||
can_load: vec![],
|
||||
can_save: vec![],
|
||||
positional: vec![],
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
named: IndexMap::new(),
|
||||
|
@ -36,7 +34,7 @@ impl Plugin for NewSkip {
|
|||
} => {
|
||||
self.skip_amount = i;
|
||||
}
|
||||
_ => return Err(ShellError::string("Unrecognized type in params")),
|
||||
_ => return Err(ShellError::labeled_error("Unrecognized type in params", "expected an integer", arg.span)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,9 +42,9 @@ impl Plugin for NewSkip {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Value) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
if self.skip_amount == 0 {
|
||||
Ok(vec![ReturnValue::Value(input)])
|
||||
Ok(vec![ReturnSuccess::value(input)])
|
||||
} else {
|
||||
self.skip_amount -= 1;
|
||||
Ok(vec![])
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use derive_new::new;
|
||||
use indexmap::IndexMap;
|
||||
use nu::{serve_plugin, Args, CommandConfig, Plugin, ShellError, Value};
|
||||
use nu::{serve_plugin, Args, CommandConfig, Plugin, ShellError, Spanned, Value};
|
||||
use ptree::item::StringItem;
|
||||
use ptree::output::print_tree_with;
|
||||
use ptree::print_config::PrintConfig;
|
||||
|
@ -31,7 +31,6 @@ impl TreeView {
|
|||
}
|
||||
}
|
||||
Value::Block(_) => {}
|
||||
Value::Error(_) => {}
|
||||
Value::Filesystem => {}
|
||||
Value::Binary(_) => {}
|
||||
}
|
||||
|
@ -85,10 +84,7 @@ impl Plugin for TreeViewer {
|
|||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
name: "tree".to_string(),
|
||||
mandatory_positional: vec![],
|
||||
optional_positional: vec![],
|
||||
can_load: vec![],
|
||||
can_save: vec![],
|
||||
positional: vec![],
|
||||
is_filter: false,
|
||||
is_sink: true,
|
||||
named: IndexMap::new(),
|
||||
|
@ -96,12 +92,11 @@ impl Plugin for TreeViewer {
|
|||
})
|
||||
}
|
||||
|
||||
fn sink(&mut self, _args: Args, input: Vec<Value>) {
|
||||
fn sink(&mut self, _args: Args, input: Vec<Spanned<Value>>) {
|
||||
if input.len() > 0 {
|
||||
for i in input.iter() {
|
||||
let view = TreeView::from_value(&i);
|
||||
let _ = view.render_view();
|
||||
//handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,84 @@
|
|||
#[macro_export]
|
||||
macro_rules! stream {
|
||||
($($expr:expr),*) => {{
|
||||
let mut v = VecDeque::new();
|
||||
|
||||
$(
|
||||
v.push_back($expr);
|
||||
)*
|
||||
|
||||
v
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! trace_stream {
|
||||
(target: $target:tt, $desc:tt = $expr:expr) => {{
|
||||
if log::log_enabled!(target: $target, log::Level::Trace) {
|
||||
use futures::stream::StreamExt;
|
||||
// Blocking is generally quite bad, but this is for debugging
|
||||
// let mut local = futures::executor::LocalPool::new();
|
||||
// let objects = local.run_until($expr.into_vec());
|
||||
// let objects: Vec<_> = futures::executor::block_on($expr.into_vec());
|
||||
|
||||
let objects = $expr.values.inspect(|o| {
|
||||
trace!(target: $target, "{} = {:#?}", $desc, o.debug());
|
||||
});
|
||||
|
||||
$crate::stream::InputStream::from_stream(objects.boxed())
|
||||
} else {
|
||||
$expr
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
crate use crate::cli::MaybeOwned;
|
||||
crate use crate::commands::command::{Command, CommandAction, CommandArgs, ReturnValue};
|
||||
crate use crate::commands::command::{
|
||||
Command, CommandAction, CommandArgs, ReturnSuccess, ReturnValue,
|
||||
};
|
||||
crate use crate::context::Context;
|
||||
crate use crate::env::host::handle_unexpected;
|
||||
crate use crate::env::{Environment, Host};
|
||||
crate use crate::errors::ShellError;
|
||||
crate use crate::object::types::ExtractType;
|
||||
crate use crate::object::{Primitive, Value};
|
||||
crate use crate::stream::{single_output, InputStream, OutputStream};
|
||||
crate use crate::parser::{Span, Spanned, SpannedItem};
|
||||
crate use crate::stream::{InputStream, OutputStream};
|
||||
crate use crate::Text;
|
||||
crate use futures::stream::BoxStream;
|
||||
crate use futures::Stream;
|
||||
crate use futures::{FutureExt, StreamExt};
|
||||
crate use std::collections::VecDeque;
|
||||
crate use std::pin::Pin;
|
||||
crate use std::future::Future;
|
||||
crate use std::sync::{Arc, Mutex};
|
||||
|
||||
pub trait FromInputStream {
|
||||
fn from_input_stream(self) -> OutputStream;
|
||||
}
|
||||
|
||||
impl<T> FromInputStream for T
|
||||
where
|
||||
T: Stream<Item = Spanned<Value>> + Send + 'static,
|
||||
{
|
||||
fn from_input_stream(self) -> OutputStream {
|
||||
OutputStream {
|
||||
values: self.map(ReturnSuccess::value).boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToOutputStream {
|
||||
fn to_output_stream(self) -> OutputStream;
|
||||
}
|
||||
|
||||
impl<T, U> ToOutputStream for T
|
||||
where
|
||||
T: Stream<Item = U> + Send + 'static,
|
||||
U: Into<ReturnValue>,
|
||||
{
|
||||
fn to_output_stream(self) -> OutputStream {
|
||||
OutputStream {
|
||||
values: self.map(|item| item.into()).boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
129
src/stream.rs
129
src/stream.rs
|
@ -1,12 +1,123 @@
|
|||
use crate::prelude::*;
|
||||
use futures::stream::BoxStream;
|
||||
|
||||
pub type InputStream = BoxStream<'static, Value>;
|
||||
pub type OutputStream = BoxStream<'static, ReturnValue>;
|
||||
|
||||
crate fn single_output(item: Value) -> OutputStream {
|
||||
let value = ReturnValue::Value(item);
|
||||
let mut vec = VecDeque::new();
|
||||
vec.push_back(value);
|
||||
vec.boxed()
|
||||
pub struct InputStream {
|
||||
crate values: BoxStream<'static, Spanned<Value>>,
|
||||
}
|
||||
|
||||
impl InputStream {
|
||||
pub fn into_vec(self) -> impl Future<Output = Vec<Spanned<Value>>> {
|
||||
self.values.collect()
|
||||
}
|
||||
|
||||
pub fn from_stream(input: impl Stream<Item = Spanned<Value>> + Send + 'static) -> InputStream {
|
||||
InputStream {
|
||||
values: input.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BoxStream<'static, Spanned<Value>>> for InputStream {
|
||||
fn from(input: BoxStream<'static, Spanned<Value>>) -> InputStream {
|
||||
InputStream { values: input }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VecDeque<Spanned<Value>>> for InputStream {
|
||||
fn from(input: VecDeque<Spanned<Value>>) -> InputStream {
|
||||
InputStream {
|
||||
values: input.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Spanned<Value>>> for InputStream {
|
||||
fn from(input: Vec<Spanned<Value>>) -> InputStream {
|
||||
let mut list = VecDeque::default();
|
||||
list.extend(input);
|
||||
|
||||
InputStream {
|
||||
values: list.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OutputStream {
|
||||
crate values: BoxStream<'static, ReturnValue>,
|
||||
}
|
||||
|
||||
impl OutputStream {
|
||||
pub fn empty() -> OutputStream {
|
||||
let v: VecDeque<ReturnValue> = VecDeque::new();
|
||||
v.into()
|
||||
}
|
||||
|
||||
pub fn from_input(input: impl Stream<Item = Spanned<Value>> + Send + 'static) -> OutputStream {
|
||||
OutputStream {
|
||||
values: input.map(ReturnSuccess::value).boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InputStream> for OutputStream {
|
||||
fn from(input: InputStream) -> OutputStream {
|
||||
OutputStream {
|
||||
values: input.values.map(ReturnSuccess::value).boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BoxStream<'static, Spanned<Value>>> for OutputStream {
|
||||
fn from(input: BoxStream<'static, Spanned<Value>>) -> OutputStream {
|
||||
OutputStream {
|
||||
values: input.map(ReturnSuccess::value).boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BoxStream<'static, ReturnValue>> for OutputStream {
|
||||
fn from(input: BoxStream<'static, ReturnValue>) -> OutputStream {
|
||||
OutputStream { values: input }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VecDeque<ReturnValue>> for OutputStream {
|
||||
fn from(input: VecDeque<ReturnValue>) -> OutputStream {
|
||||
OutputStream {
|
||||
values: input.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VecDeque<Spanned<Value>>> for OutputStream {
|
||||
fn from(input: VecDeque<Spanned<Value>>) -> OutputStream {
|
||||
OutputStream {
|
||||
values: input
|
||||
.into_iter()
|
||||
.map(|i| ReturnSuccess::value(i))
|
||||
.collect::<VecDeque<ReturnValue>>()
|
||||
.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<ReturnValue>> for OutputStream {
|
||||
fn from(input: Vec<ReturnValue>) -> OutputStream {
|
||||
let mut list = VecDeque::default();
|
||||
list.extend(input);
|
||||
|
||||
OutputStream {
|
||||
values: list.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Spanned<Value>>> for OutputStream {
|
||||
fn from(input: Vec<Spanned<Value>>) -> OutputStream {
|
||||
let mut list = VecDeque::default();
|
||||
list.extend(input.into_iter().map(ReturnSuccess::value));
|
||||
|
||||
OutputStream {
|
||||
values: list.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue