mirror of
https://github.com/nushell/nushell
synced 2024-12-26 13:03:07 +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,
|
||||
))
|
||||
}
|
||||
FlatShape::StringInterpolation => {
|
||||
// nushell ???
|
||||
output.push((
|
||||
get_shape_color(shape.1.to_string(), &self.config),
|
||||
next_token,
|
||||
))
|
||||
}
|
||||
FlatShape::Filepath => output.push((
|
||||
// nushell Path
|
||||
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_signature" => Style::new().fg(Color::Green).bold(),
|
||||
"flatshape_string" => Style::new().fg(Color::Green),
|
||||
"flatshape_string_interpolation" => Style::new().fg(Color::Cyan).bold(),
|
||||
"flatshape_filepath" => Style::new().fg(Color::Cyan),
|
||||
"flatshape_globpattern" => Style::new().fg(Color::Cyan).bold(),
|
||||
"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::engine::{EngineState, Stack};
|
||||
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;
|
||||
|
@ -341,6 +342,23 @@ pub fn eval_expression(
|
|||
})
|
||||
}
|
||||
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 {
|
||||
val: s.clone(),
|
||||
span: expr.span,
|
||||
|
|
|
@ -19,6 +19,7 @@ pub enum FlatShape {
|
|||
Operator,
|
||||
Signature,
|
||||
String,
|
||||
StringInterpolation,
|
||||
Filepath,
|
||||
GlobPattern,
|
||||
Variable,
|
||||
|
@ -42,6 +43,7 @@ impl Display for FlatShape {
|
|||
FlatShape::Operator => write!(f, "flatshape_operator"),
|
||||
FlatShape::Signature => write!(f, "flatshape_signature"),
|
||||
FlatShape::String => write!(f, "flatshape_string"),
|
||||
FlatShape::StringInterpolation => write!(f, "flatshape_string_interpolation"),
|
||||
FlatShape::Filepath => write!(f, "flatshape_filepath"),
|
||||
FlatShape::GlobPattern => write!(f, "flatshape_globpattern"),
|
||||
FlatShape::Variable => write!(f, "flatshape_variable"),
|
||||
|
@ -215,6 +217,26 @@ pub fn flatten_expression(
|
|||
}
|
||||
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) => {
|
||||
let mut output = vec![];
|
||||
for l in list {
|
||||
|
|
|
@ -1014,7 +1014,7 @@ pub(crate) fn parse_dollar_expr(
|
|||
) -> (Expression, Option<ParseError>) {
|
||||
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)
|
||||
} else if let (expr, None) = parse_range(working_set, span) {
|
||||
(expr, None)
|
||||
|
@ -1036,16 +1036,22 @@ pub fn parse_string_interpolation(
|
|||
|
||||
let contents = working_set.get_span_contents(span);
|
||||
|
||||
let start = if contents.starts_with(b"$\"") {
|
||||
span.start + 2
|
||||
let (start, end) = 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 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 {
|
||||
span.start
|
||||
};
|
||||
|
||||
let end = if contents.ends_with(b"\"") && contents.len() > 2 {
|
||||
span.end - 1
|
||||
} else {
|
||||
span.end
|
||||
(span.start, span.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 {
|
||||
expr: Expr::Call(Box::new(Call {
|
||||
head: Span {
|
||||
start: span.start,
|
||||
end: span.start + 2,
|
||||
},
|
||||
named: vec![],
|
||||
positional: output,
|
||||
decl_id,
|
||||
})),
|
||||
span,
|
||||
ty: Type::String,
|
||||
custom_completion: None,
|
||||
},
|
||||
error,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
Expression::garbage(span),
|
||||
Some(ParseError::UnknownCommand(span)),
|
||||
)
|
||||
}
|
||||
(
|
||||
Expression {
|
||||
expr: Expr::StringInterpolation(output),
|
||||
span,
|
||||
ty: Type::String,
|
||||
custom_completion: None,
|
||||
},
|
||||
error,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn parse_variable_expr(
|
||||
|
@ -3529,6 +3520,12 @@ pub fn find_captures_in_expr(
|
|||
}
|
||||
Expr::Signature(_) => {}
|
||||
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) => {
|
||||
let block = working_set.get_block(*block_id);
|
||||
let result = find_captures_in_block(working_set, block, seen);
|
||||
|
|
|
@ -33,6 +33,7 @@ pub enum Expr {
|
|||
FullCellPath(Box<FullCellPath>),
|
||||
ImportPattern(ImportPattern),
|
||||
Signature(Box<Signature>),
|
||||
StringInterpolation(Vec<Expression>),
|
||||
Nothing,
|
||||
Garbage,
|
||||
}
|
||||
|
|
|
@ -160,6 +160,14 @@ impl Expression {
|
|||
}
|
||||
false
|
||||
}
|
||||
Expr::StringInterpolation(items) => {
|
||||
for i in items {
|
||||
if i.has_in_variable(working_set) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
Expr::Operator(_) => false,
|
||||
Expr::Range(left, middle, right, ..) => {
|
||||
if let Some(left) = &left {
|
||||
|
@ -321,6 +329,11 @@ impl Expression {
|
|||
}
|
||||
Expr::Signature(_) => {}
|
||||
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) => {
|
||||
let block = working_set.get_block(*block_id);
|
||||
|
||||
|
|
|
@ -79,3 +79,8 @@ fn string_in_valuestream() -> TestResult {
|
|||
"true",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_tick_interpolation() -> TestResult {
|
||||
run_test(r#"$'(3 + 4)'"#, "7")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue