mirror of
https://github.com/nushell/nushell
synced 2024-12-29 14:33:13 +00:00
Merge pull request #89 from kubouch/hide-import-patterns
Add import patterns to 'hide'
This commit is contained in:
commit
26166192e5
3 changed files with 132 additions and 7 deletions
|
@ -600,13 +600,91 @@ pub fn parse_hide(
|
||||||
let (name_expr, err) = parse_string(working_set, spans[1]);
|
let (name_expr, err) = parse_string(working_set, spans[1]);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let name_bytes: Vec<u8> = working_set.get_span_contents(spans[1]).into();
|
let (import_pattern, err) = parse_import_pattern(working_set, spans[1]);
|
||||||
|
error = error.or(err);
|
||||||
|
|
||||||
// TODO: Do the import pattern stuff for bulk-hiding
|
let exported_names: Vec<Vec<u8>> =
|
||||||
|
if let Some(block_id) = working_set.find_module(&import_pattern.head) {
|
||||||
|
working_set
|
||||||
|
.get_block(block_id)
|
||||||
|
.exports
|
||||||
|
.iter()
|
||||||
|
.map(|(name, _)| name.clone())
|
||||||
|
.collect()
|
||||||
|
} else if import_pattern.members.is_empty() {
|
||||||
|
// The pattern head can be e.g. a function name, not just a module
|
||||||
|
vec![import_pattern.head.clone()]
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
garbage_statement(spans),
|
||||||
|
Some(ParseError::ModuleNotFound(spans[1])),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
if working_set.hide_decl(&name_bytes).is_none() {
|
// This kind of inverts the import pattern matching found in parse_use()
|
||||||
|
let names_to_hide = if import_pattern.members.is_empty() {
|
||||||
|
exported_names
|
||||||
|
} else {
|
||||||
|
match &import_pattern.members[0] {
|
||||||
|
ImportPatternMember::Glob { .. } => exported_names
|
||||||
|
.into_iter()
|
||||||
|
.map(|name| {
|
||||||
|
let mut new_name = import_pattern.head.to_vec();
|
||||||
|
new_name.push(b'.');
|
||||||
|
new_name.extend(&name);
|
||||||
|
new_name
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
ImportPatternMember::Name { name, span } => {
|
||||||
|
let new_exports: Vec<Vec<u8>> = exported_names
|
||||||
|
.into_iter()
|
||||||
|
.filter(|n| n == name)
|
||||||
|
.map(|n| {
|
||||||
|
let mut new_name = import_pattern.head.to_vec();
|
||||||
|
new_name.push(b'.');
|
||||||
|
new_name.extend(&n);
|
||||||
|
new_name
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if new_exports.is_empty() {
|
||||||
|
error = error.or(Some(ParseError::ExportNotFound(*span)))
|
||||||
|
}
|
||||||
|
|
||||||
|
new_exports
|
||||||
|
}
|
||||||
|
ImportPatternMember::List { names } => {
|
||||||
|
let mut output = vec![];
|
||||||
|
|
||||||
|
for (name, span) in names {
|
||||||
|
let mut new_exports: Vec<Vec<u8>> = exported_names
|
||||||
|
.iter()
|
||||||
|
.filter_map(|n| if n == name { Some(n.clone()) } else { None })
|
||||||
|
.map(|n| {
|
||||||
|
let mut new_name = import_pattern.head.to_vec();
|
||||||
|
new_name.push(b'.');
|
||||||
|
new_name.extend(n);
|
||||||
|
new_name
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if new_exports.is_empty() {
|
||||||
|
error = error.or(Some(ParseError::ExportNotFound(*span)))
|
||||||
|
} else {
|
||||||
|
output.append(&mut new_exports)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for name in names_to_hide {
|
||||||
|
if working_set.hide_decl(&name).is_none() {
|
||||||
error = error.or_else(|| Some(ParseError::UnknownCommand(spans[1])));
|
error = error.or_else(|| Some(ParseError::UnknownCommand(spans[1])));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the Hide command call
|
// Create the Hide command call
|
||||||
let hide_decl_id = working_set
|
let hide_decl_id = working_set
|
||||||
|
|
|
@ -375,7 +375,7 @@ impl<'a> StateWorkingSet<'a> {
|
||||||
|
|
||||||
if let Some(decl_id) = scope.decls.get(name) {
|
if let Some(decl_id) = scope.decls.get(name) {
|
||||||
if !hiding.contains(decl_id) {
|
if !hiding.contains(decl_id) {
|
||||||
// Do not hide already hidden decl
|
// Hide decl only if it's not already hidden
|
||||||
last_scope_frame.hiding.insert(*decl_id);
|
last_scope_frame.hiding.insert(*decl_id);
|
||||||
return Some(*decl_id);
|
return Some(*decl_id);
|
||||||
}
|
}
|
||||||
|
@ -409,8 +409,6 @@ impl<'a> StateWorkingSet<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn activate_overlay(&mut self, overlay: Vec<(Vec<u8>, DeclId)>) {
|
pub fn activate_overlay(&mut self, overlay: Vec<(Vec<u8>, DeclId)>) {
|
||||||
// TODO: This will overwrite all existing definitions in a scope. When we add deactivate,
|
|
||||||
// we need to re-think how make it recoverable.
|
|
||||||
let scope_frame = self
|
let scope_frame = self
|
||||||
.delta
|
.delta
|
||||||
.scope
|
.scope
|
||||||
|
|
49
src/tests.rs
49
src/tests.rs
|
@ -441,6 +441,46 @@ fn hide_twice_not_allowed() -> TestResult {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_import_1() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"module spam { export def foo [] { "foo" } }; use spam; hide spam.foo; foo"#,
|
||||||
|
"not found",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_import_2() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"module spam { export def foo [] { "foo" } }; use spam; hide spam.*; foo"#,
|
||||||
|
"not found",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_import_3() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"module spam { export def foo [] { "foo" } }; use spam; hide spam.[foo]; foo"#,
|
||||||
|
"not found",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_import_4() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"module spam { export def foo [] { "foo" } }; use spam.foo; hide foo; foo"#,
|
||||||
|
"not found",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_import_5() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"module spam { export def foo [] { "foo" } }; use spam.*; hide foo; foo"#,
|
||||||
|
"not found",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn def_twice_should_fail() -> TestResult {
|
fn def_twice_should_fail() -> TestResult {
|
||||||
fail_test(
|
fail_test(
|
||||||
|
@ -449,6 +489,15 @@ fn def_twice_should_fail() -> TestResult {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This test fails if executed each command on a separate line in REPL
|
||||||
|
#[test]
|
||||||
|
fn use_import_after_hide() -> TestResult {
|
||||||
|
run_test(
|
||||||
|
r#"module spam { export def foo [] { "foo" } }; use spam.foo; hide foo; use spam.foo; foo"#,
|
||||||
|
"foo",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_json_1() -> TestResult {
|
fn from_json_1() -> TestResult {
|
||||||
run_test(r#"('{"name": "Fred"}' | from json).name"#, "Fred")
|
run_test(r#"('{"name": "Fred"}' | from json).name"#, "Fred")
|
||||||
|
|
Loading…
Reference in a new issue