mirror of
https://github.com/nushell/nushell
synced 2025-01-02 16:29:00 +00:00
Merge pull request #81 from nushell/wrap_get
Add wrap and get and cell_path parsing
This commit is contained in:
commit
7899745c4b
18 changed files with 290 additions and 81 deletions
|
@ -5,10 +5,7 @@ use nu_protocol::{
|
||||||
Signature,
|
Signature,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::*;
|
||||||
Alias, Benchmark, BuildString, Def, Do, Each, External, For, From, FromJson, Git, GitCheckout,
|
|
||||||
Help, If, Length, Let, LetEnv, Lines, ListGitBranches, Ls, Module, Ps, Sys, Table, Use, Where,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn create_default_context() -> Rc<RefCell<EngineState>> {
|
pub fn create_default_context() -> Rc<RefCell<EngineState>> {
|
||||||
let engine_state = Rc::new(RefCell::new(EngineState::new()));
|
let engine_state = Rc::new(RefCell::new(EngineState::new()));
|
||||||
|
@ -26,6 +23,7 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
|
||||||
working_set.add_decl(Box::new(For));
|
working_set.add_decl(Box::new(For));
|
||||||
working_set.add_decl(Box::new(From));
|
working_set.add_decl(Box::new(From));
|
||||||
working_set.add_decl(Box::new(FromJson));
|
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(Help));
|
||||||
working_set.add_decl(Box::new(If));
|
working_set.add_decl(Box::new(If));
|
||||||
working_set.add_decl(Box::new(Length));
|
working_set.add_decl(Box::new(Length));
|
||||||
|
@ -39,6 +37,7 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
|
||||||
working_set.add_decl(Box::new(Table));
|
working_set.add_decl(Box::new(Table));
|
||||||
working_set.add_decl(Box::new(Use));
|
working_set.add_decl(Box::new(Use));
|
||||||
working_set.add_decl(Box::new(Where));
|
working_set.add_decl(Box::new(Where));
|
||||||
|
working_set.add_decl(Box::new(Wrap));
|
||||||
|
|
||||||
// This is a WIP proof of concept
|
// This is a WIP proof of concept
|
||||||
working_set.add_decl(Box::new(ListGitBranches));
|
working_set.add_decl(Box::new(ListGitBranches));
|
||||||
|
|
|
@ -63,8 +63,8 @@ impl Command for Ls {
|
||||||
} else {
|
} else {
|
||||||
Value::Nothing { span: call_span }
|
Value::Nothing { span: call_span }
|
||||||
},
|
},
|
||||||
Value::Int {
|
Value::Filesize {
|
||||||
val: filesize as i64,
|
val: filesize,
|
||||||
span: call_span,
|
span: call_span,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
35
crates/nu-command/src/filters/get.rs
Normal file
35
crates/nu-command/src/filters/get.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,15 @@
|
||||||
mod each;
|
mod each;
|
||||||
mod for_;
|
mod for_;
|
||||||
|
mod get;
|
||||||
mod length;
|
mod length;
|
||||||
mod lines;
|
mod lines;
|
||||||
mod where_;
|
mod where_;
|
||||||
|
mod wrap;
|
||||||
|
|
||||||
pub use each::Each;
|
pub use each::Each;
|
||||||
pub use for_::For;
|
pub use for_::For;
|
||||||
|
pub use get::Get;
|
||||||
pub use length::Length;
|
pub use length::Length;
|
||||||
pub use lines::Lines;
|
pub use lines::Lines;
|
||||||
pub use where_::Where;
|
pub use where_::Where;
|
||||||
|
pub use wrap::Wrap;
|
||||||
|
|
59
crates/nu-command/src/filters/wrap.rs
Normal file
59
crates/nu-command/src/filters/wrap.rs
Normal 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,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -274,10 +274,11 @@ pub fn host(sys: &mut System, span: Span) -> Option<Value> {
|
||||||
span,
|
span,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// dict.insert_untagged(
|
cols.push("uptime".into());
|
||||||
// "uptime",
|
vals.push(Value::Duration {
|
||||||
// UntaggedValue::duration(1000000000 * sys.uptime() as i64),
|
val: 1000000000 * sys.uptime() as u64,
|
||||||
// );
|
span,
|
||||||
|
});
|
||||||
|
|
||||||
let mut users = vec![];
|
let mut users = vec![];
|
||||||
for user in sys.users() {
|
for user in sys.users() {
|
||||||
|
|
|
@ -63,7 +63,7 @@ impl Command for Table {
|
||||||
output.push(vec![
|
output.push(vec![
|
||||||
StyledString {
|
StyledString {
|
||||||
contents: c,
|
contents: c,
|
||||||
style: nu_table::TextStyle::default_header(),
|
style: nu_table::TextStyle::default_field(),
|
||||||
},
|
},
|
||||||
StyledString {
|
StyledString {
|
||||||
contents: v.into_string(),
|
contents: v.into_string(),
|
||||||
|
|
|
@ -14,6 +14,14 @@ pub trait CallExt {
|
||||||
context: &EvaluationContext,
|
context: &EvaluationContext,
|
||||||
starting_pos: usize,
|
starting_pos: usize,
|
||||||
) -> Result<Vec<T>, ShellError>;
|
) -> Result<Vec<T>, ShellError>;
|
||||||
|
|
||||||
|
fn opt<T: FromValue>(
|
||||||
|
&self,
|
||||||
|
context: &EvaluationContext,
|
||||||
|
pos: usize,
|
||||||
|
) -> Result<Option<T>, ShellError>;
|
||||||
|
|
||||||
|
fn req<T: FromValue>(&self, context: &EvaluationContext, pos: usize) -> Result<T, ShellError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallExt for Call {
|
impl CallExt for Call {
|
||||||
|
@ -44,4 +52,29 @@ impl CallExt for Call {
|
||||||
|
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn opt<T: FromValue>(
|
||||||
|
&self,
|
||||||
|
context: &EvaluationContext,
|
||||||
|
pos: usize,
|
||||||
|
) -> Result<Option<T>, ShellError> {
|
||||||
|
if let Some(expr) = self.nth(pos) {
|
||||||
|
let result = eval_expression(context, &expr)?;
|
||||||
|
FromValue::from_value(&result).map(Some)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn req<T: FromValue>(&self, context: &EvaluationContext, pos: usize) -> Result<T, ShellError> {
|
||||||
|
if let Some(expr) = self.nth(pos) {
|
||||||
|
let result = eval_expression(context, &expr)?;
|
||||||
|
FromValue::from_value(&result)
|
||||||
|
} else {
|
||||||
|
Err(ShellError::AccessBeyondEnd(
|
||||||
|
self.positional.len(),
|
||||||
|
self.head,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,10 @@ pub fn eval_expression(
|
||||||
Expr::Var(var_id) => context
|
Expr::Var(var_id) => context
|
||||||
.get_var(*var_id)
|
.get_var(*var_id)
|
||||||
.map_err(move |_| ShellError::VariableNotFoundAtRuntime(expr.span)),
|
.map_err(move |_| ShellError::VariableNotFoundAtRuntime(expr.span)),
|
||||||
|
Expr::CellPath(cell_path) => Ok(Value::CellPath {
|
||||||
|
val: cell_path.clone(),
|
||||||
|
span: expr.span,
|
||||||
|
}),
|
||||||
Expr::FullCellPath(cell_path) => {
|
Expr::FullCellPath(cell_path) => {
|
||||||
let value = eval_expression(context, &cell_path.head)?;
|
let value = eval_expression(context, &cell_path.head)?;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// use std::path::PathBuf;
|
// use std::path::PathBuf;
|
||||||
|
|
||||||
// use nu_path::expand_path;
|
// use nu_path::expand_path;
|
||||||
|
use nu_protocol::ast::CellPath;
|
||||||
use nu_protocol::ShellError;
|
use nu_protocol::ShellError;
|
||||||
use nu_protocol::{Range, Spanned, Value};
|
use nu_protocol::{Range, Spanned, Value};
|
||||||
|
|
||||||
|
@ -110,28 +111,25 @@ impl FromValue for ColumnPath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromValue for bool {
|
*/
|
||||||
|
|
||||||
|
impl FromValue for CellPath {
|
||||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||||
match v {
|
match v {
|
||||||
Value {
|
Value::CellPath { val, .. } => Ok(val.clone()),
|
||||||
value: UntaggedValue::Primitive(Primitive::Boolean(b)),
|
v => Err(ShellError::CantConvert("cell path".into(), v.span())),
|
||||||
..
|
}
|
||||||
} => Ok(*b),
|
}
|
||||||
Value {
|
}
|
||||||
value: UntaggedValue::Row(_),
|
|
||||||
..
|
impl FromValue for bool {
|
||||||
} => {
|
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||||
let mut shell_error = ShellError::type_error("boolean", v.spanned_type_name());
|
match v {
|
||||||
shell_error.notes.push(
|
Value::Bool { val, .. } => Ok(*val),
|
||||||
"Note: you can access columns using dot. eg) $it.column or (ls).column".into(),
|
v => Err(ShellError::CantConvert("bool".into(), v.span())),
|
||||||
);
|
|
||||||
Err(shell_error)
|
|
||||||
}
|
|
||||||
v => Err(ShellError::type_error("boolean", v.spanned_type_name())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
impl FromValue for Spanned<bool> {
|
impl FromValue for Spanned<bool> {
|
||||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||||
|
|
|
@ -79,6 +79,16 @@ pub fn flatten_expression(
|
||||||
Expr::Float(_) => {
|
Expr::Float(_) => {
|
||||||
vec![(expr.span, FlatShape::Float)]
|
vec![(expr.span, FlatShape::Float)]
|
||||||
}
|
}
|
||||||
|
Expr::CellPath(cell_path) => {
|
||||||
|
let mut output = vec![];
|
||||||
|
for path_element in &cell_path.members {
|
||||||
|
match path_element {
|
||||||
|
PathMember::String { span, .. } => output.push((*span, FlatShape::String)),
|
||||||
|
PathMember::Int { span, .. } => output.push((*span, FlatShape::Int)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
Expr::FullCellPath(cell_path) => {
|
Expr::FullCellPath(cell_path) => {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
output.extend(flatten_expression(working_set, &cell_path.head));
|
output.extend(flatten_expression(working_set, &cell_path.head));
|
||||||
|
|
|
@ -6,8 +6,8 @@ use crate::{
|
||||||
|
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{
|
ast::{
|
||||||
Block, Call, Expr, Expression, FullCellPath, ImportPattern, ImportPatternMember, Operator,
|
Block, Call, CellPath, Expr, Expression, FullCellPath, ImportPattern, ImportPatternMember,
|
||||||
PathMember, Pipeline, RangeInclusion, RangeOperator, Statement,
|
Operator, PathMember, Pipeline, RangeInclusion, RangeOperator, Statement,
|
||||||
},
|
},
|
||||||
engine::StateWorkingSet,
|
engine::StateWorkingSet,
|
||||||
span, Flag, PositionalArg, Signature, Span, SyntaxShape, Type, VarId,
|
span, Flag, PositionalArg, Signature, Span, SyntaxShape, Type, VarId,
|
||||||
|
@ -1157,6 +1157,62 @@ pub fn parse_variable_expr(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_cell_path(
|
||||||
|
working_set: &mut StateWorkingSet,
|
||||||
|
tokens: impl Iterator<Item = Token>,
|
||||||
|
mut expect_dot: bool,
|
||||||
|
span: Span,
|
||||||
|
) -> (Vec<PathMember>, Option<ParseError>) {
|
||||||
|
let mut error = None;
|
||||||
|
let mut tail = vec![];
|
||||||
|
|
||||||
|
for path_element in tokens {
|
||||||
|
let bytes = working_set.get_span_contents(path_element.span);
|
||||||
|
|
||||||
|
if expect_dot {
|
||||||
|
expect_dot = false;
|
||||||
|
if bytes.len() != 1 || bytes[0] != b'.' {
|
||||||
|
error = error.or_else(|| Some(ParseError::Expected('.'.into(), path_element.span)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expect_dot = true;
|
||||||
|
|
||||||
|
match parse_int(bytes, path_element.span) {
|
||||||
|
(
|
||||||
|
Expression {
|
||||||
|
expr: Expr::Int(val),
|
||||||
|
span,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
) => tail.push(PathMember::Int {
|
||||||
|
val: val as usize,
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
_ => {
|
||||||
|
let (result, err) = parse_string(working_set, path_element.span);
|
||||||
|
error = error.or(err);
|
||||||
|
match result {
|
||||||
|
Expression {
|
||||||
|
expr: Expr::String(string),
|
||||||
|
span,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
tail.push(PathMember::String { val: string, span });
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
error =
|
||||||
|
error.or_else(|| Some(ParseError::Expected("string".into(), span)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(tail, error)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_full_cell_path(
|
pub fn parse_full_cell_path(
|
||||||
working_set: &mut StateWorkingSet,
|
working_set: &mut StateWorkingSet,
|
||||||
implicit_head: Option<VarId>,
|
implicit_head: Option<VarId>,
|
||||||
|
@ -1173,7 +1229,7 @@ pub fn parse_full_cell_path(
|
||||||
let mut tokens = tokens.into_iter().peekable();
|
let mut tokens = tokens.into_iter().peekable();
|
||||||
if let Some(head) = tokens.peek() {
|
if let Some(head) = tokens.peek() {
|
||||||
let bytes = working_set.get_span_contents(head.span);
|
let bytes = working_set.get_span_contents(head.span);
|
||||||
let (head, mut expect_dot) = if bytes.starts_with(b"(") {
|
let (head, expect_dot) = if bytes.starts_with(b"(") {
|
||||||
let mut start = head.span.start;
|
let mut start = head.span.start;
|
||||||
let mut end = head.span.end;
|
let mut end = head.span.end;
|
||||||
|
|
||||||
|
@ -1247,52 +1303,8 @@ pub fn parse_full_cell_path(
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut tail = vec![];
|
let (tail, err) = parse_cell_path(working_set, tokens, expect_dot, span);
|
||||||
|
error = error.or(err);
|
||||||
for path_element in tokens {
|
|
||||||
let bytes = working_set.get_span_contents(path_element.span);
|
|
||||||
|
|
||||||
if expect_dot {
|
|
||||||
expect_dot = false;
|
|
||||||
if bytes.len() != 1 || bytes[0] != b'.' {
|
|
||||||
error =
|
|
||||||
error.or_else(|| Some(ParseError::Expected('.'.into(), path_element.span)));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
expect_dot = true;
|
|
||||||
|
|
||||||
match parse_int(bytes, path_element.span) {
|
|
||||||
(
|
|
||||||
Expression {
|
|
||||||
expr: Expr::Int(val),
|
|
||||||
span,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
) => tail.push(PathMember::Int {
|
|
||||||
val: val as usize,
|
|
||||||
span,
|
|
||||||
}),
|
|
||||||
_ => {
|
|
||||||
let (result, err) = parse_string(working_set, path_element.span);
|
|
||||||
error = error.or(err);
|
|
||||||
match result {
|
|
||||||
Expression {
|
|
||||||
expr: Expr::String(string),
|
|
||||||
span,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
tail.push(PathMember::String { val: string, span });
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
error = error
|
|
||||||
.or_else(|| Some(ParseError::Expected("string".into(), span)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
(
|
||||||
Expression {
|
Expression {
|
||||||
|
@ -2351,6 +2363,28 @@ pub fn parse_value(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SyntaxShape::CellPath => {
|
||||||
|
let source = working_set.get_span_contents(span);
|
||||||
|
let mut error = None;
|
||||||
|
|
||||||
|
let (tokens, err) = lex(source, span.start, &[b'\n'], &[b'.']);
|
||||||
|
error = error.or(err);
|
||||||
|
|
||||||
|
let tokens = tokens.into_iter().peekable();
|
||||||
|
|
||||||
|
let (cell_path, err) = parse_cell_path(working_set, tokens, false, span);
|
||||||
|
error = error.or(err);
|
||||||
|
|
||||||
|
(
|
||||||
|
Expression {
|
||||||
|
expr: Expr::CellPath(CellPath { members: cell_path }),
|
||||||
|
span,
|
||||||
|
ty: Type::CellPath,
|
||||||
|
custom_completion: None,
|
||||||
|
},
|
||||||
|
error,
|
||||||
|
)
|
||||||
|
}
|
||||||
SyntaxShape::Any => {
|
SyntaxShape::Any => {
|
||||||
if bytes.starts_with(b"[") {
|
if bytes.starts_with(b"[") {
|
||||||
parse_value(working_set, span, &SyntaxShape::Table)
|
parse_value(working_set, span, &SyntaxShape::Table)
|
||||||
|
|
|
@ -45,4 +45,8 @@ impl Call {
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn nth(&self, pos: usize) -> Option<Expression> {
|
||||||
|
self.positional.get(pos).cloned()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use super::Expression;
|
use super::Expression;
|
||||||
use crate::Span;
|
use crate::Span;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum PathMember {
|
pub enum PathMember {
|
||||||
String { val: String, span: Span },
|
String { val: String, span: Span },
|
||||||
Int { val: usize, span: Span },
|
Int { val: usize, span: Span },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct CellPath {
|
pub struct CellPath {
|
||||||
pub members: Vec<PathMember>,
|
pub members: Vec<PathMember>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{Call, Expression, FullCellPath, Operator, RangeOperator};
|
use super::{Call, CellPath, Expression, FullCellPath, Operator, RangeOperator};
|
||||||
use crate::{BlockId, Signature, Span, VarId};
|
use crate::{BlockId, Signature, Span, VarId};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -24,6 +24,7 @@ pub enum Expr {
|
||||||
Table(Vec<Expression>, Vec<Vec<Expression>>),
|
Table(Vec<Expression>, Vec<Vec<Expression>>),
|
||||||
Keyword(Vec<u8>, Span, Box<Expression>),
|
Keyword(Vec<u8>, Span, Box<Expression>),
|
||||||
String(String), // FIXME: improve this in the future?
|
String(String), // FIXME: improve this in the future?
|
||||||
|
CellPath(CellPath),
|
||||||
FullCellPath(Box<FullCellPath>),
|
FullCellPath(Box<FullCellPath>),
|
||||||
Signature(Box<Signature>),
|
Signature(Box<Signature>),
|
||||||
Garbage,
|
Garbage,
|
||||||
|
|
|
@ -9,7 +9,7 @@ pub use stream::*;
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use crate::ast::PathMember;
|
use crate::ast::{CellPath, PathMember};
|
||||||
use crate::{span, BlockId, Span, Type};
|
use crate::{span, BlockId, Span, Type};
|
||||||
|
|
||||||
use crate::ShellError;
|
use crate::ShellError;
|
||||||
|
@ -72,6 +72,10 @@ pub enum Value {
|
||||||
val: Vec<u8>,
|
val: Vec<u8>,
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
|
CellPath {
|
||||||
|
val: CellPath,
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
|
@ -99,6 +103,7 @@ impl Value {
|
||||||
Value::Stream { span, .. } => *span,
|
Value::Stream { span, .. } => *span,
|
||||||
Value::Nothing { span, .. } => *span,
|
Value::Nothing { span, .. } => *span,
|
||||||
Value::Binary { span, .. } => *span,
|
Value::Binary { span, .. } => *span,
|
||||||
|
Value::CellPath { span, .. } => *span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +124,7 @@ impl Value {
|
||||||
Value::Nothing { span, .. } => *span = new_span,
|
Value::Nothing { span, .. } => *span = new_span,
|
||||||
Value::Error { .. } => {}
|
Value::Error { .. } => {}
|
||||||
Value::Binary { span, .. } => *span = new_span,
|
Value::Binary { span, .. } => *span = new_span,
|
||||||
|
Value::CellPath { span, .. } => *span = new_span,
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
|
@ -143,6 +149,7 @@ impl Value {
|
||||||
Value::Stream { .. } => Type::ValueStream,
|
Value::Stream { .. } => Type::ValueStream,
|
||||||
Value::Error { .. } => Type::Error,
|
Value::Error { .. } => Type::Error,
|
||||||
Value::Binary { .. } => Type::Binary,
|
Value::Binary { .. } => Type::Binary,
|
||||||
|
Value::CellPath { .. } => Type::CellPath,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +191,7 @@ impl Value {
|
||||||
Value::Nothing { .. } => String::new(),
|
Value::Nothing { .. } => String::new(),
|
||||||
Value::Error { error } => format!("{:?}", error),
|
Value::Error { error } => format!("{:?}", error),
|
||||||
Value::Binary { val, .. } => format!("{:?}", val),
|
Value::Binary { val, .. } => format!("{:?}", val),
|
||||||
|
Value::CellPath { val, .. } => format!("{:?}", val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,6 +223,7 @@ impl Value {
|
||||||
Value::Nothing { .. } => String::new(),
|
Value::Nothing { .. } => String::new(),
|
||||||
Value::Error { error } => format!("{:?}", error),
|
Value::Error { error } => format!("{:?}", error),
|
||||||
Value::Binary { val, .. } => format!("{:?}", val),
|
Value::Binary { val, .. } => format!("{:?}", val),
|
||||||
|
Value::CellPath { val, .. } => format!("{:?}", val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,6 +240,10 @@ impl TextStyle {
|
||||||
.bold(Some(true))
|
.bold(Some(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default_field() -> TextStyle {
|
||||||
|
TextStyle::new().fg(Color::Green).bold(Some(true))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_attributes(bo: bool, al: Alignment, co: Color) -> TextStyle {
|
pub fn with_attributes(bo: bool, al: Alignment, co: Color) -> TextStyle {
|
||||||
TextStyle::new().alignment(al).fg(co).bold(Some(bo))
|
TextStyle::new().alignment(al).fg(co).bold(Some(bo))
|
||||||
}
|
}
|
||||||
|
|
13
src/tests.rs
13
src/tests.rs
|
@ -396,3 +396,16 @@ fn from_json_2() -> TestResult {
|
||||||
"Sally",
|
"Sally",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wrap() -> TestResult {
|
||||||
|
run_test(r#"([1, 2, 3] | wrap foo).foo.1"#, "2")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get() -> TestResult {
|
||||||
|
run_test(
|
||||||
|
r#"[[name, grade]; [Alice, A], [Betty, B]] | get grade.1"#,
|
||||||
|
"B",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue