mirror of
https://github.com/nushell/nushell
synced 2024-12-26 13:03:07 +00:00
Fix reporting of which
and $nu.scope
(#4836)
* Refactor & fix which Instead of fetching all definitions / aliases, only show the one that is visible. * Fix $nu.scope to show only visible definitions * Add missing tests file; Rename one which test
This commit is contained in:
parent
c023d4111a
commit
72daf8c64e
6 changed files with 258 additions and 131 deletions
|
@ -51,8 +51,8 @@ impl Command for Which {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shortcuts for creating an entry to the output table
|
// Shortcut for creating an entry to the output table
|
||||||
fn entry(arg: impl Into<String>, path: Value, builtin: bool, span: Span) -> Value {
|
fn entry(arg: impl Into<String>, path: impl Into<String>, builtin: bool, span: Span) -> Value {
|
||||||
let mut cols = vec![];
|
let mut cols = vec![];
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
|
|
||||||
|
@ -60,56 +60,46 @@ fn entry(arg: impl Into<String>, path: Value, builtin: bool, span: Span) -> Valu
|
||||||
vals.push(Value::string(arg.into(), span));
|
vals.push(Value::string(arg.into(), span));
|
||||||
|
|
||||||
cols.push("path".to_string());
|
cols.push("path".to_string());
|
||||||
vals.push(path);
|
vals.push(Value::string(path.into(), span));
|
||||||
|
|
||||||
cols.push("builtin".to_string());
|
cols.push("built-in".to_string());
|
||||||
vals.push(Value::Bool { val: builtin, span });
|
vals.push(Value::Bool { val: builtin, span });
|
||||||
|
|
||||||
Value::Record { cols, vals, span }
|
Value::Record { cols, vals, span }
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! create_entry {
|
fn get_entry_in_aliases(engine_state: &EngineState, name: &str, span: Span) -> Option<Value> {
|
||||||
($arg:expr, $path:expr, $span:expr, $is_builtin:expr) => {
|
if let Some(alias_id) = engine_state.find_alias(name.as_bytes()) {
|
||||||
entry(
|
let alias = engine_state.get_alias(alias_id);
|
||||||
$arg.clone(),
|
let alias_str = alias
|
||||||
Value::string($path.to_string(), $span),
|
.iter()
|
||||||
$is_builtin,
|
.map(|alias_span| String::from_utf8_lossy(engine_state.get_span_contents(alias_span)))
|
||||||
$span,
|
.join(" ");
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_entries_in_aliases(engine_state: &EngineState, name: &str, span: Span) -> Vec<Value> {
|
trace!("Found alias: {}", name);
|
||||||
let aliases = engine_state.find_aliases(name);
|
|
||||||
|
|
||||||
let aliases = aliases
|
Some(entry(
|
||||||
.into_iter()
|
name,
|
||||||
.map(|spans| {
|
format!("Nushell alias: {}", alias_str),
|
||||||
spans
|
false,
|
||||||
.iter()
|
span,
|
||||||
.map(|span| {
|
))
|
||||||
String::from_utf8_lossy(engine_state.get_span_contents(span)).to_string()
|
} else {
|
||||||
})
|
None
|
||||||
.join(" ")
|
}
|
||||||
})
|
|
||||||
.map(|alias| create_entry!(name, format!("Nushell alias: {}", alias), span, false))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
trace!("Found {} aliases", aliases.len());
|
|
||||||
aliases
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_entries_in_custom_command(engine_state: &EngineState, name: &str, span: Span) -> Vec<Value> {
|
|
||||||
let custom_commands = engine_state.find_custom_commands(name);
|
|
||||||
|
|
||||||
custom_commands
|
|
||||||
.into_iter()
|
|
||||||
.map(|_| create_entry!(name, "Nushell custom command", span, false))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_entry_in_commands(engine_state: &EngineState, name: &str, span: Span) -> Option<Value> {
|
fn get_entry_in_commands(engine_state: &EngineState, name: &str, span: Span) -> Option<Value> {
|
||||||
if engine_state.find_decl(name.as_bytes()).is_some() {
|
if let Some(decl_id) = engine_state.find_decl(name.as_bytes()) {
|
||||||
Some(create_entry!(name, "Nushell built-in command", span, true))
|
let (msg, is_builtin) = if engine_state.get_decl(decl_id).get_block_id().is_some() {
|
||||||
|
("Nushell custom command", false)
|
||||||
|
} else {
|
||||||
|
("Nushell built-in command", true)
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!("Found command: {}", name);
|
||||||
|
|
||||||
|
Some(entry(name, msg, is_builtin, span))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -123,30 +113,21 @@ fn get_entries_in_nu(
|
||||||
) -> Vec<Value> {
|
) -> Vec<Value> {
|
||||||
let mut all_entries = vec![];
|
let mut all_entries = vec![];
|
||||||
|
|
||||||
all_entries.extend(get_entries_in_aliases(engine_state, name, span));
|
if let Some(ent) = get_entry_in_aliases(engine_state, name, span) {
|
||||||
|
all_entries.push(ent);
|
||||||
|
}
|
||||||
|
|
||||||
if !all_entries.is_empty() && skip_after_first_found {
|
if !all_entries.is_empty() && skip_after_first_found {
|
||||||
return all_entries;
|
return all_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
all_entries.extend(get_entries_in_custom_command(engine_state, name, span));
|
if let Some(ent) = get_entry_in_commands(engine_state, name, span) {
|
||||||
if !all_entries.is_empty() && skip_after_first_found {
|
all_entries.push(ent);
|
||||||
return all_entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(entry) = get_entry_in_commands(engine_state, name, span) {
|
|
||||||
all_entries.push(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
all_entries
|
all_entries
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
macro_rules! entry_path {
|
|
||||||
($arg:expr, $path:expr, $span:expr) => {
|
|
||||||
entry($arg.clone(), Value::string($path, $span), false, $span)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "which")]
|
#[cfg(feature = "which")]
|
||||||
fn get_first_entry_in_path(
|
fn get_first_entry_in_path(
|
||||||
item: &str,
|
item: &str,
|
||||||
|
@ -155,7 +136,7 @@ fn get_first_entry_in_path(
|
||||||
paths: impl AsRef<OsStr>,
|
paths: impl AsRef<OsStr>,
|
||||||
) -> Option<Value> {
|
) -> Option<Value> {
|
||||||
which::which_in(item, Some(paths), cwd)
|
which::which_in(item, Some(paths), cwd)
|
||||||
.map(|path| entry_path!(item, path.to_string_lossy().to_string(), span))
|
.map(|path| entry(item, path.to_string_lossy().to_string(), false, span))
|
||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,11 +159,12 @@ fn get_all_entries_in_path(
|
||||||
) -> Vec<Value> {
|
) -> Vec<Value> {
|
||||||
which::which_in_all(&item, Some(paths), cwd)
|
which::which_in_all(&item, Some(paths), cwd)
|
||||||
.map(|iter| {
|
.map(|iter| {
|
||||||
iter.map(|path| entry_path!(item, path.to_string_lossy().to_string(), span))
|
iter.map(|path| entry(item, path.to_string_lossy().to_string(), false, span))
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "which"))]
|
#[cfg(not(feature = "which"))]
|
||||||
fn get_all_entries_in_path(
|
fn get_all_entries_in_path(
|
||||||
_item: &str,
|
_item: &str,
|
||||||
|
|
|
@ -58,38 +58,69 @@ fn multiple_reports_for_alias_def_custom() {
|
||||||
// See: parse_definition, line 2187 for reference.
|
// See: parse_definition, line 2187 for reference.
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn multiple_reports_of_multiple_alias() {
|
fn correctly_report_of_shadowed_alias() {
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: ".",
|
cwd: ".",
|
||||||
"alias xaz = echo alias1; def helper [] {alias xaz = echo alias2; which -a xaz}; helper | length"
|
r#"alias xaz = echo alias1
|
||||||
|
def helper [] {
|
||||||
|
alias xaz = echo alias2
|
||||||
|
which -a xaz
|
||||||
|
}
|
||||||
|
helper | get path | str contains alias2"#
|
||||||
);
|
);
|
||||||
|
|
||||||
let length: i32 = actual.out.parse().unwrap();
|
assert_eq!(actual.out, "true");
|
||||||
assert_eq!(length, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multiple_reports_of_multiple_defs() {
|
fn one_report_of_multiple_defs() {
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: ".",
|
cwd: ".",
|
||||||
"def xaz [] {echo def1}; def helper [] { def xaz [] { echo def2 }; which -a xaz }; helper | length"
|
r#"def xaz [] { echo def1 }
|
||||||
|
def helper [] {
|
||||||
|
def xaz [] { echo def2 }
|
||||||
|
which -a xaz
|
||||||
|
}
|
||||||
|
helper | length"#
|
||||||
);
|
);
|
||||||
|
|
||||||
let length: i32 = actual.out.parse().unwrap();
|
let length: i32 = actual.out.parse().unwrap();
|
||||||
assert_eq!(length, 2);
|
assert_eq!(length, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fails due to ParserScope::add_definition
|
|
||||||
// frame.custom_commands.insert(name.clone(), block.clone());
|
|
||||||
// frame.commands.insert(name, whole_stream_command(block));
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn def_only_seen_once() {
|
fn def_only_seen_once() {
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: ".",
|
cwd: ".",
|
||||||
"def xaz [] {echo def1}; which -a xaz | length"
|
"def xaz [] {echo def1}; which -a xaz | length"
|
||||||
);
|
);
|
||||||
//length is 2. One custom_command (def) one built in ("wrongly" added)
|
|
||||||
let length: i32 = actual.out.parse().unwrap();
|
let length: i32 = actual.out.parse().unwrap();
|
||||||
assert_eq!(length, 1);
|
assert_eq!(length, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn do_not_show_hidden_aliases() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".",
|
||||||
|
r#"alias foo = echo foo
|
||||||
|
hide foo
|
||||||
|
which foo | length"#
|
||||||
|
);
|
||||||
|
|
||||||
|
let length: i32 = actual.out.parse().unwrap();
|
||||||
|
assert_eq!(length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn do_not_show_hidden_commands() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".",
|
||||||
|
r#"def foo [] { echo foo }
|
||||||
|
hide foo
|
||||||
|
which foo | length"#
|
||||||
|
);
|
||||||
|
|
||||||
|
let length: i32 = actual.out.parse().unwrap();
|
||||||
|
assert_eq!(length, 0);
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::io::Write;
|
||||||
|
|
||||||
use nu_path::expand_path_with;
|
use nu_path::expand_path_with;
|
||||||
use nu_protocol::ast::{Block, Call, Expr, Expression, Operator};
|
use nu_protocol::ast::{Block, Call, Expr, Expression, Operator};
|
||||||
use nu_protocol::engine::{EngineState, Stack};
|
use nu_protocol::engine::{EngineState, Stack, Visibility};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Range, ShellError, Span,
|
IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Range, ShellError, Span,
|
||||||
Spanned, Unit, Value, VarId, ENV_VARIABLE_ID,
|
Spanned, Unit, Value, VarId, ENV_VARIABLE_ID,
|
||||||
|
@ -752,41 +752,55 @@ pub fn create_scope(
|
||||||
let mut output_vals = vec![];
|
let mut output_vals = vec![];
|
||||||
|
|
||||||
let mut vars = vec![];
|
let mut vars = vec![];
|
||||||
|
|
||||||
let mut commands = vec![];
|
let mut commands = vec![];
|
||||||
let mut aliases = vec![];
|
let mut aliases = vec![];
|
||||||
let mut overlays = vec![];
|
let mut overlays = vec![];
|
||||||
|
|
||||||
|
let mut vars_map = HashMap::new();
|
||||||
|
let mut commands_map = HashMap::new();
|
||||||
|
let mut aliases_map = HashMap::new();
|
||||||
|
let mut overlays_map = HashMap::new();
|
||||||
|
let mut visibility = Visibility::new();
|
||||||
|
|
||||||
for frame in &engine_state.scope {
|
for frame in &engine_state.scope {
|
||||||
for var in &frame.vars {
|
vars_map.extend(&frame.vars);
|
||||||
let var_name = Value::string(String::from_utf8_lossy(var.0).to_string(), span);
|
commands_map.extend(&frame.decls);
|
||||||
|
aliases_map.extend(&frame.aliases);
|
||||||
|
overlays_map.extend(&frame.overlays);
|
||||||
|
|
||||||
let var_type = Value::string(engine_state.get_var(*var.1).ty.to_string(), span);
|
visibility.merge_with(frame.visibility.clone());
|
||||||
|
}
|
||||||
|
|
||||||
let var_value = if let Ok(val) = stack.get_var(*var.1, span) {
|
for var in vars_map {
|
||||||
val
|
let var_name = Value::string(String::from_utf8_lossy(var.0).to_string(), span);
|
||||||
} else {
|
|
||||||
Value::nothing(span)
|
|
||||||
};
|
|
||||||
|
|
||||||
vars.push(Value::Record {
|
let var_type = Value::string(engine_state.get_var(*var.1).ty.to_string(), span);
|
||||||
cols: vec!["name".to_string(), "type".to_string(), "value".to_string()],
|
|
||||||
vals: vec![var_name, var_type, var_value],
|
|
||||||
span,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for command in &frame.decls {
|
let var_value = if let Ok(val) = stack.get_var(*var.1, span) {
|
||||||
|
val
|
||||||
|
} else {
|
||||||
|
Value::nothing(span)
|
||||||
|
};
|
||||||
|
|
||||||
|
vars.push(Value::Record {
|
||||||
|
cols: vec!["name".to_string(), "type".to_string(), "value".to_string()],
|
||||||
|
vals: vec![var_name, var_type, var_value],
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for (command_name, decl_id) in commands_map {
|
||||||
|
if visibility.is_decl_id_visible(decl_id) {
|
||||||
let mut cols = vec![];
|
let mut cols = vec![];
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
|
|
||||||
cols.push("command".into());
|
cols.push("command".into());
|
||||||
vals.push(Value::String {
|
vals.push(Value::String {
|
||||||
val: String::from_utf8_lossy(command.0).to_string(),
|
val: String::from_utf8_lossy(command_name).to_string(),
|
||||||
span,
|
span,
|
||||||
});
|
});
|
||||||
|
|
||||||
let decl = engine_state.get_decl(*command.1);
|
let decl = engine_state.get_decl(*decl_id);
|
||||||
let signature = decl.signature();
|
let signature = decl.signature();
|
||||||
cols.push("category".to_string());
|
cols.push("category".to_string());
|
||||||
vals.push(Value::String {
|
vals.push(Value::String {
|
||||||
|
@ -998,8 +1012,10 @@ pub fn create_scope(
|
||||||
|
|
||||||
commands.push(Value::Record { cols, vals, span })
|
commands.push(Value::Record { cols, vals, span })
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (alias_name, alias_id) in &frame.aliases {
|
for (alias_name, alias_id) in aliases_map {
|
||||||
|
if visibility.is_alias_id_visible(alias_id) {
|
||||||
let alias = engine_state.get_alias(*alias_id);
|
let alias = engine_state.get_alias(*alias_id);
|
||||||
let mut alias_text = String::new();
|
let mut alias_text = String::new();
|
||||||
for span in alias {
|
for span in alias {
|
||||||
|
@ -1017,13 +1033,13 @@ pub fn create_scope(
|
||||||
Value::string(alias_text, span),
|
Value::string(alias_text, span),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for overlay in &frame.overlays {
|
for overlay in overlays_map {
|
||||||
overlays.push(Value::String {
|
overlays.push(Value::String {
|
||||||
val: String::from_utf8_lossy(overlay.0).to_string(),
|
val: String::from_utf8_lossy(overlay.0).to_string(),
|
||||||
span,
|
span,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
output_cols.push("vars".to_string());
|
output_cols.push("vars".to_string());
|
||||||
|
|
|
@ -20,24 +20,24 @@ static PWD_ENV: &str = "PWD";
|
||||||
|
|
||||||
// Tells whether a decl etc. is visible or not
|
// Tells whether a decl etc. is visible or not
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Visibility {
|
pub struct Visibility {
|
||||||
decl_ids: HashMap<DeclId, bool>,
|
decl_ids: HashMap<DeclId, bool>,
|
||||||
alias_ids: HashMap<AliasId, bool>,
|
alias_ids: HashMap<AliasId, bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Visibility {
|
impl Visibility {
|
||||||
fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Visibility {
|
Visibility {
|
||||||
decl_ids: HashMap::new(),
|
decl_ids: HashMap::new(),
|
||||||
alias_ids: HashMap::new(),
|
alias_ids: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_decl_id_visible(&self, decl_id: &DeclId) -> bool {
|
pub fn is_decl_id_visible(&self, decl_id: &DeclId) -> bool {
|
||||||
*self.decl_ids.get(decl_id).unwrap_or(&true) // by default it's visible
|
*self.decl_ids.get(decl_id).unwrap_or(&true) // by default it's visible
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_alias_id_visible(&self, alias_id: &AliasId) -> bool {
|
pub fn is_alias_id_visible(&self, alias_id: &AliasId) -> bool {
|
||||||
*self.alias_ids.get(alias_id).unwrap_or(&true) // by default it's visible
|
*self.alias_ids.get(alias_id).unwrap_or(&true) // by default it's visible
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ impl Visibility {
|
||||||
self.alias_ids.insert(*alias_id, true);
|
self.alias_ids.insert(*alias_id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_with(&mut self, other: Visibility) {
|
pub fn merge_with(&mut self, other: Visibility) {
|
||||||
// overwrite own values with the other
|
// overwrite own values with the other
|
||||||
self.decl_ids.extend(other.decl_ids);
|
self.decl_ids.extend(other.decl_ids);
|
||||||
self.alias_ids.extend(other.alias_ids);
|
self.alias_ids.extend(other.alias_ids);
|
||||||
|
@ -80,6 +80,12 @@ impl Visibility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Visibility {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ScopeFrame {
|
pub struct ScopeFrame {
|
||||||
pub vars: HashMap<Vec<u8>, VarId>,
|
pub vars: HashMap<Vec<u8>, VarId>,
|
||||||
|
@ -88,7 +94,7 @@ pub struct ScopeFrame {
|
||||||
pub aliases: HashMap<Vec<u8>, AliasId>,
|
pub aliases: HashMap<Vec<u8>, AliasId>,
|
||||||
pub env_vars: HashMap<Vec<u8>, BlockId>,
|
pub env_vars: HashMap<Vec<u8>, BlockId>,
|
||||||
pub overlays: HashMap<Vec<u8>, OverlayId>,
|
pub overlays: HashMap<Vec<u8>, OverlayId>,
|
||||||
visibility: Visibility,
|
pub visibility: Visibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScopeFrame {
|
impl ScopeFrame {
|
||||||
|
@ -377,35 +383,6 @@ impl EngineState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_aliases(&self, name: &str) -> Vec<&[Span]> {
|
|
||||||
let mut output = vec![];
|
|
||||||
|
|
||||||
for frame in &self.scope {
|
|
||||||
if let Some(alias_id) = frame.aliases.get(name.as_bytes()) {
|
|
||||||
let alias = self.get_alias(*alias_id);
|
|
||||||
output.push(alias.as_ref());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_custom_commands(&self, name: &str) -> Vec<Block> {
|
|
||||||
let mut output = vec![];
|
|
||||||
|
|
||||||
for frame in &self.scope {
|
|
||||||
if let Some(decl_id) = frame.decls.get(name.as_bytes()) {
|
|
||||||
let decl = self.get_decl(*decl_id);
|
|
||||||
|
|
||||||
if let Some(block_id) = decl.get_block_id() {
|
|
||||||
output.push(self.get_block(block_id).clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_decl(&self, name: &[u8]) -> Option<DeclId> {
|
pub fn find_decl(&self, name: &[u8]) -> Option<DeclId> {
|
||||||
let mut visibility: Visibility = Visibility::new();
|
let mut visibility: Visibility = Visibility::new();
|
||||||
|
|
||||||
|
@ -422,6 +399,22 @@ impl EngineState {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_alias(&self, name: &[u8]) -> Option<AliasId> {
|
||||||
|
let mut visibility: Visibility = Visibility::new();
|
||||||
|
|
||||||
|
for scope in self.scope.iter().rev() {
|
||||||
|
visibility.append(&scope.visibility);
|
||||||
|
|
||||||
|
if let Some(alias_id) = scope.aliases.get(name) {
|
||||||
|
if visibility.is_alias_id_visible(alias_id) {
|
||||||
|
return Some(*alias_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
pub fn plugin_decls(&self) -> impl Iterator<Item = &Box<dyn Command + 'static>> {
|
pub fn plugin_decls(&self) -> impl Iterator<Item = &Box<dyn Command + 'static>> {
|
||||||
let mut unique_plugin_decls = HashMap::new();
|
let mut unique_plugin_decls = HashMap::new();
|
||||||
|
|
|
@ -3,4 +3,5 @@ extern crate nu_test_support;
|
||||||
mod parsing;
|
mod parsing;
|
||||||
mod path;
|
mod path;
|
||||||
mod plugins;
|
mod plugins;
|
||||||
|
mod scope;
|
||||||
mod shell;
|
mod shell;
|
||||||
|
|
104
tests/scope/mod.rs
Normal file
104
tests/scope/mod.rs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
use nu_test_support::nu;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn scope_shows_alias() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".",
|
||||||
|
r#"alias xaz = echo alias1
|
||||||
|
$nu.scope.aliases | find xaz | length
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
let length: i32 = actual.out.parse().unwrap();
|
||||||
|
assert_eq!(length, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn scope_shows_command() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".",
|
||||||
|
r#"def xaz [] { echo xaz }
|
||||||
|
$nu.scope.commands | find xaz | length
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
let length: i32 = actual.out.parse().unwrap();
|
||||||
|
assert_eq!(length, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn scope_doesnt_show_scoped_hidden_alias() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".",
|
||||||
|
r#"alias xaz = echo alias1
|
||||||
|
do {
|
||||||
|
hide xaz
|
||||||
|
$nu.scope.aliases | find xaz | length
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
let length: i32 = actual.out.parse().unwrap();
|
||||||
|
assert_eq!(length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn scope_doesnt_show_hidden_alias() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".",
|
||||||
|
r#"alias xaz = echo alias1
|
||||||
|
hide xaz
|
||||||
|
$nu.scope.aliases | find xaz | length
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
let length: i32 = actual.out.parse().unwrap();
|
||||||
|
assert_eq!(length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn scope_doesnt_show_scoped_hidden_command() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".",
|
||||||
|
r#"def xaz [] { echo xaz }
|
||||||
|
do {
|
||||||
|
hide xaz
|
||||||
|
$nu.scope.commands | find xaz | length
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
let length: i32 = actual.out.parse().unwrap();
|
||||||
|
assert_eq!(length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn scope_doesnt_show_hidden_command() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".",
|
||||||
|
r#"def xaz [] { echo xaz }
|
||||||
|
hide xaz
|
||||||
|
$nu.scope.commands | find xaz | length
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
let length: i32 = actual.out.parse().unwrap();
|
||||||
|
assert_eq!(length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// same problem as 'which' command
|
||||||
|
#[ignore]
|
||||||
|
#[test]
|
||||||
|
fn correctly_report_of_shadowed_alias() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".",
|
||||||
|
r#"alias xaz = echo alias1
|
||||||
|
def helper [] {
|
||||||
|
alias xaz = echo alias2
|
||||||
|
$nu.scope.aliases
|
||||||
|
}
|
||||||
|
helper | where alias == xaz | get expansion.0"#
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(actual.out, "echo alias2");
|
||||||
|
}
|
Loading…
Reference in a new issue