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:
soumil-07 2021-08-17 19:26:35 +05:30 committed by GitHub
parent 2b7390c2a1
commit 9bd408449e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 110 additions and 16 deletions

View File

@ -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())
}

View File

@ -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};

View 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())
}

View File

@ -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),

View File

@ -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>> {

View File

@ -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());
}

View File

@ -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
}

View File

@ -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);

View File

@ -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;