mirror of
https://github.com/nushell/nushell.git
synced 2025-02-18 11:31:14 +01:00
Add support for var/string interp for external names (#729)
This commit is contained in:
parent
d0f9943709
commit
82d90f4930
@ -260,7 +260,18 @@ impl<'call> ExternalCommand<'call> {
|
|||||||
|
|
||||||
/// Spawn a command without shelling out to an external shell
|
/// Spawn a command without shelling out to an external shell
|
||||||
fn spawn_simple_command(&self, cwd: &str) -> std::process::Command {
|
fn spawn_simple_command(&self, cwd: &str) -> std::process::Command {
|
||||||
let mut process = std::process::Command::new(&self.name.item);
|
let head = trim_enclosing_quotes(&self.name.item);
|
||||||
|
let head = if head.starts_with('~') || head.starts_with("..") {
|
||||||
|
nu_path::expand_path_with(head, cwd)
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string()
|
||||||
|
} else {
|
||||||
|
head
|
||||||
|
};
|
||||||
|
|
||||||
|
let head = head.replace("\\", "\\\\");
|
||||||
|
|
||||||
|
let mut process = std::process::Command::new(&head);
|
||||||
|
|
||||||
for arg in &self.args {
|
for arg in &self.args {
|
||||||
let arg = trim_enclosing_quotes(arg);
|
let arg = trim_enclosing_quotes(arg);
|
||||||
|
@ -6,7 +6,7 @@ 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::{
|
||||||
IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Range, ShellError, Span,
|
IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Range, ShellError, Span,
|
||||||
Spanned, Type, Unit, Value, VarId, ENV_VARIABLE_ID,
|
Spanned, Unit, Value, VarId, ENV_VARIABLE_ID,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{current_dir_str, get_full_help};
|
use crate::{current_dir_str, get_full_help};
|
||||||
@ -139,26 +139,20 @@ fn eval_call(
|
|||||||
fn eval_external(
|
fn eval_external(
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
name: &str,
|
head: &Expression,
|
||||||
name_span: &Span,
|
|
||||||
args: &[Expression],
|
args: &[Expression],
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
last_expression: bool,
|
last_expression: bool,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let decl_id = engine_state
|
let decl_id = engine_state
|
||||||
.find_decl("run_external".as_bytes())
|
.find_decl("run_external".as_bytes())
|
||||||
.ok_or_else(|| ShellError::ExternalNotSupported(*name_span))?;
|
.ok_or(ShellError::ExternalNotSupported(head.span))?;
|
||||||
|
|
||||||
let command = engine_state.get_decl(decl_id);
|
let command = engine_state.get_decl(decl_id);
|
||||||
|
|
||||||
let mut call = Call::new();
|
let mut call = Call::new();
|
||||||
|
|
||||||
call.positional.push(Expression {
|
call.positional.push(head.clone());
|
||||||
expr: Expr::String(name.trim_start_matches('^').to_string()),
|
|
||||||
span: *name_span,
|
|
||||||
ty: Type::String,
|
|
||||||
custom_completion: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
call.positional.push(arg.clone())
|
call.positional.push(arg.clone())
|
||||||
@ -168,7 +162,7 @@ fn eval_external(
|
|||||||
call.named.push((
|
call.named.push((
|
||||||
Spanned {
|
Spanned {
|
||||||
item: "last_expression".into(),
|
item: "last_expression".into(),
|
||||||
span: *name_span,
|
span: head.span,
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
))
|
))
|
||||||
@ -246,18 +240,18 @@ pub fn eval_expression(
|
|||||||
.into_value(call.head),
|
.into_value(call.head),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Expr::ExternalCall(name, span, args) => {
|
Expr::ExternalCall(head, args) => {
|
||||||
|
let span = head.span;
|
||||||
// FIXME: protect this collect with ctrl-c
|
// FIXME: protect this collect with ctrl-c
|
||||||
Ok(eval_external(
|
Ok(eval_external(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
name,
|
head,
|
||||||
span,
|
|
||||||
args,
|
args,
|
||||||
PipelineData::new(*span),
|
PipelineData::new(span),
|
||||||
false,
|
false,
|
||||||
)?
|
)?
|
||||||
.into_value(*span))
|
.into_value(span))
|
||||||
}
|
}
|
||||||
Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }),
|
Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }),
|
||||||
Expr::BinaryOp(lhs, op, rhs) => {
|
Expr::BinaryOp(lhs, op, rhs) => {
|
||||||
@ -413,14 +407,13 @@ pub fn eval_block(
|
|||||||
input = eval_call(engine_state, stack, call, input)?;
|
input = eval_call(engine_state, stack, call, input)?;
|
||||||
}
|
}
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::ExternalCall(name, name_span, args),
|
expr: Expr::ExternalCall(head, args),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
input = eval_external(
|
input = eval_external(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
name,
|
head,
|
||||||
name_span,
|
|
||||||
args,
|
args,
|
||||||
input,
|
input,
|
||||||
i == pipeline.expressions.len() - 1,
|
i == pipeline.expressions.len() - 1,
|
||||||
@ -511,18 +504,10 @@ pub fn eval_subexpression(
|
|||||||
input = eval_call(engine_state, stack, call, input)?;
|
input = eval_call(engine_state, stack, call, input)?;
|
||||||
}
|
}
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::ExternalCall(name, name_span, args),
|
expr: Expr::ExternalCall(head, args),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
input = eval_external(
|
input = eval_external(engine_state, stack, head, args, input, false)?;
|
||||||
engine_state,
|
|
||||||
stack,
|
|
||||||
name,
|
|
||||||
name_span,
|
|
||||||
args,
|
|
||||||
input,
|
|
||||||
false,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
elem => {
|
elem => {
|
||||||
|
@ -156,8 +156,21 @@ pub fn flatten_expression(
|
|||||||
output.extend(args);
|
output.extend(args);
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
Expr::ExternalCall(_, name_span, args) => {
|
Expr::ExternalCall(head, args) => {
|
||||||
let mut output = vec![(*name_span, FlatShape::External)];
|
let mut output = vec![];
|
||||||
|
|
||||||
|
match **head {
|
||||||
|
Expression {
|
||||||
|
expr: Expr::String(..),
|
||||||
|
span,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
output.push((span, FlatShape::External));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
output.extend(flatten_expression(working_set, head));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
//output.push((*arg, FlatShape::ExternalArg));
|
//output.push((*arg, FlatShape::ExternalArg));
|
||||||
|
@ -191,19 +191,35 @@ pub fn parse_external_call(
|
|||||||
spans: &[Span],
|
spans: &[Span],
|
||||||
) -> (Expression, Option<ParseError>) {
|
) -> (Expression, Option<ParseError>) {
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
let name_span = spans[0];
|
|
||||||
let name = String::from_utf8_lossy(working_set.get_span_contents(name_span)).to_string();
|
let head_contents = working_set.get_span_contents(spans[0]);
|
||||||
let cwd = working_set.get_cwd();
|
|
||||||
let name = if name.starts_with('.') || name.starts_with('~') {
|
let head_span = if head_contents.starts_with(b"^") {
|
||||||
nu_path::expand_path_with(name, cwd)
|
Span {
|
||||||
.to_string_lossy()
|
start: spans[0].start + 1,
|
||||||
.to_string()
|
end: spans[0].end,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
name
|
spans[0]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let head_contents = working_set.get_span_contents(head_span);
|
||||||
|
|
||||||
let mut error = None;
|
let mut error = None;
|
||||||
|
|
||||||
|
let head = if head_contents.starts_with(b"$") || head_contents.starts_with(b"(") {
|
||||||
|
let (arg, err) = parse_expression(working_set, &[head_span], true);
|
||||||
|
error = error.or(err);
|
||||||
|
Box::new(arg)
|
||||||
|
} else {
|
||||||
|
Box::new(Expression {
|
||||||
|
expr: Expr::String(String::from_utf8_lossy(head_contents).to_string()),
|
||||||
|
span: head_span,
|
||||||
|
ty: Type::String,
|
||||||
|
custom_completion: None,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
for span in &spans[1..] {
|
for span in &spans[1..] {
|
||||||
let contents = working_set.get_span_contents(*span);
|
let contents = working_set.get_span_contents(*span);
|
||||||
|
|
||||||
@ -222,7 +238,7 @@ pub fn parse_external_call(
|
|||||||
}
|
}
|
||||||
(
|
(
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::ExternalCall(name, name_span, args),
|
expr: Expr::ExternalCall(head, args),
|
||||||
span: span(spans),
|
span: span(spans),
|
||||||
ty: Type::Unknown,
|
ty: Type::Unknown,
|
||||||
custom_completion: None,
|
custom_completion: None,
|
||||||
@ -3684,7 +3700,10 @@ pub fn find_captures_in_expr(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::CellPath(_) => {}
|
Expr::CellPath(_) => {}
|
||||||
Expr::ExternalCall(_, _, exprs) => {
|
Expr::ExternalCall(head, exprs) => {
|
||||||
|
let result = find_captures_in_expr(working_set, head, seen);
|
||||||
|
output.extend(&result);
|
||||||
|
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
let result = find_captures_in_expr(working_set, expr, seen);
|
let result = find_captures_in_expr(working_set, expr, seen);
|
||||||
output.extend(&result);
|
output.extend(&result);
|
||||||
|
@ -15,7 +15,7 @@ pub enum Expr {
|
|||||||
Var(VarId),
|
Var(VarId),
|
||||||
VarDecl(VarId),
|
VarDecl(VarId),
|
||||||
Call(Box<Call>),
|
Call(Box<Call>),
|
||||||
ExternalCall(String, Span, Vec<Expression>),
|
ExternalCall(Box<Expression>, Vec<Expression>),
|
||||||
Operator(Operator),
|
Operator(Operator),
|
||||||
RowCondition(BlockId),
|
RowCondition(BlockId),
|
||||||
BinaryOp(Box<Expression>, Box<Expression>, Box<Expression>), //lhs, op, rhs
|
BinaryOp(Box<Expression>, Box<Expression>, Box<Expression>), //lhs, op, rhs
|
||||||
|
@ -142,7 +142,10 @@ impl Expression {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
Expr::CellPath(_) => false,
|
Expr::CellPath(_) => false,
|
||||||
Expr::ExternalCall(_, _, args) => {
|
Expr::ExternalCall(head, args) => {
|
||||||
|
if head.has_in_variable(working_set) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg.has_in_variable(working_set) {
|
if arg.has_in_variable(working_set) {
|
||||||
return true;
|
return true;
|
||||||
@ -298,7 +301,8 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::CellPath(_) => {}
|
Expr::CellPath(_) => {}
|
||||||
Expr::ExternalCall(_, _, args) => {
|
Expr::ExternalCall(head, args) => {
|
||||||
|
head.replace_in_variable(working_set, new_var_id);
|
||||||
for arg in args {
|
for arg in args {
|
||||||
arg.replace_in_variable(working_set, new_var_id)
|
arg.replace_in_variable(working_set, new_var_id)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user