* WIP: Start laying overlays

* Rename Overlay->Module; Start adding overlay

* Revamp adding overlay

* Add overlay add tests; Disable debug print

* Fix overlay add; Add overlay remove

* Add overlay remove tests

* Add missing overlay remove file

* Add overlay list command

* (WIP?) Enable overlays for env vars

* Move OverlayFrames to ScopeFrames

* (WIP) Move everything to overlays only

ScopeFrame contains nothing but overlays now

* Fix predecls

* Fix wrong overlay id translation and aliases

* Fix broken env lookup logic

* Remove TODOs

* Add overlay add + remove for environment

* Add a few overlay tests; Fix overlay add name

* Some cleanup; Fix overlay add/remove names

* Clippy

* Fmt

* Remove walls of comments

* List overlays from stack; Add debugging flag

Currently, the engine state ordering is somehow broken.

* Fix (?) overlay list test

* Fix tests on Windows

* Fix activated overlay ordering

* Check for active overlays equality in overlay list

This removes the -p flag: Either both parser and engine will have the
same overlays, or the command will fail.

* Add merging on overlay remove

* Change help message and comment

* Add some remove-merge/discard tests

* (WIP) Track removed overlays properly

* Clippy; Fmt

* Fix getting last overlay; Fix predecls in overlays

* Remove merging; Fix re-add overwriting stuff

Also some error message tweaks.

* Fix overlay error in the engine

* Update variable_completions.rs

* Adds flags and optional arguments to view-source (#5446)

* added flags and optional arguments to view-source

* removed redundant code

* removed redundant code

* fmt

* fix bug in shell_integration (#5450)

* fix bug in shell_integration

* add some comments

* enable cd to work with directory abbreviations (#5452)

* enable cd to work with abbreviations

* add abbreviation example

* fix tests

* make it configurable

* make cd recornize symblic link (#5454)

* implement seq char command to generate single character sequence (#5453)

* add tmp code

* add seq char command

* Add split number flag in `split row` (#5434)

Signed-off-by: Yuheng Su <gipsyh.icu@gmail.com>

* Add two more overlay tests

* Add ModuleId to OverlayFrame

* Fix env conversion accidentally activating overlay

It activated overlay from permanent state prematurely which would
cause `overlay add` to misbehave.

* Remove unused parameter; Add overlay list test

* Remove added traces

* Add overlay commands examples

* Modify TODO

* Fix $nu.scope iteration

* Disallow removing default overlay

* Refactor some parser errors

* Remove last overlay if no argument

* Diversify overlay examples

* Make it possible to update overlay's module

In case the origin module updates, the overlay add loads the new module,
makes it overlay's origin and applies the changes. Before, it was
impossible to update the overlay if the module changed.

Co-authored-by: JT <547158+jntrnr@users.noreply.github.com>
Co-authored-by: pwygab <88221256+merelymyself@users.noreply.github.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
Co-authored-by: WindSoilder <WindSoilder@outlook.com>
Co-authored-by: Yuheng Su <gipsyh.icu@gmail.com>
This commit is contained in:
Jakub Žádník
2022-05-07 22:39:22 +03:00
committed by GitHub
parent 1cb449b2d1
commit 9b99b2f6ac
46 changed files with 2638 additions and 607 deletions

View File

@ -102,6 +102,34 @@ pub enum ParseError {
)]
ModuleNotFound(#[label = "module not found"] Span),
#[error("Active overlay not found.")]
#[diagnostic(code(nu::parser::active_overlay_not_found), url(docsrs))]
ActiveOverlayNotFound(#[label = "not an active overlay"] Span),
#[error("Module or overlay not found.")]
#[diagnostic(
code(nu::parser::module_or_overlay_not_found),
url(docsrs),
help("Requires either an existing overlay, a module, or an import pattern defining a module.")
)]
ModuleOrOverlayNotFound(#[label = "not a module or an overlay"] Span),
#[error("Cannot remove the last overlay.")]
#[diagnostic(
code(nu::parser::cant_remove_last_overlay),
url(docsrs),
help("At least one overlay must always be active.")
)]
CantRemoveLastOverlay(#[label = "this is the last overlay, can't remove it"] Span),
#[error("Cannot remove default overlay.")]
#[diagnostic(
code(nu::parser::cant_remove_default_overlay),
url(docsrs),
help("'{0}' is a default overlay. Default overlays cannot be removed.")
)]
CantRemoveDefaultOverlay(String, #[label = "can't remove overlay"] Span),
#[error("Not found.")]
#[diagnostic(code(nu::parser::not_found), url(docsrs))]
NotFound(#[label = "did not find anything under this name"] Span),
@ -245,6 +273,15 @@ pub enum ParseError {
#[diagnostic(code(nu::parser::file_not_found), url(docsrs))]
FileNotFound(String, #[label("File not found: {0}")] Span),
/// Error while trying to read a file
///
/// ## Resolution
///
/// The error will show the result from a file operation
#[error("Error trying to read file")]
#[diagnostic(code(nu::shell::error_reading_file), url(docsrs))]
ReadingFile(String, #[label("{0}")] Span),
#[error("{0}")]
#[diagnostic()]
LabeledError(String, String, #[label("{1}")] Span),
@ -268,6 +305,10 @@ impl ParseError {
ParseError::VariableNotFound(s) => *s,
ParseError::VariableNotValid(s) => *s,
ParseError::ModuleNotFound(s) => *s,
ParseError::ModuleOrOverlayNotFound(s) => *s,
ParseError::ActiveOverlayNotFound(s) => *s,
ParseError::CantRemoveLastOverlay(s) => *s,
ParseError::CantRemoveDefaultOverlay(_, s) => *s,
ParseError::NotFound(s) => *s,
ParseError::DuplicateCommandDef(s) => *s,
ParseError::UnknownCommand(s) => *s,
@ -297,6 +338,7 @@ impl ParseError {
ParseError::SourcedFileNotFound(_, s) => *s,
ParseError::RegisteredFileNotFound(_, s) => *s,
ParseError::FileNotFound(_, s) => *s,
ParseError::ReadingFile(_, s) => *s,
ParseError::LabeledError(_, _, s) => *s,
}
}

View File

@ -40,7 +40,7 @@ impl Command for KnownExternal {
let call_span = call.span();
let head_span = call.head;
let decl_id = engine_state
.find_decl("run-external".as_bytes())
.find_decl("run-external".as_bytes(), &[])
.ok_or(ShellError::ExternalNotSupported(head_span))?;
let command = engine_state.get_decl(decl_id);

View File

@ -4,8 +4,8 @@ use nu_protocol::{
Argument, Block, Call, Expr, Expression, ImportPattern, ImportPatternHead,
ImportPatternMember, Pipeline,
},
engine::StateWorkingSet,
span, Exportable, Overlay, PositionalArg, Span, SyntaxShape, Type,
engine::{StateWorkingSet, DEFAULT_OVERLAY_NAME},
span, Exportable, Module, PositionalArg, Span, SyntaxShape, Type,
};
use std::collections::HashSet;
use std::path::{Path, PathBuf};
@ -1013,7 +1013,7 @@ pub fn parse_module_block(
working_set: &mut StateWorkingSet,
span: Span,
expand_aliases_denylist: &[usize],
) -> (Block, Overlay, Option<ParseError>) {
) -> (Block, Module, Option<ParseError>) {
let mut error = None;
working_set.enter_scope();
@ -1037,7 +1037,7 @@ pub fn parse_module_block(
}
}
let mut overlay = Overlay::from_span(span);
let mut module = Module::from_span(span);
let block: Block = output
.block
@ -1093,13 +1093,13 @@ pub fn parse_module_block(
match exportable {
Some(Exportable::Decl(decl_id)) => {
overlay.add_decl(name, decl_id);
module.add_decl(name, decl_id);
}
Some(Exportable::EnvVar(block_id)) => {
overlay.add_env_var(name, block_id);
module.add_env_var(name, block_id);
}
Some(Exportable::Alias(alias_id)) => {
overlay.add_alias(name, alias_id);
module.add_alias(name, alias_id);
}
None => {} // None should always come with error from parse_export()
}
@ -1130,7 +1130,7 @@ pub fn parse_module_block(
working_set.exit_scope();
(block, overlay, error)
(block, module, error)
}
pub fn parse_module(
@ -1175,12 +1175,12 @@ pub fn parse_module(
let block_span = Span { start, end };
let (block, overlay, err) =
let (block, module, err) =
parse_module_block(working_set, block_span, expand_aliases_denylist);
error = error.or(err);
let block_id = working_set.add_block(block);
let _ = working_set.add_overlay(&module_name, overlay);
let _ = working_set.add_module(&module_name, module);
let block_expr = Expression {
expr: Expr::Block(block_id),
@ -1286,7 +1286,7 @@ pub fn parse_use(
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: Import pattern positional is not import pattern".into(),
call_span,
expr.span,
)),
);
}
@ -1306,11 +1306,11 @@ pub fn parse_use(
// TODO: Add checking for importing too long import patterns, e.g.:
// > use spam foo non existent names here do not throw error
let (import_pattern, overlay) =
if let Some(overlay_id) = working_set.find_overlay(&import_pattern.head.name) {
(import_pattern, working_set.get_overlay(overlay_id).clone())
let (import_pattern, module) =
if let Some(module_id) = working_set.find_module(&import_pattern.head.name) {
(import_pattern, working_set.get_module(module_id).clone())
} else {
// TODO: Do not close over when loading module from file
// TODO: Do not close over when loading module from file?
// It could be a file
let (module_filename, err) =
@ -1338,7 +1338,7 @@ pub fn parse_use(
working_set.add_file(module_filename, &contents);
let span_end = working_set.next_span_start();
let (block, overlay, err) = parse_module_block(
let (block, module, err) = parse_module_block(
working_set,
Span::new(span_start, span_end),
expand_aliases_denylist,
@ -1346,19 +1346,19 @@ pub fn parse_use(
error = error.or(err);
let _ = working_set.add_block(block);
let overlay_id = working_set.add_overlay(&module_name, overlay.clone());
let module_id = working_set.add_module(&module_name, module.clone());
(
ImportPattern {
head: ImportPatternHead {
name: module_name.into(),
id: Some(overlay_id),
id: Some(module_id),
span: spans[1],
},
members: import_pattern.members,
hidden: HashSet::new(),
},
overlay,
module,
)
} else {
return (
@ -1377,7 +1377,7 @@ pub fn parse_use(
let mut import_pattern = ImportPattern::new();
import_pattern.head.span = spans[1];
(import_pattern, Overlay::new())
(import_pattern, Module::new())
}
} else {
return (garbage_pipeline(spans), Some(ParseError::NonUtf8(spans[1])));
@ -1386,21 +1386,21 @@ pub fn parse_use(
let (decls_to_use, aliases_to_use) = if import_pattern.members.is_empty() {
(
overlay.decls_with_head(&import_pattern.head.name),
overlay.aliases_with_head(&import_pattern.head.name),
module.decls_with_head(&import_pattern.head.name),
module.aliases_with_head(&import_pattern.head.name),
)
} else {
match &import_pattern.members[0] {
ImportPatternMember::Glob { .. } => (overlay.decls(), overlay.aliases()),
ImportPatternMember::Glob { .. } => (module.decls(), module.aliases()),
ImportPatternMember::Name { name, span } => {
let mut decl_output = vec![];
let mut alias_output = vec![];
if let Some(id) = overlay.get_decl_id(name) {
if let Some(id) = module.get_decl_id(name) {
decl_output.push((name.clone(), id));
} else if let Some(id) = overlay.get_alias_id(name) {
} else if let Some(id) = module.get_alias_id(name) {
alias_output.push((name.clone(), id));
} else if !overlay.has_env_var(name) {
} else if !module.has_env_var(name) {
error = error.or(Some(ParseError::ExportNotFound(*span)))
}
@ -1411,11 +1411,11 @@ pub fn parse_use(
let mut alias_output = vec![];
for (name, span) in names {
if let Some(id) = overlay.get_decl_id(name) {
if let Some(id) = module.get_decl_id(name) {
decl_output.push((name.clone(), id));
} else if let Some(id) = overlay.get_alias_id(name) {
} else if let Some(id) = module.get_alias_id(name) {
alias_output.push((name.clone(), id));
} else if !overlay.has_env_var(name) {
} else if !module.has_env_var(name) {
error = error.or(Some(ParseError::ExportNotFound(*span)));
break;
}
@ -1426,7 +1426,7 @@ pub fn parse_use(
}
};
// Extend the current scope with the module's overlay
// Extend the current scope with the module's exportables
working_set.use_decls(decls_to_use);
working_set.use_aliases(aliases_to_use);
@ -1542,26 +1542,26 @@ pub fn parse_hide(
error = error.or(err);
}
let (is_module, overlay) =
if let Some(overlay_id) = working_set.find_overlay(&import_pattern.head.name) {
(true, working_set.get_overlay(overlay_id).clone())
let (is_module, module) =
if let Some(module_id) = working_set.find_module(&import_pattern.head.name) {
(true, working_set.get_module(module_id).clone())
} else if import_pattern.members.is_empty() {
// The pattern head can be:
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);
let mut module = Module::new();
module.add_alias(&import_pattern.head.name, id);
(false, overlay)
(false, module)
} else if let Some(id) = working_set.find_decl(&import_pattern.head.name) {
// a custom command,
let mut overlay = Overlay::new();
overlay.add_decl(&import_pattern.head.name, id);
let mut module = Module::new();
module.add_decl(&import_pattern.head.name, id);
(false, overlay)
(false, module)
} else {
// , or it could be an env var (handled by the engine)
(false, Overlay::new())
(false, Module::new())
}
} else {
return (
@ -1574,28 +1574,27 @@ pub fn parse_hide(
let (aliases_to_hide, decls_to_hide) = if import_pattern.members.is_empty() {
if is_module {
(
overlay.alias_names_with_head(&import_pattern.head.name),
overlay.decl_names_with_head(&import_pattern.head.name),
module.alias_names_with_head(&import_pattern.head.name),
module.decl_names_with_head(&import_pattern.head.name),
)
} else {
(overlay.alias_names(), overlay.decl_names())
(module.alias_names(), module.decl_names())
}
} else {
match &import_pattern.members[0] {
ImportPatternMember::Glob { .. } => (overlay.alias_names(), overlay.decl_names()),
ImportPatternMember::Glob { .. } => (module.alias_names(), module.decl_names()),
ImportPatternMember::Name { name, span } => {
let mut aliases = vec![];
let mut decls = vec![];
if let Some(item) =
overlay.alias_name_with_head(name, &import_pattern.head.name)
if let Some(item) = module.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)
module.decl_name_with_head(name, &import_pattern.head.name)
{
decls.push(item);
} else if !overlay.has_env_var(name) {
} else if !module.has_env_var(name) {
error = error.or(Some(ParseError::ExportNotFound(*span)));
}
@ -1607,14 +1606,14 @@ pub fn parse_hide(
for (name, span) in names {
if let Some(item) =
overlay.alias_name_with_head(name, &import_pattern.head.name)
module.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)
module.decl_name_with_head(name, &import_pattern.head.name)
{
decls.push(item);
} else if !overlay.has_env_var(name) {
} else if !module.has_env_var(name) {
error = error.or(Some(ParseError::ExportNotFound(*span)));
break;
}
@ -1673,6 +1672,445 @@ pub fn parse_hide(
}
}
pub fn parse_overlay(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
if working_set.get_span_contents(spans[0]) != b"overlay" {
return (
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: Wrong call name for 'overlay' command".into(),
span(spans),
)),
);
}
if spans.len() > 1 {
let subcommand = working_set.get_span_contents(spans[1]);
match subcommand {
b"add" => {
return parse_overlay_add(working_set, spans, expand_aliases_denylist);
}
b"list" => {
// TODO: Abstract this code blob, it's repeated all over the place:
let call = match working_set.find_decl(b"overlay list") {
Some(decl_id) => {
let (call, mut err) = parse_internal_call(
working_set,
span(&spans[..2]),
if spans.len() > 2 { &spans[2..] } else { &[] },
decl_id,
expand_aliases_denylist,
);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
err = check_call(call_span, &decl.signature(), &call).or(err);
if err.is_some() || call.has_flag("help") {
return (
Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: call_span,
ty: Type::Any,
custom_completion: None,
}]),
err,
);
}
call
}
None => {
return (
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: 'overlay' declaration not found".into(),
span(spans),
)),
)
}
};
return (
Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
ty: Type::Any,
custom_completion: None,
}]),
None,
);
}
b"remove" => {
return parse_overlay_remove(working_set, spans, expand_aliases_denylist);
}
_ => { /* continue parsing overlay */ }
}
}
let call = match working_set.find_decl(b"overlay") {
Some(decl_id) => {
let (call, mut err) = parse_internal_call(
working_set,
spans[0],
&spans[1..],
decl_id,
expand_aliases_denylist,
);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
err = check_call(call_span, &decl.signature(), &call).or(err);
if err.is_some() || call.has_flag("help") {
return (
Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: call_span,
ty: Type::Any,
custom_completion: None,
}]),
err,
);
}
call
}
None => {
return (
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: 'overlay' declaration not found".into(),
span(spans),
)),
)
}
};
(
Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
ty: Type::Any,
custom_completion: None,
}]),
None,
)
}
pub fn parse_overlay_add(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
if spans.len() > 1 && working_set.get_span_contents(span(&spans[0..2])) != b"overlay add" {
return (
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: Wrong call name for 'overlay add' command".into(),
span(spans),
)),
);
}
// TODO: Allow full import pattern as argument (requires custom naming of module/overlay)
let (call, call_span) = match working_set.find_decl(b"overlay add") {
Some(decl_id) => {
let (call, mut err) = parse_internal_call(
working_set,
span(&spans[0..2]),
&spans[2..],
decl_id,
expand_aliases_denylist,
);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
err = check_call(call_span, &decl.signature(), &call).or(err);
if err.is_some() || call.has_flag("help") {
return (
Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: call_span,
ty: Type::Any,
custom_completion: None,
}]),
err,
);
}
(call, call_span)
}
None => {
return (
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: 'overlay add' declaration not found".into(),
span(spans),
)),
)
}
};
let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) {
if let Some(s) = expr.as_string() {
(s, expr.span)
} else {
return (
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: Module name not a string".into(),
expr.span,
)),
);
}
} else {
return (
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: Missing required positional after call parsing".into(),
call_span,
)),
);
};
let pipeline = Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
ty: Type::Any,
custom_completion: None,
}]);
// TODO: Add support for it -- needs to play well with overlay remove
let has_prefix = false; //call.has_flag("prefix");
let cwd = working_set.get_cwd();
let mut error = None;
let result = if let Some(module_id) = working_set.find_overlay_origin(overlay_name.as_bytes()) {
// Activate existing overlay
if let Some(new_module_id) = working_set.find_module(overlay_name.as_bytes()) {
if module_id == new_module_id {
Some((overlay_name, Module::new(), module_id))
} else {
// The origin module of an overlay changed => update it
Some((
overlay_name,
working_set.get_module(new_module_id).clone(),
new_module_id,
))
}
} else {
Some((overlay_name, Module::new(), module_id))
}
} else {
// Create a new overlay from a module
if let Some(module_id) =
// the name is a module
working_set.find_module(overlay_name.as_bytes())
{
Some((
overlay_name,
working_set.get_module(module_id).clone(),
module_id,
))
} else {
// try if the name is a file
if let Ok(module_filename) =
String::from_utf8(trim_quotes(overlay_name.as_bytes()).to_vec())
{
if let Some(module_path) =
find_in_dirs(&module_filename, working_set, &cwd, LIB_DIRS_ENV)
{
let overlay_name = if let Some(stem) = module_path.file_stem() {
stem.to_string_lossy().to_string()
} else {
return (
pipeline,
Some(ParseError::ModuleOrOverlayNotFound(spans[1])),
);
};
if let Ok(contents) = std::fs::read(module_path) {
let span_start = working_set.next_span_start();
working_set.add_file(module_filename, &contents);
let span_end = working_set.next_span_start();
let (block, module, err) = parse_module_block(
working_set,
Span::new(span_start, span_end),
expand_aliases_denylist,
);
error = error.or(err);
let _ = working_set.add_block(block);
let module_id = working_set.add_module(&overlay_name, module.clone());
Some((overlay_name, module, module_id))
} else {
return (
pipeline,
Some(ParseError::ModuleOrOverlayNotFound(spans[1])),
);
}
} else {
error = error.or(Some(ParseError::ModuleOrOverlayNotFound(overlay_name_span)));
None
}
} else {
return (garbage_pipeline(spans), Some(ParseError::NonUtf8(spans[1])));
}
}
};
if let Some((name, module, module_id)) = result {
let (decls_to_lay, aliases_to_lay) = if has_prefix {
(
module.decls_with_head(name.as_bytes()),
module.aliases_with_head(name.as_bytes()),
)
} else {
(module.decls(), module.aliases())
};
working_set.add_overlay(
name.as_bytes().to_vec(),
module_id,
decls_to_lay,
aliases_to_lay,
);
}
(pipeline, error)
}
pub fn parse_overlay_remove(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
if spans.len() > 1 && working_set.get_span_contents(span(&spans[0..2])) != b"overlay remove" {
return (
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: Wrong call name for 'overlay remove' command".into(),
span(spans),
)),
);
}
let call = match working_set.find_decl(b"overlay remove") {
Some(decl_id) => {
let (call, mut err) = parse_internal_call(
working_set,
span(&spans[0..2]),
&spans[2..],
decl_id,
expand_aliases_denylist,
);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
err = check_call(call_span, &decl.signature(), &call).or(err);
if err.is_some() || call.has_flag("help") {
return (
Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: call_span,
ty: Type::Any,
custom_completion: None,
}]),
err,
);
}
call
}
None => {
return (
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: 'overlay remove' declaration not found".into(),
span(spans),
)),
)
}
};
let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) {
if let Some(s) = expr.as_string() {
(s, expr.span)
} else {
return (
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: Module name not a string".into(),
expr.span,
)),
);
}
} else {
(
String::from_utf8_lossy(working_set.last_overlay_name()).to_string(),
call.head,
)
};
let pipeline = Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
ty: Type::Any,
custom_completion: None,
}]);
if overlay_name == DEFAULT_OVERLAY_NAME {
return (
pipeline,
Some(ParseError::CantRemoveDefaultOverlay(
overlay_name,
overlay_name_span,
)),
);
}
if !working_set
.unique_overlay_names()
.contains(&overlay_name.as_bytes().to_vec())
{
return (
pipeline,
Some(ParseError::ActiveOverlayNotFound(overlay_name_span)),
);
}
if working_set.num_overlays() < 2 {
return (
pipeline,
Some(ParseError::CantRemoveLastOverlay(overlay_name_span)),
);
}
// let original_module = if call.has_flag("discard") {
// None
// } else if let Some(module_id) = working_set.find_module(overlay_name.as_bytes()) {
// // TODO: Remove clone
// Some(working_set.get_module(module_id).clone())
// } else {
// Some(Module::new())
// };
working_set.remove_overlay(overlay_name.as_bytes());
(pipeline, None)
}
pub fn parse_let(
working_set: &mut StateWorkingSet,
spans: &[Span],
@ -2108,7 +2546,7 @@ pub fn parse_register(
)
}
fn find_in_dirs(
pub fn find_in_dirs(
filename: &str,
working_set: &StateWorkingSet,
cwd: &str,
@ -2120,7 +2558,7 @@ fn find_in_dirs(
let path = Path::new(filename);
if path.is_relative() {
if let Some(lib_dirs) = working_set.get_env(dirs_env) {
if let Some(lib_dirs) = working_set.get_env_var(dirs_env) {
if let Ok(dirs) = lib_dirs.as_list() {
for lib_dir in dirs {
if let Ok(dir) = lib_dir.as_path() {

View File

@ -18,7 +18,8 @@ use nu_protocol::{
};
use crate::parse_keywords::{
parse_alias, parse_def, parse_def_predecl, parse_hide, parse_let, parse_module, parse_use,
parse_alias, parse_def, parse_def_predecl, parse_hide, parse_let, parse_module, parse_overlay,
parse_use,
};
use log::trace;
@ -2700,7 +2701,7 @@ pub fn parse_import_pattern(
);
};
let maybe_overlay_id = working_set.find_overlay(&head);
let maybe_module_id = working_set.find_module(&head);
let (import_pattern, err) = if let Some(tail_span) = spans.get(1) {
// FIXME: expand this to handle deeper imports once we support module imports
@ -2710,7 +2711,7 @@ pub fn parse_import_pattern(
ImportPattern {
head: ImportPatternHead {
name: head,
id: maybe_overlay_id,
id: maybe_module_id,
span: *head_span,
},
members: vec![ImportPatternMember::Glob { span: *tail_span }],
@ -2743,7 +2744,7 @@ pub fn parse_import_pattern(
ImportPattern {
head: ImportPatternHead {
name: head,
id: maybe_overlay_id,
id: maybe_module_id,
span: *head_span,
},
members: vec![ImportPatternMember::List { names: output }],
@ -2756,7 +2757,7 @@ pub fn parse_import_pattern(
ImportPattern {
head: ImportPatternHead {
name: head,
id: maybe_overlay_id,
id: maybe_module_id,
span: *head_span,
},
members: vec![],
@ -2771,7 +2772,7 @@ pub fn parse_import_pattern(
ImportPattern {
head: ImportPatternHead {
name: head,
id: maybe_overlay_id,
id: maybe_module_id,
span: *head_span,
},
members: vec![ImportPatternMember::Name {
@ -2788,7 +2789,7 @@ pub fn parse_import_pattern(
ImportPattern {
head: ImportPatternHead {
name: head,
id: maybe_overlay_id,
id: maybe_module_id,
span: *head_span,
},
members: vec![],
@ -4404,6 +4405,31 @@ pub fn parse_expression(
.0,
Some(ParseError::BuiltinCommandInPipeline("use".into(), spans[0])),
),
b"overlay" => {
if spans.len() > 1 && working_set.get_span_contents(spans[1]) == b"list" {
// whitelist 'overlay list'
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
} else {
(
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
.0,
Some(ParseError::BuiltinCommandInPipeline(
"overlay".into(),
spans[0],
)),
)
}
}
b"source" => (
parse_call(
working_set,
@ -4558,6 +4584,7 @@ pub fn parse_builtin_commands(
b"alias" => parse_alias(working_set, &lite_command.parts, expand_aliases_denylist),
b"module" => parse_module(working_set, &lite_command.parts, expand_aliases_denylist),
b"use" => parse_use(working_set, &lite_command.parts, expand_aliases_denylist),
b"overlay" => parse_overlay(working_set, &lite_command.parts, expand_aliases_denylist),
b"source" => parse_source(working_set, &lite_command.parts, expand_aliases_denylist),
b"export" => {
if let Some(decl_id) = working_set.find_decl(b"alias") {