mirror of
https://github.com/nushell/nushell.git
synced 2024-12-23 07:30:13 +01:00
Merge branch 'master' into touchups
This commit is contained in:
commit
416d1c8cbb
77
src/cli.rs
77
src/cli.rs
@ -102,19 +102,16 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
cc.store(true, Ordering::SeqCst);
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
|
||||
let mut ctrlcbreak = false;
|
||||
loop {
|
||||
if ctrl_c.load(Ordering::SeqCst) {
|
||||
ctrl_c.store(false, Ordering::SeqCst);
|
||||
if let ShellError::String(s) = ShellError::string("CTRL-C") {
|
||||
context.host.lock().unwrap().stdout(&format!("{:?}", s));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let (obj, cwd) = {
|
||||
let env = context.env.lock().unwrap();
|
||||
let last = env.last().unwrap();
|
||||
let last = env.back().unwrap();
|
||||
(last.obj().clone(), last.path().display().to_string())
|
||||
};
|
||||
let readline = match obj {
|
||||
@ -134,6 +131,20 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
rl.add_history_entry(line.clone());
|
||||
}
|
||||
|
||||
LineResult::CtrlC => {
|
||||
if ctrlcbreak {
|
||||
std::process::exit(0);
|
||||
} else {
|
||||
context
|
||||
.host
|
||||
.lock()
|
||||
.unwrap()
|
||||
.stdout("CTRL-C pressed (again to quit)");
|
||||
ctrlcbreak = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
LineResult::Error(mut line, err) => match err {
|
||||
ShellError::Diagnostic(diag) => {
|
||||
let host = context.host.lock().unwrap();
|
||||
@ -177,6 +188,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
.stdout(&format!("A surprising fatal error occurred.\n{:?}", err));
|
||||
}
|
||||
}
|
||||
ctrlcbreak = false;
|
||||
}
|
||||
rl.save_history("history.txt").unwrap();
|
||||
|
||||
@ -186,6 +198,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
enum LineResult {
|
||||
Success(String),
|
||||
Error(String, ShellError),
|
||||
CtrlC,
|
||||
Break,
|
||||
|
||||
#[allow(unused)]
|
||||
@ -201,6 +214,7 @@ impl std::ops::Try for LineResult {
|
||||
LineResult::Success(s) => Ok(Some(s)),
|
||||
LineResult::Error(_, s) => Err(s),
|
||||
LineResult::Break => Ok(None),
|
||||
LineResult::CtrlC => Ok(None),
|
||||
LineResult::FatalError(err) => Err(err),
|
||||
}
|
||||
}
|
||||
@ -259,27 +273,26 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
||||
(None, _) => break,
|
||||
|
||||
(Some(ClassifiedCommand::Expr(_)), _) => {
|
||||
return LineResult::Error(line.clone(), ShellError::unimplemented(
|
||||
"Expression-only commands",
|
||||
))
|
||||
return LineResult::Error(
|
||||
line.clone(),
|
||||
ShellError::unimplemented("Expression-only commands"),
|
||||
)
|
||||
}
|
||||
|
||||
(_, Some(ClassifiedCommand::Expr(_))) => {
|
||||
return LineResult::Error(line.clone(), ShellError::unimplemented(
|
||||
"Expression-only commands",
|
||||
))
|
||||
return LineResult::Error(
|
||||
line.clone(),
|
||||
ShellError::unimplemented("Expression-only commands"),
|
||||
)
|
||||
}
|
||||
|
||||
(Some(ClassifiedCommand::Sink(_)), Some(_)) => {
|
||||
return LineResult::Error(line.clone(), ShellError::string("Commands like table, save, and autoview must come last in the pipeline"))
|
||||
(Some(ClassifiedCommand::Sink(SinkCommand { name_span, .. })), Some(_)) => {
|
||||
return LineResult::Error(line.clone(), ShellError::maybe_labeled_error("Commands like table, save, and autoview must come last in the pipeline", "must come last", name_span));
|
||||
}
|
||||
|
||||
(Some(ClassifiedCommand::Sink(left)), None) => {
|
||||
let input_vec: Vec<Value> = input.objects.collect().await;
|
||||
left.run(
|
||||
ctx,
|
||||
input_vec,
|
||||
)?;
|
||||
left.run(ctx, input_vec)?;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -291,13 +304,12 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
},
|
||||
|
||||
(
|
||||
Some(ClassifiedCommand::Internal(left)),
|
||||
Some(_),
|
||||
) => match left.run(ctx, input).await {
|
||||
Ok(val) => ClassifiedInputStream::from_input_stream(val),
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
},
|
||||
(Some(ClassifiedCommand::Internal(left)), Some(_)) => {
|
||||
match left.run(ctx, input).await {
|
||||
Ok(val) => ClassifiedInputStream::from_input_stream(val),
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
}
|
||||
}
|
||||
|
||||
(Some(ClassifiedCommand::Internal(left)), None) => {
|
||||
match left.run(ctx, input).await {
|
||||
@ -314,13 +326,12 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
},
|
||||
|
||||
(
|
||||
Some(ClassifiedCommand::External(left)),
|
||||
Some(_),
|
||||
) => match left.run(ctx, input, StreamNext::Internal).await {
|
||||
Ok(val) => val,
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
},
|
||||
(Some(ClassifiedCommand::External(left)), Some(_)) => {
|
||||
match left.run(ctx, input, StreamNext::Internal).await {
|
||||
Ok(val) => val,
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
}
|
||||
}
|
||||
|
||||
(Some(ClassifiedCommand::External(left)), None) => {
|
||||
match left.run(ctx, input, StreamNext::Last).await {
|
||||
@ -333,9 +344,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
||||
|
||||
LineResult::Success(line.clone())
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => {
|
||||
LineResult::Error("".to_string(), ShellError::string("CTRL-C"))
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => LineResult::CtrlC,
|
||||
Err(ReadlineError::Eof) => {
|
||||
println!("CTRL-D");
|
||||
LineResult::Break
|
||||
|
@ -5,7 +5,7 @@ use std::path::PathBuf;
|
||||
|
||||
pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let env = args.env.lock().unwrap();
|
||||
let latest = env.last().unwrap();
|
||||
let latest = env.back().unwrap();
|
||||
|
||||
match latest.obj {
|
||||
Value::Filesystem => {
|
||||
@ -13,17 +13,23 @@ pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let path = match args.positional.first() {
|
||||
None => match dirs::home_dir() {
|
||||
Some(o) => o,
|
||||
_ => return Err(ShellError::string("Can not change to home directory")),
|
||||
_ => {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Can not change to home directory",
|
||||
"can not go to home",
|
||||
args.name_span,
|
||||
))
|
||||
}
|
||||
},
|
||||
Some(v) => {
|
||||
let target = v.as_string()?.clone();
|
||||
match dunce::canonicalize(cwd.join(&target).as_path()) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Can not change to directory",
|
||||
"directory not found",
|
||||
args.positional[0].span.clone(),
|
||||
Some(args.positional[0].span.clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -35,10 +41,10 @@ pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
if args.positional.len() > 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Can not change to directory",
|
||||
"directory not found",
|
||||
args.positional[0].span.clone(),
|
||||
Some(args.positional[0].span.clone()),
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::string("Can not change to directory"));
|
||||
|
@ -4,6 +4,7 @@ use crate::parser::lexer::{Span, Spanned};
|
||||
use crate::parser::registry::Args;
|
||||
use crate::prelude::*;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use futures::stream::StreamExt;
|
||||
use futures_codec::{Decoder, Encoder, Framed};
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::path::PathBuf;
|
||||
@ -109,44 +110,47 @@ impl InternalCommand {
|
||||
context: &mut Context,
|
||||
input: ClassifiedInputStream,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
let result = context.run_command(
|
||||
let mut result = context.run_command(
|
||||
self.command,
|
||||
self.name_span.clone(),
|
||||
self.args,
|
||||
input.objects,
|
||||
)?;
|
||||
let env = context.env.clone();
|
||||
|
||||
let stream = result.filter_map(move |v| match v {
|
||||
ReturnValue::Action(action) => match action {
|
||||
CommandAction::ChangePath(path) => {
|
||||
env.lock().unwrap().last_mut().map(|x| {
|
||||
x.path = path;
|
||||
x
|
||||
});
|
||||
futures::future::ready(None)
|
||||
let mut stream = VecDeque::new();
|
||||
while let Some(item) = result.next().await {
|
||||
match item {
|
||||
ReturnValue::Value(Value::Error(err)) => {
|
||||
return Err(*err);
|
||||
}
|
||||
CommandAction::Enter(obj) => {
|
||||
let new_env = Environment {
|
||||
obj: obj,
|
||||
path: PathBuf::from("/"),
|
||||
};
|
||||
env.lock().unwrap().push(new_env);
|
||||
futures::future::ready(None)
|
||||
}
|
||||
CommandAction::Exit => {
|
||||
let mut v = env.lock().unwrap();
|
||||
if v.len() == 1 {
|
||||
std::process::exit(0);
|
||||
ReturnValue::Action(action) => match action {
|
||||
CommandAction::ChangePath(path) => {
|
||||
context.env.lock().unwrap().back_mut().map(|x| {
|
||||
x.path = path;
|
||||
x
|
||||
});
|
||||
}
|
||||
v.pop();
|
||||
futures::future::ready(None)
|
||||
CommandAction::Enter(obj) => {
|
||||
let new_env = Environment {
|
||||
obj: obj,
|
||||
path: PathBuf::from("/"),
|
||||
};
|
||||
context.env.lock().unwrap().push_back(new_env);
|
||||
}
|
||||
CommandAction::Exit => match context.env.lock().unwrap().pop_back() {
|
||||
Some(Environment {
|
||||
obj: Value::Filesystem,
|
||||
..
|
||||
}) => std::process::exit(0),
|
||||
None => std::process::exit(-1),
|
||||
_ => {}
|
||||
},
|
||||
},
|
||||
|
||||
ReturnValue::Value(v) => {
|
||||
stream.push_back(v);
|
||||
}
|
||||
},
|
||||
|
||||
ReturnValue::Value(v) => futures::future::ready(Some(v)),
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
Ok(stream.boxed() as InputStream)
|
||||
}
|
||||
}
|
||||
@ -265,7 +269,7 @@ impl ExternalCommand {
|
||||
}
|
||||
process = Exec::shell(new_arg_string);
|
||||
}
|
||||
process = process.cwd(context.env.lock().unwrap().first().unwrap().path());
|
||||
process = process.cwd(context.env.lock().unwrap().front().unwrap().path());
|
||||
|
||||
let mut process = match stream_next {
|
||||
StreamNext::Last => process,
|
||||
|
@ -8,7 +8,7 @@ use std::path::PathBuf;
|
||||
|
||||
pub struct CommandArgs {
|
||||
pub host: Arc<Mutex<dyn Host + Send>>,
|
||||
pub env: Arc<Mutex<Vec<Environment>>>,
|
||||
pub env: Arc<Mutex<VecDeque<Environment>>>,
|
||||
pub name_span: Option<Span>,
|
||||
pub positional: Vec<Spanned<Value>>,
|
||||
pub named: indexmap::IndexMap<String, Value>,
|
||||
|
@ -7,14 +7,18 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.positional.len() == 0 {
|
||||
return Err(ShellError::string("open requires a filepath or url"));
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"open requires a path or url",
|
||||
"missing path",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let cwd = args
|
||||
.env
|
||||
.lock()
|
||||
.unwrap()
|
||||
.first()
|
||||
.front()
|
||||
.unwrap()
|
||||
.path()
|
||||
.to_path_buf();
|
||||
|
@ -5,15 +5,11 @@ use crate::prelude::*;
|
||||
|
||||
pub fn first(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.positional.len() == 0 {
|
||||
if let Some(span) = args.name_span {
|
||||
return Err(ShellError::labeled_error(
|
||||
"First requires an amount",
|
||||
"needs parameter",
|
||||
span,
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::string("first requires an amount."));
|
||||
}
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"First requires an amount",
|
||||
"needs parameter",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let amount = args.positional[0].as_i64();
|
||||
|
@ -57,11 +57,16 @@ pub fn from_xml_string_to_value(s: String) -> Value {
|
||||
|
||||
pub fn from_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
let span = args.name_span;
|
||||
Ok(out
|
||||
.map(|a| match a {
|
||||
Value::Primitive(Primitive::String(s)) => ReturnValue::Value(from_xml_string_to_value(s)),
|
||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::string(
|
||||
.map(move |a| match a {
|
||||
Value::Primitive(Primitive::String(s)) => {
|
||||
ReturnValue::Value(from_xml_string_to_value(s))
|
||||
}
|
||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
"Trying to convert XML from non-string".to_string(),
|
||||
"given non-string",
|
||||
span,
|
||||
)))),
|
||||
})
|
||||
.boxed())
|
||||
|
@ -1,17 +1,19 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::Value;
|
||||
use crate::parser::lexer::Span;
|
||||
use crate::prelude::*;
|
||||
|
||||
fn get_member(path: &str, obj: &Value) -> Option<Value> {
|
||||
fn get_member(path: &str, span: Span, obj: &Value) -> Option<Value> {
|
||||
let mut current = obj;
|
||||
for p in path.split(".") {
|
||||
match current.get_data_by_key(p) {
|
||||
Some(v) => current = v,
|
||||
None => {
|
||||
return Some(Value::Error(Box::new(ShellError::string(format!(
|
||||
"Object field name not found: {}",
|
||||
p
|
||||
)))))
|
||||
return Some(Value::Error(Box::new(ShellError::labeled_error(
|
||||
"Unknown field",
|
||||
"object missing field",
|
||||
span,
|
||||
))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,15 +23,11 @@ fn get_member(path: &str, obj: &Value) -> Option<Value> {
|
||||
|
||||
pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.positional.len() == 0 {
|
||||
if let Some(span) = args.name_span {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Get requires a field or field path",
|
||||
"needs parameter",
|
||||
span,
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::string("get requires fields."));
|
||||
}
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Get requires a field or field path",
|
||||
"needs parameter",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let amount = args.positional[0].as_i64();
|
||||
@ -44,7 +42,11 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
.boxed());
|
||||
}
|
||||
|
||||
let fields: Result<Vec<String>, _> = args.positional.iter().map(|a| a.as_string()).collect();
|
||||
let fields: Result<Vec<(String, Span)>, _> = args
|
||||
.positional
|
||||
.iter()
|
||||
.map(|a| (a.as_string().map(|x| (x, a.span))))
|
||||
.collect();
|
||||
let fields = fields?;
|
||||
|
||||
let stream = args
|
||||
@ -52,7 +54,7 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
.map(move |item| {
|
||||
let mut result = VecDeque::new();
|
||||
for field in &fields {
|
||||
match get_member(field, &item) {
|
||||
match get_member(&field.0, field.1, &item) {
|
||||
Some(Value::List(l)) => {
|
||||
for item in l {
|
||||
result.push_back(ReturnValue::Value(item.copy()));
|
||||
|
@ -7,8 +7,8 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let env = args.env.lock().unwrap();
|
||||
let path = env.last().unwrap().path.to_path_buf();
|
||||
let obj = &env.last().unwrap().obj;
|
||||
let path = env.back().unwrap().path.to_path_buf();
|
||||
let obj = &env.back().unwrap().obj;
|
||||
let mut full_path = PathBuf::from(path);
|
||||
match &args.positional.get(0) {
|
||||
Some(Spanned {
|
||||
@ -31,7 +31,11 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
s.span,
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::string(e.to_string()));
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(o) => o,
|
||||
|
@ -6,14 +6,18 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
pub fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.positional.len() == 0 {
|
||||
return Err(ShellError::string("open requires a filepath or url"));
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Open requires a path or url",
|
||||
"needs path or url",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let cwd = args
|
||||
.env
|
||||
.lock()
|
||||
.unwrap()
|
||||
.first()
|
||||
.front()
|
||||
.unwrap()
|
||||
.path()
|
||||
.to_path_buf();
|
||||
|
@ -5,15 +5,11 @@ use crate::prelude::*;
|
||||
|
||||
pub fn pick(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.positional.len() == 0 {
|
||||
if let Some(span) = args.name_span {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Pick requires fields",
|
||||
"needs parameter",
|
||||
span,
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::string("pick requires fields."));
|
||||
}
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Pick requires fields",
|
||||
"needs parameter",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let fields: Result<Vec<String>, _> = args.positional.iter().map(|a| a.as_string()).collect();
|
||||
|
@ -5,15 +5,11 @@ use crate::prelude::*;
|
||||
|
||||
pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.positional.len() == 0 {
|
||||
if let Some(span) = args.name_span {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Reject requires fields",
|
||||
"needs parameter",
|
||||
span,
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::string("reject requires fields."));
|
||||
}
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Reject requires fields",
|
||||
"needs parameter",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let fields: Result<Vec<String>, _> = args.positional.iter().map(|a| a.as_string()).collect();
|
||||
|
@ -6,7 +6,11 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
if args.positional.len() == 0 {
|
||||
return Err(ShellError::string("save requires a filepath"));
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Save requires a filepath",
|
||||
"needs path",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let cwd = args
|
||||
@ -14,7 +18,7 @@ pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
.env
|
||||
.lock()
|
||||
.unwrap()
|
||||
.first()
|
||||
.front()
|
||||
.unwrap()
|
||||
.path()
|
||||
.to_path_buf();
|
||||
|
@ -6,14 +6,18 @@ use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
|
||||
pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.positional.is_empty() {
|
||||
return Err(ShellError::string("size requires at least one file"));
|
||||
if args.positional.len() == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Size requires a filepath",
|
||||
"needs path",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
let cwd = args
|
||||
.env
|
||||
.lock()
|
||||
.unwrap()
|
||||
.first()
|
||||
.front()
|
||||
.unwrap()
|
||||
.path()
|
||||
.to_path_buf();
|
||||
|
@ -3,15 +3,11 @@ use crate::prelude::*;
|
||||
|
||||
pub fn skip(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.positional.len() == 0 {
|
||||
if let Some(span) = args.name_span {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Skip requires an amount",
|
||||
"needs parameter",
|
||||
span,
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::string("skip requires an amount."));
|
||||
}
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Skip requires an amount",
|
||||
"needs parameter",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let amount = args.positional[0].as_i64();
|
||||
|
@ -4,15 +4,11 @@ use prettyprint::PrettyPrinter;
|
||||
|
||||
pub fn view(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.positional.len() == 0 {
|
||||
if let Some(span) = args.name_span {
|
||||
return Err(ShellError::labeled_error(
|
||||
"View requires a filename",
|
||||
"needs parameter",
|
||||
span,
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::string("view requires a filename."));
|
||||
}
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"View requires a filename",
|
||||
"needs parameter",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let target = match args.positional[0].as_string() {
|
||||
@ -34,7 +30,7 @@ pub fn view(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
.env
|
||||
.lock()
|
||||
.unwrap()
|
||||
.first()
|
||||
.front()
|
||||
.unwrap()
|
||||
.path()
|
||||
.to_path_buf();
|
||||
|
@ -25,8 +25,12 @@ impl Command for Where {
|
||||
}
|
||||
|
||||
pub fn r#where(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.positional.is_empty() {
|
||||
return Err(ShellError::string("select requires a field"));
|
||||
if args.positional.len() == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Where requires a condition",
|
||||
"needs condition",
|
||||
args.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let block = args.positional[0].as_block()?;
|
||||
|
@ -13,16 +13,18 @@ pub struct Context {
|
||||
commands: IndexMap<String, Arc<dyn Command>>,
|
||||
sinks: IndexMap<String, Arc<dyn Sink>>,
|
||||
crate host: Arc<Mutex<dyn Host + Send>>,
|
||||
crate env: Arc<Mutex<Vec<Environment>>>,
|
||||
crate env: Arc<Mutex<VecDeque<Environment>>>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
crate fn basic() -> Result<Context, Box<dyn Error>> {
|
||||
let mut env = VecDeque::new();
|
||||
env.push_back(Environment::basic()?);
|
||||
Ok(Context {
|
||||
commands: indexmap::IndexMap::new(),
|
||||
sinks: indexmap::IndexMap::new(),
|
||||
host: Arc::new(Mutex::new(crate::env::host::BasicHost)),
|
||||
env: Arc::new(Mutex::new(vec![Environment::basic()?])),
|
||||
env: Arc::new(Mutex::new(env)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,20 @@ impl ShellError {
|
||||
)
|
||||
}
|
||||
|
||||
crate fn maybe_labeled_error(
|
||||
msg: impl Into<String>,
|
||||
label: impl Into<String>,
|
||||
span: Option<Span>,
|
||||
) -> ShellError {
|
||||
match span {
|
||||
Some(span) => ShellError::diagnostic(
|
||||
Diagnostic::new(Severity::Error, msg.into())
|
||||
.with_label(Label::new_primary(span).with_message(label.into())),
|
||||
),
|
||||
None => ShellError::string(msg),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn string(title: impl Into<String>) -> ShellError {
|
||||
ShellError::String(StringError::new(title.into(), Value::nothing()))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user