mirror of
https://github.com/nushell/nushell
synced 2024-12-27 05:23:11 +00:00
Remove unwraps (#1153)
* Remove a batch of unwraps * finish another batch
This commit is contained in:
parent
339a2de0eb
commit
5919c6c433
27 changed files with 449 additions and 220 deletions
|
@ -254,7 +254,7 @@ pub struct ExpandTracer {
|
||||||
|
|
||||||
impl ExpandTracer {
|
impl ExpandTracer {
|
||||||
pub fn print(&self, source: Text) -> PrintTracer {
|
pub fn print(&self, source: Text) -> PrintTracer {
|
||||||
let root = self.frame_stack.get(0).unwrap().to_tree_frame(&source);
|
let root = self.frame_stack[0].to_tree_frame(&source);
|
||||||
|
|
||||||
PrintTracer { root, source }
|
PrintTracer { root, source }
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,11 @@ impl CompareOperator {
|
||||||
|
|
||||||
impl From<&str> for CompareOperator {
|
impl From<&str> for CompareOperator {
|
||||||
fn from(input: &str) -> CompareOperator {
|
fn from(input: &str) -> CompareOperator {
|
||||||
CompareOperator::from_str(input).unwrap()
|
if let Ok(output) = CompareOperator::from_str(input) {
|
||||||
|
output
|
||||||
|
} else {
|
||||||
|
unreachable!("Internal error: CompareOperator from failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +94,11 @@ impl EvaluationOperator {
|
||||||
|
|
||||||
impl From<&str> for EvaluationOperator {
|
impl From<&str> for EvaluationOperator {
|
||||||
fn from(input: &str) -> EvaluationOperator {
|
fn from(input: &str) -> EvaluationOperator {
|
||||||
EvaluationOperator::from_str(input).unwrap()
|
if let Ok(output) = EvaluationOperator::from_str(input) {
|
||||||
|
output
|
||||||
|
} else {
|
||||||
|
unreachable!("Internal error: EvaluationOperator 'from' failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,13 +148,21 @@ macro_rules! primitive_decimal {
|
||||||
$(
|
$(
|
||||||
impl From<$ty> for Number {
|
impl From<$ty> for Number {
|
||||||
fn from(decimal: $ty) -> Number {
|
fn from(decimal: $ty) -> Number {
|
||||||
Number::Decimal(BigDecimal::$from(decimal).unwrap())
|
if let Some(num) = BigDecimal::$from(decimal) {
|
||||||
|
Number::Decimal(num)
|
||||||
|
} else {
|
||||||
|
unreachable!("Internal error: BigDecimal 'from' failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&$ty> for Number {
|
impl From<&$ty> for Number {
|
||||||
fn from(decimal: &$ty) -> Number {
|
fn from(decimal: &$ty) -> Number {
|
||||||
Number::Decimal(BigDecimal::$from(*decimal).unwrap())
|
if let Some(num) = BigDecimal::$from(*decimal) {
|
||||||
|
Number::Decimal(num)
|
||||||
|
} else {
|
||||||
|
unreachable!("Internal error: BigDecimal 'from' failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
@ -909,11 +917,13 @@ pub fn module(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_int<T>(frag: &str, neg: Option<T>) -> i64 {
|
fn parse_int<T>(frag: &str, neg: Option<T>) -> i64 {
|
||||||
let int = FromStr::from_str(frag).unwrap();
|
if let Ok(int) = FromStr::from_str(frag) {
|
||||||
|
match neg {
|
||||||
match neg {
|
None => int,
|
||||||
None => int,
|
Some(_) => -int,
|
||||||
Some(_) => -int,
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!("Internal error: parse_int failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -323,10 +323,13 @@ impl TokenTreeBuilder {
|
||||||
|
|
||||||
let mut input = input.into_iter();
|
let mut input = input.into_iter();
|
||||||
|
|
||||||
let head = input.next().unwrap();
|
if let Some(head) = input.next() {
|
||||||
let tail = input.collect();
|
let tail = input.collect();
|
||||||
|
|
||||||
CallNode::new(Box::new(head), tail).spanned(span.into())
|
CallNode::new(Box::new(head), tail).spanned(span.into())
|
||||||
|
} else {
|
||||||
|
unreachable!("Internal error: spanned_call failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume_delimiter(
|
fn consume_delimiter(
|
||||||
|
|
|
@ -88,9 +88,19 @@ impl RawNumber {
|
||||||
|
|
||||||
pub(crate) fn to_number(self, source: &Text) -> Number {
|
pub(crate) fn to_number(self, source: &Text) -> Number {
|
||||||
match self {
|
match self {
|
||||||
RawNumber::Int(tag) => Number::Int(BigInt::from_str(tag.slice(source)).unwrap()),
|
RawNumber::Int(tag) => {
|
||||||
|
if let Ok(int) = BigInt::from_str(tag.slice(source)) {
|
||||||
|
Number::Int(int)
|
||||||
|
} else {
|
||||||
|
unreachable!("Internal error: to_number failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
RawNumber::Decimal(tag) => {
|
RawNumber::Decimal(tag) => {
|
||||||
Number::Decimal(BigDecimal::from_str(tag.slice(source)).unwrap())
|
if let Ok(decimal) = BigDecimal::from_str(tag.slice(source)) {
|
||||||
|
Number::Decimal(decimal)
|
||||||
|
} else {
|
||||||
|
unreachable!("Internal error: to_number failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,14 +124,14 @@ impl CallStub {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_parameter(&mut self, name: &str) -> &mut Self {
|
pub fn with_parameter(&mut self, name: &str) -> Result<&mut Self, ShellError> {
|
||||||
let fields: Vec<Value> = name
|
let fields: Vec<Value> = name
|
||||||
.split('.')
|
.split('.')
|
||||||
.map(|s| UntaggedValue::string(s.to_string()).into_value(Tag::unknown()))
|
.map(|s| UntaggedValue::string(s.to_string()).into_value(Tag::unknown()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.positionals.push(value::column_path(&fields));
|
self.positionals.push(value::column_path(&fields)?);
|
||||||
self
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(&self) -> CallInfo {
|
pub fn create(&self) -> CallInfo {
|
||||||
|
@ -156,7 +156,11 @@ pub fn expect_return_value_at(
|
||||||
};
|
};
|
||||||
|
|
||||||
if idx == at {
|
if idx == at {
|
||||||
return item.raw_value().unwrap();
|
if let Some(value) = item.raw_value() {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
panic!("Internal error: could not get raw value in expect_return_value_at")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +172,7 @@ pub fn expect_return_value_at(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod value {
|
pub mod value {
|
||||||
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Primitive, TaggedDictBuilder, UntaggedValue, Value};
|
use nu_protocol::{Primitive, TaggedDictBuilder, UntaggedValue, Value};
|
||||||
use nu_source::Tag;
|
use nu_source::Tag;
|
||||||
use nu_value_ext::ValueExt;
|
use nu_value_ext::ValueExt;
|
||||||
|
@ -199,10 +204,10 @@ pub mod value {
|
||||||
UntaggedValue::table(list).into_untagged_value()
|
UntaggedValue::table(list).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn column_path(paths: &[Value]) -> Value {
|
pub fn column_path(paths: &[Value]) -> Result<Value, ShellError> {
|
||||||
UntaggedValue::Primitive(Primitive::ColumnPath(
|
Ok(UntaggedValue::Primitive(Primitive::ColumnPath(
|
||||||
table(&paths.to_vec()).as_column_path().unwrap().item,
|
table(&paths.to_vec()).as_column_path()?.item,
|
||||||
))
|
))
|
||||||
.into_untagged_value()
|
.into_untagged_value())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,11 @@ impl AbsoluteFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dir(&self) -> AbsolutePath {
|
pub fn dir(&self) -> AbsolutePath {
|
||||||
AbsolutePath::new(self.inner.parent().unwrap())
|
AbsolutePath::new(if let Some(parent) = self.inner.parent() {
|
||||||
|
parent
|
||||||
|
} else {
|
||||||
|
unreachable!("Internal error: could not get parent in dir")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
mod integration {
|
mod integration {
|
||||||
use crate::inc::{Action, SemVerAction};
|
use crate::inc::{Action, SemVerAction};
|
||||||
use crate::Inc;
|
use crate::Inc;
|
||||||
|
use nu_errors::ShellError;
|
||||||
use nu_plugin::test_helpers::value::{column_path, string};
|
use nu_plugin::test_helpers::value::{column_path, string};
|
||||||
use nu_plugin::test_helpers::{plugin, CallStub};
|
use nu_plugin::test_helpers::{plugin, CallStub};
|
||||||
|
|
||||||
|
@ -52,16 +53,21 @@ mod integration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn picks_up_argument_for_field() {
|
fn picks_up_argument_for_field() -> Result<(), ShellError> {
|
||||||
plugin(&mut Inc::new())
|
plugin(&mut Inc::new())
|
||||||
.args(CallStub::new().with_parameter("package.version").create())
|
.args(CallStub::new().with_parameter("package.version")?.create())
|
||||||
.setup(|plugin, _| {
|
.setup(|plugin, _| {
|
||||||
plugin.expect_field(column_path(&[string("package"), string("version")]))
|
//FIXME: this will need to be updated
|
||||||
|
if let Ok(column_path) = column_path(&[string("package"), string("version")]) {
|
||||||
|
plugin.expect_field(column_path)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
mod sem_ver {
|
mod sem_ver {
|
||||||
use crate::Inc;
|
use crate::Inc;
|
||||||
|
use nu_errors::ShellError;
|
||||||
use nu_plugin::test_helpers::value::{get_data, string, structured_sample_record};
|
use nu_plugin::test_helpers::value::{get_data, string, structured_sample_record};
|
||||||
use nu_plugin::test_helpers::{expect_return_value_at, plugin, CallStub};
|
use nu_plugin::test_helpers::{expect_return_value_at, plugin, CallStub};
|
||||||
|
|
||||||
|
@ -70,12 +76,12 @@ mod integration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn major_input_using_the_field_passed_as_parameter() {
|
fn major_input_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
|
||||||
let run = plugin(&mut Inc::new())
|
let run = plugin(&mut Inc::new())
|
||||||
.args(
|
.args(
|
||||||
CallStub::new()
|
CallStub::new()
|
||||||
.with_long_flag("major")
|
.with_long_flag("major")
|
||||||
.with_parameter("version")
|
.with_parameter("version")?
|
||||||
.create(),
|
.create(),
|
||||||
)
|
)
|
||||||
.input(cargo_sample_record("0.1.3"))
|
.input(cargo_sample_record("0.1.3"))
|
||||||
|
@ -85,15 +91,16 @@ mod integration {
|
||||||
let actual = expect_return_value_at(run, 0);
|
let actual = expect_return_value_at(run, 0);
|
||||||
|
|
||||||
assert_eq!(get_data(actual, "version"), string("1.0.0"));
|
assert_eq!(get_data(actual, "version"), string("1.0.0"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn minor_input_using_the_field_passed_as_parameter() {
|
fn minor_input_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
|
||||||
let run = plugin(&mut Inc::new())
|
let run = plugin(&mut Inc::new())
|
||||||
.args(
|
.args(
|
||||||
CallStub::new()
|
CallStub::new()
|
||||||
.with_long_flag("minor")
|
.with_long_flag("minor")
|
||||||
.with_parameter("version")
|
.with_parameter("version")?
|
||||||
.create(),
|
.create(),
|
||||||
)
|
)
|
||||||
.input(cargo_sample_record("0.1.3"))
|
.input(cargo_sample_record("0.1.3"))
|
||||||
|
@ -103,15 +110,16 @@ mod integration {
|
||||||
let actual = expect_return_value_at(run, 0);
|
let actual = expect_return_value_at(run, 0);
|
||||||
|
|
||||||
assert_eq!(get_data(actual, "version"), string("0.2.0"));
|
assert_eq!(get_data(actual, "version"), string("0.2.0"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn patch_input_using_the_field_passed_as_parameter() {
|
fn patch_input_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
|
||||||
let run = plugin(&mut Inc::new())
|
let run = plugin(&mut Inc::new())
|
||||||
.args(
|
.args(
|
||||||
CallStub::new()
|
CallStub::new()
|
||||||
.with_long_flag("patch")
|
.with_long_flag("patch")
|
||||||
.with_parameter("version")
|
.with_parameter("version")?
|
||||||
.create(),
|
.create(),
|
||||||
)
|
)
|
||||||
.input(cargo_sample_record("0.1.3"))
|
.input(cargo_sample_record("0.1.3"))
|
||||||
|
@ -121,6 +129,7 @@ mod integration {
|
||||||
let actual = expect_return_value_at(run, 0);
|
let actual = expect_return_value_at(run, 0);
|
||||||
|
|
||||||
assert_eq!(get_data(actual, "version"), string("0.1.4"));
|
assert_eq!(get_data(actual, "version"), string("0.1.4"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
mod integration {
|
mod integration {
|
||||||
use crate::strutils::{Action, ReplaceAction};
|
use crate::strutils::{Action, ReplaceAction};
|
||||||
use crate::Str;
|
use crate::Str;
|
||||||
|
use nu_errors::ShellError;
|
||||||
use nu_plugin::test_helpers::value::{
|
use nu_plugin::test_helpers::value::{
|
||||||
column_path, get_data, int, string, structured_sample_record, table,
|
column_path, get_data, int, string, structured_sample_record, table,
|
||||||
unstructured_sample_record,
|
unstructured_sample_record,
|
||||||
|
@ -83,16 +84,21 @@ mod integration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn picks_up_argument_for_field() {
|
fn picks_up_argument_for_field() -> Result<(), ShellError> {
|
||||||
plugin(&mut Str::new())
|
plugin(&mut Str::new())
|
||||||
.args(
|
.args(
|
||||||
CallStub::new()
|
CallStub::new()
|
||||||
.with_parameter("package.description")
|
.with_parameter("package.description")?
|
||||||
.create(),
|
.create(),
|
||||||
)
|
)
|
||||||
.setup(|plugin, _| {
|
.setup(|plugin, _| {
|
||||||
plugin.expect_field(column_path(&[string("package"), string("description")]))
|
//FIXME: this is possibly not correct
|
||||||
|
if let Ok(column_path) = column_path(&[string("package"), string("description")]) {
|
||||||
|
plugin.expect_field(column_path)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -115,12 +121,12 @@ mod integration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn upcases_the_input_using_the_field_passed_as_parameter() {
|
fn upcases_the_input_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
|
||||||
let run = plugin(&mut Str::new())
|
let run = plugin(&mut Str::new())
|
||||||
.args(
|
.args(
|
||||||
CallStub::new()
|
CallStub::new()
|
||||||
.with_long_flag("upcase")
|
.with_long_flag("upcase")
|
||||||
.with_parameter("name")
|
.with_parameter("name")?
|
||||||
.create(),
|
.create(),
|
||||||
)
|
)
|
||||||
.input(structured_sample_record("name", "jotandrehuda"))
|
.input(structured_sample_record("name", "jotandrehuda"))
|
||||||
|
@ -130,15 +136,16 @@ mod integration {
|
||||||
let actual = expect_return_value_at(run, 0);
|
let actual = expect_return_value_at(run, 0);
|
||||||
|
|
||||||
assert_eq!(get_data(actual, "name"), string("JOTANDREHUDA"));
|
assert_eq!(get_data(actual, "name"), string("JOTANDREHUDA"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn downcases_the_input_using_the_field_passed_as_parameter() {
|
fn downcases_the_input_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
|
||||||
let run = plugin(&mut Str::new())
|
let run = plugin(&mut Str::new())
|
||||||
.args(
|
.args(
|
||||||
CallStub::new()
|
CallStub::new()
|
||||||
.with_long_flag("downcase")
|
.with_long_flag("downcase")
|
||||||
.with_parameter("name")
|
.with_parameter("name")?
|
||||||
.create(),
|
.create(),
|
||||||
)
|
)
|
||||||
.input(structured_sample_record("name", "JOTANDREHUDA"))
|
.input(structured_sample_record("name", "JOTANDREHUDA"))
|
||||||
|
@ -148,15 +155,17 @@ mod integration {
|
||||||
let actual = expect_return_value_at(run, 0);
|
let actual = expect_return_value_at(run, 0);
|
||||||
|
|
||||||
assert_eq!(get_data(actual, "name"), string("jotandrehuda"));
|
assert_eq!(get_data(actual, "name"), string("jotandrehuda"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn converts_the_input_to_integer_using_the_field_passed_as_parameter() {
|
fn converts_the_input_to_integer_using_the_field_passed_as_parameter() -> Result<(), ShellError>
|
||||||
|
{
|
||||||
let run = plugin(&mut Str::new())
|
let run = plugin(&mut Str::new())
|
||||||
.args(
|
.args(
|
||||||
CallStub::new()
|
CallStub::new()
|
||||||
.with_long_flag("to-int")
|
.with_long_flag("to-int")
|
||||||
.with_parameter("Nu_birthday")
|
.with_parameter("Nu_birthday")?
|
||||||
.create(),
|
.create(),
|
||||||
)
|
)
|
||||||
.input(structured_sample_record("Nu_birthday", "10"))
|
.input(structured_sample_record("Nu_birthday", "10"))
|
||||||
|
@ -166,14 +175,15 @@ mod integration {
|
||||||
let actual = expect_return_value_at(run, 0);
|
let actual = expect_return_value_at(run, 0);
|
||||||
|
|
||||||
assert_eq!(get_data(actual, "Nu_birthday"), int(10));
|
assert_eq!(get_data(actual, "Nu_birthday"), int(10));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn replaces_the_input_using_the_field_passed_as_parameter() {
|
fn replaces_the_input_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
|
||||||
let run = plugin(&mut Str::new())
|
let run = plugin(&mut Str::new())
|
||||||
.args(
|
.args(
|
||||||
CallStub::new()
|
CallStub::new()
|
||||||
.with_parameter("rustconf")
|
.with_parameter("rustconf")?
|
||||||
.with_named_parameter("replace", string("22nd August 2019"))
|
.with_named_parameter("replace", string("22nd August 2019"))
|
||||||
.create(),
|
.create(),
|
||||||
)
|
)
|
||||||
|
@ -184,14 +194,15 @@ mod integration {
|
||||||
let actual = expect_return_value_at(run, 0);
|
let actual = expect_return_value_at(run, 0);
|
||||||
|
|
||||||
assert_eq!(get_data(actual, "rustconf"), string("22nd August 2019"));
|
assert_eq!(get_data(actual, "rustconf"), string("22nd August 2019"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn find_and_replaces_the_input_using_the_field_passed_as_parameter() {
|
fn find_and_replaces_the_input_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
|
||||||
let run = plugin(&mut Str::new())
|
let run = plugin(&mut Str::new())
|
||||||
.args(
|
.args(
|
||||||
CallStub::new()
|
CallStub::new()
|
||||||
.with_parameter("staff")
|
.with_parameter("staff")?
|
||||||
.with_named_parameter(
|
.with_named_parameter(
|
||||||
"find-replace",
|
"find-replace",
|
||||||
table(&[string("kittens"), string("jotandrehuda")]),
|
table(&[string("kittens"), string("jotandrehuda")]),
|
||||||
|
@ -205,6 +216,7 @@ mod integration {
|
||||||
let actual = expect_return_value_at(run, 0);
|
let actual = expect_return_value_at(run, 0);
|
||||||
|
|
||||||
assert_eq!(get_data(actual, "staff"), string("wyjotandrehuda"));
|
assert_eq!(get_data(actual, "staff"), string("wyjotandrehuda"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
10
src/cli.rs
10
src/cli.rs
|
@ -384,7 +384,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cwd = context.shell_manager.path();
|
let cwd = context.shell_manager.path()?;
|
||||||
|
|
||||||
rl.set_helper(Some(crate::shell::Helper::new(context.clone())));
|
rl.set_helper(Some(crate::shell::Helper::new(context.clone())));
|
||||||
|
|
||||||
|
@ -452,7 +452,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
|
|
||||||
context.with_host(|host| {
|
context.with_host(|host| {
|
||||||
print_err(err, host, &Text::from(line.clone()));
|
print_err(err, host, &Text::from(line.clone()));
|
||||||
});
|
})?;
|
||||||
|
|
||||||
context.maybe_print_errors(Text::from(line.clone()));
|
context.maybe_print_errors(Text::from(line.clone()));
|
||||||
}
|
}
|
||||||
|
@ -474,7 +474,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
let _ = rl.save_history(&History::path());
|
let _ = rl.save_history(&History::path());
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
} else {
|
} else {
|
||||||
context.with_host(|host| host.stdout("CTRL-C pressed (again to quit)"));
|
context.with_host(|host| host.stdout("CTRL-C pressed (again to quit)"))?;
|
||||||
ctrlcbreak = true;
|
ctrlcbreak = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -634,13 +634,13 @@ pub fn classify_pipeline(
|
||||||
let result = expand_syntax(
|
let result = expand_syntax(
|
||||||
&PipelineShape,
|
&PipelineShape,
|
||||||
&mut iterator,
|
&mut iterator,
|
||||||
&context.expand_context(source),
|
&context.expand_context(source)?,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.into());
|
.map_err(|err| err.into());
|
||||||
|
|
||||||
if log_enabled!(target: "nu::expand_syntax", log::Level::Debug) {
|
if log_enabled!(target: "nu::expand_syntax", log::Level::Debug) {
|
||||||
outln!("");
|
outln!("");
|
||||||
ptree::print_tree(&iterator.expand_tracer().print(source.clone())).unwrap();
|
let _ = ptree::print_tree(&iterator.expand_tracer().print(source.clone()));
|
||||||
outln!("");
|
outln!("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,7 @@ pub(crate) async fn run_external_command(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
process = process.cwd(context.shell_manager.path());
|
process = process.cwd(context.shell_manager.path()?);
|
||||||
|
|
||||||
trace!(target: "nu::run::external", "cwd = {:?}", context.shell_manager.path());
|
trace!(target: "nu::run::external", "cwd = {:?}", context.shell_manager.path());
|
||||||
|
|
||||||
|
|
|
@ -46,11 +46,11 @@ pub(crate) async fn run_internal_command(
|
||||||
match item {
|
match item {
|
||||||
Ok(ReturnSuccess::Action(action)) => match action {
|
Ok(ReturnSuccess::Action(action)) => match action {
|
||||||
CommandAction::ChangePath(path) => {
|
CommandAction::ChangePath(path) => {
|
||||||
context.shell_manager.set_path(path);
|
context.shell_manager.set_path(path)?;
|
||||||
}
|
}
|
||||||
CommandAction::Exit => std::process::exit(0), // TODO: save history.txt
|
CommandAction::Exit => std::process::exit(0), // TODO: save history.txt
|
||||||
CommandAction::Error(err) => {
|
CommandAction::Error(err) => {
|
||||||
context.error(err);
|
context.error(err)?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
CommandAction::AutoConvert(tagged_contents, extension) => {
|
CommandAction::AutoConvert(tagged_contents, extension) => {
|
||||||
|
@ -99,39 +99,43 @@ pub(crate) async fn run_internal_command(
|
||||||
value: UntaggedValue::Primitive(Primitive::String(cmd)),
|
value: UntaggedValue::Primitive(Primitive::String(cmd)),
|
||||||
tag,
|
tag,
|
||||||
} => {
|
} => {
|
||||||
context.shell_manager.insert_at_current(Box::new(
|
let result = context.shell_manager.insert_at_current(Box::new(
|
||||||
HelpShell::for_command(
|
HelpShell::for_command(
|
||||||
UntaggedValue::string(cmd).into_value(tag),
|
UntaggedValue::string(cmd).into_value(tag),
|
||||||
&context.registry(),
|
&context.registry(),
|
||||||
)?,
|
)?,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
result?
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
context.shell_manager.insert_at_current(Box::new(
|
let result = context.shell_manager.insert_at_current(Box::new(
|
||||||
HelpShell::index(&context.registry()).unwrap(),
|
HelpShell::index(&context.registry())?,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
result?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CommandAction::EnterValueShell(value) => {
|
CommandAction::EnterValueShell(value) => {
|
||||||
context
|
context
|
||||||
.shell_manager
|
.shell_manager
|
||||||
.insert_at_current(Box::new(ValueShell::new(value)));
|
.insert_at_current(Box::new(ValueShell::new(value)))?;
|
||||||
}
|
}
|
||||||
CommandAction::EnterShell(location) => {
|
CommandAction::EnterShell(location) => {
|
||||||
context.shell_manager.insert_at_current(Box::new(
|
context.shell_manager.insert_at_current(Box::new(
|
||||||
FilesystemShell::with_location(location, context.registry().clone()).unwrap(),
|
FilesystemShell::with_location(location, context.registry().clone()).unwrap(),
|
||||||
));
|
))?;
|
||||||
}
|
}
|
||||||
CommandAction::PreviousShell => {
|
CommandAction::PreviousShell => {
|
||||||
context.shell_manager.prev();
|
context.shell_manager.prev()?;
|
||||||
}
|
}
|
||||||
CommandAction::NextShell => {
|
CommandAction::NextShell => {
|
||||||
context.shell_manager.next();
|
context.shell_manager.next()?;
|
||||||
}
|
}
|
||||||
CommandAction::LeaveShell => {
|
CommandAction::LeaveShell => {
|
||||||
context.shell_manager.remove_at_current();
|
context.shell_manager.remove_at_current()?;
|
||||||
if context.shell_manager.is_empty() {
|
if context.shell_manager.is_empty()? {
|
||||||
std::process::exit(0); // TODO: save history.txt
|
std::process::exit(0); // TODO: save history.txt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,7 +153,7 @@ pub(crate) async fn run_internal_command(
|
||||||
let mut buffer = termcolor::Buffer::ansi();
|
let mut buffer = termcolor::Buffer::ansi();
|
||||||
|
|
||||||
let _ = doc.render_raw(
|
let _ = doc.render_raw(
|
||||||
context.with_host(|host| host.width() - 5),
|
context.with_host(|host| host.width() - 5)?,
|
||||||
&mut nu_source::TermColored::new(&mut buffer),
|
&mut nu_source::TermColored::new(&mut buffer),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -159,7 +163,7 @@ pub(crate) async fn run_internal_command(
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
context.error(err);
|
context.error(err)?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,35 +55,52 @@ pub mod clipboard {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn inner_clip(input: Vec<Value>, name: Tag) -> OutputStream {
|
async fn inner_clip(input: Vec<Value>, name: Tag) -> OutputStream {
|
||||||
let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap();
|
if let Ok(clip_context) = ClipboardProvider::new() {
|
||||||
let mut new_copy_data = String::new();
|
let mut clip_context: ClipboardContext = clip_context;
|
||||||
|
let mut new_copy_data = String::new();
|
||||||
|
|
||||||
if !input.is_empty() {
|
if !input.is_empty() {
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for i in input.iter() {
|
for i in input.iter() {
|
||||||
if !first {
|
if !first {
|
||||||
new_copy_data.push_str("\n");
|
new_copy_data.push_str("\n");
|
||||||
} else {
|
} else {
|
||||||
first = false;
|
first = false;
|
||||||
}
|
|
||||||
|
|
||||||
let string: String = match i.as_string() {
|
|
||||||
Ok(string) => string.to_string(),
|
|
||||||
Err(_) => {
|
|
||||||
return OutputStream::one(Err(ShellError::labeled_error(
|
|
||||||
"Given non-string data",
|
|
||||||
"expected strings from pipeline",
|
|
||||||
name,
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
new_copy_data.push_str(&string);
|
let string: String = match i.as_string() {
|
||||||
|
Ok(string) => string.to_string(),
|
||||||
|
Err(_) => {
|
||||||
|
return OutputStream::one(Err(ShellError::labeled_error(
|
||||||
|
"Given non-string data",
|
||||||
|
"expected strings from pipeline",
|
||||||
|
name,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
new_copy_data.push_str(&string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match clip_context.set_contents(new_copy_data) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(_) => {
|
||||||
|
return OutputStream::one(Err(ShellError::labeled_error(
|
||||||
|
"Could not set contents of clipboard",
|
||||||
|
"could not set contents of clipboard",
|
||||||
|
name,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputStream::empty()
|
||||||
|
} else {
|
||||||
|
OutputStream::one(Err(ShellError::labeled_error(
|
||||||
|
"Could not open clipboard",
|
||||||
|
"could not open clipboard",
|
||||||
|
name,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
clip_context.set_contents(new_copy_data).unwrap();
|
|
||||||
|
|
||||||
OutputStream::empty()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl PerItemCommand for Enter {
|
||||||
// If it's a file, attempt to open the file as a value and enter it
|
// If it's a file, attempt to open the file as a value and enter it
|
||||||
let cwd = raw_args.shell_manager.path();
|
let cwd = raw_args.shell_manager.path();
|
||||||
|
|
||||||
let full_path = std::path::PathBuf::from(cwd);
|
let full_path = std::path::PathBuf::from(cwd?);
|
||||||
|
|
||||||
let (file_extension, contents, contents_tag) =
|
let (file_extension, contents, contents_tag) =
|
||||||
crate::commands::open::fetch(
|
crate::commands::open::fetch(
|
||||||
|
|
|
@ -45,7 +45,6 @@ pub fn evaluate_by(
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Value> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
|
|
||||||
if values.is_empty() {
|
if values.is_empty() {
|
||||||
yield Err(ShellError::labeled_error(
|
yield Err(ShellError::labeled_error(
|
||||||
"Expected table from pipeline",
|
"Expected table from pipeline",
|
||||||
|
@ -141,6 +140,7 @@ mod tests {
|
||||||
use crate::data::value;
|
use crate::data::value;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{UntaggedValue, Value};
|
use nu_protocol::{UntaggedValue, Value};
|
||||||
use nu_source::TaggedItem;
|
use nu_source::TaggedItem;
|
||||||
|
|
||||||
|
@ -160,21 +160,20 @@ mod tests {
|
||||||
UntaggedValue::table(list).into_untagged_value()
|
UntaggedValue::table(list).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_sorted_by_date() -> Value {
|
fn nu_releases_sorted_by_date() -> Result<Value, ShellError> {
|
||||||
let key = String::from("date");
|
let key = String::from("date");
|
||||||
|
|
||||||
t_sort(
|
t_sort(
|
||||||
Some(key),
|
Some(key),
|
||||||
None,
|
None,
|
||||||
&nu_releases_grouped_by_date(),
|
&nu_releases_grouped_by_date()?,
|
||||||
Tag::unknown(),
|
Tag::unknown(),
|
||||||
)
|
)
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_grouped_by_date() -> Value {
|
fn nu_releases_grouped_by_date() -> Result<Value, ShellError> {
|
||||||
let key = String::from("date").tagged_unknown();
|
let key = String::from("date").tagged_unknown();
|
||||||
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
group(&key, nu_releases_commiters(), Tag::unknown())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_commiters() -> Vec<Value> {
|
fn nu_releases_commiters() -> Vec<Value> {
|
||||||
|
@ -230,28 +229,32 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn evaluates_the_tables() {
|
fn evaluates_the_tables() -> Result<(), ShellError> {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
evaluate(&nu_releases_sorted_by_date(), None, Tag::unknown()).unwrap(),
|
evaluate(&nu_releases_sorted_by_date()?, None, Tag::unknown())?,
|
||||||
table(&[table(&[
|
table(&[table(&[
|
||||||
table(&[int(1), int(1), int(1)]),
|
table(&[int(1), int(1), int(1)]),
|
||||||
table(&[int(1), int(1), int(1)]),
|
table(&[int(1), int(1), int(1)]),
|
||||||
table(&[int(1), int(1), int(1)]),
|
table(&[int(1), int(1), int(1)]),
|
||||||
]),])
|
]),])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn evaluates_the_tables_with_custom_evaluator() {
|
fn evaluates_the_tables_with_custom_evaluator() -> Result<(), ShellError> {
|
||||||
let eval = String::from("name");
|
let eval = String::from("name");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
evaluate(&nu_releases_sorted_by_date(), Some(eval), Tag::unknown()).unwrap(),
|
evaluate(&nu_releases_sorted_by_date()?, Some(eval), Tag::unknown())?,
|
||||||
table(&[table(&[
|
table(&[table(&[
|
||||||
table(&[string("AR"), string("JT"), string("YK")]),
|
table(&[string("AR"), string("JT"), string("YK")]),
|
||||||
table(&[string("AR"), string("YK"), string("JT")]),
|
table(&[string("AR"), string("YK"), string("JT")]),
|
||||||
table(&[string("YK"), string("JT"), string("AR")]),
|
table(&[string("YK"), string("JT"), string("AR")]),
|
||||||
]),])
|
]),])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ impl PerItemCommand for Open {
|
||||||
|
|
||||||
fn run(call_info: &CallInfo, raw_args: &RawCommandArgs) -> Result<OutputStream, ShellError> {
|
fn run(call_info: &CallInfo, raw_args: &RawCommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let shell_manager = &raw_args.shell_manager;
|
let shell_manager = &raw_args.shell_manager;
|
||||||
let cwd = PathBuf::from(shell_manager.path());
|
let cwd = PathBuf::from(shell_manager.path()?);
|
||||||
let full_path = cwd;
|
let full_path = cwd;
|
||||||
|
|
||||||
let path = call_info.args.nth(0).ok_or_else(|| {
|
let path = call_info.args.nth(0).ok_or_else(|| {
|
||||||
|
|
|
@ -130,7 +130,7 @@ fn save(
|
||||||
}: RunnableContext,
|
}: RunnableContext,
|
||||||
raw_args: RawCommandArgs,
|
raw_args: RawCommandArgs,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let mut full_path = PathBuf::from(shell_manager.path());
|
let mut full_path = PathBuf::from(shell_manager.path()?);
|
||||||
let name_tag = name.clone();
|
let name_tag = name.clone();
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
|
|
|
@ -32,7 +32,16 @@ fn shells(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream
|
||||||
let mut shells_out = VecDeque::new();
|
let mut shells_out = VecDeque::new();
|
||||||
let tag = args.call_info.name_tag;
|
let tag = args.call_info.name_tag;
|
||||||
|
|
||||||
for (index, shell) in args.shell_manager.shells.lock().unwrap().iter().enumerate() {
|
for (index, shell) in args
|
||||||
|
.shell_manager
|
||||||
|
.shells
|
||||||
|
.lock()
|
||||||
|
.map_err(|_| {
|
||||||
|
ShellError::labeled_error("Could not list shells", "could not list shells", &tag)
|
||||||
|
})?
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
let mut dict = TaggedDictBuilder::new(&tag);
|
let mut dict = TaggedDictBuilder::new(&tag);
|
||||||
|
|
||||||
if index == (*args.shell_manager.current_shell).load(Ordering::SeqCst) {
|
if index == (*args.shell_manager.current_shell).load(Ordering::SeqCst) {
|
||||||
|
|
|
@ -95,6 +95,13 @@ impl CommandRegistry {
|
||||||
})?;
|
})?;
|
||||||
Ok(registry.keys().cloned().collect())
|
Ok(registry.keys().cloned().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn snapshot(&self) -> Result<IndexMap<String, Arc<Command>>, ShellError> {
|
||||||
|
let registry = self.registry.lock().map_err(|_| {
|
||||||
|
ShellError::untagged_runtime_error("Internal error: names could not get mutex")
|
||||||
|
})?;
|
||||||
|
Ok(registry.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -114,12 +121,12 @@ impl Context {
|
||||||
pub(crate) fn expand_context<'context>(
|
pub(crate) fn expand_context<'context>(
|
||||||
&'context self,
|
&'context self,
|
||||||
source: &'context Text,
|
source: &'context Text,
|
||||||
) -> ExpandContext<'context> {
|
) -> Result<ExpandContext<'context>, ShellError> {
|
||||||
ExpandContext::new(
|
Ok(ExpandContext::new(
|
||||||
Box::new(self.registry.clone()),
|
Box::new(self.registry.clone()),
|
||||||
source,
|
source,
|
||||||
self.shell_manager.homedir(),
|
self.shell_manager.homedir()?,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn basic() -> Result<Context, Box<dyn Error>> {
|
pub(crate) fn basic() -> Result<Context, Box<dyn Error>> {
|
||||||
|
@ -133,7 +140,7 @@ impl Context {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn error(&mut self, error: ShellError) {
|
pub(crate) fn error(&mut self, error: ShellError) -> Result<(), ShellError> {
|
||||||
self.with_errors(|errors| errors.push(error))
|
self.with_errors(|errors| errors.push(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,16 +184,30 @@ impl Context {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with_host<T>(&mut self, block: impl FnOnce(&mut dyn Host) -> T) -> T {
|
pub(crate) fn with_host<T>(
|
||||||
let mut host = self.host.lock().unwrap();
|
&mut self,
|
||||||
|
block: impl FnOnce(&mut dyn Host) -> T,
|
||||||
block(&mut *host)
|
) -> Result<T, ShellError> {
|
||||||
|
if let Ok(mut host) = self.host.lock() {
|
||||||
|
Ok(block(&mut *host))
|
||||||
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock host in with_host",
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with_errors<T>(&mut self, block: impl FnOnce(&mut Vec<ShellError>) -> T) -> T {
|
pub(crate) fn with_errors<T>(
|
||||||
let mut errors = self.current_errors.lock().unwrap();
|
&mut self,
|
||||||
|
block: impl FnOnce(&mut Vec<ShellError>) -> T,
|
||||||
block(&mut *errors)
|
) -> Result<T, ShellError> {
|
||||||
|
if let Ok(mut errors) = self.current_errors.lock() {
|
||||||
|
Ok(block(&mut *errors))
|
||||||
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock host in with_errors",
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_commands(&mut self, commands: Vec<Arc<Command>>) -> Result<(), ShellError> {
|
pub fn add_commands(&mut self, commands: Vec<Arc<Command>>) -> Result<(), ShellError> {
|
||||||
|
|
|
@ -359,12 +359,14 @@ impl Shapes {
|
||||||
|
|
||||||
pub fn to_values(&self) -> Vec<Value> {
|
pub fn to_values(&self) -> Vec<Value> {
|
||||||
if self.shapes.len() == 1 {
|
if self.shapes.len() == 1 {
|
||||||
let shape = self.shapes.keys().nth(0).unwrap();
|
if let Some(shape) = self.shapes.keys().nth(0) {
|
||||||
|
let mut tagged_dict = TaggedDictBuilder::new(Tag::unknown());
|
||||||
let mut tagged_dict = TaggedDictBuilder::new(Tag::unknown());
|
tagged_dict.insert_untagged("type", shape.to_value());
|
||||||
tagged_dict.insert_untagged("type", shape.to_value());
|
tagged_dict.insert_untagged("rows", UntaggedValue::string("all"));
|
||||||
tagged_dict.insert_untagged("rows", UntaggedValue::string("all"));
|
vec![tagged_dict.into_value()]
|
||||||
vec![tagged_dict.into_value()]
|
} else {
|
||||||
|
unreachable!("Internal error: impossible state in to_values")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.shapes
|
self.shapes
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -39,10 +39,10 @@ impl RenderView for EntriesView {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let max_name_size: usize = self.entries.iter().map(|(n, _)| n.len()).max().unwrap();
|
if let Some(max_name_size) = self.entries.iter().map(|(n, _)| n.len()).max() {
|
||||||
|
for (name, value) in &self.entries {
|
||||||
for (name, value) in &self.entries {
|
outln!("{:width$} : {}", name, value, width = max_name_size)
|
||||||
outln!("{:width$} : {}", name, value, width = max_name_size)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -376,7 +376,7 @@ impl RenderView for TableView {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
table.print_term(&mut *host.out_terminal()).unwrap();
|
table.print_term(&mut *host.out_terminal()).map_err(|_| ShellError::untagged_runtime_error("Internal error: could not print to terminal (for unix systems check to make sure TERM is set)"))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,15 @@ where
|
||||||
{
|
{
|
||||||
fn to_input_stream(self) -> InputStream {
|
fn to_input_stream(self) -> InputStream {
|
||||||
InputStream {
|
InputStream {
|
||||||
values: self.map(|item| item.into().unwrap()).boxed(),
|
values: self
|
||||||
|
.map(|item| {
|
||||||
|
if let Ok(result) = item.into() {
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
unreachable!("Internal errors: to_input_stream in inconsistent state")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.boxed(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,18 +25,21 @@ impl HelpShell {
|
||||||
let mut cmds = TaggedDictBuilder::new(Tag::unknown());
|
let mut cmds = TaggedDictBuilder::new(Tag::unknown());
|
||||||
let mut specs = Vec::new();
|
let mut specs = Vec::new();
|
||||||
|
|
||||||
for cmd in registry.names()? {
|
let snapshot = registry.snapshot()?;
|
||||||
let mut spec = TaggedDictBuilder::new(Tag::unknown());
|
|
||||||
let value = command_dict(registry.get_command(&cmd)?.unwrap(), Tag::unknown());
|
|
||||||
|
|
||||||
spec.insert_untagged("name", cmd);
|
for (name, cmd) in snapshot.iter() {
|
||||||
|
let mut spec = TaggedDictBuilder::new(Tag::unknown());
|
||||||
|
let value = command_dict(cmd.clone(), Tag::unknown());
|
||||||
|
|
||||||
|
spec.insert_untagged("name", name.to_string());
|
||||||
spec.insert_untagged(
|
spec.insert_untagged(
|
||||||
"description",
|
"description",
|
||||||
value
|
value
|
||||||
.get_data_by_key("usage".spanned_unknown())
|
.get_data_by_key("usage".spanned_unknown())
|
||||||
.unwrap()
|
.ok_or_else(|| {
|
||||||
.as_string()
|
ShellError::untagged_runtime_error("Internal error: expected to find usage")
|
||||||
.unwrap(),
|
})?
|
||||||
|
.as_string()?,
|
||||||
);
|
);
|
||||||
spec.insert_value("details", value);
|
spec.insert_value("details", value);
|
||||||
|
|
||||||
|
@ -77,7 +80,8 @@ impl HelpShell {
|
||||||
match p {
|
match p {
|
||||||
x if x == sep => {}
|
x if x == sep => {}
|
||||||
step => {
|
step => {
|
||||||
let value = viewed.get_data_by_key(step.to_str().unwrap().spanned_unknown());
|
let step: &str = &step.to_string_lossy().to_string();
|
||||||
|
let value = viewed.get_data_by_key(step.spanned_unknown());
|
||||||
if let Some(v) = value {
|
if let Some(v) = value {
|
||||||
viewed = v.clone();
|
viewed = v.clone();
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,10 @@ impl Completer for Helper {
|
||||||
|
|
||||||
impl Hinter for Helper {
|
impl Hinter for Helper {
|
||||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||||
self.context.shell_manager.hint(line, pos, ctx)
|
match self.context.shell_manager.hint(line, pos, ctx) {
|
||||||
|
Ok(output) => output,
|
||||||
|
Err(e) => Some(format!("{}", e)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,31 +81,43 @@ impl Highlighter for Helper {
|
||||||
let mut tokens = TokensIterator::all(&tokens[..], Text::from(line), v.span());
|
let mut tokens = TokensIterator::all(&tokens[..], Text::from(line), v.span());
|
||||||
|
|
||||||
let text = Text::from(line);
|
let text = Text::from(line);
|
||||||
let expand_context = self.context.expand_context(&text);
|
match self.context.expand_context(&text) {
|
||||||
|
Ok(expand_context) => {
|
||||||
|
let shapes = {
|
||||||
|
// We just constructed a token list that only contains a pipeline, so it can't fail
|
||||||
|
if let Err(err) =
|
||||||
|
color_fallible_syntax(&PipelineShape, &mut tokens, &expand_context)
|
||||||
|
{
|
||||||
|
let error_msg = format!("{}", err);
|
||||||
|
return Cow::Owned(error_msg);
|
||||||
|
}
|
||||||
|
tokens.with_color_tracer(|_, tracer| tracer.finish());
|
||||||
|
|
||||||
let shapes = {
|
tokens.state().shapes()
|
||||||
// We just constructed a token list that only contains a pipeline, so it can't fail
|
};
|
||||||
color_fallible_syntax(&PipelineShape, &mut tokens, &expand_context).unwrap();
|
|
||||||
tokens.with_color_tracer(|_, tracer| tracer.finish());
|
|
||||||
|
|
||||||
tokens.state().shapes()
|
trace!(target: "nu::color_syntax", "{:#?}", tokens.color_tracer());
|
||||||
};
|
|
||||||
|
|
||||||
trace!(target: "nu::color_syntax", "{:#?}", tokens.color_tracer());
|
if log_enabled!(target: "nu::color_syntax", log::Level::Debug) {
|
||||||
|
outln!("");
|
||||||
|
let _ = ptree::print_tree(
|
||||||
|
&tokens.color_tracer().clone().print(Text::from(line)),
|
||||||
|
);
|
||||||
|
outln!("");
|
||||||
|
}
|
||||||
|
|
||||||
if log_enabled!(target: "nu::color_syntax", log::Level::Debug) {
|
for shape in shapes {
|
||||||
outln!("");
|
let styled = paint_flat_shape(&shape, line);
|
||||||
ptree::print_tree(&tokens.color_tracer().clone().print(Text::from(line)))
|
out.push_str(&styled);
|
||||||
.unwrap();
|
}
|
||||||
outln!("");
|
|
||||||
|
Cow::Owned(out)
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
let error_msg = format!("{}", err);
|
||||||
|
Cow::Owned(error_msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for shape in shapes {
|
|
||||||
let styled = paint_flat_shape(&shape, line);
|
|
||||||
out.push_str(&styled);
|
|
||||||
}
|
|
||||||
|
|
||||||
Cow::Owned(out)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,53 +30,95 @@ impl ShellManager {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_at_current(&mut self, shell: Box<dyn Shell + Send>) {
|
pub fn insert_at_current(&mut self, shell: Box<dyn Shell + Send>) -> Result<(), ShellError> {
|
||||||
self.shells.lock().unwrap().push(shell);
|
if let Ok(mut shells) = self.shells.lock() {
|
||||||
self.current_shell
|
shells.push(shell);
|
||||||
.store(self.shells.lock().unwrap().len() - 1, Ordering::SeqCst);
|
} else {
|
||||||
self.set_path(self.path());
|
return Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock shells ring buffer",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let shells_len = if let Ok(shells) = self.shells.lock() {
|
||||||
|
shells.len()
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock shells ring buffer",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
self.current_shell.store(shells_len - 1, Ordering::SeqCst);
|
||||||
|
self.set_path(self.path()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_shell(&self) -> usize {
|
pub fn current_shell(&self) -> usize {
|
||||||
self.current_shell.load(Ordering::SeqCst)
|
self.current_shell.load(Ordering::SeqCst)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_at_current(&mut self) {
|
pub fn remove_at_current(&mut self) -> Result<(), ShellError> {
|
||||||
{
|
{
|
||||||
let mut shells = self.shells.lock().unwrap();
|
if let Ok(mut shells) = self.shells.lock() {
|
||||||
if shells.len() > 0 {
|
if shells.len() > 0 {
|
||||||
if self.current_shell() == shells.len() - 1 {
|
if self.current_shell() == shells.len() - 1 {
|
||||||
shells.pop();
|
shells.pop();
|
||||||
let new_len = shells.len();
|
let new_len = shells.len();
|
||||||
if new_len > 0 {
|
if new_len > 0 {
|
||||||
self.current_shell.store(new_len - 1, Ordering::SeqCst);
|
self.current_shell.store(new_len - 1, Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
shells.remove(self.current_shell());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
shells.remove(self.current_shell());
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock shells ring buffer",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.set_path(self.path());
|
self.set_path(self.path()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> Result<bool, ShellError> {
|
||||||
self.shells.lock().unwrap().is_empty()
|
if let Ok(shells) = self.shells.lock() {
|
||||||
|
Ok(shells.is_empty())
|
||||||
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock shells ring buffer (is_empty)",
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path(&self) -> String {
|
pub fn path(&self) -> Result<String, ShellError> {
|
||||||
self.shells.lock().unwrap()[self.current_shell()].path()
|
if let Ok(shells) = self.shells.lock() {
|
||||||
|
Ok(shells[self.current_shell()].path())
|
||||||
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock shells ring buffer (path)",
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pwd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn pwd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let env = self.shells.lock().unwrap();
|
if let Ok(shells) = self.shells.lock() {
|
||||||
|
shells[self.current_shell()].pwd(args)
|
||||||
env[self.current_shell()].pwd(args)
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock shells ring buffer (pwd)",
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_path(&mut self, path: String) {
|
pub fn set_path(&mut self, path: String) -> Result<(), ShellError> {
|
||||||
self.shells.lock().unwrap()[self.current_shell()].set_path(path)
|
if let Ok(mut shells) = self.shells.lock() {
|
||||||
|
shells[self.current_shell()].set_path(path);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock shells ring buffer (set_path)",
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn complete(
|
pub fn complete(
|
||||||
|
@ -85,43 +127,77 @@ impl ShellManager {
|
||||||
pos: usize,
|
pos: usize,
|
||||||
ctx: &rustyline::Context<'_>,
|
ctx: &rustyline::Context<'_>,
|
||||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), rustyline::error::ReadlineError> {
|
) -> Result<(usize, Vec<rustyline::completion::Pair>), rustyline::error::ReadlineError> {
|
||||||
self.shells.lock().unwrap()[self.current_shell()].complete(line, pos, ctx)
|
if let Ok(shells) = self.shells.lock() {
|
||||||
|
shells[self.current_shell()].complete(line, pos, ctx)
|
||||||
|
} else {
|
||||||
|
Err(rustyline::error::ReadlineError::Io(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Other,
|
||||||
|
"Internal error: could not lock shells ring buffer (complete)",
|
||||||
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
pub fn hint(
|
||||||
self.shells.lock().unwrap()[self.current_shell()].hint(line, pos, ctx)
|
&self,
|
||||||
|
line: &str,
|
||||||
|
pos: usize,
|
||||||
|
ctx: &rustyline::Context<'_>,
|
||||||
|
) -> Result<Option<String>, ShellError> {
|
||||||
|
if let Ok(shells) = self.shells.lock() {
|
||||||
|
Ok(shells[self.current_shell()].hint(line, pos, ctx))
|
||||||
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock shells ring buffer (hint)",
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) {
|
pub fn next(&mut self) -> Result<(), ShellError> {
|
||||||
{
|
{
|
||||||
let shell_len = self.shells.lock().unwrap().len();
|
if let Ok(shells) = self.shells.lock() {
|
||||||
if self.current_shell() == (shell_len - 1) {
|
let shell_len = shells.len();
|
||||||
self.current_shell.store(0, Ordering::SeqCst);
|
if self.current_shell() == (shell_len - 1) {
|
||||||
|
self.current_shell.store(0, Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
self.current_shell
|
||||||
|
.store(self.current_shell() + 1, Ordering::SeqCst);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.current_shell
|
return Err(ShellError::untagged_runtime_error(
|
||||||
.store(self.current_shell() + 1, Ordering::SeqCst);
|
"Internal error: could not lock shells ring buffer (next)",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.set_path(self.path());
|
self.set_path(self.path()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prev(&mut self) {
|
pub fn prev(&mut self) -> Result<(), ShellError> {
|
||||||
{
|
{
|
||||||
let shell_len = self.shells.lock().unwrap().len();
|
if let Ok(shells) = self.shells.lock() {
|
||||||
if self.current_shell() == 0 {
|
let shell_len = shells.len();
|
||||||
self.current_shell.store(shell_len - 1, Ordering::SeqCst);
|
if self.current_shell() == 0 {
|
||||||
|
self.current_shell.store(shell_len - 1, Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
self.current_shell
|
||||||
|
.store(self.current_shell() - 1, Ordering::SeqCst);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.current_shell
|
return Err(ShellError::untagged_runtime_error(
|
||||||
.store(self.current_shell() - 1, Ordering::SeqCst);
|
"Internal error: could not lock shells ring buffer (prev)",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.set_path(self.path());
|
self.set_path(self.path()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn homedir(&self) -> Option<PathBuf> {
|
pub fn homedir(&self) -> Result<Option<PathBuf>, ShellError> {
|
||||||
let env = self.shells.lock().unwrap();
|
if let Ok(shells) = self.shells.lock() {
|
||||||
|
Ok(shells[self.current_shell()].homedir())
|
||||||
env[self.current_shell()].homedir()
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock shells ring buffer (homedir)",
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ls(
|
pub fn ls(
|
||||||
|
@ -130,15 +206,23 @@ impl ShellManager {
|
||||||
context: &RunnableContext,
|
context: &RunnableContext,
|
||||||
full: bool,
|
full: bool,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let env = self.shells.lock().unwrap();
|
if let Ok(shells) = self.shells.lock() {
|
||||||
|
shells[self.current_shell()].ls(path, context, full)
|
||||||
env[self.current_shell()].ls(path, context, full)
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock shells ring buffer (ls)",
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let env = self.shells.lock().unwrap();
|
if let Ok(shells) = self.shells.lock() {
|
||||||
|
shells[self.current_shell()].cd(args)
|
||||||
env[self.current_shell()].cd(args)
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(
|
||||||
|
"Internal error: could not lock shells ring buffer (cd)",
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cp(
|
pub fn cp(
|
||||||
|
@ -146,9 +230,9 @@ impl ShellManager {
|
||||||
args: CopyArgs,
|
args: CopyArgs,
|
||||||
context: &RunnablePerItemContext,
|
context: &RunnablePerItemContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let env = self.shells.lock();
|
let shells = self.shells.lock();
|
||||||
|
|
||||||
match env {
|
match shells {
|
||||||
Ok(x) => {
|
Ok(x) => {
|
||||||
let path = x[self.current_shell()].path();
|
let path = x[self.current_shell()].path();
|
||||||
x[self.current_shell()].cp(args, context.name.clone(), &path)
|
x[self.current_shell()].cp(args, context.name.clone(), &path)
|
||||||
|
@ -166,9 +250,9 @@ impl ShellManager {
|
||||||
args: RemoveArgs,
|
args: RemoveArgs,
|
||||||
context: &RunnablePerItemContext,
|
context: &RunnablePerItemContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let env = self.shells.lock();
|
let shells = self.shells.lock();
|
||||||
|
|
||||||
match env {
|
match shells {
|
||||||
Ok(x) => {
|
Ok(x) => {
|
||||||
let path = x[self.current_shell()].path();
|
let path = x[self.current_shell()].path();
|
||||||
x[self.current_shell()].rm(args, context.name.clone(), &path)
|
x[self.current_shell()].rm(args, context.name.clone(), &path)
|
||||||
|
@ -186,9 +270,9 @@ impl ShellManager {
|
||||||
args: MkdirArgs,
|
args: MkdirArgs,
|
||||||
context: &RunnablePerItemContext,
|
context: &RunnablePerItemContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let env = self.shells.lock();
|
let shells = self.shells.lock();
|
||||||
|
|
||||||
match env {
|
match shells {
|
||||||
Ok(x) => {
|
Ok(x) => {
|
||||||
let path = x[self.current_shell()].path();
|
let path = x[self.current_shell()].path();
|
||||||
x[self.current_shell()].mkdir(args, context.name.clone(), &path)
|
x[self.current_shell()].mkdir(args, context.name.clone(), &path)
|
||||||
|
@ -206,9 +290,9 @@ impl ShellManager {
|
||||||
args: MoveArgs,
|
args: MoveArgs,
|
||||||
context: &RunnablePerItemContext,
|
context: &RunnablePerItemContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let env = self.shells.lock();
|
let shells = self.shells.lock();
|
||||||
|
|
||||||
match env {
|
match shells {
|
||||||
Ok(x) => {
|
Ok(x) => {
|
||||||
let path = x[self.current_shell()].path();
|
let path = x[self.current_shell()].path();
|
||||||
x[self.current_shell()].mv(args, context.name.clone(), &path)
|
x[self.current_shell()].mv(args, context.name.clone(), &path)
|
||||||
|
|
|
@ -44,7 +44,8 @@ impl ValueShell {
|
||||||
match p {
|
match p {
|
||||||
x if x == sep => {}
|
x if x == sep => {}
|
||||||
step => {
|
step => {
|
||||||
let value = viewed.get_data_by_key(step.to_str().unwrap().spanned_unknown());
|
let name: &str = &step.to_string_lossy().to_string();
|
||||||
|
let value = viewed.get_data_by_key(name.spanned_unknown());
|
||||||
if let Some(v) = value {
|
if let Some(v) = value {
|
||||||
viewed = v.clone();
|
viewed = v.clone();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue