mirror of
https://github.com/nushell/nushell.git
synced 2025-03-09 21:21:25 +01:00
<!-- if this PR closes one or more issues, you can automatically link the PR with them by using one of the [*linking keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword), e.g. - this PR should close #xxxx - fixes #xxxx you can also mention related issues, PRs or discussions! --> # Description <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> Relative: #8248 After this pr, user can define const variable inside a module.  And user can export const variables, the following screenshot shows how it works (it follows https://github.com/nushell/nushell/issues/8248#issuecomment-1637442612):  ## About the change 1. To make module support const, we need to change `parse_module_block` to support `const` keyword. 2. To suport export `const`, we need to make module tracking variables, so we add `variables` attribute to `Module` 3. During eval, the const variable may not exists in `stack`, because we don't eval `const` when we define a module, so we need to find variables which are already registered in `engine_state` ## One more thing to note about the const value. Consider the following code ``` module foo { const b = 3; export def bar [] { $b } } use foo bar const b = 4; bar ``` The result will be 3 (which is defined in module) rather than 4. I think it's expected behavior. It's something like [dynamic binding](https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding-Tips.html) vs [lexical binding](https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html) in lisp like language, and lexical binding should be right behavior which generates more predicable result, and it doesn't introduce really subtle bugs in nushell code. What if user want dynamic-binding?(For example: the example code returns `4`) There is no way to do this, user should consider passing the value as argument to custom command rather than const. ## TODO - [X] adding tests for the feature. - [X] support export const out of module to use. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> # Tests + Formatting <!-- Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # After Submitting <!-- If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. -->
81 lines
1.7 KiB
Rust
81 lines
1.7 KiB
Rust
use nu_protocol::engine::{EngineState, StateWorkingSet};
|
|
|
|
use crate::*;
|
|
|
|
pub fn create_default_context() -> EngineState {
|
|
let mut engine_state = EngineState::new();
|
|
|
|
let delta = {
|
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
|
|
|
macro_rules! bind_command {
|
|
( $( $command:expr ),* $(,)? ) => {
|
|
$( working_set.add_decl(Box::new($command)); )*
|
|
};
|
|
}
|
|
|
|
// Core
|
|
bind_command! {
|
|
Alias,
|
|
Break,
|
|
Collect,
|
|
Const,
|
|
Continue,
|
|
Def,
|
|
DefEnv,
|
|
Describe,
|
|
Do,
|
|
Echo,
|
|
ErrorMake,
|
|
ExportAlias,
|
|
ExportCommand,
|
|
ExportConst,
|
|
ExportDef,
|
|
ExportDefEnv,
|
|
ExportExtern,
|
|
ExportUse,
|
|
ExportModule,
|
|
Extern,
|
|
ExternWrapped,
|
|
For,
|
|
Hide,
|
|
HideEnv,
|
|
If,
|
|
Ignore,
|
|
Overlay,
|
|
OverlayUse,
|
|
OverlayList,
|
|
OverlayNew,
|
|
OverlayHide,
|
|
LazyMake,
|
|
Let,
|
|
Loop,
|
|
Match,
|
|
Module,
|
|
Mut,
|
|
Return,
|
|
Scope,
|
|
ScopeAliases,
|
|
ScopeCommands,
|
|
ScopeEngineStats,
|
|
ScopeModules,
|
|
ScopeVariables,
|
|
Try,
|
|
Use,
|
|
Version,
|
|
While,
|
|
};
|
|
|
|
//#[cfg(feature = "plugin")]
|
|
bind_command!(Register);
|
|
|
|
working_set.render()
|
|
};
|
|
|
|
if let Err(err) = engine_state.merge_delta(delta) {
|
|
eprintln!("Error creating default context: {err:?}");
|
|
}
|
|
|
|
engine_state
|
|
}
|