This commit is contained in:
Yehuda Katz 2019-07-08 09:44:53 -07:00
parent 71adfb4cdc
commit 7b68739b52
47 changed files with 467 additions and 354 deletions

View File

@ -231,7 +231,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,
@ -396,7 +396,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
}
(Some(ClassifiedCommand::Sink(left)), None) => {
let input_vec: Vec<Value> = input.objects.into_vec().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);
}

View File

@ -22,7 +22,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() {

View File

@ -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();

View File

@ -59,24 +59,6 @@ impl ClassifiedInputStream {
}
}
pub fn into_vec(self) -> impl std::future::Future<Output = Vec<Value>> {
self.objects.into_vec()
}
crate fn from_vec(stream: VecDeque<Value>) -> ClassifiedInputStream {
ClassifiedInputStream {
objects: stream.into(),
stdin: None,
}
}
crate fn from_list(stream: Vec<Value>) -> ClassifiedInputStream {
ClassifiedInputStream {
objects: stream.into(),
stdin: None,
}
}
crate fn from_input_stream(stream: impl Into<InputStream>) -> ClassifiedInputStream {
ClassifiedInputStream {
objects: stream.into(),
@ -111,7 +93,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)
}
}
@ -160,7 +146,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),
@ -199,7 +189,7 @@ impl ExternalCommand {
stream_next: StreamNext,
) -> Result<ClassifiedInputStream, ShellError> {
let stdin = input.stdin;
let inputs: Vec<Value> = input.objects.into_vec().await;
let inputs: Vec<Spanned<Value>> = input.objects.into_vec().await;
trace!("-> {}", self.name);
trace!("inputs = {:?}", inputs);

View File

@ -7,7 +7,7 @@ use crate::parser::{
use crate::prelude::*;
use getset::Getters;
use serde::{Deserialize, Serialize};
use std::{ops::Try, path::PathBuf};
use std::path::PathBuf;
#[derive(Getters)]
#[get = "crate"]
@ -49,26 +49,26 @@ 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 ReturnSuccess {
Value(Value),
Value(Spanned<Value>),
Action(CommandAction),
}
pub type ReturnValue = Result<ReturnSuccess, ShellError>;
impl From<Value> for ReturnValue {
fn from(input: Value) -> ReturnValue {
impl From<Spanned<Value>> for ReturnValue {
fn from(input: Spanned<Value>) -> ReturnValue {
Ok(ReturnSuccess::Value(input))
}
}
@ -78,8 +78,12 @@ impl ReturnSuccess {
Ok(ReturnSuccess::Action(CommandAction::ChangePath(path)))
}
pub fn value(input: Value) -> ReturnValue {
Ok(ReturnSuccess::Value(input))
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)))
}
}

View File

@ -1,4 +1,3 @@
#[macro_use]
use crate::prelude::*;
use crate::errors::ShellError;
@ -44,7 +43,7 @@ impl Command for Config {
}
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);
@ -56,7 +55,7 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
.ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?;
return Ok(
vec![value.clone()].into(), // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(),
stream![value.clone()], // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(),
);
}
@ -66,16 +65,21 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
config::write_config(&result)?;
return Ok(stream![Value::Object(result.into())].from_input_stream());
return Ok(
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(stream![Value::Object(result.into())].from_input_stream());
return Ok(
stream![Spanned::from_item(Value::Object(result.into()), c.span())].from_input_stream(),
);
}
if let Some(v) = args.get("remove") {
@ -90,7 +94,7 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
)));
}
let obj = VecDeque::from_iter(vec![Value::Object(result.into())]);
let obj = VecDeque::from_iter(vec![Value::Object(result.into()).spanned(v)]);
return Ok(obj.from_input_stream());
}

View File

@ -49,7 +49,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(
@ -90,7 +90,7 @@ pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
};
stream.push_back(Ok(ReturnSuccess::Action(CommandAction::Enter(
parse_as_value(file_extension, contents, span)?,
parse_as_value(file_extension, contents, contents_span, span)?,
))));
Ok(stream.into())

View File

@ -31,9 +31,9 @@ pub fn from_ini(args: CommandArgs) -> Result<OutputStream, ShellError> {
let span = args.name_span;
Ok(out
.values
.map(move |a| match a {
.map(move |a| match a.item {
Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s) {
Ok(x) => Ok(ReturnSuccess::Value(x)),
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
Err(e) => Err(ShellError::maybe_labeled_error(
"Could not parse as INI",
format!("{:#?}", e),

View File

@ -12,7 +12,7 @@ fn convert_json_value_to_nu_value(v: &serde_hjson::Value) -> Value {
serde_hjson::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))),
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).spanned_unknown())
.collect(),
),
serde_hjson::Value::Object(o) => {
@ -35,9 +35,9 @@ pub fn from_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
let span = args.name_span;
Ok(out
.values
.map(move |a| match a {
.map(move |a| match a.item {
Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s) {
Ok(x) => ReturnSuccess::value(x),
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
Err(_) => Err(ShellError::maybe_labeled_error(
"Could not parse as JSON",
"piped data failed JSON parse",

View File

@ -10,7 +10,7 @@ fn convert_toml_value_to_nu_value(v: &toml::Value) -> Value {
toml::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))),
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).spanned_unknown())
.collect(),
),
toml::Value::Datetime(dt) => Value::Primitive(Primitive::String(dt.to_string())),
@ -34,9 +34,9 @@ pub fn from_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
let span = args.name_span;
Ok(out
.values
.map(move |a| match a {
.map(move |a| match a.item {
Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s) {
Ok(x) => ReturnSuccess::value(x),
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
Err(_) => Err(ShellError::maybe_labeled_error(
"Could not parse as TOML",
"piped data failed TOML parse",

View File

@ -10,7 +10,7 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value {
children_values.push(from_node_to_value(&c));
}
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)) => {
@ -22,6 +22,7 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value {
}
_ => true,
})
.map(|v| v.spanned_unknown())
.collect();
let mut collected = Dictionary::default();
@ -53,9 +54,9 @@ pub fn from_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
let span = args.name_span;
Ok(out
.values
.map(move |a| match a {
.map(move |a| match a.item {
Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s) {
Ok(x) => ReturnSuccess::value(x),
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
Err(_) => Err(ShellError::maybe_labeled_error(
"Could not parse as XML",
"piped data failed XML parse",

View File

@ -14,7 +14,7 @@ fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value) -> Value {
serde_yaml::Value::String(s) => Value::string(s),
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).spanned_unknown())
.collect(),
),
serde_yaml::Value::Mapping(t) => {
@ -44,9 +44,9 @@ pub fn from_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> {
let span = args.name_span;
Ok(out
.values
.map(move |a| match a {
.map(move |a| match a.item {
Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s) {
Ok(x) => ReturnSuccess::value(x),
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
Err(_) => Err(ShellError::maybe_labeled_error(
"Could not parse as YAML",
"piped data failed YAML parse",

View File

@ -3,7 +3,7 @@ use crate::object::Value;
use crate::parser::Span;
use crate::prelude::*;
fn get_member(path: &str, span: Span, obj: &Value) -> Result<Value, ShellError> {
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) {
@ -18,7 +18,7 @@ fn get_member(path: &str, span: Span, obj: &Value) -> Result<Value, ShellError>
}
}
Ok(current.copy())
Ok(current.clone())
}
pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
@ -56,12 +56,15 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut result = VecDeque::new();
for field in &fields {
match get_member(&field.0, field.1, &item) {
Ok(Value::List(l)) => {
Ok(Spanned {
item: Value::List(l),
..
}) => {
for item in l {
result.push_back(ReturnSuccess::value(item.copy()));
result.push_back(ReturnSuccess::value(item.clone()));
}
}
Ok(x) => result.push_back(ReturnSuccess::value(x.copy())),
Ok(x) => result.push_back(ReturnSuccess::value(x.clone())),
Err(_) => {}
}
}

View File

@ -11,7 +11,7 @@ pub fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> {
let stream = input
.values
.map(move |v| match v {
.map(move |v| match v.item {
Value::Primitive(Primitive::String(s)) => {
let split_result: Vec<_> = s.lines().filter(|s| s.trim() != "").collect();
@ -19,9 +19,9 @@ pub fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut result = VecDeque::new();
for s in split_result {
result.push_back(ReturnSuccess::value(Value::Primitive(Primitive::String(
s.into(),
))));
result.push_back(ReturnSuccess::value(
Value::Primitive(Primitive::String(s.into())).spanned_unknown(),
));
}
result
}

View File

@ -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);
@ -45,7 +45,7 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
for entry in entries {
let value = Value::Object(dir_entry_dict(&entry?)?);
shell_entries.push_back(ReturnSuccess::value(value))
shell_entries.push_back(ReturnSuccess::value(value.spanned_unknown()))
}
Ok(shell_entries.to_output_stream())
}
@ -125,9 +125,12 @@ 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(ReturnSuccess::value(item.copy()));
entries.push_back(ReturnSuccess::value(item.clone()));
}
}
x => {

View File

@ -49,7 +49,7 @@ macro_rules! command {
positional: vec![$($mandatory_positional)*],
rest_positional: false,
named: {
use $crate::parser::registry::{NamedType, NamedValue};
use $crate::parser::registry::NamedType;
#[allow(unused_mut)]
let mut named: indexmap::IndexMap<String, NamedType> = indexmap::IndexMap::new();
@ -261,10 +261,10 @@ macro_rules! command {
Extract {
$($extract:tt)* {
use std::convert::TryInto;
use $crate::object::types::ExtractType;
let value = $args.expect_nth($($positional_count)*)?;
let value = $param_kind.check(value)?;
value.extract()
// let value = $param_kind.check(value)?;
$param_kind::extract(value)?
}
}
);

View File

@ -21,7 +21,7 @@ command! {
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(
@ -64,6 +64,7 @@ command! {
stream.push_back(ReturnSuccess::value(parse_as_value(
file_extension,
contents,
contents_span,
span,
)?));
@ -75,7 +76,7 @@ pub fn fetch(
cwd: &PathBuf,
location: &str,
span: Span,
) -> Result<(Option<String>, String), ShellError> {
) -> Result<(Option<String>, String, Span), ShellError> {
let mut cwd = cwd.clone();
if location.starts_with("http:") || location.starts_with("https:") {
let response = reqwest::get(location);
@ -106,7 +107,7 @@ pub fn fetch(
None => path_extension,
};
Ok((extension, Value::string(s)))
Ok((extension, s, span))
}
Err(_) => {
return Err(ShellError::labeled_error(
@ -131,7 +132,8 @@ pub fn fetch(
Ok(s) => Ok((
cwd.extension()
.map(|name| name.to_string_lossy().to_string()),
Value::string(s),
s,
span,
)),
Err(_) => Ok((None, Value::Binary(bytes))),
},
@ -149,10 +151,12 @@ 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)
.map(|c| c.spanned(contents_span))
.map_err(move |_| {
ShellError::maybe_labeled_error(
"Could not open as TOML",
@ -161,6 +165,7 @@ pub fn parse_as_value(
)
}),
Some(x) if x == "json" => crate::commands::from_json::from_json_string_to_value(contents)
.map(|c| c.spanned(contents_span))
.map_err(move |_| {
ShellError::maybe_labeled_error(
"Could not open as JSON",
@ -169,6 +174,7 @@ pub fn parse_as_value(
)
}),
Some(x) if x == "ini" => crate::commands::from_ini::from_ini_string_to_value(contents)
.map(|c| c.spanned(contents_span))
.map_err(move |_| {
ShellError::maybe_labeled_error(
"Could not open as INI",
@ -177,6 +183,7 @@ pub fn parse_as_value(
)
}),
Some(x) if x == "xml" => crate::commands::from_xml::from_xml_string_to_value(contents)
.map(|c| c.spanned(contents_span))
.map_err(move |_| {
ShellError::maybe_labeled_error(
"Could not open as XML",
@ -185,6 +192,7 @@ pub fn parse_as_value(
)
}),
Some(x) if x == "yml" => crate::commands::from_yaml::from_yaml_string_to_value(contents)
.map(|c| c.spanned(contents_span))
.map_err(move |_| {
ShellError::maybe_labeled_error(
"Could not open as YAML",
@ -193,6 +201,7 @@ pub fn parse_as_value(
)
}),
Some(x) if x == "yaml" => crate::commands::from_yaml::from_yaml_string_to_value(contents)
.map(|c| c.spanned(contents_span))
.map_err(move |_| {
ShellError::maybe_labeled_error(
"Could not open as YAML",
@ -200,6 +209,6 @@ pub fn parse_as_value(
name_span,
)
}),
_ => Ok(Value::string(contents)),
_ => Ok(Value::string(contents).spanned(contents_span)),
}
}

View File

@ -14,11 +14,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
let objects = input
.values
.map(move |item| Value::Object(select_fields(&item, &fields)));
.map(move |value| Value::Object(select_fields(&value.item, &fields)).spanned(value.span));
Ok(objects.from_input_stream())
}

View File

@ -50,14 +50,17 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
stdin.write(format!("{}\n", request_raw).as_bytes())?;
}
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
.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");

View File

@ -4,14 +4,14 @@ 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)| Value::Object(process_dict(process)))
.map(|(item, process)| Value::Object(process_dict(process)).spanned(args.name_span))
.collect::<VecDeque<_>>();
Ok(list.from_input_stream())

View File

@ -18,7 +18,7 @@ pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> {
let stream = args
.input
.values
.map(move |item| Value::Object(reject_fields(&item, &fields)));
.map(move |item| Value::Object(reject_fields(&item, &fields)).spanned(args.name_span));
Ok(stream.from_input_stream())
}

View File

@ -24,20 +24,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(spanned_name).into());
contents.clear();
}
Ok(list.to_output_stream())
}
fn count(name: &str, contents: &str) -> ReturnValue {
fn count(name: &str, contents: &str) -> Value {
let mut lines: i64 = 0;
let mut words: i64 = 0;
let mut chars: i64 = 0;
@ -69,5 +69,5 @@ fn count(name: &str, contents: &str) -> ReturnValue {
dict.add("chars", Value::int(chars));
dict.add("max length", Value::int(bytes));
ReturnSuccess::value(Value::Object(dict))
Value::Object(dict)
}

View File

@ -11,8 +11,8 @@ pub fn sort_by(args: CommandArgs) -> Result<OutputStream, ShellError> {
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().collect::<VecDeque<_>>()

View File

@ -21,7 +21,7 @@ pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(input
.values
.map(move |v| match v {
.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);
@ -40,7 +40,7 @@ pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
for (&k, v) in split_result.iter().zip(gen_columns.iter()) {
dict.add(v.clone(), Value::Primitive(Primitive::String(k.into())));
}
ReturnSuccess::value(Value::Object(dict))
ReturnSuccess::value(Value::Object(dict).spanned(v.span))
} else if split_result.len() == (positional.len() - 1) {
let mut dict = crate::object::Dictionary::default();
for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) {
@ -49,7 +49,7 @@ pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
Value::Primitive(Primitive::String(k.into())),
);
}
ReturnSuccess::value(Value::Object(dict))
ReturnSuccess::value(Value::Object(dict).spanned(v.span))
} else {
let mut dict = crate::object::Dictionary::default();
for k in positional.iter().skip(1) {
@ -58,7 +58,7 @@ pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
Value::Primitive(Primitive::String("".into())),
);
}
ReturnSuccess::value(Value::Object(dict))
ReturnSuccess::value(Value::Object(dict).spanned(v.span))
}
}
_ => Err(ShellError::maybe_labeled_error(

View File

@ -22,7 +22,7 @@ pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
let stream = input
.values
.map(move |v| match v {
.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);
@ -32,9 +32,9 @@ pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut result = VecDeque::new();
for s in split_result {
result.push_back(ReturnSuccess::value(Value::Primitive(Primitive::String(
s.into(),
))));
result.push_back(ReturnSuccess::value(
Value::Primitive(Primitive::String(s.into())).spanned(v.span),
));
}
result
}

View File

@ -1,95 +1,53 @@
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 log::trace;
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 +65,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("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 +108,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 mut stream = VecDeque::new();
stream.push_back(Value::Object(Dictionary::from(idx)));
let mut stream = stream![idx.into_spanned_value()];
Ok(stream.from_input_stream())
}

View File

@ -5,7 +5,7 @@ pub fn to_array(args: CommandArgs) -> Result<OutputStream, ShellError> {
let out = args.input.values.collect();
Ok(out
.map(|vec: Vec<_>| stream![Value::List(vec)])
.map(|vec: Vec<_>| stream![Value::List(vec).spanned_unknown()]) // TODO: args.input should have a span
.flatten_stream()
.from_input_stream())
}

View File

@ -45,15 +45,16 @@ pub fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
let out = args.input;
let span = args.name_span;
Ok(out
.map(
move |a| match serde_json::to_string(&value_to_json_value(&a)) {
Ok(x) => Ok(ReturnValue::Value(Value::Primitive(Primitive::String(x)))),
Err(_) => Err(ShellError::maybe_labeled_error(
"Can not convert to JSON string",
"can not convert piped data to JSON string",
span,
)),
},
)
.boxed())
.values
.map(move |a| match serde_json::to_string(&a) {
Ok(x) => {
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(args.name_span))
}
Err(_) => Err(ShellError::maybe_labeled_error(
"Can not convert to JSON string",
"can not convert piped data to JSON string",
span,
)),
})
.to_output_stream())
}

View File

@ -37,7 +37,9 @@ pub fn to_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(out
.values
.map(move |a| match toml::to_string(&a) {
Ok(x) => ReturnSuccess::value(Value::Primitive(Primitive::String(x))),
Ok(x) => {
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(args.name_span))
}
Err(_) => Err(ShellError::maybe_labeled_error(
"Can not convert to TOML string",
"can not convert piped data to TOML string",

View File

@ -10,15 +10,14 @@ pub fn trim(args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(input
.values
.map(move |v| match v {
Value::Primitive(Primitive::String(s)) => {
ReturnSuccess::value(Value::Primitive(Primitive::String(s.trim().into())))
}
_ => Err(ShellError::maybe_labeled_error(
"Expected string values from pipeline",
"expects strings from pipeline",
span,
)),
})
.map(move |v| ReturnSuccess::value(String::check(&v)?.clone()))
// Value::Primitive(Primitive::String(s)) => {
// ReturnSuccess::value(Value::Primitive(Primitive::String(s.trim().into())))
// }
// _ => Err(ShellError::maybe_labeled_error(
// "Expected string values from pipeline",
// "expects strings from pipeline",
// span,
// )),
.to_output_stream())
}

View File

@ -1,5 +1,5 @@
use crate::errors::ShellError;
use crate::object::types::*;
use crate::object::Block;
use crate::prelude::*;
use futures::future::ready;
use log::trace;
@ -13,7 +13,7 @@ command! {
let return_value = match result {
Err(err) => Some(Err(err)),
Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.copy()))),
Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.clone()))),
_ => None,
};

View File

@ -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(),

View File

@ -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
}
}

View File

@ -48,7 +48,7 @@ pub fn labelled(
) -> impl FnOnce(ShellError) -> ShellError + 'a {
let span = span.into();
move |error| ShellError::maybe_labeled_error(heading, span_message, span)
move |_| ShellError::maybe_labeled_error(heading, span_message, span)
}
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
@ -247,10 +247,6 @@ 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, Clone)]

View File

@ -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(),
}
}
@ -64,8 +64,10 @@ crate fn evaluate_baseline_expr(
})
}
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
.vars
.get(span.slice(source))
.map(|v| v.copy())
.unwrap_or_else(|| Value::nothing()),
span,
)),
hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.item, span)),
hir::Variable::Other(span) => Ok(scope
.vars
.get(span.slice(source))
.map(|v| v.clone())
.unwrap_or_else(|| Value::nothing().spanned(span))),
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -153,8 +153,8 @@ impl Deserialize<'de> for Block {
}
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));
@ -174,20 +174,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,
}
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> {
@ -199,12 +198,12 @@ 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),
@ -281,6 +280,12 @@ impl std::convert::TryFrom<Option<&'a Spanned<Value>>> for Switch {
}
}
impl Spanned<Value> {
crate fn debug(&'a self) -> ValueDebug<'a> {
ValueDebug { value: self }
}
}
impl Value {
crate fn type_name(&self) -> String {
match self {
@ -314,13 +319,16 @@ impl Value {
}
}
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 => {}
},
@ -333,7 +341,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,
@ -352,20 +360,6 @@ impl Value {
}
}
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::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),
@ -417,7 +411,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!(
@ -509,11 +503,6 @@ impl Value {
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 {
@ -522,9 +511,9 @@ crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Diction
let descs = obj.data_descriptors();
for field in fields {
match descs.iter().find(|d| *d == field) {
match descs.iter().find(|d| d.name.is_string(field)) {
None => out.add(field, Value::nothing()),
Some(desc) => out.add(desc.clone(), obj.get_data(desc).borrow().copy()),
Some(desc) => out.add(desc.clone(), obj.get_data(desc).borrow().clone()),
}
}
@ -539,7 +528,7 @@ crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Diction
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.add(desc.clone(), obj.get_data(&desc).borrow().clone()),
}
}
@ -552,7 +541,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) {

View File

@ -16,24 +16,31 @@ 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.item.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,9 +50,11 @@ 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)
.map(|v| v.spanned(span))
.map_err(|err| ShellError::string(&format!("Couldn't parse config file:\n{}", err)))?;
Ok(parsed.extra)

View File

@ -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 {
@ -28,8 +28,8 @@ impl PartialOrd for Dictionary {
}
}
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 {
@ -93,7 +93,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 +114,41 @@ impl Dictionary {
debug.finish()
}
}
#[derive(Debug)]
pub struct SpannedDictBuilder {
span: Span,
dict: IndexMap<DataDescriptor, 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<DataDescriptor>, value: impl Into<Value>) {
self.dict
.insert(key.into(), value.into().spanned(self.span));
}
pub fn insert_spanned(
&mut self,
key: impl Into<DataDescriptor>,
value: impl Into<Spanned<Value>>,
) {
self.dict.insert(key.into(), value.into());
}
pub fn into_spanned_value(self) -> Spanned<Value> {
Value::Object(Dictionary { entries: self.dict }).spanned(self.span)
}
}
impl From<SpannedDictBuilder> for Spanned<Value> {
fn from(input: SpannedDictBuilder) -> Spanned<Value> {
input.into_spanned_value()
}
}

23
src/object/into.rs Normal file
View 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)
}
}

View File

@ -2,29 +2,44 @@ 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;
pub trait Type: std::fmt::Debug + Send {
type Extractor: ExtractType;
fn name(&self) -> &'static str;
fn check(&self, value: Spanned<Value>) -> Result<Spanned<Value>, ShellError>;
fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError>;
fn coerce(&self) -> Option<hir::ExpressionKindHint> {
None
}
}
pub trait ExtractType<T>: Type {
fn extract(value: Value) -> T;
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"
}
fn check(&self, value: Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
Ok(value)
}
}
impl ExtractType for Spanned<Value> {
fn extract(value: &Spanned<Value>) -> Result<Self, ShellError> {
Ok(value.clone())
}
fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
Ok(value)
}
}
@ -33,11 +48,13 @@ impl Type for Any {
pub struct Integer;
impl Type for Integer {
type Extractor = i64;
fn name(&self) -> &'static str {
"Integer"
}
fn check(&self, value: Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
match value {
v @ Spanned {
item: Value::Primitive(Primitive::Int(_)),
@ -48,11 +65,67 @@ impl Type for Integer {
}
}
impl ExtractType<i64> for Integer {
fn extract(value: Value) -> i64 {
impl ExtractType for i64 {
fn extract(value: &Spanned<Value>) -> Result<i64, ShellError> {
match value {
Value::Primitive(Primitive::Int(int)) => int,
_ => unreachable!("invariant: must check before extract"),
&Spanned {
item: Value::Primitive(Primitive::Int(int)),
..
} => Ok(int),
other => Err(ShellError::type_error("Integer", other.spanned_type_name())),
}
}
fn check(&self, 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"
}
fn check(&self, 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())),
}
}
}
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(&self, 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())),
}
}
}
@ -61,11 +134,13 @@ impl ExtractType<i64> for Integer {
pub struct Block;
impl Type for Block {
type Extractor = value::Block;
fn name(&self) -> &'static str {
"Block"
}
fn check(&self, value: Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
match value {
v @ Spanned {
item: Value::Block(_),
@ -76,11 +151,24 @@ impl Type for Block {
}
}
impl ExtractType<value::Block> for Block {
fn extract(value: Value) -> value::Block {
impl ExtractType for value::Block {
fn extract(value: &Spanned<Value>) -> Result<value::Block, ShellError> {
match value {
Value::Block(block) => block,
_ => unreachable!("invariant: must check before extract"),
Spanned {
item: Value::Block(block),
..
} => Ok(block.clone()),
other => Err(ShellError::type_error("Block", other.spanned_type_name())),
}
}
fn check(&self, 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())),
}
}
}

View File

@ -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};

View File

@ -16,6 +16,13 @@ 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 +71,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 +129,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]
}

View File

@ -42,7 +42,7 @@ crate use crate::env::{Environment, Host};
crate use crate::errors::ShellError;
crate use crate::object::types::{ExtractType, Type};
crate use crate::object::{Primitive, Value};
crate use crate::parser::{Span, Spanned};
crate use crate::parser::{Span, Spanned, SpannedItem};
crate use crate::stream::{InputStream, OutputStream};
crate use crate::Text;
crate use futures::stream::BoxStream;
@ -58,7 +58,7 @@ pub trait FromInputStream {
impl<T> FromInputStream for T
where
T: Stream<Item = Value> + Send + 'static,
T: Stream<Item = Spanned<Value>> + Send + 'static,
{
fn from_input_stream(self) -> OutputStream {
OutputStream {

View File

@ -1,15 +1,15 @@
use crate::prelude::*;
pub struct InputStream {
crate values: BoxStream<'static, Value>,
crate values: BoxStream<'static, Spanned<Value>>,
}
impl InputStream {
pub fn into_vec(self) -> impl Future<Output = Vec<Value>> {
pub fn into_vec(self) -> impl Future<Output = Vec<Spanned<Value>>> {
self.values.collect()
}
pub fn from_stream(input: impl Stream<Item = Value> + Send + 'static) -> InputStream {
pub fn from_stream(input: impl Stream<Item = Spanned<Value>> + Send + 'static) -> InputStream {
InputStream {
values: input.boxed(),
}
@ -22,8 +22,8 @@ impl From<BoxStream<'static, Value>> for InputStream {
}
}
impl From<VecDeque<Value>> for InputStream {
fn from(input: VecDeque<Value>) -> InputStream {
impl From<VecDeque<Spanned<Value>>> for InputStream {
fn from(input: VecDeque<Spanned<Value>>) -> InputStream {
InputStream {
values: input.boxed(),
}
@ -46,13 +46,7 @@ pub struct OutputStream {
}
impl OutputStream {
pub fn from_stream(input: impl Stream<Item = ReturnValue> + Send + 'static) -> OutputStream {
OutputStream {
values: input.boxed(),
}
}
pub fn from_input(input: impl Stream<Item = Value> + Send + 'static) -> OutputStream {
pub fn from_input(input: impl Stream<Item = Spanned<Value>> + Send + 'static) -> OutputStream {
OutputStream {
values: input.map(ReturnSuccess::value).boxed(),
}