mirror of
https://github.com/nushell/nushell.git
synced 2025-04-15 00:38:19 +02:00
* Moves off of draining between filters. Instead, the sink will pull on the stream, and will drain element-wise. This moves the whole stream to being lazy. * Adds ctrl-c support and connects it into some of the key points where we pull on the stream. If a ctrl-c is detect, we immediately halt pulling on the stream and return to the prompt. * Moves away from having a SourceMap where anchor locations are stored. Now AnchorLocation is kept directly in the Tag. * To make this possible, split tag and span. Span is largely used in the parser and is copyable. Tag is now no longer copyable.
309 lines
8.9 KiB
Rust
309 lines
8.9 KiB
Rust
pub(crate) mod atom;
|
|
pub(crate) mod delimited;
|
|
pub(crate) mod file_path;
|
|
pub(crate) mod list;
|
|
pub(crate) mod number;
|
|
pub(crate) mod pattern;
|
|
pub(crate) mod string;
|
|
pub(crate) mod unit;
|
|
pub(crate) mod variable_path;
|
|
|
|
use crate::parser::hir::syntax_shape::{
|
|
color_delimited_square, color_fallible_syntax, color_fallible_syntax_with, expand_atom,
|
|
expand_delimited_square, expand_expr, expand_syntax, AtomicToken, BareShape, ColorableDotShape,
|
|
DotShape, ExpandContext, ExpandExpression, ExpandSyntax, ExpansionRule, ExpressionContinuation,
|
|
ExpressionContinuationShape, FallibleColorSyntax, FlatShape,
|
|
};
|
|
use crate::parser::{
|
|
hir,
|
|
hir::{Expression, TokensIterator},
|
|
};
|
|
use crate::prelude::*;
|
|
use std::path::PathBuf;
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub struct AnyExpressionShape;
|
|
|
|
impl ExpandExpression for AnyExpressionShape {
|
|
fn expand_expr<'a, 'b>(
|
|
&self,
|
|
token_nodes: &mut TokensIterator<'_>,
|
|
context: &ExpandContext,
|
|
) -> Result<hir::Expression, ShellError> {
|
|
// Look for an expression at the cursor
|
|
let head = expand_expr(&AnyExpressionStartShape, token_nodes, context)?;
|
|
|
|
continue_expression(head, token_nodes, context)
|
|
}
|
|
}
|
|
|
|
impl FallibleColorSyntax for AnyExpressionShape {
|
|
type Info = ();
|
|
type Input = ();
|
|
|
|
fn color_syntax<'a, 'b>(
|
|
&self,
|
|
_input: &(),
|
|
token_nodes: &'b mut TokensIterator<'a>,
|
|
context: &ExpandContext,
|
|
shapes: &mut Vec<Spanned<FlatShape>>,
|
|
) -> Result<(), ShellError> {
|
|
// Look for an expression at the cursor
|
|
color_fallible_syntax(&AnyExpressionStartShape, token_nodes, context, shapes)?;
|
|
|
|
match continue_coloring_expression(token_nodes, context, shapes) {
|
|
Err(_) => {
|
|
// it's fine for there to be no continuation
|
|
}
|
|
|
|
Ok(()) => {}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub(crate) fn continue_expression(
|
|
mut head: hir::Expression,
|
|
token_nodes: &mut TokensIterator<'_>,
|
|
context: &ExpandContext,
|
|
) -> Result<hir::Expression, ShellError> {
|
|
loop {
|
|
// Check to see whether there's any continuation after the head expression
|
|
let continuation = expand_syntax(&ExpressionContinuationShape, token_nodes, context);
|
|
|
|
match continuation {
|
|
// If there's no continuation, return the head
|
|
Err(_) => return Ok(head),
|
|
// Otherwise, form a new expression by combining the head with the continuation
|
|
Ok(continuation) => match continuation {
|
|
// If the continuation is a `.member`, form a path with the new member
|
|
ExpressionContinuation::DotSuffix(_dot, member) => {
|
|
head = Expression::dot_member(head, member);
|
|
}
|
|
|
|
// Otherwise, if the continuation is an infix suffix, form an infix expression
|
|
ExpressionContinuation::InfixSuffix(op, expr) => {
|
|
head = Expression::infix(head, op, expr);
|
|
}
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn continue_coloring_expression(
|
|
token_nodes: &mut TokensIterator<'_>,
|
|
context: &ExpandContext,
|
|
shapes: &mut Vec<Spanned<FlatShape>>,
|
|
) -> Result<(), ShellError> {
|
|
// if there's not even one expression continuation, fail
|
|
color_fallible_syntax(&ExpressionContinuationShape, token_nodes, context, shapes)?;
|
|
|
|
loop {
|
|
// Check to see whether there's any continuation after the head expression
|
|
let result =
|
|
color_fallible_syntax(&ExpressionContinuationShape, token_nodes, context, shapes);
|
|
|
|
match result {
|
|
Err(_) => {
|
|
// We already saw one continuation, so just return
|
|
return Ok(());
|
|
}
|
|
|
|
Ok(_) => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub struct AnyExpressionStartShape;
|
|
|
|
impl ExpandExpression for AnyExpressionStartShape {
|
|
fn expand_expr<'a, 'b>(
|
|
&self,
|
|
token_nodes: &mut TokensIterator<'_>,
|
|
context: &ExpandContext,
|
|
) -> Result<hir::Expression, ShellError> {
|
|
let atom = expand_atom(token_nodes, "expression", context, ExpansionRule::new())?;
|
|
|
|
match atom.item {
|
|
AtomicToken::Size { number, unit } => {
|
|
return Ok(hir::Expression::size(
|
|
number.to_number(context.source),
|
|
unit.item,
|
|
Tag {
|
|
span: atom.span,
|
|
anchor: None,
|
|
},
|
|
))
|
|
}
|
|
|
|
AtomicToken::SquareDelimited { nodes, .. } => {
|
|
expand_delimited_square(&nodes, atom.span.into(), context)
|
|
}
|
|
|
|
AtomicToken::Word { .. } | AtomicToken::Dot { .. } => {
|
|
let end = expand_syntax(&BareTailShape, token_nodes, context)?;
|
|
Ok(hir::Expression::bare(atom.span.until_option(end)))
|
|
}
|
|
|
|
other => return other.spanned(atom.span).into_hir(context, "expression"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FallibleColorSyntax for AnyExpressionStartShape {
|
|
type Info = ();
|
|
type Input = ();
|
|
|
|
fn color_syntax<'a, 'b>(
|
|
&self,
|
|
_input: &(),
|
|
token_nodes: &'b mut TokensIterator<'a>,
|
|
context: &ExpandContext,
|
|
shapes: &mut Vec<Spanned<FlatShape>>,
|
|
) -> Result<(), ShellError> {
|
|
let atom = token_nodes.spanned(|token_nodes| {
|
|
expand_atom(
|
|
token_nodes,
|
|
"expression",
|
|
context,
|
|
ExpansionRule::permissive(),
|
|
)
|
|
});
|
|
|
|
let atom = match atom {
|
|
Spanned {
|
|
item: Err(_err),
|
|
span,
|
|
} => {
|
|
shapes.push(FlatShape::Error.spanned(span));
|
|
return Ok(());
|
|
}
|
|
|
|
Spanned {
|
|
item: Ok(value), ..
|
|
} => value,
|
|
};
|
|
|
|
match atom.item {
|
|
AtomicToken::Size { number, unit } => shapes.push(
|
|
FlatShape::Size {
|
|
number: number.span.into(),
|
|
unit: unit.span.into(),
|
|
}
|
|
.spanned(atom.span),
|
|
),
|
|
|
|
AtomicToken::SquareDelimited { nodes, spans } => {
|
|
color_delimited_square(spans, &nodes, atom.span.into(), context, shapes)
|
|
}
|
|
|
|
AtomicToken::Word { .. } | AtomicToken::Dot { .. } => {
|
|
shapes.push(FlatShape::Word.spanned(atom.span));
|
|
}
|
|
|
|
_ => atom.color_tokens(shapes),
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub struct BareTailShape;
|
|
|
|
impl FallibleColorSyntax for BareTailShape {
|
|
type Info = ();
|
|
type Input = ();
|
|
|
|
fn color_syntax<'a, 'b>(
|
|
&self,
|
|
_input: &(),
|
|
token_nodes: &'b mut TokensIterator<'a>,
|
|
context: &ExpandContext,
|
|
shapes: &mut Vec<Spanned<FlatShape>>,
|
|
) -> Result<(), ShellError> {
|
|
let len = shapes.len();
|
|
|
|
loop {
|
|
let word = color_fallible_syntax_with(
|
|
&BareShape,
|
|
&FlatShape::Word,
|
|
token_nodes,
|
|
context,
|
|
shapes,
|
|
);
|
|
|
|
match word {
|
|
// if a word was found, continue
|
|
Ok(_) => continue,
|
|
// if a word wasn't found, try to find a dot
|
|
Err(_) => {}
|
|
}
|
|
|
|
// try to find a dot
|
|
let dot = color_fallible_syntax_with(
|
|
&ColorableDotShape,
|
|
&FlatShape::Word,
|
|
token_nodes,
|
|
context,
|
|
shapes,
|
|
);
|
|
|
|
match dot {
|
|
// if a dot was found, try to find another word
|
|
Ok(_) => continue,
|
|
// otherwise, we're done
|
|
Err(_) => break,
|
|
}
|
|
}
|
|
|
|
if shapes.len() > len {
|
|
Ok(())
|
|
} else {
|
|
Err(ShellError::syntax_error(
|
|
"No tokens matched BareTailShape".tagged_unknown(),
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ExpandSyntax for BareTailShape {
|
|
type Output = Option<Span>;
|
|
|
|
fn expand_syntax<'a, 'b>(
|
|
&self,
|
|
token_nodes: &'b mut TokensIterator<'a>,
|
|
context: &ExpandContext,
|
|
) -> Result<Option<Span>, ShellError> {
|
|
let mut end: Option<Span> = None;
|
|
|
|
loop {
|
|
match expand_syntax(&BareShape, token_nodes, context) {
|
|
Ok(bare) => {
|
|
end = Some(bare.span);
|
|
continue;
|
|
}
|
|
|
|
Err(_) => match expand_syntax(&DotShape, token_nodes, context) {
|
|
Ok(dot) => {
|
|
end = Some(dot);
|
|
continue;
|
|
}
|
|
|
|
Err(_) => break,
|
|
},
|
|
}
|
|
}
|
|
|
|
Ok(end)
|
|
}
|
|
}
|
|
|
|
pub fn expand_file_path(string: &str, context: &ExpandContext) -> PathBuf {
|
|
let expanded = shellexpand::tilde_with_context(string, || context.homedir());
|
|
|
|
PathBuf::from(expanded.as_ref())
|
|
}
|