Merge branch 'main' into source-command

This commit is contained in:
Tanishq Kancharla
2021-10-03 14:25:00 -04:00
committed by GitHub
38 changed files with 1168 additions and 126 deletions

View File

@ -8,6 +8,7 @@ edition = "2018"
[dependencies]
nu-engine = { path = "../nu-engine" }
nu-json = { path = "../nu-json" }
nu-path = { path = "../nu-path" }
nu-protocol = { path = "../nu-protocol" }
nu-table = { path = "../nu-table" }

View File

@ -0,0 +1,35 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
pub struct ExportDef;
impl Command for ExportDef {
fn name(&self) -> &str {
"export def"
}
fn usage(&self) -> &str {
"Define a custom command and export it from a module"
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("export def")
.required("target", SyntaxShape::String, "definition name")
.required("params", SyntaxShape::Signature, "parameters")
.required(
"block",
SyntaxShape::Block(Some(vec![])),
"body of the definition",
)
}
fn run(
&self,
_context: &EvaluationContext,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head })
}
}

View File

@ -0,0 +1,28 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
pub struct Hide;
impl Command for Hide {
fn name(&self) -> &str {
"hide"
}
fn usage(&self) -> &str {
"Hide definitions in the current scope"
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("hide").required("pattern", SyntaxShape::String, "import pattern")
}
fn run(
&self,
_context: &EvaluationContext,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head })
}
}

View File

@ -1,7 +1,9 @@
mod alias;
mod def;
mod do_;
mod export_def;
mod help;
mod hide;
mod if_;
mod let_;
mod module;
@ -11,7 +13,9 @@ mod use_;
pub use alias::Alias;
pub use def::Def;
pub use do_::Do;
pub use export_def::ExportDef;
pub use help::Help;
pub use hide::Hide;
pub use if_::If;
pub use let_::Let;
pub use module::Module;

View File

@ -14,7 +14,7 @@ impl Command for Use {
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("use").required("module_name", SyntaxShape::String, "module name")
Signature::build("use").required("pattern", SyntaxShape::String, "import pattern")
}
fn run(

View File

@ -5,11 +5,7 @@ use nu_protocol::{
Signature,
};
use crate::{
Alias, Benchmark, BuildString, Def, Do, Each, External, For, From, FromJson, Git, GitCheckout,
Help, If, Length, Let, LetEnv, Lines, ListGitBranches, Ls, Module, Ps, Source, Sys, Table, Use,
Where,
};
use crate::*;
pub fn create_default_context() -> Rc<RefCell<EngineState>> {
let engine_state = Rc::new(RefCell::new(EngineState::new()));
@ -20,14 +16,18 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
working_set.add_decl(Box::new(Alias));
working_set.add_decl(Box::new(Benchmark));
working_set.add_decl(Box::new(BuildString));
working_set.add_decl(Box::new(Cd));
working_set.add_decl(Box::new(Def));
working_set.add_decl(Box::new(Do));
working_set.add_decl(Box::new(Each));
working_set.add_decl(Box::new(ExportDef));
working_set.add_decl(Box::new(External));
working_set.add_decl(Box::new(For));
working_set.add_decl(Box::new(From));
working_set.add_decl(Box::new(FromJson));
working_set.add_decl(Box::new(Get));
working_set.add_decl(Box::new(Help));
working_set.add_decl(Box::new(Hide));
working_set.add_decl(Box::new(If));
working_set.add_decl(Box::new(Length));
working_set.add_decl(Box::new(Let));
@ -36,10 +36,12 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
working_set.add_decl(Box::new(Ls));
working_set.add_decl(Box::new(Module));
working_set.add_decl(Box::new(Ps));
working_set.add_decl(Box::new(Select));
working_set.add_decl(Box::new(Sys));
working_set.add_decl(Box::new(Table));
working_set.add_decl(Box::new(Use));
working_set.add_decl(Box::new(Where));
working_set.add_decl(Box::new(Wrap));
// This is a WIP proof of concept
working_set.add_decl(Box::new(ListGitBranches));

View File

@ -0,0 +1,46 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
pub struct Cd;
impl Command for Cd {
fn name(&self) -> &str {
"cd"
}
fn usage(&self) -> &str {
"Change directory."
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("cd").optional("path", SyntaxShape::FilePath, "the path to change to")
}
fn run(
&self,
context: &EvaluationContext,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let path: Option<String> = call.opt(context, 0)?;
let path = match path {
Some(path) => {
let path = nu_path::expand_tilde(path);
path.to_string_lossy().to_string()
}
None => {
let path = nu_path::expand_tilde("~");
path.to_string_lossy().to_string()
}
};
let _ = std::env::set_current_dir(&path);
//FIXME: this only changes the current scope, but instead this environment variable
//should probably be a block that loads the information from the state in the overlay
context.add_env_var("PWD".into(), path);
Ok(Value::Nothing { span: call.head })
}
}

View File

@ -63,8 +63,8 @@ impl Command for Ls {
} else {
Value::Nothing { span: call_span }
},
Value::Int {
val: filesize as i64,
Value::Filesize {
val: filesize,
span: call_span,
},
],

View File

@ -1,3 +1,5 @@
mod cd;
mod ls;
pub use cd::Cd;
pub use ls::Ls;

View File

@ -0,0 +1,35 @@
use nu_engine::CallExt;
use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
pub struct Get;
impl Command for Get {
fn name(&self) -> &str {
"get"
}
fn usage(&self) -> &str {
"Extract data using a cell path."
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("wrap").required(
"cell_path",
SyntaxShape::CellPath,
"the cell path to the data",
)
}
fn run(
&self,
context: &EvaluationContext,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let cell_path: CellPath = call.req(context, 0)?;
input.follow_cell_path(&cell_path.members)
}
}

View File

@ -62,7 +62,7 @@ impl Command for Lines {
.filter_map(|s| {
if !s.is_empty() {
Some(Value::String {
val: s.trim().into(),
val: s.into(),
span,
})
} else {

View File

@ -1,11 +1,17 @@
mod each;
mod for_;
mod get;
mod length;
mod lines;
mod select;
mod where_;
mod wrap;
pub use each::Each;
pub use for_::For;
pub use get::Get;
pub use length::Length;
pub use lines::Lines;
pub use select::Select;
pub use where_::Where;
pub use wrap::Wrap;

View File

@ -0,0 +1,182 @@
use nu_engine::CallExt;
use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Example, IntoValueStream, ShellError, Signature, Span, SyntaxShape, Value};
pub struct Select;
impl Command for Select {
fn name(&self) -> &str {
"select"
}
fn signature(&self) -> Signature {
Signature::build("select").rest(
"rest",
SyntaxShape::CellPath,
"the columns to select from the table",
)
}
fn usage(&self) -> &str {
"Down-select table to only these columns."
}
fn run(
&self,
context: &EvaluationContext,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let columns: Vec<CellPath> = call.rest(context, 0)?;
let span = call.head;
select(span, columns, input)
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Select just the name column",
example: "ls | select name",
result: None,
},
Example {
description: "Select the name and size columns",
example: "ls | select name size",
result: None,
},
]
}
}
fn select(span: Span, columns: Vec<CellPath>, input: Value) -> Result<Value, ShellError> {
if columns.is_empty() {
return Err(ShellError::CantFindColumn(span));
}
match input {
Value::List {
vals: input_vals,
span,
} => {
let mut output = vec![];
for input_val in input_vals {
let mut cols = vec![];
let mut vals = vec![];
for path in &columns {
//FIXME: improve implementation to not clone
let fetcher = input_val.clone().follow_cell_path(&path.members)?;
cols.push(path.into_string());
vals.push(fetcher);
}
output.push(Value::Record { cols, vals, span })
}
Ok(Value::List { vals: output, span })
}
Value::Stream { stream, span } => Ok(Value::Stream {
stream: stream
.map(move |x| {
let mut cols = vec![];
let mut vals = vec![];
for path in &columns {
//FIXME: improve implementation to not clone
match x.clone().follow_cell_path(&path.members) {
Ok(value) => {
cols.push(path.into_string());
vals.push(value);
}
Err(error) => {
cols.push(path.into_string());
vals.push(Value::Error { error });
}
}
}
Value::Record { cols, vals, span }
})
.into_value_stream(),
span,
}),
v => {
let mut cols = vec![];
let mut vals = vec![];
for cell_path in columns {
// FIXME: remove clone
let result = v.clone().follow_cell_path(&cell_path.members)?;
cols.push(cell_path.into_string());
vals.push(result);
}
Ok(Value::Record { cols, vals, span })
}
}
}
// #[cfg(test)]
// mod tests {
// use nu_protocol::ColumnPath;
// use nu_source::Span;
// use nu_source::SpannedItem;
// use nu_source::Tag;
// use nu_stream::InputStream;
// use nu_test_support::value::nothing;
// use nu_test_support::value::row;
// use nu_test_support::value::string;
// use super::select;
// use super::Command;
// use super::ShellError;
// #[test]
// fn examples_work_as_expected() -> Result<(), ShellError> {
// use crate::examples::test as test_examples;
// test_examples(Command {})
// }
// #[test]
// fn select_using_sparse_table() {
// // Create a sparse table with 3 rows:
// // col_foo | col_bar
// // -----------------
// // foo |
// // | bar
// // foo |
// let input = vec![
// row(indexmap! {"col_foo".into() => string("foo")}),
// row(indexmap! {"col_bar".into() => string("bar")}),
// row(indexmap! {"col_foo".into() => string("foo")}),
// ];
// let expected = vec![
// row(
// indexmap! {"col_none".into() => nothing(), "col_foo".into() => string("foo"), "col_bar".into() => nothing()},
// ),
// row(
// indexmap! {"col_none".into() => nothing(), "col_foo".into() => nothing(), "col_bar".into() => string("bar")},
// ),
// row(
// indexmap! {"col_none".into() => nothing(), "col_foo".into() => string("foo"), "col_bar".into() => nothing()},
// ),
// ];
// let actual = select(
// Tag::unknown(),
// vec![
// ColumnPath::build(&"col_none".to_string().spanned(Span::unknown())),
// ColumnPath::build(&"col_foo".to_string().spanned(Span::unknown())),
// ColumnPath::build(&"col_bar".to_string().spanned(Span::unknown())),
// ],
// input.into(),
// );
// assert_eq!(Ok(expected), actual.map(InputStream::into_vec));
// }
// }

View File

@ -0,0 +1,59 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{IntoValueStream, Signature, SyntaxShape, Value};
pub struct Wrap;
impl Command for Wrap {
fn name(&self) -> &str {
"wrap"
}
fn usage(&self) -> &str {
"Wrap the value into a column."
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("wrap").required("name", SyntaxShape::String, "the name of the column")
}
fn run(
&self,
context: &EvaluationContext,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let span = call.head;
let name: String = call.req(context, 0)?;
match input {
Value::List { vals, .. } => Ok(Value::List {
vals: vals
.into_iter()
.map(move |x| Value::Record {
cols: vec![name.clone()],
vals: vec![x],
span,
})
.collect(),
span,
}),
Value::Stream { stream, .. } => Ok(Value::Stream {
stream: stream
.map(move |x| Value::Record {
cols: vec![name.clone()],
vals: vec![x],
span,
})
.into_value_stream(),
span,
}),
_ => Ok(Value::Record {
cols: vec![name],
vals: vec![input],
span,
}),
}
}
}

View File

@ -274,10 +274,11 @@ pub fn host(sys: &mut System, span: Span) -> Option<Value> {
span,
});
}
// dict.insert_untagged(
// "uptime",
// UntaggedValue::duration(1000000000 * sys.uptime() as i64),
// );
cols.push("uptime".into());
vals.push(Value::Duration {
val: 1000000000 * sys.uptime() as u64,
span,
});
let mut users = vec![];
for user in sys.users() {

View File

@ -63,7 +63,7 @@ impl Command for Table {
output.push(vec![
StyledString {
contents: c,
style: nu_table::TextStyle::default_header(),
style: nu_table::TextStyle::default_field(),
},
StyledString {
contents: v.into_string(),