mirror of
https://github.com/nushell/nushell.git
synced 2024-11-29 03:44:19 +01:00
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
This commit is contained in:
parent
fcc13224c1
commit
328f7e92a0
@ -17,11 +17,11 @@ impl Command for Hide {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Hide definitions in the current scope"
|
"Hide symbols in the current scope"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
"If there is a definition and an environment variable with the same name in the current scope, first the definition will be hidden, then the environment variable."
|
"Symbols are hidden by priority: First aliases, then custom commands, then environment variables."
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -67,7 +67,7 @@ impl Command for Hide {
|
|||||||
overlay.env_var_with_head(name, &import_pattern.head.name)
|
overlay.env_var_with_head(name, &import_pattern.head.name)
|
||||||
{
|
{
|
||||||
output.push((name, id));
|
output.push((name, id));
|
||||||
} else if !overlay.has_decl(name) {
|
} else if !(overlay.has_alias(name) || overlay.has_decl(name)) {
|
||||||
return Err(ShellError::EnvVarNotFoundAtRuntime(
|
return Err(ShellError::EnvVarNotFoundAtRuntime(
|
||||||
String::from_utf8_lossy(name).into(),
|
String::from_utf8_lossy(name).into(),
|
||||||
*span,
|
*span,
|
||||||
@ -84,7 +84,7 @@ impl Command for Hide {
|
|||||||
overlay.env_var_with_head(name, &import_pattern.head.name)
|
overlay.env_var_with_head(name, &import_pattern.head.name)
|
||||||
{
|
{
|
||||||
output.push((name, id));
|
output.push((name, id));
|
||||||
} else if !overlay.has_decl(name) {
|
} else if !(overlay.has_alias(name) || overlay.has_decl(name)) {
|
||||||
return Err(ShellError::EnvVarNotFoundAtRuntime(
|
return Err(ShellError::EnvVarNotFoundAtRuntime(
|
||||||
String::from_utf8_lossy(name).into(),
|
String::from_utf8_lossy(name).into(),
|
||||||
*span,
|
*span,
|
||||||
|
@ -82,9 +82,9 @@ fn get_entries_in_aliases(engine_state: &EngineState, name: &str, span: Span) ->
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|spans| {
|
.map(|spans| {
|
||||||
spans
|
spans
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|span| {
|
.map(|span| {
|
||||||
String::from_utf8_lossy(engine_state.get_span_contents(&span)).to_string()
|
String::from_utf8_lossy(engine_state.get_span_contents(span)).to_string()
|
||||||
})
|
})
|
||||||
.join(" ")
|
.join(" ")
|
||||||
})
|
})
|
||||||
|
@ -945,9 +945,10 @@ pub fn eval_variable(
|
|||||||
commands.push(Value::Record { cols, vals, span })
|
commands.push(Value::Record { cols, vals, span })
|
||||||
}
|
}
|
||||||
|
|
||||||
for alias in &frame.aliases {
|
for (alias_name, alias_id) in &frame.aliases {
|
||||||
|
let alias = engine_state.get_alias(*alias_id);
|
||||||
let mut alias_text = String::new();
|
let mut alias_text = String::new();
|
||||||
for span in alias.1 {
|
for span in alias {
|
||||||
let contents = engine_state.get_span_contents(span);
|
let contents = engine_state.get_span_contents(span);
|
||||||
if !alias_text.is_empty() {
|
if !alias_text.is_empty() {
|
||||||
alias_text.push(' ');
|
alias_text.push(' ');
|
||||||
@ -956,7 +957,7 @@ pub fn eval_variable(
|
|||||||
}
|
}
|
||||||
aliases.push((
|
aliases.push((
|
||||||
Value::String {
|
Value::String {
|
||||||
val: String::from_utf8_lossy(alias.0).to_string(),
|
val: String::from_utf8_lossy(alias_name).to_string(),
|
||||||
span,
|
span,
|
||||||
},
|
},
|
||||||
Value::string(alias_text, span),
|
Value::string(alias_text, span),
|
||||||
|
@ -1320,14 +1320,21 @@ pub fn parse_hide(
|
|||||||
if let Some(overlay_id) = working_set.find_overlay(&import_pattern.head.name) {
|
if let Some(overlay_id) = working_set.find_overlay(&import_pattern.head.name) {
|
||||||
(true, working_set.get_overlay(overlay_id).clone())
|
(true, working_set.get_overlay(overlay_id).clone())
|
||||||
} else if import_pattern.members.is_empty() {
|
} else if import_pattern.members.is_empty() {
|
||||||
// The pattern head can be e.g. a function name, not just a module
|
// The pattern head can be:
|
||||||
if let Some(id) = working_set.find_decl(&import_pattern.head.name) {
|
if let Some(id) = working_set.find_alias(&import_pattern.head.name) {
|
||||||
|
// an alias,
|
||||||
|
let mut overlay = Overlay::new();
|
||||||
|
overlay.add_alias(&import_pattern.head.name, id);
|
||||||
|
|
||||||
|
(false, overlay)
|
||||||
|
} else if let Some(id) = working_set.find_decl(&import_pattern.head.name) {
|
||||||
|
// a custom command,
|
||||||
let mut overlay = Overlay::new();
|
let mut overlay = Overlay::new();
|
||||||
overlay.add_decl(&import_pattern.head.name, id);
|
overlay.add_decl(&import_pattern.head.name, id);
|
||||||
|
|
||||||
(false, overlay)
|
(false, overlay)
|
||||||
} else {
|
} else {
|
||||||
// Or it could be an env var
|
// , or it could be an env var (handled by the engine)
|
||||||
(false, Overlay::new())
|
(false, Overlay::new())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1338,49 +1345,71 @@ pub fn parse_hide(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// This kind of inverts the import pattern matching found in parse_use()
|
// This kind of inverts the import pattern matching found in parse_use()
|
||||||
let decls_to_hide = if import_pattern.members.is_empty() {
|
let (aliases_to_hide, decls_to_hide) = if import_pattern.members.is_empty() {
|
||||||
if is_module {
|
if is_module {
|
||||||
overlay.decls_with_head(&import_pattern.head.name)
|
(
|
||||||
|
overlay.alias_names_with_head(&import_pattern.head.name),
|
||||||
|
overlay.decl_names_with_head(&import_pattern.head.name),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
overlay.decls()
|
(overlay.alias_names(), overlay.decl_names())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match &import_pattern.members[0] {
|
match &import_pattern.members[0] {
|
||||||
ImportPatternMember::Glob { .. } => overlay.decls(),
|
ImportPatternMember::Glob { .. } => (overlay.alias_names(), overlay.decl_names()),
|
||||||
ImportPatternMember::Name { name, span } => {
|
ImportPatternMember::Name { name, span } => {
|
||||||
let mut output = vec![];
|
let mut aliases = vec![];
|
||||||
|
let mut decls = vec![];
|
||||||
|
|
||||||
if let Some(item) = overlay.decl_with_head(name, &import_pattern.head.name) {
|
if let Some(item) =
|
||||||
output.push(item);
|
overlay.alias_name_with_head(name, &import_pattern.head.name)
|
||||||
|
{
|
||||||
|
aliases.push(item);
|
||||||
|
} else if let Some(item) =
|
||||||
|
overlay.decl_name_with_head(name, &import_pattern.head.name)
|
||||||
|
{
|
||||||
|
decls.push(item);
|
||||||
} else if !overlay.has_env_var(name) {
|
} else if !overlay.has_env_var(name) {
|
||||||
error = error.or(Some(ParseError::ExportNotFound(*span)));
|
error = error.or(Some(ParseError::ExportNotFound(*span)));
|
||||||
}
|
}
|
||||||
|
|
||||||
output
|
(aliases, decls)
|
||||||
}
|
}
|
||||||
ImportPatternMember::List { names } => {
|
ImportPatternMember::List { names } => {
|
||||||
let mut output = vec![];
|
let mut aliases = vec![];
|
||||||
|
let mut decls = vec![];
|
||||||
|
|
||||||
for (name, span) in names {
|
for (name, span) in names {
|
||||||
if let Some(item) = overlay.decl_with_head(name, &import_pattern.head.name)
|
if let Some(item) =
|
||||||
|
overlay.alias_name_with_head(name, &import_pattern.head.name)
|
||||||
{
|
{
|
||||||
output.push(item);
|
aliases.push(item);
|
||||||
|
} else if let Some(item) =
|
||||||
|
overlay.decl_name_with_head(name, &import_pattern.head.name)
|
||||||
|
{
|
||||||
|
decls.push(item);
|
||||||
} else if !overlay.has_env_var(name) {
|
} else if !overlay.has_env_var(name) {
|
||||||
error = error.or(Some(ParseError::ExportNotFound(*span)));
|
error = error.or(Some(ParseError::ExportNotFound(*span)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
output
|
(aliases, decls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let import_pattern = {
|
||||||
|
let aliases: HashSet<Vec<u8>> = aliases_to_hide.iter().cloned().collect();
|
||||||
|
let decls: HashSet<Vec<u8>> = decls_to_hide.iter().cloned().collect();
|
||||||
|
|
||||||
|
import_pattern.with_hidden(decls.union(&aliases).cloned().collect())
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: `use spam; use spam foo; hide foo` will hide both `foo` and `spam foo` since
|
// TODO: `use spam; use spam foo; hide foo` will hide both `foo` and `spam foo` since
|
||||||
// they point to the same DeclId. Do we want to keep it that way?
|
// they point to the same DeclId. Do we want to keep it that way?
|
||||||
working_set.hide_decls(&decls_to_hide);
|
working_set.hide_decls(&decls_to_hide);
|
||||||
let import_pattern = import_pattern
|
working_set.hide_aliases(&aliases_to_hide);
|
||||||
.with_hidden(decls_to_hide.iter().map(|(name, _)| name.clone()).collect());
|
|
||||||
|
|
||||||
// Create a new Use command call to pass the new import pattern
|
// Create a new Use command call to pass the new import pattern
|
||||||
let import_pattern_expr = Expression {
|
let import_pattern_expr = Expression {
|
||||||
|
@ -828,9 +828,11 @@ pub fn parse_call(
|
|||||||
|
|
||||||
if expand_aliases {
|
if expand_aliases {
|
||||||
// If the word is an alias, expand it and re-parse the expression
|
// If the word is an alias, expand it and re-parse the expression
|
||||||
if let Some(expansion) = working_set.find_alias(&name) {
|
if let Some(alias_id) = working_set.find_alias(&name) {
|
||||||
trace!("expanding alias");
|
trace!("expanding alias");
|
||||||
|
|
||||||
|
let expansion = working_set.get_alias(alias_id);
|
||||||
|
|
||||||
let orig_span = spans[pos];
|
let orig_span = spans[pos];
|
||||||
let mut new_spans: Vec<Span> = vec![];
|
let mut new_spans: Vec<Span> = vec![];
|
||||||
new_spans.extend(&spans[0..pos]);
|
new_spans.extend(&spans[0..pos]);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::{Command, Stack};
|
use super::{Command, Stack};
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::Block, BlockId, DeclId, Example, Overlay, OverlayId, ShellError, Signature, Span, Type,
|
ast::Block, AliasId, BlockId, DeclId, Example, Overlay, OverlayId, ShellError, Signature, Span,
|
||||||
VarId,
|
Type, VarId,
|
||||||
};
|
};
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use std::{
|
use std::{
|
||||||
@ -20,12 +20,14 @@ use std::path::PathBuf;
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Visibility {
|
struct Visibility {
|
||||||
decl_ids: HashMap<DeclId, bool>,
|
decl_ids: HashMap<DeclId, bool>,
|
||||||
|
alias_ids: HashMap<AliasId, bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Visibility {
|
impl Visibility {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Visibility {
|
Visibility {
|
||||||
decl_ids: HashMap::new(),
|
decl_ids: HashMap::new(),
|
||||||
|
alias_ids: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,27 +35,46 @@ impl Visibility {
|
|||||||
*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 {
|
||||||
|
*self.alias_ids.get(alias_id).unwrap_or(&true) // by default it's visible
|
||||||
|
}
|
||||||
|
|
||||||
fn hide_decl_id(&mut self, decl_id: &DeclId) {
|
fn hide_decl_id(&mut self, decl_id: &DeclId) {
|
||||||
self.decl_ids.insert(*decl_id, false);
|
self.decl_ids.insert(*decl_id, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hide_alias_id(&mut self, alias_id: &AliasId) {
|
||||||
|
self.alias_ids.insert(*alias_id, false);
|
||||||
|
}
|
||||||
|
|
||||||
fn use_decl_id(&mut self, decl_id: &DeclId) {
|
fn use_decl_id(&mut self, decl_id: &DeclId) {
|
||||||
self.decl_ids.insert(*decl_id, true);
|
self.decl_ids.insert(*decl_id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn use_alias_id(&mut self, alias_id: &AliasId) {
|
||||||
|
self.alias_ids.insert(*alias_id, true);
|
||||||
|
}
|
||||||
|
|
||||||
fn merge_with(&mut self, other: Visibility) {
|
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.env_var_ids.extend(other.env_var_ids);
|
// self.env_var_ids.extend(other.env_var_ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append(&mut self, other: &Visibility) {
|
fn append(&mut self, other: &Visibility) {
|
||||||
// take new values from other but keep own values
|
// take new values from the other but keep own values
|
||||||
for (decl_id, visible) in other.decl_ids.iter() {
|
for (decl_id, visible) in other.decl_ids.iter() {
|
||||||
if !self.decl_ids.contains_key(decl_id) {
|
if !self.decl_ids.contains_key(decl_id) {
|
||||||
self.decl_ids.insert(*decl_id, *visible);
|
self.decl_ids.insert(*decl_id, *visible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (alias_id, visible) in other.alias_ids.iter() {
|
||||||
|
if !self.alias_ids.contains_key(alias_id) {
|
||||||
|
self.alias_ids.insert(*alias_id, *visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +83,7 @@ pub struct ScopeFrame {
|
|||||||
pub vars: HashMap<Vec<u8>, VarId>,
|
pub vars: HashMap<Vec<u8>, VarId>,
|
||||||
predecls: HashMap<Vec<u8>, DeclId>, // temporary storage for predeclarations
|
predecls: HashMap<Vec<u8>, DeclId>, // temporary storage for predeclarations
|
||||||
pub decls: HashMap<Vec<u8>, DeclId>,
|
pub decls: HashMap<Vec<u8>, DeclId>,
|
||||||
pub aliases: HashMap<Vec<u8>, Vec<Span>>,
|
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,
|
visibility: Visibility,
|
||||||
@ -140,6 +161,7 @@ pub struct EngineState {
|
|||||||
file_contents: im::Vector<(Vec<u8>, usize, usize)>,
|
file_contents: im::Vector<(Vec<u8>, usize, usize)>,
|
||||||
vars: im::Vector<Type>,
|
vars: im::Vector<Type>,
|
||||||
decls: im::Vector<Box<dyn Command + 'static>>,
|
decls: im::Vector<Box<dyn Command + 'static>>,
|
||||||
|
aliases: im::Vector<Vec<Span>>,
|
||||||
blocks: im::Vector<Block>,
|
blocks: im::Vector<Block>,
|
||||||
overlays: im::Vector<Overlay>,
|
overlays: im::Vector<Overlay>,
|
||||||
pub scope: im::Vector<ScopeFrame>,
|
pub scope: im::Vector<ScopeFrame>,
|
||||||
@ -169,6 +191,7 @@ impl EngineState {
|
|||||||
Type::Unknown
|
Type::Unknown
|
||||||
],
|
],
|
||||||
decls: im::vector![],
|
decls: im::vector![],
|
||||||
|
aliases: im::vector![],
|
||||||
blocks: im::vector![],
|
blocks: im::vector![],
|
||||||
overlays: im::vector![],
|
overlays: im::vector![],
|
||||||
scope: im::vector![ScopeFrame::new()],
|
scope: im::vector![ScopeFrame::new()],
|
||||||
@ -196,6 +219,7 @@ impl EngineState {
|
|||||||
self.files.extend(delta.files);
|
self.files.extend(delta.files);
|
||||||
self.file_contents.extend(delta.file_contents);
|
self.file_contents.extend(delta.file_contents);
|
||||||
self.decls.extend(delta.decls);
|
self.decls.extend(delta.decls);
|
||||||
|
self.aliases.extend(delta.aliases);
|
||||||
self.vars.extend(delta.vars);
|
self.vars.extend(delta.vars);
|
||||||
self.blocks.extend(delta.blocks);
|
self.blocks.extend(delta.blocks);
|
||||||
self.overlays.extend(delta.overlays);
|
self.overlays.extend(delta.overlays);
|
||||||
@ -311,6 +335,10 @@ impl EngineState {
|
|||||||
self.decls.len()
|
self.decls.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn num_aliases(&self) -> usize {
|
||||||
|
self.aliases.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn num_blocks(&self) -> usize {
|
pub fn num_blocks(&self) -> usize {
|
||||||
self.blocks.len()
|
self.blocks.len()
|
||||||
}
|
}
|
||||||
@ -344,12 +372,13 @@ impl EngineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_aliases(&self, name: &str) -> Vec<Vec<Span>> {
|
pub fn find_aliases(&self, name: &str) -> Vec<&[Span]> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
|
||||||
for frame in &self.scope {
|
for frame in &self.scope {
|
||||||
if let Some(alias) = frame.aliases.get(name.as_bytes()) {
|
if let Some(alias_id) = frame.aliases.get(name.as_bytes()) {
|
||||||
output.push(alias.clone());
|
let alias = self.get_alias(*alias_id);
|
||||||
|
output.push(alias.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,6 +481,13 @@ impl EngineState {
|
|||||||
.expect("internal error: missing declaration")
|
.expect("internal error: missing declaration")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_alias(&self, alias_id: AliasId) -> &[Span] {
|
||||||
|
self.aliases
|
||||||
|
.get(alias_id)
|
||||||
|
.expect("internal error: missing alias")
|
||||||
|
.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get all IDs of all commands within scope, sorted by the commads' names
|
/// Get all IDs of all commands within scope, sorted by the commads' names
|
||||||
pub fn get_decl_ids_sorted(&self, include_hidden: bool) -> impl Iterator<Item = DeclId> {
|
pub fn get_decl_ids_sorted(&self, include_hidden: bool) -> impl Iterator<Item = DeclId> {
|
||||||
let mut decls_map = HashMap::new();
|
let mut decls_map = HashMap::new();
|
||||||
@ -607,6 +643,7 @@ pub struct StateDelta {
|
|||||||
pub(crate) file_contents: Vec<(Vec<u8>, usize, usize)>,
|
pub(crate) file_contents: Vec<(Vec<u8>, usize, usize)>,
|
||||||
vars: Vec<Type>, // indexed by VarId
|
vars: Vec<Type>, // indexed by VarId
|
||||||
decls: Vec<Box<dyn Command>>, // indexed by DeclId
|
decls: Vec<Box<dyn Command>>, // indexed by DeclId
|
||||||
|
aliases: Vec<Vec<Span>>, // indexed by AliasId
|
||||||
pub blocks: Vec<Block>, // indexed by BlockId
|
pub blocks: Vec<Block>, // indexed by BlockId
|
||||||
overlays: Vec<Overlay>, // indexed by OverlayId
|
overlays: Vec<Overlay>, // indexed by OverlayId
|
||||||
pub scope: Vec<ScopeFrame>,
|
pub scope: Vec<ScopeFrame>,
|
||||||
@ -627,6 +664,7 @@ impl StateDelta {
|
|||||||
file_contents: vec![],
|
file_contents: vec![],
|
||||||
vars: vec![],
|
vars: vec![],
|
||||||
decls: vec![],
|
decls: vec![],
|
||||||
|
aliases: vec![],
|
||||||
blocks: vec![],
|
blocks: vec![],
|
||||||
overlays: vec![],
|
overlays: vec![],
|
||||||
scope: vec![ScopeFrame::new()],
|
scope: vec![ScopeFrame::new()],
|
||||||
@ -643,6 +681,10 @@ impl StateDelta {
|
|||||||
self.decls.len()
|
self.decls.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn num_aliases(&self) -> usize {
|
||||||
|
self.aliases.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn num_blocks(&self) -> usize {
|
pub fn num_blocks(&self) -> usize {
|
||||||
self.blocks.len()
|
self.blocks.len()
|
||||||
}
|
}
|
||||||
@ -676,6 +718,10 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
self.delta.num_decls() + self.permanent_state.num_decls()
|
self.delta.num_decls() + self.permanent_state.num_decls()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn num_aliases(&self) -> usize {
|
||||||
|
self.delta.num_aliases() + self.permanent_state.num_aliases()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn num_blocks(&self) -> usize {
|
pub fn num_blocks(&self) -> usize {
|
||||||
self.delta.num_blocks() + self.permanent_state.num_blocks()
|
self.delta.num_blocks() + self.permanent_state.num_blocks()
|
||||||
}
|
}
|
||||||
@ -786,9 +832,49 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hide_decls(&mut self, decls: &[(Vec<u8>, DeclId)]) {
|
pub fn hide_alias(&mut self, name: &[u8]) -> Option<AliasId> {
|
||||||
|
let mut visibility: Visibility = Visibility::new();
|
||||||
|
|
||||||
|
// Since we can mutate scope frames in delta, remove the id directly
|
||||||
|
for scope in self.delta.scope.iter_mut().rev() {
|
||||||
|
visibility.append(&scope.visibility);
|
||||||
|
|
||||||
|
if let Some(alias_id) = scope.aliases.remove(name) {
|
||||||
|
return Some(alias_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We cannot mutate the permanent state => store the information in the current scope frame
|
||||||
|
let last_scope_frame = self
|
||||||
|
.delta
|
||||||
|
.scope
|
||||||
|
.last_mut()
|
||||||
|
.expect("internal error: missing required scope frame");
|
||||||
|
|
||||||
|
for scope in self.permanent_state.scope.iter().rev() {
|
||||||
|
visibility.append(&scope.visibility);
|
||||||
|
|
||||||
|
if let Some(alias_id) = scope.aliases.get(name) {
|
||||||
|
if visibility.is_alias_id_visible(alias_id) {
|
||||||
|
// Hide alias only if it's not already hidden
|
||||||
|
last_scope_frame.visibility.hide_alias_id(alias_id);
|
||||||
|
return Some(*alias_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hide_decls(&mut self, decls: &[Vec<u8>]) {
|
||||||
for decl in decls.iter() {
|
for decl in decls.iter() {
|
||||||
self.hide_decl(&decl.0); // let's assume no errors
|
self.hide_decl(decl); // let's assume no errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hide_aliases(&mut self, aliases: &[Vec<u8>]) {
|
||||||
|
for alias in aliases.iter() {
|
||||||
|
self.hide_alias(alias); // let's assume no errors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -941,6 +1027,30 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_alias(&self, name: &[u8]) -> Option<AliasId> {
|
||||||
|
let mut visibility: Visibility = Visibility::new();
|
||||||
|
|
||||||
|
for scope in self.delta.scope.iter().rev() {
|
||||||
|
visibility.append(&scope.visibility);
|
||||||
|
|
||||||
|
if let Some(alias_id) = scope.aliases.get(name) {
|
||||||
|
return Some(*alias_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for scope in self.permanent_state.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
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_overlay(&self, name: &[u8]) -> Option<OverlayId> {
|
pub fn find_overlay(&self, name: &[u8]) -> Option<OverlayId> {
|
||||||
for scope in self.delta.scope.iter().rev() {
|
for scope in self.delta.scope.iter().rev() {
|
||||||
if let Some(overlay_id) = scope.overlays.get(name) {
|
if let Some(overlay_id) = scope.overlays.get(name) {
|
||||||
@ -1003,22 +1113,6 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_alias(&self, name: &[u8]) -> Option<&[Span]> {
|
|
||||||
for scope in self.delta.scope.iter().rev() {
|
|
||||||
if let Some(spans) = scope.aliases.get(name) {
|
|
||||||
return Some(spans);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for scope in self.permanent_state.scope.iter().rev() {
|
|
||||||
if let Some(spans) = scope.aliases.get(name) {
|
|
||||||
return Some(spans);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_variable(&mut self, mut name: Vec<u8>, ty: Type) -> VarId {
|
pub fn add_variable(&mut self, mut name: Vec<u8>, ty: Type) -> VarId {
|
||||||
let next_id = self.next_var_id();
|
let next_id = self.next_var_id();
|
||||||
|
|
||||||
@ -1041,13 +1135,17 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_alias(&mut self, name: Vec<u8>, replacement: Vec<Span>) {
|
pub fn add_alias(&mut self, name: Vec<u8>, replacement: Vec<Span>) {
|
||||||
|
self.delta.aliases.push(replacement);
|
||||||
|
let alias_id = self.num_aliases() - 1;
|
||||||
|
|
||||||
let last = self
|
let last = self
|
||||||
.delta
|
.delta
|
||||||
.scope
|
.scope
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.expect("internal error: missing stack frame");
|
.expect("internal error: missing stack frame");
|
||||||
|
|
||||||
last.aliases.insert(name, replacement);
|
last.aliases.insert(name, alias_id);
|
||||||
|
last.visibility.use_alias_id(&alias_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_cwd(&self) -> String {
|
pub fn get_cwd(&self) -> String {
|
||||||
@ -1105,6 +1203,19 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_alias(&self, alias_id: AliasId) -> &[Span] {
|
||||||
|
let num_permanent_aliases = self.permanent_state.num_aliases();
|
||||||
|
if alias_id < num_permanent_aliases {
|
||||||
|
self.permanent_state.get_alias(alias_id)
|
||||||
|
} else {
|
||||||
|
self.delta
|
||||||
|
.aliases
|
||||||
|
.get(alias_id - num_permanent_aliases)
|
||||||
|
.expect("internal error: missing alias")
|
||||||
|
.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_commands_by_prefix(&self, name: &[u8]) -> Vec<Vec<u8>> {
|
pub fn find_commands_by_prefix(&self, name: &[u8]) -> Vec<Vec<u8>> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub type VarId = usize;
|
pub type VarId = usize;
|
||||||
pub type DeclId = usize;
|
pub type DeclId = usize;
|
||||||
|
pub type AliasId = usize;
|
||||||
pub type BlockId = usize;
|
pub type BlockId = usize;
|
||||||
pub type OverlayId = usize;
|
pub type OverlayId = usize;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{BlockId, DeclId, Span};
|
use crate::{AliasId, BlockId, DeclId, Span};
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
@ -9,6 +9,7 @@ use indexmap::IndexMap;
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Overlay {
|
pub struct Overlay {
|
||||||
pub decls: IndexMap<Vec<u8>, DeclId>,
|
pub decls: IndexMap<Vec<u8>, DeclId>,
|
||||||
|
pub aliases: IndexMap<Vec<u8>, AliasId>,
|
||||||
pub env_vars: IndexMap<Vec<u8>, BlockId>,
|
pub env_vars: IndexMap<Vec<u8>, BlockId>,
|
||||||
pub span: Option<Span>,
|
pub span: Option<Span>,
|
||||||
}
|
}
|
||||||
@ -17,6 +18,7 @@ impl Overlay {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Overlay {
|
Overlay {
|
||||||
decls: IndexMap::new(),
|
decls: IndexMap::new(),
|
||||||
|
aliases: IndexMap::new(),
|
||||||
env_vars: IndexMap::new(),
|
env_vars: IndexMap::new(),
|
||||||
span: None,
|
span: None,
|
||||||
}
|
}
|
||||||
@ -25,6 +27,7 @@ impl Overlay {
|
|||||||
pub fn from_span(span: Span) -> Self {
|
pub fn from_span(span: Span) -> Self {
|
||||||
Overlay {
|
Overlay {
|
||||||
decls: IndexMap::new(),
|
decls: IndexMap::new(),
|
||||||
|
aliases: IndexMap::new(),
|
||||||
env_vars: IndexMap::new(),
|
env_vars: IndexMap::new(),
|
||||||
span: Some(span),
|
span: Some(span),
|
||||||
}
|
}
|
||||||
@ -34,6 +37,10 @@ impl Overlay {
|
|||||||
self.decls.insert(name.to_vec(), decl_id)
|
self.decls.insert(name.to_vec(), decl_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_alias(&mut self, name: &[u8], alias_id: AliasId) -> Option<AliasId> {
|
||||||
|
self.aliases.insert(name.to_vec(), alias_id)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_env_var(&mut self, name: &[u8], block_id: BlockId) -> Option<BlockId> {
|
pub fn add_env_var(&mut self, name: &[u8], block_id: BlockId) -> Option<BlockId> {
|
||||||
self.env_vars.insert(name.to_vec(), block_id)
|
self.env_vars.insert(name.to_vec(), block_id)
|
||||||
}
|
}
|
||||||
@ -51,16 +58,35 @@ impl Overlay {
|
|||||||
self.decls.get(name).copied()
|
self.decls.get(name).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_alias_id(&self, name: &[u8]) -> Option<AliasId> {
|
||||||
|
self.aliases.get(name).copied()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn has_decl(&self, name: &[u8]) -> bool {
|
pub fn has_decl(&self, name: &[u8]) -> bool {
|
||||||
self.decls.contains_key(name)
|
self.decls.contains_key(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decl_with_head(&self, name: &[u8], head: &[u8]) -> Option<(Vec<u8>, DeclId)> {
|
pub fn has_alias(&self, name: &[u8]) -> bool {
|
||||||
if let Some(id) = self.get_decl_id(name) {
|
self.aliases.contains_key(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decl_name_with_head(&self, name: &[u8], head: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
if self.has_decl(name) {
|
||||||
let mut new_name = head.to_vec();
|
let mut new_name = head.to_vec();
|
||||||
new_name.push(b' ');
|
new_name.push(b' ');
|
||||||
new_name.extend(name);
|
new_name.extend(name);
|
||||||
Some((new_name, id))
|
Some(new_name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alias_name_with_head(&self, name: &[u8], head: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
if self.has_alias(name) {
|
||||||
|
let mut new_name = head.to_vec();
|
||||||
|
new_name.push(b' ');
|
||||||
|
new_name.extend(name);
|
||||||
|
Some(new_name)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -78,6 +104,30 @@ impl Overlay {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decl_names_with_head(&self, head: &[u8]) -> Vec<Vec<u8>> {
|
||||||
|
self.decls
|
||||||
|
.keys()
|
||||||
|
.map(|name| {
|
||||||
|
let mut new_name = head.to_vec();
|
||||||
|
new_name.push(b' ');
|
||||||
|
new_name.extend(name);
|
||||||
|
new_name
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alias_names_with_head(&self, head: &[u8]) -> Vec<Vec<u8>> {
|
||||||
|
self.aliases
|
||||||
|
.keys()
|
||||||
|
.map(|name| {
|
||||||
|
let mut new_name = head.to_vec();
|
||||||
|
new_name.push(b' ');
|
||||||
|
new_name.extend(name);
|
||||||
|
new_name
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn decls(&self) -> Vec<(Vec<u8>, DeclId)> {
|
pub fn decls(&self) -> Vec<(Vec<u8>, DeclId)> {
|
||||||
self.decls
|
self.decls
|
||||||
.iter()
|
.iter()
|
||||||
@ -85,6 +135,21 @@ impl Overlay {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decl_names(&self) -> Vec<Vec<u8>> {
|
||||||
|
self.decls.keys().cloned().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alias_names(&self) -> Vec<Vec<u8>> {
|
||||||
|
self.aliases.keys().cloned().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn aliases(&self) -> Vec<(Vec<u8>, AliasId)> {
|
||||||
|
self.aliases
|
||||||
|
.iter()
|
||||||
|
.map(|(name, id)| (name.clone(), *id))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_env_var_id(&self, name: &[u8]) -> Option<BlockId> {
|
pub fn get_env_var_id(&self, name: &[u8]) -> Option<BlockId> {
|
||||||
self.env_vars.get(name).copied()
|
self.env_vars.get(name).copied()
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,14 @@ fn hides_def() -> TestResult {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"alias foo = echo "foo"; hide foo; foo"#,
|
||||||
|
"", // we just care if it errors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hides_env() -> TestResult {
|
fn hides_env() -> TestResult {
|
||||||
fail_test(r#"let-env foo = "foo"; hide foo; $env.foo"#, "did you mean")
|
fail_test(r#"let-env foo = "foo"; hide foo; $env.foo"#, "did you mean")
|
||||||
@ -24,6 +32,14 @@ fn hides_def_then_redefines() -> TestResult {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_then_redefines() -> TestResult {
|
||||||
|
run_test(
|
||||||
|
r#"alias foo = echo "foo"; hide foo; alias foo = echo "foo"; foo"#,
|
||||||
|
"foo",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hides_env_then_redefines() -> TestResult {
|
fn hides_env_then_redefines() -> TestResult {
|
||||||
run_test(
|
run_test(
|
||||||
@ -64,6 +80,38 @@ fn hides_def_in_scope_4() -> TestResult {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_in_scope_1() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"alias foo = echo "foo"; do { hide foo; foo }"#,
|
||||||
|
"", // we just care if it errors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_in_scope_2() -> TestResult {
|
||||||
|
run_test(
|
||||||
|
r#"alias foo = echo "foo"; do { alias foo = echo "bar"; hide foo; foo }"#,
|
||||||
|
"foo",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_in_scope_3() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"alias foo = echo "foo"; do { hide foo; alias foo = echo "bar"; hide foo; foo }"#,
|
||||||
|
"", // we just care if it errors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_in_scope_4() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"alias foo = echo "foo"; do { alias foo = echo "bar"; hide foo; hide foo; foo }"#,
|
||||||
|
"", // we just care if it errors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hides_env_in_scope_1() -> TestResult {
|
fn hides_env_in_scope_1() -> TestResult {
|
||||||
fail_test(
|
fail_test(
|
||||||
@ -104,6 +152,14 @@ fn hide_def_twice_not_allowed() -> TestResult {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hide_alias_twice_not_allowed() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"alias foo = echo "foo"; hide foo; hide foo"#,
|
||||||
|
"did not find",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hide_env_twice_not_allowed() -> TestResult {
|
fn hide_env_twice_not_allowed() -> TestResult {
|
||||||
fail_test(r#"let-env foo = "foo"; hide foo; hide foo"#, "did not find")
|
fail_test(r#"let-env foo = "foo"; hide foo; hide foo"#, "did not find")
|
||||||
@ -125,6 +181,38 @@ fn hides_def_runs_env_2() -> TestResult {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_runs_def_1() -> TestResult {
|
||||||
|
run_test(
|
||||||
|
r#"def foo [] { "bar" }; alias foo = echo "foo"; hide foo; foo"#,
|
||||||
|
"bar",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_runs_def_2() -> TestResult {
|
||||||
|
run_test(
|
||||||
|
r#"alias foo = echo "foo"; def foo [] { "bar" }; hide foo; foo"#,
|
||||||
|
"bar",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_runs_env_1() -> TestResult {
|
||||||
|
run_test(
|
||||||
|
r#"let-env foo = "bar"; alias foo = echo "foo"; hide foo; $env.foo"#,
|
||||||
|
"bar",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_runs_env_2() -> TestResult {
|
||||||
|
run_test(
|
||||||
|
r#"alias foo = echo "foo"; let-env foo = "bar"; hide foo; $env.foo"#,
|
||||||
|
"bar",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hides_def_and_env() -> TestResult {
|
fn hides_def_and_env() -> TestResult {
|
||||||
fail_test(
|
fail_test(
|
||||||
@ -133,6 +221,30 @@ fn hides_def_and_env() -> TestResult {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_and_def() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"alias foo = echo "foo"; def foo [] { "bar" }; hide foo; hide foo; foo"#,
|
||||||
|
"", // we just care if it errors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_def_and_env_1() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"alias foo = echo "foo"; def foo [] { "foo" }; let-env foo = "bar"; hide foo; hide foo; hide foo; $env.foo"#,
|
||||||
|
"", // we just care if it errors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hides_alias_def_and_env_2() -> TestResult {
|
||||||
|
fail_test(
|
||||||
|
r#"alias foo = echo "foo"; def foo [] { "foo" }; let-env foo = "bar"; hide foo; hide foo; hide foo; foo"#,
|
||||||
|
"", // we just care if it errors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hides_def_import_1() -> TestResult {
|
fn hides_def_import_1() -> TestResult {
|
||||||
fail_test(
|
fail_test(
|
||||||
|
Loading…
Reference in New Issue
Block a user