Date literals (#4619)

* Date literals

* update deps

* Add date+duration
This commit is contained in:
JT
2022-02-23 21:02:48 -05:00
committed by GitHub
parent 63487941fb
commit 4b18fdcc6e
19 changed files with 201 additions and 23 deletions

View File

@ -131,6 +131,13 @@ impl Highlighter for NuHighlighter {
next_token,
))
}
FlatShape::DateTime => {
// nushell ???
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::List => {
// nushell ???
output.push((

View File

@ -22,6 +22,7 @@ pub fn get_shape_color(shape: String, conf: &Config) -> Style {
"shape_signature" => Style::new().fg(Color::Green).bold(),
"shape_string" => Style::new().fg(Color::Green),
"shape_string_interpolation" => Style::new().fg(Color::Cyan).bold(),
"shape_datetime" => Style::new().fg(Color::Cyan).bold(),
"shape_list" => Style::new().fg(Color::Cyan).bold(),
"shape_table" => Style::new().fg(Color::Blue).bold(),
"shape_record" => Style::new().fg(Color::Cyan).bold(),

View File

@ -30,7 +30,7 @@ calamine = "0.18.0"
chrono = { version = "0.4.19", features = ["serde"] }
chrono-humanize = "0.2.1"
chrono-tz = "0.6.0"
crossterm = "0.22.1"
crossterm = "0.23"
csv = "1.1.3"
dialoguer = "0.9.0"
digest = "0.10.0"
@ -47,7 +47,7 @@ Inflector = "0.11"
itertools = "0.10.0"
lazy_static = "1.4.0"
log = "0.4.14"
lscolors = { version = "0.8.0", features = ["crossterm"] }
lscolors = { version = "0.9.0", features = ["crossterm"] }
md5 = { package = "md-5", version = "0.10.0" }
meval = "0.2.0"
mime = "0.3.16"

View File

@ -41,8 +41,8 @@ impl Command for UpdateCells {
Example {
description: "Update the zero value cells to empty strings.",
example: r#"[
[2021-04-16, 2021-06-10, 2021-09-18, 2021-10-15, 2021-11-16, 2021-11-17, 2021-11-18];
[ 37, 0, 0, 0, 37, 0, 0]
["2021-04-16", "2021-06-10", "2021-09-18", "2021-10-15", "2021-11-16", "2021-11-17", "2021-11-18"];
[ 37, 0, 0, 0, 37, 0, 0]
] | update cells {|value|
if $value == 0 {
""
@ -78,8 +78,8 @@ impl Command for UpdateCells {
Example {
description: "Update the zero value cells to empty strings in 2 last columns.",
example: r#"[
[2021-04-16, 2021-06-10, 2021-09-18, 2021-10-15, 2021-11-16, 2021-11-17, 2021-11-18];
[ 37, 0, 0, 0, 37, 0, 0]
["2021-04-16", "2021-06-10", "2021-09-18", "2021-10-15", "2021-11-16", "2021-11-17", "2021-11-18"];
[ 37, 0, 0, 0, 37, 0, 0]
] | update cells -c ["2021-11-18", "2021-11-17"] {|value|
if $value == 0 {
""

View File

@ -212,6 +212,7 @@ fn convert_to_value(
"subexpressions and cellpaths not supported in nuon".into(),
expr.span,
)),
Expr::DateTime(dt) => Ok(Value::Date { val: dt, span }),
Expr::ExternalCall(..) => Err(ShellError::OutsideSpannedLabeledError(
original_text.to_string(),
"Error when loading".into(),

View File

@ -57,7 +57,7 @@ fn value_to_string(v: &Value, span: Span) -> Result<String, ShellError> {
}
Value::CellPath { .. } => Err(ShellError::UnsupportedInput("cellpath".to_string(), span)),
Value::CustomValue { .. } => Err(ShellError::UnsupportedInput("custom".to_string(), span)),
Value::Date { .. } => Err(ShellError::UnsupportedInput("date".to_string(), span)),
Value::Date { val, .. } => Ok(val.to_rfc3339()),
Value::Duration { val, .. } => Ok(format!("{}ns", *val)),
Value::Error { .. } => Err(ShellError::UnsupportedInput("error".to_string(), span)),
Value::Filesize { val, .. } => Ok(format!("{}b", *val)),

View File

@ -292,6 +292,10 @@ pub fn eval_expression(
)?
.into_value(span))
}
Expr::DateTime(dt) => Ok(Value::Date {
val: *dt,
span: expr.span,
}),
Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }),
Expr::BinaryOp(lhs, op, rhs) => {
let op_span = op.span;

View File

@ -4,6 +4,7 @@ version = "0.59.0"
edition = "2021"
[dependencies]
chrono = "0.4.19"
miette = "4.1.0"
thiserror = "1.0.29"
serde_json = "1.0"

View File

@ -23,6 +23,7 @@ pub enum FlatShape {
Record,
Block,
Filepath,
DateTime,
GlobPattern,
Variable,
Flag,
@ -45,6 +46,7 @@ impl Display for FlatShape {
FlatShape::Operator => write!(f, "shape_operator"),
FlatShape::Signature => write!(f, "shape_signature"),
FlatShape::String => write!(f, "shape_string"),
FlatShape::DateTime => write!(f, "shape_datetime"),
FlatShape::StringInterpolation => write!(f, "shape_string_interpolation"),
FlatShape::List => write!(f, "shape_list"),
FlatShape::Table => write!(f, "shape_table"),
@ -184,6 +186,9 @@ pub fn flatten_expression(
Expr::Nothing => {
vec![(expr.span, FlatShape::Nothing)]
}
Expr::DateTime(_) => {
vec![(expr.span, FlatShape::DateTime)]
}
Expr::Int(_) => {
vec![(expr.span, FlatShape::Int)]
}

View File

@ -1704,6 +1704,65 @@ pub fn parse_filepath(
}
}
/// Parse a datetime type, eg '2022-02-02'
pub fn parse_datetime(
working_set: &mut StateWorkingSet,
span: Span,
) -> (Expression, Option<ParseError>) {
trace!("parsing: datetime");
let bytes = working_set.get_span_contents(span);
let token = String::from_utf8_lossy(bytes).to_string();
if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&token) {
return (
Expression {
expr: Expr::DateTime(datetime),
span,
ty: Type::Date,
custom_completion: None,
},
None,
);
}
// Just the date
if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&format!("{}T00:00:00+00:00", token))
{
return (
Expression {
expr: Expr::DateTime(datetime),
span,
ty: Type::Date,
custom_completion: None,
},
None,
);
}
// Date and time, assume UTC
if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&format!("{}+00:00", token)) {
return (
Expression {
expr: Expr::DateTime(datetime),
span,
ty: Type::Date,
custom_completion: None,
},
None,
);
}
(
garbage(span),
Some(ParseError::Mismatch(
"datetime".into(),
"non-datetime".into(),
span,
)),
)
}
/// Parse a duration type, eg '10day'
pub fn parse_duration(
working_set: &mut StateWorkingSet,
@ -3115,6 +3174,7 @@ pub fn parse_value(
SyntaxShape::Number => parse_number(bytes, span),
SyntaxShape::Int => parse_int(bytes, span),
SyntaxShape::Duration => parse_duration(working_set, span),
SyntaxShape::DateTime => parse_datetime(working_set, span),
SyntaxShape::Filesize => parse_filesize(working_set, span),
SyntaxShape::Range => parse_range(working_set, span),
SyntaxShape::Filepath => parse_filepath(working_set, span),
@ -3212,6 +3272,7 @@ pub fn parse_value(
SyntaxShape::Int,
SyntaxShape::Number,
SyntaxShape::Range,
SyntaxShape::DateTime,
SyntaxShape::Filesize,
SyntaxShape::Duration,
SyntaxShape::Block(None),
@ -3950,6 +4011,7 @@ pub fn discover_captures_in_expr(
}
}
Expr::CellPath(_) => {}
Expr::DateTime(_) => {}
Expr::ExternalCall(head, exprs) => {
let result = discover_captures_in_expr(working_set, head, seen, seen_blocks);
output.extend(&result);

View File

@ -31,6 +31,7 @@ pub fn math_result_type(
(Type::Int, Type::Float) => (Type::Float, None),
(Type::Float, Type::Float) => (Type::Float, None),
(Type::String, Type::String) => (Type::String, None),
(Type::Date, Type::Duration) => (Type::Date, None),
(Type::Duration, Type::Duration) => (Type::Duration, None),
(Type::Filesize, Type::Filesize) => (Type::Filesize, None),
@ -69,6 +70,7 @@ pub fn math_result_type(
(Type::Float, Type::Int) => (Type::Float, None),
(Type::Int, Type::Float) => (Type::Float, None),
(Type::Float, Type::Float) => (Type::Float, None),
(Type::Date, Type::Date) => (Type::Duration, None),
(Type::Duration, Type::Duration) => (Type::Duration, None),
(Type::Filesize, Type::Filesize) => (Type::Filesize, None),

View File

@ -1,3 +1,5 @@
use chrono::FixedOffset;
use super::{Call, CellPath, Expression, FullCellPath, Operator, RangeOperator};
use crate::{ast::ImportPattern, BlockId, Signature, Span, Spanned, Unit, VarId};
@ -26,6 +28,7 @@ pub enum Expr {
Record(Vec<(Expression, Expression)>),
Keyword(Vec<u8>, Span, Box<Expression>),
ValueWithUnit(Box<Expression>, Spanned<Unit>),
DateTime(chrono::DateTime<FixedOffset>),
Filepath(String),
GlobPattern(String),
String(String),

View File

@ -142,6 +142,7 @@ impl Expression {
false
}
Expr::CellPath(_) => false,
Expr::DateTime(_) => false,
Expr::ExternalCall(head, args) => {
if head.has_in_variable(working_set) {
return true;
@ -301,6 +302,7 @@ impl Expression {
}
}
Expr::CellPath(_) => {}
Expr::DateTime(_) => {}
Expr::ExternalCall(head, args) => {
head.replace_in_variable(working_set, new_var_id);
for arg in args {
@ -443,6 +445,7 @@ impl Expression {
}
}
Expr::CellPath(_) => {}
Expr::DateTime(_) => {}
Expr::ExternalCall(head, args) => {
head.replace_span(working_set, replaced, new_span);
for arg in args {

View File

@ -55,6 +55,9 @@ pub enum SyntaxShape {
/// A duration value is allowed, eg `19day`
Duration,
/// A datetime value, eg `2022-02-02` or `2019-10-12T07:20:50.52+00:00`
DateTime,
/// An operator
Operator,
@ -94,6 +97,7 @@ impl SyntaxShape {
SyntaxShape::Block(_) => Type::Block,
SyntaxShape::CellPath => Type::Unknown,
SyntaxShape::Custom(custom, _) => custom.to_type(),
SyntaxShape::DateTime => Type::Date,
SyntaxShape::Duration => Type::Duration,
SyntaxShape::Expression => Type::Unknown,
SyntaxShape::Filepath => Type::String,
@ -145,6 +149,7 @@ impl Display for SyntaxShape {
SyntaxShape::Record => write!(f, "record"),
SyntaxShape::Filesize => write!(f, "filesize"),
SyntaxShape::Duration => write!(f, "duration"),
SyntaxShape::DateTime => write!(f, "datetime"),
SyntaxShape::Operator => write!(f, "operator"),
SyntaxShape::RowCondition => write!(f, "condition"),
SyntaxShape::MathExpression => write!(f, "variable"),

View File

@ -1306,6 +1306,17 @@ impl Value {
val: lhs - rhs,
span,
}),
(Value::Date { val: lhs, .. }, Value::Date { val: rhs, .. }) => {
let result = lhs.signed_duration_since(*rhs);
match result.num_nanoseconds() {
Some(v) => Ok(Value::Duration { val: v, span }),
None => Err(ShellError::OperatorOverflow(
"subtraction operation overflowed".into(),
span,
)),
}
}
(Value::Date { val: lhs, .. }, Value::Duration { val: rhs, .. }) => {
match lhs.checked_sub_signed(chrono::Duration::nanoseconds(*rhs)) {
Some(val) => Ok(Value::Date { val, span }),