Compare commits

...

116 Commits

Author SHA1 Message Date
388973e9ab Bump to 0.26.0 (#2974) 2021-01-26 23:07:08 +13:00
2129ec7558 allow pad to use multi-byte chars (#2973) 2021-01-26 22:09:38 +13:00
82f122525c Delete nushell-demo.svg 2021-01-25 20:35:10 +13:00
7c4c00f1e6 Update README.md 2021-01-25 20:34:05 +13:00
fe6c7dc10a Add files via upload 2021-01-25 20:33:06 +13:00
9bc24e3b12 Remove unnecessary clone() (#2970) 2021-01-25 20:13:05 +13:00
833baca66e Add a new animated demo (#2971) 2021-01-25 20:12:44 +13:00
9fd92512a2 Use equality assert macros (#2969) 2021-01-25 18:16:10 +13:00
b692ca7896 Fix ps sys units (#2967)
* Fix the units for sys and ps

* Better conversion
2021-01-25 08:34:43 +13:00
52dc04a35a Error on bad row in column path (#2964)
* Error on bad row in column path

* Add more pathing tests
2021-01-22 18:14:13 -05:00
42b1287759 Parity and anchor carrying for str command suite. (#2965)
Bring the majority of str sub commands to parity supporting their actions
by column paths. Ensuring they carry over anchor meta data as well.
2021-01-22 18:13:30 -05:00
5a471aa1d0 fixed char signature (#2963) 2021-01-22 15:48:31 -06:00
a4b8d4a098 Add rest support to blocks (#2962) 2021-01-23 10:28:32 +13:00
a3be6affa4 fix some misalignment errors (#2959) 2021-01-23 07:39:09 +13:00
71b99edd48 parser/add rest args to def (#2961)
* Add rest arg to def

This commit applied adds the ability to define the rest parameter of a def
command. It does not implement the functionality to expand the rest argument in
a user defined def function.

The rest argument has to be exactly worded "...rest".

Example after this PR is applied:

file test.nu
```shell
def my_command [
    ...rest:int # My rest arg
] {
    echo 1 2 3
}
```

```shell
> source test.nu
> my_command -h
Usage:
  > my_command ...args {flags}

Parameters:
  ...args: My rest arg

Flags:
  -h, --help: Display this help message
```

* Fix space in help on wrong side
2021-01-23 07:13:29 +13:00
64553ddcb7 upgrade shadow-rs 0.5.23 (#2960)
* update to shadow-rs 0.4. use easy

* update shadow-rs to 0.5

* fix version not used

* update

* update Cargo.lock

* update Cargo.lock

* fix wasm build error when use dependence git2
fix error link:https://dev.azure.com/nushell/nushell/_build/results?buildId=4858&view=logs&j=1a745d4c-b027-5f34-06d8-d6f256bfe9f9&t=a0a335cb-fa1f-5bbf-be01-1a90d6899e54

* remove code not used; fix warning by RUSTFLAGS="-D warnings" build error

* upgrade shadow-rs 0.5.2

* upgrade shadow-rs 0.5.7

make nushell reduce dependence crates smaller and  build fast.

* upgrade shadow-rs 0.5.8

fix when use api 'strip_prefix()' method in less than rust1.45.0 build failed

* fix https://github.com/baoyachi/shadow-rs/issues?q=is%3Aissue+is%3Aclosed
2021-01-23 07:09:57 +13:00
2a42482ae9 Clean up and refactoring examples tests. (#2957) 2021-01-20 21:07:16 -05:00
11f345a8ae added more char escapes (#2955)
* added more char escapes

* move commands with \x1b over from char.rs to ansi.rs
2021-01-21 13:15:58 +13:00
fec50d8cfe Fix bug #2921 (#2945)
* Fix bug #2921

Moving whether a range should be parsed further back, giving e.G. parsing of
invocations precedence fixes the bug

* Add test
2021-01-21 07:58:37 +13:00
05e42381df Add --skip flag to nth command (#2953)
clippy & rustfmt included
2021-01-21 06:37:30 +13:00
b435075e09 Temporarily(?) switch from heim+uom to sysinfo (#2954)
* Switch from heim to sysinfo

* WIP

* more cleanup

* fmt

* lint
2021-01-20 20:18:38 +13:00
430da53f0b Replace dirs and directories with maintained (#2949) 2021-01-19 14:24:27 -06:00
2e6d836dd1 Flush out! lines, helps autoview (#2952) 2021-01-20 07:23:37 +13:00
899d324a9c fix: error Variable not in scope for a def parameter #2901 (#2951)
adding tests to notice regressions on this issue

Co-authored-by: hk <alexhaka10@protonmail.com>
2021-01-20 07:21:11 +13:00
576ed6a906 parser/split long short flags (#2944)
* Remove wrong test case

* Parse long and shortflags without space correctly

* Update param_flag_list.rs

* Update param_flag_list.rs

Co-authored-by: Jonathan Turner <jonathandturner@users.noreply.github.com>
2021-01-20 07:19:53 +13:00
d744cf8437 [Gitpod] Don't test removed feature 'test-bins' (#2948)
Fixes nushell/nushell#2947
2021-01-19 22:43:42 +13:00
088e662285 Replace git current_branch to shadow-rs branch (#2935)
* update to shadow-rs 0.4. use easy

* update shadow-rs to 0.5

* fix version not used

* update

* update Cargo.lock

* update Cargo.lock

* fix wasm build error when use dependence git2
fix error link:https://dev.azure.com/nushell/nushell/_build/results?buildId=4858&view=logs&j=1a745d4c-b027-5f34-06d8-d6f256bfe9f9&t=a0a335cb-fa1f-5bbf-be01-1a90d6899e54

* remove code not used; fix warning by RUSTFLAGS="-D warnings" build error

* upgrade shadow-rs 0.5.2

* upgrade shadow-rs 0.5.7

make nushell reduce dependence crates smaller and  build fast.

* upgrade shadow-rs 0.5.8

fix when use api 'strip_prefix()' method in less than rust1.45.0 build failed

* use shadow-rs branch replace with current_branch method;
remove and reduce git dependencies.

* upgrade shadow-rs 0.5.12-pre,test build error with wasm

* upgrade Cargo.lock

* upgarde shadow-rs depencdence

* fix build error in wasm

* add clippy warning
2021-01-16 07:06:29 +13:00
f9b0b81eb2 Add def documentation (#2939) 2021-01-15 20:21:18 +13:00
c5485c6501 a small regex optimization (#2937)
* a small regex optimization

* removed comments
2021-01-15 20:20:28 +13:00
d8ed01400f str set sub command removal. (#2940) 2021-01-14 18:55:37 -05:00
ebc4694e05 move keybinding_path to nu-data (#2927) 2021-01-14 06:31:47 +13:00
a9441d670e Revert tab completion changes (#2929)
* Undo tab completion changes

* Remove extra newline
2021-01-14 06:29:18 +13:00
495d2ebd70 Improve tab completion behaviour (#2916)
* Improve tab completion behaviour

* Fix clippy issue

* Add test cases
2021-01-13 17:04:29 +13:00
ad26adc3e3 remove set from windows cmd_builtins (#2924) 2021-01-13 14:46:58 +13:00
63a62e19f9 Update alias docs (#2925) 2021-01-13 14:46:15 +13:00
4f2ae34df9 Don't throw err on typename as parameter name (#2926)
Before this was an error:
`def e [path:path] {echo $path}`
Now its not.
2021-01-13 14:44:55 +13:00
a636f161a4 Add dirs dependency to nu-engine (#2922)
* Add dirs dependency to nu-engine

* Dir feature should be added to root features
2021-01-13 10:18:13 +13:00
dfb1e22559 Update alias docs to new syntax (#2917)
This confused me today after upgrading Nu. I believe this is now correct.
2021-01-13 08:30:27 +13:00
dff85a7f70 RangeIterator can also go down (#2913) 2021-01-13 08:27:54 +13:00
3be198d2f5 Don't print description in help if none exists (#2915) 2021-01-13 07:27:48 +13:00
d19314fe3a Fix the wasm build (#2919) 2021-01-13 07:14:35 +13:00
d06f457b2a nu-cli refactor moving commands into their own crate nu-command (#2910)
* move commands, futures.rs, script.rs, utils

* move over maybe_print_errors

* add nu_command crate references to nu_cli

* in commands.rs open up to pub mod from pub(crate)

* nu-cli, nu-command, and nu tests are now passing

* cargo fmt

* clean up nu-cli/src/prelude.rs

* code cleanup

* for some reason lex.rs was not formatted, may be causing my error

* remove mod completion from lib.rs which was not being used along with quickcheck macros

* add in allow unused imports

* comment out one failing external test; comment out one failing internal test

* revert commenting out failing tests; something else might be going on; someone with a windows machine should check and see what is going on with these failing windows tests

* Update Cargo.toml

Extend the optional features to nu-command

Co-authored-by: Jonathan Turner <jonathandturner@users.noreply.github.com>
2021-01-12 17:59:53 +13:00
7d07881d96 Bump to 0.25.2 (#2908) 2021-01-12 07:50:53 +13:00
3e6e3a207c Feature/def signature with comments (#2905)
* Put parse_definition related funcs into own module

* Add failing lexer test

* Implement Parsing of definition signature

This commit applied changes how the signature of a function is parsed. Before
there was a little bit of "quick-and-dirty" string-matching/parsing involved.
Now, a signature is a little bit more properly parsed.
The grammar of a definition signature understood by these parsing-functions is
as follows:
 `[ (parameter | flag | <eol>)* ]`
where
parameter is:
    `name (<:> type)? (<,> | <eol> | (#Comment <eol>))?`
flag is:
    `--name (-shortform)? (<:> type)? (<,> | <eol> | (#Comment <eol>))?`
(Note: After the last item no <,> has to come.)
Note: It is now possible to pass comments to flags and parameters
Example:
[
  d:int          # The required d parameter
  --x (-x):string # The all powerful x flag
  --y (-y):int    # The accompanying y flag
]

(Sadly there seems to be a bug (Or is this expected behaviour?) in the lexer, because of which `--x(-x)` would
be treated as one baseline token and is therefore not correctly recognized as 2. For
now a space has to be inserted)

During the implementation of the module, 2 question arose:
Should flag/parameter names be allowed to be type names?
Example case:
```shell
def f [ string ] { echo $string }
```
Currently an error is thrown

* Fix clippy lints

* Remove wrong comment

* Add spacing

* Add Cargo.lock
2021-01-12 06:53:58 +13:00
481c6d4511 nu_cli refactor in preparation for a crate called nu_command (#2907)
* move basic_shell_manager to nu-engine

* move basic_evaluation_context to nu-engine

* fix failing test in feature which commands/classified/external.rs
2021-01-11 17:58:15 +13:00
231a445809 working for comparing filepath to string (#2906)
* working for comparing filepath to string

* added tests
2021-01-11 16:41:19 +13:00
93e8f6c05e Split nu-cli into nu-cli/nu-engine (#2898)
We split off the evaluation engine part of nu-cli into its own crate. This helps improve build times for nu-cli by 17% in my tests. It also helps us see a bit better what's the core engine portion vs the part specific to the interactive CLI piece.

There's more than can be done here, but I think it's a good start in the right direction.
2021-01-10 15:50:49 +13:00
9de2144fc4 compare filepath and string (#2897) 2021-01-09 14:09:49 -06:00
363dc51ba0 Add aliased command to which output (#2894)
* Add aliased command to which output

* Fix alias arguments not being displayed
2021-01-10 06:19:46 +13:00
99117ff2ef Fix reading/writing bigint and bigdecimal (#2893) 2021-01-09 12:53:59 +13:00
5356cb9fbd Obey precedence rules in which; Fix #2875 (#2885)
* Obay precedence rules in which; Fix #2875

Before which did not obay the precedence of alias before def commands.
Furthermore, `which -a echo` would only report either an alias or a def command or an
internal command with the provided name. Not all.

With this commit applied its fixed :)

Example:
```shell
/home/leo/repos/nushell(fix/which_reports_wrong_usage)> def echo [] {^echo hi}
/home/leo/repos/nushell(fix/which_reports_wrong_usage)> echo
hi
/home/leo/repos/nushell(fix/which_reports_wrong_usage)> which -a echo
───┬──────┬──────────────────────────┬─────────
 # │ arg  │           path           │ builtin
───┼──────┼──────────────────────────┼─────────
 0 │ echo │ Nushell custom command   │ No
 1 │ echo │ Nushell built-in command │ Yes
 2 │ echo │ /usr/bin/echo            │ No
───┴──────┴──────────────────────────┴─────────
/home/leo/repos/nushell(fix/which_reports_wrong_usage)> alias echo = ^echo hi there
/home/leo/repos/nushell(fix/which_reports_wrong_usage)> echo
hi there
/home/leo/repos/nushell(fix/which_reports_wrong_usage)> which -a echo
───┬──────┬──────────────────────────┬─────────
 # │ arg  │           path           │ builtin
───┼──────┼──────────────────────────┼─────────
 0 │ echo │ Nushell alias            │ No
 1 │ echo │ Nushell custom command   │ No
 2 │ echo │ Nushell built-in command │ Yes
 3 │ echo │ /usr/bin/echo            │ No
───┴──────┴──────────────────────────┴─────────
```

* Fix clippy lint

* Fix vec always Some even if empty
2021-01-09 06:44:31 +13:00
0e13d9fbaa Rename the Path and Pattern primitives (#2889)
* Rename the Path primitive to FilePath

* Rename glob pattern also

* more fun

* Fix the Windows path methods
2021-01-08 20:30:41 +13:00
2dcb16870b Treat all the startup commands as a single script file (#2890) 2021-01-08 19:36:31 +13:00
ac9909112f Remove the line primitive (#2887) 2021-01-08 14:45:25 +13:00
eb3c2c9e76 Add comments to next LiteCommand (#2846)
This commit applied adds comments preceding a command to the LiteCommands new
field `comments`.

This can be usefull for example when defining a function with `def`. Nushell
could pick up the comments and display them when the user types `help my_def_func`.

Example
```shell
def my_echo [arg] { echo $arg }
```
The LiteCommand def will now contain the comments `My echo` and `It's much
better :)`.

The comment is not associated with the next command if there is a (or multiple) newline
between them.
Example
```shell

echo 42
```

This new functionality is similar to DocStrings. One might introduce a special
notation for such DocStrings, so that the parser can differentiate better
between discardable comments and usefull documentation.
2021-01-08 06:14:51 +13:00
3d29e3efbf Update README.md 2021-01-07 18:12:04 +13:00
f410fb6689 Document lexer (#2865)
* Update dependencies

* Document the lexer and lightly improve its names

The bulk of this pull request adds a substantial amount of new inline
documentation for the lexer. Along the way, I made a few minor changes
to the names in the lexer, most of which were internal.

The main change that affects other files is renaming `group` to `block`,
since the function is actually parsing a block (a list of groups).

* Fix rustfmt

* Update lock

Co-authored-by: Jonathan Turner <jonathandturner@users.noreply.github.com>
Co-authored-by: Jonathan Turner <jonathan.d.turner@gmail.com>
2021-01-07 16:03:00 +13:00
eb62fd466e Adding coerce filesize functionality to math avg median (#2848)
* Adding coerce filesize functionality to math avg median

* Updating initial value creating in Math Summation Reducer

* Update reducers.rs

Co-authored-by: Jonathan Turner <jonathandturner@users.noreply.github.com>
2021-01-07 16:01:52 +13:00
b50cdd6de8 Update dependency rust-embed now that issue with its use of syn has been fixed. (#2880)
* update the rust-embed dependency of nu-cli to 5.8.0 and undo the version pin of syn now that rust-embed-impl has been fixed

* unpin syn version in chart plugin
2021-01-07 14:33:39 +13:00
f38e2b5c6d updated dependencies (#2857)
Same as #2786

Co-authored-by: sousajo <sousajo@pop-os.localdomain>
Co-authored-by: Jonathan Turner <jonathandturner@users.noreply.github.com>
2021-01-07 13:38:22 +13:00
455915ec9e upgrade shadow-rs 0.5.8 (#2861)
* update to shadow-rs 0.4. use easy

* update shadow-rs to 0.5

* fix version not used

* update

* update Cargo.lock

* update Cargo.lock

* fix wasm build error when use dependence git2
fix error link:https://dev.azure.com/nushell/nushell/_build/results?buildId=4858&view=logs&j=1a745d4c-b027-5f34-06d8-d6f256bfe9f9&t=a0a335cb-fa1f-5bbf-be01-1a90d6899e54

* remove code not used; fix warning by RUSTFLAGS="-D warnings" build error

* upgrade shadow-rs 0.5.2

* upgrade shadow-rs 0.5.7

make nushell reduce dependence crates smaller and  build fast.

* upgrade shadow-rs 0.5.8

fix when use api 'strip_prefix()' method in less than rust1.45.0 build failed
2021-01-07 06:51:28 +13:00
2333158256 nucli refactor: move rustyline and ctrlc features in cli.rs to line_editor.rs (#2854)
* move rustyline and ctrlc features in cli.rs to feature.rs

* rename feature.rs to line_editor.rs
2021-01-07 06:47:36 +13:00
3ffa804088 Add syn to the lock file (#2871) 2021-01-06 15:58:04 +13:00
98810d22b1 Update Cargo.toml 2021-01-06 15:37:39 +13:00
5e72b2a797 Bump to 0.25.1 for the hotfix release (#2870) 2021-01-06 15:16:08 +13:00
7e4e7fa4a6 Pin the syn version to avoid breaking change (#2868)
* Pin the syn version to avoid breaking change

* pin syn in wasm also
2021-01-06 14:32:08 +13:00
d297199d7c Bump to 0.25.0 (#2860) 2021-01-05 18:10:24 +13:00
17a433996e rename set/set-env to let/let-env (#2859) 2021-01-05 12:30:55 +13:00
b9bb4692a4 Allow source during parsing. Hacky but works (#2855) 2021-01-04 19:32:17 +13:00
d05dcdda02 make nushell reduce dependence crates smaller and build fast (#2853)
* update to shadow-rs 0.4. use easy

* update shadow-rs to 0.5

* fix version not used

* update

* update Cargo.lock

* update Cargo.lock

* fix wasm build error when use dependence git2
fix error link:https://dev.azure.com/nushell/nushell/_build/results?buildId=4858&view=logs&j=1a745d4c-b027-5f34-06d8-d6f256bfe9f9&t=a0a335cb-fa1f-5bbf-be01-1a90d6899e54

* remove code not used; fix warning by RUSTFLAGS="-D warnings" build error

* upgrade shadow-rs 0.5.2

* upgrade shadow-rs 0.5.7

make nushell reduce dependence crates smaller and  build fast.
2021-01-04 06:14:03 +13:00
27fe356214 Add proper shadowing (#2851) 2021-01-03 20:48:02 +13:00
fc44df1e45 Don't leak set/set-env/source scopes via actions (#2849) 2021-01-03 19:44:21 +13:00
77f915befe Tighten how input streams handle nothing, and related (#2847) 2021-01-03 14:22:44 +13:00
a5f7600f6f Fix typos (#2842) 2021-01-02 17:24:32 +13:00
7eb8634ad7 Fix typo in sort-by error message (#2841) 2021-01-01 18:34:50 -06:00
452d8c06e9 Improve some errors, streamline internal error handling (#2839)
* Improve some errors, streamline internal error handling

* Fix lints
2021-01-02 08:52:19 +13:00
48f535f02e Display aliases and custom commands in which; fix #2810 (#2834)
* Display aliases and custom commands in which; Fix #2810

Example output of nu after the commit is applied:

```shell
/home/leo/repos/nushell(feature/which_inspect_alias)> def docker-ps [] { docker ps --format '{{json .}}' | from json -o }
/home/leo/repos/nushell(feature/which_inspect_alias)> which docker-ps
───┬───────────┬────────────────────────┬─────────
 # │    arg    │          path          │ builtin
───┼───────────┼────────────────────────┼─────────
 0 │ docker-ps │ nushell custom command │ No
───┴───────────┴────────────────────────┴─────────
/home/leo/repos/nushell(feature/which_inspect_alias)> alias d = gid pd
/home/leo/repos/nushell(feature/which_inspect_alias)> which d
───┬─────┬───────────────┬─────────
 # │ arg │     path      │ builtin
───┼─────┼───────────────┼─────────
 0 │ d   │ nushell alias │ No
───┴─────┴───────────────┴─────────
```

* Update documentation
2021-01-02 06:40:44 +13:00
43c10b0625 Properly handle commands defined inside of other commands (#2837)
* Fix function inner scopes

* tweak error
2021-01-01 19:23:54 +13:00
328b09fe04 Properly error when 'source' argument can't be found (#2836) 2021-01-01 17:33:38 +13:00
15d49e4096 Rust 1.49 Clippy Fixes (#2835) 2021-01-01 15:13:59 +13:00
3ef53fe2cd move create_default_context out of cli.rs and into its own mod (#2833) 2021-01-01 15:12:16 +13:00
7d8e759e98 Nucli refactor script mod (#2831)
* move process_script and run_script_standalone out of cli.rs

* cargo fmt

* code cleanup imports

* unused imports issue in cli.rs
2020-12-31 12:38:31 +13:00
69b3be61a4 Simplify run_block slightly (#2830)
* Simplify run_block slightly

* Add early return on C-c
2020-12-31 12:37:07 +13:00
79476a5cb2 Replace clipboard with arboard (#2832) 2020-12-31 06:16:02 +13:00
f449baf8de Change ls to output path (#2829)
* make name a path vs string

* add support for comparing path to string
2020-12-28 14:52:28 -06:00
5ff4bcfb7a Nucli refactor crate stream (#2828)
* nu-stream is building on its own, now clean up Cargo.toml

* replace the stream crate in nu-cli

* cc

* since we moved stream out of the nu-cli crate and into its own crate we need to remove pub(crate) and just make it pub

* clean up the prelude and hand merge everything together

* clean up Cargo.tom

* cargo fmt along with Cargo.lock
2020-12-28 18:34:27 +13:00
98537ce8b7 remove code not used. Fix use shadow-rs build warning (#2827)
* update to shadow-rs 0.4. use easy

* update shadow-rs to 0.5

* fix version not used

* update

* update Cargo.lock

* update Cargo.lock

* fix wasm build error when use dependence git2
fix error link:https://dev.azure.com/nushell/nushell/_build/results?buildId=4858&view=logs&j=1a745d4c-b027-5f34-06d8-d6f256bfe9f9&t=a0a335cb-fa1f-5bbf-be01-1a90d6899e54

* remove code not used; fix warning by RUSTFLAGS="-D warnings" build error

* upgrade shadow-rs 0.5.2
2020-12-28 08:00:14 +13:00
d2a00a2daa update to shadow-rs 0.5. make use easy (#2793)
* update to shadow-rs 0.4. use easy

* update shadow-rs to 0.5

* fix version not used

* update

* update Cargo.lock

* update Cargo.lock

* fix wasm build error when use dependence git2
fix error link:https://dev.azure.com/nushell/nushell/_build/results?buildId=4858&view=logs&j=1a745d4c-b027-5f34-06d8-d6f256bfe9f9&t=a0a335cb-fa1f-5bbf-be01-1a90d6899e54
2020-12-24 05:56:05 +13:00
f22938fc4a Add support for custom subcommands (#2814)
* Add support for custom subcommands

* clippy
2020-12-23 20:43:56 +13:00
1e67ae8e94 Fix broken links in the README (#2813) 2020-12-22 17:35:06 +13:00
c012d648fb Add experimental support for flags in custom commands (#2808)
* Add experimental support for flags in custom commands

* clippy
2020-12-21 20:36:59 +13:00
67acaae53c Rename cond math (#2807)
* Simplifies 'if' to work on the available scope rather than a stream

* Rename initializer/math for better readability

* Fix description

* fmt
2020-12-21 17:32:06 +13:00
e3da546e23 Simplifies 'if' to work on the available scope rather than a stream (#2805) 2020-12-21 16:02:39 +13:00
e5b136f70d Add script sourcing (#2803)
* Add script sourcing

* clippy
2020-12-19 20:47:34 +13:00
058ef69da3 Add set-env for setting environment variables (#2802) 2020-12-19 19:25:03 +13:00
2a483531a4 Bug report uses version command (#2797) 2020-12-19 18:25:32 +13:00
05202671db Improve errors on success (#2801) 2020-12-19 18:24:56 +13:00
8509873043 Parse mid-line comments (#2800) 2020-12-19 11:23:02 +13:00
57a2d695e2 Removing the defs inside of blocks for now (#2798) 2020-12-19 07:53:00 +13:00
0b5ab1ef22 Don't print a nothing value (#2796) 2020-12-19 05:48:22 +13:00
2eac79569c highlight trailing spaces in tables in darkgray (#2794)
* highlight trailing spaces in tables in darkgray

* added leading spaces highlighting

* added config point to change the color

* Trigger Build
2020-12-18 07:47:05 -06:00
ac578b8491 Multiline scripts part 2 (#2795)
* Begin allowing comments and multiline scripts.

* clippy

* Finish moving to groups. Test pass

* Keep going

* WIP

* WIP

* BROKEN WIP

* WIP

* WIP

* Fix more tests

* WIP: alias starts working

* Broken WIP

* Broken WIP

* Variables begin to work

* captures start working

* A little better but needs fixed scope

* Shorthand env setting

* Update main merge

* Broken WIP

* WIP

* custom command parsing

* Custom commands start working

* Fix coloring and parsing of block

* Almost there

* Add some tests

* Add more param types

* Bump version

* Fix benchmark

* Fix stuff
2020-12-18 20:53:49 +13:00
5183fd25bb Bump version (#2792) 2020-12-16 09:13:18 +13:00
10f5a8ef78 Update uom and heim dependencies (#2767)
v0.29.0 and earlier versions of `uom` fail to compile on nightly because
of now-ambiguous trait bounds. The issue was corrected in v0.30.0 of
`uom`. `uom` and `heim` dependencies have been updated to the
latest version to include this fix and allow nushell to compile on
nightly.

Co-authored-by: Boutin, Michael <mjboutin@ecolab.com>
2020-12-15 13:27:21 -06:00
a30837298d Bump version (#2791) 2020-12-16 06:30:50 +13:00
f377a3a7b4 Added math abs command. (#2789) 2020-12-16 05:37:12 +13:00
83c874666a Date utility commands (#2780)
* updated & added date related commands based on the new design

* added proper error handling when date format string is invalid

* fixed format issue

* fixed an issue caused due to the change in primitive Date type

* added `date list-timezone` command to list all supported time zones and updated `date to-timezone` accordingly
2020-12-12 12:18:03 -06:00
e000ed47cd Fix Gitpod dev setup by forcing a dev image rebuild (#2783) 2020-12-09 06:44:23 +13:00
af2f064f42 Add random chars cmd (#2782) 2020-12-09 06:43:46 +13:00
9c7b25134b Parsing: Explain parsing errors and show sample lines. (#2774)
This makes the errors slightly better. It took me a while to realize I was missing the `--raw` flag.

```
open "data.csv" | from csv --separator ';'
```

    error: Could not parse as CSV split by ',' (Line 1: expected 1 fields, found 14)
      ┌─ shell:1:1
      │
    1 │ open "data.csv" | from csv --separator ';'
      │ ^^^^ ------------------------------------------------- value originates from here
      │ │
      │ input cannot be parsed as CSV split by ','. Sample input:
    Name;Data
    Ugly;row
    AnotherUgly;row

I think this still needs some refinement. Maybe we don't want to show
the separator all the time, omitting the defaults or the separator
on other formats.
2020-12-07 07:19:04 +13:00
2d15df9e6c Revert "Bump Rustyline to 7.0.0 (#2776)" (#2778)
This reverts commit e73278990c.
2020-12-05 17:12:42 +13:00
d2ab287756 Tell Nu to look for hash's rest columns paths first. (#2777) 2020-12-04 13:49:58 -05:00
e73278990c Bump Rustyline to 7.0.0 (#2776)
* Bump Rustyline to 7.0.0

* Append history instead of always save

* Add associated type to Hinter

* Convert to using Rustyline KeyEvent

* Use AcceptOrInsertLine as struct

* Cargo fmt

* Make convert_keyevent pub

* Better naming for RL conversion
2020-12-05 06:29:40 +13:00
12bc92df35 Make run_block public (#2772) 2020-12-02 23:00:30 +13:00
f19a801022 enhanced version command with more info (#2773) 2020-12-01 13:57:49 -06:00
b193303aa3 Add hash command with base64 subcommand (#2769)
* WIP try testing hash command

Ensure test worked

fmt

WIP get it working for other types of base64

Use optional named arg

WIP

* rebased and refactored a little with encoding and decoding

Fix some typos

Add some more charactersets

refactor several args into the encoding config struct and fix character_set arg. It needs to match the field

Add main hash command so it can be found via help

Added tests for running the whole pipeline

* add test case to cover invalid character sets

* clippy and fmt
2020-12-01 06:47:35 +13:00
562 changed files with 13899 additions and 10895 deletions

View File

@ -23,8 +23,25 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Configuration (please complete the following information):**
- OS (e.g. Windows):
- Nu version (you can use the `version` command to find out):
- Optional features (if any):
Add any other context about the problem here.
Run `version | pivot` and paste the output to show OS, features, etc.
```
> version | pivot
╭───┬────────────────────┬───────────────────────────────────────────────────────────────────────╮
│ # │ Column0 │ Column1 │
├───┼────────────────────┼───────────────────────────────────────────────────────────────────────┤
│ 0 │ version │ 0.24.1 │
│ 1 │ build_os │ macos-x86_64 │
│ 2 │ rust_version │ rustc 1.48.0 │
│ 3 │ cargo_version │ cargo 1.48.0 │
│ 4 │ pkg_version │ 0.24.1 │
│ 5 │ build_time │ 2020-12-18 09:54:09 │
│ 6 │ build_rust_channel │ release │
│ 7 │ features │ ctrlc, default, directories, dirs, git, ichwh, ptree, rich-benchmark, │
│ │ │ rustyline, term, uuid, which, zip │
╰───┴────────────────────┴───────────────────────────────────────────────────────────────────────╯
```
**Add any other context about the problem here.**

6
.gitpod.Dockerfile vendored
View File

@ -1,5 +1,9 @@
FROM gitpod/workspace-full
# Gitpod will not rebuild Nushell's dev image unless *some* change is made to this Dockerfile.
# To force a rebuild, simply increase this counter:
ENV TRIGGER_REBUILD 1
USER gitpod
RUN sudo apt-get update && \
@ -11,4 +15,4 @@ RUN sudo apt-get update && \
rust-lldb \
&& sudo rm -rf /var/lib/apt/lists/*
ENV RUST_LLDB=/usr/bin/lldb-8
ENV RUST_LLDB=/usr/bin/lldb-11

View File

@ -4,7 +4,7 @@ tasks:
- name: Clippy
init: cargo clippy --all --features=stable -- -D clippy::result_unwrap_used -D clippy::option_unwrap_used
- name: Testing
init: cargo test --all --features=stable,test-bins
init: cargo test --all --features=stable
- name: Build
init: cargo build --features=stable
- name: Nu

2328
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@ license = "MIT"
name = "nu"
readme = "README.md"
repository = "https://github.com/nushell/nushell"
version = "0.23.0"
version = "0.26.0"
[workspace]
members = ["crates/*/"]
@ -18,65 +18,64 @@ members = ["crates/*/"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nu-cli = {version = "0.23.0", path = "./crates/nu-cli"}
nu-data = {version = "0.23.0", path = "./crates/nu-data"}
nu-errors = {version = "0.23.0", path = "./crates/nu-errors"}
nu-parser = {version = "0.23.0", path = "./crates/nu-parser"}
nu-plugin = {version = "0.23.0", path = "./crates/nu-plugin"}
nu-protocol = {version = "0.23.0", path = "./crates/nu-protocol"}
nu-source = {version = "0.23.0", path = "./crates/nu-source"}
nu-value-ext = {version = "0.23.0", path = "./crates/nu-value-ext"}
nu-cli = {version = "0.26.0", path = "./crates/nu-cli"}
nu-command = {version = "0.26.0", path = "./crates/nu-command"}
nu-data = {version = "0.26.0", path = "./crates/nu-data"}
nu-engine = {version = "0.26.0", path = "./crates/nu-engine"}
nu-errors = {version = "0.26.0", path = "./crates/nu-errors"}
nu-parser = {version = "0.26.0", path = "./crates/nu-parser"}
nu-plugin = {version = "0.26.0", path = "./crates/nu-plugin"}
nu-protocol = {version = "0.26.0", path = "./crates/nu-protocol"}
nu-source = {version = "0.26.0", path = "./crates/nu-source"}
nu-value-ext = {version = "0.26.0", path = "./crates/nu-value-ext"}
nu_plugin_binaryview = {version = "0.23.0", path = "./crates/nu_plugin_binaryview", optional = true}
nu_plugin_chart = {version = "0.23.0", path = "./crates/nu_plugin_chart", optional = true}
nu_plugin_fetch = {version = "0.23.0", path = "./crates/nu_plugin_fetch", optional = true}
nu_plugin_from_bson = {version = "0.23.0", path = "./crates/nu_plugin_from_bson", optional = true}
nu_plugin_from_sqlite = {version = "0.23.0", path = "./crates/nu_plugin_from_sqlite", optional = true}
nu_plugin_inc = {version = "0.23.0", path = "./crates/nu_plugin_inc", optional = true}
nu_plugin_match = {version = "0.23.0", path = "./crates/nu_plugin_match", optional = true}
nu_plugin_post = {version = "0.23.0", path = "./crates/nu_plugin_post", optional = true}
nu_plugin_ps = {version = "0.23.0", path = "./crates/nu_plugin_ps", optional = true}
nu_plugin_s3 = {version = "0.23.0", path = "./crates/nu_plugin_s3", optional = true}
nu_plugin_start = {version = "0.23.0", path = "./crates/nu_plugin_start", optional = true}
nu_plugin_sys = {version = "0.23.0", path = "./crates/nu_plugin_sys", optional = true}
nu_plugin_textview = {version = "0.23.0", path = "./crates/nu_plugin_textview", optional = true}
nu_plugin_to_bson = {version = "0.23.0", path = "./crates/nu_plugin_to_bson", optional = true}
nu_plugin_to_sqlite = {version = "0.23.0", path = "./crates/nu_plugin_to_sqlite", optional = true}
nu_plugin_tree = {version = "0.23.0", path = "./crates/nu_plugin_tree", optional = true}
nu_plugin_xpath = {version = "0.23.0", path = "./crates/nu_plugin_xpath", optional = true}
nu_plugin_selector = {version = "0.23.0", path = "./crates/nu_plugin_selector", optional = true}
nu_plugin_binaryview = {version = "0.26.0", path = "./crates/nu_plugin_binaryview", optional = true}
nu_plugin_chart = {version = "0.26.0", path = "./crates/nu_plugin_chart", optional = true}
nu_plugin_fetch = {version = "0.26.0", path = "./crates/nu_plugin_fetch", optional = true}
nu_plugin_from_bson = {version = "0.26.0", path = "./crates/nu_plugin_from_bson", optional = true}
nu_plugin_from_sqlite = {version = "0.26.0", path = "./crates/nu_plugin_from_sqlite", optional = true}
nu_plugin_inc = {version = "0.26.0", path = "./crates/nu_plugin_inc", optional = true}
nu_plugin_match = {version = "0.26.0", path = "./crates/nu_plugin_match", optional = true}
nu_plugin_post = {version = "0.26.0", path = "./crates/nu_plugin_post", optional = true}
nu_plugin_ps = {version = "0.26.0", path = "./crates/nu_plugin_ps", optional = true}
nu_plugin_s3 = {version = "0.26.0", path = "./crates/nu_plugin_s3", optional = true}
nu_plugin_selector = {version = "0.26.0", path = "./crates/nu_plugin_selector", optional = true}
nu_plugin_start = {version = "0.26.0", path = "./crates/nu_plugin_start", optional = true}
nu_plugin_sys = {version = "0.26.0", path = "./crates/nu_plugin_sys", optional = true}
nu_plugin_textview = {version = "0.26.0", path = "./crates/nu_plugin_textview", optional = true}
nu_plugin_to_bson = {version = "0.26.0", path = "./crates/nu_plugin_to_bson", optional = true}
nu_plugin_to_sqlite = {version = "0.26.0", path = "./crates/nu_plugin_to_sqlite", optional = true}
nu_plugin_tree = {version = "0.26.0", path = "./crates/nu_plugin_tree", optional = true}
nu_plugin_xpath = {version = "0.26.0", path = "./crates/nu_plugin_xpath", optional = true}
# Required to bootstrap the main binary
clap = "2.33.3"
ctrlc = {version = "3.1.6", optional = true}
futures = {version = "0.3.5", features = ["compat", "io-compat"]}
itertools = "0.10.0"
log = "0.4.11"
pretty_env_logger = "0.4.0"
itertools = "0.9.0"
[dev-dependencies]
dunce = "1.0.1"
nu-test-support = {version = "0.23.0", path = "./crates/nu-test-support"}
nu-test-support = {version = "0.26.0", path = "./crates/nu-test-support"}
[build-dependencies]
[features]
ctrlc-support = ["nu-cli/ctrlc"]
directories-support = ["nu-cli/directories", "nu-cli/dirs", "nu-data/directories", "nu-data/dirs"]
git-support = ["nu-cli/git2"]
ptree-support = ["nu-cli/ptree"]
rich-benchmark = ["nu-cli/rich-benchmark"]
rustyline-support = ["nu-cli/rustyline-support"]
term-support = ["nu-cli/term"]
uuid-support = ["nu-cli/uuid_crate"]
which-support = ["nu-cli/ichwh", "nu-cli/which"]
ctrlc-support = ["nu-cli/ctrlc", "nu-command/ctrlc"]
directories-support = ["nu-cli/directories", "nu-cli/dirs", "nu-command/directories", "nu-command/dirs", "nu-data/directories", "nu-data/dirs", "nu-engine/dirs"]
ptree-support = ["nu-cli/ptree", "nu-command/ptree"]
rustyline-support = ["nu-cli/rustyline-support", "nu-command/rustyline-support"]
term-support = ["nu-cli/term", "nu-command/term"]
uuid-support = ["nu-cli/uuid_crate", "nu-command/uuid_crate"]
which-support = ["nu-cli/ichwh", "nu-cli/which", "nu-command/ichwh", "nu-command/which"]
default = [
"sys",
"ps",
"textview",
"inc",
"git-support",
"directories-support",
"ctrlc-support",
"which-support",
@ -87,8 +86,7 @@ default = [
"match",
"post",
"fetch",
"rich-benchmark",
"zip-support"
"zip-support",
]
extra = ["default", "binaryview", "tree", "clipboard-cli", "trash-support", "start", "bson", "sqlite", "s3", "chart", "xpath", "selector"]
stable = ["default"]
@ -105,26 +103,26 @@ post = ["nu_plugin_post"]
ps = ["nu_plugin_ps"]
sys = ["nu_plugin_sys"]
textview = ["nu_plugin_textview"]
zip-support = ["nu-cli/zip"]
zip-support = ["nu-cli/zip", "nu-command/zip"]
# Extra
binaryview = ["nu_plugin_binaryview"]
bson = ["nu_plugin_from_bson", "nu_plugin_to_bson"]
chart = ["nu_plugin_chart"]
clipboard-cli = ["nu-cli/clipboard-cli"]
clipboard-cli = ["nu-cli/clipboard-cli", "nu-command/clipboard-cli"]
s3 = ["nu_plugin_s3"]
selector = ["nu_plugin_selector"]
sqlite = ["nu_plugin_from_sqlite", "nu_plugin_to_sqlite"]
start = ["nu_plugin_start"]
trash-support = ["nu-cli/trash-support"]
trash-support = ["nu-cli/trash-support", "nu-command/trash-support"]
tree = ["nu_plugin_tree"]
xpath = ["nu_plugin_xpath"]
selector = ["nu_plugin_selector"]
[profile.release]
#strip = "symbols" #Couldn't get working +nightly
opt-level = 'z' #Optimize for size
lto = true #Link Time Optimization
codegen-units = 1 #Reduce parallel codegen units
lto = true #Link Time Optimization
opt-level = 'z' #Optimize for size
# Core plugins that ship with `cargo install nu` by default
# Currently, Cargo limits us to installing only one binary

View File

@ -11,7 +11,7 @@
A new type of shell.
![Example of nushell](images/nushell-autocomplete.gif "Example of nushell")
![Example of nushell](images/nushell-autocomplete5.gif "Example of nushell")
## Status
@ -64,7 +64,7 @@ To install Nu via cargo (make sure you have installed [rustup](https://rustup.rs
cargo install nu
```
You can also build Nu yourself with all the bells and whistles (be sure to have installed the [dependencies](https://www.nushell.sh/book/en/installation.html#dependencies) for your platform), once you have checked out this repo with git:
You can also build Nu yourself with all the bells and whistles (be sure to have installed the [dependencies](https://www.nushell.sh/book/installation.html#dependencies) for your platform), once you have checked out this repo with git:
```bash
cargo build --workspace --features=extra
@ -234,7 +234,7 @@ Here we use the variable `$it` to refer to the value being piped to the external
### Configuration
Nu has early support for configuring the shell. You can refer to the book for a list of [all supported variables](https://www.nushell.sh/book/en/configuration.html).
Nu has early support for configuring the shell. You can refer to the book for a list of [all supported variables](https://www.nushell.sh/book/configuration.html).
To set one of these variables, you can use `config set`. For example:
@ -300,8 +300,8 @@ Nu is in heavy development, and will naturally change as it matures and people u
| Errors | | | X | | | Error reporting works, but could use usability polish
| Documentation | | X | | | | Book and related are barebones and lack task-based lessons
| Paging | | X | | | | Textview has paging, but we'd like paging for tables
| Functions| X | | | | | No functions, yet, only aliases
| Variables| X | | | | | Nu doesn't yet support variables
| Functions | | X | | | | No functions, yet, only aliases
| Variables| | X | | | | Nu doesn't yet support variables
| Completions | | X | | | | Completions are currently barebones, at best
| Type-checking | | X | | | | Commands check basic types, but input/output isn't checked

View File

@ -1,59 +1,66 @@
[package]
authors = ["The Nu Project Contributors"]
build = "build.rs"
description = "CLI for nushell"
edition = "2018"
license = "MIT"
name = "nu-cli"
version = "0.23.0"
version = "0.26.0"
[lib]
doctest = false
[dependencies]
nu-data = {version = "0.23.0", path = "../nu-data"}
nu-errors = {version = "0.23.0", path = "../nu-errors"}
nu-json = {version = "0.23.0", path = "../nu-json"}
nu-parser = {version = "0.23.0", path = "../nu-parser"}
nu-plugin = {version = "0.23.0", path = "../nu-plugin"}
nu-protocol = {version = "0.23.0", path = "../nu-protocol"}
nu-source = {version = "0.23.0", path = "../nu-source"}
nu-table = {version = "0.23.0", path = "../nu-table"}
nu-test-support = {version = "0.23.0", path = "../nu-test-support"}
nu-value-ext = {version = "0.23.0", path = "../nu-value-ext"}
nu-command = { version = "0.26.0", path = "../nu-command" }
nu-data = { version = "0.26.0", path = "../nu-data" }
nu-engine = { version = "0.26.0", path = "../nu-engine" }
nu-errors = { version = "0.26.0", path = "../nu-errors" }
nu-json = { version = "0.26.0", path = "../nu-json" }
nu-parser = { version = "0.26.0", path = "../nu-parser" }
nu-plugin = { version = "0.26.0", path = "../nu-plugin" }
nu-protocol = { version = "0.26.0", path = "../nu-protocol" }
nu-source = { version = "0.26.0", path = "../nu-source" }
nu-stream = { version = "0.26.0", path = "../nu-stream" }
nu-table = { version = "0.26.0", path = "../nu-table" }
nu-test-support = { version = "0.26.0", path = "../nu-test-support" }
nu-value-ext = { version = "0.26.0", path = "../nu-value-ext" }
Inflector = "0.11"
ansi_term = "0.12.1"
arboard = { version = "1.1.0", optional = true }
async-recursion = "0.3.1"
async-trait = "0.1.40"
base64 = "0.12.3"
base64 = "0.13.0"
bigdecimal = { version = "0.2.0", features = ["serde"] }
byte-unit = "4.0.9"
bytes = "0.5.6"
calamine = "0.16.1"
chrono = { version = "0.4.15", features = ["serde"] }
chrono-tz = "0.5.3"
clap = "2.33.3"
codespan-reporting = "0.9.5"
codespan-reporting = "0.11.0"
csv = "1.1.3"
ctrlc = { version = "3.1.6", optional = true }
derive-new = "0.5.8"
directories = {version = "3.0.1", optional = true}
dirs = {version = "3.0.1", optional = true}
directories-next = { version = "2.0.0", optional = true }
dirs-next = { version = "2.0.0", optional = true }
dtparse = "1.2.0"
dunce = "1.0.1"
eml-parser = "0.1.0"
encoding_rs = "0.8.24"
filesize = "0.2.0"
fs_extra = "1.2.0"
futures = { version = "0.3.5", features = ["compat", "io-compat"] }
futures-util = "0.3.5"
futures-util = "0.3.8"
futures_codec = "0.4.1"
getset = "0.1.1"
git2 = {version = "0.13.11", default_features = false, optional = true}
glob = "0.3.0"
heim = {version = "0.1.0-beta.3", optional = true}
htmlescape = "0.3.1"
ical = "0.6.0"
ical = "0.7.0"
ichwh = { version = "0.3.4", optional = true }
indexmap = { version = "1.6.0", features = ["serde-1"] }
itertools = "0.9.0"
itertools = "0.10.0"
lazy_static = "1.*"
log = "0.4.11"
meval = "0.2.0"
num-bigint = { version = "0.3.0", features = ["serde"] }
@ -64,11 +71,12 @@ pin-utils = "0.1.0"
pretty-hex = "0.2.0"
ptree = { version = "0.3.0", optional = true }
query_interface = "0.3.5"
quick-xml = "0.18.1"
quick-xml = "0.20.0"
rand = "0.7.3"
rayon = "1.4.0"
regex = "1.3.9"
roxmltree = "0.13.0"
rust-embed = "5.6.0"
roxmltree = "0.14.0"
rust-embed = "5.8.0"
rustyline = { version = "6.3.0", optional = true }
serde = { version = "1.0.115", features = ["derive"] }
serde_bytes = "0.11.5"
@ -85,20 +93,15 @@ tempfile = "3.1.0"
term = { version = "0.6.1", optional = true }
term_size = "0.3.2"
termcolor = "1.1.0"
titlecase = "1.0"
toml = "0.5.6"
trash = { version = "1.2.0", optional = true }
unicode-segmentation = "1.6.0"
uom = {version = "0.28.0", features = ["f64", "try-from"]}
url = "2.1.1"
uuid_crate = { package = "uuid", version = "0.8.1", features = ["v4"], optional = true }
which = { version = "4.0.2", optional = true }
zip = { version = "0.5.7", optional = true }
lazy_static = "1.*"
Inflector = "0.11"
clipboard = {version = "0.5.0", optional = true}
encoding_rs = "0.8.24"
rayon = "1.4.0"
trash = {version = "1.2.0", optional = true}
url = "2.1.1"
shadow-rs = { version = "0.5", default-features = false, optional = true }
[target.'cfg(unix)'.dependencies]
umask = "1.0.0"
@ -113,18 +116,20 @@ users = "0.10.0"
[dependencies.rusqlite]
features = ["bundled", "blob"]
optional = true
version = "0.24.0"
version = "0.24.2"
[build-dependencies]
git2 = {version = "0.13.11", optional = true}
shadow-rs = "0.5"
[dev-dependencies]
quickcheck = "0.9.2"
quickcheck_macros = "0.9.1"
[features]
clipboard-cli = ["clipboard"]
rich-benchmark = ["heim"]
rustyline-support = ["rustyline"]
default = ["shadow-rs"]
clipboard-cli = ["arboard"]
rustyline-support = ["rustyline", "nu-engine/rustyline-support"]
stable = []
trash-support = ["trash"]
dirs = ["dirs-next"]
directories = ["directories-next"]

View File

@ -1,36 +1,3 @@
use std::path::Path;
use std::{env, fs, io};
fn main() -> Result<(), io::Error> {
let out_dir = env::var_os("OUT_DIR").expect(
"\
OUT_DIR environment variable not found. \
OUT_DIR is guaranteed to exist in a build script by cargo - see \
https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts\
");
let latest_commit_hash = latest_commit_hash(env::current_dir()?).unwrap_or_default();
let commit_hash_path = Path::new(&out_dir).join("git_commit_hash");
fs::write(commit_hash_path, latest_commit_hash)?;
Ok(())
}
#[allow(unused_variables)]
fn latest_commit_hash<P: AsRef<Path>>(dir: P) -> Result<String, Box<dyn std::error::Error>> {
#[cfg(feature = "git2")]
{
use git2::Repository;
let dir = dir.as_ref();
Ok(Repository::discover(dir)?
.head()?
.peel_to_commit()?
.id()
.to_string())
}
#[cfg(not(feature = "git2"))]
{
Ok(String::new())
}
fn main() -> shadow_rs::SdResult<()> {
shadow_rs::new()
}

File diff suppressed because it is too large Load Diff

View File

@ -1,64 +0,0 @@
use crate::commands::Command;
use indexmap::IndexMap;
use nu_errors::ShellError;
use nu_parser::SignatureRegistry;
use nu_protocol::Signature;
use parking_lot::Mutex;
use std::sync::Arc;
#[derive(Debug, Clone, Default)]
pub struct CommandRegistry {
registry: Arc<Mutex<IndexMap<String, Command>>>,
}
impl SignatureRegistry for CommandRegistry {
fn has(&self, name: &str) -> bool {
let registry = self.registry.lock();
registry.contains_key(name)
}
fn get(&self, name: &str) -> Option<Signature> {
let registry = self.registry.lock();
registry.get(name).map(|command| command.signature())
}
fn clone_box(&self) -> Box<dyn SignatureRegistry> {
Box::new(self.clone())
}
}
impl CommandRegistry {
pub fn new() -> CommandRegistry {
CommandRegistry {
registry: Arc::new(Mutex::new(IndexMap::default())),
}
}
}
impl CommandRegistry {
pub fn get_command(&self, name: &str) -> Option<Command> {
let registry = self.registry.lock();
registry.get(name).cloned()
}
pub fn expect_command(&self, name: &str) -> Result<Command, ShellError> {
self.get_command(name).ok_or_else(|| {
ShellError::untagged_runtime_error(format!("Could not load command: {}", name))
})
}
pub fn has(&self, name: &str) -> bool {
let registry = self.registry.lock();
registry.contains_key(name)
}
pub fn insert(&mut self, name: impl Into<String>, command: Command) {
let mut registry = self.registry.lock();
registry.insert(name.into(), command);
}
pub fn names(&self) -> Vec<String> {
let registry = self.registry.lock();
registry.keys().cloned().collect()
}
}

View File

@ -1,221 +0,0 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use crate::types::deduction::{VarDeclaration, VarSyntaxShapeDeductor};
use deduction_to_signature::DeductionToSignature;
use log::trace;
use nu_data::config;
use nu_errors::ShellError;
use nu_protocol::{
hir::Block, CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
};
use nu_source::Tagged;
pub struct Alias;
#[derive(Deserialize)]
pub struct AliasArgs {
pub name: Tagged<String>,
pub args: Vec<Value>,
pub block: Block,
pub infer: Option<bool>,
pub save: Option<bool>,
}
#[async_trait]
impl WholeStreamCommand for Alias {
fn name(&self) -> &str {
"alias"
}
fn signature(&self) -> Signature {
Signature::build("alias")
.required("name", SyntaxShape::String, "the name of the alias")
.required("args", SyntaxShape::Table, "the arguments to the alias")
.required(
"block",
SyntaxShape::Block,
"the block to run as the body of the alias",
)
.switch("infer", "infer argument types (experimental)", Some('i'))
.switch("save", "save the alias to your config", Some('s'))
}
fn usage(&self) -> &str {
"Define a shortcut for another command."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
alias(args, registry).await
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "An alias without parameters",
example: "alias say-hi [] { echo 'Hello!' }",
result: None,
},
Example {
description: "An alias with a single parameter",
example: "alias l [x] { ls $x }",
result: None,
},
]
}
}
pub async fn alias(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let mut raw_input = args.raw_input.clone();
let (
AliasArgs {
name,
args: list,
block,
infer,
save,
},
_ctx,
) = args.process(&registry).await?;
if let Some(true) = save {
let mut result = nu_data::config::read(name.clone().tag, &None)?;
// process the alias to remove the --save flag
let left_brace = raw_input.find('{').unwrap_or(0);
let right_brace = raw_input.rfind('}').unwrap_or_else(|| raw_input.len());
let left = raw_input[..left_brace]
.replace("--save", "") // TODO using regex (or reconstruct string from AST?)
.replace("-si", "-i")
.replace("-s ", "")
.replace("-is", "-i");
let right = raw_input[right_brace..]
.replace("--save", "")
.replace("-si", "-i")
.replace("-s ", "")
.replace("-is", "-i");
raw_input = format!("{}{}{}", left, &raw_input[left_brace..right_brace], right);
// create a value from raw_input alias
let alias: Value = raw_input.trim().to_string().into();
let alias_start = raw_input.find('[').unwrap_or(0); // used to check if the same alias already exists
// add to startup if alias doesn't exist and replace if it does
match result.get_mut("startup") {
Some(startup) => {
if let UntaggedValue::Table(ref mut commands) = startup.value {
if let Some(command) = commands.iter_mut().find(|command| {
let cmd_str = command.as_string().unwrap_or_default();
cmd_str.starts_with(&raw_input[..alias_start])
}) {
*command = alias;
} else {
commands.push(alias);
}
}
}
None => {
let table = UntaggedValue::table(&[alias]);
result.insert("startup".to_string(), table.into_value(Tag::default()));
}
}
config::write(&result, &None)?;
}
let mut processed_args: Vec<VarDeclaration> = vec![];
for (_, item) in list.iter().enumerate() {
match item.as_string() {
Ok(var_name) => {
let dollar_var_name = format!("${}", var_name);
processed_args.push(VarDeclaration {
name: dollar_var_name,
// type_decl: None,
span: item.tag.span,
});
}
Err(_) => {
return Err(ShellError::labeled_error(
"Expected a string",
"expected a string",
item.tag(),
));
}
}
}
trace!("Found vars: {:?}", processed_args);
let inferred_shapes = {
if let Some(true) = infer {
VarSyntaxShapeDeductor::infer_vars(&processed_args, &block, &registry)?
} else {
processed_args.into_iter().map(|arg| (arg, None)).collect()
}
};
let signature = DeductionToSignature::get(&name.item, &inferred_shapes);
trace!("Inferred signature: {:?}", signature);
Ok(OutputStream::one(ReturnSuccess::action(
CommandAction::AddAlias(Box::new(signature), block),
)))
}
#[cfg(test)]
mod tests {
use super::Alias;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Alias {})?)
}
}
mod deduction_to_signature {
//For now this logic is relativly simple.
//For each var, one mandatory positional is added.
//As soon as more support for optional positional arguments is arrived,
//this logic might be a little bit more tricky.
use crate::types::deduction::{Deduction, VarDeclaration};
use nu_protocol::{PositionalType, Signature, SyntaxShape};
pub struct DeductionToSignature {}
impl DeductionToSignature {
pub fn get(
cmd_name: &str,
deductions: &[(VarDeclaration, Option<Deduction>)],
) -> Signature {
let mut signature = Signature::build(cmd_name);
for (decl, deduction) in deductions {
match deduction {
None => signature.positional.push((
PositionalType::optional(&decl.name, SyntaxShape::Any),
decl.name.clone(),
)),
Some(deduction) => match deduction {
Deduction::VarShapeDeduction(normal_var_deduction) => {
signature.positional.push((
PositionalType::optional(
&decl.name,
normal_var_deduction[0].deduction,
),
decl.name.clone(),
))
}
},
}
}
signature
}
}
}

View File

@ -1,88 +0,0 @@
use crate::commands::classified::expr::run_expression_block;
use crate::commands::classified::internal::run_internal_command;
use crate::evaluation_context::EvaluationContext;
use crate::prelude::*;
use crate::stream::InputStream;
use futures::stream::TryStreamExt;
use nu_errors::ShellError;
use nu_protocol::hir::{Block, ClassifiedCommand, Commands};
use nu_protocol::{ReturnSuccess, Scope, UntaggedValue, Value};
use std::sync::atomic::Ordering;
pub(crate) async fn run_block(
block: &Block,
ctx: &mut EvaluationContext,
mut input: InputStream,
scope: Arc<Scope>,
) -> Result<InputStream, ShellError> {
let mut output: Result<InputStream, ShellError> = Ok(InputStream::empty());
for pipeline in &block.block {
match output {
Ok(inp) if inp.is_empty() => {}
Ok(inp) => {
let mut output_stream = inp.to_output_stream();
loop {
match output_stream.try_next().await {
Ok(Some(ReturnSuccess::Value(Value {
value: UntaggedValue::Error(e),
..
}))) => return Err(e),
Ok(Some(_item)) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
return Err(err.clone());
}
if ctx.ctrl_c.load(Ordering::SeqCst) {
break;
}
}
Ok(None) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
return Err(err.clone());
}
break;
}
Err(e) => return Err(e),
}
}
}
Err(e) => {
return Err(e);
}
}
output = run_pipeline(pipeline, ctx, input, scope.clone()).await;
input = InputStream::empty();
}
output
}
async fn run_pipeline(
commands: &Commands,
ctx: &mut EvaluationContext,
mut input: InputStream,
scope: Arc<Scope>,
) -> Result<InputStream, ShellError> {
for item in commands.list.clone() {
input = match item {
ClassifiedCommand::Dynamic(_) => {
return Err(ShellError::unimplemented("Dynamic commands"))
}
ClassifiedCommand::Expr(expr) => {
run_expression_block(*expr, ctx, scope.clone()).await?
}
ClassifiedCommand::Error(err) => return Err(err.into()),
ClassifiedCommand::Internal(left) => {
run_internal_command(left, ctx, input, scope.clone()).await?
}
};
}
Ok(input)
}

View File

@ -1,10 +0,0 @@
pub(crate) mod block;
mod dynamic;
pub(crate) mod expr;
pub(crate) mod external;
pub(crate) mod internal;
pub(crate) mod maybe_text_codec;
pub(crate) mod plugin;
#[allow(unused_imports)]
pub(crate) use dynamic::Command as DynamicCommand;

View File

@ -1,340 +0,0 @@
use crate::command_registry::CommandRegistry;
use crate::commands::help::get_help;
use crate::deserializer::ConfigDeserializer;
use crate::evaluate::evaluate_args::evaluate_args;
use crate::prelude::*;
use derive_new::new;
use getset::Getters;
use nu_errors::ShellError;
use nu_protocol::hir;
use nu_protocol::{CallInfo, EvaluatedArgs, ReturnSuccess, Scope, Signature, UntaggedValue, Value};
use parking_lot::Mutex;
use serde::{Deserialize, Serialize};
use std::ops::Deref;
use std::sync::atomic::AtomicBool;
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct UnevaluatedCallInfo {
pub args: hir::Call,
pub name_tag: Tag,
pub scope: Arc<Scope>,
}
impl UnevaluatedCallInfo {
pub async fn evaluate(self, registry: &CommandRegistry) -> Result<CallInfo, ShellError> {
let args = evaluate_args(&self.args, registry, self.scope.clone()).await?;
Ok(CallInfo {
args,
name_tag: self.name_tag,
})
}
pub fn switch_present(&self, switch: &str) -> bool {
self.args.switch_preset(switch)
}
}
#[derive(Getters)]
#[get = "pub(crate)"]
pub struct CommandArgs {
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
pub ctrl_c: Arc<AtomicBool>,
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
pub shell_manager: ShellManager,
pub call_info: UnevaluatedCallInfo,
pub input: InputStream,
pub raw_input: String,
}
#[derive(Getters, Clone)]
#[get = "pub(crate)"]
pub struct RawCommandArgs {
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
pub ctrl_c: Arc<AtomicBool>,
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
pub shell_manager: ShellManager,
pub call_info: UnevaluatedCallInfo,
}
impl RawCommandArgs {
pub fn with_input(self, input: impl Into<InputStream>) -> CommandArgs {
CommandArgs {
host: self.host,
ctrl_c: self.ctrl_c,
current_errors: self.current_errors,
shell_manager: self.shell_manager,
call_info: self.call_info,
input: input.into(),
raw_input: String::default(),
}
}
}
impl std::fmt::Debug for CommandArgs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.call_info.fmt(f)
}
}
impl CommandArgs {
pub async fn evaluate_once(
self,
registry: &CommandRegistry,
) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
let host = self.host.clone();
let ctrl_c = self.ctrl_c.clone();
let shell_manager = self.shell_manager.clone();
let input = self.input;
let call_info = self.call_info.evaluate(registry).await?;
Ok(EvaluatedWholeStreamCommandArgs::new(
host,
ctrl_c,
shell_manager,
call_info,
input,
))
}
pub async fn evaluate_once_with_scope(
self,
registry: &CommandRegistry,
scope: Arc<Scope>,
) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
let host = self.host.clone();
let ctrl_c = self.ctrl_c.clone();
let shell_manager = self.shell_manager.clone();
let input = self.input;
let call_info = UnevaluatedCallInfo {
name_tag: self.call_info.name_tag,
args: self.call_info.args,
scope: scope.clone(),
};
let call_info = call_info.evaluate(registry).await?;
Ok(EvaluatedWholeStreamCommandArgs::new(
host,
ctrl_c,
shell_manager,
call_info,
input,
))
}
pub async fn process<'de, T: Deserialize<'de>>(
self,
registry: &CommandRegistry,
) -> Result<(T, InputStream), ShellError> {
let args = self.evaluate_once(registry).await?;
let call_info = args.call_info.clone();
let mut deserializer = ConfigDeserializer::from_call_info(call_info);
Ok((T::deserialize(&mut deserializer)?, args.input))
}
}
pub struct RunnableContext {
pub input: InputStream,
pub shell_manager: ShellManager,
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
pub ctrl_c: Arc<AtomicBool>,
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
pub registry: CommandRegistry,
pub name: Tag,
pub raw_input: String,
}
impl RunnableContext {
pub fn get_command(&self, name: &str) -> Option<Command> {
self.registry.get_command(name)
}
}
pub struct EvaluatedWholeStreamCommandArgs {
pub args: EvaluatedCommandArgs,
pub input: InputStream,
}
impl Deref for EvaluatedWholeStreamCommandArgs {
type Target = EvaluatedCommandArgs;
fn deref(&self) -> &Self::Target {
&self.args
}
}
impl EvaluatedWholeStreamCommandArgs {
pub fn new(
host: Arc<parking_lot::Mutex<dyn Host>>,
ctrl_c: Arc<AtomicBool>,
shell_manager: ShellManager,
call_info: CallInfo,
input: impl Into<InputStream>,
) -> EvaluatedWholeStreamCommandArgs {
EvaluatedWholeStreamCommandArgs {
args: EvaluatedCommandArgs {
host,
ctrl_c,
shell_manager,
call_info,
},
input: input.into(),
}
}
pub fn name_tag(&self) -> Tag {
self.args.call_info.name_tag.clone()
}
pub fn parts(self) -> (InputStream, EvaluatedArgs) {
let EvaluatedWholeStreamCommandArgs { args, input } = self;
(input, args.call_info.args)
}
pub fn split(self) -> (InputStream, EvaluatedCommandArgs) {
let EvaluatedWholeStreamCommandArgs { args, input } = self;
(input, args)
}
}
#[derive(Getters, new)]
#[get = "pub(crate)"]
pub struct EvaluatedCommandArgs {
pub host: Arc<parking_lot::Mutex<dyn Host>>,
pub ctrl_c: Arc<AtomicBool>,
pub shell_manager: ShellManager,
pub call_info: CallInfo,
}
impl EvaluatedCommandArgs {
pub fn nth(&self, pos: usize) -> Option<&Value> {
self.call_info.args.nth(pos)
}
/// Get the nth positional argument, error if not possible
pub fn expect_nth(&self, pos: usize) -> Result<&Value, ShellError> {
self.call_info
.args
.nth(pos)
.ok_or_else(|| ShellError::unimplemented("Better error: expect_nth"))
}
pub fn get(&self, name: &str) -> Option<&Value> {
self.call_info.args.get(name)
}
pub fn has(&self, name: &str) -> bool {
self.call_info.args.has(name)
}
}
pub struct Example {
pub example: &'static str,
pub description: &'static str,
pub result: Option<Vec<Value>>,
}
#[async_trait]
pub trait WholeStreamCommand: Send + Sync {
fn name(&self) -> &str;
fn signature(&self) -> Signature {
Signature::new(self.name()).desc(self.usage()).filter()
}
fn usage(&self) -> &str;
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError>;
fn is_binary(&self) -> bool {
false
}
// Commands that are not meant to be run by users
fn is_internal(&self) -> bool {
false
}
fn examples(&self) -> Vec<Example> {
Vec::new()
}
}
#[derive(Clone)]
pub struct Command(Arc<dyn WholeStreamCommand>);
impl PrettyDebugWithSource for Command {
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
b::typed(
"whole stream command",
b::description(self.name())
+ b::space()
+ b::equals()
+ b::space()
+ self.signature().pretty_debug(source),
)
}
}
impl std::fmt::Debug for Command {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Command({})", self.name())
}
}
impl Command {
pub fn name(&self) -> &str {
self.0.name()
}
pub fn signature(&self) -> Signature {
self.0.signature()
}
pub fn usage(&self) -> &str {
self.0.usage()
}
pub fn examples(&self) -> Vec<Example> {
self.0.examples()
}
pub async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
if args.call_info.switch_present("help") {
let cl = self.0.clone();
let registry = registry.clone();
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
UntaggedValue::string(get_help(&*cl, &registry)).into_value(Tag::unknown()),
))))
} else {
self.0.run(args, registry).await
}
}
pub fn is_binary(&self) -> bool {
self.0.is_binary()
}
pub fn is_internal(&self) -> bool {
self.0.is_internal()
}
pub fn stream_command(&self) -> &dyn WholeStreamCommand {
&*self.0
}
}
pub fn whole_stream_command(command: impl WholeStreamCommand + 'static) -> Command {
Command(Arc::new(command))
}

View File

@ -1,76 +0,0 @@
use crate::prelude::*;
use chrono::{DateTime, Local};
use nu_errors::ShellError;
use crate::commands::date::utils::{date_to_value, date_to_value_raw};
use crate::commands::WholeStreamCommand;
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged;
pub struct Date;
#[derive(Deserialize)]
pub struct FormatArgs {
format: Tagged<String>,
raw: Option<bool>,
}
#[async_trait]
impl WholeStreamCommand for Date {
fn name(&self) -> &str {
"date format"
}
fn signature(&self) -> Signature {
Signature::build("date format")
.required("format", SyntaxShape::String, "strftime format")
.switch("raw", "print date without tables", Some('r'))
}
fn usage(&self) -> &str {
"format the current date using the given format string."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
format(args, registry).await
}
}
pub async fn format(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let tag = args.call_info.name_tag.clone();
let (FormatArgs { format, raw }, _) = args.process(&registry).await?;
let dt_fmt = format.to_string();
let value = {
let local: DateTime<Local> = Local::now();
if let Some(true) = raw {
UntaggedValue::string(date_to_value_raw(local, dt_fmt)).into_untagged_value()
} else {
date_to_value(local, tag, dt_fmt)
}
};
Ok(OutputStream::one(value))
}
#[cfg(test)]
mod tests {
use super::Date;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Date {})?)
}
}

View File

@ -1,11 +0,0 @@
pub mod command;
pub mod format;
pub mod now;
pub mod utc;
mod utils;
pub use command::Command as Date;
pub use format::Date as DateFormat;
pub use now::Date as DateNow;
pub use utc::Date as DateUTC;

View File

@ -1,63 +0,0 @@
use crate::prelude::*;
use chrono::{DateTime, Local};
use nu_errors::ShellError;
use crate::commands::date::utils::date_to_value;
use crate::commands::WholeStreamCommand;
use nu_protocol::Signature;
pub struct Date;
#[async_trait]
impl WholeStreamCommand for Date {
fn name(&self) -> &str {
"date now"
}
fn signature(&self) -> Signature {
Signature::build("date now")
}
fn usage(&self) -> &str {
"return the current date."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
now(args, registry).await
}
}
pub async fn now(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let args = args.evaluate_once(&registry).await?;
let tag = args.call_info.name_tag.clone();
let no_fmt = "".to_string();
let value = {
let local: DateTime<Local> = Local::now();
date_to_value(local, tag, no_fmt)
};
Ok(OutputStream::one(value))
}
#[cfg(test)]
mod tests {
use super::Date;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Date {})?)
}
}

View File

@ -1,64 +0,0 @@
use crate::prelude::*;
use chrono::DateTime;
use nu_protocol::{Dictionary, Value};
use chrono::{Datelike, TimeZone, Timelike};
use core::fmt::Display;
use indexmap::IndexMap;
use nu_protocol::UntaggedValue;
pub fn date_to_value_raw<T: TimeZone>(dt: DateTime<T>, dt_format: String) -> String
where
T::Offset: Display,
{
let result = dt.format(&dt_format);
format!("{}", result)
}
pub fn date_to_value<T: TimeZone>(dt: DateTime<T>, tag: Tag, dt_format: String) -> Value
where
T::Offset: Display,
{
let mut indexmap = IndexMap::new();
if dt_format.is_empty() {
indexmap.insert(
"year".to_string(),
UntaggedValue::int(dt.year()).into_value(&tag),
);
indexmap.insert(
"month".to_string(),
UntaggedValue::int(dt.month()).into_value(&tag),
);
indexmap.insert(
"day".to_string(),
UntaggedValue::int(dt.day()).into_value(&tag),
);
indexmap.insert(
"hour".to_string(),
UntaggedValue::int(dt.hour()).into_value(&tag),
);
indexmap.insert(
"minute".to_string(),
UntaggedValue::int(dt.minute()).into_value(&tag),
);
indexmap.insert(
"second".to_string(),
UntaggedValue::int(dt.second()).into_value(&tag),
);
let tz = dt.offset();
indexmap.insert(
"timezone".to_string(),
UntaggedValue::string(format!("{}", tz)).into_value(&tag),
);
} else {
let result = dt.format(&dt_format);
indexmap.insert(
"formatted".to_string(),
UntaggedValue::string(format!("{}", result)).into_value(&tag),
);
}
UntaggedValue::Row(Dictionary::from(indexmap)).into_value(&tag)
}

View File

@ -1,185 +0,0 @@
use crate::command_registry::CommandRegistry;
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{
hir::Block, hir::ClassifiedCommand, Scope, Signature, SyntaxShape, UntaggedValue,
};
pub struct If;
#[derive(Deserialize)]
pub struct IfArgs {
condition: Block,
then_case: Block,
else_case: Block,
}
#[async_trait]
impl WholeStreamCommand for If {
fn name(&self) -> &str {
"if"
}
fn signature(&self) -> Signature {
Signature::build("if")
.required(
"condition",
SyntaxShape::Math,
"the condition that must match",
)
.required(
"then_case",
SyntaxShape::Block,
"block to run if condition is true",
)
.required(
"else_case",
SyntaxShape::Block,
"block to run if condition is false",
)
}
fn usage(&self) -> &str {
"Run blocks if a condition is true or false."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
if_command(args, registry).await
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Run a block if a condition is true",
example: "echo 10 | if $it > 5 { echo 'greater than 5' } { echo 'less than or equal to 5' }",
result: Some(vec![UntaggedValue::string("greater than 5").into()]),
},
Example {
description: "Run a block if a condition is false",
example: "echo 1 | if $it > 5 { echo 'greater than 5' } { echo 'less than or equal to 5' }",
result: Some(vec![UntaggedValue::string("less than or equal to 5").into()]),
},
]
}
}
async fn if_command(
raw_args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone());
let scope = raw_args.call_info.scope.clone();
let tag = raw_args.call_info.name_tag.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
let (
IfArgs {
condition,
then_case,
else_case,
},
input,
) = raw_args.process(&registry).await?;
let condition = {
if condition.block.len() != 1 {
return Err(ShellError::labeled_error(
"Expected a condition",
"expected a condition",
tag,
));
}
match condition.block[0].list.get(0) {
Some(item) => match item {
ClassifiedCommand::Expr(expr) => expr.clone(),
_ => {
return Err(ShellError::labeled_error(
"Expected a condition",
"expected a condition",
tag,
));
}
},
None => {
return Err(ShellError::labeled_error(
"Expected a condition",
"expected a condition",
tag,
));
}
}
};
Ok(input
.then(move |input| {
let condition = condition.clone();
let then_case = then_case.clone();
let else_case = else_case.clone();
let registry = registry.clone();
let scope = Scope::append_var(scope.clone(), "$it", input);
let mut context = context.clone();
async move {
//FIXME: should we use the scope that's brought in as well?
let condition = evaluate_baseline_expr(&condition, &*registry, scope.clone()).await;
match condition {
Ok(condition) => match condition.as_bool() {
Ok(b) => {
if b {
match run_block(
&then_case,
Arc::make_mut(&mut context),
InputStream::empty(),
scope,
)
.await
{
Ok(stream) => stream.to_output_stream(),
Err(e) => futures::stream::iter(vec![Err(e)].into_iter())
.to_output_stream(),
}
} else {
match run_block(
&else_case,
Arc::make_mut(&mut context),
InputStream::empty(),
scope,
)
.await
{
Ok(stream) => stream.to_output_stream(),
Err(e) => futures::stream::iter(vec![Err(e)].into_iter())
.to_output_stream(),
}
}
}
Err(e) => {
futures::stream::iter(vec![Err(e)].into_iter()).to_output_stream()
}
},
Err(e) => futures::stream::iter(vec![Err(e)].into_iter()).to_output_stream(),
}
}
})
.flatten()
.to_output_stream())
}
#[cfg(test)]
mod tests {
use super::If;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(If {})?)
}
}

View File

@ -1,78 +0,0 @@
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use derive_new::new;
use nu_errors::ShellError;
use nu_protocol::{hir::Block, PositionalType, Scope, Signature, UntaggedValue};
#[derive(new, Clone)]
pub struct AliasCommand {
sig: Signature,
block: Block,
}
#[async_trait]
impl WholeStreamCommand for AliasCommand {
fn name(&self) -> &str {
&self.sig.name
}
fn signature(&self) -> Signature {
self.sig.clone()
}
fn usage(&self) -> &str {
""
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let call_info = args.call_info.clone();
let registry = registry.clone();
let mut block = self.block.clone();
block.set_redirect(call_info.args.external_redirection);
// let alias_command = self.clone();
let mut context = EvaluationContext::from_args(&args, &registry);
let input = args.input;
let scope = call_info.scope.clone();
let evaluated = call_info.evaluate(&registry).await?;
let mut vars = IndexMap::new();
let mut num_positionals = 0;
if let Some(positional) = &evaluated.args.positional {
num_positionals = positional.len();
for (idx, arg) in positional.iter().enumerate() {
let pos_type = &self.sig.positional[idx].0;
match pos_type {
PositionalType::Mandatory(name, _) | PositionalType::Optional(name, _) => {
vars.insert(name.clone(), arg.clone());
}
}
}
}
//Fill out every missing argument with empty value
if self.sig.positional.len() > num_positionals {
for idx in num_positionals..self.sig.positional.len() {
let pos_type = &self.sig.positional[idx].0;
match pos_type {
PositionalType::Mandatory(name, _) | PositionalType::Optional(name, _) => {
vars.insert(name.clone(), UntaggedValue::nothing().into_untagged_value());
}
}
}
}
let scope = Scope::append_vars(scope, vars);
// FIXME: we need to patch up the spans to point at the top-level error
Ok(run_block(&block, &mut context, input, scope)
.await?
.to_output_stream())
}
}

View File

@ -1,78 +0,0 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
pub struct SubCommand;
#[derive(Deserialize)]
pub struct SubCommandArgs {
separator: Option<Tagged<String>>,
}
#[async_trait]
impl WholeStreamCommand for SubCommand {
fn name(&self) -> &str {
"str collect"
}
fn signature(&self) -> Signature {
Signature::build("str collect").desc(self.usage()).optional(
"separator",
SyntaxShape::String,
"the separator to put between the different values",
)
}
fn usage(&self) -> &str {
"collects a list of strings into a string"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
collect(args, registry).await
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Collect a list of string",
example: "echo ['a' 'b' 'c'] | str collect",
result: Some(vec![Value::from("abc")]),
}]
}
}
pub async fn collect(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let (SubCommandArgs { separator }, input) = args.process(registry).await?;
let separator = separator.map(|tagged| tagged.item).unwrap_or_default();
let strings: Vec<Result<String, ShellError>> =
input.map(|value| value.as_string()).collect().await;
let strings: Vec<String> = strings.into_iter().collect::<Result<_, _>>()?;
let output = strings.join(&separator);
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(output).into_value(tag),
)))
}
#[cfg(test)]
mod tests {
use super::ShellError;
use super::SubCommand;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(SubCommand {})?)
}
}

View File

@ -1,66 +0,0 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
pub struct SubCommand;
#[async_trait]
impl WholeStreamCommand for SubCommand {
fn name(&self) -> &str {
"str length"
}
fn signature(&self) -> Signature {
Signature::build("str length")
}
fn usage(&self) -> &str {
"outputs the lengths of the strings in the pipeline"
}
async fn run(
&self,
args: CommandArgs,
_registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
Ok(args
.input
.map(move |x| match x.as_string() {
Ok(s) => ReturnSuccess::value(UntaggedValue::int(s.len()).into_untagged_value()),
Err(err) => Err(err),
})
.to_output_stream())
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Return the lengths of multiple strings",
example: "echo 'hello' | str length",
result: Some(vec![UntaggedValue::int(5).into_untagged_value()]),
},
Example {
description: "Return the lengths of multiple strings",
example: "echo 'hi' 'there' | str length",
result: Some(vec![
UntaggedValue::int(2).into_untagged_value(),
UntaggedValue::int(5).into_untagged_value(),
]),
},
]
}
}
#[cfg(test)]
mod tests {
use super::ShellError;
use super::SubCommand;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(SubCommand {})?)
}
}

View File

@ -1,59 +0,0 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
pub struct SubCommand;
#[async_trait]
impl WholeStreamCommand for SubCommand {
fn name(&self) -> &str {
"str reverse"
}
fn signature(&self) -> Signature {
Signature::build("str reverse")
}
fn usage(&self) -> &str {
"outputs the reversals of the strings in the pipeline"
}
async fn run(
&self,
args: CommandArgs,
_registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
Ok(args
.input
.map(move |x| match x.as_string() {
Ok(s) => ReturnSuccess::value(
UntaggedValue::string(s.chars().rev().collect::<String>())
.into_untagged_value(),
),
Err(err) => Err(err),
})
.to_output_stream())
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Return the reversals of multiple strings",
example: "echo 'Nushell' | str reverse",
result: Some(vec![UntaggedValue::string("llehsuN").into_untagged_value()]),
}]
}
}
#[cfg(test)]
mod tests {
use super::ShellError;
use super::SubCommand;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(SubCommand {})?)
}
}

View File

@ -1,124 +0,0 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::{Tag, Tagged};
use nu_value_ext::ValueExt;
#[derive(Deserialize)]
struct Arguments {
replace: Tagged<String>,
rest: Vec<ColumnPath>,
}
pub struct SubCommand;
#[async_trait]
impl WholeStreamCommand for SubCommand {
fn name(&self) -> &str {
"str set"
}
fn signature(&self) -> Signature {
Signature::build("str set")
.required("set", SyntaxShape::String, "the new string to set")
.rest(
SyntaxShape::ColumnPath,
"optionally set text by column paths",
)
}
fn usage(&self) -> &str {
"sets text"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
operate(args, registry).await
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Set contents with preferred string",
example: "echo 'good day' | str set 'good bye'",
result: Some(vec![Value::from("good bye")]),
},
Example {
description: "Set the contents on preferred column paths",
example: "open Cargo.toml | str set '255' package.version",
result: None,
},
]
}
}
#[derive(Clone)]
struct Replace(String);
async fn operate(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let (Arguments { replace, rest }, input) = args.process(&registry).await?;
let options = Replace(replace.item);
let column_paths: Vec<_> = rest;
Ok(input
.map(move |v| {
if column_paths.is_empty() {
ReturnSuccess::value(action(&v, &options, v.tag())?)
} else {
let mut ret = v;
for path in &column_paths {
let options = options.clone();
ret = ret.swap_data_by_column_path(
path,
Box::new(move |old| action(old, &options, old.tag())),
)?;
}
ReturnSuccess::value(ret)
}
})
.to_output_stream())
}
fn action(_input: &Value, options: &Replace, tag: impl Into<Tag>) -> Result<Value, ShellError> {
let replacement = &options.0;
Ok(UntaggedValue::string(replacement.as_str()).into_value(tag))
}
#[cfg(test)]
mod tests {
use super::ShellError;
use super::{action, Replace, SubCommand};
use nu_source::Tag;
use nu_test_support::value::string;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(SubCommand {})?)
}
#[test]
fn sets() {
let word = string("andres");
let expected = string("robalino");
let set_options = Replace(String::from("robalino"));
let actual = action(&word, &set_options, Tag::unknown()).unwrap();
assert_eq!(actual, expected);
}
}

View File

@ -1,96 +0,0 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use indexmap::IndexMap;
use nu_data::TaggedListBuilder;
use nu_errors::ShellError;
use nu_protocol::{Dictionary, Signature, UntaggedValue};
const GIT_COMMIT_HASH: &str = include_str!(concat!(env!("OUT_DIR"), "/git_commit_hash"));
pub struct Version;
#[async_trait]
impl WholeStreamCommand for Version {
fn name(&self) -> &str {
"version"
}
fn signature(&self) -> Signature {
Signature::build("version")
}
fn usage(&self) -> &str {
"Display Nu version"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
version(args, registry)
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Display Nu version",
example: "version",
result: None,
}]
}
}
pub fn version(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let tag = args.call_info.args.span;
let mut indexmap = IndexMap::with_capacity(4);
indexmap.insert(
"version".to_string(),
UntaggedValue::string(clap::crate_version!()).into_value(&tag),
);
let commit_hash = Some(GIT_COMMIT_HASH.trim()).filter(|x| !x.is_empty());
if let Some(commit_hash) = commit_hash {
indexmap.insert(
"commit_hash".to_string(),
UntaggedValue::string(commit_hash).into_value(&tag),
);
}
indexmap.insert("features".to_string(), features_enabled(&tag).into_value());
let value = UntaggedValue::Row(Dictionary::from(indexmap)).into_value(&tag);
Ok(OutputStream::one(value))
}
fn features_enabled(tag: impl Into<Tag>) -> TaggedListBuilder {
let mut names = TaggedListBuilder::new(tag);
names.push_untagged(UntaggedValue::string("default"));
#[cfg(feature = "clipboard-cli")]
{
names.push_untagged(UntaggedValue::string("clipboard"));
}
#[cfg(feature = "trash-support")]
{
names.push_untagged(UntaggedValue::string("trash"));
}
names
}
#[cfg(test)]
mod tests {
use super::ShellError;
use super::Version;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Version {})?)
}
}

View File

@ -1,134 +0,0 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use indexmap::map::IndexMap;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
pub struct Which;
#[async_trait]
impl WholeStreamCommand for Which {
fn name(&self) -> &str {
"which"
}
fn signature(&self) -> Signature {
Signature::build("which")
.required("application", SyntaxShape::String, "application")
.switch("all", "list all executables", Some('a'))
}
fn usage(&self) -> &str {
"Finds a program file."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
which(args, registry).await
}
}
/// Shortcuts for creating an entry to the output table
fn entry(arg: impl Into<String>, path: Value, builtin: bool, tag: Tag) -> Value {
let mut map = IndexMap::new();
map.insert(
"arg".to_string(),
UntaggedValue::Primitive(Primitive::String(arg.into())).into_value(tag.clone()),
);
map.insert("path".to_string(), path);
map.insert(
"builtin".to_string(),
UntaggedValue::boolean(builtin).into_value(tag.clone()),
);
UntaggedValue::row(map).into_value(tag)
}
macro_rules! entry_builtin {
($arg:expr, $tag:expr) => {
entry(
$arg.clone(),
UntaggedValue::Primitive(Primitive::String("nushell built-in command".to_string()))
.into_value($tag.clone()),
true,
$tag,
)
};
}
#[allow(unused)]
macro_rules! entry_path {
($arg:expr, $path:expr, $tag:expr) => {
entry(
$arg.clone(),
UntaggedValue::Primitive(Primitive::Path($path)).into_value($tag.clone()),
false,
$tag,
)
};
}
#[derive(Deserialize, Debug)]
struct WhichArgs {
application: Tagged<String>,
all: bool,
}
async fn which(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let mut output = vec![];
let (WhichArgs { application, all }, _) = args.process(&registry).await?;
let external = application.starts_with('^');
let item = if external {
application.item[1..].to_string()
} else {
application.item.clone()
};
if !external {
let builtin = registry.has(&item);
if builtin {
output.push(ReturnSuccess::value(entry_builtin!(
item,
application.tag.clone()
)));
}
}
#[cfg(feature = "ichwh")]
{
if let Ok(paths) = ichwh::which_all(&item).await {
for path in paths {
output.push(ReturnSuccess::value(entry_path!(
item,
path.into(),
application.tag.clone()
)));
}
}
}
if all {
Ok(futures::stream::iter(output.into_iter()).to_output_stream())
} else {
Ok(futures::stream::iter(output.into_iter().take(1)).to_output_stream())
}
}
#[cfg(test)]
mod tests {
use super::ShellError;
use super::Which;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Which {})?)
}
}

View File

@ -5,7 +5,7 @@ use indexmap::set::IndexSet;
use super::matchers::Matcher;
use crate::completion::{Completer, CompletionContext, Suggestion};
use crate::evaluation_context::EvaluationContext;
use nu_engine::EvaluationContext;
pub struct CommandCompleter;
@ -17,7 +17,7 @@ impl Completer for CommandCompleter {
matcher: &dyn Matcher,
) -> Vec<Suggestion> {
let context: &EvaluationContext = ctx.as_ref();
let mut commands: IndexSet<String> = IndexSet::from_iter(context.registry.names());
let mut commands: IndexSet<String> = IndexSet::from_iter(context.scope.get_command_names());
// Command suggestions can come from three possible sets:
// 1. internal command names,
@ -38,7 +38,7 @@ impl Completer for CommandCompleter {
})
.collect();
if partial != "" {
if !partial.is_empty() {
let path_completer = crate::completion::path::PathCompleter;
let path_results = path_completer.path_suggestions(partial, matcher);
let iter = path_results.into_iter().filter_map(|path_suggestion| {

View File

@ -138,7 +138,7 @@ impl<'s> Flatten<'s> {
result
}
fn pipeline(&self, pipeline: &Commands) -> Vec<CompletionLocation> {
fn pipeline(&self, pipeline: &Pipeline) -> Vec<CompletionLocation> {
let mut result = Vec::new();
for command in &pipeline.list {
@ -158,7 +158,11 @@ impl<'s> Flatten<'s> {
/// Flattens the block into a Vec of completion locations
pub fn completion_locations(&self, block: &Block) -> Vec<CompletionLocation> {
block.block.iter().flat_map(|v| self.pipeline(v)).collect()
block
.block
.iter()
.flat_map(|g| g.pipelines.iter().flat_map(|v| self.pipeline(v)))
.collect()
}
pub fn new(line: &'s str) -> Flatten<'s> {
@ -252,7 +256,7 @@ pub fn completion_location(line: &str, block: &Block, pos: usize) -> Vec<Complet
mod tests {
use super::*;
use nu_parser::SignatureRegistry;
use nu_parser::{block, classify_block, lex, ParserScope};
use nu_protocol::{Signature, SyntaxShape};
#[derive(Clone, Debug)]
@ -264,35 +268,52 @@ mod tests {
}
}
impl SignatureRegistry for VecRegistry {
fn has(&self, name: &str) -> bool {
impl ParserScope for VecRegistry {
fn has_signature(&self, name: &str) -> bool {
self.0.iter().any(|v| v.name == name)
}
fn get(&self, name: &str) -> Option<nu_protocol::Signature> {
fn get_signature(&self, name: &str) -> Option<nu_protocol::Signature> {
self.0.iter().find(|v| v.name == name).map(Clone::clone)
}
fn clone_box(&self) -> Box<dyn SignatureRegistry> {
Box::new(self.clone())
fn get_alias(&self, _name: &str) -> Option<Vec<Spanned<String>>> {
None
}
fn add_alias(&self, _name: &str, _replacement: Vec<Spanned<String>>) {
todo!()
}
fn add_definition(&self, _block: Block) {}
fn get_definitions(&self) -> Vec<Block> {
vec![]
}
fn enter_scope(&self) {}
fn exit_scope(&self) {}
}
mod completion_location {
use super::*;
use nu_parser::{classify_block, lite_parse, SignatureRegistry};
use nu_parser::ParserScope;
fn completion_location(
line: &str,
registry: &dyn SignatureRegistry,
scope: &dyn ParserScope,
pos: usize,
) -> Vec<LocationType> {
let (lite_block, _) = lite_parse(line, 0);
let (tokens, _) = lex(line, 0);
let (lite_block, _) = block(tokens);
let block = classify_block(&lite_block, registry);
scope.enter_scope();
let (block, _) = classify_block(&lite_block, scope);
scope.exit_scope();
super::completion_location(line, &block.block, pos)
super::completion_location(line, &block, pos)
.into_iter()
.map(|v| v.item)
.collect()

View File

@ -1,6 +1,6 @@
use super::matchers::Matcher;
use crate::completion::{Completer, CompletionContext, Suggestion};
use crate::evaluation_context::EvaluationContext;
use nu_engine::EvaluationContext;
pub struct FlagCompleter {
pub(crate) cmd: String,
@ -15,7 +15,7 @@ impl Completer for FlagCompleter {
) -> Vec<Suggestion> {
let context: &EvaluationContext = ctx.as_ref();
if let Some(cmd) = context.registry.get_command(&self.cmd) {
if let Some(cmd) = context.scope.get_command(&self.cmd) {
let sig = cmd.signature();
let mut suggestions = Vec::new();
for (name, (named_type, _desc)) in sig.named.iter() {

View File

@ -4,8 +4,8 @@ pub(crate) mod flag;
pub(crate) mod matchers;
pub(crate) mod path;
use crate::evaluation_context::EvaluationContext;
use matchers::Matcher;
use nu_engine::EvaluationContext;
#[derive(Debug, Eq, PartialEq)]
pub struct Suggestion {

View File

@ -22,14 +22,14 @@ impl PathCompleter {
None => ("", expanded),
};
let base_dir = if base_dir_name == "" {
let base_dir = if base_dir_name.is_empty() {
PathBuf::from(".")
} else {
#[cfg(feature = "directories")]
{
let home_prefix = format!("~{}", SEP);
if base_dir_name.starts_with(&home_prefix) {
let mut home_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("~"));
let mut home_dir = dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("~"));
home_dir.push(&base_dir_name[2..]);
home_dir
} else {

View File

@ -1,6 +1,3 @@
pub(crate) mod directory_specific_environment;
pub(crate) mod environment;
pub(crate) mod environment_syncer;
pub(crate) mod host;
pub(crate) use self::host::Host;

View File

@ -1,6 +1,5 @@
use crate::commands;
use commands::autoenv;
use indexmap::{IndexMap, IndexSet};
use nu_command::commands::autoenv;
use nu_errors::ShellError;
use serde::Deserialize;
use std::env::*;

View File

@ -1,38 +1,9 @@
use crate::env::directory_specific_environment::*;
use indexmap::{indexmap, IndexSet};
use nu_data::config::Conf;
use nu_engine::Env;
use nu_errors::ShellError;
use nu_protocol::{UntaggedValue, Value};
use std::env::*;
use std::ffi::OsString;
use std::fmt::Debug;
pub trait Env: Debug + Send {
fn env(&self) -> Option<Value>;
fn path(&self) -> Option<Value>;
fn add_env(&mut self, key: &str, value: &str);
fn add_path(&mut self, new_path: OsString);
}
impl Env for Box<dyn Env> {
fn env(&self) -> Option<Value> {
(**self).env()
}
fn path(&self) -> Option<Value> {
(**self).path()
}
fn add_env(&mut self, key: &str, value: &str) {
(**self).add_env(key, value);
}
fn add_path(&mut self, new_path: OsString) {
(**self).add_path(new_path);
}
}
#[derive(Debug, Default)]
pub struct Environment {
@ -128,7 +99,7 @@ impl Env for Environment {
{
let mut new_paths = current_paths.clone();
let new_path_candidates = split_paths(&paths).map(|path| {
let new_path_candidates = std::env::split_paths(&paths).map(|path| {
UntaggedValue::string(path.to_string_lossy()).into_value(tag.clone())
});

View File

@ -1,9 +1,10 @@
use crate::env::environment::{Env, Environment};
use crate::evaluation_context::EvaluationContext;
use crate::env::environment::Environment;
use nu_data::config::{Conf, NuConfig};
use nu_engine::Env;
use nu_engine::EvaluationContext;
use nu_errors::ShellError;
use parking_lot::Mutex;
use std::sync::Arc;
use std::sync::{atomic::Ordering, Arc};
pub struct EnvironmentSyncer {
pub env: Arc<Mutex<Box<Environment>>>,
@ -63,8 +64,12 @@ impl EnvironmentSyncer {
pub fn autoenv(&self, ctx: &mut EvaluationContext) -> Result<(), ShellError> {
let mut environment = self.env.lock();
let auto = environment.autoenv(ctx.user_recently_used_autoenv_untrust);
ctx.user_recently_used_autoenv_untrust = false;
let recently_used = ctx
.user_recently_used_autoenv_untrust
.load(Ordering::SeqCst);
let auto = environment.autoenv(recently_used);
ctx.user_recently_used_autoenv_untrust
.store(false, Ordering::SeqCst);
auto
}
@ -148,10 +153,10 @@ impl EnvironmentSyncer {
#[cfg(test)]
mod tests {
use super::EnvironmentSyncer;
use crate::env::environment::Env;
use crate::evaluation_context::EvaluationContext;
use indexmap::IndexMap;
use nu_data::config::tests::FakeConfig;
use nu_engine::basic_evaluation_context;
use nu_engine::Env;
use nu_errors::ShellError;
use nu_test_support::fs::Stub::FileWithContent;
use nu_test_support::playground::Playground;
@ -166,8 +171,8 @@ mod tests {
#[test]
fn syncs_env_if_new_env_entry_is_added_to_an_existing_configuration() -> Result<(), ShellError>
{
let mut ctx = EvaluationContext::basic()?;
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
let mut ctx = basic_evaluation_context()?;
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
let mut expected = IndexMap::new();
expected.insert(
@ -198,7 +203,7 @@ mod tests {
let new_file = dirs.test().join("updated_configuration.toml");
let fake_config = FakeConfig::new(&file);
let mut actual = EnvironmentSyncer::with_config(Box::new(fake_config.clone()));
let mut actual = EnvironmentSyncer::with_config(Box::new(fake_config));
// Here, the environment variables from the current session
// are cleared since we will load and set them from the
@ -269,8 +274,8 @@ mod tests {
#[test]
fn syncs_env_if_new_env_entry_in_session_is_not_in_configuration_file() -> Result<(), ShellError>
{
let mut ctx = EvaluationContext::basic()?;
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
let mut ctx = basic_evaluation_context()?;
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
let mut expected = IndexMap::new();
expected.insert(
@ -368,8 +373,8 @@ mod tests {
#[test]
fn nu_envs_have_higher_priority_and_does_not_get_overwritten() -> Result<(), ShellError> {
let mut ctx = EvaluationContext::basic()?;
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
let mut ctx = basic_evaluation_context()?;
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
let mut expected = IndexMap::new();
expected.insert(
@ -444,8 +449,8 @@ mod tests {
#[test]
fn syncs_path_if_new_path_entry_in_session_is_not_in_configuration_file(
) -> Result<(), ShellError> {
let mut ctx = EvaluationContext::basic()?;
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
let mut ctx = basic_evaluation_context()?;
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
let expected = std::env::join_paths(vec![
PathBuf::from("/Users/andresrobalino/.volta/bin"),
@ -531,8 +536,8 @@ mod tests {
#[test]
fn nu_paths_have_higher_priority_and_new_paths_get_appended_to_the_end(
) -> Result<(), ShellError> {
let mut ctx = EvaluationContext::basic()?;
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
let mut ctx = basic_evaluation_context()?;
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
let expected = std::env::join_paths(vec![
PathBuf::from("/Users/andresrobalino/.volta/bin"),

View File

@ -1,195 +0,0 @@
use crate::command_registry::CommandRegistry;
use crate::commands::{command::CommandArgs, Command, UnevaluatedCallInfo};
use crate::env::host::Host;
use crate::shell::shell_manager::ShellManager;
use crate::stream::{InputStream, OutputStream};
use indexmap::IndexMap;
use nu_errors::ShellError;
use nu_protocol::{hir, Scope};
use nu_source::{Tag, Text};
use parking_lot::Mutex;
use std::error::Error;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
#[derive(Clone)]
pub struct EvaluationContext {
pub registry: CommandRegistry,
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
pub ctrl_c: Arc<AtomicBool>,
pub raw_input: String,
pub user_recently_used_autoenv_untrust: bool,
pub(crate) shell_manager: ShellManager,
/// Windows-specific: keep track of previous cwd on each drive
pub windows_drives_previous_cwd: Arc<Mutex<std::collections::HashMap<String, String>>>,
}
impl EvaluationContext {
pub(crate) fn registry(&self) -> &CommandRegistry {
&self.registry
}
pub(crate) fn from_raw(
raw_args: &CommandArgs,
registry: &CommandRegistry,
) -> EvaluationContext {
EvaluationContext {
registry: registry.clone(),
host: raw_args.host.clone(),
current_errors: raw_args.current_errors.clone(),
ctrl_c: raw_args.ctrl_c.clone(),
shell_manager: raw_args.shell_manager.clone(),
user_recently_used_autoenv_untrust: false,
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
raw_input: String::default(),
}
}
pub(crate) fn from_args(args: &CommandArgs, registry: &CommandRegistry) -> EvaluationContext {
EvaluationContext {
registry: registry.clone(),
host: args.host.clone(),
current_errors: args.current_errors.clone(),
ctrl_c: args.ctrl_c.clone(),
shell_manager: args.shell_manager.clone(),
user_recently_used_autoenv_untrust: false,
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
raw_input: String::default(),
}
}
pub fn basic() -> Result<EvaluationContext, Box<dyn Error>> {
let registry = CommandRegistry::new();
Ok(EvaluationContext {
registry,
host: Arc::new(parking_lot::Mutex::new(Box::new(
crate::env::host::BasicHost,
))),
current_errors: Arc::new(Mutex::new(vec![])),
ctrl_c: Arc::new(AtomicBool::new(false)),
user_recently_used_autoenv_untrust: false,
shell_manager: ShellManager::basic()?,
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
raw_input: String::default(),
})
}
pub(crate) fn error(&mut self, error: ShellError) {
self.with_errors(|errors| errors.push(error))
}
pub(crate) fn clear_errors(&mut self) {
self.current_errors.lock().clear()
}
pub(crate) fn get_errors(&self) -> Vec<ShellError> {
self.current_errors.lock().clone()
}
pub(crate) fn add_error(&self, err: ShellError) {
self.current_errors.lock().push(err);
}
pub(crate) fn maybe_print_errors(&mut self, source: Text) -> bool {
let errors = self.current_errors.clone();
let mut errors = errors.lock();
if errors.len() > 0 {
let error = errors[0].clone();
*errors = vec![];
crate::cli::print_err(error, &source);
true
} else {
false
}
}
pub(crate) fn configure<T>(
&mut self,
config: &dyn nu_data::config::Conf,
block: impl FnOnce(&dyn nu_data::config::Conf, &mut Self) -> T,
) {
block(config, &mut *self);
}
pub(crate) fn with_host<T>(&mut self, block: impl FnOnce(&mut dyn Host) -> T) -> T {
let mut host = self.host.lock();
block(&mut *host)
}
pub(crate) fn with_errors<T>(&mut self, block: impl FnOnce(&mut Vec<ShellError>) -> T) -> T {
let mut errors = self.current_errors.lock();
block(&mut *errors)
}
pub fn add_commands(&mut self, commands: Vec<Command>) {
for command in commands {
self.registry.insert(command.name().to_string(), command);
}
}
#[allow(unused)]
pub(crate) fn get_command(&self, name: &str) -> Option<Command> {
self.registry.get_command(name)
}
pub(crate) fn is_command_registered(&self, name: &str) -> bool {
self.registry.has(name)
}
pub(crate) fn expect_command(&self, name: &str) -> Result<Command, ShellError> {
self.registry.expect_command(name)
}
pub(crate) async fn run_command(
&mut self,
command: Command,
name_tag: Tag,
args: hir::Call,
scope: Arc<Scope>,
input: InputStream,
) -> Result<OutputStream, ShellError> {
let command_args = self.command_args(args, input, name_tag, scope);
command.run(command_args, self.registry()).await
}
fn call_info(&self, args: hir::Call, name_tag: Tag, scope: Arc<Scope>) -> UnevaluatedCallInfo {
UnevaluatedCallInfo {
args,
name_tag,
scope,
}
}
fn command_args(
&self,
args: hir::Call,
input: InputStream,
name_tag: Tag,
scope: Arc<Scope>,
) -> CommandArgs {
CommandArgs {
host: self.host.clone(),
ctrl_c: self.ctrl_c.clone(),
current_errors: self.current_errors.clone(),
shell_manager: self.shell_manager.clone(),
call_info: self.call_info(args, name_tag, scope),
input,
raw_input: self.raw_input.clone(),
}
}
pub fn get_env(&self) -> IndexMap<String, String> {
let mut output = IndexMap::new();
for (var, value) in self.host.lock().vars() {
output.insert(var, value);
}
output
}
}

View File

@ -1,492 +0,0 @@
use nu_errors::ShellError;
use nu_protocol::hir::ClassifiedBlock;
use nu_protocol::{
Primitive, ReturnSuccess, Scope, ShellTypeName, Signature, SyntaxShape, UntaggedValue, Value,
};
use nu_source::{AnchorLocation, TaggedItem};
use crate::prelude::*;
use num_bigint::BigInt;
use crate::command_registry::CommandRegistry;
use crate::commands::classified::block::run_block;
use crate::commands::command::CommandArgs;
use crate::commands::{
whole_stream_command, BuildString, Command, Each, Echo, First, Get, Keep, Last, Nth,
StrCollect, WholeStreamCommand, Wrap,
};
use crate::evaluation_context::EvaluationContext;
use crate::stream::{InputStream, OutputStream};
use async_trait::async_trait;
use futures::executor::block_on;
use serde::Deserialize;
pub fn test_examples(cmd: Command) -> Result<(), ShellError> {
let examples = cmd.examples();
let mut base_context = EvaluationContext::basic()?;
base_context.add_commands(vec![
// Mocks
whole_stream_command(MockLs {}),
// Minimal restricted commands to aid in testing
whole_stream_command(Echo {}),
whole_stream_command(BuildString {}),
whole_stream_command(First {}),
whole_stream_command(Get {}),
whole_stream_command(Keep {}),
whole_stream_command(Each {}),
whole_stream_command(Last {}),
whole_stream_command(Nth {}),
whole_stream_command(StrCollect),
whole_stream_command(Wrap),
cmd,
]);
for sample_pipeline in examples {
let mut ctx = base_context.clone();
let block = parse_line(sample_pipeline.example, &mut ctx)?;
if let Some(expected) = &sample_pipeline.result {
let result = block_on(evaluate_block(block, &mut ctx))?;
ctx.with_errors(|reasons| reasons.iter().cloned().take(1).next())
.map_or(Ok(()), Err)?;
if expected.len() != result.len() {
let rows_returned =
format!("expected: {}\nactual: {}", expected.len(), result.len());
let failed_call = format!("command: {}\n", sample_pipeline.example);
panic!(
"example command produced unexpected number of results.\n {} {}",
failed_call, rows_returned
);
}
for (e, a) in expected.iter().zip(result.iter()) {
if !values_equal(e, a) {
let row_errored = format!("expected: {:#?}\nactual: {:#?}", e, a);
let failed_call = format!("command: {}\n", sample_pipeline.example);
panic!(
"example command produced unexpected result.\n {} {}",
failed_call, row_errored
);
}
}
}
}
Ok(())
}
pub fn test(cmd: impl WholeStreamCommand + 'static) -> Result<(), ShellError> {
let examples = cmd.examples();
let mut base_context = EvaluationContext::basic()?;
base_context.add_commands(vec![
whole_stream_command(Echo {}),
whole_stream_command(BuildString {}),
whole_stream_command(Get {}),
whole_stream_command(Keep {}),
whole_stream_command(Each {}),
whole_stream_command(cmd),
whole_stream_command(StrCollect),
whole_stream_command(Wrap),
]);
for sample_pipeline in examples {
let mut ctx = base_context.clone();
let block = parse_line(sample_pipeline.example, &mut ctx)?;
if let Some(expected) = &sample_pipeline.result {
let result = block_on(evaluate_block(block, &mut ctx))?;
ctx.with_errors(|reasons| reasons.iter().cloned().take(1).next())
.map_or(Ok(()), Err)?;
if expected.len() != result.len() {
let rows_returned =
format!("expected: {}\nactual: {}", expected.len(), result.len());
let failed_call = format!("command: {}\n", sample_pipeline.example);
panic!(
"example command produced unexpected number of results.\n {} {}",
failed_call, rows_returned
);
}
for (e, a) in expected.iter().zip(result.iter()) {
if !values_equal(e, a) {
let row_errored = format!("expected: {:#?}\nactual: {:#?}", e, a);
let failed_call = format!("command: {}\n", sample_pipeline.example);
panic!(
"example command produced unexpected result.\n {} {}",
failed_call, row_errored
);
}
}
}
}
Ok(())
}
pub fn test_anchors(cmd: Command) -> Result<(), ShellError> {
let examples = cmd.examples();
let mut base_context = EvaluationContext::basic()?;
base_context.add_commands(vec![
// Minimal restricted commands to aid in testing
whole_stream_command(MockCommand {}),
whole_stream_command(MockEcho {}),
whole_stream_command(MockLs {}),
whole_stream_command(BuildString {}),
whole_stream_command(First {}),
whole_stream_command(Get {}),
whole_stream_command(Keep {}),
whole_stream_command(Each {}),
whole_stream_command(Last {}),
whole_stream_command(Nth {}),
whole_stream_command(StrCollect),
whole_stream_command(Wrap),
cmd,
]);
for sample_pipeline in examples {
let pipeline_with_anchor = format!("mock --open --path | {}", sample_pipeline.example);
let mut ctx = base_context.clone();
let block = parse_line(&pipeline_with_anchor, &mut ctx)?;
let result = block_on(evaluate_block(block, &mut ctx))?;
ctx.with_errors(|reasons| reasons.iter().cloned().take(1).next())
.map_or(Ok(()), Err)?;
for actual in result.iter() {
if !is_anchor_carried(actual, mock_path()) {
let failed_call = format!("command: {}\n", pipeline_with_anchor);
panic!(
"example command didn't carry anchor tag correctly.\n {} {:#?} {:#?}",
failed_call,
actual,
mock_path()
);
}
}
}
Ok(())
}
/// Parse and run a nushell pipeline
fn parse_line(line: &str, ctx: &mut EvaluationContext) -> Result<ClassifiedBlock, ShellError> {
let line = if let Some(line) = line.strip_suffix('\n') {
line
} else {
line
};
let (lite_result, err) = nu_parser::lite_parse(&line, 0);
if let Some(err) = err {
return Err(err.into());
}
// TODO ensure the command whose examples we're testing is actually in the pipeline
let classified_block = nu_parser::classify_block(&lite_result, ctx.registry());
Ok(classified_block)
}
async fn evaluate_block(
block: ClassifiedBlock,
ctx: &mut EvaluationContext,
) -> Result<Vec<Value>, ShellError> {
let input_stream = InputStream::empty();
let env = ctx.get_env();
let scope = Scope::from_env(env);
Ok(run_block(&block.block, ctx, input_stream, scope)
.await?
.drain_vec()
.await)
}
// TODO probably something already available to do this
// TODO perhaps better panic messages when things don't compare
// Deep value comparisons that ignore tags
fn values_equal(expected: &Value, actual: &Value) -> bool {
use nu_protocol::UntaggedValue::*;
match (&expected.value, &actual.value) {
(Primitive(e), Primitive(a)) => e == a,
(Row(e), Row(a)) => {
if e.entries.len() != a.entries.len() {
return false;
}
e.entries
.iter()
.zip(a.entries.iter())
.all(|((ek, ev), (ak, av))| ek == ak && values_equal(ev, av))
}
(Table(e), Table(a)) => e.iter().zip(a.iter()).all(|(e, a)| values_equal(e, a)),
(e, a) => unimplemented!("{} {}", e.type_name(), a.type_name()),
}
}
fn is_anchor_carried(actual: &Value, anchor: AnchorLocation) -> bool {
actual.tag.anchor() == Some(anchor)
}
#[derive(Deserialize)]
struct Arguments {
path: Option<bool>,
open: bool,
}
struct MockCommand;
#[async_trait]
impl WholeStreamCommand for MockCommand {
fn name(&self) -> &str {
"mock"
}
fn signature(&self) -> Signature {
Signature::build("mock")
.switch("open", "fake opening sources", Some('o'))
.switch("path", "file open", Some('p'))
}
fn usage(&self) -> &str {
"Generates tables and metadata that mimics behavior of real commands in controlled ways."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let name_tag = args.call_info.name_tag.clone();
let (
Arguments {
path: mocked_path,
open: open_mock,
},
_input,
) = args.process(&registry).await?;
let out = UntaggedValue::string("Yehuda Katz in Ecuador");
if open_mock {
if let Some(true) = mocked_path {
return Ok(OutputStream::one(Ok(ReturnSuccess::Value(Value {
value: out,
tag: Tag {
anchor: Some(mock_path()),
span: name_tag.span,
},
}))));
}
}
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
out.into_value(name_tag),
))))
}
}
struct MockEcho;
#[derive(Deserialize)]
struct MockEchoArgs {
pub rest: Vec<Value>,
}
#[async_trait]
impl WholeStreamCommand for MockEcho {
fn name(&self) -> &str {
"echo"
}
fn signature(&self) -> Signature {
Signature::build("echo").rest(SyntaxShape::Any, "the values to echo")
}
fn usage(&self) -> &str {
"Mock echo."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let name_tag = args.call_info.name_tag.clone();
let (MockEchoArgs { rest }, input) = args.process(&registry).await?;
let mut base_value = UntaggedValue::string("Yehuda Katz in Ecuador").into_value(name_tag);
let input: Vec<Value> = input.collect().await;
if let Some(first) = input.get(0) {
base_value = first.clone()
}
let stream = rest.into_iter().map(move |i| {
let base_value = base_value.clone();
match i.as_string() {
Ok(s) => OutputStream::one(Ok(ReturnSuccess::Value(Value {
value: UntaggedValue::Primitive(Primitive::String(s)),
tag: base_value.tag,
}))),
_ => match i {
Value {
value: UntaggedValue::Table(table),
..
} => {
if table.len() == 1 && table[0].is_table() {
let mut values: Vec<Value> =
table[0].table_entries().map(Clone::clone).collect();
for v in values.iter_mut() {
v.tag = base_value.tag();
}
let subtable =
vec![UntaggedValue::Table(values).into_value(base_value.tag())];
futures::stream::iter(subtable.into_iter().map(ReturnSuccess::value))
.to_output_stream()
} else {
futures::stream::iter(
table
.into_iter()
.map(move |mut v| {
v.tag = base_value.tag();
v
})
.map(ReturnSuccess::value),
)
.to_output_stream()
}
}
_ => OutputStream::one(Ok(ReturnSuccess::Value(Value {
value: i.value.clone(),
tag: base_value.tag,
}))),
},
}
});
Ok(futures::stream::iter(stream).flatten().to_output_stream())
}
}
struct MockLs;
#[async_trait]
impl WholeStreamCommand for MockLs {
fn name(&self) -> &str {
"ls"
}
fn signature(&self) -> Signature {
Signature::build("ls")
}
fn usage(&self) -> &str {
"Mock ls."
}
async fn run(
&self,
args: CommandArgs,
_: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let name_tag = args.call_info.name_tag.clone();
let mut base_value =
UntaggedValue::string("Andrés N. Robalino in Portland").into_value(name_tag);
let input: Vec<Value> = args.input.collect().await;
if let Some(first) = input.get(0) {
base_value = first.clone()
}
Ok(futures::stream::iter(
file_listing()
.iter()
.map(|row| Value {
value: row.value.clone(),
tag: base_value.tag.clone(),
})
.collect::<Vec<_>>()
.into_iter()
.map(ReturnSuccess::value),
)
.to_output_stream())
}
}
fn int(s: impl Into<BigInt>) -> Value {
UntaggedValue::int(s).into_untagged_value()
}
fn string(input: impl Into<String>) -> Value {
UntaggedValue::string(input.into()).into_untagged_value()
}
fn date(input: impl Into<String>) -> Value {
let key = input.into().tagged_unknown();
crate::value::Date::naive_from_str(key.borrow_tagged())
.expect("date from string failed")
.into_untagged_value()
}
fn file_listing() -> Vec<Value> {
vec![
row! {
"name".to_string() => string("Andrés.txt"),
"type".to_string() => string("File"),
"chickens".to_string() => int(10),
"modified".to_string() => date("2019-07-23")
},
row! {
"name".to_string() => string("Jonathan"),
"type".to_string() => string("Dir"),
"chickens".to_string() => int(5),
"modified".to_string() => date("2019-07-23")
},
row! {
"name".to_string() => string("Andrés.txt"),
"type".to_string() => string("File"),
"chickens".to_string() => int(20),
"modified".to_string() => date("2019-09-24")
},
row! {
"name".to_string() => string("Yehuda"),
"type".to_string() => string("Dir"),
"chickens".to_string() => int(4),
"modified".to_string() => date("2019-09-24")
},
]
}
fn mock_path() -> AnchorLocation {
let path = String::from("path/to/las_best_arepas_in_the_world.txt");
AnchorLocation::File(path)
}

View File

@ -1,26 +0,0 @@
pub fn current_branch() -> Option<String> {
#[cfg(feature = "git2")]
{
use git2::{Repository, RepositoryOpenFlags};
use std::ffi::OsString;
let v: Vec<OsString> = vec![];
match Repository::open_ext(".", RepositoryOpenFlags::empty(), v) {
Ok(repo) => {
let r = repo.head();
match r {
Ok(r) => match r.shorthand() {
Some(s) => Some(s.to_string()),
None => None,
},
_ => None,
}
}
_ => None,
}
}
#[cfg(not(feature = "git2"))]
{
None
}
}

View File

@ -405,14 +405,10 @@ pub struct Keybinding {
type Keybindings = Vec<Keybinding>;
pub(crate) fn keybinding_path() -> Result<std::path::PathBuf, nu_errors::ShellError> {
nu_data::config::default_path_for(&Some(std::path::PathBuf::from("keybindings.yml")))
}
pub(crate) fn load_keybindings(
rl: &mut rustyline::Editor<crate::shell::Helper>,
) -> Result<(), nu_errors::ShellError> {
let filename = keybinding_path()?;
let filename = nu_data::keybinding::keybinding_path()?;
let contents = std::fs::read_to_string(filename);
// Silently fail if there is no file there

View File

@ -14,52 +14,28 @@ extern crate quickcheck;
extern crate quickcheck_macros;
mod cli;
mod command_registry;
mod commands;
#[cfg(feature = "rustyline-support")]
mod completion;
mod deserializer;
mod documentation;
mod env;
mod evaluate;
mod evaluation_context;
mod format;
mod futures;
#[cfg(feature = "rustyline-support")]
mod git;
#[cfg(feature = "rustyline-support")]
mod keybinding;
mod path;
mod plugin;
mod line_editor;
mod shell;
mod stream;
pub mod types;
pub mod utils;
#[cfg(test)]
mod examples;
#[cfg(feature = "rustyline-support")]
pub use crate::cli::cli;
pub use crate::cli::{
create_default_context, parse_and_eval, process_line, register_plugins,
run_pipeline_standalone, run_vec_of_pipelines, LineResult,
};
pub use crate::command_registry::CommandRegistry;
pub use crate::commands::command::{
whole_stream_command, CommandArgs, EvaluatedWholeStreamCommandArgs, Example, WholeStreamCommand,
};
pub use crate::commands::help::get_help;
pub use crate::cli::{parse_and_eval, register_plugins, run_script_file};
pub use crate::env::environment_syncer::EnvironmentSyncer;
pub use crate::env::host::BasicHost;
pub use crate::evaluation_context::EvaluationContext;
pub use crate::prelude::ToOutputStream;
pub use crate::stream::{InputStream, InterruptibleStream, OutputStream};
pub use nu_command::commands::default_context::create_default_context;
pub use nu_data::config;
pub use nu_data::dict::TaggedListBuilder;
pub use nu_data::primitive;
pub use nu_data::value;
pub use nu_stream::{InputStream, InterruptibleStream, OutputStream};
pub use nu_value_ext::ValueExt;
pub use num_traits::cast::ToPrimitive;

View File

@ -0,0 +1,234 @@
use nu_engine::EvaluationContext;
use std::error::Error;
#[allow(unused_imports)]
use crate::prelude::*;
#[allow(unused_imports)]
use nu_command::script::LineResult;
#[cfg(feature = "rustyline-support")]
use crate::shell::Helper;
#[cfg(feature = "rustyline-support")]
use rustyline::{
self,
config::Configurer,
config::{ColorMode, CompletionType, Config},
error::ReadlineError,
At, Cmd, Editor, KeyPress, Movement, Word,
};
#[cfg(feature = "rustyline-support")]
pub fn convert_rustyline_result_to_string(input: Result<String, ReadlineError>) -> LineResult {
match input {
Ok(s) if s == "history -c" || s == "history --clear" => LineResult::ClearHistory,
Ok(s) => LineResult::Success(s),
Err(ReadlineError::Interrupted) => LineResult::CtrlC,
Err(ReadlineError::Eof) => LineResult::CtrlD,
Err(err) => {
outln!("Error: {:?}", err);
LineResult::Break
}
}
}
#[cfg(feature = "rustyline-support")]
pub fn default_rustyline_editor_configuration() -> Editor<Helper> {
#[cfg(windows)]
const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::Circular;
#[cfg(not(windows))]
const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::List;
let config = Config::builder().color_mode(ColorMode::Forced).build();
let mut rl: Editor<_> = Editor::with_config(config);
// add key bindings to move over a whole word with Ctrl+ArrowLeft and Ctrl+ArrowRight
rl.bind_sequence(
KeyPress::ControlLeft,
Cmd::Move(Movement::BackwardWord(1, Word::Vi)),
);
rl.bind_sequence(
KeyPress::ControlRight,
Cmd::Move(Movement::ForwardWord(1, At::AfterEnd, Word::Vi)),
);
// workaround for multiline-paste hang in rustyline (see https://github.com/kkawakam/rustyline/issues/202)
rl.bind_sequence(KeyPress::BracketedPasteStart, rustyline::Cmd::Noop);
// Let's set the defaults up front and then override them later if the user indicates
// defaults taken from here https://github.com/kkawakam/rustyline/blob/2fe886c9576c1ea13ca0e5808053ad491a6fe049/src/config.rs#L150-L167
rl.set_max_history_size(100);
rl.set_history_ignore_dups(true);
rl.set_history_ignore_space(false);
rl.set_completion_type(DEFAULT_COMPLETION_MODE);
rl.set_completion_prompt_limit(100);
rl.set_keyseq_timeout(-1);
rl.set_edit_mode(rustyline::config::EditMode::Emacs);
rl.set_auto_add_history(false);
rl.set_bell_style(rustyline::config::BellStyle::default());
rl.set_color_mode(rustyline::ColorMode::Enabled);
rl.set_tab_stop(8);
if let Err(e) = crate::keybinding::load_keybindings(&mut rl) {
println!("Error loading keybindings: {:?}", e);
}
rl
}
#[cfg(feature = "rustyline-support")]
pub fn configure_rustyline_editor(
rl: &mut Editor<Helper>,
config: &dyn nu_data::config::Conf,
) -> Result<(), ShellError> {
#[cfg(windows)]
const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::Circular;
#[cfg(not(windows))]
const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::List;
if let Some(line_editor_vars) = config.var("line_editor") {
for (idx, value) in line_editor_vars.row_entries() {
match idx.as_ref() {
"max_history_size" => {
if let Ok(max_history_size) = value.as_u64() {
rl.set_max_history_size(max_history_size as usize);
}
}
"history_duplicates" => {
// history_duplicates = match value.as_string() {
// Ok(s) if s.to_lowercase() == "alwaysadd" => {
// rustyline::config::HistoryDuplicates::AlwaysAdd
// }
// Ok(s) if s.to_lowercase() == "ignoreconsecutive" => {
// rustyline::config::HistoryDuplicates::IgnoreConsecutive
// }
// _ => rustyline::config::HistoryDuplicates::AlwaysAdd,
// };
if let Ok(history_duplicates) = value.as_bool() {
rl.set_history_ignore_dups(history_duplicates);
}
}
"history_ignore_space" => {
if let Ok(history_ignore_space) = value.as_bool() {
rl.set_history_ignore_space(history_ignore_space);
}
}
"completion_type" => {
let completion_type = match value.as_string() {
Ok(s) if s.to_lowercase() == "circular" => {
rustyline::config::CompletionType::Circular
}
Ok(s) if s.to_lowercase() == "list" => {
rustyline::config::CompletionType::List
}
#[cfg(all(unix, feature = "with-fuzzy"))]
Ok(s) if s.to_lowercase() == "fuzzy" => {
rustyline::config::CompletionType::Fuzzy
}
_ => DEFAULT_COMPLETION_MODE,
};
rl.set_completion_type(completion_type);
}
"completion_prompt_limit" => {
if let Ok(completion_prompt_limit) = value.as_u64() {
rl.set_completion_prompt_limit(completion_prompt_limit as usize);
}
}
"keyseq_timeout_ms" => {
if let Ok(keyseq_timeout_ms) = value.as_u64() {
rl.set_keyseq_timeout(keyseq_timeout_ms as i32);
}
}
"edit_mode" => {
let edit_mode = match value.as_string() {
Ok(s) if s.to_lowercase() == "vi" => rustyline::config::EditMode::Vi,
Ok(s) if s.to_lowercase() == "emacs" => rustyline::config::EditMode::Emacs,
_ => rustyline::config::EditMode::Emacs,
};
rl.set_edit_mode(edit_mode);
// Note: When edit_mode is Emacs, the keyseq_timeout_ms is set to -1
// no matter what you may have configured. This is so that key chords
// can be applied without having to do them in a given timeout. So,
// it essentially turns off the keyseq timeout.
}
"auto_add_history" => {
if let Ok(auto_add_history) = value.as_bool() {
rl.set_auto_add_history(auto_add_history);
}
}
"bell_style" => {
let bell_style = match value.as_string() {
Ok(s) if s.to_lowercase() == "audible" => {
rustyline::config::BellStyle::Audible
}
Ok(s) if s.to_lowercase() == "none" => rustyline::config::BellStyle::None,
Ok(s) if s.to_lowercase() == "visible" => {
rustyline::config::BellStyle::Visible
}
_ => rustyline::config::BellStyle::default(),
};
rl.set_bell_style(bell_style);
}
"color_mode" => {
let color_mode = match value.as_string() {
Ok(s) if s.to_lowercase() == "enabled" => rustyline::ColorMode::Enabled,
Ok(s) if s.to_lowercase() == "forced" => rustyline::ColorMode::Forced,
Ok(s) if s.to_lowercase() == "disabled" => rustyline::ColorMode::Disabled,
_ => rustyline::ColorMode::Enabled,
};
rl.set_color_mode(color_mode);
}
"tab_stop" => {
if let Ok(tab_stop) = value.as_u64() {
rl.set_tab_stop(tab_stop as usize);
}
}
_ => (),
}
}
}
Ok(())
}
#[cfg(feature = "rustyline-support")]
pub fn nu_line_editor_helper(
context: &mut EvaluationContext,
config: &dyn nu_data::config::Conf,
) -> crate::shell::Helper {
let hinter = rustyline_hinter(config);
crate::shell::Helper::new(context.clone(), hinter)
}
#[cfg(feature = "rustyline-support")]
pub fn rustyline_hinter(
config: &dyn nu_data::config::Conf,
) -> Option<rustyline::hint::HistoryHinter> {
if let Some(line_editor_vars) = config.var("line_editor") {
for (idx, value) in line_editor_vars.row_entries() {
if idx == "show_hints" && value.expect_string() == "false" {
return None;
}
}
}
Some(rustyline::hint::HistoryHinter {})
}
pub fn configure_ctrl_c(_context: &mut EvaluationContext) -> Result<(), Box<dyn Error>> {
#[cfg(feature = "ctrlc")]
{
let cc = _context.ctrl_c.clone();
ctrlc::set_handler(move || {
cc.store(true, Ordering::SeqCst);
})?;
if _context.ctrl_c.load(Ordering::SeqCst) {
_context.ctrl_c.store(false, Ordering::SeqCst);
}
}
Ok(())
}

View File

@ -21,28 +21,6 @@ macro_rules! stream {
}}
}
#[macro_export]
macro_rules! trace_stream {
(target: $target:tt, $desc:tt = $expr:expr) => {{
if log::log_enabled!(target: $target, log::Level::Trace) {
use futures::stream::StreamExt;
let objects = $expr.inspect(move |o| {
trace!(
target: $target,
"{} = {}",
$desc,
nu_source::PrettyDebug::plain_string(o, 70)
);
});
$crate::stream::InputStream::from_stream(objects.boxed())
} else {
$expr
}
}};
}
#[macro_export]
macro_rules! trace_out_stream {
(target: $target:tt, $desc:tt = $expr:expr) => {{
@ -61,48 +39,24 @@ macro_rules! trace_out_stream {
);
});
$crate::stream::OutputStream::new(objects)
nu_stream::OutputStream::new(objects)
} else {
$expr
}
}};
}
pub(crate) use nu_protocol::{errln, out, outln, row};
use nu_source::HasFallibleSpan;
pub(crate) use crate::command_registry::CommandRegistry;
pub(crate) use crate::commands::command::{CommandArgs, RawCommandArgs, RunnableContext};
pub(crate) use crate::commands::Example;
pub(crate) use crate::evaluation_context::EvaluationContext;
pub(crate) use nu_data::config;
pub(crate) use nu_data::value;
// pub(crate) use crate::env::host::handle_unexpected;
pub(crate) use crate::env::Host;
pub(crate) use crate::shell::filesystem_shell::FilesystemShell;
pub(crate) use crate::shell::help_shell::HelpShell;
pub(crate) use crate::shell::shell_manager::ShellManager;
pub(crate) use crate::shell::value_shell::ValueShell;
pub(crate) use crate::stream::{InputStream, InterruptibleStream, OutputStream};
pub(crate) use bigdecimal::BigDecimal;
pub(crate) use futures::stream::BoxStream;
pub(crate) use futures::{Stream, StreamExt};
pub(crate) use nu_source::{
b, AnchorLocation, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource, Span, SpannedItem, Tag,
TaggedItem, Text,
};
pub(crate) use nu_engine::Host;
#[allow(unused_imports)]
pub(crate) use nu_errors::ShellError;
#[allow(unused_imports)]
pub(crate) use nu_protocol::outln;
pub(crate) use nu_stream::OutputStream;
#[allow(unused_imports)]
pub(crate) use nu_value_ext::ValueExt;
pub(crate) use num_bigint::BigInt;
pub(crate) use num_traits::cast::ToPrimitive;
pub(crate) use serde::Deserialize;
pub(crate) use std::collections::VecDeque;
pub(crate) use std::future::Future;
pub(crate) use std::sync::atomic::AtomicBool;
pub(crate) use std::sync::Arc;
pub(crate) use async_trait::async_trait;
pub(crate) use indexmap::IndexMap;
pub(crate) use itertools::Itertools;
#[allow(unused_imports)]
pub(crate) use std::sync::atomic::Ordering;
pub trait FromInputStream {
fn from_input_stream(self) -> OutputStream;
@ -119,26 +73,6 @@ where
}
}
pub trait ToInputStream {
fn to_input_stream(self) -> InputStream;
}
impl<T, U> ToInputStream for T
where
T: Stream<Item = U> + Send + 'static,
U: Into<Result<nu_protocol::Value, nu_errors::ShellError>>,
{
fn to_input_stream(self) -> InputStream {
InputStream::from_stream(self.map(|item| match item.into() {
Ok(result) => result,
Err(err) => match HasFallibleSpan::maybe_span(&err) {
Some(span) => nu_protocol::UntaggedValue::Error(err).into_value(span),
None => nu_protocol::UntaggedValue::Error(err).into_untagged_value(),
},
}))
}
}
pub trait ToOutputStream {
fn to_output_stream(self) -> OutputStream;
}
@ -154,16 +88,3 @@ where
}
}
}
pub trait Interruptible<V> {
fn interruptible(self, ctrl_c: Arc<AtomicBool>) -> InterruptibleStream<V>;
}
impl<S, V> Interruptible<V> for S
where
S: Stream<Item = V> + Send + 'static,
{
fn interruptible(self, ctrl_c: Arc<AtomicBool>) -> InterruptibleStream<V> {
InterruptibleStream::new(self, ctrl_c)
}
}

View File

@ -2,15 +2,8 @@
#[cfg(feature = "rustyline-support")]
pub(crate) mod completer;
pub(crate) mod filesystem_shell;
pub(crate) mod help_shell;
#[cfg(feature = "rustyline-support")]
pub(crate) mod helper;
pub(crate) mod painter;
pub(crate) mod palette;
pub(crate) mod shell;
pub(crate) mod shell_manager;
pub(crate) mod value_shell;
#[cfg(feature = "rustyline-support")]
pub(crate) use helper::Helper;

View File

@ -4,7 +4,8 @@ use crate::completion::matchers;
use crate::completion::matchers::Matcher;
use crate::completion::path::{PathCompleter, PathSuggestion};
use crate::completion::{self, Completer, Suggestion};
use crate::evaluation_context::EvaluationContext;
use nu_engine::EvaluationContext;
use nu_parser::ParserScope;
use nu_source::Tag;
use std::borrow::Cow;
@ -23,10 +24,12 @@ impl NuCompleter {
use completion::engine::LocationType;
let nu_context: &EvaluationContext = context.as_ref();
let (lite_block, _) = nu_parser::lite_parse(line, 0);
let classified_block = nu_parser::classify_block(&lite_block, &nu_context.registry);
let locations = completion::engine::completion_location(line, &classified_block.block, pos);
nu_context.scope.enter_scope();
let (block, _) = nu_parser::parse(line, 0, &nu_context.scope);
nu_context.scope.exit_scope();
let locations = completion::engine::completion_location(line, &block, pos);
let matcher = nu_data::config::config(Tag::unknown())
.ok()

View File

@ -1,13 +1,8 @@
use std::borrow::Cow::{self, Owned};
use nu_parser::SignatureRegistry;
use nu_source::{Tag, Tagged};
use crate::completion;
use crate::evaluation_context::EvaluationContext;
use crate::shell::completer::NuCompleter;
use crate::shell::painter::Painter;
use crate::shell::palette::DefaultPalette;
use nu_engine::{DefaultPalette, EvaluationContext, Painter};
use nu_source::{Tag, Tagged};
use std::borrow::Cow::{self, Owned};
pub struct Helper {
completer: NuCompleter,
@ -87,11 +82,7 @@ impl rustyline::highlight::Highlighter for Helper {
}
fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> {
Painter::paint_string(
line,
&self.context.registry().clone_box(),
&DefaultPalette {},
)
Painter::paint_string(line, &self.context.scope, &DefaultPalette {})
}
fn highlight_char(&self, _line: &str, _pos: usize) -> bool {
@ -121,7 +112,14 @@ impl rustyline::validate::Validator for NuValidator {
) -> rustyline::Result<rustyline::validate::ValidationResult> {
let src = ctx.input();
let (_, err) = nu_parser::lite_parse(src, 0);
let (tokens, err) = nu_parser::lex(src, 0);
if let Some(err) = err {
if let nu_errors::ParseErrorReason::Eof { .. } = err.reason() {
return Ok(rustyline::validate::ValidationResult::Incomplete);
}
}
let (_, err) = nu_parser::block(tokens);
if let Some(err) = err {
if let nu_errors::ParseErrorReason::Eof { .. } = err.reason() {
@ -146,3 +144,51 @@ fn vec_tag<T>(input: Vec<Tagged<T>>) -> Option<Tag> {
}
impl rustyline::Helper for Helper {}
#[cfg(test)]
mod tests {
use super::*;
use nu_engine::basic_evaluation_context;
use rustyline::completion::Completer;
use rustyline::line_buffer::LineBuffer;
#[ignore]
#[test]
fn closing_quote_should_replaced() {
let text = "cd \"folder with spaces\\subdirectory\\\"";
let replacement = "\"folder with spaces\\subdirectory\\subsubdirectory\\\"";
let mut buffer = LineBuffer::with_capacity(256);
buffer.insert_str(0, text);
buffer.set_pos(text.len() - 1);
let helper = Helper::new(basic_evaluation_context().unwrap(), None);
helper.update(&mut buffer, "cd ".len(), &replacement);
assert_eq!(
buffer.as_str(),
"cd \"folder with spaces\\subdirectory\\subsubdirectory\\\""
);
}
#[ignore]
#[test]
fn replacement_with_cursor_in_text() {
let text = "cd \"folder with spaces\\subdirectory\\\"";
let replacement = "\"folder with spaces\\subdirectory\\subsubdirectory\\\"";
let mut buffer = LineBuffer::with_capacity(256);
buffer.insert_str(0, text);
buffer.set_pos(text.len() - 30);
let helper = Helper::new(basic_evaluation_context().unwrap(), None);
helper.update(&mut buffer, "cd ".len(), &replacement);
assert_eq!(
buffer.as_str(),
"cd \"folder with spaces\\subdirectory\\subsubdirectory\\\""
);
}
}

View File

@ -1,12 +1,14 @@
use crate::CommandRegistry;
#![allow(dead_code)]
use itertools::{merge_join_by, EitherOrBoth, Itertools};
use lazy_static::lazy_static;
use log::trace;
use nu_engine::Scope;
use nu_errors::ShellError;
use nu_parser::SignatureRegistry;
use nu_parser::ParserScope;
use nu_protocol::{
hir::{
Binary, Block, ClassifiedCommand, Commands, Expression, Literal, NamedArguments,
NamedValue, Operator, SpannedExpression,
Binary, Block, ClassifiedCommand, Expression, Literal, NamedArguments, NamedValue,
Operator, Pipeline, SpannedExpression,
},
NamedType, PositionalType, Signature, SyntaxShape,
};
@ -14,9 +16,6 @@ use nu_source::Span;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, hash::Hash};
use itertools::{merge_join_by, EitherOrBoth, Itertools};
use log::trace;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VarDeclaration {
pub name: String,
@ -290,13 +289,13 @@ fn get_shape_of_expr(expr: &SpannedExpression) -> Option<SyntaxShape> {
Expression::ExternalWord => Some(SyntaxShape::String),
Expression::Synthetic(_) => Some(SyntaxShape::String),
Expression::Binary(_) => Some(SyntaxShape::Math),
Expression::Binary(_) => Some(SyntaxShape::RowCondition),
Expression::Range(_) => Some(SyntaxShape::Range),
Expression::List(_) => Some(SyntaxShape::Table),
Expression::Boolean(_) => Some(SyntaxShape::String),
Expression::Path(_) => Some(SyntaxShape::ColumnPath),
Expression::FilePath(_) => Some(SyntaxShape::Path),
Expression::FilePath(_) => Some(SyntaxShape::FilePath),
Expression::Block(_) => Some(SyntaxShape::Block),
Expression::ExternalCommand(_) => Some(SyntaxShape::String),
Expression::Table(_, _) => Some(SyntaxShape::Table),
@ -318,14 +317,14 @@ fn spanned_to_binary(bin_spanned: &SpannedExpression) -> &Binary {
///Returns result shape of this math expr otherwise
fn get_result_shape_of_math_expr(
bin: &Binary,
(pipeline_idx, pipeline): (usize, &Commands),
registry: &CommandRegistry,
(pipeline_idx, pipeline): (usize, &Pipeline),
scope: &Scope,
) -> Result<Option<SyntaxShape>, ShellError> {
let mut shapes: Vec<Option<SyntaxShape>> = vec![];
for expr in &[&bin.left, &bin.right] {
let shape = match &expr.expr {
Expression::Binary(deep_binary) => {
get_result_shape_of_math_expr(&deep_binary, (pipeline_idx, pipeline), registry)?
get_result_shape_of_math_expr(&deep_binary, (pipeline_idx, pipeline), scope)?
}
_ => get_shape_of_expr(expr),
};
@ -356,7 +355,7 @@ impl VarSyntaxShapeDeductor {
pub fn infer_vars(
vars_to_find: &[VarDeclaration],
block: &Block,
registry: &CommandRegistry,
scope: &Scope,
) -> Result<Vec<(VarDeclaration, Option<Deduction>)>, ShellError> {
trace!("Deducing shapes for vars: {:?}", vars_to_find);
@ -367,7 +366,7 @@ impl VarSyntaxShapeDeductor {
dependencies: Vec::new(),
dependencies_on_result_type: Vec::new(),
};
deducer.infer_shape(block, registry)?;
deducer.infer_shape(block, scope)?;
deducer.solve_dependencies();
trace!("Found shapes for vars: {:?}", deducer.inferences);
@ -386,24 +385,22 @@ impl VarSyntaxShapeDeductor {
.collect())
}
fn infer_shape(&mut self, block: &Block, registry: &CommandRegistry) -> Result<(), ShellError> {
fn infer_shape(&mut self, block: &Block, scope: &Scope) -> Result<(), ShellError> {
trace!("Infering vars in shape");
for pipeline in &block.block {
self.infer_pipeline(pipeline, registry)?;
for group in &block.block {
for pipeline in &group.pipelines {
self.infer_pipeline(pipeline, scope)?;
}
}
Ok(())
}
pub fn infer_pipeline(
&mut self,
pipeline: &Commands,
registry: &CommandRegistry,
) -> Result<(), ShellError> {
pub fn infer_pipeline(&mut self, pipeline: &Pipeline, scope: &Scope) -> Result<(), ShellError> {
trace!("Infering vars in pipeline");
for (cmd_pipeline_idx, classified) in pipeline.list.iter().enumerate() {
match &classified {
ClassifiedCommand::Internal(internal) => {
if let Some(signature) = registry.get(&internal.name) {
if let Some(signature) = scope.get_signature(&internal.name) {
//When the signature is given vars directly used as named or positional
//arguments can be deduced
//e.G. cp $var1 $var2
@ -426,7 +423,7 @@ impl VarSyntaxShapeDeductor {
self.infer_shapes_in_expr(
(cmd_pipeline_idx, pipeline),
pos_expr,
registry,
scope,
)?;
}
}
@ -437,7 +434,7 @@ impl VarSyntaxShapeDeductor {
self.infer_shapes_in_expr(
(cmd_pipeline_idx, pipeline),
named_expr,
registry,
scope,
)?;
}
}
@ -448,11 +445,7 @@ impl VarSyntaxShapeDeductor {
"Infering shapes in ClassifiedCommand::Expr: {:?}",
spanned_expr
);
self.infer_shapes_in_expr(
(cmd_pipeline_idx, pipeline),
spanned_expr,
registry,
)?;
self.infer_shapes_in_expr((cmd_pipeline_idx, pipeline), spanned_expr, scope)?;
}
ClassifiedCommand::Dynamic(_) | ClassifiedCommand::Error(_) => unimplemented!(),
}
@ -534,25 +527,25 @@ impl VarSyntaxShapeDeductor {
fn infer_shapes_in_expr(
&mut self,
(pipeline_idx, pipeline): (usize, &Commands),
(pipeline_idx, pipeline): (usize, &Pipeline),
spanned_expr: &SpannedExpression,
registry: &CommandRegistry,
scope: &Scope,
) -> Result<(), ShellError> {
match &spanned_expr.expr {
Expression::Binary(_) => {
trace!("Infering vars in bin expr");
self.infer_shapes_in_binary_expr((pipeline_idx, pipeline), spanned_expr, registry)?;
self.infer_shapes_in_binary_expr((pipeline_idx, pipeline), spanned_expr, scope)?;
}
Expression::Block(b) => {
trace!("Infering vars in block");
self.infer_shape(&b, registry)?;
self.infer_shape(&b, scope)?;
}
Expression::Path(path) => {
trace!("Infering vars in path");
match &path.head.expr {
//PathMember can't be var yet (?)
//TODO Iterate over path parts and find var when implemented
Expression::Invocation(b) => self.infer_shape(&b, registry)?,
Expression::Invocation(b) => self.infer_shape(&b, scope)?,
Expression::Variable(var_name, span) => {
self.checked_insert(
&VarUsage::new(var_name, span),
@ -593,12 +586,12 @@ impl VarSyntaxShapeDeductor {
Expression::List(inner_exprs) => {
trace!("Infering vars in list");
for expr in inner_exprs {
self.infer_shapes_in_expr((pipeline_idx, pipeline), expr, registry)?;
self.infer_shapes_in_expr((pipeline_idx, pipeline), expr, scope)?;
}
}
Expression::Invocation(invoc) => {
trace!("Infering vars in invocation: {:?}", invoc);
self.infer_shape(invoc, registry)?;
self.infer_shape(invoc, scope)?;
}
Expression::Table(header, _rows) => {
self.infer_shapes_in_table_header(header)?;
@ -660,11 +653,11 @@ impl VarSyntaxShapeDeductor {
(var, expr): (&VarUsage, &SpannedExpression),
//source_bin is binary having var on one and expr on other side
source_bin: &SpannedExpression,
(pipeline_idx, pipeline): (usize, &Commands),
registry: &CommandRegistry,
(pipeline_idx, pipeline): (usize, &Pipeline),
scope: &Scope,
) -> Result<Option<SyntaxShape>, ShellError> {
get_result_shape_of_math_expr(spanned_to_binary(expr), (pipeline_idx, pipeline), registry)
.map(|shape| {
get_result_shape_of_math_expr(spanned_to_binary(expr), (pipeline_idx, pipeline), scope).map(
|shape| {
if shape == None {
self.dependencies_on_result_type.push((
var.clone(),
@ -673,7 +666,8 @@ impl VarSyntaxShapeDeductor {
));
}
shape
})
},
)
}
fn get_shape_of_binary_arg_or_insert_dependency(
@ -682,8 +676,8 @@ impl VarSyntaxShapeDeductor {
(var, expr): (&VarUsage, &SpannedExpression),
//source_bin is binary having var on one and expr on other side
source_bin: &SpannedExpression,
(pipeline_idx, pipeline): (usize, &Commands),
registry: &CommandRegistry,
(pipeline_idx, pipeline): (usize, &Pipeline),
scope: &Scope,
) -> Result<Option<SyntaxShape>, ShellError> {
trace!("Getting shape of binary arg {:?} for var {:?}", expr, var);
if let Some(shape) = self.get_shape_of_expr_or_insert_dependency(
@ -695,11 +689,12 @@ impl VarSyntaxShapeDeductor {
match shape {
//If the shape of expr is math, we return the result shape of this math expr if
//possible
SyntaxShape::Math => self.get_result_shape_of_math_expr_or_insert_dependency(
SyntaxShape::RowCondition => self
.get_result_shape_of_math_expr_or_insert_dependency(
(var, expr),
source_bin,
(pipeline_idx, pipeline),
registry,
scope,
),
_ => Ok(Some(shape)),
}
@ -714,8 +709,7 @@ impl VarSyntaxShapeDeductor {
var: &VarUsage,
bin_spanned: &SpannedExpression,
list: &[SpannedExpression],
(_pipeline_idx, _pipeline): (usize, &Commands),
_registry: &CommandRegistry,
(_pipeline_idx, _pipeline): (usize, &Pipeline),
) -> Option<Vec<SyntaxShape>> {
let shapes_in_list = list
.iter()
@ -740,8 +734,8 @@ impl VarSyntaxShapeDeductor {
var_side: BinarySide,
//Binary having expr on one side and var on other
bin_spanned: &SpannedExpression,
(pipeline_idx, pipeline): (usize, &Commands),
registry: &CommandRegistry,
(pipeline_idx, pipeline): (usize, &Pipeline),
scope: &Scope,
) -> Result<(), ShellError> {
trace!("Infering shapes between var {:?} and expr {:?}", var, expr);
let bin = spanned_to_binary(bin_spanned);
@ -765,18 +759,15 @@ impl VarSyntaxShapeDeductor {
)],
)?;
}
Operator::In | Operator::NotIn => {
match var_side {
Operator::In | Operator::NotIn => match var_side {
BinarySide::Left => match &expr.expr {
Expression::List(list) => {
if !list.is_empty() {
let shapes_in_list = self
.get_shapes_in_list_or_insert_dependency(
let shapes_in_list = self.get_shapes_in_list_or_insert_dependency(
var,
bin_spanned,
&list,
(pipeline_idx, pipeline),
registry,
);
match shapes_in_list {
None => {}
@ -806,7 +797,9 @@ impl VarSyntaxShapeDeductor {
| Expression::Command
| Expression::Invocation(_)
| Expression::Boolean(_)
| Expression::Garbage => {unreachable!("Parser should have rejected code. In only applicable with rhs of type List")}
| Expression::Garbage => {
unreachable!("Parser should have rejected code. In only applicable with rhs of type List")
}
},
BinarySide::Right => {
self.checked_insert(
@ -817,8 +810,7 @@ impl VarSyntaxShapeDeductor {
),
)?;
}
}
}
},
Operator::Modulo => {
self.checked_insert(
var,
@ -840,7 +832,7 @@ impl VarSyntaxShapeDeductor {
(var, expr),
bin_spanned,
(pipeline_idx, pipeline),
registry,
scope,
)? {
match shape {
SyntaxShape::Int | SyntaxShape::Number => {
@ -873,7 +865,7 @@ impl VarSyntaxShapeDeductor {
(var, expr),
bin_spanned,
(pipeline_idx, pipeline),
registry,
scope,
)? {
self.checked_insert(
var,
@ -893,9 +885,9 @@ impl VarSyntaxShapeDeductor {
fn infer_shapes_in_binary_expr(
&mut self,
(pipeline_idx, pipeline): (usize, &Commands),
(pipeline_idx, pipeline): (usize, &Pipeline),
bin_spanned: &SpannedExpression,
registry: &CommandRegistry,
scope: &Scope,
) -> Result<(), ShellError> {
let bin = spanned_to_binary(bin_spanned);
if let Expression::Variable(left_var_name, l_span) = &bin.left.expr {
@ -904,7 +896,7 @@ impl VarSyntaxShapeDeductor {
BinarySide::Left,
bin_spanned,
(pipeline_idx, pipeline),
registry,
scope,
)?;
}
@ -914,13 +906,13 @@ impl VarSyntaxShapeDeductor {
BinarySide::Right,
bin_spanned,
(pipeline_idx, pipeline),
registry,
scope,
)?;
}
//Descend deeper into bin tree
self.infer_shapes_in_expr((pipeline_idx, pipeline), &bin.right, registry)?;
self.infer_shapes_in_expr((pipeline_idx, pipeline), &bin.right, scope)?;
//Descend deeper into bin tree
self.infer_shapes_in_expr((pipeline_idx, pipeline), &bin.left, registry)?;
self.infer_shapes_in_expr((pipeline_idx, pipeline), &bin.left, scope)?;
Ok(())
}

View File

@ -1,299 +0,0 @@
#[cfg(test)]
mod tests {
use nu_test_support::nu;
use nu_test_support::playground::Playground;
#[test]
fn alias_without_args() {
let actual = nu!(
cwd: ".",
r#"
alias -i e [] {^echo hi nushell | to json}
e
"#
);
#[cfg(not(windows))]
assert_eq!(actual.out, "\"hi nushell\\n\"");
#[cfg(windows)]
assert_eq!(actual.out, "\"hi nushell\\r\\n\"");
}
#[test]
fn alias_args_work() {
Playground::setup("append_test_2", |dirs, _| {
let actual = nu!(
cwd: dirs.root(),
r#"
alias -i double_echo [b] {echo $b | to json}
double_echo 1kb
"#
);
assert_eq!(actual.out, "1024");
})
}
#[test]
fn alias_args_double_echo() {
Playground::setup("append_test_1", |dirs, _| {
let actual = nu!(
cwd: dirs.root(),
r#"
alias -i double_echo [a b] {echo $a $b}
double_echo 1 2 | to json
"#
);
assert_eq!(actual.out, "[1,2]");
})
}
#[test]
#[cfg(not(windows))]
fn alias_parses_path_tilde() {
let actual = nu!(
cwd: "tests/fixtures/formats",
r#"
alias -i new-cd [dir] { cd $dir }
new-cd ~
pwd
"#
);
//If this fails for you, check for any special unicode characters in your ~ path
assert!(actual.out.chars().filter(|c| *c == '/').count() == 2);
#[cfg(target_os = "linux")]
assert!(actual.out.contains("home"));
#[cfg(target_os = "macos")]
assert!(actual.out.contains("Users"));
}
#[test]
fn alias_missing_args_work() {
Playground::setup("append_test_1", |dirs, _| {
let actual = nu!(
cwd: dirs.root(),
r#"
alias double_echo [a b] {^echo $a $b}
double_echo bob
"#
);
assert_eq!(actual.out, "bob");
})
}
#[test]
#[ignore]
fn alias_with_in_str_var_right() {
//Failing
let actual = nu!(
cwd: ".",
r#"
alias -i lw [newbie] {echo 1 2 3 | where "hello_world" in $newbie | to json}
lw [hello_world_test_repo]
"#
);
assert_eq!(actual.out, "[1,2,3]");
}
#[test]
fn alias_with_in_str_var_right_mismatch() {
let actual = nu!(
cwd: ".",
r#"
alias -i lw [rust_newbie] { echo 1 2 3 | where "hello_world" in $rust_newbie | to json }
lw [ big_brain_programmer ]
"#
);
assert_eq!(actual.out, "");
}
#[test]
fn alias_with_in_err() {
//in operator only applicable for strings atm
let actual = nu!(
cwd: ".",
r#"
alias -i lw [p] {echo 1 2 3 | where $p in [1 3 2] | to json}
lw /root/sys
"#
);
assert!(actual.err.contains("Type"));
}
#[test]
#[ignore]
fn alias_with_contains() {
//Failing
let actual = nu!(
cwd: ".",
r#"
alias -i lw [p] {echo 1 2 3 | where $p in [1 hi 3] | to json}
lw 1
"#
);
assert_eq!(actual.out, "[1,2,3]");
}
#[test]
#[ignore]
fn alias_with_contains_and_var_is_right_side() {
//Failing
let actual = nu!(
cwd: ".",
r#"
alias -i lw [p] {echo 1 2 3 | where 1 in $p | to json}
lw [1 2 hi]
"#
);
assert_eq!(actual.out, "[1,2,3]");
}
#[test]
fn error_alias_wrong_shape_shallow() {
let actual = nu!(
cwd: ".",
r#"
alias -i round-to [num digits] { echo $num | str from -d $digits }
round-to 3.45 a
"#
);
assert!(actual.err.contains("Type"));
}
#[test]
fn error_alias_wrong_shape_deep_invocation() {
let actual = nu!(
cwd: ".",
r#"
alias -i round-to [nums digits] { echo $nums | each {= $(str from -d $digits)}}
round-to 3.45 a
"#
);
assert!(actual.err.contains("Type"));
}
#[test]
fn error_alias_wrong_shape_deep_binary() {
let actual = nu!(
cwd: ".",
r#"
alias -i round-plus-one [nums digits] { echo $nums | each {= $(str from -d $digits | str to-decimal) + 1}}
round-plus-one 3.45 a
"#
);
assert!(actual.err.contains("Type"));
}
#[test]
fn error_alias_wrong_shape_deeper_binary() {
let actual = nu!(
cwd: ".",
r#"
alias -i round-one-more [num digits] { echo $num | str from -d $(= $digits + 1) }
round-one-more 3.45 a
"#
);
assert!(actual.err.contains("Type"));
}
#[test]
fn error_alias_syntax_shape_clash() {
let actual = nu!(
cwd: ".",
r#"
alias -i clash [a] { echo 1.1 2 3 | each { str from -d $a } | range $a }
"#
);
assert!(actual.err.contains("Contrary types for variable $a"));
}
#[test]
#[ignore]
fn alias_with_math_var() {
//Failing
let actual = nu!(
cwd: ".",
r#"
alias -i echo_math [math] { echo {= 1 + $math}}
echo_math 1 + 1 | to json
"#
);
assert_eq!(actual.out, "3");
}
#[test]
#[ignore]
fn alias_with_math_var2() {
//Failing
let actual = nu!(
cwd: ".",
r#"
alias -i round-plus-one [nums digits math] { echo $nums | each {= $(str from -d $digits | str to-decimal) + $math}}
round-plus-one 3.45 2 1 + 1 | to json
"#
);
assert_eq!(actual.out, "5.45");
}
#[test]
fn alias_with_true_and_false() {
//https://github.com/nushell/nushell/issues/2416
let actual = nu!(
cwd: ".",
r#"
alias -i is_empty [a] {if $(echo $a | empty?) == $true { echo $true } { echo $false }}
is_empty ""
"#
);
assert!(actual.out.contains("true"));
}
#[test]
fn alias_sent_env() {
//https://github.com/nushell/nushell/issues/1835
let actual = nu!(
cwd: ".",
r#"
alias -i set-env [name value] { echo $nu.env | insert $name $value | get SHELL | to json }
set-env SHELL /bin/nu
"#
);
assert_eq!(actual.out, "\"/bin/nu\"");
}
#[test]
#[ignore]
fn alias_with_math_arg() {
//Failing
let actual = nu!(
cwd: ".",
r#"
alias -i lswh [math] { echo 1 2 3 | where $math | to json }
lswh $it > 2
"#
);
assert_eq!(actual.out, "3");
}
#[test]
#[cfg(not(windows))]
fn alias_ls() {
//https://github.com/nushell/nushell/issues/1632
let actual = nu!(
cwd: ".",
r#"
touch /tmp/nushell_alias_test
alias -i l [x] { ls $x }
l /tmp | to json
"#
);
assert!(actual.out.contains("nushell_alias_test"));
}
}

View File

@ -1,13 +0,0 @@
use nu_test_support::{nu, pipeline};
#[test]
fn echo_range_is_lazy() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
echo 1..10000000000 | first 3 | to json
"#
));
assert_eq!(actual.out, "[1,2,3]");
}

View File

@ -0,0 +1,132 @@
[package]
authors = ["The Nu Project Contributors"]
build = "build.rs"
description = "CLI for nushell"
edition = "2018"
license = "MIT"
name = "nu-command"
version = "0.26.0"
[lib]
doctest = false
[dependencies]
nu-data = { version = "0.26.0", path = "../nu-data" }
nu-engine = { version = "0.26.0", path = "../nu-engine" }
nu-errors = { version = "0.26.0", path = "../nu-errors" }
nu-json = { version = "0.26.0", path = "../nu-json" }
nu-parser = { version = "0.26.0", path = "../nu-parser" }
nu-plugin = { version = "0.26.0", path = "../nu-plugin" }
nu-protocol = { version = "0.26.0", path = "../nu-protocol" }
nu-source = { version = "0.26.0", path = "../nu-source" }
nu-stream = { version = "0.26.0", path = "../nu-stream" }
nu-table = { version = "0.26.0", path = "../nu-table" }
nu-test-support = { version = "0.26.0", path = "../nu-test-support" }
nu-value-ext = { version = "0.26.0", path = "../nu-value-ext" }
Inflector = "0.11"
ansi_term = "0.12.1"
arboard = { version = "1.1.0", optional = true }
async-recursion = "0.3.1"
async-trait = "0.1.40"
base64 = "0.13.0"
bigdecimal = { version = "0.2.0", features = ["serde"] }
byte-unit = "4.0.9"
bytes = "0.5.6"
calamine = "0.16.1"
chrono = { version = "0.4.15", features = ["serde"] }
chrono-tz = "0.5.3"
clap = "2.33.3"
codespan-reporting = "0.11.0"
csv = "1.1.3"
ctrlc = { version = "3.1.6", optional = true }
derive-new = "0.5.8"
directories-next = { version = "2.0.0", optional = true }
dirs-next = { version = "2.0.0", optional = true }
dtparse = "1.2.0"
dunce = "1.0.1"
eml-parser = "0.1.0"
encoding_rs = "0.8.24"
filesize = "0.2.0"
fs_extra = "1.2.0"
futures = { version = "0.3.5", features = ["compat", "io-compat"] }
futures-util = "0.3.8"
futures_codec = "0.4.1"
getset = "0.1.1"
glob = "0.3.0"
htmlescape = "0.3.1"
ical = "0.7.0"
ichwh = { version = "0.3.4", optional = true }
indexmap = { version = "1.6.0", features = ["serde-1"] }
itertools = "0.10.0"
lazy_static = "1.*"
log = "0.4.11"
meval = "0.2.0"
num-bigint = { version = "0.3.0", features = ["serde"] }
num-format = { version = "0.4.0", features = ["with-num-bigint"] }
num-traits = "0.2.12"
parking_lot = "0.11.0"
pin-utils = "0.1.0"
pretty-hex = "0.2.0"
ptree = { version = "0.3.0", optional = true }
query_interface = "0.3.5"
quick-xml = "0.20.0"
rand = "0.7.3"
rayon = "1.4.0"
regex = "1.3.9"
roxmltree = "0.14.0"
rust-embed = "5.8.0"
rustyline = { version = "6.3.0", optional = true }
serde = { version = "1.0.115", features = ["derive"] }
serde_bytes = "0.11.5"
serde_ini = "0.2.0"
serde_json = "1.0.57"
serde_urlencoded = "0.7.0"
serde_yaml = "0.8.13"
sha2 = "0.9.1"
shellexpand = "2.0.0"
strip-ansi-escapes = "0.1.0"
sxd-document = "0.3.2"
sxd-xpath = "0.4.2"
tempfile = "3.1.0"
term = { version = "0.6.1", optional = true }
term_size = "0.3.2"
termcolor = "1.1.0"
titlecase = "1.0"
toml = "0.5.6"
trash = { version = "1.2.0", optional = true }
unicode-segmentation = "1.6.0"
url = "2.1.1"
uuid_crate = { package = "uuid", version = "0.8.1", features = ["v4"], optional = true }
which = { version = "4.0.2", optional = true }
zip = { version = "0.5.7", optional = true }
[target.'cfg(unix)'.dependencies]
umask = "1.0.0"
users = "0.10.0"
# TODO this will be possible with new dependency resolver
# (currently on nightly behind -Zfeatures=itarget):
# https://github.com/rust-lang/cargo/issues/7914
#[target.'cfg(not(windows))'.dependencies]
#num-format = {version = "0.4", features = ["with-system-locale"]}
[dependencies.rusqlite]
features = ["bundled", "blob"]
optional = true
version = "0.24.2"
[build-dependencies]
shadow-rs = "0.5"
[dev-dependencies]
quickcheck = "0.9.2"
quickcheck_macros = "0.9.1"
[features]
clipboard-cli = ["arboard"]
rustyline-support = ["rustyline"]
stable = []
trash-support = ["trash"]
directories = ["directories-next"]
dirs = ["dirs-next"]

Binary file not shown.

View File

@ -0,0 +1,3 @@
fn main() -> shadow_rs::SdResult<()> {
shadow_rs::new()
}

View File

@ -4,11 +4,10 @@ pub(crate) mod macros;
mod from_delimited_data;
mod to_delimited_data;
pub(crate) mod alias;
pub(crate) mod ansi;
pub(crate) mod append;
pub(crate) mod args;
pub(crate) mod autoenv;
pub mod autoenv;
pub(crate) mod autoenv_trust;
pub(crate) mod autoenv_untrust;
pub(crate) mod autoview;
@ -21,7 +20,7 @@ pub(crate) mod chart;
pub(crate) mod classified;
#[cfg(feature = "clipboard-cli")]
pub(crate) mod clip;
pub(crate) mod command;
pub mod command;
pub(crate) mod compact;
pub(crate) mod config;
pub(crate) mod constants;
@ -29,7 +28,9 @@ pub(crate) mod count;
pub(crate) mod cp;
pub(crate) mod date;
pub(crate) mod debug;
pub(crate) mod def;
pub(crate) mod default;
pub mod default_context;
pub(crate) mod describe;
pub(crate) mod do_;
pub(crate) mod drop;
@ -62,6 +63,7 @@ pub(crate) mod from_yaml;
pub(crate) mod get;
pub(crate) mod group_by;
pub(crate) mod group_by_date;
pub(crate) mod hash_;
pub(crate) mod headers;
pub(crate) mod help;
pub(crate) mod histogram;
@ -71,6 +73,8 @@ pub(crate) mod insert;
pub(crate) mod into_int;
pub(crate) mod keep;
pub(crate) mod last;
pub(crate) mod let_;
pub(crate) mod let_env;
pub(crate) mod lines;
pub(crate) mod ls;
pub(crate) mod math;
@ -94,7 +98,6 @@ pub(crate) mod reject;
pub(crate) mod rename;
pub(crate) mod reverse;
pub(crate) mod rm;
pub(crate) mod run_alias;
pub(crate) mod run_external;
pub(crate) mod save;
pub(crate) mod select;
@ -106,6 +109,7 @@ pub(crate) mod size;
pub(crate) mod skip;
pub(crate) mod sleep;
pub(crate) mod sort_by;
pub(crate) mod source;
pub(crate) mod split;
pub(crate) mod split_by;
pub(crate) mod str_;
@ -132,11 +136,7 @@ pub(crate) mod wrap;
pub(crate) use autoview::Autoview;
pub(crate) use cd::Cd;
pub(crate) use command::{
whole_stream_command, Command, Example, UnevaluatedCallInfo, WholeStreamCommand,
};
pub(crate) use alias::Alias;
pub(crate) use ansi::Ansi;
pub(crate) use append::Command as Append;
pub(crate) use autoenv::Autoenv;
@ -153,8 +153,9 @@ pub(crate) use config::{
};
pub(crate) use count::Count;
pub(crate) use cp::Cpy;
pub(crate) use date::{Date, DateFormat, DateNow, DateUTC};
pub(crate) use date::{Date, DateFormat, DateListTimeZone, DateNow, DateToTable, DateToTimeZone};
pub(crate) use debug::Debug;
pub(crate) use def::Def;
pub(crate) use default::Default;
pub(crate) use describe::Describe;
pub(crate) use do_::Do;
@ -199,6 +200,7 @@ pub(crate) use from_yaml::FromYML;
pub(crate) use get::Get;
pub(crate) use group_by::Command as GroupBy;
pub(crate) use group_by_date::GroupByDate;
pub(crate) use hash_::{Hash, HashBase64};
pub(crate) use headers::Headers;
pub(crate) use help::Help;
pub(crate) use histogram::Histogram;
@ -207,11 +209,13 @@ pub(crate) use insert::Command as Insert;
pub(crate) use into_int::IntoInt;
pub(crate) use keep::{Keep, KeepUntil, KeepWhile};
pub(crate) use last::Last;
pub(crate) use let_::Let;
pub(crate) use let_env::LetEnv;
pub(crate) use lines::Lines;
pub(crate) use ls::Ls;
pub(crate) use math::{
Math, MathAverage, MathCeil, MathEval, MathFloor, MathMaximum, MathMedian, MathMinimum,
MathMode, MathProduct, MathRound, MathStddev, MathSummation, MathVariance,
Math, MathAbs, MathAverage, MathCeil, MathEval, MathFloor, MathMaximum, MathMedian,
MathMinimum, MathMode, MathProduct, MathRound, MathStddev, MathSummation, MathVariance,
};
pub(crate) use merge::Merge;
pub(crate) use mkdir::Mkdir;
@ -230,7 +234,9 @@ pub(crate) use prev::Previous;
pub(crate) use pwd::Pwd;
#[cfg(feature = "uuid_crate")]
pub(crate) use random::RandomUUID;
pub(crate) use random::{Random, RandomBool, RandomDecimal, RandomDice, RandomInteger};
pub(crate) use random::{
Random, RandomBool, RandomChars, RandomDecimal, RandomDice, RandomInteger,
};
pub(crate) use range::Range;
pub(crate) use reduce::Reduce;
pub(crate) use reject::Reject;
@ -248,13 +254,14 @@ pub(crate) use size::Size;
pub(crate) use skip::{Skip, SkipUntil, SkipWhile};
pub(crate) use sleep::Sleep;
pub(crate) use sort_by::SortBy;
pub(crate) use source::Source;
pub(crate) use split::{Split, SplitChars, SplitColumn, SplitRow};
pub(crate) use split_by::SplitBy;
pub(crate) use str_::{
Str, StrCamelCase, StrCapitalize, StrCollect, StrContains, StrDowncase, StrEndsWith,
StrFindReplace, StrFrom, StrIndexOf, StrKebabCase, StrLPad, StrLength, StrPascalCase, StrRPad,
StrReverse, StrScreamingSnakeCase, StrSet, StrSnakeCase, StrStartsWith, StrSubstring,
StrToDatetime, StrToDecimal, StrToInteger, StrTrim, StrTrimLeft, StrTrimRight, StrUpcase,
StrReverse, StrScreamingSnakeCase, StrSnakeCase, StrStartsWith, StrSubstring, StrToDatetime,
StrToDecimal, StrToInteger, StrTrim, StrTrimLeft, StrTrimRight, StrUpcase,
};
pub(crate) use table::Table;
pub(crate) use tags::Tags;
@ -280,8 +287,8 @@ pub(crate) use wrap::Wrap;
#[cfg(test)]
mod tests {
use super::*;
use crate::commands::whole_stream_command;
use crate::examples::{test_anchors, test_examples};
use nu_engine::{whole_stream_command, Command};
use nu_errors::ShellError;
fn full_tests() -> Vec<Command> {
@ -292,6 +299,34 @@ mod tests {
whole_stream_command(Move),
whole_stream_command(Update),
whole_stream_command(Empty),
// Str Command Suite
whole_stream_command(Str),
whole_stream_command(StrToDecimal),
whole_stream_command(StrToInteger),
whole_stream_command(StrDowncase),
whole_stream_command(StrUpcase),
whole_stream_command(StrCapitalize),
whole_stream_command(StrFindReplace),
whole_stream_command(StrFrom),
whole_stream_command(StrSubstring),
whole_stream_command(StrToDatetime),
whole_stream_command(StrContains),
whole_stream_command(StrIndexOf),
whole_stream_command(StrTrim),
whole_stream_command(StrTrimLeft),
whole_stream_command(StrTrimRight),
whole_stream_command(StrStartsWith),
whole_stream_command(StrEndsWith),
//whole_stream_command(StrCollect),
whole_stream_command(StrLength),
whole_stream_command(StrLPad),
whole_stream_command(StrReverse),
whole_stream_command(StrRPad),
whole_stream_command(StrCamelCase),
whole_stream_command(StrPascalCase),
whole_stream_command(StrKebabCase),
whole_stream_command(StrSnakeCase),
whole_stream_command(StrScreamingSnakeCase),
]
}

View File

@ -1,6 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use ansi_term::Color;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
@ -9,7 +9,7 @@ pub struct Ansi;
#[derive(Deserialize)]
struct AnsiArgs {
color: Value,
code: Value,
escape: Option<Tagged<String>>,
osc: Option<Tagged<String>>,
}
@ -23,18 +23,18 @@ impl WholeStreamCommand for Ansi {
fn signature(&self) -> Signature {
Signature::build("ansi")
.optional(
"color",
"code",
SyntaxShape::Any,
"the name of the color to use or 'reset' to reset the color",
"the name of the code to use like 'green' or 'reset' to reset the color",
)
.named(
"escape", // \x1b
"escape", // \x1b[
SyntaxShape::Any,
"escape sequence without the escape character(s)",
Some('e'),
)
.named(
"osc",
"osc", // \x1b]
SyntaxShape::Any,
"operating system command (ocs) escape sequence without the escape character(s)",
Some('o'),
@ -118,12 +118,8 @@ Format: #
]
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let (AnsiArgs { color, escape, osc }, _) = args.process(&registry).await?;
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let (AnsiArgs { code, escape, osc }, _) = args.process().await?;
if let Some(e) = escape {
let esc_vec: Vec<char> = e.item.chars().collect();
@ -149,6 +145,7 @@ Format: #
o.tag(),
));
}
//Operating system command aka osc ESC ] <- note the right brace, not left brace for osc
// OCS's need to end with a bell '\x07' char
let output = format!("\x1b]{};", o.item);
@ -157,25 +154,24 @@ Format: #
)));
}
let color_string = color.as_string()?;
let ansi_code = str_to_ansi_color(color_string);
let code_string = code.as_string()?;
let ansi_code = str_to_ansi(code_string);
if let Some(output) = ansi_code {
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(output).into_value(color.tag()),
UntaggedValue::string(output).into_value(code.tag()),
)))
} else {
Err(ShellError::labeled_error(
"Unknown color",
"unknown color",
color.tag(),
"Unknown ansi code",
"unknown ansi code",
code.tag(),
))
}
// }
}
}
pub fn str_to_ansi_color(s: String) -> Option<String> {
pub fn str_to_ansi(s: String) -> Option<String> {
match s.as_str() {
"g" | "green" => Some(Color::Green.prefix().to_string()),
"gb" | "green_bold" => Some(Color::Green.bold().prefix().to_string()),
@ -226,6 +222,57 @@ pub fn str_to_ansi_color(s: String) -> Option<String> {
"wd" | "white_dimmed" => Some(Color::White.dimmed().prefix().to_string()),
"wr" | "white_reverse" => Some(Color::White.reverse().prefix().to_string()),
"reset" => Some("\x1b[0m".to_owned()),
// Reference for ansi codes https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
// Another good reference http://ascii-table.com/ansi-escape-sequences.php
// For setting title like `echo [$(char title) $(pwd) $(char bel)] | str collect`
"title" => Some("\x1b]2;".to_string()), // ESC]2; xterm sets window title using OSC syntax escapes
"bel" => Some('\x07'.to_string()), // Terminal Bell
"backspace" => Some('\x08'.to_string()), // Backspace
// Ansi Erase Sequences
"clear_screen" => Some("\x1b[J".to_string()), // clears the screen
"clear_screen_from_cursor_to_end" => Some("\x1b[0J".to_string()), // clears from cursor until end of screen
"clear_screen_from_cursor_to_beginning" => Some("\x1b[1J".to_string()), // clears from cursor to beginning of screen
"cls" | "clear_entire_screen" => Some("\x1b[2J".to_string()), // clears the entire screen
"erase_line" => Some("\x1b[K".to_string()), // clears the current line
"erase_line_from_cursor_to_end" => Some("\x1b[0K".to_string()), // clears from cursor to end of line
"erase_line_from_cursor_to_beginning" => Some("\x1b[1K".to_string()), // clears from cursor to start of line
"erase_entire_line" => Some("\x1b[2K".to_string()), // clears entire line
// Turn on/off cursor
"cursor_off" => Some("\x1b[?25l".to_string()),
"cursor_on" => Some("\x1b[?25h".to_string()),
// Turn on/off blinking
"cursor_blink_off" => Some("\x1b[?12l".to_string()),
"cursor_blink_on" => Some("\x1b[?12h".to_string()),
// Cursor position in ESC [ <r>;<c>R where r = row and c = column
"cursor_position" => Some("\x1b[6n".to_string()),
// Report Terminal Identity
"identity" => Some("\x1b[0c".to_string()),
// Ansi escape only - CSI command
"csi" | "escape" | "escape_left" => Some("\x1b[".to_string()),
// OSC escape (Operating system command)
"osc" | "escape_right" => Some("\x1b]".to_string()),
// Ansi RGB - Needs to be 32;2;r;g;b or 48;2;r;g;b
// assuming the rgb will be passed via command and no here
"rgb_fg" => Some("\x1b[32;2;".to_string()),
"rgb_bg" => Some("\x1b[48;2;".to_string()),
// Ansi color index - Needs 38;5;idx or 48;5;idx where idx = 0 to 255
"idx_fg" | "color_idx_fg" => Some("\x1b[38;5;".to_string()),
"idx_bg" | "color_idx_bg" => Some("\x1b[48;5;".to_string()),
// Returns terminal size like "[<r>;<c>R" where r is rows and c is columns
// This should work assuming your terminal is not greater than 999x999
"size" => Some("\x1b[s\x1b[999;999H\x1b[6n\x1b[u".to_string()),
_ => None,
}
}

View File

@ -1,6 +1,5 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
@ -29,12 +28,8 @@ impl WholeStreamCommand for Command {
"Append a row to the table"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let (Arguments { mut value }, input) = args.process(registry).await?;
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let (Arguments { mut value }, input) = args.process().await?;
let input: Vec<Value> = input.collect().await;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
use serde::Deserialize;
@ -61,15 +61,9 @@ The file can contain several optional sections:
fn signature(&self) -> Signature {
Signature::build("autoenv")
}
async fn run(
&self,
_args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(crate::commands::help::get_help(&Autoenv, &registry))
.into_value(Tag::unknown()),
UntaggedValue::string(get_help(&Autoenv, &args.scope)).into_value(Tag::unknown()),
)))
}

View File

@ -1,6 +1,6 @@
use super::autoenv::read_trusted;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::SyntaxShape;
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
@ -22,14 +22,11 @@ impl WholeStreamCommand for AutoenvTrust {
"Trust a .nu-env file in the current or given directory"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let ctx = EvaluationContext::from_args(&args);
let file_to_trust = match args.call_info.evaluate(registry).await?.args.nth(0) {
let file_to_trust = match args.call_info.evaluate(&ctx).await?.args.nth(0) {
Some(Value {
value: UntaggedValue::Primitive(Primitive::String(ref path)),
tag: _,

View File

@ -1,6 +1,6 @@
use super::autoenv::Trusted;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::SyntaxShape;
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
@ -26,13 +26,10 @@ impl WholeStreamCommand for AutoenvUnTrust {
"Untrust a .nu-env file in the current or given directory"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let file_to_untrust = match args.call_info.evaluate(registry).await?.args.nth(0) {
let ctx = EvaluationContext::from_args(&args);
let file_to_untrust = match args.call_info.evaluate(&ctx).await?.args.nth(0) {
Some(Value {
value: UntaggedValue::Primitive(Primitive::String(ref path)),
tag: _,

View File

@ -1,11 +1,11 @@
use crate::commands::autoview::options::{ConfigExtensions, NuConfig as AutoViewConfiguration};
use crate::commands::{UnevaluatedCallInfo, WholeStreamCommand};
use crate::prelude::*;
use crate::primitive::get_color_config;
use nu_data::value::format_leaf;
use nu_engine::{UnevaluatedCallInfo, WholeStreamCommand};
use nu_errors::ShellError;
use nu_protocol::hir::{self, Expression, ExternalRedirection, Literal, SpannedExpression};
use nu_protocol::{Primitive, Scope, Signature, UntaggedValue, Value};
use nu_protocol::{Primitive, Signature, UntaggedValue, Value};
use nu_table::TextStyle;
use parking_lot::Mutex;
use std::sync::atomic::AtomicBool;
@ -26,20 +26,15 @@ impl WholeStreamCommand for Command {
"View the contents of the pipeline as a table or list."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
autoview(RunnableContext {
input: args.input,
registry: registry.clone(),
scope: args.scope.clone(),
shell_manager: args.shell_manager,
host: args.host,
ctrl_c: args.ctrl_c,
current_errors: args.current_errors,
name: args.call_info.name_tag,
raw_input: args.raw_input,
})
.await
}
@ -65,7 +60,7 @@ pub struct RunnableContextWithoutInput {
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
pub ctrl_c: Arc<AtomicBool>,
pub registry: CommandRegistry,
pub scope: Scope,
pub name: Tag,
}
@ -76,7 +71,7 @@ impl RunnableContextWithoutInput {
host: context.host,
ctrl_c: context.ctrl_c,
current_errors: context.current_errors,
registry: context.registry,
scope: context.scope,
name: context.name,
};
(context.input, new_context)
@ -109,7 +104,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
if let Some(table) = table {
let command_args = create_default_command_args(&context).with_input(stream);
let result = table.run(command_args, &context.registry).await?;
let result = table.run(command_args).await?;
result.collect::<Vec<_>>().await;
}
}
@ -126,7 +121,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
);
let command_args =
create_default_command_args(&context).with_input(stream);
let result = text.run(command_args, &context.registry).await?;
let result = text.run(command_args).await?;
result.collect::<Vec<_>>().await;
} else {
out!("{}", s);
@ -139,30 +134,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
out!("{}", s);
}
Value {
value: UntaggedValue::Primitive(Primitive::Line(ref s)),
tag: Tag { anchor, span },
} if anchor.is_some() => {
if let Some(text) = text {
let mut stream = VecDeque::new();
stream.push_back(
UntaggedValue::string(s).into_value(Tag { anchor, span }),
);
let command_args =
create_default_command_args(&context).with_input(stream);
let result = text.run(command_args, &context.registry).await?;
result.collect::<Vec<_>>().await;
} else {
out!("{}\n", s);
}
}
Value {
value: UntaggedValue::Primitive(Primitive::Line(s)),
..
} => {
out!("{}\n", s);
}
Value {
value: UntaggedValue::Primitive(Primitive::Path(s)),
value: UntaggedValue::Primitive(Primitive::FilePath(s)),
..
} => {
out!("{}", s.display());
@ -224,7 +196,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
stream.push_back(x);
let command_args =
create_default_command_args(&context).with_input(stream);
let result = binary.run(command_args, &context.registry).await?;
let result = binary.run(command_args).await?;
result.collect::<Vec<_>>().await;
} else {
use pretty_hex::*;
@ -276,7 +248,12 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
nu_table::draw_table(&table, term_width, &color_hm);
}
Value {
value: UntaggedValue::Primitive(Primitive::Nothing),
..
} => {
// Do nothing
}
Value {
value: ref item, ..
} => {
@ -285,7 +262,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
stream.push_back(x);
let command_args =
create_default_command_args(&context).with_input(stream);
let result = table.run(command_args, &context.registry).await?;
let result = table.run(command_args).await?;
result.collect::<Vec<_>>().await;
} else {
out!("{:?}", item);
@ -318,8 +295,8 @@ fn create_default_command_args(context: &RunnableContextWithoutInput) -> RawComm
external_redirection: ExternalRedirection::Stdout,
},
name_tag: context.name.clone(),
scope: Scope::create(),
},
scope: Scope::new(),
}
}

View File

@ -1,12 +1,12 @@
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
#[cfg(feature = "rich-benchmark")]
use heim::cpu::time;
// #[cfg(feature = "rich-benchmark")]
// use heim::cpu::time;
use nu_engine::run_block;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
hir::{Block, ClassifiedCommand, Commands, InternalCommand},
Dictionary, Scope, Signature, SyntaxShape, UntaggedValue, Value,
hir::{Block, CapturedBlock, ClassifiedCommand, Group, InternalCommand, Pipeline},
Dictionary, Signature, SyntaxShape, UntaggedValue, Value,
};
use rand::{
distributions::Alphanumeric,
@ -19,8 +19,8 @@ pub struct Benchmark;
#[derive(Deserialize, Debug)]
struct BenchmarkArgs {
block: Block,
passthrough: Option<Block>,
block: CapturedBlock,
passthrough: Option<CapturedBlock>,
}
#[async_trait]
@ -48,12 +48,8 @@ impl WholeStreamCommand for Benchmark {
"Runs a block and returns the time it took to execute it"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
benchmark(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
benchmark(args).await
}
fn examples(&self) -> Vec<Example> {
@ -72,78 +68,73 @@ impl WholeStreamCommand for Benchmark {
}
}
async fn benchmark(
raw_args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
async fn benchmark(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = raw_args.call_info.args.span;
let mut context = EvaluationContext::from_raw(&raw_args, &registry);
let scope = raw_args.call_info.scope.clone();
let (BenchmarkArgs { block, passthrough }, input) = raw_args.process(&registry).await?;
let mut context = EvaluationContext::from_raw(&raw_args);
let scope = raw_args.scope.clone();
let (BenchmarkArgs { block, passthrough }, input) = raw_args.process().await?;
let env = scope.env();
let env = scope.get_env_vars();
let name = generate_free_name(&env);
let mut env = IndexMap::new();
env.insert(name, generate_random_env_value());
let scope = Scope::append_env(scope, env);
scope.add_env_var(name, generate_random_env_value());
let start_time = Instant::now();
#[cfg(feature = "rich-benchmark")]
let start = time().await;
// #[cfg(feature = "rich-benchmark")]
// let start = time().await;
let result = run_block(&block, &mut context, input, scope.clone()).await;
context.scope.enter_scope();
let result = run_block(&block.block, &context, input).await;
context.scope.exit_scope();
let output = result?.into_vec().await;
#[cfg(feature = "rich-benchmark")]
let end = time().await;
// #[cfg(feature = "rich-benchmark")]
// let end = time().await;
let end_time = Instant::now();
context.clear_errors();
// return basic runtime
#[cfg(not(feature = "rich-benchmark"))]
//#[cfg(not(feature = "rich-benchmark"))]
{
let mut indexmap = IndexMap::with_capacity(1);
let real_time = into_big_int(end_time - start_time);
indexmap.insert("real time".to_string(), real_time);
benchmark_output(indexmap, output, passthrough, &tag, &mut context, scope).await
benchmark_output(indexmap, output, passthrough, &tag, &mut context).await
}
// return advanced stats
#[cfg(feature = "rich-benchmark")]
if let (Ok(start), Ok(end)) = (start, end) {
let mut indexmap = IndexMap::with_capacity(4);
// #[cfg(feature = "rich-benchmark")]
// if let (Ok(start), Ok(end)) = (start, end) {
// let mut indexmap = IndexMap::with_capacity(4);
let real_time = into_big_int(end_time - start_time);
indexmap.insert("real time".to_string(), real_time);
// let real_time = into_big_int(end_time - start_time);
// indexmap.insert("real time".to_string(), real_time);
let user_time = into_big_int(end.user() - start.user());
indexmap.insert("user time".to_string(), user_time);
// let user_time = into_big_int(end.user() - start.user());
// indexmap.insert("user time".to_string(), user_time);
let system_time = into_big_int(end.system() - start.system());
indexmap.insert("system time".to_string(), system_time);
// let system_time = into_big_int(end.system() - start.system());
// indexmap.insert("system time".to_string(), system_time);
let idle_time = into_big_int(end.idle() - start.idle());
indexmap.insert("idle time".to_string(), idle_time);
// let idle_time = into_big_int(end.idle() - start.idle());
// indexmap.insert("idle time".to_string(), idle_time);
benchmark_output(indexmap, output, passthrough, &tag, &mut context, scope).await
} else {
Err(ShellError::untagged_runtime_error(
"Could not retreive CPU time",
))
}
// benchmark_output(indexmap, output, passthrough, &tag, &mut context).await
// } else {
// Err(ShellError::untagged_runtime_error(
// "Could not retrieve CPU time",
// ))
// }
}
async fn benchmark_output<T, Output>(
indexmap: IndexMap<String, BigInt>,
block_output: Output,
passthrough: Option<Block>,
passthrough: Option<CapturedBlock>,
tag: T,
context: &mut EvaluationContext,
scope: Arc<Scope>,
) -> Result<OutputStream, ShellError>
where
T: Into<Tag> + Copy,
@ -161,9 +152,12 @@ where
let benchmark_output = InputStream::one(value);
// add autoview for an empty block
let time_block = add_implicit_autoview(time_block);
let time_block = add_implicit_autoview(time_block.block);
let _ = run_block(&time_block, context, benchmark_output, scope).await?;
context.scope.enter_scope();
let result = run_block(&time_block, context, benchmark_output).await;
context.scope.exit_scope();
result?;
context.clear_errors();
Ok(block_output.into())
@ -175,15 +169,19 @@ where
fn add_implicit_autoview(mut block: Block) -> Block {
if block.block.is_empty() {
block.push({
let mut commands = Commands::new(block.span);
let group = Group::new(
vec![{
let mut commands = Pipeline::new(block.span);
commands.push(ClassifiedCommand::Internal(InternalCommand::new(
"autoview".to_string(),
block.span,
block.span,
)));
commands
});
}],
block.span,
);
block.push(group);
}
block
}

View File

@ -1,8 +1,8 @@
use crate::prelude::*;
use nu_errors::ShellError;
use crate::commands::WholeStreamCommand;
use nu_data::value::format_leaf;
use nu_engine::WholeStreamCommand;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
#[derive(Deserialize)]
@ -27,13 +27,9 @@ impl WholeStreamCommand for BuildString {
"Builds a string from the arguments"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let (BuildStringArgs { rest }, _) = args.process(&registry).await?;
let (BuildStringArgs { rest }, _) = args.process().await?;
let mut output_string = String::new();

View File

@ -1,7 +1,7 @@
use crate::commands::{command::EvaluatedWholeStreamCommandArgs, WholeStreamCommand};
use crate::prelude::*;
use chrono::{Datelike, Local, NaiveDate};
use indexmap::IndexMap;
use nu_engine::{EvaluatedWholeStreamCommandArgs, WholeStreamCommand};
use nu_errors::ShellError;
use nu_protocol::{Dictionary, Signature, SyntaxShape, UntaggedValue, Value};
@ -41,12 +41,8 @@ impl WholeStreamCommand for Cal {
"Display a calendar."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
cal(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
cal(args).await
}
fn examples(&self) -> Vec<Example> {
@ -70,12 +66,8 @@ impl WholeStreamCommand for Cal {
}
}
pub async fn cal(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let args = args.evaluate_once(&registry).await?;
pub async fn cal(args: CommandArgs) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once().await?;
let mut calendar_vec_deque = VecDeque::new();
let tag = args.call_info.name_tag.clone();

View File

@ -1,16 +1,9 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use std::path::PathBuf;
use nu_engine::shell::CdArgs;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape};
use nu_source::Tagged;
#[derive(Deserialize)]
pub struct CdArgs {
pub(crate) path: Option<Tagged<PathBuf>>,
}
pub struct Cd;
@ -23,7 +16,7 @@ impl WholeStreamCommand for Cd {
fn signature(&self) -> Signature {
Signature::build("cd").optional(
"directory",
SyntaxShape::Path,
SyntaxShape::FilePath,
"the directory to change to",
)
}
@ -32,14 +25,10 @@ impl WholeStreamCommand for Cd {
"Change to a new path."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let name = args.call_info.name_tag.clone();
let shell_manager = args.shell_manager.clone();
let (args, _): (CdArgs, _) = args.process(&registry).await?;
let (args, _): (CdArgs, _) = args.process().await?;
shell_manager.cd(args, name)
}

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
@ -19,7 +19,7 @@ impl WholeStreamCommand for Char {
}
fn signature(&self) -> Signature {
Signature::build("ansi")
Signature::build("char")
.required(
"character",
SyntaxShape::Any,
@ -56,12 +56,8 @@ impl WholeStreamCommand for Char {
]
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let (CharArgs { name, unicode }, _) = args.process(&registry).await?;
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let (CharArgs { name, unicode }, _) = args.process().await?;
if unicode {
let decoded_char = string_to_unicode_char(&name.item);
@ -134,24 +130,6 @@ fn str_to_character(s: &str) -> Option<String> {
"snowy" | "snow" => Some("❄️".to_string()),
"thunderstorm" | "thunder" => Some("🌩️".to_string()),
// Reference for ansi codes https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
// Another good reference http://ascii-table.com/ansi-escape-sequences.php
// For setting title like `echo [$(char title) $(pwd) $(char bel)] | str collect`
"title" => Some("\x1b]2;".to_string()), // ESC]2; xterm sets window title
"bel" => Some('\x07'.to_string()), // Terminal Bell
"backspace" => Some('\x08'.to_string()), // Backspace
// Ansi Erase Sequences
"clear_screen" => Some("\x1b[J".to_string()), // clears the screen
"clear_screen_from_cursor_to_end" => Some("\x1b[0J".to_string()), // clears from cursor until end of screen
"clear_screen_from_cursor_to_beginning" => Some("\x1b[1J".to_string()), // clears from cursor to beginning of screen
"cls" | "clear_entire_screen" => Some("\x1b[2J".to_string()), // clears the entire screen
"erase_line" => Some("\x1b[K".to_string()), // clears the current line
"erase_line_from_cursor_to_end" => Some("\x1b[0K".to_string()), // clears from cursor to end of line
"erase_line_from_cursor_to_beginning" => Some("\x1b[1K".to_string()), // clears from cursor to start of line
"erase_entire_line" => Some("\x1b[2K".to_string()), // clears entire line
_ => None,
}
}

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
@ -20,21 +20,15 @@ impl WholeStreamCommand for Chart {
"Displays charts."
}
async fn run(
&self,
_args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
if registry.get_command("chart bar").is_none() {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
if args.scope.get_command("chart bar").is_none() {
return Err(ShellError::untagged_runtime_error(
"nu_plugin_chart not installed.",
));
}
let registry = registry.clone();
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
UntaggedValue::string(crate::commands::help::get_help(&Chart, &registry))
.into_value(Tag::unknown()),
UntaggedValue::string(get_help(&Chart, &args.scope)).into_value(Tag::unknown()),
))))
}
}

View File

@ -1,7 +1,7 @@
use crate::commands::classified::maybe_text_codec::{MaybeTextCodec, StringOrBinary};
use crate::evaluate::evaluate_baseline_expr;
use crate::futures::ThreadedReceiver;
use crate::prelude::*;
use nu_engine::evaluate_baseline_expr;
use nu_engine::{MaybeTextCodec, StringOrBinary};
use std::borrow::Cow;
use std::io::Write;
@ -16,14 +16,14 @@ use log::trace;
use nu_errors::ShellError;
use nu_protocol::hir::Expression;
use nu_protocol::hir::{ExternalCommand, ExternalRedirection};
use nu_protocol::{Primitive, Scope, ShellTypeName, UntaggedValue, Value};
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
use nu_source::Tag;
use nu_stream::trace_stream;
pub(crate) async fn run_external_command(
command: ExternalCommand,
context: &mut EvaluationContext,
input: InputStream,
scope: Arc<Scope>,
external_redirection: ExternalRedirection,
) -> Result<InputStream, ShellError> {
trace!(target: "nu::run::external", "-> {}", command.name);
@ -36,14 +36,13 @@ pub(crate) async fn run_external_command(
));
}
run_with_stdin(command, context, input, scope, external_redirection).await
run_with_stdin(command, context, input, external_redirection).await
}
async fn run_with_stdin(
command: ExternalCommand,
context: &mut EvaluationContext,
input: InputStream,
scope: Arc<Scope>,
external_redirection: ExternalRedirection,
) -> Result<InputStream, ShellError> {
let path = context.shell_manager.path();
@ -53,7 +52,7 @@ async fn run_with_stdin(
let mut command_args = vec![];
for arg in command.args.iter() {
let is_literal = matches!(arg.expr, Expression::Literal(_));
let value = evaluate_baseline_expr(arg, &context.registry, scope.clone()).await?;
let value = evaluate_baseline_expr(arg, context).await?;
// Skip any arguments that don't really exist, treating them as optional
// FIXME: we may want to preserve the gap in the future, though it's hard to say
@ -97,7 +96,7 @@ async fn run_with_stdin(
#[cfg(feature = "dirs")]
{
home_dir = dirs::home_dir;
home_dir = dirs_next::home_dir;
}
#[cfg(not(feature = "dirs"))]
{
@ -132,7 +131,7 @@ async fn run_with_stdin(
&process_args[..],
input,
external_redirection,
scope,
&context.scope,
)
}
@ -142,7 +141,7 @@ fn spawn(
args: &[String],
input: InputStream,
external_redirection: ExternalRedirection,
scope: Arc<Scope>,
scope: &Scope,
) -> Result<InputStream, ShellError> {
let command = command.clone();
@ -173,7 +172,7 @@ fn spawn(
trace!(target: "nu::run::external", "cwd = {:?}", &path);
process.env_clear();
process.envs(scope.env());
process.envs(scope.get_env_vars());
// We want stdout regardless of what
// we are doing ($it case or pipe stdin)
@ -223,8 +222,7 @@ fn spawn(
for value in block_on_stream(input) {
match &value.value {
UntaggedValue::Primitive(Primitive::Nothing) => continue,
UntaggedValue::Primitive(Primitive::String(s))
| UntaggedValue::Primitive(Primitive::Line(s)) => {
UntaggedValue::Primitive(Primitive::String(s)) => {
if stdin_write.write(s.as_bytes()).is_err() {
// Other side has closed, so exit
return Ok(());
@ -466,7 +464,7 @@ pub fn did_find_command(#[allow(unused)] name: &str) -> bool {
let cmd_builtins = [
"assoc", "break", "color", "copy", "date", "del", "dir", "dpath", "echo", "erase",
"for", "ftype", "md", "mkdir", "mklink", "move", "path", "ren", "rename", "rd",
"rmdir", "set", "start", "time", "title", "type", "ver", "verify", "vol",
"rmdir", "start", "time", "title", "type", "ver", "verify", "vol",
];
cmd_builtins.contains(&name)
@ -535,17 +533,16 @@ mod tests {
add_double_quotes, argument_is_quoted, escape_double_quotes, expand_tilde, remove_quotes,
};
#[cfg(feature = "which")]
use super::{run_external_command, EvaluationContext, InputStream};
use super::{run_external_command, InputStream};
#[cfg(feature = "which")]
use futures::executor::block_on;
#[cfg(feature = "which")]
use nu_engine::basic_evaluation_context;
#[cfg(feature = "which")]
use nu_errors::ShellError;
#[cfg(feature = "which")]
use nu_protocol::Scope;
#[cfg(feature = "which")]
use nu_test_support::commands::ExternalBuilder;
// async fn read(mut stream: OutputStream) -> Option<Value> {
// match stream.try_next().await {
// Ok(val) => {
@ -566,17 +563,13 @@ mod tests {
let input = InputStream::empty();
let mut ctx =
EvaluationContext::basic().expect("There was a problem creating a basic context.");
basic_evaluation_context().expect("There was a problem creating a basic context.");
assert!(run_external_command(
cmd,
&mut ctx,
input,
Scope::create(),
ExternalRedirection::Stdout
)
assert!(
run_external_command(cmd, &mut ctx, input, ExternalRedirection::Stdout)
.await
.is_err());
.is_err()
);
Ok(())
}
@ -584,7 +577,7 @@ mod tests {
// async fn failure_run() -> Result<(), ShellError> {
// let cmd = ExternalBuilder::for_name("fail").build();
// let mut ctx = EvaluationContext::basic().expect("There was a problem creating a basic context.");
// let mut ctx = crate::cli::basic_evaluation_context().expect("There was a problem creating a basic context.");
// let stream = run_external_command(cmd, &mut ctx, None, false)
// .await?
// .expect("There was a problem running the external command.");

View File

@ -0,0 +1,5 @@
mod dynamic;
pub(crate) mod external;
#[allow(unused_imports)]
pub(crate) use dynamic::Command as DynamicCommand;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::Signature;
use std::process::Command;
@ -20,7 +20,7 @@ impl WholeStreamCommand for Clear {
"Clears the terminal"
}
async fn run(&self, _: CommandArgs, _: &CommandRegistry) -> Result<OutputStream, ShellError> {
async fn run(&self, _: CommandArgs) -> Result<OutputStream, ShellError> {
if cfg!(windows) {
Command::new("cmd")
.args(&["/C", "cls"])

View File

@ -1,11 +1,10 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use futures::stream::StreamExt;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, Value};
use clipboard::{ClipboardContext, ClipboardProvider};
use arboard::Clipboard;
pub struct Clip;
@ -23,12 +22,8 @@ impl WholeStreamCommand for Clip {
"Copy the contents of the pipeline to the copy/paste buffer"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
clip(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
clip(args).await
}
fn examples(&self) -> Vec<Example> {
@ -47,16 +42,12 @@ impl WholeStreamCommand for Clip {
}
}
pub async fn clip(
args: CommandArgs,
_registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
pub async fn clip(args: CommandArgs) -> Result<OutputStream, ShellError> {
let input = args.input;
let name = args.call_info.name_tag.clone();
let values: Vec<Value> = input.collect().await;
if let Ok(clip_context) = ClipboardProvider::new() {
let mut clip_context: ClipboardContext = clip_context;
if let Ok(mut clip_context) = Clipboard::new() {
let mut new_copy_data = String::new();
if !values.is_empty() {
@ -81,7 +72,7 @@ pub async fn clip(
}
}
match clip_context.set_contents(new_copy_data) {
match clip_context.set_text(new_copy_data) {
Ok(_) => {}
Err(_) => {
return Err(ShellError::labeled_error(

View File

@ -0,0 +1,21 @@
use crate::prelude::*;
use nu_engine::Command;
use nu_errors::ShellError;
use parking_lot::Mutex;
use std::sync::atomic::AtomicBool;
pub struct RunnableContext {
pub input: InputStream,
pub shell_manager: ShellManager,
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
pub ctrl_c: Arc<AtomicBool>,
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
pub scope: Scope,
pub name: Tag,
}
impl RunnableContext {
pub fn get_command(&self, name: &str) -> Option<Command> {
self.scope.get_command(name)
}
}

View File

@ -1,8 +1,7 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use futures::future;
use futures::stream::StreamExt;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
@ -28,12 +27,8 @@ impl WholeStreamCommand for Compact {
"Creates a table with non-empty rows"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
compact(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
compact(args).await
}
fn examples(&self) -> Vec<Example> {
@ -45,12 +40,8 @@ impl WholeStreamCommand for Compact {
}
}
pub async fn compact(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let (CompactArgs { rest: columns }, input) = args.process(&registry).await?;
pub async fn compact(args: CommandArgs) -> Result<OutputStream, ShellError> {
let (CompactArgs { rest: columns }, input) = args.process().await?;
Ok(input
.filter_map(move |item| {
future::ready(if columns.is_empty() {

View File

@ -1,6 +1,5 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
@ -20,12 +19,8 @@ impl WholeStreamCommand for SubCommand {
"clear the config"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
clear(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
clear(args).await
}
fn examples(&self) -> Vec<Example> {
@ -37,10 +32,7 @@ impl WholeStreamCommand for SubCommand {
}
}
pub async fn clear(
args: CommandArgs,
_registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
pub async fn clear(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name_span = args.call_info.name_tag.clone();
// NOTE: None because we are not loading a new config file, we just want to read from the

View File

@ -1,8 +1,9 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use crate::{CommandArgs, CommandRegistry, OutputStream};
use nu_engine::CommandArgs;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
use nu_stream::OutputStream;
pub struct Command;
@ -20,11 +21,7 @@ impl WholeStreamCommand for Command {
"Configuration management."
}
async fn run(
&self,
args: CommandArgs,
_registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let name_span = args.call_info.name_tag.clone();
let name = args.call_info.name_tag;
let result = nu_data::config::read(name_span, &None)?;

View File

@ -1,6 +1,5 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
@ -29,12 +28,8 @@ impl WholeStreamCommand for SubCommand {
"Gets a value from the config"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
get(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
get(args).await
}
fn examples(&self) -> Vec<Example> {
@ -46,12 +41,9 @@ impl WholeStreamCommand for SubCommand {
}
}
pub async fn get(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
pub async fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name_tag = args.call_info.name_tag.clone();
let (GetArgs { path }, _) = args.process(&registry).await?;
let (GetArgs { path }, _) = args.process().await?;
// NOTE: None because we are not loading a new config file, we just want to read from the
// existing config

View File

@ -1,6 +1,5 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged;
@ -22,7 +21,7 @@ impl WholeStreamCommand for SubCommand {
fn signature(&self) -> Signature {
Signature::build("config load").required(
"load",
SyntaxShape::Path,
SyntaxShape::FilePath,
"Path to load the config from",
)
}
@ -31,22 +30,15 @@ impl WholeStreamCommand for SubCommand {
"Loads the config from the path given"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
set(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
set(args).await
}
}
pub async fn set(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
pub async fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name = args.call_info.name_tag.clone();
let name_span = args.call_info.name_tag.clone();
let (LoadArgs { load }, _) = args.process(&registry).await?;
let (LoadArgs { load }, _) = args.process().await?;
let configuration = load.item().clone();

View File

@ -1,6 +1,5 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue};
@ -20,12 +19,8 @@ impl WholeStreamCommand for SubCommand {
"return the path to the config file"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
path(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
path(args).await
}
fn examples(&self) -> Vec<Example> {
@ -37,13 +32,10 @@ impl WholeStreamCommand for SubCommand {
}
}
pub async fn path(
args: CommandArgs,
_registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
pub async fn path(args: CommandArgs) -> Result<OutputStream, ShellError> {
let path = config::default_path()?;
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::Primitive(Primitive::Path(path)).into_value(args.call_info.name_tag),
UntaggedValue::Primitive(Primitive::FilePath(path)).into_value(args.call_info.name_tag),
)))
}

View File

@ -1,6 +1,5 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged;
@ -30,12 +29,8 @@ impl WholeStreamCommand for SubCommand {
"Removes a value from the config"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
remove(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
remove(args).await
}
fn examples(&self) -> Vec<Example> {
@ -47,12 +42,9 @@ impl WholeStreamCommand for SubCommand {
}
}
pub async fn remove(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
pub async fn remove(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name_span = args.call_info.name_tag.clone();
let (RemoveArgs { remove }, _) = args.process(&registry).await?;
let (RemoveArgs { remove }, _) = args.process().await?;
let mut result = nu_data::config::read(name_span, &None)?;

View File

@ -1,6 +1,5 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
@ -28,12 +27,8 @@ impl WholeStreamCommand for SubCommand {
"Sets a value in the config"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
set(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
set(args).await
}
fn examples(&self) -> Vec<Example> {
@ -62,12 +57,9 @@ impl WholeStreamCommand for SubCommand {
}
}
pub async fn set(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
pub async fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name_tag = args.call_info.name_tag.clone();
let (SetArgs { path, mut value }, _) = args.process(&registry).await?;
let (SetArgs { path, mut value }, _) = args.process().await?;
// NOTE: None because we are not loading a new config file, we just want to read from the
// existing config

View File

@ -1,6 +1,5 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
@ -30,12 +29,8 @@ impl WholeStreamCommand for SubCommand {
"Sets a value in the config"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
set_into(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
set_into(args).await
}
fn examples(&self) -> Vec<Example> {
@ -47,14 +42,11 @@ impl WholeStreamCommand for SubCommand {
}
}
pub async fn set_into(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
pub async fn set_into(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name_span = args.call_info.name_tag.clone();
let name = args.call_info.name_tag.clone();
let (SetIntoArgs { set_into: v }, input) = args.process(&registry).await?;
let (SetIntoArgs { set_into: v }, input) = args.process().await?;
// NOTE: None because we are not loading a new config file, we just want to read from the
// existing config

View File

@ -1,7 +1,6 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use futures::stream::StreamExt;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, UntaggedValue, Value};
@ -30,13 +29,9 @@ impl WholeStreamCommand for Count {
"Show the total number of rows or items."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let (CountArgs { column }, input) = args.process(&registry).await?;
let (CountArgs { column }, input) = args.process().await?;
let rows: Vec<Value> = input.collect().await;
let count = if column {

View File

@ -1,20 +1,10 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape};
use nu_source::Tagged;
use std::path::PathBuf;
pub struct Cpy;
#[derive(Deserialize)]
pub struct CopyArgs {
pub src: Tagged<PathBuf>,
pub dst: Tagged<PathBuf>,
pub recursive: Tagged<bool>,
}
#[async_trait]
impl WholeStreamCommand for Cpy {
fn name(&self) -> &str {
@ -23,8 +13,8 @@ impl WholeStreamCommand for Cpy {
fn signature(&self) -> Signature {
Signature::build("cp")
.required("src", SyntaxShape::Pattern, "the place to copy from")
.required("dst", SyntaxShape::Path, "the place to copy to")
.required("src", SyntaxShape::GlobPattern, "the place to copy from")
.required("dst", SyntaxShape::FilePath, "the place to copy to")
.switch(
"recursive",
"copy recursively through subdirectories",
@ -36,14 +26,10 @@ impl WholeStreamCommand for Cpy {
"Copy files."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let shell_manager = args.shell_manager.clone();
let name = args.call_info.name_tag.clone();
let (args, _) = args.process(&registry).await?;
let (args, _) = args.process().await?;
shell_manager.cp(args, name)
}

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
@ -19,16 +19,9 @@ impl WholeStreamCommand for Command {
"Apply date function"
}
async fn run(
&self,
_args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(crate::commands::help::get_help(&Command, &registry))
.into_value(Tag::unknown()),
UntaggedValue::string(get_help(&Command, &args.scope)).into_value(Tag::unknown()),
)))
}
}

View File

@ -0,0 +1,109 @@
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
Dictionary, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
};
use nu_source::Tagged;
use std::fmt::{self, write};
pub struct Date;
#[derive(Deserialize)]
pub struct FormatArgs {
format: Tagged<String>,
table: bool,
}
#[async_trait]
impl WholeStreamCommand for Date {
fn name(&self) -> &str {
"date format"
}
fn signature(&self) -> Signature {
Signature::build("date format")
.required("format", SyntaxShape::String, "strftime format")
.switch("table", "print date in a table", Some('t'))
}
fn usage(&self) -> &str {
"Format a given date using the given format string."
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
format(args).await
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Format the current date",
example: "date now | date format '%Y.%m.%d_%H %M %S,%z'",
result: None,
},
Example {
description: "Format the current date and print in a table",
example: "date now | date format -t '%Y-%m-%d_%H:%M:%S %z'",
result: None,
},
]
}
}
pub async fn format(args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let (FormatArgs { format, table }, input) = args.process().await?;
Ok(input
.map(move |value| match value {
Value {
value: UntaggedValue::Primitive(Primitive::Date(dt)),
..
} => {
let mut output = String::new();
if let Err(fmt::Error) =
write(&mut output, format_args!("{}", dt.format(&format.item)))
{
Err(ShellError::labeled_error(
"The date format is invalid",
"invalid strftime format",
&format.tag,
))
} else {
let value = if table {
let mut indexmap = IndexMap::new();
indexmap.insert(
"formatted".to_string(),
UntaggedValue::string(&output).into_value(&tag),
);
UntaggedValue::Row(Dictionary::from(indexmap)).into_value(&tag)
} else {
UntaggedValue::string(&output).into_value(&tag)
};
ReturnSuccess::value(value)
}
}
_ => Err(ShellError::labeled_error(
"Expected a date from pipeline",
"requires date input",
&tag,
)),
})
.to_output_stream())
}
#[cfg(test)]
mod tests {
use super::Date;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Date {})?)
}
}

View File

@ -0,0 +1,75 @@
use crate::prelude::*;
use chrono_tz::TZ_VARIANTS;
use indexmap::IndexMap;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Dictionary, ReturnSuccess, Signature, UntaggedValue};
pub struct Date;
#[async_trait]
impl WholeStreamCommand for Date {
fn name(&self) -> &str {
"date list-timezone"
}
fn signature(&self) -> Signature {
Signature::build("date list-timezone")
}
fn usage(&self) -> &str {
"List supported time zones."
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
list_timezone(args).await
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "List all supported time zones",
example: "date list-timezone",
result: None,
},
Example {
description: "List all supported European time zones",
example: "date list-timezone | where timezone =~ Europe",
result: None,
},
]
}
}
async fn list_timezone(args: CommandArgs) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once().await?;
let tag = args.call_info.name_tag.clone();
let list = TZ_VARIANTS.iter().map(move |tz| {
let mut entries = IndexMap::new();
entries.insert(
"timezone".to_string(),
UntaggedValue::string(tz.name()).into_value(&tag),
);
Ok(ReturnSuccess::Value(
UntaggedValue::Row(Dictionary { entries }).into_value(&tag),
))
});
Ok(futures::stream::iter(list).to_output_stream())
}
#[cfg(test)]
mod tests {
use super::Date;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Date {})?)
}
}

View File

@ -0,0 +1,15 @@
pub mod command;
pub mod format;
pub mod list_timezone;
pub mod now;
pub mod to_table;
pub mod to_timezone;
mod parser;
pub use command::Command as Date;
pub use format::Date as DateFormat;
pub use list_timezone::Date as DateListTimeZone;
pub use now::Date as DateNow;
pub use to_table::Date as DateToTable;
pub use to_timezone::Date as DateToTimeZone;

View File

@ -0,0 +1,50 @@
use crate::prelude::*;
use chrono::{DateTime, Local};
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, UntaggedValue};
pub struct Date;
#[async_trait]
impl WholeStreamCommand for Date {
fn name(&self) -> &str {
"date now"
}
fn signature(&self) -> Signature {
Signature::build("date now")
}
fn usage(&self) -> &str {
"Get the current date."
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
now(args).await
}
}
pub async fn now(args: CommandArgs) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once().await?;
let tag = args.call_info.name_tag.clone();
let now: DateTime<Local> = Local::now();
let value = UntaggedValue::date(now.with_timezone(now.offset())).into_value(&tag);
Ok(OutputStream::one(value))
}
#[cfg(test)]
mod tests {
use super::Date;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Date {})?)
}
}

View File

@ -0,0 +1,107 @@
// Modified from chrono::format::scan
use chrono::{DateTime, FixedOffset, Local, Offset, TimeZone};
use chrono_tz::Tz;
use titlecase::titlecase;
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
pub enum ParseErrorKind {
/// Given field is out of permitted range.
OutOfRange,
/// The input string has some invalid character sequence for given formatting items.
Invalid,
/// The input string has been prematurely ended.
TooShort,
}
pub fn datetime_in_timezone(
dt: &DateTime<FixedOffset>,
s: &str,
) -> Result<DateTime<FixedOffset>, ParseErrorKind> {
match timezone_offset_internal(s, true, true) {
Ok(offset) => match FixedOffset::east_opt(offset) {
Some(offset) => Ok(dt.with_timezone(&offset)),
None => Err(ParseErrorKind::OutOfRange),
},
Err(ParseErrorKind::Invalid) => {
if s.to_lowercase() == "local" {
Ok(dt.with_timezone(Local::now().offset()))
} else {
let tz: Tz = parse_timezone_internal(s)?;
let offset = tz.offset_from_utc_datetime(&dt.naive_utc()).fix();
Ok(dt.with_timezone(&offset))
}
}
Err(e) => Err(e),
}
}
fn parse_timezone_internal(s: &str) -> Result<Tz, ParseErrorKind> {
if let Ok(tz) = s.parse() {
Ok(tz)
} else if let Ok(tz) = titlecase(s).parse() {
Ok(tz)
} else if let Ok(tz) = s.to_uppercase().parse() {
Ok(tz)
} else {
Err(ParseErrorKind::Invalid)
}
}
fn timezone_offset_internal(
mut s: &str,
consume_colon: bool,
allow_missing_minutes: bool,
) -> Result<i32, ParseErrorKind> {
fn digits(s: &str) -> Result<(u8, u8), ParseErrorKind> {
let b = s.as_bytes();
if b.len() < 2 {
Err(ParseErrorKind::TooShort)
} else {
Ok((b[0], b[1]))
}
}
let negative = match s.as_bytes().first() {
Some(&b'+') => false,
Some(&b'-') => true,
Some(_) => return Err(ParseErrorKind::Invalid),
None => return Err(ParseErrorKind::TooShort),
};
s = &s[1..];
// hours (00--99)
let hours = match digits(s)? {
(h1 @ b'0'..=b'9', h2 @ b'0'..=b'9') => i32::from((h1 - b'0') * 10 + (h2 - b'0')),
_ => return Err(ParseErrorKind::Invalid),
};
s = &s[2..];
// colons (and possibly other separators)
if consume_colon {
s = s.trim_start_matches(|c: char| c == ':' || c.is_whitespace());
}
// minutes (00--59)
// if the next two items are digits then we have to add minutes
let minutes = if let Ok(ds) = digits(s) {
match ds {
(m1 @ b'0'..=b'5', m2 @ b'0'..=b'9') => i32::from((m1 - b'0') * 10 + (m2 - b'0')),
(b'6'..=b'9', b'0'..=b'9') => return Err(ParseErrorKind::OutOfRange),
_ => return Err(ParseErrorKind::Invalid),
}
} else if allow_missing_minutes {
0
} else {
return Err(ParseErrorKind::TooShort);
};
match s.len() {
len if len >= 2 => &s[2..],
len if len == 0 => s,
_ => return Err(ParseErrorKind::TooShort),
};
let seconds = hours * 3600 + minutes * 60;
Ok(if negative { -seconds } else { seconds })
}

View File

@ -0,0 +1,105 @@
use crate::prelude::*;
use chrono::{Datelike, Timelike};
use indexmap::IndexMap;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Dictionary, Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
pub struct Date;
#[async_trait]
impl WholeStreamCommand for Date {
fn name(&self) -> &str {
"date to-table"
}
fn signature(&self) -> Signature {
Signature::build("date to-table")
}
fn usage(&self) -> &str {
"Print the date in a structured table."
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
to_table(args).await
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Print the current date in a table",
example: "date now | date to-table",
result: None,
}]
}
}
async fn to_table(args: CommandArgs) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once().await?;
let tag = args.call_info.name_tag.clone();
let input = args.input;
Ok(input
.map(move |value| match value {
Value {
value: UntaggedValue::Primitive(Primitive::Date(dt)),
..
} => {
let mut indexmap = IndexMap::new();
indexmap.insert(
"year".to_string(),
UntaggedValue::int(dt.year()).into_value(&tag),
);
indexmap.insert(
"month".to_string(),
UntaggedValue::int(dt.month()).into_value(&tag),
);
indexmap.insert(
"day".to_string(),
UntaggedValue::int(dt.day()).into_value(&tag),
);
indexmap.insert(
"hour".to_string(),
UntaggedValue::int(dt.hour()).into_value(&tag),
);
indexmap.insert(
"minute".to_string(),
UntaggedValue::int(dt.minute()).into_value(&tag),
);
indexmap.insert(
"second".to_string(),
UntaggedValue::int(dt.second()).into_value(&tag),
);
let tz = dt.offset();
indexmap.insert(
"timezone".to_string(),
UntaggedValue::string(format!("{}", tz)).into_value(&tag),
);
let value = UntaggedValue::Row(Dictionary::from(indexmap)).into_value(&tag);
ReturnSuccess::value(value)
}
_ => Err(ShellError::labeled_error(
"Expected a date from pipeline",
"requires date input",
&tag,
)),
})
.to_output_stream())
}
#[cfg(test)]
mod tests {
use super::Date;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Date {})?)
}
}

View File

@ -0,0 +1,110 @@
use crate::commands::date::parser::{datetime_in_timezone, ParseErrorKind};
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
pub struct Date;
#[derive(Deserialize)]
struct DateToTimeZoneArgs {
timezone: Tagged<String>,
}
#[async_trait]
impl WholeStreamCommand for Date {
fn name(&self) -> &str {
"date to-timezone"
}
fn signature(&self) -> Signature {
Signature::build("date to-timezone").required(
"time zone",
SyntaxShape::String,
"time zone description",
)
}
fn usage(&self) -> &str {
"Convert a date to a given time zone.
Use `date list-timezone` to list all supported time zones.
"
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
to_timezone(args).await
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Get the current date in UTC+05:00",
example: "date now | date to-timezone +0500",
result: None,
},
Example {
description: "Get the current local date",
example: "date now | date to-timezone local",
result: None,
},
Example {
description: "Get the current date in Hawaii",
example: "date now | date to-timezone US/Hawaii",
result: None,
},
]
}
}
async fn to_timezone(args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let (DateToTimeZoneArgs { timezone }, input) = args.process().await?;
Ok(input
.map(move |value| match value {
Value {
value: UntaggedValue::Primitive(Primitive::Date(dt)),
..
} => match datetime_in_timezone(&dt, &timezone.item) {
Ok(dt) => {
let value = UntaggedValue::date(dt).into_value(&tag);
ReturnSuccess::value(value)
}
Err(e) => Err(ShellError::labeled_error(
error_message(e),
"invalid time zone",
&timezone.tag,
)),
},
_ => Err(ShellError::labeled_error(
"Expected a date from pipeline",
"requires date input",
&tag,
)),
})
.to_output_stream())
}
fn error_message(err: ParseErrorKind) -> &'static str {
match err {
ParseErrorKind::Invalid => "The time zone description is invalid",
ParseErrorKind::OutOfRange => "The time zone offset is out of range",
ParseErrorKind::TooShort => "The format of the time zone is invalid",
}
}
#[cfg(test)]
mod tests {
use super::Date;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Date {})?)
}
}

View File

@ -3,7 +3,7 @@ use chrono::{DateTime, Utc};
use nu_errors::ShellError;
use crate::commands::date::utils::date_to_value;
use crate::commands::WholeStreamCommand;
use nu_engine::WholeStreamCommand;
use nu_protocol::Signature;
pub struct Date;
@ -22,21 +22,13 @@ impl WholeStreamCommand for Date {
"return the current date in utc."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
utc(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
utc(args).await
}
}
pub async fn utc(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let args = args.evaluate_once(&registry).await?;
pub async fn utc(args: CommandArgs) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once().await?;
let tag = args.call_info.name_tag.clone();
let no_fmt = "".to_string();

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
@ -24,21 +24,13 @@ impl WholeStreamCommand for Debug {
"Print the Rust debug representation of the values"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
debug_value(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
debug_value(args).await
}
}
async fn debug_value(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let (DebugArgs { raw }, input) = args.process(&registry).await?;
async fn debug_value(args: CommandArgs) -> Result<OutputStream, ShellError> {
let (DebugArgs { raw }, input) = args.process().await?;
Ok(input
.map(move |v| {
if raw {

View File

@ -0,0 +1,48 @@
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{hir::CapturedBlock, Signature, SyntaxShape, Value};
use nu_source::Tagged;
pub struct Def;
#[derive(Deserialize)]
pub struct DefArgs {
pub name: Tagged<String>,
pub args: Tagged<Vec<Value>>,
pub block: CapturedBlock,
}
#[async_trait]
impl WholeStreamCommand for Def {
fn name(&self) -> &str {
"def"
}
fn signature(&self) -> Signature {
Signature::build("def")
.required("name", SyntaxShape::String, "the name of the command")
.required(
"params",
SyntaxShape::Table,
"the parameters of the command",
)
.required("block", SyntaxShape::Block, "the body of the command")
}
fn usage(&self) -> &str {
"Create a command and set it to a definition."
}
async fn run(&self, _args: CommandArgs) -> Result<OutputStream, ShellError> {
// Currently, we don't do anything here because we should have already
// installed the definition as we entered the scope
// We just create a command so that we can get proper coloring
Ok(OutputStream::empty())
}
fn examples(&self) -> Vec<Example> {
vec![]
}
}

View File

@ -1,6 +1,5 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
@ -34,12 +33,8 @@ impl WholeStreamCommand for Default {
"Sets a default row's column if missing."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
default(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
default(args).await
}
fn examples(&self) -> Vec<Example> {
@ -51,12 +46,8 @@ impl WholeStreamCommand for Default {
}
}
async fn default(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let (DefaultArgs { column, value }, input) = args.process(&registry).await?;
async fn default(args: CommandArgs) -> Result<OutputStream, ShellError> {
let (DefaultArgs { column, value }, input) = args.process().await?;
Ok(input
.map(move |item| {

View File

@ -0,0 +1,249 @@
use crate::prelude::*;
use nu_engine::basic_evaluation_context;
use nu_engine::whole_stream_command;
use std::error::Error;
pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Box<dyn Error>> {
let context = basic_evaluation_context()?;
{
use crate::commands::*;
context.add_commands(vec![
// Fundamentals
whole_stream_command(NuPlugin),
whole_stream_command(Let),
whole_stream_command(LetEnv),
whole_stream_command(Def),
whole_stream_command(Source),
// System/file operations
whole_stream_command(Exec),
whole_stream_command(Pwd),
whole_stream_command(Ls),
whole_stream_command(Du),
whole_stream_command(Cd),
whole_stream_command(Remove),
whole_stream_command(Open),
whole_stream_command(Config),
whole_stream_command(ConfigGet),
whole_stream_command(ConfigSet),
whole_stream_command(ConfigSetInto),
whole_stream_command(ConfigClear),
whole_stream_command(ConfigLoad),
whole_stream_command(ConfigRemove),
whole_stream_command(ConfigPath),
whole_stream_command(Help),
whole_stream_command(History),
whole_stream_command(Save),
whole_stream_command(Touch),
whole_stream_command(Cpy),
whole_stream_command(Date),
whole_stream_command(DateListTimeZone),
whole_stream_command(DateNow),
whole_stream_command(DateToTable),
whole_stream_command(DateToTimeZone),
whole_stream_command(DateFormat),
whole_stream_command(Cal),
whole_stream_command(Mkdir),
whole_stream_command(Mv),
whole_stream_command(Kill),
whole_stream_command(Version),
whole_stream_command(Clear),
whole_stream_command(Describe),
whole_stream_command(Which),
whole_stream_command(Debug),
whole_stream_command(WithEnv),
whole_stream_command(Do),
whole_stream_command(Sleep),
// Statistics
whole_stream_command(Size),
whole_stream_command(Count),
whole_stream_command(Benchmark),
// Metadata
whole_stream_command(Tags),
// Shells
whole_stream_command(Next),
whole_stream_command(Previous),
whole_stream_command(Shells),
whole_stream_command(Enter),
whole_stream_command(Exit),
// Viz
whole_stream_command(Chart),
// Viewers
whole_stream_command(Autoview),
whole_stream_command(Table),
// Text manipulation
whole_stream_command(Hash),
whole_stream_command(HashBase64),
whole_stream_command(Split),
whole_stream_command(SplitColumn),
whole_stream_command(SplitRow),
whole_stream_command(SplitChars),
whole_stream_command(Lines),
whole_stream_command(Echo),
whole_stream_command(Parse),
whole_stream_command(Str),
whole_stream_command(StrToDecimal),
whole_stream_command(StrToInteger),
whole_stream_command(StrDowncase),
whole_stream_command(StrUpcase),
whole_stream_command(StrCapitalize),
whole_stream_command(StrFindReplace),
whole_stream_command(StrFrom),
whole_stream_command(StrSubstring),
whole_stream_command(StrToDatetime),
whole_stream_command(StrContains),
whole_stream_command(StrIndexOf),
whole_stream_command(StrTrim),
whole_stream_command(StrTrimLeft),
whole_stream_command(StrTrimRight),
whole_stream_command(StrStartsWith),
whole_stream_command(StrEndsWith),
whole_stream_command(StrCollect),
whole_stream_command(StrLength),
whole_stream_command(StrLPad),
whole_stream_command(StrReverse),
whole_stream_command(StrRPad),
whole_stream_command(StrCamelCase),
whole_stream_command(StrPascalCase),
whole_stream_command(StrKebabCase),
whole_stream_command(StrSnakeCase),
whole_stream_command(StrScreamingSnakeCase),
whole_stream_command(BuildString),
whole_stream_command(Ansi),
whole_stream_command(Char),
// Column manipulation
whole_stream_command(Move),
whole_stream_command(Reject),
whole_stream_command(Select),
whole_stream_command(Get),
whole_stream_command(Update),
whole_stream_command(Insert),
whole_stream_command(IntoInt),
whole_stream_command(SplitBy),
// Row manipulation
whole_stream_command(Reverse),
whole_stream_command(Append),
whole_stream_command(Prepend),
whole_stream_command(SortBy),
whole_stream_command(GroupBy),
whole_stream_command(GroupByDate),
whole_stream_command(First),
whole_stream_command(Last),
whole_stream_command(Every),
whole_stream_command(Nth),
whole_stream_command(Drop),
whole_stream_command(Format),
whole_stream_command(FileSize),
whole_stream_command(Where),
whole_stream_command(If),
whole_stream_command(Compact),
whole_stream_command(Default),
whole_stream_command(Skip),
whole_stream_command(SkipUntil),
whole_stream_command(SkipWhile),
whole_stream_command(Keep),
whole_stream_command(KeepUntil),
whole_stream_command(KeepWhile),
whole_stream_command(Range),
whole_stream_command(Rename),
whole_stream_command(Uniq),
whole_stream_command(Each),
whole_stream_command(EachGroup),
whole_stream_command(EachWindow),
whole_stream_command(Empty),
// Table manipulation
whole_stream_command(Flatten),
whole_stream_command(Move),
whole_stream_command(Merge),
whole_stream_command(Shuffle),
whole_stream_command(Wrap),
whole_stream_command(Pivot),
whole_stream_command(Headers),
whole_stream_command(Reduce),
// Data processing
whole_stream_command(Histogram),
whole_stream_command(Autoenv),
whole_stream_command(AutoenvTrust),
whole_stream_command(AutoenvUnTrust),
whole_stream_command(Math),
whole_stream_command(MathAbs),
whole_stream_command(MathAverage),
whole_stream_command(MathEval),
whole_stream_command(MathMedian),
whole_stream_command(MathMinimum),
whole_stream_command(MathMode),
whole_stream_command(MathMaximum),
whole_stream_command(MathStddev),
whole_stream_command(MathSummation),
whole_stream_command(MathVariance),
whole_stream_command(MathProduct),
whole_stream_command(MathRound),
whole_stream_command(MathFloor),
whole_stream_command(MathCeil),
// File format output
whole_stream_command(To),
whole_stream_command(ToCSV),
whole_stream_command(ToHTML),
whole_stream_command(ToJSON),
whole_stream_command(ToMarkdown),
whole_stream_command(ToTOML),
whole_stream_command(ToTSV),
whole_stream_command(ToURL),
whole_stream_command(ToYAML),
whole_stream_command(ToXML),
// File format input
whole_stream_command(From),
whole_stream_command(FromCSV),
whole_stream_command(FromEML),
whole_stream_command(FromTSV),
whole_stream_command(FromSSV),
whole_stream_command(FromINI),
whole_stream_command(FromJSON),
whole_stream_command(FromODS),
whole_stream_command(FromTOML),
whole_stream_command(FromURL),
whole_stream_command(FromXLSX),
whole_stream_command(FromXML),
whole_stream_command(FromYAML),
whole_stream_command(FromYML),
whole_stream_command(FromIcs),
whole_stream_command(FromVcf),
// "Private" commands (not intended to be accessed directly)
whole_stream_command(RunExternalCommand { interactive }),
// Random value generation
whole_stream_command(Random),
whole_stream_command(RandomBool),
whole_stream_command(RandomDice),
#[cfg(feature = "uuid_crate")]
whole_stream_command(RandomUUID),
whole_stream_command(RandomInteger),
whole_stream_command(RandomDecimal),
whole_stream_command(RandomChars),
// Path
whole_stream_command(PathBasename),
whole_stream_command(PathCommand),
whole_stream_command(PathDirname),
whole_stream_command(PathExists),
whole_stream_command(PathExpand),
whole_stream_command(PathExtension),
whole_stream_command(PathFilestem),
whole_stream_command(PathType),
// Url
whole_stream_command(UrlCommand),
whole_stream_command(UrlScheme),
whole_stream_command(UrlPath),
whole_stream_command(UrlHost),
whole_stream_command(UrlQuery),
whole_stream_command(Seq),
whole_stream_command(SeqDates),
]);
#[cfg(feature = "clipboard-cli")]
{
context.add_commands(vec![whole_stream_command(crate::commands::clip::Clip)]);
}
}
Ok(context)
}

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
@ -23,19 +23,12 @@ impl WholeStreamCommand for Describe {
"Describes the objects in the stream."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
describe(args, registry).await
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
describe(args).await
}
}
pub async fn describe(
args: CommandArgs,
_registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
pub async fn describe(args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(args
.input
.map(|row| {

Some files were not shown because too many files have changed in this diff Show More