nushell/crates/nu-command/src/core_commands/hide.rs
Jakub Žádník 328f7e92a0
Hide alias (#4432)
* Add alias interning

Now, AliasId is used to reference aliases stored in EngineState, similar
to decls, blocks, etc.

* Fix wrong message

* Fix using decl instead of alias

* Extend also alias id visibility

* Merge also aliases from delta

* Add alias hiding code

Does not work yet but passes tests at least.

* Fix wrong alias lookup and visibility appending

* Add hide alias tests

* Fmt & Clippy

* Fix random clippy warnings in "which" command
2022-02-12 11:50:37 +02:00

120 lines
4.3 KiB
Rust

use nu_protocol::ast::{Call, Expr, Expression, ImportPatternMember};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, PipelineData, ShellError, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Hide;
impl Command for Hide {
fn name(&self) -> &str {
"hide"
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("hide")
.required("pattern", SyntaxShape::ImportPattern, "import pattern")
.category(Category::Core)
}
fn usage(&self) -> &str {
"Hide symbols in the current scope"
}
fn extra_usage(&self) -> &str {
"Symbols are hidden by priority: First aliases, then custom commands, then environment variables."
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let import_pattern = if let Some(Expression {
expr: Expr::ImportPattern(pat),
..
}) = call.positional.get(0)
{
pat
} else {
return Err(ShellError::SpannedLabeledError(
"Unexpected import".into(),
"import pattern not supported".into(),
call.head,
));
};
let head_name_str = if let Ok(s) = String::from_utf8(import_pattern.head.name.clone()) {
s
} else {
return Err(ShellError::NonUtf8(import_pattern.head.span));
};
if let Some(overlay_id) = engine_state.find_overlay(&import_pattern.head.name) {
// The first word is a module
let overlay = engine_state.get_overlay(overlay_id);
let env_vars_to_hide = if import_pattern.members.is_empty() {
overlay.env_vars_with_head(&import_pattern.head.name)
} else {
match &import_pattern.members[0] {
ImportPatternMember::Glob { .. } => overlay.env_vars(),
ImportPatternMember::Name { name, span } => {
let mut output = vec![];
if let Some((name, id)) =
overlay.env_var_with_head(name, &import_pattern.head.name)
{
output.push((name, id));
} else if !(overlay.has_alias(name) || overlay.has_decl(name)) {
return Err(ShellError::EnvVarNotFoundAtRuntime(
String::from_utf8_lossy(name).into(),
*span,
));
}
output
}
ImportPatternMember::List { names } => {
let mut output = vec![];
for (name, span) in names {
if let Some((name, id)) =
overlay.env_var_with_head(name, &import_pattern.head.name)
{
output.push((name, id));
} else if !(overlay.has_alias(name) || overlay.has_decl(name)) {
return Err(ShellError::EnvVarNotFoundAtRuntime(
String::from_utf8_lossy(name).into(),
*span,
));
}
}
output
}
}
};
for (name, _) in env_vars_to_hide {
let name = if let Ok(s) = String::from_utf8(name.clone()) {
s
} else {
return Err(ShellError::NonUtf8(import_pattern.span()));
};
if stack.remove_env_var(engine_state, &name).is_none() {
return Err(ShellError::NotFound(call.positional[0].span));
}
}
} else if !import_pattern.hidden.contains(&import_pattern.head.name)
&& stack.remove_env_var(engine_state, &head_name_str).is_none()
{
return Err(ShellError::NotFound(call.positional[0].span));
}
Ok(PipelineData::new(call.head))
}
}