forked from extern/nushell
Add =~
and !~
operators on strings
`left =~ right` return true if left contains right, using Rust's `String::contains`. `!~` is the negated version. A new `apply_operator` function is added which decouples evaluation from `Value::compare`. This returns a `Value` and opens the door to implementing `+` for example, though it wouldn't be useful immediately. The `operator!` macro had to be changed slightly as it would choke on `~` in arguments.
This commit is contained in:
parent
e4226def16
commit
8f9dd6516e
@ -1,51 +0,0 @@
|
||||
use nu_source::ShellAnnotation;
|
||||
use pretty::{Render, RenderAnnotated};
|
||||
use std::io;
|
||||
use termcolor::WriteColor;
|
||||
|
||||
pub struct TermColored<'a, W> {
|
||||
color_stack: Vec<ShellAnnotation>,
|
||||
upstream: &'a mut W,
|
||||
}
|
||||
|
||||
impl<'a, W> TermColored<'a, W> {
|
||||
pub fn new(upstream: &'a mut W) -> TermColored<'a, W> {
|
||||
TermColored {
|
||||
color_stack: Vec::new(),
|
||||
upstream,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, W> Render for TermColored<'a, W>
|
||||
where
|
||||
W: io::Write,
|
||||
{
|
||||
type Error = io::Error;
|
||||
|
||||
fn write_str(&mut self, s: &str) -> io::Result<usize> {
|
||||
self.upstream.write(s.as_bytes())
|
||||
}
|
||||
|
||||
fn write_str_all(&mut self, s: &str) -> io::Result<()> {
|
||||
self.upstream.write_all(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, W> RenderAnnotated<ShellAnnotation> for TermColored<'a, W>
|
||||
where
|
||||
W: WriteColor,
|
||||
{
|
||||
fn push_annotation(&mut self, ann: &ShellAnnotation) -> Result<(), Self::Error> {
|
||||
self.color_stack.push(*ann);
|
||||
self.upstream.set_color(&(*ann).into())
|
||||
}
|
||||
|
||||
fn pop_annotation(&mut self) -> Result<(), Self::Error> {
|
||||
self.color_stack.pop();
|
||||
match self.color_stack.last() {
|
||||
Some(previous) => self.upstream.set_color(&(*previous).into()),
|
||||
None => self.upstream.reset(),
|
||||
}
|
||||
}
|
||||
}
|
@ -13,13 +13,7 @@ use crate::parse::parser::Number;
|
||||
use crate::parse::unit::Unit;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
#[cfg(not(coloring_in_tokens))]
|
||||
use nu_errors::ShellError;
|
||||
#[cfg(not(coloring_in_tokens))]
|
||||
use nu_protocol::{EvaluatedArgs, Scope};
|
||||
use nu_protocol::{PathMember, ShellTypeName};
|
||||
#[cfg(not(coloring_in_tokens))]
|
||||
use nu_source::Text;
|
||||
use nu_source::{
|
||||
b, DebugDocBuilder, HasSpan, PrettyDebug, PrettyDebugWithSource, Span, Spanned, SpannedItem,
|
||||
};
|
||||
|
@ -1,5 +1,4 @@
|
||||
pub mod commands;
|
||||
pub mod debug;
|
||||
pub mod hir;
|
||||
pub mod parse;
|
||||
pub mod parse_command;
|
||||
|
@ -11,5 +11,6 @@ pub use self::meta::{
|
||||
pub use self::pretty::{
|
||||
b, DebugDoc, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource, ShellAnnotation,
|
||||
};
|
||||
pub use self::term_colored::TermColored;
|
||||
pub use self::text::Text;
|
||||
pub use self::tracable::{nom_input, NomSpan, TracableContext};
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::parser::hir;
|
||||
use derive_new::new;
|
||||
use nu_parser::hir;
|
||||
|
||||
#[derive(new, Debug, Eq, PartialEq)]
|
||||
pub(crate) struct Command {
|
||||
|
@ -1,9 +1,12 @@
|
||||
use super::ClassifiedInputStream;
|
||||
use crate::data::value;
|
||||
use crate::prelude::*;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use futures::stream::StreamExt;
|
||||
use futures_codec::{Decoder, Encoder, Framed};
|
||||
use log::trace;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::Value;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use subprocess::Exec;
|
||||
|
||||
@ -105,7 +108,7 @@ impl Command {
|
||||
let input_strings = inputs
|
||||
.iter()
|
||||
.map(|i| {
|
||||
i.as_string().map_err(|_| {
|
||||
i.as_string().map(|s| s.to_string()).map_err(|_| {
|
||||
let arg = self.args.iter().find(|arg| arg.arg.contains("$it"));
|
||||
if let Some(arg) = arg {
|
||||
ShellError::labeled_error(
|
||||
@ -206,9 +209,8 @@ impl Command {
|
||||
let stdout = popen.stdout.take().unwrap();
|
||||
let file = futures::io::AllowStdIo::new(stdout);
|
||||
let stream = Framed::new(file, LinesCodec {});
|
||||
let stream = stream.map(move |line| {
|
||||
UntaggedValue::string(line.unwrap()).into_value(&name_tag)
|
||||
});
|
||||
let stream =
|
||||
stream.map(move |line| value::string(line.unwrap()).into_value(&name_tag));
|
||||
Ok(ClassifiedInputStream::from_input_stream(
|
||||
stream.boxed() as BoxStream<'static, Value>
|
||||
))
|
||||
|
@ -1,7 +1,10 @@
|
||||
use crate::parser::hir;
|
||||
use crate::data::value;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use log::{log_enabled, trace};
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::hir;
|
||||
use nu_protocol::{CommandAction, Primitive, ReturnSuccess, UntaggedValue, Value};
|
||||
|
||||
use super::ClassifiedInputStream;
|
||||
|
||||
@ -77,7 +80,7 @@ impl Command {
|
||||
} => {
|
||||
context.shell_manager.insert_at_current(Box::new(
|
||||
HelpShell::for_command(
|
||||
UntaggedValue::string(cmd).into_value(tag),
|
||||
value::string(cmd).into_value(tag),
|
||||
&context.registry(),
|
||||
).unwrap(),
|
||||
));
|
||||
@ -126,12 +129,12 @@ impl Command {
|
||||
|
||||
doc.render_raw(
|
||||
context.with_host(|host| host.width() - 5),
|
||||
&mut crate::parser::debug::TermColored::new(&mut buffer),
|
||||
&mut nu_source::TermColored::new(&mut buffer),
|
||||
).unwrap();
|
||||
|
||||
let value = String::from_utf8_lossy(buffer.as_slice());
|
||||
|
||||
yield Ok(UntaggedValue::string(value).into_untagged_value())
|
||||
yield Ok(value::string(value).into_untagged_value())
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::parser::{hir, TokenNode};
|
||||
use crate::prelude::*;
|
||||
use nu_parser::{hir, TokenNode};
|
||||
|
||||
mod dynamic;
|
||||
mod external;
|
||||
@ -11,7 +11,6 @@ pub(crate) use dynamic::Command as DynamicCommand;
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use external::{Command as ExternalCommand, ExternalArg, ExternalArgs, StreamNext};
|
||||
pub(crate) use internal::Command as InternalCommand;
|
||||
pub(crate) use pipeline::Pipeline as ClassifiedPipeline;
|
||||
|
||||
pub(crate) struct ClassifiedInputStream {
|
||||
pub(crate) objects: InputStream,
|
||||
@ -21,7 +20,7 @@ pub(crate) struct ClassifiedInputStream {
|
||||
impl ClassifiedInputStream {
|
||||
pub(crate) fn new() -> ClassifiedInputStream {
|
||||
ClassifiedInputStream {
|
||||
objects: vec![UntaggedValue::nothing().into_untagged_value()].into(),
|
||||
objects: vec![crate::data::value::nothing().into_untagged_value()].into(),
|
||||
stdin: None,
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -150,10 +150,10 @@ impl CompareValues {
|
||||
}
|
||||
|
||||
pub(crate) fn coerce_compare(
|
||||
left: &Value,
|
||||
right: &Value,
|
||||
left: &UntaggedValue,
|
||||
right: &UntaggedValue,
|
||||
) -> Result<CompareValues, (&'static str, &'static str)> {
|
||||
match (&left.value, &right.value) {
|
||||
match (left, right) {
|
||||
(UntaggedValue::Primitive(left), UntaggedValue::Primitive(right)) => {
|
||||
coerce_compare_primitive(left, right)
|
||||
}
|
||||
|
@ -98,8 +98,8 @@ pub fn nothing() -> UntaggedValue {
|
||||
|
||||
pub fn compare_values(
|
||||
operator: &Operator,
|
||||
left: &Value,
|
||||
right: &Value,
|
||||
left: &UntaggedValue,
|
||||
right: &UntaggedValue,
|
||||
) -> Result<bool, (&'static str, &'static str)> {
|
||||
match operator {
|
||||
_ => {
|
||||
|
@ -1,13 +1,7 @@
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::data::base::Block;
|
||||
use crate::data::value;
|
||||
use crate::errors::ArgumentError;
|
||||
use crate::evaluate::operator::apply_operator;
|
||||
use crate::parser::hir::path::{ColumnPath, UnspannedPathMember};
|
||||
use crate::parser::{
|
||||
hir::{self, Expression, RawExpression},
|
||||
CommandRegistry,
|
||||
};
|
||||
use crate::prelude::*;
|
||||
use crate::TaggedDictBuilder;
|
||||
use log::trace;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::data::base::{Primitive, UntaggedValue, Value};
|
||||
use crate::parser::Operator;
|
||||
use crate::traits::ShellTypeName;
|
||||
use crate::data::value;
|
||||
use nu_parser::Operator;
|
||||
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
|
||||
use std::ops::Not;
|
||||
|
||||
pub fn apply_operator(
|
||||
@ -14,12 +14,10 @@ pub fn apply_operator(
|
||||
| Operator::LessThan
|
||||
| Operator::GreaterThan
|
||||
| Operator::LessThanOrEqual
|
||||
| Operator::GreaterThanOrEqual => left.compare(op, right).map(UntaggedValue::boolean),
|
||||
Operator::Dot => Ok(UntaggedValue::boolean(false)),
|
||||
Operator::Contains => contains(left, right).map(UntaggedValue::boolean),
|
||||
Operator::NotContains => contains(left, right)
|
||||
.map(Not::not)
|
||||
.map(UntaggedValue::boolean),
|
||||
| Operator::GreaterThanOrEqual => left.compare(op, right).map(value::boolean),
|
||||
Operator::Dot => Ok(value::boolean(false)),
|
||||
Operator::Contains => contains(left, right).map(value::boolean),
|
||||
Operator::NotContains => contains(left, right).map(Not::not).map(value::boolean),
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user