From 7488254cca6ff6140f8fe4c8439f6a6295da204e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BD=C3=A1dn=C3=ADk?= Date: Tue, 28 Sep 2021 23:18:48 +0300 Subject: [PATCH] Implement a rough version of 'hide' 'hide' command is used to undefine custom commands --- crates/nu-command/src/core_commands/use_.rs | 2 +- crates/nu-command/src/default_context.rs | 9 +- crates/nu-parser/src/parse_keywords.rs | 63 +++++++++++++- crates/nu-parser/src/parser.rs | 3 +- crates/nu-protocol/src/engine/engine_state.rs | 86 ++++++++++++++++++- 5 files changed, 150 insertions(+), 13 deletions(-) diff --git a/crates/nu-command/src/core_commands/use_.rs b/crates/nu-command/src/core_commands/use_.rs index 30b5e3d0b0..3cfae2e49d 100644 --- a/crates/nu-command/src/core_commands/use_.rs +++ b/crates/nu-command/src/core_commands/use_.rs @@ -14,7 +14,7 @@ impl Command for Use { } fn signature(&self) -> nu_protocol::Signature { - Signature::build("use").required("module_name", SyntaxShape::String, "module name") + Signature::build("use").required("pattern", SyntaxShape::String, "import pattern") } fn run( diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 4140ca1a4d..42b30cf877 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -7,7 +7,7 @@ use nu_protocol::{ use crate::{ Alias, Benchmark, BuildString, Def, Do, Each, ExportDef, External, For, From, FromJson, Git, GitCheckout, - If, Length, Let, LetEnv, Lines, ListGitBranches, Ls, Module, Sys, Table, Use, Where, + Hide, If, Length, Let, LetEnv, Lines, ListGitBranches, Ls, Module, Sys, Table, Use, Where, }; pub fn create_default_context() -> Rc> { @@ -29,8 +29,8 @@ pub fn create_default_context() -> Rc> { working_set.add_decl(Box::new(Alias)); working_set.add_decl(Box::new(Benchmark)); working_set.add_decl(Box::new(BuildString)); - - working_set.add_decl(Box::new(Def)); + + working_set.add_decl(Box::new(Def)); working_set.add_decl(Box::new(Do)); working_set.add_decl(Box::new(Each)); working_set.add_decl(Box::new(ExportDef)); @@ -38,6 +38,7 @@ pub fn create_default_context() -> Rc> { working_set.add_decl(Box::new(For)); working_set.add_decl(Box::new(From)); working_set.add_decl(Box::new(FromJson)); + working_set.add_decl(Box::new(Hide)); working_set.add_decl(Box::new(If)); working_set.add_decl(Box::new(Length)); working_set.add_decl(Box::new(Let)); @@ -48,7 +49,7 @@ pub fn create_default_context() -> Rc> { working_set.add_decl(Box::new(Sys)); working_set.add_decl(Box::new(Table)); working_set.add_decl(Box::new(Use)); - working_set.add_decl(Box::new(Where)); + working_set.add_decl(Box::new(Where)); // This is a WIP proof of concept working_set.add_decl(Box::new(ListGitBranches)); diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index 787de1b53b..c27c66d637 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -472,8 +472,6 @@ pub fn parse_use( let mut error = None; let bytes = working_set.get_span_contents(spans[0]); - // TODO: Currently, this directly imports the module's definitions into the current scope. - // Later, we want to put them behind the module's name and add selective importing if bytes == b"use" && spans.len() >= 2 { let (module_name_expr, err) = parse_string(working_set, spans[1]); error = error.or(err); @@ -482,8 +480,6 @@ pub fn parse_use( error = error.or(err); let exports = if let Some(block_id) = working_set.find_module(&import_pattern.head) { - // TODO: Since we don't use the Block at all, we might just as well create a separate - // Module that holds only the exports, without having Blocks in the way. working_set.get_block(block_id).exports.clone() } else { return ( @@ -571,6 +567,65 @@ pub fn parse_use( } } +pub fn parse_hide( + working_set: &mut StateWorkingSet, + spans: &[Span], +) -> (Statement, Option) { + let mut error = None; + let bytes = working_set.get_span_contents(spans[0]); + + if bytes == b"hide" && spans.len() >= 2 { + let (name_expr, err) = parse_string(working_set, spans[1]); + error = error.or(err); + + let name_bytes: Vec = working_set.get_span_contents(spans[1]).into(); + + // TODO: Do the import pattern stuff for bulk-hiding + // TODO: move this error into error = error.or pattern + let _decl_id = if let Some(id) = working_set.find_decl(&name_bytes) { + id + } else { + return ( + garbage_statement(spans), + Some(ParseError::UnknownCommand(spans[1])), + ); + }; + + // Hide the definitions + working_set.hide_decl(name_bytes); + + // Create the Hide command call + let hide_decl_id = working_set + .find_decl(b"hide") + .expect("internal error: missing hide command"); + + let call = Box::new(Call { + head: spans[0], + decl_id: hide_decl_id, + positional: vec![name_expr], + named: vec![], + }); + + ( + Statement::Pipeline(Pipeline::from_vec(vec![Expression { + expr: Expr::Call(call), + span: span(spans), + ty: Type::Unknown, + custom_completion: None, + }])), + error, + ) + } else { + ( + garbage_statement(spans), + Some(ParseError::UnknownState( + "Expected structure: hide ".into(), + span(spans), + )), + ) + } +} + pub fn parse_let( working_set: &mut StateWorkingSet, spans: &[Span], diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index daff7c6054..d3464869f4 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -14,7 +14,7 @@ use nu_protocol::{ }; use crate::parse_keywords::{ - parse_alias, parse_def, parse_def_predecl, parse_let, parse_module, parse_use, + parse_alias, parse_def, parse_def_predecl, parse_hide, parse_let, parse_module, parse_use, }; #[derive(Debug, Clone)] @@ -2589,6 +2589,7 @@ pub fn parse_statement( garbage_statement(spans), Some(ParseError::UnexpectedKeyword("export".into(), spans[0])), ), + b"hide" => parse_hide(working_set, spans), _ => { let (expr, err) = parse_expression(working_set, spans); (Statement::Pipeline(Pipeline::from_vec(vec![expr])), err) diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index f466318970..9ddb768449 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -18,6 +18,7 @@ pub struct ScopeFrame { decls: HashMap, DeclId>, aliases: HashMap, Vec>, modules: HashMap, BlockId>, + hiding: HashMap, usize>, // defines what is being hidden and its "hiding strength" } impl ScopeFrame { @@ -27,6 +28,7 @@ impl ScopeFrame { decls: HashMap::new(), aliases: HashMap::new(), modules: HashMap::new(), + hiding: HashMap::new(), } } @@ -81,6 +83,9 @@ impl EngineState { for item in first.modules.into_iter() { last.modules.insert(item.0, item.1); } + for item in first.hiding.into_iter() { + last.hiding.insert(item.0, item.1); + } } } @@ -124,9 +129,23 @@ impl EngineState { } pub fn find_decl(&self, name: &[u8]) -> Option { + let mut hiding_strength = 0; + // println!("state: starting finding {}", String::from_utf8_lossy(&name)); + for scope in self.scope.iter().rev() { + // println!("hiding map: {:?}", scope.hiding); + // check if we're hiding the declin this scope + if let Some(strength) = scope.hiding.get(name) { + hiding_strength += strength; + } + if let Some(decl_id) = scope.decls.get(name) { - return Some(*decl_id); + // if we're hiding this decl, do not return it and reduce the hiding strength + if hiding_strength > 0 { + hiding_strength -= 1; + } else { + return Some(*decl_id); + } } } @@ -243,10 +262,12 @@ impl StateDelta { } pub fn enter_scope(&mut self) { + // println!("enter scope"); self.scope.push(ScopeFrame::new()); } pub fn exit_scope(&mut self) { + // println!("exit scope"); self.scope.pop(); } } @@ -280,6 +301,7 @@ impl<'a> StateWorkingSet<'a> { pub fn add_decl(&mut self, decl: Box) -> DeclId { let name = decl.name().as_bytes().to_vec(); + // println!("adding {}", String::from_utf8_lossy(&name)); self.delta.decls.push(decl); let decl_id = self.num_decls() - 1; @@ -289,11 +311,36 @@ impl<'a> StateWorkingSet<'a> { .scope .last_mut() .expect("internal error: missing required scope frame"); + + // reset "hiding strength" to 0 => not hidden + if let Some(strength) = scope_frame.hiding.get_mut(&name) { + *strength = 0; + // println!(" strength: {}", strength); + } + scope_frame.decls.insert(name, decl_id); decl_id } + pub fn hide_decl(&mut self, name: Vec) { + let scope_frame = self + .delta + .scope + .last_mut() + .expect("internal error: missing required scope frame"); + + if let Some(strength) = scope_frame.hiding.get_mut(&name) { + *strength += 1; + // println!("hiding {}, strength: {}", String::from_utf8_lossy(&name), strength); + } else { + // println!("hiding {}, strength: 1", String::from_utf8_lossy(&name)); + scope_frame.hiding.insert(name, 1); + } + + // println!("hiding map: {:?}", scope_frame.hiding); + } + pub fn add_block(&mut self, block: Block) -> BlockId { self.delta.blocks.push(block); @@ -401,15 +448,48 @@ impl<'a> StateWorkingSet<'a> { } pub fn find_decl(&self, name: &[u8]) -> Option { + let mut hiding_strength = 0; + // println!("set: starting finding {}", String::from_utf8_lossy(&name)); + for scope in self.delta.scope.iter().rev() { + // println!("delta frame"); + // println!("hiding map: {:?}", scope.hiding); + // check if we're hiding the declin this scope + if let Some(strength) = scope.hiding.get(name) { + hiding_strength += strength; + // println!(" was hiding, strength {}", hiding_strength); + } + if let Some(decl_id) = scope.decls.get(name) { - return Some(*decl_id); + // if we're hiding this decl, do not return it and reduce the hiding strength + if hiding_strength > 0 { + hiding_strength -= 1; + // println!(" decl found, strength {}", hiding_strength); + } else { + // println!(" decl found, return"); + return Some(*decl_id); + } } } for scope in self.permanent_state.scope.iter().rev() { + // println!("perma frame"); + // println!("hiding map: {:?}", scope.hiding); + // check if we're hiding the declin this scope + if let Some(strength) = scope.hiding.get(name) { + hiding_strength += strength; + // println!(" was hiding, strength {}", hiding_strength); + } + if let Some(decl_id) = scope.decls.get(name) { - return Some(*decl_id); + // if we're hiding this decl, do not return it and reduce the hiding strength + if hiding_strength > 0 { + hiding_strength -= 1; + // println!(" decl found, strength {}", hiding_strength); + } else { + // println!(" decl found, return"); + return Some(*decl_id); + } } }