From d5d4da0bf874a8ec3d24863c557dd40bb850e71b Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sat, 20 Jul 2019 07:48:14 +1200 Subject: [PATCH 1/4] Add first step of uuid generation and bookkeeping --- Cargo.lock | 2 + Cargo.toml | 1 + src/cli.rs | 1 + src/commands/classified.rs | 16 +++++++- src/commands/command.rs | 10 +++++ src/commands/open.rs | 75 ++++++++++++++++++++++++++------------ src/commands/trim.rs | 2 - src/context.rs | 17 +++++++++ src/errors.rs | 7 +++- src/parser/parse/span.rs | 29 +++++++++++++-- 10 files changed, 128 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3215ea850..5ba1ed079 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1696,6 +1696,7 @@ dependencies = [ "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "toml-query 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3181,6 +3182,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 21d32ad17..f0789c337 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,7 @@ crossterm = "0.9.6" tempfile = "3.1.0" image = "0.21.2" semver = "0.9.0" +uuid = {version = "0.7.4", features = [ "v4", "serde" ]} [dev-dependencies] pretty_assertions = "0.6.1" diff --git a/src/cli.rs b/src/cli.rs index a36e28e07..741f6e573 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -494,6 +494,7 @@ fn classify_command( Ok(ClassifiedCommand::Internal(InternalCommand { command, name_span: Some(head.span().clone()), + span_sources: context.span_sources.clone(), args, })) } diff --git a/src/commands/classified.rs b/src/commands/classified.rs index 7d3fd288f..b6f2fe975 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -1,13 +1,16 @@ use crate::commands::command::Sink; +use crate::context::SpanSource; use crate::parser::{registry::Args, Span, Spanned, TokenNode}; use crate::prelude::*; use bytes::{BufMut, BytesMut}; use futures::stream::StreamExt; use futures_codec::{Decoder, Encoder, Framed}; use log::{log_enabled, trace}; +use std::collections::HashMap; use std::io::{Error, ErrorKind}; use std::sync::Arc; use subprocess::Exec; +use uuid::Uuid; /// A simple `Codec` implementation that splits up data into lines. pub struct LinesCodec {} @@ -116,6 +119,7 @@ impl SinkCommand { crate struct InternalCommand { crate command: Arc, crate name_span: Option, + crate span_sources: HashMap, crate args: Args, } @@ -134,8 +138,13 @@ impl InternalCommand { 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 result = context.run_command( + self.command, + self.name_span.clone(), + self.span_sources, + self.args, + objects, + )?; let mut result = result.values; @@ -146,6 +155,9 @@ impl InternalCommand { CommandAction::ChangePath(path) => { context.env.lock().unwrap().path = path; } + CommandAction::AddSpanSource(uuid, span_source) => { + context.add_span_source(uuid, span_source); + } CommandAction::Exit => std::process::exit(0), }, diff --git a/src/commands/command.rs b/src/commands/command.rs index 6dd31e216..cdd0b1a5c 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -1,3 +1,4 @@ +use crate::context::SpanSource; use crate::errors::ShellError; use crate::object::Value; use crate::parser::{ @@ -7,7 +8,9 @@ use crate::parser::{ use crate::prelude::*; use getset::Getters; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; use std::path::PathBuf; +use uuid::Uuid; #[derive(Getters)] #[get = "crate"] @@ -15,6 +18,7 @@ pub struct CommandArgs { pub host: Arc>, pub env: Arc>, pub name_span: Option, + pub span_sources: HashMap, pub args: Args, pub input: InputStream, } @@ -49,6 +53,7 @@ impl CommandArgs { pub struct SinkCommandArgs { pub ctx: Context, pub name_span: Option, + pub span_sources: HashMap, pub args: Args, pub input: Vec>, } @@ -56,6 +61,7 @@ pub struct SinkCommandArgs { #[derive(Debug, Serialize, Deserialize)] pub enum CommandAction { ChangePath(PathBuf), + AddSpanSource(Uuid, SpanSource), Exit, } @@ -82,6 +88,10 @@ impl ReturnSuccess { Ok(ReturnSuccess::Value(input.into())) } + pub fn action(input: CommandAction) -> ReturnValue { + Ok(ReturnSuccess::Action(input)) + } + pub fn spanned_value(input: Value, span: Span) -> ReturnValue { Ok(ReturnSuccess::Value(Spanned::from_item(input, span))) } diff --git a/src/commands/open.rs b/src/commands/open.rs index fda4fa335..5ca073151 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -1,3 +1,4 @@ +use crate::context::SpanSource; use crate::errors::ShellError; use crate::object::{Primitive, Switch, Value}; use crate::parser::parse::span::Span; @@ -5,6 +6,7 @@ use crate::prelude::*; use mime::Mime; use std::path::{Path, PathBuf}; use std::str::FromStr; +use uuid::Uuid; command! { Open as open(args, path: Spanned, --raw: Switch,) { @@ -21,19 +23,7 @@ command! { let path_str = path.to_str().ok_or(ShellError::type_error("Path", "invalid path".spanned(path.span)))?; - let (file_extension, contents, contents_span) = fetch(&full_path, path_str, path.span)?; - // 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, contents, contents_span, span_source) = fetch(&full_path, path_str, path.span)?; let file_extension = if raw.is_present() { None @@ -41,6 +31,13 @@ command! { file_extension }; + let mut stream = VecDeque::new(); + + if let Some(uuid) = contents_span.source { + // If we have loaded something, track its source + stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(uuid, span_source))) + } + match contents { Value::Primitive(Primitive::String(string)) => stream.push_back(ReturnSuccess::value(parse_as_value( @@ -62,7 +59,7 @@ pub fn fetch( cwd: &PathBuf, location: &str, span: Span, -) -> Result<(Option, Value, Span), ShellError> { +) -> Result<(Option, Value, Span, SpanSource), ShellError> { let mut cwd = cwd.clone(); if location.starts_with("http:") || location.starts_with("https:") { let response = reqwest::get(location); @@ -74,12 +71,14 @@ pub fn fetch( (mime::APPLICATION, mime::XML) => Ok(( Some("xml".to_string()), Value::string(r.text().unwrap()), - span, + Span::unknown_with_uuid(Uuid::new_v4()), + SpanSource::Url(r.url().to_string()), )), (mime::APPLICATION, mime::JSON) => Ok(( Some("json".to_string()), Value::string(r.text().unwrap()), - span, + Span::unknown_with_uuid(Uuid::new_v4()), + SpanSource::Url(r.url().to_string()), )), (mime::APPLICATION, mime::OCTET_STREAM) => { let mut buf: Vec = vec![]; @@ -90,7 +89,12 @@ pub fn fetch( span, ) })?; - Ok((None, Value::Binary(buf), span)) + Ok(( + None, + Value::Binary(buf), + Span::unknown_with_uuid(Uuid::new_v4()), + SpanSource::Url(r.url().to_string()), + )) } (mime::IMAGE, image_ty) => { let mut buf: Vec = vec![]; @@ -101,12 +105,18 @@ pub fn fetch( span, ) })?; - Ok((Some(image_ty.to_string()), Value::Binary(buf), span)) + Ok(( + Some(image_ty.to_string()), + Value::Binary(buf), + Span::unknown_with_uuid(Uuid::new_v4()), + SpanSource::Url(r.url().to_string()), + )) } (mime::TEXT, mime::HTML) => Ok(( Some("html".to_string()), Value::string(r.text().unwrap()), - span, + Span::unknown_with_uuid(Uuid::new_v4()), + SpanSource::Url(r.url().to_string()), )), (mime::TEXT, mime::PLAIN) => { let path_extension = r @@ -120,16 +130,27 @@ pub fn fetch( .map(|name| name.to_string_lossy().to_string()) }); - Ok((path_extension, Value::string(r.text().unwrap()), span)) + Ok(( + path_extension, + Value::string(r.text().unwrap()), + Span::unknown_with_uuid(Uuid::new_v4()), + SpanSource::Url(r.url().to_string()), + )) } (ty, sub_ty) => Ok(( None, Value::string(format!("Not yet support MIME type: {} {}", ty, sub_ty)), - span, + Span::unknown_with_uuid(Uuid::new_v4()), + SpanSource::Url(r.url().to_string()), )), } } - None => Ok((None, Value::string(format!("No content type found")), span)), + None => Ok(( + None, + Value::string(format!("No content type found")), + Span::unknown_with_uuid(Uuid::new_v4()), + SpanSource::Url(r.url().to_string()), + )), }, Err(_) => { return Err(ShellError::labeled_error( @@ -147,9 +168,15 @@ pub fn fetch( cwd.extension() .map(|name| name.to_string_lossy().to_string()), Value::string(s), - span, + Span::unknown_with_uuid(Uuid::new_v4()), + SpanSource::File(cwd.to_string_lossy().to_string()), + )), + Err(_) => Ok(( + None, + Value::Binary(bytes), + Span::unknown_with_uuid(Uuid::new_v4()), + SpanSource::File(cwd.to_string_lossy().to_string()), )), - Err(_) => Ok((None, Value::Binary(bytes), span)), }, Err(_) => { return Err(ShellError::labeled_error( diff --git a/src/commands/trim.rs b/src/commands/trim.rs index e0f2d42b0..838875faa 100644 --- a/src/commands/trim.rs +++ b/src/commands/trim.rs @@ -2,8 +2,6 @@ use crate::errors::ShellError; use crate::object::Value; use crate::prelude::*; -// TODO: "Amount remaining" wrapper - pub fn trim(args: CommandArgs) -> Result { let input = args.input; diff --git a/src/context.rs b/src/context.rs index 05be6ae0f..654e8a3a7 100644 --- a/src/context.rs +++ b/src/context.rs @@ -4,15 +4,24 @@ use crate::parser::{ Span, }; use crate::prelude::*; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; use indexmap::IndexMap; +use std::collections::HashMap; use std::error::Error; use std::sync::Arc; +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum SpanSource { + Url(String), + File(String), +} #[derive(Clone)] pub struct Context { commands: IndexMap>, sinks: IndexMap>, + crate span_sources: HashMap, crate host: Arc>, crate env: Arc>, } @@ -22,6 +31,7 @@ impl Context { Ok(Context { commands: indexmap::IndexMap::new(), sinks: indexmap::IndexMap::new(), + span_sources: HashMap::new(), host: Arc::new(Mutex::new(crate::env::host::BasicHost)), env: Arc::new(Mutex::new(Environment::basic()?)), }) @@ -39,6 +49,10 @@ impl Context { } } + pub fn add_span_source(&mut self, uuid: Uuid, span_source: SpanSource) { + self.span_sources.insert(uuid, span_source); + } + crate fn has_sink(&self, name: &str) -> bool { self.sinks.contains_key(name) } @@ -57,6 +71,7 @@ impl Context { let command_args = SinkCommandArgs { ctx: self.clone(), name_span, + span_sources: self.span_sources.clone(), args, input, }; @@ -80,6 +95,7 @@ impl Context { &mut self, command: Arc, name_span: Option, + span_sources: HashMap, args: Args, input: InputStream, ) -> Result { @@ -87,6 +103,7 @@ impl Context { host: self.host.clone(), env: self.env.clone(), name_span, + span_sources, args, input, }; diff --git a/src/errors.rs b/src/errors.rs index 3b84eba14..8d9f44fd9 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -17,7 +17,12 @@ impl Description { pub fn from(item: Spanned>) -> Description { match item { Spanned { - span: Span { start: 0, end: 0 }, + span: + Span { + start: 0, + end: 0, + source: None, + }, item, } => Description::Synthetic(item.into()), Spanned { span, item } => Description::Source(Spanned::from_item(item.into(), span)), diff --git a/src/parser/parse/span.rs b/src/parser/parse/span.rs index d82f43468..7d6aa7334 100644 --- a/src/parser/parse/span.rs +++ b/src/parser/parse/span.rs @@ -3,6 +3,7 @@ use derive_new::new; use getset::Getters; use serde::Serialize; use serde_derive::Deserialize; +use uuid::Uuid; #[derive( new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash, Getters, @@ -75,13 +76,17 @@ impl Spanned { pub struct Span { crate start: usize, crate end: usize, - // source: &'source str, + pub source: Option, } impl From> for Span { fn from(input: Option) -> Span { match input { - None => Span { start: 0, end: 0 }, + None => Span { + start: 0, + end: 0, + source: None, + }, Some(span) => span, } } @@ -104,6 +109,7 @@ impl From> for Span { Span { start: input.offset, end: input.offset + input.fragment.len(), + source: None, } } } @@ -113,6 +119,7 @@ impl From<(nom5_locate::LocatedSpan, nom5_locate::LocatedSpan)> for Spa Span { start: input.0.offset, end: input.1.offset, + source: None, } } } @@ -122,6 +129,7 @@ impl From<(usize, usize)> for Span { Span { start: input.0, end: input.1, + source: None, } } } @@ -131,13 +139,26 @@ impl From<&std::ops::Range> for Span { Span { start: input.start, end: input.end, + source: None, } } } impl Span { pub fn unknown() -> Span { - Span { start: 0, end: 0 } + Span { + start: 0, + end: 0, + source: None, + } + } + + pub fn unknown_with_uuid(uuid: Uuid) -> Span { + Span { + start: 0, + end: 0, + source: Some(uuid), + } } pub fn is_unknown(&self) -> bool { @@ -154,6 +175,7 @@ impl language_reporting::ReportingSpan for Span { Span { start, end: self.end, + source: None, } } @@ -161,6 +183,7 @@ impl language_reporting::ReportingSpan for Span { Span { start: self.start, end, + source: None, } } From 27dbc1cb9a128fa5ac3fe2fa18f227a0df0d4c34 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sat, 20 Jul 2019 13:12:04 +1200 Subject: [PATCH 2/4] Add syntect (and borrow bat's theme file) --- Cargo.lock | 1 + Cargo.toml | 1 + assets/themes.bin | Bin 0 -> 10247 bytes src/cli.rs | 2 +- src/commands/autoview.rs | 77 +++++++++++++++++++++++++++++++++++++ src/commands/classified.rs | 8 ++-- src/commands/command.rs | 6 +-- src/context.rs | 30 ++++++++++++--- src/lib.rs | 1 + src/main.rs | 4 +- 10 files changed, 113 insertions(+), 17 deletions(-) create mode 100644 assets/themes.bin diff --git a/Cargo.lock b/Cargo.lock index 5ba1ed079..c7d6cea2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1689,6 +1689,7 @@ dependencies = [ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", "subprocess 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "syntect 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sys-info 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", "sysinfo 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index f0789c337..e47ccfcfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,6 +76,7 @@ tempfile = "3.1.0" image = "0.21.2" semver = "0.9.0" uuid = {version = "0.7.4", features = [ "v4", "serde" ]} +syntect = "3.2.0" [dev-dependencies] pretty_assertions = "0.6.1" diff --git a/assets/themes.bin b/assets/themes.bin new file mode 100644 index 0000000000000000000000000000000000000000..23ad91328066c5b6bd7ab332b807a8f81736aa1c GIT binary patch literal 10247 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 NWD<6?`G3L=vBYGeDiQzy literal 0 HcmV?d00001 diff --git a/src/cli.rs b/src/cli.rs index 741f6e573..bde6f770e 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -494,7 +494,7 @@ fn classify_command( Ok(ClassifiedCommand::Internal(InternalCommand { command, name_span: Some(head.span().clone()), - span_sources: context.span_sources.clone(), + source_map: context.source_map.clone(), args, })) } diff --git a/src/commands/autoview.rs b/src/commands/autoview.rs index e9f6599f8..d13d324f9 100644 --- a/src/commands/autoview.rs +++ b/src/commands/autoview.rs @@ -1,7 +1,9 @@ use crate::commands::command::SinkCommandArgs; +use crate::context::{SourceMap, SpanSource}; use crate::errors::ShellError; use crate::format::GenericView; use crate::prelude::*; +use std::path::Path; pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> { if args.input.len() > 0 { @@ -11,6 +13,8 @@ pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> { } = args.input[0] { args.ctx.get_sink("binaryview").run(args)?; + } else if is_single_text_value(&args.input) { + view_text_value(&args.input[0], &args.source_map); } else if equal_shapes(&args.input) { args.ctx.get_sink("table").run(args)?; } else { @@ -44,3 +48,76 @@ fn equal_shapes(input: &Vec>) -> bool { true } + +fn is_single_text_value(input: &Vec>) -> bool { + if input.len() != 1 { + return false; + } + if let Spanned { + item: Value::Primitive(Primitive::String(_)), + .. + } = input[0] + { + true + } else { + false + } +} + +fn view_text_value(value: &Spanned, source_map: &SourceMap) { + match value { + Spanned { + item: Value::Primitive(Primitive::String(s)), + span, + } => { + let source = span.source.map(|x| source_map.get(&x)).flatten(); + + if let Some(source) = source { + match source { + SpanSource::File(file) => { + let path = Path::new(file); + match path.extension() { + Some(extension) => { + use syntect::easy::HighlightLines; + use syntect::highlighting::{Style, ThemeSet}; + use syntect::parsing::SyntaxSet; + use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings}; + + // Load these once at the start of your program + let ps = SyntaxSet::load_defaults_newlines(); + + if let Some(syntax) = + ps.find_syntax_by_extension(extension.to_str().unwrap()) + { + let ts: ThemeSet = syntect::dumps::from_binary(include_bytes!( + "../../assets/themes.bin" + )); + let mut h = + HighlightLines::new(syntax, &ts.themes["OneHalfDark"]); + + for line in LinesWithEndings::from(s) { + let ranges: Vec<(Style, &str)> = h.highlight(line, &ps); + let escaped = + as_24_bit_terminal_escaped(&ranges[..], false); + print!("{}", escaped); + } + } else { + println!("{}", s); + } + } + _ => { + println!("{}", s); + } + } + } + _ => { + println!("{}", s); + } + } + } else { + println!("{}", s); + } + } + _ => {} + } +} diff --git a/src/commands/classified.rs b/src/commands/classified.rs index b6f2fe975..da4ce706c 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -1,16 +1,14 @@ use crate::commands::command::Sink; -use crate::context::SpanSource; +use crate::context::SourceMap; use crate::parser::{registry::Args, Span, Spanned, TokenNode}; use crate::prelude::*; use bytes::{BufMut, BytesMut}; use futures::stream::StreamExt; use futures_codec::{Decoder, Encoder, Framed}; use log::{log_enabled, trace}; -use std::collections::HashMap; use std::io::{Error, ErrorKind}; use std::sync::Arc; use subprocess::Exec; -use uuid::Uuid; /// A simple `Codec` implementation that splits up data into lines. pub struct LinesCodec {} @@ -119,7 +117,7 @@ impl SinkCommand { crate struct InternalCommand { crate command: Arc, crate name_span: Option, - crate span_sources: HashMap, + crate source_map: SourceMap, crate args: Args, } @@ -141,7 +139,7 @@ impl InternalCommand { let result = context.run_command( self.command, self.name_span.clone(), - self.span_sources, + self.source_map, self.args, objects, )?; diff --git a/src/commands/command.rs b/src/commands/command.rs index cdd0b1a5c..5bc2e0877 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -1,3 +1,4 @@ +use crate::context::SourceMap; use crate::context::SpanSource; use crate::errors::ShellError; use crate::object::Value; @@ -8,7 +9,6 @@ use crate::parser::{ use crate::prelude::*; use getset::Getters; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; use std::path::PathBuf; use uuid::Uuid; @@ -18,7 +18,7 @@ pub struct CommandArgs { pub host: Arc>, pub env: Arc>, pub name_span: Option, - pub span_sources: HashMap, + pub source_map: SourceMap, pub args: Args, pub input: InputStream, } @@ -53,7 +53,7 @@ impl CommandArgs { pub struct SinkCommandArgs { pub ctx: Context, pub name_span: Option, - pub span_sources: HashMap, + pub source_map: SourceMap, pub args: Args, pub input: Vec>, } diff --git a/src/context.rs b/src/context.rs index 654e8a3a7..94d15aab5 100644 --- a/src/context.rs +++ b/src/context.rs @@ -17,11 +17,29 @@ pub enum SpanSource { Url(String), File(String), } + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct SourceMap(HashMap); + +impl SourceMap { + pub fn insert(&mut self, uuid: Uuid, span_source: SpanSource) { + self.0.insert(uuid, span_source); + } + + pub fn get(&self, uuid: &Uuid) -> Option<&SpanSource> { + self.0.get(uuid) + } + + pub fn new() -> SourceMap { + SourceMap(HashMap::new()) + } +} + #[derive(Clone)] pub struct Context { commands: IndexMap>, sinks: IndexMap>, - crate span_sources: HashMap, + crate source_map: SourceMap, crate host: Arc>, crate env: Arc>, } @@ -31,7 +49,7 @@ impl Context { Ok(Context { commands: indexmap::IndexMap::new(), sinks: indexmap::IndexMap::new(), - span_sources: HashMap::new(), + source_map: SourceMap::new(), host: Arc::new(Mutex::new(crate::env::host::BasicHost)), env: Arc::new(Mutex::new(Environment::basic()?)), }) @@ -50,7 +68,7 @@ impl Context { } pub fn add_span_source(&mut self, uuid: Uuid, span_source: SpanSource) { - self.span_sources.insert(uuid, span_source); + self.source_map.insert(uuid, span_source); } crate fn has_sink(&self, name: &str) -> bool { @@ -71,7 +89,7 @@ impl Context { let command_args = SinkCommandArgs { ctx: self.clone(), name_span, - span_sources: self.span_sources.clone(), + source_map: self.source_map.clone(), args, input, }; @@ -95,7 +113,7 @@ impl Context { &mut self, command: Arc, name_span: Option, - span_sources: HashMap, + source_map: SourceMap, args: Args, input: InputStream, ) -> Result { @@ -103,7 +121,7 @@ impl Context { host: self.host.clone(), env: self.env.clone(), name_span, - span_sources, + source_map, args, input, }; diff --git a/src/lib.rs b/src/lib.rs index 4528be06b..13a48915c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ #![feature(bind_by_move_pattern_guards)] #![feature(box_syntax)] #![feature(type_ascription)] +#![feature(option_flattening)] #[macro_use] mod prelude; diff --git a/src/main.rs b/src/main.rs index afb0bb32a..9ad29a625 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,8 +9,8 @@ use log::LevelFilter; use std::error::Error; fn main() -> Result<(), Box> { - let matches = App::new("nu shell") - .version("0.5") + let matches = App::new("nushell") + .version("0.1.3") .arg( Arg::with_name("loglevel") .short("l") From 08f6d29b79e17ad40347c53fb5662967b6138247 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sat, 20 Jul 2019 13:18:27 +1200 Subject: [PATCH 3/4] Fix race condition in test --- tests/commands_test.rs | 74 ++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/tests/commands_test.rs b/tests/commands_test.rs index 30aa84799..52c8b2017 100644 --- a/tests/commands_test.rs +++ b/tests/commands_test.rs @@ -1,7 +1,7 @@ mod helpers; -use helpers as h; use h::in_directory as cwd; +use helpers as h; #[test] fn lines() { @@ -14,18 +14,22 @@ fn lines() { #[test] fn open_csv() { - nu!(output, + nu!( + output, cwd("tests/fixtures/formats"), - "open caco3_plastics.csv | get root | first 1 | get origin | echo $it"); + "open caco3_plastics.csv | get root | first 1 | get origin | echo $it" + ); assert_eq!(output, "SPAIN"); } #[test] fn open_toml() { - nu!(output, - cwd("tests/fixtures/formats"), - "open cargo_sample.toml | get package.edition | echo $it"); + nu!( + output, + cwd("tests/fixtures/formats"), + "open cargo_sample.toml | get package.edition | echo $it" + ); assert_eq!(output, "2018"); } @@ -41,32 +45,40 @@ fn open_json() { #[test] fn open_xml() { - nu!(output, + nu!( + output, cwd("tests/fixtures/formats"), - "open jonathan.xml | get rss.channel.item.link | echo $it"); + "open jonathan.xml | get rss.channel.item.link | echo $it" + ); - assert_eq!(output, "http://www.jonathanturner.org/2015/10/off-to-new-adventures.html") + assert_eq!( + output, + "http://www.jonathanturner.org/2015/10/off-to-new-adventures.html" + ) } #[test] fn open_ini() { - nu!(output, + nu!( + output, cwd("tests/fixtures/formats"), - "open sample.ini | get SectionOne.integer | echo $it"); + "open sample.ini | get SectionOne.integer | echo $it" + ); assert_eq!(output, "1234") } #[test] fn open_error_if_file_not_found() { - nu_error!(output, + nu_error!( + output, cwd("tests/fixtures/formats"), - "open i_dont_exist.txt | echo $it"); + "open i_dont_exist.txt | echo $it" + ); assert!(output.contains("File cound not be opened")); } - #[test] fn rm() { let directory = "tests/fixtures/nuplayground"; @@ -74,9 +86,7 @@ fn rm() { h::create_file_at(&file); - nu!(_output, - cwd(directory), - "rm rm_test.txt"); + nu!(_output, cwd(directory), "rm rm_test.txt"); assert!(!h::file_exists_at(&file)); } @@ -85,30 +95,34 @@ fn rm() { fn can_remove_directory_contents_with_recursive_flag() { let path = "tests/fixtures/nuplayground/rm_test"; - if h::file_exists_at(&path) { h::delete_directory_at(path) } + if h::file_exists_at(&path) { + h::delete_directory_at(path) + } h::create_directory_at(path); for f in ["yehuda.txt", "jonathan.txt", "andres.txt"].iter() { h::create_file_at(&format!("{}/{}", path, f)); - }; + } - nu!(_output, + nu!( + _output, cwd("tests/fixtures/nuplayground"), - "rm rm_test --recursive"); + "rm rm_test --recursive" + ); assert!(!h::file_exists_at(&path)); } #[test] fn rm_error_if_attempting_to_delete_a_directory_without_recursive_flag() { - let path = "tests/fixtures/nuplayground/rm_test"; + let path = "tests/fixtures/nuplayground/rm_test_2"; - if h::file_exists_at(&path) { h::delete_directory_at(path) } + if h::file_exists_at(&path) { + h::delete_directory_at(path) + } h::create_directory_at(path); - nu_error!(output, - cwd("tests/fixtures/nuplayground"), - "rm rm_test"); + nu_error!(output, cwd("tests/fixtures/nuplayground"), "rm rm_test_2"); assert!(h::file_exists_at(&path)); assert!(output.contains("is a directory")); @@ -117,18 +131,14 @@ fn rm_error_if_attempting_to_delete_a_directory_without_recursive_flag() { #[test] fn rm_error_if_attempting_to_delete_single_dot_as_argument() { - nu_error!(output, - cwd("tests/fixtures/nuplayground"), - "rm ."); + nu_error!(output, cwd("tests/fixtures/nuplayground"), "rm ."); assert!(output.contains("may not be removed")); } #[test] fn rm_error_if_attempting_to_delete_two_dot_as_argument() { - nu_error!(output, - cwd("tests/fixtures/nuplayground"), - "rm .."); + nu_error!(output, cwd("tests/fixtures/nuplayground"), "rm .."); assert!(output.contains("may not be removed")); } From 15507f00fcf38948fee04e93a5654eaf7085d1c3 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sat, 20 Jul 2019 14:27:10 +1200 Subject: [PATCH 4/4] Introduce CallInfo, which abstracts args, name_span, and source_map --- src/commands/autoview.rs | 2 +- src/commands/cd.rs | 2 +- src/commands/clip.rs | 2 +- src/commands/command.rs | 27 ++++++++++--------- src/commands/config.rs | 8 +++--- src/commands/first.rs | 2 +- src/commands/from_csv.rs | 14 ++++++---- src/commands/from_ini.rs | 2 +- src/commands/from_json.rs | 2 +- src/commands/from_toml.rs | 2 +- src/commands/from_xml.rs | 2 +- src/commands/from_yaml.rs | 2 +- src/commands/get.rs | 2 +- src/commands/lines.rs | 2 +- src/commands/ls.rs | 4 +-- src/commands/open.rs | 4 +-- src/commands/pick.rs | 2 +- src/commands/plugin.rs | 4 +-- src/commands/ps.rs | 2 +- src/commands/reject.rs | 4 +-- src/commands/rm.rs | 33 +++++++++++------------ src/commands/save.rs | 6 ++--- src/commands/skip_while.rs | 2 +- src/commands/split_column.rs | 4 +-- src/commands/split_row.rs | 4 +-- src/commands/sysinfo.rs | 19 +++++++------- src/commands/to_json.rs | 2 +- src/commands/to_toml.rs | 2 +- src/commands/to_yaml.rs | 2 +- src/context.rs | 18 ++++++++----- src/lib.rs | 3 ++- src/plugin.rs | 18 ++++++++----- src/plugins/binaryview.rs | 51 ++++++++++++++++++++++++++++++------ src/plugins/inc.rs | 14 +++++----- src/plugins/skip.rs | 16 +++++++---- src/plugins/tree.rs | 4 +-- 36 files changed, 173 insertions(+), 116 deletions(-) diff --git a/src/commands/autoview.rs b/src/commands/autoview.rs index d13d324f9..b09215982 100644 --- a/src/commands/autoview.rs +++ b/src/commands/autoview.rs @@ -14,7 +14,7 @@ pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> { { args.ctx.get_sink("binaryview").run(args)?; } else if is_single_text_value(&args.input) { - view_text_value(&args.input[0], &args.source_map); + view_text_value(&args.input[0], &args.call_info.source_map); } else if equal_shapes(&args.input) { args.ctx.get_sink("table").run(args)?; } else { diff --git a/src/commands/cd.rs b/src/commands/cd.rs index 246c4c40d..b68a0deb7 100644 --- a/src/commands/cd.rs +++ b/src/commands/cd.rs @@ -13,7 +13,7 @@ pub fn cd(args: CommandArgs) -> Result { return Err(ShellError::maybe_labeled_error( "Can not change to home directory", "can not go to home", - args.name_span, + args.call_info.name_span, )) } }, diff --git a/src/commands/clip.rs b/src/commands/clip.rs index 96b6b7081..32294bf77 100644 --- a/src/commands/clip.rs +++ b/src/commands/clip.rs @@ -16,7 +16,7 @@ pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> { } let string = i.as_string().map_err(labelled( - args.name_span, + args.call_info.name_span, "Given non-string data", "expected strings from pipeline", ))?; diff --git a/src/commands/command.rs b/src/commands/command.rs index 5bc2e0877..e5057c6cd 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -12,49 +12,52 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; use uuid::Uuid; +#[derive(Deserialize, Serialize, Debug)] +pub struct CallInfo { + pub args: Args, + pub source_map: SourceMap, + pub name_span: Option, +} + #[derive(Getters)] #[get = "crate"] pub struct CommandArgs { pub host: Arc>, pub env: Arc>, - pub name_span: Option, - pub source_map: SourceMap, - pub args: Args, + pub call_info: CallInfo, pub input: InputStream, } impl CommandArgs { pub fn nth(&self, pos: usize) -> Option<&Spanned> { - self.args.nth(pos) + self.call_info.args.nth(pos) } pub fn positional_iter(&self) -> impl Iterator> { - self.args.positional_iter() + self.call_info.args.positional_iter() } pub fn expect_nth(&self, pos: usize) -> Result<&Spanned, ShellError> { - self.args.expect_nth(pos) + self.call_info.args.expect_nth(pos) } pub fn len(&self) -> usize { - self.args.len() + self.call_info.args.len() } pub fn get(&self, name: &str) -> Option<&Spanned> { - self.args.get(name) + self.call_info.args.get(name) } #[allow(unused)] pub fn has(&self, name: &str) -> bool { - self.args.has(name) + self.call_info.args.has(name) } } pub struct SinkCommandArgs { pub ctx: Context, - pub name_span: Option, - pub source_map: SourceMap, - pub args: Args, + pub call_info: CallInfo, pub input: Vec>, } diff --git a/src/commands/config.rs b/src/commands/config.rs index 954cc08ef..7da3c91c6 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -39,10 +39,10 @@ impl Command for Config { } pub fn config(args: CommandArgs) -> Result { - let mut result = crate::object::config::config(args.name_span)?; + let mut result = crate::object::config::config(args.call_info.name_span)?; - trace!("{:#?}", args.args.positional); - trace!("{:#?}", args.args.named); + trace!("{:#?}", args.call_info.args.positional); + trace!("{:#?}", args.call_info.args.named); if let Some(v) = args.get("get") { let key = v.as_string()?; @@ -95,7 +95,7 @@ pub fn config(args: CommandArgs) -> Result { } if args.len() == 0 { - return Ok(vec![Value::Object(result.into()).spanned(args.name_span)].into()); + return Ok(vec![Value::Object(result.into()).spanned(args.call_info.name_span)].into()); } Err(ShellError::string(format!("Unimplemented"))) diff --git a/src/commands/first.rs b/src/commands/first.rs index 5a466a8cd..aec66b3a6 100644 --- a/src/commands/first.rs +++ b/src/commands/first.rs @@ -8,7 +8,7 @@ pub fn first(args: CommandArgs) -> Result { return Err(ShellError::maybe_labeled_error( "First requires an amount", "needs parameter", - args.name_span, + args.call_info.name_span, )); } diff --git a/src/commands/from_csv.rs b/src/commands/from_csv.rs index c6e0fa9ec..9c70bf1ed 100644 --- a/src/commands/from_csv.rs +++ b/src/commands/from_csv.rs @@ -6,8 +6,9 @@ pub fn from_csv_string_to_value( s: String, span: impl Into, ) -> Result, Box> { - - let mut reader = ReaderBuilder::new().has_headers(false).from_reader(s.as_bytes()); + let mut reader = ReaderBuilder::new() + .has_headers(false) + .from_reader(s.as_bytes()); let span = span.into(); let mut fields: VecDeque = VecDeque::new(); @@ -28,9 +29,12 @@ pub fn from_csv_string_to_value( let row_values = row_values?; let mut row = SpannedDictBuilder::new(span); - + for (idx, entry) in row_values.iter().enumerate() { - row.insert_spanned(fields.get(idx).unwrap(), Value::Primitive(Primitive::String(String::from(entry))).spanned(span)); + row.insert_spanned( + fields.get(idx).unwrap(), + Value::Primitive(Primitive::String(String::from(entry))).spanned(span), + ); } rows.insert_spanned(row.into_spanned_value()); @@ -45,7 +49,7 @@ pub fn from_csv_string_to_value( pub fn from_csv(args: CommandArgs) -> Result { let out = args.input; - let span = args.name_span; + let span = args.call_info.name_span; Ok(out .values diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index 340ad26e4..193356dce 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -39,7 +39,7 @@ pub fn from_ini_string_to_value( pub fn from_ini(args: CommandArgs) -> Result { let out = args.input; - let span = args.name_span; + let span = args.call_info.name_span; Ok(out .values .map(move |a| match a.item { diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index 36dae4b1b..f3968dd12 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -45,7 +45,7 @@ pub fn from_json_string_to_value( pub fn from_json(args: CommandArgs) -> Result { let out = args.input; - let span = args.name_span; + let span = args.call_info.name_span; Ok(out .values .map(move |a| match a.item { diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index 1745548ee..cf650dd99 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -43,7 +43,7 @@ pub fn from_toml_string_to_value( pub fn from_toml(args: CommandArgs) -> Result { let out = args.input; - let span = args.name_span; + let span = args.call_info.name_span; Ok(out .values .map(move |a| match a.item { diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index db56cb830..cc221df33 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -61,7 +61,7 @@ pub fn from_xml_string_to_value( pub fn from_xml(args: CommandArgs) -> Result { let out = args.input; - let span = args.name_span; + let span = args.call_info.name_span; Ok(out .values .map(move |a| match a.item { diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index 12121037b..475926d4a 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -50,7 +50,7 @@ pub fn from_yaml_string_to_value( pub fn from_yaml(args: CommandArgs) -> Result { let out = args.input; - let span = args.name_span; + let span = args.call_info.name_span; Ok(out .values .map(move |a| match a.item { diff --git a/src/commands/get.rs b/src/commands/get.rs index e6d1de26b..6cdea2e1f 100644 --- a/src/commands/get.rs +++ b/src/commands/get.rs @@ -26,7 +26,7 @@ pub fn get(args: CommandArgs) -> Result { return Err(ShellError::maybe_labeled_error( "Get requires a field or field path", "needs parameter", - args.name_span, + args.call_info.name_span, )); } diff --git a/src/commands/lines.rs b/src/commands/lines.rs index 12cd0c020..219f4d39d 100644 --- a/src/commands/lines.rs +++ b/src/commands/lines.rs @@ -7,7 +7,7 @@ use log::trace; pub fn lines(args: CommandArgs) -> Result { let input = args.input; - let span = args.name_span; + let span = args.call_info.name_span; let stream = input .values diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 17843e69e..72ef4883b 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -30,7 +30,7 @@ pub fn ls(args: CommandArgs) -> Result { return Err(ShellError::maybe_labeled_error( e.to_string(), e.to_string(), - args.name_span, + args.call_info.name_span, )); } } @@ -40,7 +40,7 @@ pub fn ls(args: CommandArgs) -> Result { let mut shell_entries = VecDeque::new(); for entry in entries { - let value = dir_entry_dict(&entry?, args.name_span)?; + let value = dir_entry_dict(&entry?, args.call_info.name_span)?; shell_entries.push_back(ReturnSuccess::value(value)) } Ok(shell_entries.to_output_stream()) diff --git a/src/commands/open.rs b/src/commands/open.rs index 0f5f3021a..60b11a72a 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -10,7 +10,7 @@ use uuid::Uuid; command! { Open as open(args, path: Spanned, --raw: Switch,) { - let span = args.name_span; + let span = args.call_info.name_span; let cwd = args .env @@ -48,7 +48,7 @@ command! { )?) ), - other => stream.push_back(ReturnSuccess::value(other.spanned(span))), + other => stream.push_back(ReturnSuccess::value(other.spanned(contents_span))), }; stream diff --git a/src/commands/pick.rs b/src/commands/pick.rs index 0d53ce994..b28660c2a 100644 --- a/src/commands/pick.rs +++ b/src/commands/pick.rs @@ -7,7 +7,7 @@ pub fn pick(args: CommandArgs) -> Result { return Err(ShellError::maybe_labeled_error( "Pick requires fields", "needs parameter", - args.name_span, + args.call_info.name_span, )); } diff --git a/src/commands/plugin.rs b/src/commands/plugin.rs index a27f1944a..62507ed31 100644 --- a/src/commands/plugin.rs +++ b/src/commands/plugin.rs @@ -84,7 +84,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result Result Result<(), ShellError> { //use subprocess::Exec; - let request = JsonRpc::new("sink", (args.args, args.input)); + let request = JsonRpc::new("sink", (args.call_info, args.input)); let request_raw = serde_json::to_string(&request).unwrap(); let mut tmpfile = tempfile::NamedTempFile::new()?; let _ = writeln!(tmpfile, "{}", request_raw); diff --git a/src/commands/ps.rs b/src/commands/ps.rs index 14b9ba27f..2924785a8 100644 --- a/src/commands/ps.rs +++ b/src/commands/ps.rs @@ -10,7 +10,7 @@ pub fn ps(args: CommandArgs) -> Result { let list = list .into_iter() - .map(|(_, process)| process_dict(process, args.name_span)) + .map(|(_, process)| process_dict(process, args.call_info.name_span)) .collect::>(); Ok(list.from_input_stream()) diff --git a/src/commands/reject.rs b/src/commands/reject.rs index 362df135d..775207629 100644 --- a/src/commands/reject.rs +++ b/src/commands/reject.rs @@ -3,13 +3,13 @@ use crate::object::base::reject_fields; use crate::prelude::*; pub fn reject(args: CommandArgs) -> Result { - let name_span = args.name_span; + let name_span = args.call_info.name_span; if args.len() == 0 { return Err(ShellError::maybe_labeled_error( "Reject requires fields", "needs parameter", - args.name_span, + args.call_info.name_span, )); } diff --git a/src/commands/rm.rs b/src/commands/rm.rs index 776d27d17..5760a3444 100644 --- a/src/commands/rm.rs +++ b/src/commands/rm.rs @@ -1,7 +1,7 @@ use crate::errors::ShellError; -use crate::prelude::*; -use crate::parser::registry::{CommandConfig, NamedType, PositionalType}; use crate::parser::hir::SyntaxType; +use crate::parser::registry::{CommandConfig, NamedType, PositionalType}; +use crate::prelude::*; use indexmap::IndexMap; pub struct Remove; @@ -31,28 +31,25 @@ impl Command for Remove { } pub fn rm(args: CommandArgs) -> Result { - let mut full_path = args.env - .lock() - .unwrap() - .path() - .to_path_buf(); + let mut full_path = args.env.lock().unwrap().path().to_path_buf(); - - match args.nth(0) - .ok_or_else(|| ShellError::string(&format!("No file or directory specified")))? - .as_string()? - .as_str() { - "." | ".." => return Err(ShellError::string("\".\" and \"..\" may not be removed")), - file => full_path.push(file), + match args + .nth(0) + .ok_or_else(|| ShellError::string(&format!("No file or directory specified")))? + .as_string()? + .as_str() + { + "." | ".." => return Err(ShellError::string("\".\" and \"..\" may not be removed")), + file => full_path.push(file), } - if full_path.is_dir() { if !args.has("recursive") { return Err(ShellError::labeled_error( - "is a directory", - "", - args.name_span.unwrap())); + "is a directory", + "", + args.call_info.name_span.unwrap(), + )); } std::fs::remove_dir_all(&full_path).expect("can not remove directory"); } else if full_path.is_file() { diff --git a/src/commands/save.rs b/src/commands/save.rs index 312e7a2cb..a9545651a 100644 --- a/src/commands/save.rs +++ b/src/commands/save.rs @@ -8,15 +8,15 @@ use crate::parser::Spanned; use std::path::{Path, PathBuf}; pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> { - if args.args.positional.is_none() { + if args.call_info.args.positional.is_none() { return Err(ShellError::maybe_labeled_error( "Save requires a filepath", "needs path", - args.name_span, + args.call_info.name_span, )); } - let positional = match args.args.positional { + let positional = match args.call_info.args.positional { None => return Err(ShellError::string("save requires a filepath")), Some(p) => p, }; diff --git a/src/commands/skip_while.rs b/src/commands/skip_while.rs index 605747e69..c0aa0f3b0 100644 --- a/src/commands/skip_while.rs +++ b/src/commands/skip_while.rs @@ -30,7 +30,7 @@ pub fn skip_while(args: CommandArgs) -> Result { return Err(ShellError::maybe_labeled_error( "Where requires a condition", "needs condition", - args.name_span, + args.call_info.name_span, )); } diff --git a/src/commands/split_column.rs b/src/commands/split_column.rs index cf3423037..90c12b8f8 100644 --- a/src/commands/split_column.rs +++ b/src/commands/split_column.rs @@ -5,13 +5,13 @@ use log::trace; pub fn split_column(args: CommandArgs) -> Result { let positional: Vec<_> = args.positional_iter().cloned().collect(); - let span = args.name_span; + let span = args.call_info.name_span; if positional.len() == 0 { return Err(ShellError::maybe_labeled_error( "Split-column needs more information", "needs parameter (eg split-column \",\")", - args.name_span, + args.call_info.name_span, )); } diff --git a/src/commands/split_row.rs b/src/commands/split_row.rs index 06637ff05..fb530ac8a 100644 --- a/src/commands/split_row.rs +++ b/src/commands/split_row.rs @@ -6,13 +6,13 @@ use log::trace; pub fn split_row(args: CommandArgs) -> Result { let positional: Vec> = args.positional_iter().cloned().collect(); - let span = args.name_span; + let span = args.call_info.name_span; if positional.len() == 0 { return Err(ShellError::maybe_labeled_error( "Split-row needs more information", "needs parameter (eg split-row \"\\n\")", - args.name_span, + args.call_info.name_span, )); } diff --git a/src/commands/sysinfo.rs b/src/commands/sysinfo.rs index 421980dca..425505936 100644 --- a/src/commands/sysinfo.rs +++ b/src/commands/sysinfo.rs @@ -7,10 +7,11 @@ use sys_info::*; use sysinfo::{ComponentExt, DiskExt, NetworkExt, RefreshKind, SystemExt}; pub fn sysinfo(args: CommandArgs) -> Result { - let mut idx = SpannedDictBuilder::new(args.name_span); + let name_span = args.call_info.name_span; + let mut idx = SpannedDictBuilder::new(name_span); if let (Ok(name), Ok(version)) = (os_type(), os_release()) { - let mut os_idx = SpannedDictBuilder::new(args.name_span); + let mut os_idx = SpannedDictBuilder::new(name_span); os_idx.insert("name", Primitive::String(name)); os_idx.insert("version", Primitive::String(version)); @@ -18,7 +19,7 @@ pub fn sysinfo(args: CommandArgs) -> Result { } if let (Ok(num_cpu), Ok(cpu_speed)) = (cpu_num(), cpu_speed()) { - let mut cpu_idx = SpannedDictBuilder::new(args.name_span); + let mut cpu_idx = SpannedDictBuilder::new(name_span); cpu_idx.insert("num", Primitive::Int(num_cpu as i64)); cpu_idx.insert("speed", Primitive::Int(cpu_speed as i64)); @@ -26,7 +27,7 @@ pub fn sysinfo(args: CommandArgs) -> Result { } if let Ok(x) = loadavg() { - let mut load_idx = SpannedDictBuilder::new(args.name_span); + let mut load_idx = SpannedDictBuilder::new(name_span); load_idx.insert("1min", Primitive::Float(OF64::from(x.one))); load_idx.insert("5min", Primitive::Float(OF64::from(x.five))); @@ -36,7 +37,7 @@ pub fn sysinfo(args: CommandArgs) -> Result { } if let Ok(x) = mem_info() { - let mut mem_idx = SpannedDictBuilder::new(args.name_span); + let mut mem_idx = SpannedDictBuilder::new(name_span); mem_idx.insert("total", Primitive::Bytes(x.total as u64 * 1024)); mem_idx.insert("free", Primitive::Bytes(x.free as u64 * 1024)); @@ -70,7 +71,7 @@ pub fn sysinfo(args: CommandArgs) -> Result { #[cfg(not(windows))] { if let Ok(x) = boottime() { - let mut boottime_idx = SpannedDictBuilder::new(args.name_span); + let mut boottime_idx = SpannedDictBuilder::new(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)); @@ -84,7 +85,7 @@ pub fn sysinfo(args: CommandArgs) -> Result { if components_list.len() > 0 { let mut v: Vec> = vec![]; for component in components_list { - let mut component_idx = SpannedDictBuilder::new(args.name_span); + let mut component_idx = SpannedDictBuilder::new(name_span); component_idx.insert("name", Primitive::String(component.get_label().to_string())); component_idx.insert( "temp", @@ -107,7 +108,7 @@ pub fn sysinfo(args: CommandArgs) -> Result { let mut v = vec![]; for disk in disks { - let mut disk_idx = SpannedDictBuilder::new(args.name_span); + let mut disk_idx = SpannedDictBuilder::new(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())); @@ -121,7 +122,7 @@ pub fn sysinfo(args: CommandArgs) -> Result { let incoming = network.get_income(); let outgoing = network.get_outcome(); - let mut network_idx = SpannedDictBuilder::new(args.name_span); + let mut network_idx = SpannedDictBuilder::new(name_span); network_idx.insert("incoming", Value::bytes(incoming)); network_idx.insert("outgoing", Value::bytes(outgoing)); idx.insert_spanned("network", network_idx); diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index c6ace9103..5cd4c913c 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -42,7 +42,7 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value { pub fn to_json(args: CommandArgs) -> Result { let out = args.input; - let name_span = args.name_span; + let name_span = args.call_info.name_span; Ok(out .values .map( diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index 6ffbe6ba3..354976a87 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -32,7 +32,7 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value { pub fn to_toml(args: CommandArgs) -> Result { let out = args.input; - let name_span = args.name_span; + let name_span = args.call_info.name_span; Ok(out .values diff --git a/src/commands/to_yaml.rs b/src/commands/to_yaml.rs index 1a64898ba..66db5afa4 100644 --- a/src/commands/to_yaml.rs +++ b/src/commands/to_yaml.rs @@ -40,7 +40,7 @@ pub fn value_to_yaml_value(v: &Value) -> serde_yaml::Value { pub fn to_yaml(args: CommandArgs) -> Result { let out = args.input; - let name_span = args.name_span; + let name_span = args.call_info.name_span; Ok(out .values .map( diff --git a/src/context.rs b/src/context.rs index 94d15aab5..9be7463a0 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,4 +1,4 @@ -use crate::commands::command::{Sink, SinkCommandArgs}; +use crate::commands::command::{CallInfo, Sink, SinkCommandArgs}; use crate::parser::{ registry::{Args, CommandConfig, CommandRegistry}, Span, @@ -88,9 +88,11 @@ impl Context { ) -> Result<(), ShellError> { let command_args = SinkCommandArgs { ctx: self.clone(), - name_span, - source_map: self.source_map.clone(), - args, + call_info: CallInfo { + name_span, + source_map: self.source_map.clone(), + args, + }, input, }; @@ -120,9 +122,11 @@ impl Context { let command_args = CommandArgs { host: self.host.clone(), env: self.env.clone(), - name_span, - source_map, - args, + call_info: CallInfo { + name_span, + source_map, + args, + }, input, }; diff --git a/src/lib.rs b/src/lib.rs index 13a48915c..f5f7f90f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,8 @@ mod plugin; mod shell; mod stream; -pub use crate::commands::command::{ReturnSuccess, ReturnValue}; +pub use crate::commands::command::{CallInfo, ReturnSuccess, ReturnValue}; +pub use crate::context::SpanSource; pub use crate::env::host::BasicHost; pub use crate::parser::parse::span::SpannedItem; pub use crate::parser::Spanned; diff --git a/src/plugin.rs b/src/plugin.rs index 4126b9d08..fdc6c8a6c 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,11 +1,11 @@ -use crate::{Args, CommandConfig, ReturnValue, ShellError, Spanned, Value}; +use crate::{CallInfo, CommandConfig, ReturnValue, ShellError, Spanned, Value}; use serde::{Deserialize, Serialize}; use std::io; pub trait Plugin { fn config(&mut self) -> Result; #[allow(unused)] - fn begin_filter(&mut self, args: Args) -> Result<(), ShellError> { + fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> { Err(ShellError::string( "`begin_filter` not implemented in plugin", )) @@ -15,7 +15,7 @@ pub trait Plugin { Err(ShellError::string("`filter` not implemented in plugin")) } #[allow(unused)] - fn sink(&mut self, args: Args, input: Vec>) {} + fn sink(&mut self, call_info: CallInfo, input: Vec>) {} fn quit(&mut self) { return; @@ -134,8 +134,14 @@ fn send_response(result: T) { #[allow(non_camel_case_types)] pub enum NuCommand { config, - begin_filter { params: Args }, - filter { params: Spanned }, - sink { params: (Args, Vec>) }, + begin_filter { + params: CallInfo, + }, + filter { + params: Spanned, + }, + sink { + params: (CallInfo, Vec>), + }, quit, } diff --git a/src/plugins/binaryview.rs b/src/plugins/binaryview.rs index 8c525f388..b71a8a88a 100644 --- a/src/plugins/binaryview.rs +++ b/src/plugins/binaryview.rs @@ -1,6 +1,10 @@ +#![feature(option_flattening)] use crossterm::{cursor, terminal, Attribute, RawScreen}; use indexmap::IndexMap; -use nu::{serve_plugin, Args, CommandConfig, NamedType, Plugin, ShellError, Spanned, Value}; +use nu::{ + serve_plugin, CallInfo, CommandConfig, NamedType, Plugin, ShellError, SpanSource, Spanned, + Value, +}; use pretty_hex::*; struct BinaryView; @@ -25,14 +29,15 @@ impl Plugin for BinaryView { }) } - fn sink(&mut self, args: Args, input: Vec>) { + fn sink(&mut self, call_info: CallInfo, input: Vec>) { for v in input { match v { Spanned { item: Value::Binary(b), - .. + span, } => { - let _ = view_binary(&b, args.has("lores")); + let source = span.source.map(|x| call_info.source_map.get(&x)).flatten(); + let _ = view_binary(&b, source, call_info.args.has("lores")); } _ => {} } @@ -40,17 +45,21 @@ impl Plugin for BinaryView { } } -fn view_binary(b: &[u8], lores_mode: bool) -> Result<(), Box> { +fn view_binary( + b: &[u8], + source: Option<&SpanSource>, + lores_mode: bool, +) -> Result<(), Box> { if b.len() > 3 { match (b[0], b[1], b[2]) { (0x4e, 0x45, 0x53) => { - view_contents_interactive(b, lores_mode)?; + view_contents_interactive(b, source, lores_mode)?; return Ok(()); } _ => {} } } - view_contents(b, lores_mode)?; + view_contents(b, source, lores_mode)?; Ok(()) } @@ -247,7 +256,11 @@ fn load_from_jpg_buffer(buffer: &[u8]) -> Option<(RawImageBuffer)> { }) } -pub fn view_contents(buffer: &[u8], lores_mode: bool) -> Result<(), Box> { +pub fn view_contents( + buffer: &[u8], + _source: Option<&SpanSource>, + lores_mode: bool, +) -> Result<(), Box> { let mut raw_image_buffer = load_from_png_buffer(buffer); if raw_image_buffer.is_none() { @@ -332,14 +345,29 @@ pub fn view_contents(buffer: &[u8], lores_mode: bool) -> Result<(), Box, lores_mode: bool, ) -> Result<(), Box> { use rawkey::{KeyCode, RawKey}; + let sav_path = if let Some(SpanSource::File(f)) = source { + let mut path = std::path::PathBuf::from(f); + path.set_extension("sav"); + Some(path) + } else { + None + }; + let mut nes = neso::Nes::new(48000.0); let rawkey = RawKey::new(); nes.load_rom(&buffer); + if let Some(ref sav_path) = sav_path { + if let Ok(contents) = std::fs::read(sav_path) { + let _ = nes.load_state(&contents); + } + } + nes.reset(); if let Ok(_raw) = RawScreen::into_raw_mode() { @@ -403,6 +431,13 @@ pub fn view_contents_interactive( } } + if let Some(ref sav_path) = sav_path { + let buffer = nes.save_state(); + if let Ok(buffer) = buffer { + let _ = std::fs::write(sav_path, buffer); + } + } + let cursor = cursor(); let _ = cursor.show(); diff --git a/src/plugins/inc.rs b/src/plugins/inc.rs index 8d69f91d5..f03edc985 100644 --- a/src/plugins/inc.rs +++ b/src/plugins/inc.rs @@ -1,7 +1,7 @@ use indexmap::IndexMap; use nu::{ - serve_plugin, Args, CommandConfig, NamedType, Plugin, PositionalType, Primitive, ReturnSuccess, - ReturnValue, ShellError, Spanned, SpannedItem, Value, + serve_plugin, CallInfo, CommandConfig, NamedType, Plugin, PositionalType, Primitive, + ReturnSuccess, ReturnValue, ShellError, Spanned, SpannedItem, Value, }; struct Inc { @@ -99,18 +99,18 @@ impl Plugin for Inc { rest_positional: true, }) } - fn begin_filter(&mut self, args: Args) -> Result<(), ShellError> { - if args.has("major") { + fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> { + if call_info.args.has("major") { self.major = true; } - if args.has("minor") { + if call_info.args.has("minor") { self.minor = true; } - if args.has("patch") { + if call_info.args.has("patch") { self.patch = true; } - if let Some(args) = args.positional { + if let Some(args) = call_info.args.positional { for arg in args { match arg { Spanned { diff --git a/src/plugins/skip.rs b/src/plugins/skip.rs index 0a1fdf7a9..e7a4f6003 100644 --- a/src/plugins/skip.rs +++ b/src/plugins/skip.rs @@ -1,7 +1,7 @@ use indexmap::IndexMap; use nu::{ - serve_plugin, Args, CommandConfig, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, - Spanned, Value, + serve_plugin, CallInfo, CommandConfig, Plugin, Primitive, ReturnSuccess, ReturnValue, + ShellError, Spanned, Value, }; struct NewSkip { @@ -24,8 +24,8 @@ impl Plugin for NewSkip { rest_positional: true, }) } - fn begin_filter(&mut self, args: Args) -> Result<(), ShellError> { - if let Some(args) = args.positional { + fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> { + if let Some(args) = call_info.args.positional { for arg in args { match arg { Spanned { @@ -34,7 +34,13 @@ impl Plugin for NewSkip { } => { self.skip_amount = i; } - _ => return Err(ShellError::labeled_error("Unrecognized type in params", "expected an integer", arg.span)), + _ => { + return Err(ShellError::labeled_error( + "Unrecognized type in params", + "expected an integer", + arg.span, + )) + } } } } diff --git a/src/plugins/tree.rs b/src/plugins/tree.rs index cfaf26990..b2bc9e1ca 100644 --- a/src/plugins/tree.rs +++ b/src/plugins/tree.rs @@ -1,6 +1,6 @@ use derive_new::new; use indexmap::IndexMap; -use nu::{serve_plugin, Args, CommandConfig, Plugin, ShellError, Spanned, Value}; +use nu::{serve_plugin, CallInfo, CommandConfig, Plugin, ShellError, Spanned, Value}; use ptree::item::StringItem; use ptree::output::print_tree_with; use ptree::print_config::PrintConfig; @@ -91,7 +91,7 @@ impl Plugin for TreeViewer { }) } - fn sink(&mut self, _args: Args, input: Vec>) { + fn sink(&mut self, _call_info: CallInfo, input: Vec>) { if input.len() > 0 { for i in input.iter() { let view = TreeView::from_value(&i);