mirror of
https://github.com/nushell/nushell
synced 2024-12-27 05:23:11 +00:00
Add single tick string interpolation (#581)
* Add single tick string interpolation * give string interpolation its own highlighting
This commit is contained in:
parent
d603086d2f
commit
ca6baf7a46
8 changed files with 99 additions and 35 deletions
|
@ -118,6 +118,13 @@ impl Highlighter for NuHighlighter {
|
||||||
next_token,
|
next_token,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
FlatShape::StringInterpolation => {
|
||||||
|
// nushell ???
|
||||||
|
output.push((
|
||||||
|
get_shape_color(shape.1.to_string(), &self.config),
|
||||||
|
next_token,
|
||||||
|
))
|
||||||
|
}
|
||||||
FlatShape::Filepath => output.push((
|
FlatShape::Filepath => output.push((
|
||||||
// nushell Path
|
// nushell Path
|
||||||
get_shape_color(shape.1.to_string(), &self.config),
|
get_shape_color(shape.1.to_string(), &self.config),
|
||||||
|
|
|
@ -18,6 +18,7 @@ pub fn get_shape_color(shape: String, conf: &Config) -> Style {
|
||||||
"flatshape_operator" => Style::new().fg(Color::Yellow),
|
"flatshape_operator" => Style::new().fg(Color::Yellow),
|
||||||
"flatshape_signature" => Style::new().fg(Color::Green).bold(),
|
"flatshape_signature" => Style::new().fg(Color::Green).bold(),
|
||||||
"flatshape_string" => Style::new().fg(Color::Green),
|
"flatshape_string" => Style::new().fg(Color::Green),
|
||||||
|
"flatshape_string_interpolation" => Style::new().fg(Color::Cyan).bold(),
|
||||||
"flatshape_filepath" => Style::new().fg(Color::Cyan),
|
"flatshape_filepath" => Style::new().fg(Color::Cyan),
|
||||||
"flatshape_globpattern" => Style::new().fg(Color::Cyan).bold(),
|
"flatshape_globpattern" => Style::new().fg(Color::Cyan).bold(),
|
||||||
"flatshape_variable" => Style::new().fg(Color::Purple),
|
"flatshape_variable" => Style::new().fg(Color::Purple),
|
||||||
|
|
|
@ -3,7 +3,8 @@ use std::cmp::Ordering;
|
||||||
use nu_protocol::ast::{Block, Call, Expr, Expression, Operator, Statement};
|
use nu_protocol::ast::{Block, Call, Expr, Expression, Operator, Statement};
|
||||||
use nu_protocol::engine::{EngineState, Stack};
|
use nu_protocol::engine::{EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
IntoPipelineData, PipelineData, Range, ShellError, Span, Spanned, Type, Unit, Value, VarId,
|
IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Range, ShellError, Span,
|
||||||
|
Spanned, Type, Unit, Value, VarId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::get_full_help;
|
use crate::get_full_help;
|
||||||
|
@ -341,6 +342,23 @@ pub fn eval_expression(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Expr::Keyword(_, _, expr) => eval_expression(engine_state, stack, expr),
|
Expr::Keyword(_, _, expr) => eval_expression(engine_state, stack, expr),
|
||||||
|
Expr::StringInterpolation(exprs) => {
|
||||||
|
let mut parts = vec![];
|
||||||
|
for expr in exprs {
|
||||||
|
parts.push(eval_expression(engine_state, stack, expr)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = stack.get_config().unwrap_or_default();
|
||||||
|
|
||||||
|
parts
|
||||||
|
.into_iter()
|
||||||
|
.into_pipeline_data(None)
|
||||||
|
.collect_string("", &config)
|
||||||
|
.map(|x| Value::String {
|
||||||
|
val: x,
|
||||||
|
span: expr.span,
|
||||||
|
})
|
||||||
|
}
|
||||||
Expr::String(s) => Ok(Value::String {
|
Expr::String(s) => Ok(Value::String {
|
||||||
val: s.clone(),
|
val: s.clone(),
|
||||||
span: expr.span,
|
span: expr.span,
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub enum FlatShape {
|
||||||
Operator,
|
Operator,
|
||||||
Signature,
|
Signature,
|
||||||
String,
|
String,
|
||||||
|
StringInterpolation,
|
||||||
Filepath,
|
Filepath,
|
||||||
GlobPattern,
|
GlobPattern,
|
||||||
Variable,
|
Variable,
|
||||||
|
@ -42,6 +43,7 @@ impl Display for FlatShape {
|
||||||
FlatShape::Operator => write!(f, "flatshape_operator"),
|
FlatShape::Operator => write!(f, "flatshape_operator"),
|
||||||
FlatShape::Signature => write!(f, "flatshape_signature"),
|
FlatShape::Signature => write!(f, "flatshape_signature"),
|
||||||
FlatShape::String => write!(f, "flatshape_string"),
|
FlatShape::String => write!(f, "flatshape_string"),
|
||||||
|
FlatShape::StringInterpolation => write!(f, "flatshape_string_interpolation"),
|
||||||
FlatShape::Filepath => write!(f, "flatshape_filepath"),
|
FlatShape::Filepath => write!(f, "flatshape_filepath"),
|
||||||
FlatShape::GlobPattern => write!(f, "flatshape_globpattern"),
|
FlatShape::GlobPattern => write!(f, "flatshape_globpattern"),
|
||||||
FlatShape::Variable => write!(f, "flatshape_variable"),
|
FlatShape::Variable => write!(f, "flatshape_variable"),
|
||||||
|
@ -215,6 +217,26 @@ pub fn flatten_expression(
|
||||||
}
|
}
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
Expr::StringInterpolation(exprs) => {
|
||||||
|
let mut output = vec![(
|
||||||
|
Span {
|
||||||
|
start: expr.span.start,
|
||||||
|
end: expr.span.start + 2,
|
||||||
|
},
|
||||||
|
FlatShape::StringInterpolation,
|
||||||
|
)];
|
||||||
|
for expr in exprs {
|
||||||
|
output.extend(flatten_expression(working_set, expr));
|
||||||
|
}
|
||||||
|
output.push((
|
||||||
|
Span {
|
||||||
|
start: expr.span.end - 1,
|
||||||
|
end: expr.span.end,
|
||||||
|
},
|
||||||
|
FlatShape::StringInterpolation,
|
||||||
|
));
|
||||||
|
output
|
||||||
|
}
|
||||||
Expr::Record(list) => {
|
Expr::Record(list) => {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
for l in list {
|
for l in list {
|
||||||
|
|
|
@ -1014,7 +1014,7 @@ pub(crate) fn parse_dollar_expr(
|
||||||
) -> (Expression, Option<ParseError>) {
|
) -> (Expression, Option<ParseError>) {
|
||||||
let contents = working_set.get_span_contents(span);
|
let contents = working_set.get_span_contents(span);
|
||||||
|
|
||||||
if contents.starts_with(b"$\"") {
|
if contents.starts_with(b"$\"") || contents.starts_with(b"$'") {
|
||||||
parse_string_interpolation(working_set, span)
|
parse_string_interpolation(working_set, span)
|
||||||
} else if let (expr, None) = parse_range(working_set, span) {
|
} else if let (expr, None) = parse_range(working_set, span) {
|
||||||
(expr, None)
|
(expr, None)
|
||||||
|
@ -1036,16 +1036,22 @@ pub fn parse_string_interpolation(
|
||||||
|
|
||||||
let contents = working_set.get_span_contents(span);
|
let contents = working_set.get_span_contents(span);
|
||||||
|
|
||||||
let start = if contents.starts_with(b"$\"") {
|
let (start, end) = if contents.starts_with(b"$\"") {
|
||||||
span.start + 2
|
let end = if contents.ends_with(b"\"") && contents.len() > 2 {
|
||||||
|
span.end - 1
|
||||||
|
} else {
|
||||||
|
span.end
|
||||||
|
};
|
||||||
|
(span.start + 2, end)
|
||||||
|
} else if contents.starts_with(b"$'") {
|
||||||
|
let end = if contents.ends_with(b"'") && contents.len() > 2 {
|
||||||
|
span.end - 1
|
||||||
|
} else {
|
||||||
|
span.end
|
||||||
|
};
|
||||||
|
(span.start + 2, end)
|
||||||
} else {
|
} else {
|
||||||
span.start
|
(span.start, span.end)
|
||||||
};
|
|
||||||
|
|
||||||
let end = if contents.ends_with(b"\"") && contents.len() > 2 {
|
|
||||||
span.end - 1
|
|
||||||
} else {
|
|
||||||
span.end
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let inner_span = Span { start, end };
|
let inner_span = Span { start, end };
|
||||||
|
@ -1134,30 +1140,15 @@ pub fn parse_string_interpolation(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(decl_id) = working_set.find_decl(b"build-string") {
|
(
|
||||||
(
|
Expression {
|
||||||
Expression {
|
expr: Expr::StringInterpolation(output),
|
||||||
expr: Expr::Call(Box::new(Call {
|
span,
|
||||||
head: Span {
|
ty: Type::String,
|
||||||
start: span.start,
|
custom_completion: None,
|
||||||
end: span.start + 2,
|
},
|
||||||
},
|
error,
|
||||||
named: vec![],
|
)
|
||||||
positional: output,
|
|
||||||
decl_id,
|
|
||||||
})),
|
|
||||||
span,
|
|
||||||
ty: Type::String,
|
|
||||||
custom_completion: None,
|
|
||||||
},
|
|
||||||
error,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
Expression::garbage(span),
|
|
||||||
Some(ParseError::UnknownCommand(span)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_variable_expr(
|
pub fn parse_variable_expr(
|
||||||
|
@ -3529,6 +3520,12 @@ pub fn find_captures_in_expr(
|
||||||
}
|
}
|
||||||
Expr::Signature(_) => {}
|
Expr::Signature(_) => {}
|
||||||
Expr::String(_) => {}
|
Expr::String(_) => {}
|
||||||
|
Expr::StringInterpolation(exprs) => {
|
||||||
|
for expr in exprs {
|
||||||
|
let result = find_captures_in_expr(working_set, expr, seen);
|
||||||
|
output.extend(&result);
|
||||||
|
}
|
||||||
|
}
|
||||||
Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => {
|
Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => {
|
||||||
let block = working_set.get_block(*block_id);
|
let block = working_set.get_block(*block_id);
|
||||||
let result = find_captures_in_block(working_set, block, seen);
|
let result = find_captures_in_block(working_set, block, seen);
|
||||||
|
|
|
@ -33,6 +33,7 @@ pub enum Expr {
|
||||||
FullCellPath(Box<FullCellPath>),
|
FullCellPath(Box<FullCellPath>),
|
||||||
ImportPattern(ImportPattern),
|
ImportPattern(ImportPattern),
|
||||||
Signature(Box<Signature>),
|
Signature(Box<Signature>),
|
||||||
|
StringInterpolation(Vec<Expression>),
|
||||||
Nothing,
|
Nothing,
|
||||||
Garbage,
|
Garbage,
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,6 +160,14 @@ impl Expression {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
Expr::StringInterpolation(items) => {
|
||||||
|
for i in items {
|
||||||
|
if i.has_in_variable(working_set) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
Expr::Operator(_) => false,
|
Expr::Operator(_) => false,
|
||||||
Expr::Range(left, middle, right, ..) => {
|
Expr::Range(left, middle, right, ..) => {
|
||||||
if let Some(left) = &left {
|
if let Some(left) = &left {
|
||||||
|
@ -321,6 +329,11 @@ impl Expression {
|
||||||
}
|
}
|
||||||
Expr::Signature(_) => {}
|
Expr::Signature(_) => {}
|
||||||
Expr::String(_) => {}
|
Expr::String(_) => {}
|
||||||
|
Expr::StringInterpolation(items) => {
|
||||||
|
for i in items {
|
||||||
|
i.replace_in_variable(working_set, new_var_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => {
|
Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => {
|
||||||
let block = working_set.get_block(*block_id);
|
let block = working_set.get_block(*block_id);
|
||||||
|
|
||||||
|
|
|
@ -79,3 +79,8 @@ fn string_in_valuestream() -> TestResult {
|
||||||
"true",
|
"true",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_tick_interpolation() -> TestResult {
|
||||||
|
run_test(r#"$'(3 + 4)'"#, "7")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue