nushell/crates/nu-protocol/src/engine/stack.rs

825 lines
30 KiB
Rust
Raw Normal View History

IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
use crate::{
engine::{
Internal representation (IR) compiler and evaluator (#13330) # Description This PR adds an internal representation language to Nushell, offering an alternative evaluator based on simple instructions, stream-containing registers, and indexed control flow. The number of registers required is determined statically at compile-time, and the fixed size required is allocated upon entering the block. Each instruction is associated with a span, which makes going backwards from IR instructions to source code very easy. Motivations for IR: 1. **Performance.** By simplifying the evaluation path and making it more cache-friendly and branch predictor-friendly, code that does a lot of computation in Nushell itself can be sped up a decent bit. Because the IR is fairly easy to reason about, we can also implement optimization passes in the future to eliminate and simplify code. 2. **Correctness.** The instructions mostly have very simple and easily-specified behavior, so hopefully engine changes are a little bit easier to reason about, and they can be specified in a more formal way at some point. I have made an effort to document each of the instructions in the docs for the enum itself in a reasonably specific way. Some of the errors that would have happened during evaluation before are now moved to the compilation step instead, because they don't make sense to check during evaluation. 3. **As an intermediate target.** This is a good step for us to bring the [`new-nu-parser`](https://github.com/nushell/new-nu-parser) in at some point, as code generated from new AST can be directly compared to code generated from old AST. If the IR code is functionally equivalent, it will behave the exact same way. 4. **Debugging.** With a little bit more work, we can probably give control over advancing the virtual machine that `IrBlock`s run on to some sort of external driver, making things like breakpoints and single stepping possible. Tools like `view ir` and [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir) make it easier than before to see what exactly is going on with your Nushell code. The goal is to eventually replace the AST evaluator entirely, once we're sure it's working just as well. You can help dogfood this by running Nushell with `$env.NU_USE_IR` set to some value. The environment variable is checked when Nushell starts, so config runs with IR, or it can also be set on a line at the REPL to change it dynamically. It is also checked when running `do` in case within a script you want to just run a specific piece of code with or without IR. # Example ```nushell view ir { |data| mut sum = 0 for n in $data { $sum += $n } $sum } ``` ```gas # 3 registers, 19 instructions, 0 bytes of data 0: load-literal %0, int(0) 1: store-variable var 904, %0 # let 2: drain %0 3: drop %0 4: load-variable %1, var 903 5: iterate %0, %1, end 15 # for, label(1), from(14:) 6: store-variable var 905, %0 7: load-variable %0, var 904 8: load-variable %2, var 905 9: binary-op %0, Math(Plus), %2 10: span %0 11: store-variable var 904, %0 12: load-literal %0, nothing 13: drain %0 14: jump 5 15: drop %0 # label(0), from(5:) 16: drain %0 17: load-variable %0, var 904 18: return %0 ``` # Benchmarks All benchmarks run on a base model Mac Mini M1. ## Iterative Fibonacci sequence This is about as best case as possible, making use of the much faster control flow. Most code will not experience a speed improvement nearly this large. ```nushell def fib [n: int] { mut a = 0 mut b = 1 for _ in 2..=$n { let c = $a + $b $a = $b $b = $c } $b } use std bench bench { 0..50 | each { |n| fib $n } } ``` IR disabled: ``` ╭───────┬─────────────────╮ │ mean │ 1ms 924µs 665ns │ │ min │ 1ms 700µs 83ns │ │ max │ 3ms 450µs 125ns │ │ std │ 395µs 759ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` IR enabled: ``` ╭───────┬─────────────────╮ │ mean │ 452µs 820ns │ │ min │ 427µs 417ns │ │ max │ 540µs 167ns │ │ std │ 17µs 158ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` ![explore ir view](https://github.com/nushell/nushell/assets/10729/d7bccc03-5222-461c-9200-0dce71b83b83) ## [gradient_benchmark_no_check.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/gradient_benchmark_no_check.nu) IR disabled: ``` ╭───┬──────────────────╮ │ 0 │ 27ms 929µs 958ns │ │ 1 │ 21ms 153µs 459ns │ │ 2 │ 18ms 639µs 666ns │ │ 3 │ 19ms 554µs 583ns │ │ 4 │ 13ms 383µs 375ns │ │ 5 │ 11ms 328µs 208ns │ │ 6 │ 5ms 659µs 542ns │ ╰───┴──────────────────╯ ``` IR enabled: ``` ╭───┬──────────────────╮ │ 0 │ 22ms 662µs │ │ 1 │ 17ms 221µs 792ns │ │ 2 │ 14ms 786µs 708ns │ │ 3 │ 13ms 876µs 834ns │ │ 4 │ 13ms 52µs 875ns │ │ 5 │ 11ms 269µs 666ns │ │ 6 │ 6ms 942µs 500ns │ ╰───┴──────────────────╯ ``` ## [random-bytes.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/random-bytes.nu) I got pretty random results out of this benchmark so I decided not to include it. Not clear why. # User-Facing Changes - IR compilation errors may appear even if the user isn't evaluating with IR. - IR evaluation can be enabled by setting the `NU_USE_IR` environment variable to any value. - New command `view ir` pretty-prints the IR for a block, and `view ir --json` can be piped into an external tool like [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir). # Tests + Formatting All tests are passing with `NU_USE_IR=1`, and I've added some more eval tests to compare the results for some very core operations. I will probably want to add some more so we don't have to always check `NU_USE_IR=1 toolkit test --workspace` on a regular basis. # After Submitting - [ ] release notes - [ ] further documentation of instructions? - [ ] post-release: publish `nu_plugin_explore_ir`
2024-07-11 00:33:59 +00:00
ArgumentStack, EngineState, ErrorHandlerStack, Redirection, StackCallArgGuard,
StackCaptureGuard, StackIoGuard, StackOutDest, DEFAULT_OVERLAY_NAME,
},
Config, OutDest, ShellError, Span, Value, VarId, ENV_VARIABLE_ID, NU_VARIABLE_ID,
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
};
use std::{
collections::{HashMap, HashSet},
Add Stack::stdout_file and Stack::stderr_file to capture stdout/-err of external commands (#12857) # Description In this PR I added two new methods to `Stack`, `stdout_file` and `stderr_file`. These two modify the inner `StackOutDest` and set a `File` into the `stdout` and `stderr` respectively. Different to the `push_redirection` methods, these do not require to hold a guard up all the time but require ownership of the stack. This is primarly useful for applications that use `nu` as a language but not the `nushell`. This PR replaces my first attempt #12851 to add a way to capture stdout/-err of external commands. Capturing the stdout without having to write into a file is possible with crates like [`os_pipe`](https://docs.rs/os_pipe), an example for this is given in the doc comment of the `stdout_file` command and can be executed as a doctest (although it doesn't validate that you actually got any data). This implementation takes `File` as input to make it easier to implement on different operating systems without having to worry about `OwnedHandle` or `OwnedFd`. Also this doesn't expose any use `os_pipe` to not leak its types into this API, making it depend on it. As in my previous attempt, @IanManske guided me here. # User-Facing Changes This change has no effect on `nushell` and therefore no user-facing changes. # Tests + Formatting This only exposes a new way of using already existing code and has therefore no further testing. The doctest succeeds on my machine at least (x86 Windows, 64 Bit). # After Submitting All the required documentation is already part of this PR.
2024-05-13 18:48:38 +00:00
fs::File,
sync::Arc,
};
2021-08-15 22:33:34 +00:00
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
/// Environment variables per overlay
pub type EnvVars = HashMap<String, HashMap<String, Value>>;
/// A runtime value stack used during evaluation
///
/// A note on implementation:
///
/// We previously set up the stack in a traditional way, where stack frames had parents which would
/// represent other frames that you might return to when exiting a function.
///
/// While experimenting with blocks, we found that we needed to have closure captures of variables
/// seen outside of the blocks, so that they blocks could be run in a way that was both thread-safe
/// and followed the restrictions for closures applied to iterators. The end result left us with
/// closure-captured single stack frames that blocks could see.
///
/// Blocks make up the only scope and stack definition abstraction in Nushell. As a result, we were
/// creating closure captures at any point we wanted to have a Block value we could safely evaluate
/// in any context. This meant that the parents were going largely unused, with captured variables
/// taking their place. The end result is this, where we no longer have separate frames, but instead
/// use the Stack as a way of representing the local and closure-captured state.
2021-10-25 04:01:02 +00:00
#[derive(Debug, Clone)]
2021-10-25 20:04:23 +00:00
pub struct Stack {
/// Variables
Move variables to var stack (#8604) # Description This moves the representation of variables on the stack to a Vec, which more closely resembles a stack. For small numbers of variables live at any one point, this tends to be more efficient than a HashMap. Having a stack-like vector also allows us to remember a stack position, temporarily push variables on, then quickly drop the stack back to the original size when we're done. We'll need this capability to allow matching inside of conditions. On this mac, a simple run of: `timeit { mut x = 1; while $x < 1000000 { $x += 1 } }` Went from 1 sec 86 ms, down to 1 sec 2 ms. Clearly, we have a lot more ground we can make up in looping speed 😅 but it's nice that for fixing this to make matching easier, we also get a win in terms of lookup speed for small numbers of variables. # User-Facing Changes Likely users won't (hopefully) see any negative impact and may even see a small positive impact. # 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` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass > **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.
2023-03-24 23:56:45 +00:00
pub vars: Vec<(VarId, Value)>,
/// Environment variables arranged as a stack to be able to recover values from parent scopes
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
pub env_vars: Vec<Arc<EnvVars>>,
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
/// Tells which environment variables from engine state are hidden, per overlay.
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
pub env_hidden: Arc<HashMap<String, HashSet<String>>>,
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
/// List of active overlays
pub active_overlays: Vec<String>,
Internal representation (IR) compiler and evaluator (#13330) # Description This PR adds an internal representation language to Nushell, offering an alternative evaluator based on simple instructions, stream-containing registers, and indexed control flow. The number of registers required is determined statically at compile-time, and the fixed size required is allocated upon entering the block. Each instruction is associated with a span, which makes going backwards from IR instructions to source code very easy. Motivations for IR: 1. **Performance.** By simplifying the evaluation path and making it more cache-friendly and branch predictor-friendly, code that does a lot of computation in Nushell itself can be sped up a decent bit. Because the IR is fairly easy to reason about, we can also implement optimization passes in the future to eliminate and simplify code. 2. **Correctness.** The instructions mostly have very simple and easily-specified behavior, so hopefully engine changes are a little bit easier to reason about, and they can be specified in a more formal way at some point. I have made an effort to document each of the instructions in the docs for the enum itself in a reasonably specific way. Some of the errors that would have happened during evaluation before are now moved to the compilation step instead, because they don't make sense to check during evaluation. 3. **As an intermediate target.** This is a good step for us to bring the [`new-nu-parser`](https://github.com/nushell/new-nu-parser) in at some point, as code generated from new AST can be directly compared to code generated from old AST. If the IR code is functionally equivalent, it will behave the exact same way. 4. **Debugging.** With a little bit more work, we can probably give control over advancing the virtual machine that `IrBlock`s run on to some sort of external driver, making things like breakpoints and single stepping possible. Tools like `view ir` and [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir) make it easier than before to see what exactly is going on with your Nushell code. The goal is to eventually replace the AST evaluator entirely, once we're sure it's working just as well. You can help dogfood this by running Nushell with `$env.NU_USE_IR` set to some value. The environment variable is checked when Nushell starts, so config runs with IR, or it can also be set on a line at the REPL to change it dynamically. It is also checked when running `do` in case within a script you want to just run a specific piece of code with or without IR. # Example ```nushell view ir { |data| mut sum = 0 for n in $data { $sum += $n } $sum } ``` ```gas # 3 registers, 19 instructions, 0 bytes of data 0: load-literal %0, int(0) 1: store-variable var 904, %0 # let 2: drain %0 3: drop %0 4: load-variable %1, var 903 5: iterate %0, %1, end 15 # for, label(1), from(14:) 6: store-variable var 905, %0 7: load-variable %0, var 904 8: load-variable %2, var 905 9: binary-op %0, Math(Plus), %2 10: span %0 11: store-variable var 904, %0 12: load-literal %0, nothing 13: drain %0 14: jump 5 15: drop %0 # label(0), from(5:) 16: drain %0 17: load-variable %0, var 904 18: return %0 ``` # Benchmarks All benchmarks run on a base model Mac Mini M1. ## Iterative Fibonacci sequence This is about as best case as possible, making use of the much faster control flow. Most code will not experience a speed improvement nearly this large. ```nushell def fib [n: int] { mut a = 0 mut b = 1 for _ in 2..=$n { let c = $a + $b $a = $b $b = $c } $b } use std bench bench { 0..50 | each { |n| fib $n } } ``` IR disabled: ``` ╭───────┬─────────────────╮ │ mean │ 1ms 924µs 665ns │ │ min │ 1ms 700µs 83ns │ │ max │ 3ms 450µs 125ns │ │ std │ 395µs 759ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` IR enabled: ``` ╭───────┬─────────────────╮ │ mean │ 452µs 820ns │ │ min │ 427µs 417ns │ │ max │ 540µs 167ns │ │ std │ 17µs 158ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` ![explore ir view](https://github.com/nushell/nushell/assets/10729/d7bccc03-5222-461c-9200-0dce71b83b83) ## [gradient_benchmark_no_check.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/gradient_benchmark_no_check.nu) IR disabled: ``` ╭───┬──────────────────╮ │ 0 │ 27ms 929µs 958ns │ │ 1 │ 21ms 153µs 459ns │ │ 2 │ 18ms 639µs 666ns │ │ 3 │ 19ms 554µs 583ns │ │ 4 │ 13ms 383µs 375ns │ │ 5 │ 11ms 328µs 208ns │ │ 6 │ 5ms 659µs 542ns │ ╰───┴──────────────────╯ ``` IR enabled: ``` ╭───┬──────────────────╮ │ 0 │ 22ms 662µs │ │ 1 │ 17ms 221µs 792ns │ │ 2 │ 14ms 786µs 708ns │ │ 3 │ 13ms 876µs 834ns │ │ 4 │ 13ms 52µs 875ns │ │ 5 │ 11ms 269µs 666ns │ │ 6 │ 6ms 942µs 500ns │ ╰───┴──────────────────╯ ``` ## [random-bytes.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/random-bytes.nu) I got pretty random results out of this benchmark so I decided not to include it. Not clear why. # User-Facing Changes - IR compilation errors may appear even if the user isn't evaluating with IR. - IR evaluation can be enabled by setting the `NU_USE_IR` environment variable to any value. - New command `view ir` pretty-prints the IR for a block, and `view ir --json` can be piped into an external tool like [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir). # Tests + Formatting All tests are passing with `NU_USE_IR=1`, and I've added some more eval tests to compare the results for some very core operations. I will probably want to add some more so we don't have to always check `NU_USE_IR=1 toolkit test --workspace` on a regular basis. # After Submitting - [ ] release notes - [ ] further documentation of instructions? - [ ] post-release: publish `nu_plugin_explore_ir`
2024-07-11 00:33:59 +00:00
/// Argument stack for IR evaluation
pub arguments: ArgumentStack,
/// Error handler stack for IR evaluation
pub error_handlers: ErrorHandlerStack,
/// Set true to always use IR mode
pub use_ir: bool,
pub recursion_count: u64,
pub parent_stack: Option<Arc<Stack>>,
/// Variables that have been deleted (this is used to hide values from parent stack lookups)
pub parent_deletions: Vec<VarId>,
/// Locally updated config. Use [`.get_config()`] to access correctly.
pub config: Option<Arc<Config>>,
pub(crate) out_dest: StackOutDest,
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
}
impl Default for Stack {
fn default() -> Self {
Self::new()
}
2021-08-15 22:33:34 +00:00
}
impl Stack {
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
/// Create a new stack.
///
/// stdout and stderr will be set to [`OutDest::Inherit`]. So, if the last command is an external command,
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
/// then its output will be forwarded to the terminal/stdio streams.
///
/// Use [`Stack::capture`] afterwards if you need to evaluate an expression to a [`Value`](crate::Value)
/// (as opposed to a [`PipelineData`](crate::PipelineData)).
pub fn new() -> Self {
Self {
vars: Vec::new(),
env_vars: Vec::new(),
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
env_hidden: Arc::new(HashMap::new()),
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
active_overlays: vec![DEFAULT_OVERLAY_NAME.to_string()],
Internal representation (IR) compiler and evaluator (#13330) # Description This PR adds an internal representation language to Nushell, offering an alternative evaluator based on simple instructions, stream-containing registers, and indexed control flow. The number of registers required is determined statically at compile-time, and the fixed size required is allocated upon entering the block. Each instruction is associated with a span, which makes going backwards from IR instructions to source code very easy. Motivations for IR: 1. **Performance.** By simplifying the evaluation path and making it more cache-friendly and branch predictor-friendly, code that does a lot of computation in Nushell itself can be sped up a decent bit. Because the IR is fairly easy to reason about, we can also implement optimization passes in the future to eliminate and simplify code. 2. **Correctness.** The instructions mostly have very simple and easily-specified behavior, so hopefully engine changes are a little bit easier to reason about, and they can be specified in a more formal way at some point. I have made an effort to document each of the instructions in the docs for the enum itself in a reasonably specific way. Some of the errors that would have happened during evaluation before are now moved to the compilation step instead, because they don't make sense to check during evaluation. 3. **As an intermediate target.** This is a good step for us to bring the [`new-nu-parser`](https://github.com/nushell/new-nu-parser) in at some point, as code generated from new AST can be directly compared to code generated from old AST. If the IR code is functionally equivalent, it will behave the exact same way. 4. **Debugging.** With a little bit more work, we can probably give control over advancing the virtual machine that `IrBlock`s run on to some sort of external driver, making things like breakpoints and single stepping possible. Tools like `view ir` and [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir) make it easier than before to see what exactly is going on with your Nushell code. The goal is to eventually replace the AST evaluator entirely, once we're sure it's working just as well. You can help dogfood this by running Nushell with `$env.NU_USE_IR` set to some value. The environment variable is checked when Nushell starts, so config runs with IR, or it can also be set on a line at the REPL to change it dynamically. It is also checked when running `do` in case within a script you want to just run a specific piece of code with or without IR. # Example ```nushell view ir { |data| mut sum = 0 for n in $data { $sum += $n } $sum } ``` ```gas # 3 registers, 19 instructions, 0 bytes of data 0: load-literal %0, int(0) 1: store-variable var 904, %0 # let 2: drain %0 3: drop %0 4: load-variable %1, var 903 5: iterate %0, %1, end 15 # for, label(1), from(14:) 6: store-variable var 905, %0 7: load-variable %0, var 904 8: load-variable %2, var 905 9: binary-op %0, Math(Plus), %2 10: span %0 11: store-variable var 904, %0 12: load-literal %0, nothing 13: drain %0 14: jump 5 15: drop %0 # label(0), from(5:) 16: drain %0 17: load-variable %0, var 904 18: return %0 ``` # Benchmarks All benchmarks run on a base model Mac Mini M1. ## Iterative Fibonacci sequence This is about as best case as possible, making use of the much faster control flow. Most code will not experience a speed improvement nearly this large. ```nushell def fib [n: int] { mut a = 0 mut b = 1 for _ in 2..=$n { let c = $a + $b $a = $b $b = $c } $b } use std bench bench { 0..50 | each { |n| fib $n } } ``` IR disabled: ``` ╭───────┬─────────────────╮ │ mean │ 1ms 924µs 665ns │ │ min │ 1ms 700µs 83ns │ │ max │ 3ms 450µs 125ns │ │ std │ 395µs 759ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` IR enabled: ``` ╭───────┬─────────────────╮ │ mean │ 452µs 820ns │ │ min │ 427µs 417ns │ │ max │ 540µs 167ns │ │ std │ 17µs 158ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` ![explore ir view](https://github.com/nushell/nushell/assets/10729/d7bccc03-5222-461c-9200-0dce71b83b83) ## [gradient_benchmark_no_check.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/gradient_benchmark_no_check.nu) IR disabled: ``` ╭───┬──────────────────╮ │ 0 │ 27ms 929µs 958ns │ │ 1 │ 21ms 153µs 459ns │ │ 2 │ 18ms 639µs 666ns │ │ 3 │ 19ms 554µs 583ns │ │ 4 │ 13ms 383µs 375ns │ │ 5 │ 11ms 328µs 208ns │ │ 6 │ 5ms 659µs 542ns │ ╰───┴──────────────────╯ ``` IR enabled: ``` ╭───┬──────────────────╮ │ 0 │ 22ms 662µs │ │ 1 │ 17ms 221µs 792ns │ │ 2 │ 14ms 786µs 708ns │ │ 3 │ 13ms 876µs 834ns │ │ 4 │ 13ms 52µs 875ns │ │ 5 │ 11ms 269µs 666ns │ │ 6 │ 6ms 942µs 500ns │ ╰───┴──────────────────╯ ``` ## [random-bytes.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/random-bytes.nu) I got pretty random results out of this benchmark so I decided not to include it. Not clear why. # User-Facing Changes - IR compilation errors may appear even if the user isn't evaluating with IR. - IR evaluation can be enabled by setting the `NU_USE_IR` environment variable to any value. - New command `view ir` pretty-prints the IR for a block, and `view ir --json` can be piped into an external tool like [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir). # Tests + Formatting All tests are passing with `NU_USE_IR=1`, and I've added some more eval tests to compare the results for some very core operations. I will probably want to add some more so we don't have to always check `NU_USE_IR=1 toolkit test --workspace` on a regular basis. # After Submitting - [ ] release notes - [ ] further documentation of instructions? - [ ] post-release: publish `nu_plugin_explore_ir`
2024-07-11 00:33:59 +00:00
arguments: ArgumentStack::new(),
error_handlers: ErrorHandlerStack::new(),
use_ir: false,
recursion_count: 0,
parent_stack: None,
parent_deletions: vec![],
config: None,
out_dest: StackOutDest::new(),
}
}
/// Create a new child stack from a parent.
///
/// Changes from this child can be merged back into the parent with
/// [`Stack::with_changes_from_child`]
pub fn with_parent(parent: Arc<Stack>) -> Stack {
Stack {
// here we are still cloning environment variable-related information
env_vars: parent.env_vars.clone(),
env_hidden: parent.env_hidden.clone(),
active_overlays: parent.active_overlays.clone(),
Internal representation (IR) compiler and evaluator (#13330) # Description This PR adds an internal representation language to Nushell, offering an alternative evaluator based on simple instructions, stream-containing registers, and indexed control flow. The number of registers required is determined statically at compile-time, and the fixed size required is allocated upon entering the block. Each instruction is associated with a span, which makes going backwards from IR instructions to source code very easy. Motivations for IR: 1. **Performance.** By simplifying the evaluation path and making it more cache-friendly and branch predictor-friendly, code that does a lot of computation in Nushell itself can be sped up a decent bit. Because the IR is fairly easy to reason about, we can also implement optimization passes in the future to eliminate and simplify code. 2. **Correctness.** The instructions mostly have very simple and easily-specified behavior, so hopefully engine changes are a little bit easier to reason about, and they can be specified in a more formal way at some point. I have made an effort to document each of the instructions in the docs for the enum itself in a reasonably specific way. Some of the errors that would have happened during evaluation before are now moved to the compilation step instead, because they don't make sense to check during evaluation. 3. **As an intermediate target.** This is a good step for us to bring the [`new-nu-parser`](https://github.com/nushell/new-nu-parser) in at some point, as code generated from new AST can be directly compared to code generated from old AST. If the IR code is functionally equivalent, it will behave the exact same way. 4. **Debugging.** With a little bit more work, we can probably give control over advancing the virtual machine that `IrBlock`s run on to some sort of external driver, making things like breakpoints and single stepping possible. Tools like `view ir` and [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir) make it easier than before to see what exactly is going on with your Nushell code. The goal is to eventually replace the AST evaluator entirely, once we're sure it's working just as well. You can help dogfood this by running Nushell with `$env.NU_USE_IR` set to some value. The environment variable is checked when Nushell starts, so config runs with IR, or it can also be set on a line at the REPL to change it dynamically. It is also checked when running `do` in case within a script you want to just run a specific piece of code with or without IR. # Example ```nushell view ir { |data| mut sum = 0 for n in $data { $sum += $n } $sum } ``` ```gas # 3 registers, 19 instructions, 0 bytes of data 0: load-literal %0, int(0) 1: store-variable var 904, %0 # let 2: drain %0 3: drop %0 4: load-variable %1, var 903 5: iterate %0, %1, end 15 # for, label(1), from(14:) 6: store-variable var 905, %0 7: load-variable %0, var 904 8: load-variable %2, var 905 9: binary-op %0, Math(Plus), %2 10: span %0 11: store-variable var 904, %0 12: load-literal %0, nothing 13: drain %0 14: jump 5 15: drop %0 # label(0), from(5:) 16: drain %0 17: load-variable %0, var 904 18: return %0 ``` # Benchmarks All benchmarks run on a base model Mac Mini M1. ## Iterative Fibonacci sequence This is about as best case as possible, making use of the much faster control flow. Most code will not experience a speed improvement nearly this large. ```nushell def fib [n: int] { mut a = 0 mut b = 1 for _ in 2..=$n { let c = $a + $b $a = $b $b = $c } $b } use std bench bench { 0..50 | each { |n| fib $n } } ``` IR disabled: ``` ╭───────┬─────────────────╮ │ mean │ 1ms 924µs 665ns │ │ min │ 1ms 700µs 83ns │ │ max │ 3ms 450µs 125ns │ │ std │ 395µs 759ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` IR enabled: ``` ╭───────┬─────────────────╮ │ mean │ 452µs 820ns │ │ min │ 427µs 417ns │ │ max │ 540µs 167ns │ │ std │ 17µs 158ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` ![explore ir view](https://github.com/nushell/nushell/assets/10729/d7bccc03-5222-461c-9200-0dce71b83b83) ## [gradient_benchmark_no_check.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/gradient_benchmark_no_check.nu) IR disabled: ``` ╭───┬──────────────────╮ │ 0 │ 27ms 929µs 958ns │ │ 1 │ 21ms 153µs 459ns │ │ 2 │ 18ms 639µs 666ns │ │ 3 │ 19ms 554µs 583ns │ │ 4 │ 13ms 383µs 375ns │ │ 5 │ 11ms 328µs 208ns │ │ 6 │ 5ms 659µs 542ns │ ╰───┴──────────────────╯ ``` IR enabled: ``` ╭───┬──────────────────╮ │ 0 │ 22ms 662µs │ │ 1 │ 17ms 221µs 792ns │ │ 2 │ 14ms 786µs 708ns │ │ 3 │ 13ms 876µs 834ns │ │ 4 │ 13ms 52µs 875ns │ │ 5 │ 11ms 269µs 666ns │ │ 6 │ 6ms 942µs 500ns │ ╰───┴──────────────────╯ ``` ## [random-bytes.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/random-bytes.nu) I got pretty random results out of this benchmark so I decided not to include it. Not clear why. # User-Facing Changes - IR compilation errors may appear even if the user isn't evaluating with IR. - IR evaluation can be enabled by setting the `NU_USE_IR` environment variable to any value. - New command `view ir` pretty-prints the IR for a block, and `view ir --json` can be piped into an external tool like [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir). # Tests + Formatting All tests are passing with `NU_USE_IR=1`, and I've added some more eval tests to compare the results for some very core operations. I will probably want to add some more so we don't have to always check `NU_USE_IR=1 toolkit test --workspace` on a regular basis. # After Submitting - [ ] release notes - [ ] further documentation of instructions? - [ ] post-release: publish `nu_plugin_explore_ir`
2024-07-11 00:33:59 +00:00
arguments: ArgumentStack::new(),
error_handlers: ErrorHandlerStack::new(),
use_ir: parent.use_ir,
recursion_count: parent.recursion_count,
vars: vec![],
parent_deletions: vec![],
config: parent.config.clone(),
out_dest: parent.out_dest.clone(),
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
parent_stack: Some(parent),
Use only $nu.env.PWD for getting the current directory (#587) * Use only $nu.env.PWD for getting current directory Because setting and reading to/from std::env changes the global state shich is problematic if we call `cd` from multiple threads (e.g., in a `par-each` block). With this change, when engine-q starts, it will either inherit existing PWD env var, or create a new one from `std::env::current_dir()`. Otherwise, everything that needs the current directory will get it from `$nu.env.PWD`. Each spawned external command will get its current directory per-process which should be thread-safe. One thing left to do is to patch nu-path for this as well since it uses `std::env::current_dir()` in its expansions. * Rename nu-path functions *_with is not *_relative which should be more descriptive and frees "with" for use in a followup commit. * Clone stack every each iter; Fix some commands Cloning the stack each iteration of `each` makes sure we're not reusing PWD between iterations. Some fixes in commands to make them use the new PWD. * Post-rebase cleanup, fmt, clippy * Change back _relative to _with in nu-path funcs Didn't use the idea I had for the new "_with". * Remove leftover current_dir from rebase * Add cwd sync at merge_delta() This makes sure the parser and completer always have up-to-date cwd. * Always pass absolute path to glob in ls * Do not allow PWD a relative path; Allow recovery Makes it possible to recover PWD by proceeding with the REPL cycle. * Clone stack in each also for byte/string stream * (WIP) Start moving env variables to engine state * (WIP) Move env vars to engine state (ugly) Quick and dirty code. * (WIP) Remove unused mut and args; Fmt * (WIP) Fix dataframe tests * (WIP) Fix missing args after rebase * (WIP) Clone only env vars, not the whole stack * (WIP) Add env var clone to `for` loop as well * Minor edits * Refactor merge_delta() to include stack merging. Less error-prone than doing it manually. * Clone env for each `update` command iteration * Mark env var hidden only when found in eng. state * Fix clippt warnings * Add TODO about env var reading * Do not clone empty environment in loops * Remove extra cwd collection * Split current_dir() into str and path; Fix autocd * Make completions respect PWD env var
2022-01-04 22:30:34 +00:00
}
}
/// Take an [`Arc`] parent, and a child, and apply all the changes from a child back to the parent.
///
/// Here it is assumed that `child` was created by a call to [`Stack::with_parent`] with `parent`.
///
/// For this to be performant and not clone `parent`, `child` should be the only other
/// referencer of `parent`.
pub fn with_changes_from_child(parent: Arc<Stack>, child: Stack) -> Stack {
// we're going to drop the link to the parent stack on our new stack
// so that we can unwrap the Arc as a unique reference
drop(child.parent_stack);
let mut unique_stack = Arc::unwrap_or_clone(parent);
unique_stack
.vars
.retain(|(var, _)| !child.parent_deletions.contains(var));
for (var, value) in child.vars {
unique_stack.add_var(var, value);
}
unique_stack.env_vars = child.env_vars;
unique_stack.env_hidden = child.env_hidden;
unique_stack.active_overlays = child.active_overlays;
unique_stack.config = child.config;
unique_stack
}
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
pub fn with_env(
&mut self,
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
env_vars: &[Arc<EnvVars>],
env_hidden: &Arc<HashMap<String, HashSet<String>>>,
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
) {
// Do not clone the environment if it hasn't changed
if self.env_vars.iter().any(|scope| !scope.is_empty()) {
env_vars.clone_into(&mut self.env_vars);
Use only $nu.env.PWD for getting the current directory (#587) * Use only $nu.env.PWD for getting current directory Because setting and reading to/from std::env changes the global state shich is problematic if we call `cd` from multiple threads (e.g., in a `par-each` block). With this change, when engine-q starts, it will either inherit existing PWD env var, or create a new one from `std::env::current_dir()`. Otherwise, everything that needs the current directory will get it from `$nu.env.PWD`. Each spawned external command will get its current directory per-process which should be thread-safe. One thing left to do is to patch nu-path for this as well since it uses `std::env::current_dir()` in its expansions. * Rename nu-path functions *_with is not *_relative which should be more descriptive and frees "with" for use in a followup commit. * Clone stack every each iter; Fix some commands Cloning the stack each iteration of `each` makes sure we're not reusing PWD between iterations. Some fixes in commands to make them use the new PWD. * Post-rebase cleanup, fmt, clippy * Change back _relative to _with in nu-path funcs Didn't use the idea I had for the new "_with". * Remove leftover current_dir from rebase * Add cwd sync at merge_delta() This makes sure the parser and completer always have up-to-date cwd. * Always pass absolute path to glob in ls * Do not allow PWD a relative path; Allow recovery Makes it possible to recover PWD by proceeding with the REPL cycle. * Clone stack in each also for byte/string stream * (WIP) Start moving env variables to engine state * (WIP) Move env vars to engine state (ugly) Quick and dirty code. * (WIP) Remove unused mut and args; Fmt * (WIP) Fix dataframe tests * (WIP) Fix missing args after rebase * (WIP) Clone only env vars, not the whole stack * (WIP) Add env var clone to `for` loop as well * Minor edits * Refactor merge_delta() to include stack merging. Less error-prone than doing it manually. * Clone env for each `update` command iteration * Mark env var hidden only when found in eng. state * Fix clippt warnings * Add TODO about env var reading * Do not clone empty environment in loops * Remove extra cwd collection * Split current_dir() into str and path; Fix autocd * Make completions respect PWD env var
2022-01-04 22:30:34 +00:00
}
if !self.env_hidden.is_empty() {
self.env_hidden.clone_from(env_hidden);
2021-10-25 20:04:23 +00:00
}
2021-08-15 22:33:34 +00:00
}
/// Lookup a variable, returning None if it is not present
fn lookup_var(&self, var_id: VarId) -> Option<Value> {
Move variables to var stack (#8604) # Description This moves the representation of variables on the stack to a Vec, which more closely resembles a stack. For small numbers of variables live at any one point, this tends to be more efficient than a HashMap. Having a stack-like vector also allows us to remember a stack position, temporarily push variables on, then quickly drop the stack back to the original size when we're done. We'll need this capability to allow matching inside of conditions. On this mac, a simple run of: `timeit { mut x = 1; while $x < 1000000 { $x += 1 } }` Went from 1 sec 86 ms, down to 1 sec 2 ms. Clearly, we have a lot more ground we can make up in looping speed 😅 but it's nice that for fixing this to make matching easier, we also get a win in terms of lookup speed for small numbers of variables. # User-Facing Changes Likely users won't (hopefully) see any negative impact and may even see a small positive impact. # 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` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass > **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.
2023-03-24 23:56:45 +00:00
for (id, val) in &self.vars {
if var_id == *id {
return Some(val.clone());
Move variables to var stack (#8604) # Description This moves the representation of variables on the stack to a Vec, which more closely resembles a stack. For small numbers of variables live at any one point, this tends to be more efficient than a HashMap. Having a stack-like vector also allows us to remember a stack position, temporarily push variables on, then quickly drop the stack back to the original size when we're done. We'll need this capability to allow matching inside of conditions. On this mac, a simple run of: `timeit { mut x = 1; while $x < 1000000 { $x += 1 } }` Went from 1 sec 86 ms, down to 1 sec 2 ms. Clearly, we have a lot more ground we can make up in looping speed 😅 but it's nice that for fixing this to make matching easier, we also get a win in terms of lookup speed for small numbers of variables. # User-Facing Changes Likely users won't (hopefully) see any negative impact and may even see a small positive impact. # 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` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass > **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.
2023-03-24 23:56:45 +00:00
}
2021-08-15 22:33:34 +00:00
}
if let Some(stack) = &self.parent_stack {
if !self.parent_deletions.contains(&var_id) {
return stack.lookup_var(var_id);
Move variables to var stack (#8604) # Description This moves the representation of variables on the stack to a Vec, which more closely resembles a stack. For small numbers of variables live at any one point, this tends to be more efficient than a HashMap. Having a stack-like vector also allows us to remember a stack position, temporarily push variables on, then quickly drop the stack back to the original size when we're done. We'll need this capability to allow matching inside of conditions. On this mac, a simple run of: `timeit { mut x = 1; while $x < 1000000 { $x += 1 } }` Went from 1 sec 86 ms, down to 1 sec 2 ms. Clearly, we have a lot more ground we can make up in looping speed 😅 but it's nice that for fixing this to make matching easier, we also get a win in terms of lookup speed for small numbers of variables. # User-Facing Changes Likely users won't (hopefully) see any negative impact and may even see a small positive impact. # 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` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass > **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.
2023-03-24 23:56:45 +00:00
}
}
None
}
/// Lookup a variable, erroring if it is not found
///
/// The passed-in span will be used to tag the value
pub fn get_var(&self, var_id: VarId, span: Span) -> Result<Value, ShellError> {
match self.lookup_var(var_id) {
Some(v) => Ok(v.with_span(span)),
None => Err(ShellError::VariableNotFoundAtRuntime { span }),
}
}
/// Lookup a variable, erroring if it is not found
///
/// While the passed-in span will be used for errors, the returned value
/// has the span from where it was originally defined
pub fn get_var_with_origin(&self, var_id: VarId, span: Span) -> Result<Value, ShellError> {
match self.lookup_var(var_id) {
Some(v) => Ok(v),
None => {
if var_id == NU_VARIABLE_ID || var_id == ENV_VARIABLE_ID {
return Err(ShellError::GenericError {
error: "Built-in variables `$env` and `$nu` have no metadata".into(),
msg: "no metadata available".into(),
span: Some(span),
help: None,
inner: vec![],
});
}
Err(ShellError::VariableNotFoundAtRuntime { span })
}
}
}
/// Get the local config if set, otherwise the config from the engine state.
///
/// This is the canonical way to get [`Config`] when [`Stack`] is available.
pub fn get_config(&self, engine_state: &EngineState) -> Arc<Config> {
self.config
.clone()
.unwrap_or_else(|| engine_state.config.clone())
}
/// Update the local config with the config stored in the `config` environment variable. Run
/// this after assigning to `$env.config`.
///
/// The config will be updated with successfully parsed values even if an error occurs.
pub fn update_config(&mut self, engine_state: &EngineState) -> Result<(), ShellError> {
if let Some(mut config) = self.get_env_var(engine_state, "config") {
let existing_config = self.get_config(engine_state);
let (new_config, error) = config.parse_as_config(&existing_config);
self.config = Some(new_config.into());
// The config value is modified by the update, so we should add it again
self.add_env_var("config".into(), config);
match error {
None => Ok(()),
Some(err) => Err(err),
}
} else {
self.config = None;
Ok(())
}
}
2021-10-25 04:01:02 +00:00
pub fn add_var(&mut self, var_id: VarId, value: Value) {
Move variables to var stack (#8604) # Description This moves the representation of variables on the stack to a Vec, which more closely resembles a stack. For small numbers of variables live at any one point, this tends to be more efficient than a HashMap. Having a stack-like vector also allows us to remember a stack position, temporarily push variables on, then quickly drop the stack back to the original size when we're done. We'll need this capability to allow matching inside of conditions. On this mac, a simple run of: `timeit { mut x = 1; while $x < 1000000 { $x += 1 } }` Went from 1 sec 86 ms, down to 1 sec 2 ms. Clearly, we have a lot more ground we can make up in looping speed 😅 but it's nice that for fixing this to make matching easier, we also get a win in terms of lookup speed for small numbers of variables. # User-Facing Changes Likely users won't (hopefully) see any negative impact and may even see a small positive impact. # 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` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass > **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.
2023-03-24 23:56:45 +00:00
//self.vars.insert(var_id, value);
for (id, val) in &mut self.vars {
if *id == var_id {
*val = value;
return;
}
}
self.vars.push((var_id, value));
}
pub fn remove_var(&mut self, var_id: VarId) {
for (idx, (id, _)) in self.vars.iter().enumerate() {
if *id == var_id {
self.vars.remove(idx);
break;
Move variables to var stack (#8604) # Description This moves the representation of variables on the stack to a Vec, which more closely resembles a stack. For small numbers of variables live at any one point, this tends to be more efficient than a HashMap. Having a stack-like vector also allows us to remember a stack position, temporarily push variables on, then quickly drop the stack back to the original size when we're done. We'll need this capability to allow matching inside of conditions. On this mac, a simple run of: `timeit { mut x = 1; while $x < 1000000 { $x += 1 } }` Went from 1 sec 86 ms, down to 1 sec 2 ms. Clearly, we have a lot more ground we can make up in looping speed 😅 but it's nice that for fixing this to make matching easier, we also get a win in terms of lookup speed for small numbers of variables. # User-Facing Changes Likely users won't (hopefully) see any negative impact and may even see a small positive impact. # 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` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass > **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.
2023-03-24 23:56:45 +00:00
}
}
// even if we did have it in the original layer, we need to make sure to remove it here
// as well (since the previous update might have simply hid the parent value)
if self.parent_stack.is_some() {
self.parent_deletions.push(var_id);
}
2021-08-15 22:33:34 +00:00
}
pub fn add_env_var(&mut self, var: String, value: Value) {
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
if let Some(last_overlay) = self.active_overlays.last() {
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
if let Some(env_hidden) = Arc::make_mut(&mut self.env_hidden).get_mut(last_overlay) {
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
// if the env var was hidden, let's activate it again
env_hidden.remove(&var);
}
Use only $nu.env.PWD for getting the current directory (#587) * Use only $nu.env.PWD for getting current directory Because setting and reading to/from std::env changes the global state shich is problematic if we call `cd` from multiple threads (e.g., in a `par-each` block). With this change, when engine-q starts, it will either inherit existing PWD env var, or create a new one from `std::env::current_dir()`. Otherwise, everything that needs the current directory will get it from `$nu.env.PWD`. Each spawned external command will get its current directory per-process which should be thread-safe. One thing left to do is to patch nu-path for this as well since it uses `std::env::current_dir()` in its expansions. * Rename nu-path functions *_with is not *_relative which should be more descriptive and frees "with" for use in a followup commit. * Clone stack every each iter; Fix some commands Cloning the stack each iteration of `each` makes sure we're not reusing PWD between iterations. Some fixes in commands to make them use the new PWD. * Post-rebase cleanup, fmt, clippy * Change back _relative to _with in nu-path funcs Didn't use the idea I had for the new "_with". * Remove leftover current_dir from rebase * Add cwd sync at merge_delta() This makes sure the parser and completer always have up-to-date cwd. * Always pass absolute path to glob in ls * Do not allow PWD a relative path; Allow recovery Makes it possible to recover PWD by proceeding with the REPL cycle. * Clone stack in each also for byte/string stream * (WIP) Start moving env variables to engine state * (WIP) Move env vars to engine state (ugly) Quick and dirty code. * (WIP) Remove unused mut and args; Fmt * (WIP) Fix dataframe tests * (WIP) Fix missing args after rebase * (WIP) Clone only env vars, not the whole stack * (WIP) Add env var clone to `for` loop as well * Minor edits * Refactor merge_delta() to include stack merging. Less error-prone than doing it manually. * Clone env for each `update` command iteration * Mark env var hidden only when found in eng. state * Fix clippt warnings * Add TODO about env var reading * Do not clone empty environment in loops * Remove extra cwd collection * Split current_dir() into str and path; Fix autocd * Make completions respect PWD env var
2022-01-04 22:30:34 +00:00
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
if let Some(scope) = self.env_vars.last_mut() {
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
let scope = Arc::make_mut(scope);
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
if let Some(env_vars) = scope.get_mut(last_overlay) {
env_vars.insert(var, value);
} else {
scope.insert(last_overlay.into(), [(var, value)].into_iter().collect());
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
}
} else {
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
self.env_vars.push(Arc::new(
[(last_overlay.into(), [(var, value)].into_iter().collect())]
.into_iter()
.collect(),
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
));
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
}
} else {
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
// TODO: Remove panic
panic!("internal error: no active overlay");
}
2021-08-15 22:33:34 +00:00
}
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
pub fn last_overlay_name(&self) -> Result<String, ShellError> {
self.active_overlays
.last()
.cloned()
2023-03-06 17:33:09 +00:00
.ok_or_else(|| ShellError::NushellFailed {
msg: "No active overlay".into(),
})
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
}
pub fn captures_to_stack(&self, captures: Vec<(VarId, Value)>) -> Stack {
self.captures_to_stack_preserve_out_dest(captures).capture()
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
}
pub fn captures_to_stack_preserve_out_dest(&self, captures: Vec<(VarId, Value)>) -> Stack {
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
let mut env_vars = self.env_vars.clone();
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
env_vars.push(Arc::new(HashMap::new()));
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
Stack {
vars: captures,
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
env_vars,
env_hidden: self.env_hidden.clone(),
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
active_overlays: self.active_overlays.clone(),
Internal representation (IR) compiler and evaluator (#13330) # Description This PR adds an internal representation language to Nushell, offering an alternative evaluator based on simple instructions, stream-containing registers, and indexed control flow. The number of registers required is determined statically at compile-time, and the fixed size required is allocated upon entering the block. Each instruction is associated with a span, which makes going backwards from IR instructions to source code very easy. Motivations for IR: 1. **Performance.** By simplifying the evaluation path and making it more cache-friendly and branch predictor-friendly, code that does a lot of computation in Nushell itself can be sped up a decent bit. Because the IR is fairly easy to reason about, we can also implement optimization passes in the future to eliminate and simplify code. 2. **Correctness.** The instructions mostly have very simple and easily-specified behavior, so hopefully engine changes are a little bit easier to reason about, and they can be specified in a more formal way at some point. I have made an effort to document each of the instructions in the docs for the enum itself in a reasonably specific way. Some of the errors that would have happened during evaluation before are now moved to the compilation step instead, because they don't make sense to check during evaluation. 3. **As an intermediate target.** This is a good step for us to bring the [`new-nu-parser`](https://github.com/nushell/new-nu-parser) in at some point, as code generated from new AST can be directly compared to code generated from old AST. If the IR code is functionally equivalent, it will behave the exact same way. 4. **Debugging.** With a little bit more work, we can probably give control over advancing the virtual machine that `IrBlock`s run on to some sort of external driver, making things like breakpoints and single stepping possible. Tools like `view ir` and [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir) make it easier than before to see what exactly is going on with your Nushell code. The goal is to eventually replace the AST evaluator entirely, once we're sure it's working just as well. You can help dogfood this by running Nushell with `$env.NU_USE_IR` set to some value. The environment variable is checked when Nushell starts, so config runs with IR, or it can also be set on a line at the REPL to change it dynamically. It is also checked when running `do` in case within a script you want to just run a specific piece of code with or without IR. # Example ```nushell view ir { |data| mut sum = 0 for n in $data { $sum += $n } $sum } ``` ```gas # 3 registers, 19 instructions, 0 bytes of data 0: load-literal %0, int(0) 1: store-variable var 904, %0 # let 2: drain %0 3: drop %0 4: load-variable %1, var 903 5: iterate %0, %1, end 15 # for, label(1), from(14:) 6: store-variable var 905, %0 7: load-variable %0, var 904 8: load-variable %2, var 905 9: binary-op %0, Math(Plus), %2 10: span %0 11: store-variable var 904, %0 12: load-literal %0, nothing 13: drain %0 14: jump 5 15: drop %0 # label(0), from(5:) 16: drain %0 17: load-variable %0, var 904 18: return %0 ``` # Benchmarks All benchmarks run on a base model Mac Mini M1. ## Iterative Fibonacci sequence This is about as best case as possible, making use of the much faster control flow. Most code will not experience a speed improvement nearly this large. ```nushell def fib [n: int] { mut a = 0 mut b = 1 for _ in 2..=$n { let c = $a + $b $a = $b $b = $c } $b } use std bench bench { 0..50 | each { |n| fib $n } } ``` IR disabled: ``` ╭───────┬─────────────────╮ │ mean │ 1ms 924µs 665ns │ │ min │ 1ms 700µs 83ns │ │ max │ 3ms 450µs 125ns │ │ std │ 395µs 759ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` IR enabled: ``` ╭───────┬─────────────────╮ │ mean │ 452µs 820ns │ │ min │ 427µs 417ns │ │ max │ 540µs 167ns │ │ std │ 17µs 158ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` ![explore ir view](https://github.com/nushell/nushell/assets/10729/d7bccc03-5222-461c-9200-0dce71b83b83) ## [gradient_benchmark_no_check.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/gradient_benchmark_no_check.nu) IR disabled: ``` ╭───┬──────────────────╮ │ 0 │ 27ms 929µs 958ns │ │ 1 │ 21ms 153µs 459ns │ │ 2 │ 18ms 639µs 666ns │ │ 3 │ 19ms 554µs 583ns │ │ 4 │ 13ms 383µs 375ns │ │ 5 │ 11ms 328µs 208ns │ │ 6 │ 5ms 659µs 542ns │ ╰───┴──────────────────╯ ``` IR enabled: ``` ╭───┬──────────────────╮ │ 0 │ 22ms 662µs │ │ 1 │ 17ms 221µs 792ns │ │ 2 │ 14ms 786µs 708ns │ │ 3 │ 13ms 876µs 834ns │ │ 4 │ 13ms 52µs 875ns │ │ 5 │ 11ms 269µs 666ns │ │ 6 │ 6ms 942µs 500ns │ ╰───┴──────────────────╯ ``` ## [random-bytes.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/random-bytes.nu) I got pretty random results out of this benchmark so I decided not to include it. Not clear why. # User-Facing Changes - IR compilation errors may appear even if the user isn't evaluating with IR. - IR evaluation can be enabled by setting the `NU_USE_IR` environment variable to any value. - New command `view ir` pretty-prints the IR for a block, and `view ir --json` can be piped into an external tool like [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir). # Tests + Formatting All tests are passing with `NU_USE_IR=1`, and I've added some more eval tests to compare the results for some very core operations. I will probably want to add some more so we don't have to always check `NU_USE_IR=1 toolkit test --workspace` on a regular basis. # After Submitting - [ ] release notes - [ ] further documentation of instructions? - [ ] post-release: publish `nu_plugin_explore_ir`
2024-07-11 00:33:59 +00:00
arguments: ArgumentStack::new(),
error_handlers: ErrorHandlerStack::new(),
use_ir: self.use_ir,
recursion_count: self.recursion_count,
parent_stack: None,
parent_deletions: vec![],
config: self.config.clone(),
out_dest: self.out_dest.clone(),
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
}
}
Recursively export constants from modules (#10049) <!-- 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. --> https://github.com/nushell/nushell/pull/9773 introduced constants to modules and allowed to export them, but only within one level. This PR: * allows recursive exporting of constants from all submodules * fixes submodule imports in a list import pattern * makes sure exported constants are actual constants Should unblock https://github.com/nushell/nushell/pull/9678 ### Example: ```nushell module spam { export module eggs { export module bacon { export const viking = 'eats' } } } use spam print $spam.eggs.bacon.viking # prints 'eats' use spam [eggs] print $eggs.bacon.viking # prints 'eats' use spam eggs bacon viking print $viking # prints 'eats' ``` ### Limitation 1: Considering the above `spam` module, attempting to get `eggs bacon` from `spam` module doesn't work directly: ```nushell use spam [ eggs bacon ] # attempts to load `eggs`, then `bacon` use spam [ "eggs bacon" ] # obviously wrong name for a constant, but doesn't work also for commands ``` Workaround (for example): ```nushell use spam eggs use eggs [ bacon ] print $bacon.viking # prints 'eats' ``` I'm thinking I'll just leave it in, as you can easily work around this. It is also a limitation of the import pattern in general, not just constants. ### Limitation 2: `overlay use` successfully imports the constants, but `overlay hide` does not hide them, even though it seems to hide normal variables successfully. This needs more investigation. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> Allows recursive constant exports from submodules. # 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. -->
2023-08-20 12:51:35 +00:00
pub fn gather_captures(&self, engine_state: &EngineState, captures: &[VarId]) -> Stack {
let mut vars = Vec::with_capacity(captures.len());
2021-10-25 20:04:23 +00:00
let fake_span = Span::new(0, 0);
2021-10-25 20:04:23 +00:00
for capture in captures {
2021-10-25 21:14:21 +00:00
// Note: this assumes we have calculated captures correctly and that commands
// that take in a var decl will manually set this into scope when running the blocks
if let Ok(value) = self.get_var(*capture, fake_span) {
Move variables to var stack (#8604) # Description This moves the representation of variables on the stack to a Vec, which more closely resembles a stack. For small numbers of variables live at any one point, this tends to be more efficient than a HashMap. Having a stack-like vector also allows us to remember a stack position, temporarily push variables on, then quickly drop the stack back to the original size when we're done. We'll need this capability to allow matching inside of conditions. On this mac, a simple run of: `timeit { mut x = 1; while $x < 1000000 { $x += 1 } }` Went from 1 sec 86 ms, down to 1 sec 2 ms. Clearly, we have a lot more ground we can make up in looping speed 😅 but it's nice that for fixing this to make matching easier, we also get a win in terms of lookup speed for small numbers of variables. # User-Facing Changes Likely users won't (hopefully) see any negative impact and may even see a small positive impact. # 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` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass > **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.
2023-03-24 23:56:45 +00:00
vars.push((*capture, value));
Recursively export constants from modules (#10049) <!-- 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. --> https://github.com/nushell/nushell/pull/9773 introduced constants to modules and allowed to export them, but only within one level. This PR: * allows recursive exporting of constants from all submodules * fixes submodule imports in a list import pattern * makes sure exported constants are actual constants Should unblock https://github.com/nushell/nushell/pull/9678 ### Example: ```nushell module spam { export module eggs { export module bacon { export const viking = 'eats' } } } use spam print $spam.eggs.bacon.viking # prints 'eats' use spam [eggs] print $eggs.bacon.viking # prints 'eats' use spam eggs bacon viking print $viking # prints 'eats' ``` ### Limitation 1: Considering the above `spam` module, attempting to get `eggs bacon` from `spam` module doesn't work directly: ```nushell use spam [ eggs bacon ] # attempts to load `eggs`, then `bacon` use spam [ "eggs bacon" ] # obviously wrong name for a constant, but doesn't work also for commands ``` Workaround (for example): ```nushell use spam eggs use eggs [ bacon ] print $bacon.viking # prints 'eats' ``` I'm thinking I'll just leave it in, as you can easily work around this. It is also a limitation of the import pattern in general, not just constants. ### Limitation 2: `overlay use` successfully imports the constants, but `overlay hide` does not hide them, even though it seems to hide normal variables successfully. This needs more investigation. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> Allows recursive constant exports from submodules. # 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. -->
2023-08-20 12:51:35 +00:00
} else if let Some(const_val) = &engine_state.get_var(*capture).const_val {
vars.push((*capture, const_val.clone()));
2021-10-25 21:14:21 +00:00
}
2021-10-25 20:04:23 +00:00
}
2021-10-25 04:01:02 +00:00
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
let mut env_vars = self.env_vars.clone();
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
env_vars.push(Arc::new(HashMap::new()));
2021-11-04 02:32:35 +00:00
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
Stack {
vars,
env_vars,
env_hidden: self.env_hidden.clone(),
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
active_overlays: self.active_overlays.clone(),
Internal representation (IR) compiler and evaluator (#13330) # Description This PR adds an internal representation language to Nushell, offering an alternative evaluator based on simple instructions, stream-containing registers, and indexed control flow. The number of registers required is determined statically at compile-time, and the fixed size required is allocated upon entering the block. Each instruction is associated with a span, which makes going backwards from IR instructions to source code very easy. Motivations for IR: 1. **Performance.** By simplifying the evaluation path and making it more cache-friendly and branch predictor-friendly, code that does a lot of computation in Nushell itself can be sped up a decent bit. Because the IR is fairly easy to reason about, we can also implement optimization passes in the future to eliminate and simplify code. 2. **Correctness.** The instructions mostly have very simple and easily-specified behavior, so hopefully engine changes are a little bit easier to reason about, and they can be specified in a more formal way at some point. I have made an effort to document each of the instructions in the docs for the enum itself in a reasonably specific way. Some of the errors that would have happened during evaluation before are now moved to the compilation step instead, because they don't make sense to check during evaluation. 3. **As an intermediate target.** This is a good step for us to bring the [`new-nu-parser`](https://github.com/nushell/new-nu-parser) in at some point, as code generated from new AST can be directly compared to code generated from old AST. If the IR code is functionally equivalent, it will behave the exact same way. 4. **Debugging.** With a little bit more work, we can probably give control over advancing the virtual machine that `IrBlock`s run on to some sort of external driver, making things like breakpoints and single stepping possible. Tools like `view ir` and [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir) make it easier than before to see what exactly is going on with your Nushell code. The goal is to eventually replace the AST evaluator entirely, once we're sure it's working just as well. You can help dogfood this by running Nushell with `$env.NU_USE_IR` set to some value. The environment variable is checked when Nushell starts, so config runs with IR, or it can also be set on a line at the REPL to change it dynamically. It is also checked when running `do` in case within a script you want to just run a specific piece of code with or without IR. # Example ```nushell view ir { |data| mut sum = 0 for n in $data { $sum += $n } $sum } ``` ```gas # 3 registers, 19 instructions, 0 bytes of data 0: load-literal %0, int(0) 1: store-variable var 904, %0 # let 2: drain %0 3: drop %0 4: load-variable %1, var 903 5: iterate %0, %1, end 15 # for, label(1), from(14:) 6: store-variable var 905, %0 7: load-variable %0, var 904 8: load-variable %2, var 905 9: binary-op %0, Math(Plus), %2 10: span %0 11: store-variable var 904, %0 12: load-literal %0, nothing 13: drain %0 14: jump 5 15: drop %0 # label(0), from(5:) 16: drain %0 17: load-variable %0, var 904 18: return %0 ``` # Benchmarks All benchmarks run on a base model Mac Mini M1. ## Iterative Fibonacci sequence This is about as best case as possible, making use of the much faster control flow. Most code will not experience a speed improvement nearly this large. ```nushell def fib [n: int] { mut a = 0 mut b = 1 for _ in 2..=$n { let c = $a + $b $a = $b $b = $c } $b } use std bench bench { 0..50 | each { |n| fib $n } } ``` IR disabled: ``` ╭───────┬─────────────────╮ │ mean │ 1ms 924µs 665ns │ │ min │ 1ms 700µs 83ns │ │ max │ 3ms 450µs 125ns │ │ std │ 395µs 759ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` IR enabled: ``` ╭───────┬─────────────────╮ │ mean │ 452µs 820ns │ │ min │ 427µs 417ns │ │ max │ 540µs 167ns │ │ std │ 17µs 158ns │ │ times │ [list 50 items] │ ╰───────┴─────────────────╯ ``` ![explore ir view](https://github.com/nushell/nushell/assets/10729/d7bccc03-5222-461c-9200-0dce71b83b83) ## [gradient_benchmark_no_check.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/gradient_benchmark_no_check.nu) IR disabled: ``` ╭───┬──────────────────╮ │ 0 │ 27ms 929µs 958ns │ │ 1 │ 21ms 153µs 459ns │ │ 2 │ 18ms 639µs 666ns │ │ 3 │ 19ms 554µs 583ns │ │ 4 │ 13ms 383µs 375ns │ │ 5 │ 11ms 328µs 208ns │ │ 6 │ 5ms 659µs 542ns │ ╰───┴──────────────────╯ ``` IR enabled: ``` ╭───┬──────────────────╮ │ 0 │ 22ms 662µs │ │ 1 │ 17ms 221µs 792ns │ │ 2 │ 14ms 786µs 708ns │ │ 3 │ 13ms 876µs 834ns │ │ 4 │ 13ms 52µs 875ns │ │ 5 │ 11ms 269µs 666ns │ │ 6 │ 6ms 942µs 500ns │ ╰───┴──────────────────╯ ``` ## [random-bytes.nu](https://github.com/nushell/nu_scripts/blob/main/benchmarks/random-bytes.nu) I got pretty random results out of this benchmark so I decided not to include it. Not clear why. # User-Facing Changes - IR compilation errors may appear even if the user isn't evaluating with IR. - IR evaluation can be enabled by setting the `NU_USE_IR` environment variable to any value. - New command `view ir` pretty-prints the IR for a block, and `view ir --json` can be piped into an external tool like [`explore ir`](https://github.com/devyn/nu_plugin_explore_ir). # Tests + Formatting All tests are passing with `NU_USE_IR=1`, and I've added some more eval tests to compare the results for some very core operations. I will probably want to add some more so we don't have to always check `NU_USE_IR=1 toolkit test --workspace` on a regular basis. # After Submitting - [ ] release notes - [ ] further documentation of instructions? - [ ] post-release: publish `nu_plugin_explore_ir`
2024-07-11 00:33:59 +00:00
arguments: ArgumentStack::new(),
error_handlers: ErrorHandlerStack::new(),
use_ir: self.use_ir,
recursion_count: self.recursion_count,
parent_stack: None,
parent_deletions: vec![],
config: self.config.clone(),
out_dest: self.out_dest.clone(),
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
}
2021-08-15 22:33:34 +00:00
}
/// Flatten the env var scope frames into one frame
Use only $nu.env.PWD for getting the current directory (#587) * Use only $nu.env.PWD for getting current directory Because setting and reading to/from std::env changes the global state shich is problematic if we call `cd` from multiple threads (e.g., in a `par-each` block). With this change, when engine-q starts, it will either inherit existing PWD env var, or create a new one from `std::env::current_dir()`. Otherwise, everything that needs the current directory will get it from `$nu.env.PWD`. Each spawned external command will get its current directory per-process which should be thread-safe. One thing left to do is to patch nu-path for this as well since it uses `std::env::current_dir()` in its expansions. * Rename nu-path functions *_with is not *_relative which should be more descriptive and frees "with" for use in a followup commit. * Clone stack every each iter; Fix some commands Cloning the stack each iteration of `each` makes sure we're not reusing PWD between iterations. Some fixes in commands to make them use the new PWD. * Post-rebase cleanup, fmt, clippy * Change back _relative to _with in nu-path funcs Didn't use the idea I had for the new "_with". * Remove leftover current_dir from rebase * Add cwd sync at merge_delta() This makes sure the parser and completer always have up-to-date cwd. * Always pass absolute path to glob in ls * Do not allow PWD a relative path; Allow recovery Makes it possible to recover PWD by proceeding with the REPL cycle. * Clone stack in each also for byte/string stream * (WIP) Start moving env variables to engine state * (WIP) Move env vars to engine state (ugly) Quick and dirty code. * (WIP) Remove unused mut and args; Fmt * (WIP) Fix dataframe tests * (WIP) Fix missing args after rebase * (WIP) Clone only env vars, not the whole stack * (WIP) Add env var clone to `for` loop as well * Minor edits * Refactor merge_delta() to include stack merging. Less error-prone than doing it manually. * Clone env for each `update` command iteration * Mark env var hidden only when found in eng. state * Fix clippt warnings * Add TODO about env var reading * Do not clone empty environment in loops * Remove extra cwd collection * Split current_dir() into str and path; Fix autocd * Make completions respect PWD env var
2022-01-04 22:30:34 +00:00
pub fn get_env_vars(&self, engine_state: &EngineState) -> HashMap<String, Value> {
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
let mut result = HashMap::new();
for active_overlay in self.active_overlays.iter() {
if let Some(env_vars) = engine_state.env_vars.get(active_overlay) {
result.extend(
env_vars
.iter()
.filter(|(k, _)| {
if let Some(env_hidden) = self.env_hidden.get(active_overlay) {
!env_hidden.contains(*k)
} else {
// nothing has been hidden in this overlay
true
}
})
.map(|(k, v)| (k.clone(), v.clone()))
.collect::<HashMap<String, Value>>(),
);
}
}
result.extend(self.get_stack_env_vars());
result
}
/// Get flattened environment variables only from the stack
pub fn get_stack_env_vars(&self) -> HashMap<String, Value> {
let mut result = HashMap::new();
for scope in &self.env_vars {
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
for active_overlay in self.active_overlays.iter() {
if let Some(env_vars) = scope.get(active_overlay) {
result.extend(env_vars.clone());
}
}
}
result
2021-09-19 19:29:58 +00:00
}
/// Get flattened environment variables only from the stack and one overlay
pub fn get_stack_overlay_env_vars(&self, overlay_name: &str) -> HashMap<String, Value> {
let mut result = HashMap::new();
for scope in &self.env_vars {
if let Some(active_overlay) = self.active_overlays.iter().find(|n| n == &overlay_name) {
if let Some(env_vars) = scope.get(active_overlay) {
result.extend(env_vars.clone());
}
}
}
result
}
/// Same as get_env_vars, but returns only the names as a HashSet
pub fn get_env_var_names(&self, engine_state: &EngineState) -> HashSet<String> {
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
let mut result = HashSet::new();
for active_overlay in self.active_overlays.iter() {
if let Some(env_vars) = engine_state.env_vars.get(active_overlay) {
result.extend(
env_vars
.keys()
.filter(|k| {
if let Some(env_hidden) = self.env_hidden.get(active_overlay) {
!env_hidden.contains(*k)
} else {
// nothing has been hidden in this overlay
true
}
})
.cloned()
.collect::<HashSet<String>>(),
);
}
}
for scope in &self.env_vars {
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
for active_overlay in self.active_overlays.iter() {
if let Some(env_vars) = scope.get(active_overlay) {
result.extend(env_vars.keys().cloned().collect::<HashSet<String>>());
}
}
}
result
}
Use only $nu.env.PWD for getting the current directory (#587) * Use only $nu.env.PWD for getting current directory Because setting and reading to/from std::env changes the global state shich is problematic if we call `cd` from multiple threads (e.g., in a `par-each` block). With this change, when engine-q starts, it will either inherit existing PWD env var, or create a new one from `std::env::current_dir()`. Otherwise, everything that needs the current directory will get it from `$nu.env.PWD`. Each spawned external command will get its current directory per-process which should be thread-safe. One thing left to do is to patch nu-path for this as well since it uses `std::env::current_dir()` in its expansions. * Rename nu-path functions *_with is not *_relative which should be more descriptive and frees "with" for use in a followup commit. * Clone stack every each iter; Fix some commands Cloning the stack each iteration of `each` makes sure we're not reusing PWD between iterations. Some fixes in commands to make them use the new PWD. * Post-rebase cleanup, fmt, clippy * Change back _relative to _with in nu-path funcs Didn't use the idea I had for the new "_with". * Remove leftover current_dir from rebase * Add cwd sync at merge_delta() This makes sure the parser and completer always have up-to-date cwd. * Always pass absolute path to glob in ls * Do not allow PWD a relative path; Allow recovery Makes it possible to recover PWD by proceeding with the REPL cycle. * Clone stack in each also for byte/string stream * (WIP) Start moving env variables to engine state * (WIP) Move env vars to engine state (ugly) Quick and dirty code. * (WIP) Remove unused mut and args; Fmt * (WIP) Fix dataframe tests * (WIP) Fix missing args after rebase * (WIP) Clone only env vars, not the whole stack * (WIP) Add env var clone to `for` loop as well * Minor edits * Refactor merge_delta() to include stack merging. Less error-prone than doing it manually. * Clone env for each `update` command iteration * Mark env var hidden only when found in eng. state * Fix clippt warnings * Add TODO about env var reading * Do not clone empty environment in loops * Remove extra cwd collection * Split current_dir() into str and path; Fix autocd * Make completions respect PWD env var
2022-01-04 22:30:34 +00:00
pub fn get_env_var(&self, engine_state: &EngineState, name: &str) -> Option<Value> {
for scope in self.env_vars.iter().rev() {
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
for active_overlay in self.active_overlays.iter().rev() {
if let Some(env_vars) = scope.get(active_overlay) {
if let Some(v) = env_vars.get(name) {
return Some(v.clone());
}
}
}
2021-10-25 04:01:02 +00:00
}
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
for active_overlay in self.active_overlays.iter().rev() {
let is_hidden = if let Some(env_hidden) = self.env_hidden.get(active_overlay) {
env_hidden.contains(name)
} else {
false
};
if !is_hidden {
if let Some(env_vars) = engine_state.env_vars.get(active_overlay) {
if let Some(v) = env_vars.get(name) {
return Some(v.clone());
}
}
}
Use only $nu.env.PWD for getting the current directory (#587) * Use only $nu.env.PWD for getting current directory Because setting and reading to/from std::env changes the global state shich is problematic if we call `cd` from multiple threads (e.g., in a `par-each` block). With this change, when engine-q starts, it will either inherit existing PWD env var, or create a new one from `std::env::current_dir()`. Otherwise, everything that needs the current directory will get it from `$nu.env.PWD`. Each spawned external command will get its current directory per-process which should be thread-safe. One thing left to do is to patch nu-path for this as well since it uses `std::env::current_dir()` in its expansions. * Rename nu-path functions *_with is not *_relative which should be more descriptive and frees "with" for use in a followup commit. * Clone stack every each iter; Fix some commands Cloning the stack each iteration of `each` makes sure we're not reusing PWD between iterations. Some fixes in commands to make them use the new PWD. * Post-rebase cleanup, fmt, clippy * Change back _relative to _with in nu-path funcs Didn't use the idea I had for the new "_with". * Remove leftover current_dir from rebase * Add cwd sync at merge_delta() This makes sure the parser and completer always have up-to-date cwd. * Always pass absolute path to glob in ls * Do not allow PWD a relative path; Allow recovery Makes it possible to recover PWD by proceeding with the REPL cycle. * Clone stack in each also for byte/string stream * (WIP) Start moving env variables to engine state * (WIP) Move env vars to engine state (ugly) Quick and dirty code. * (WIP) Remove unused mut and args; Fmt * (WIP) Fix dataframe tests * (WIP) Fix missing args after rebase * (WIP) Clone only env vars, not the whole stack * (WIP) Add env var clone to `for` loop as well * Minor edits * Refactor merge_delta() to include stack merging. Less error-prone than doing it manually. * Clone env for each `update` command iteration * Mark env var hidden only when found in eng. state * Fix clippt warnings * Add TODO about env var reading * Do not clone empty environment in loops * Remove extra cwd collection * Split current_dir() into str and path; Fix autocd * Make completions respect PWD env var
2022-01-04 22:30:34 +00:00
}
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
None
2021-10-02 13:10:28 +00:00
}
pub fn has_env_var(&self, engine_state: &EngineState, name: &str) -> bool {
for scope in self.env_vars.iter().rev() {
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
for active_overlay in self.active_overlays.iter().rev() {
if let Some(env_vars) = scope.get(active_overlay) {
if env_vars.contains_key(name) {
return true;
}
}
}
}
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
for active_overlay in self.active_overlays.iter().rev() {
let is_hidden = if let Some(env_hidden) = self.env_hidden.get(active_overlay) {
env_hidden.contains(name)
} else {
false
};
if !is_hidden {
if let Some(env_vars) = engine_state.env_vars.get(active_overlay) {
if env_vars.contains_key(name) {
return true;
}
}
}
}
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
false
}
pub fn remove_env_var(&mut self, engine_state: &EngineState, name: &str) -> bool {
for scope in self.env_vars.iter_mut().rev() {
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
let scope = Arc::make_mut(scope);
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
for active_overlay in self.active_overlays.iter().rev() {
if let Some(env_vars) = scope.get_mut(active_overlay) {
if env_vars.remove(name).is_some() {
return true;
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
}
}
}
}
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
for active_overlay in self.active_overlays.iter().rev() {
if let Some(env_vars) = engine_state.env_vars.get(active_overlay) {
if env_vars.get(name).is_some() {
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
let env_hidden = Arc::make_mut(&mut self.env_hidden);
if let Some(env_hidden_in_overlay) = env_hidden.get_mut(active_overlay) {
env_hidden_in_overlay.insert(name.into());
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
} else {
Use Arc for environment variables on the stack (#13333) # Description This is another easy performance lift that just changes `env_vars` and `env_hidden` on `Stack` to use `Arc`. I noticed that these were being cloned on essentially every closure invocation during captures gathering, so we're paying the cost for all of that even when we don't change anything. On top of that, for `env_vars`, there's actually an entirely fresh `HashMap` created for each child scope, so it's highly unlikely that we'll modify the parent ones. Uses `Arc::make_mut` instead to take care of things when we need to mutate something, and most of the time nothing has to be cloned at all. # Benchmarks The benefits are greater the more calls there are to env-cloning functions like `captures_to_stack()`. Calling custom commands in a loop is basically best case for a performance improvement. Plain `each` with a literal block isn't so badly affected because the stack is set up once. ## random_bytes.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/random-bytes.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 603ms 759µs 727ns │ │ │ │ │ min │ 593ms 298µs 167ns │ │ │ │ │ max │ 648ms 612µs 291ns │ │ │ │ │ std │ 9ms 335µs 251ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 518ms 400µs 557ns │ │ │ │ │ min │ 507ms 762µs 583ns │ │ │ │ │ max │ 566ms 695µs 166ns │ │ │ │ │ std │ 9ms 554µs 767ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` ## gradient_benchmark_no_check.nu ```nushell use std bench do { const SCRIPT = ../nu_scripts/benchmarks/gradient_benchmark_no_check.nu let before_change = bench { nu $SCRIPT } let after_change = bench { target/release/nu $SCRIPT } { before: ($before_change | reject times), after: ($after_change | reject times) } } ``` ``` ╭────────┬──────────────────────────────╮ │ │ ╭──────┬───────────────────╮ │ │ before │ │ mean │ 146ms 543µs 380ns │ │ │ │ │ min │ 142ms 416µs 166ns │ │ │ │ │ max │ 189ms 595µs │ │ │ │ │ std │ 7ms 140µs 342ns │ │ │ │ ╰──────┴───────────────────╯ │ │ │ ╭──────┬───────────────────╮ │ │ after │ │ mean │ 134ms 211µs 678ns │ │ │ │ │ min │ 132ms 433µs 125ns │ │ │ │ │ max │ 135ms 722µs 583ns │ │ │ │ │ std │ 793µs 134ns │ │ │ │ ╰──────┴───────────────────╯ │ ╰────────┴──────────────────────────────╯ ``` # User-Facing Changes Better performance, particularly for custom commands, especially if there are a lot of environment variables. Nothing else. # Tests + Formatting All passing.
2024-07-11 00:34:50 +00:00
env_hidden
.insert(active_overlay.into(), [name.into()].into_iter().collect());
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
}
return true;
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
}
}
}
false
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
}
pub fn has_env_overlay(&self, name: &str, engine_state: &EngineState) -> bool {
for scope in self.env_vars.iter().rev() {
if scope.contains_key(name) {
return true;
}
2021-08-15 22:33:34 +00:00
}
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
engine_state.env_vars.contains_key(name)
}
pub fn is_overlay_active(&self, name: &str) -> bool {
self.active_overlays.iter().any(|n| n == name)
}
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
pub fn add_overlay(&mut self, name: String) {
self.active_overlays.retain(|o| o != &name);
self.active_overlays.push(name);
}
pub fn remove_overlay(&mut self, name: &str) {
Overlays (#5375) * 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>
2022-05-07 19:39:22 +00:00
self.active_overlays.retain(|o| o != name);
}
/// Returns the [`OutDest`] to use for the current command's stdout.
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
///
/// This will be the pipe redirection if one is set,
/// otherwise it will be the current file redirection,
/// otherwise it will be the process's stdout indicated by [`OutDest::Inherit`].
pub fn stdout(&self) -> &OutDest {
self.out_dest.stdout()
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
}
/// Returns the [`OutDest`] to use for the current command's stderr.
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
///
/// This will be the pipe redirection if one is set,
/// otherwise it will be the current file redirection,
/// otherwise it will be the process's stderr indicated by [`OutDest::Inherit`].
pub fn stderr(&self) -> &OutDest {
self.out_dest.stderr()
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
}
/// Returns the [`OutDest`] of the pipe redirection applied to the current command's stdout.
pub fn pipe_stdout(&self) -> Option<&OutDest> {
self.out_dest.pipe_stdout.as_ref()
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
}
/// Returns the [`OutDest`] of the pipe redirection applied to the current command's stderr.
pub fn pipe_stderr(&self) -> Option<&OutDest> {
self.out_dest.pipe_stderr.as_ref()
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
}
/// Temporarily set the pipe stdout redirection to [`OutDest::Capture`].
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
///
/// This is used before evaluating an expression into a `Value`.
pub fn start_capture(&mut self) -> StackCaptureGuard {
StackCaptureGuard::new(self)
}
/// Temporarily use the output redirections in the parent scope.
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
///
/// This is used before evaluating an argument to a call.
pub fn use_call_arg_out_dest(&mut self) -> StackCallArgGuard {
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
StackCallArgGuard::new(self)
}
/// Temporarily apply redirections to stdout and/or stderr.
pub fn push_redirection(
&mut self,
stdout: Option<Redirection>,
stderr: Option<Redirection>,
) -> StackIoGuard {
StackIoGuard::new(self, stdout, stderr)
}
/// Mark stdout for the last command as [`OutDest::Capture`].
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
///
/// This will irreversibly alter the output redirections, and so it only makes sense to use this on an owned `Stack`
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
/// (which is why this function does not take `&mut self`).
///
/// See [`Stack::start_capture`] which can temporarily set stdout as [`OutDest::Capture`] for a mutable `Stack` reference.
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
pub fn capture(mut self) -> Self {
self.out_dest.pipe_stdout = Some(OutDest::Capture);
self.out_dest.pipe_stderr = None;
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
self
}
/// Clears any pipe and file redirections and resets stdout and stderr to [`OutDest::Inherit`].
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
///
/// This will irreversibly reset the output redirections, and so it only makes sense to use this on an owned `Stack`
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
/// (which is why this function does not take `&mut self`).
pub fn reset_out_dest(mut self) -> Self {
self.out_dest = StackOutDest::new();
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
self
}
/// Clears any pipe redirections, keeping the current stdout and stderr.
///
/// This will irreversibly reset some of the output redirections, and so it only makes sense to use this on an owned `Stack`
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
/// (which is why this function does not take `&mut self`).
pub fn reset_pipes(mut self) -> Self {
self.out_dest.pipe_stdout = None;
self.out_dest.pipe_stderr = None;
IO and redirection overhaul (#11934) # Description The PR overhauls how IO redirection is handled, allowing more explicit and fine-grain control over `stdout` and `stderr` output as well as more efficient IO and piping. To summarize the changes in this PR: - Added a new `IoStream` type to indicate the intended destination for a pipeline element's `stdout` and `stderr`. - The `stdout` and `stderr` `IoStream`s are stored in the `Stack` and to avoid adding 6 additional arguments to every eval function and `Command::run`. The `stdout` and `stderr` streams can be temporarily overwritten through functions on `Stack` and these functions will return a guard that restores the original `stdout` and `stderr` when dropped. - In the AST, redirections are now directly part of a `PipelineElement` as a `Option<Redirection>` field instead of having multiple different `PipelineElement` enum variants for each kind of redirection. This required changes to the parser, mainly in `lite_parser.rs`. - `Command`s can also set a `IoStream` override/redirection which will apply to the previous command in the pipeline. This is used, for example, in `ignore` to allow the previous external command to have its stdout redirected to `Stdio::null()` at spawn time. In contrast, the current implementation has to create an os pipe and manually consume the output on nushell's side. File and pipe redirections (`o>`, `e>`, `e>|`, etc.) have precedence over overrides from commands. This PR improves piping and IO speed, partially addressing #10763. Using the `throughput` command from that issue, this PR gives the following speedup on my setup for the commands below: | Command | Before (MB/s) | After (MB/s) | Bash (MB/s) | | --------------------------- | -------------:| ------------:| -----------:| | `throughput o> /dev/null` | 1169 | 52938 | 54305 | | `throughput \| ignore` | 840 | 55438 | N/A | | `throughput \| null` | Error | 53617 | N/A | | `throughput \| rg 'x'` | 1165 | 3049 | 3736 | | `(throughput) \| rg 'x'` | 810 | 3085 | 3815 | (Numbers above are the median samples for throughput) This PR also paves the way to refactor our `ExternalStream` handling in the various commands. For example, this PR already fixes the following code: ```nushell ^sh -c 'echo -n "hello "; sleep 0; echo "world"' | find "hello world" ``` This returns an empty list on 0.90.1 and returns a highlighted "hello world" on this PR. Since the `stdout` and `stderr` `IoStream`s are available to commands when they are run, then this unlocks the potential for more convenient behavior. E.g., the `find` command can disable its ansi highlighting if it detects that the output `IoStream` is not the terminal. Knowing the output streams will also allow background job output to be redirected more easily and efficiently. # User-Facing Changes - External commands returned from closures will be collected (in most cases): ```nushell 1..2 | each {|_| nu -c "print a" } ``` This gives `["a", "a"]` on this PR, whereas this used to print "a\na\n" and then return an empty list. ```nushell 1..2 | each {|_| nu -c "print -e a" } ``` This gives `["", ""]` and prints "a\na\n" to stderr, whereas this used to return an empty list and print "a\na\n" to stderr. - Trailing new lines are always trimmed for external commands when piping into internal commands or collecting it as a value. (Failure to decode the output as utf-8 will keep the trailing newline for the last binary value.) In the current nushell version, the following three code snippets differ only in parenthesis placement, but they all also have different outputs: 1. `1..2 | each { ^echo a }` ``` a a ╭────────────╮ │ empty list │ ╰────────────╯ ``` 2. `1..2 | each { (^echo a) }` ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` 3. `1..2 | (each { ^echo a })` ``` ╭───┬───╮ │ 0 │ a │ │ │ │ │ 1 │ a │ │ │ │ ╰───┴───╯ ``` But in this PR, the above snippets will all have the same output: ``` ╭───┬───╮ │ 0 │ a │ │ 1 │ a │ ╰───┴───╯ ``` - All existing flags on `run-external` are now deprecated. - File redirections now apply to all commands inside a code block: ```nushell (nu -c "print -e a"; nu -c "print -e b") e> test.out ``` This gives "a\nb\n" in `test.out` and prints nothing. The same result would happen when printing to stdout and using a `o>` file redirection. - External command output will (almost) never be ignored, and ignoring output must be explicit now: ```nushell (^echo a; ^echo b) ``` This prints "a\nb\n", whereas this used to print only "b\n". This only applies to external commands; values and internal commands not in return position will not print anything (e.g., `(echo a; echo b)` still only prints "b"). - `complete` now always captures stderr (`do` is not necessary). # After Submitting The language guide and other documentation will need to be updated.
2024-03-14 20:51:55 +00:00
self
2021-08-15 22:33:34 +00:00
}
Add Stack::stdout_file and Stack::stderr_file to capture stdout/-err of external commands (#12857) # Description In this PR I added two new methods to `Stack`, `stdout_file` and `stderr_file`. These two modify the inner `StackOutDest` and set a `File` into the `stdout` and `stderr` respectively. Different to the `push_redirection` methods, these do not require to hold a guard up all the time but require ownership of the stack. This is primarly useful for applications that use `nu` as a language but not the `nushell`. This PR replaces my first attempt #12851 to add a way to capture stdout/-err of external commands. Capturing the stdout without having to write into a file is possible with crates like [`os_pipe`](https://docs.rs/os_pipe), an example for this is given in the doc comment of the `stdout_file` command and can be executed as a doctest (although it doesn't validate that you actually got any data). This implementation takes `File` as input to make it easier to implement on different operating systems without having to worry about `OwnedHandle` or `OwnedFd`. Also this doesn't expose any use `os_pipe` to not leak its types into this API, making it depend on it. As in my previous attempt, @IanManske guided me here. # User-Facing Changes This change has no effect on `nushell` and therefore no user-facing changes. # Tests + Formatting This only exposes a new way of using already existing code and has therefore no further testing. The doctest succeeds on my machine at least (x86 Windows, 64 Bit). # After Submitting All the required documentation is already part of this PR.
2024-05-13 18:48:38 +00:00
/// Replaces the default stdout of the stack with a given file.
///
/// This method configures the default stdout to redirect to a specified file.
/// It is primarily useful for applications using `nu` as a language, where the stdout of
/// external commands that are not explicitly piped can be redirected to a file.
///
/// # Using Pipes
///
/// For use in third-party applications pipes might be very useful as they allow using the
/// stdout of external commands for different uses.
/// For example the [`os_pipe`](https://docs.rs/os_pipe) crate provides a elegant way to to
/// access the stdout.
///
/// ```
/// # use std::{fs::File, io::{self, Read}, thread, error};
/// # use nu_protocol::engine::Stack;
/// #
/// let (mut reader, writer) = os_pipe::pipe().unwrap();
/// // Use a thread to avoid blocking the execution of the called command.
/// let reader = thread::spawn(move || {
/// let mut buf: Vec<u8> = Vec::new();
/// reader.read_to_end(&mut buf)?;
/// Ok::<_, io::Error>(buf)
/// });
///
/// #[cfg(windows)]
/// let file = std::os::windows::io::OwnedHandle::from(writer).into();
/// #[cfg(unix)]
/// let file = std::os::unix::io::OwnedFd::from(writer).into();
///
/// let stack = Stack::new().stdout_file(file);
///
/// // Execute some nu code.
///
/// drop(stack); // drop the stack so that the writer will be dropped too
/// let buf = reader.join().unwrap().unwrap();
/// // Do with your buffer whatever you want.
/// ```
pub fn stdout_file(mut self, file: File) -> Self {
self.out_dest.stdout = OutDest::File(Arc::new(file));
self
}
/// Replaces the default stderr of the stack with a given file.
///
/// For more info, see [`stdout_file`](Self::stdout_file).
pub fn stderr_file(mut self, file: File) -> Self {
self.out_dest.stderr = OutDest::File(Arc::new(file));
self
}
/// Set the PWD environment variable to `path`.
///
/// This method accepts `path` with trailing slashes, but they're removed
/// before writing the value into PWD.
pub fn set_cwd(&mut self, path: impl AsRef<std::path::Path>) -> Result<(), ShellError> {
// Helper function to create a simple generic error.
// Its messages are not especially helpful, but these errors don't occur often, so it's probably fine.
fn error(msg: &str) -> Result<(), ShellError> {
Err(ShellError::GenericError {
error: msg.into(),
msg: "".into(),
span: None,
help: None,
inner: vec![],
})
}
let path = path.as_ref();
if !path.is_absolute() {
error("Cannot set $env.PWD to a non-absolute path")
} else if !path.exists() {
error("Cannot set $env.PWD to a non-existent directory")
} else if !path.is_dir() {
error("Cannot set $env.PWD to a non-directory")
} else {
// Strip trailing slashes, if any.
let path = nu_path::strip_trailing_slash(path);
let value = Value::string(path.to_string_lossy(), Span::unknown());
self.add_env_var("PWD".into(), value);
Ok(())
}
}
2021-08-15 22:33:34 +00:00
}
#[cfg(test)]
mod test {
use std::sync::Arc;
use crate::{engine::EngineState, Span, Value};
use super::Stack;
const ZERO_SPAN: Span = Span { start: 0, end: 0 };
fn string_value(s: &str) -> Value {
Value::String {
val: s.to_string(),
internal_span: ZERO_SPAN,
}
}
#[test]
fn test_children_see_inner_values() {
let mut original = Stack::new();
original.add_var(0, string_value("hello"));
let cloned = Stack::with_parent(Arc::new(original));
assert_eq!(cloned.get_var(0, ZERO_SPAN), Ok(string_value("hello")));
}
#[test]
fn test_children_dont_see_deleted_values() {
let mut original = Stack::new();
original.add_var(0, string_value("hello"));
let mut cloned = Stack::with_parent(Arc::new(original));
cloned.remove_var(0);
assert_eq!(
cloned.get_var(0, ZERO_SPAN),
Err(crate::ShellError::VariableNotFoundAtRuntime { span: ZERO_SPAN })
);
}
#[test]
fn test_children_changes_override_parent() {
let mut original = Stack::new();
original.add_var(0, string_value("hello"));
let mut cloned = Stack::with_parent(Arc::new(original));
cloned.add_var(0, string_value("there"));
assert_eq!(cloned.get_var(0, ZERO_SPAN), Ok(string_value("there")));
cloned.remove_var(0);
// the underlying value shouldn't magically re-appear
assert_eq!(
cloned.get_var(0, ZERO_SPAN),
Err(crate::ShellError::VariableNotFoundAtRuntime { span: ZERO_SPAN })
);
}
#[test]
fn test_children_changes_persist_in_offspring() {
let mut original = Stack::new();
original.add_var(0, string_value("hello"));
let mut cloned = Stack::with_parent(Arc::new(original));
cloned.add_var(1, string_value("there"));
cloned.remove_var(0);
let cloned = Stack::with_parent(Arc::new(cloned));
assert_eq!(
cloned.get_var(0, ZERO_SPAN),
Err(crate::ShellError::VariableNotFoundAtRuntime { span: ZERO_SPAN })
);
assert_eq!(cloned.get_var(1, ZERO_SPAN), Ok(string_value("there")));
}
#[test]
fn test_merging_children_back_to_parent() {
let mut original = Stack::new();
let engine_state = EngineState::new();
original.add_var(0, string_value("hello"));
let original_arc = Arc::new(original);
let mut cloned = Stack::with_parent(original_arc.clone());
cloned.add_var(1, string_value("there"));
cloned.remove_var(0);
cloned.add_env_var("ADDED_IN_CHILD".to_string(), string_value("New Env Var"));
let original = Stack::with_changes_from_child(original_arc, cloned);
assert_eq!(
original.get_var(0, ZERO_SPAN),
Err(crate::ShellError::VariableNotFoundAtRuntime { span: ZERO_SPAN })
);
assert_eq!(original.get_var(1, ZERO_SPAN), Ok(string_value("there")));
assert_eq!(
original.get_env_var(&engine_state, "ADDED_IN_CHILD"),
Some(string_value("New Env Var")),
);
}
}