mirror of
https://github.com/nushell/nushell
synced 2024-12-26 04:53:09 +00:00
Add the ability to remove and list aliases (#3879)
* Add the ability to remove and list aliases * Fix failing unit tests * Add a test to check unalias shadowing blocks
This commit is contained in:
parent
2b7390c2a1
commit
9bd408449e
9 changed files with 110 additions and 16 deletions
|
@ -2,7 +2,7 @@ use crate::prelude::*;
|
|||
use nu_engine::WholeStreamCommand;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
||||
|
||||
pub struct Alias;
|
||||
|
||||
|
@ -35,6 +35,18 @@ impl WholeStreamCommand for Alias {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn alias(_: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn alias(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
// TODO: is there a better way of checking whether no arguments were passed?
|
||||
if args.nth(0).is_none() {
|
||||
let aliases = UntaggedValue::string(
|
||||
&args
|
||||
.scope()
|
||||
.get_aliases()
|
||||
.iter()
|
||||
.map(|val| format!("{} = '{}'", val.0, val.1.iter().map(|x| &x.item).join(" ")))
|
||||
.join("\n"),
|
||||
);
|
||||
return Ok(OutputStream::one(aliases));
|
||||
}
|
||||
Ok(OutputStream::empty())
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ mod nu_plugin;
|
|||
mod nu_signature;
|
||||
mod source;
|
||||
mod tags;
|
||||
mod unalias;
|
||||
mod version;
|
||||
|
||||
pub use self::nu_plugin::SubCommand as NuPlugin;
|
||||
|
@ -32,4 +33,5 @@ pub use ignore::Ignore;
|
|||
pub use let_::Let;
|
||||
pub use source::Source;
|
||||
pub use tags::Tags;
|
||||
pub use unalias::Unalias;
|
||||
pub use version::{version, Version};
|
||||
|
|
37
crates/nu-command/src/commands/core_commands/unalias.rs
Normal file
37
crates/nu-command/src/commands/core_commands/unalias.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
|
||||
pub struct Unalias;
|
||||
|
||||
impl WholeStreamCommand for Unalias {
|
||||
fn name(&self) -> &str {
|
||||
"unalias"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("unalias").required("name", SyntaxShape::String, "the name of the alias")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Removes an alias"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
unalias(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Remove the 'v' alias",
|
||||
example: "unalias v",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unalias(_: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(OutputStream::empty())
|
||||
}
|
|
@ -18,6 +18,7 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
|||
whole_stream_command(Def),
|
||||
whole_stream_command(Source),
|
||||
whole_stream_command(Alias),
|
||||
whole_stream_command(Unalias),
|
||||
whole_stream_command(Ignore),
|
||||
// System/file operations
|
||||
whole_stream_command(Exec),
|
||||
|
|
|
@ -317,6 +317,10 @@ mod tests {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn remove_alias(&self, _name: &str) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn add_definition(&self, _block: Arc<Block>) {}
|
||||
|
||||
fn get_definitions(&self) -> Vec<Arc<Block>> {
|
||||
|
|
|
@ -407,6 +407,12 @@ impl ParserScope for Scope {
|
|||
}
|
||||
}
|
||||
|
||||
fn remove_alias(&self, name: &str) {
|
||||
for frame in self.frames.lock().iter_mut().rev() {
|
||||
frame.aliases.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
fn enter_scope(&self) {
|
||||
self.frames.lock().push(ScopeFrame::new());
|
||||
}
|
||||
|
|
|
@ -1902,7 +1902,7 @@ fn parse_call(
|
|||
)),
|
||||
);
|
||||
}
|
||||
} else if lite_cmd.parts[0].item == "alias" {
|
||||
} else if lite_cmd.parts[0].item == "alias" || lite_cmd.parts[0].item == "unalias" {
|
||||
let error = parse_alias(&lite_cmd, scope);
|
||||
if error.is_none() {
|
||||
return (Some(ClassifiedCommand::Internal(internal_command)), None);
|
||||
|
@ -2048,26 +2048,41 @@ fn expand_shorthand_forms(
|
|||
}
|
||||
|
||||
fn parse_alias(call: &LiteCommand, scope: &dyn ParserScope) -> Option<ParseError> {
|
||||
if call.parts.len() == 2 && (call.parts[1].item == "--help" || (call.parts[1].item == "-h")) {
|
||||
return None;
|
||||
}
|
||||
if call.parts[0].item == "alias" {
|
||||
if (call.parts.len() == 1)
|
||||
|| (call.parts.len() == 2
|
||||
&& (call.parts[1].item == "--help" || (call.parts[1].item == "-h")))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
if call.parts.len() < 4 {
|
||||
return Some(ParseError::mismatch("alias", call.parts[0].clone()));
|
||||
}
|
||||
|
||||
if call.parts.len() < 4 {
|
||||
return Some(ParseError::mismatch("alias", call.parts[0].clone()));
|
||||
}
|
||||
if call.parts[0].item != "alias" {
|
||||
return Some(ParseError::mismatch("alias", call.parts[0].clone()));
|
||||
}
|
||||
|
||||
if call.parts[0].item != "alias" {
|
||||
return Some(ParseError::mismatch("alias", call.parts[0].clone()));
|
||||
}
|
||||
|
||||
if call.parts[2].item != "=" {
|
||||
return Some(ParseError::mismatch("=", call.parts[2].clone()));
|
||||
if call.parts[2].item != "=" {
|
||||
return Some(ParseError::mismatch("=", call.parts[2].clone()));
|
||||
}
|
||||
} else {
|
||||
// unalias
|
||||
if call.parts.len() != 2 {
|
||||
return Some(ParseError::mismatch("unalias", call.parts[0].clone()));
|
||||
}
|
||||
}
|
||||
|
||||
let name = call.parts[1].item.clone();
|
||||
let args: Vec<_> = call.parts.iter().skip(3).cloned().collect();
|
||||
|
||||
scope.add_alias(&name, args);
|
||||
match call.parts[0].item.as_str() {
|
||||
"alias" => scope.add_alias(&name, args),
|
||||
"unalias" => {
|
||||
scope.remove_alias(&name);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
None
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ pub trait ParserScope: Debug {
|
|||
|
||||
fn get_alias(&self, name: &str) -> Option<Vec<Spanned<String>>>;
|
||||
|
||||
fn remove_alias(&self, name: &str);
|
||||
|
||||
fn add_alias(&self, name: &str, replacement: Vec<Spanned<String>>);
|
||||
|
||||
fn enter_scope(&self);
|
||||
|
|
|
@ -1145,6 +1145,21 @@ fn nothing_string_2() {
|
|||
assert_eq!(actual.out, "true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unalias_shadowing() {
|
||||
let actual = nu!(
|
||||
cwd: ".", pipeline(
|
||||
r#"
|
||||
alias ll = ls -l
|
||||
let xyz = { ll -a }
|
||||
unalias ll
|
||||
do $xyz
|
||||
"#)
|
||||
);
|
||||
|
||||
assert_eq!(actual.out, "");
|
||||
}
|
||||
|
||||
mod parse {
|
||||
use nu_test_support::nu;
|
||||
|
||||
|
|
Loading…
Reference in a new issue