Compare commits

...

66 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
523 changed files with 7101 additions and 5338 deletions

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

1961
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.25.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.25.0", path = "./crates/nu-cli"}
nu-data = {version = "0.25.0", path = "./crates/nu-data"}
nu-errors = {version = "0.25.0", path = "./crates/nu-errors"}
nu-parser = {version = "0.25.0", path = "./crates/nu-parser"}
nu-plugin = {version = "0.25.0", path = "./crates/nu-plugin"}
nu-protocol = {version = "0.25.0", path = "./crates/nu-protocol"}
nu-source = {version = "0.25.0", path = "./crates/nu-source"}
nu-value-ext = {version = "0.25.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.25.0", path = "./crates/nu_plugin_binaryview", optional = true}
nu_plugin_chart = {version = "0.25.0", path = "./crates/nu_plugin_chart", optional = true}
nu_plugin_fetch = {version = "0.25.0", path = "./crates/nu_plugin_fetch", optional = true}
nu_plugin_from_bson = {version = "0.25.0", path = "./crates/nu_plugin_from_bson", optional = true}
nu_plugin_from_sqlite = {version = "0.25.0", path = "./crates/nu_plugin_from_sqlite", optional = true}
nu_plugin_inc = {version = "0.25.0", path = "./crates/nu_plugin_inc", optional = true}
nu_plugin_match = {version = "0.25.0", path = "./crates/nu_plugin_match", optional = true}
nu_plugin_post = {version = "0.25.0", path = "./crates/nu_plugin_post", optional = true}
nu_plugin_ps = {version = "0.25.0", path = "./crates/nu_plugin_ps", optional = true}
nu_plugin_s3 = {version = "0.25.0", path = "./crates/nu_plugin_s3", optional = true}
nu_plugin_start = {version = "0.25.0", path = "./crates/nu_plugin_start", optional = true}
nu_plugin_sys = {version = "0.25.0", path = "./crates/nu_plugin_sys", optional = true}
nu_plugin_textview = {version = "0.25.0", path = "./crates/nu_plugin_textview", optional = true}
nu_plugin_to_bson = {version = "0.25.0", path = "./crates/nu_plugin_to_bson", optional = true}
nu_plugin_to_sqlite = {version = "0.25.0", path = "./crates/nu_plugin_to_sqlite", optional = true}
nu_plugin_tree = {version = "0.25.0", path = "./crates/nu_plugin_tree", optional = true}
nu_plugin_xpath = {version = "0.25.0", path = "./crates/nu_plugin_xpath", optional = true}
nu_plugin_selector = {version = "0.25.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.25.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
@ -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

@ -5,80 +5,80 @@ description = "CLI for nushell"
edition = "2018"
license = "MIT"
name = "nu-cli"
version = "0.25.0"
version = "0.26.0"
[lib]
doctest = false
[dependencies]
nu-data = {version = "0.25.0", path = "../nu-data"}
nu-errors = {version = "0.25.0", path = "../nu-errors"}
nu-json = {version = "0.25.0", path = "../nu-json"}
nu-parser = {version = "0.25.0", path = "../nu-parser"}
nu-plugin = {version = "0.25.0", path = "../nu-plugin"}
nu-protocol = {version = "0.25.0", path = "../nu-protocol"}
nu-source = {version = "0.25.0", path = "../nu-source"}
nu-stream = {version = "0.25.0", path = "../nu-stream"}
nu-table = {version = "0.25.0", path = "../nu-table"}
nu-test-support = {version = "0.25.0", path = "../nu-test-support"}
nu-value-ext = {version = "0.25.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}
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"]}
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 = { 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}
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 = { version = "0.3.5", features = ["compat", "io-compat"] }
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-rc.1", optional = true}
htmlescape = "0.3.1"
ical = "0.6.0"
ichwh = {version = "0.3.4", optional = true}
indexmap = {version = "1.6.0", features = ["serde-1"]}
itertools = "0.9.0"
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-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}
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"
rustyline = {version = "6.3.0", optional = true}
serde = {version = "1.0.115", features = ["derive"]}
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"
@ -90,18 +90,18 @@ 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 = { 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}
trash = { version = "1.2.0", optional = true }
unicode-segmentation = "1.6.0"
uom = {version = "0.30.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}
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 }
shadow-rs = { version = "0.5", default-features = false, optional = true }
[target.'cfg(unix)'.dependencies]
umask = "1.0.0"
@ -126,8 +126,10 @@ quickcheck = "0.9.2"
quickcheck_macros = "0.9.1"
[features]
default = ["shadow-rs"]
clipboard-cli = ["arboard"]
rich-benchmark = ["heim"]
rustyline-support = ["rustyline"]
rustyline-support = ["rustyline", "nu-engine/rustyline-support"]
stable = []
trash-support = ["trash"]
dirs = ["dirs-next"]
directories = ["directories-next"]

View File

@ -1,27 +1,36 @@
use crate::commands::classified::block::run_block;
use crate::commands::default_context::create_default_context;
use crate::evaluation_context::EvaluationContext;
use crate::prelude::*;
use crate::script::{print_err, run_script_standalone};
use crate::line_editor::configure_ctrl_c;
use nu_command::commands::default_context::create_default_context;
#[allow(unused_imports)]
use nu_command::maybe_print_errors;
use nu_engine::run_block;
use nu_engine::EvaluationContext;
#[allow(unused_imports)]
pub(crate) use crate::script::{process_script, LineResult};
pub(crate) use nu_command::script::{process_script, LineResult};
#[cfg(feature = "rustyline-support")]
use crate::shell::Helper;
use crate::line_editor::{
configure_rustyline_editor, convert_rustyline_result_to_string,
default_rustyline_editor_configuration, nu_line_editor_helper,
};
#[allow(unused_imports)]
use nu_data::config;
use nu_source::{Tag, Text};
use nu_stream::InputStream;
#[allow(unused_imports)]
use std::sync::atomic::Ordering;
use nu_command::script::{print_err, run_script_standalone};
#[cfg(feature = "rustyline-support")]
use rustyline::{self, error::ReadlineError};
use crate::EnvironmentSyncer;
use nu_errors::ShellError;
use nu_parser::ParserScope;
use nu_protocol::{UntaggedValue, Value};
#[cfg(feature = "rustyline-support")]
use rustyline::{
self,
config::Configurer,
config::{ColorMode, CompletionType, Config},
error::ReadlineError,
At, Cmd, Editor, KeyPress, Movement, Word,
};
use std::error::Error;
use std::iter::Iterator;
use std::path::PathBuf;
@ -85,20 +94,6 @@ pub async fn run_script_file(
Ok(())
}
#[cfg(feature = "rustyline-support")]
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
}
}
}
/// The entry point for the CLI. Will register all known internal commands, load experimental commands, load plugins, then prepare the prompt and line reader for input.
#[cfg(feature = "rustyline-support")]
pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
@ -128,7 +123,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
// Give ourselves a scope to work in
context.scope.enter_scope();
let history_path = crate::commands::history::history_path(&configuration);
let history_path = nu_engine::history_path(&configuration);
let _ = rl.load_history(&history_path);
let mut session_text = String::new();
@ -168,17 +163,9 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
let (prompt_block, err) = nu_parser::parse(&prompt_line, 0, &context.scope);
if err.is_some() {
use crate::git::current_branch;
context.scope.exit_scope();
format!(
"\x1b[32m{}{}\x1b[m> ",
cwd,
match current_branch() {
Some(s) => format!("({})", s),
None => "".to_string(),
}
)
format!("\x1b[32m{}{}\x1b[m> ", cwd, current_branch())
} else {
// let env = context.get_env();
@ -189,7 +176,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
Ok(result) => match result.collect_string(Tag::unknown()).await {
Ok(string_result) => {
let errors = context.get_errors();
context.maybe_print_errors(Text::from(prompt_line));
maybe_print_errors(&context, Text::from(prompt_line));
context.clear_errors();
if !errors.is_empty() {
@ -214,15 +201,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
}
}
} else {
use crate::git::current_branch;
format!(
"\x1b[32m{}{}\x1b[m> ",
cwd,
match current_branch() {
Some(s) => format!("({})", s),
None => "".to_string(),
}
)
format!("\x1b[32m{}{}\x1b[m> ", cwd, current_branch())
}
};
@ -284,7 +263,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
LineResult::Success(line) => {
rl.add_history_entry(&line);
let _ = rl.save_history(&history_path);
context.maybe_print_errors(Text::from(session_text.clone()));
maybe_print_errors(&context, Text::from(session_text.clone()));
}
LineResult::ClearHistory => {
@ -300,7 +279,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
print_err(err, &Text::from(session_text.clone()));
});
context.maybe_print_errors(Text::from(session_text.clone()));
maybe_print_errors(&context, Text::from(session_text.clone()));
}
LineResult::CtrlC => {
@ -344,7 +323,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
}
pub fn register_plugins(context: &mut EvaluationContext) -> Result<(), ShellError> {
if let Ok(plugins) = crate::plugin::scan(search_paths()) {
if let Ok(plugins) = nu_engine::plugin::build_plugin::scan(search_paths()) {
context.add_commands(
plugins
.into_iter()
@ -356,23 +335,6 @@ pub fn register_plugins(context: &mut EvaluationContext) -> Result<(), ShellErro
Ok(())
}
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(())
}
async fn run_startup_commands(
context: &mut EvaluationContext,
config: &dyn nu_data::config::Conf,
@ -383,16 +345,17 @@ async fn run_startup_commands(
value: UntaggedValue::Table(pipelines),
..
} => {
let mut script_file = String::new();
for pipeline in pipelines {
if let Ok(pipeline_string) = pipeline.as_string() {
let _ = run_script_standalone(pipeline_string, false, context, false).await;
}
script_file.push_str(&pipeline.as_string()?);
script_file.push('\n');
}
let _ = run_script_standalone(script_file, false, context, false).await;
}
_ => {
return Err(ShellError::untagged_runtime_error(
"expected a table of pipeline strings as startup commands",
))
));
}
}
}
@ -400,187 +363,6 @@ async fn run_startup_commands(
Ok(())
}
#[cfg(feature = "rustyline-support")]
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")]
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")]
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")]
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 async fn parse_and_eval(line: &str, ctx: &EvaluationContext) -> Result<String, ShellError> {
// FIXME: do we still need this?
let line = if let Some(s) = line.strip_suffix('\n') {
@ -607,15 +389,32 @@ pub async fn parse_and_eval(line: &str, ctx: &EvaluationContext) -> Result<Strin
result?.collect_string(Tag::unknown()).await.map(|x| x.item)
}
#[allow(dead_code)]
fn current_branch() -> String {
#[cfg(feature = "shadow-rs")]
{
Some(shadow_rs::branch())
.map(|x| x.trim().to_string())
.filter(|x| !x.is_empty())
.map(|x| format!("({})", x))
.unwrap_or_default()
}
#[cfg(not(feature = "shadow-rs"))]
{
"".to_string()
}
}
#[cfg(test)]
mod tests {
use nu_engine::basic_evaluation_context;
#[quickcheck]
fn quickcheck_parse(data: String) -> bool {
let (tokens, err) = nu_parser::lex(&data, 0);
let (lite_block, err2) = nu_parser::group(tokens);
let (lite_block, err2) = nu_parser::block(tokens);
if err.is_none() && err2.is_none() {
let context = crate::evaluation_context::EvaluationContext::basic().unwrap();
let context = basic_evaluation_context().unwrap();
let _ = nu_parser::classify_block(&lite_block, &context.scope);
}
true

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,395 +0,0 @@
use crate::deserializer::ConfigDeserializer;
use crate::evaluate::evaluate_args::evaluate_args;
use crate::prelude::*;
use crate::{commands::help::get_help, run_block};
use derive_new::new;
use getset::Getters;
use nu_errors::ShellError;
use nu_protocol::hir::{self, Block};
use nu_protocol::{CallInfo, EvaluatedArgs, ReturnSuccess, Signature, UntaggedValue, Value};
use parking_lot::Mutex;
use serde::Deserialize;
use std::ops::Deref;
use std::sync::atomic::AtomicBool;
#[derive(Debug, Clone)]
pub struct UnevaluatedCallInfo {
pub args: hir::Call,
pub name_tag: Tag,
}
impl UnevaluatedCallInfo {
pub async fn evaluate(self, ctx: &EvaluationContext) -> Result<CallInfo, ShellError> {
let args = evaluate_args(&self.args, ctx).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 scope: Scope,
pub input: InputStream,
}
#[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 scope: Scope,
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,
scope: self.scope,
input: input.into(),
}
}
}
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) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
let ctx = EvaluationContext::from_args(&self);
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(&ctx).await?;
let scope = self.scope.clone();
Ok(EvaluatedWholeStreamCommandArgs::new(
host,
ctrl_c,
shell_manager,
call_info,
input,
scope,
))
}
pub async fn process<'de, T: Deserialize<'de>>(self) -> Result<(T, InputStream), ShellError> {
let args = self.evaluate_once().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 scope: Scope,
pub name: Tag,
}
impl RunnableContext {
pub fn get_command(&self, name: &str) -> Option<Command> {
self.scope.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>,
scope: Scope,
) -> EvaluatedWholeStreamCommandArgs {
EvaluatedWholeStreamCommandArgs {
args: EvaluatedCommandArgs {
host,
ctrl_c,
shell_manager,
call_info,
scope,
},
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,
pub scope: Scope,
}
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) -> 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()
}
}
// Custom commands are blocks, so we can use the information in the block to also
// implement a WholeStreamCommand
#[allow(clippy::suspicious_else_formatting)]
#[async_trait]
impl WholeStreamCommand for Block {
fn name(&self) -> &str {
&self.params.name
}
fn signature(&self) -> Signature {
self.params.clone()
}
fn usage(&self) -> &str {
""
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let call_info = args.call_info.clone();
let mut block = self.clone();
block.set_redirect(call_info.args.external_redirection);
let ctx = EvaluationContext::from_args(&args);
let evaluated = call_info.evaluate(&ctx).await?;
let input = args.input;
ctx.scope.enter_scope();
if let Some(args) = evaluated.args.positional {
// FIXME: do not do this
for arg in args.into_iter().zip(self.params.positional.iter()) {
let name = arg.1 .0.name();
if name.starts_with('$') {
ctx.scope.add_var(name, arg.0);
} else {
ctx.scope.add_var(format!("${}", name), arg.0);
}
}
}
if let Some(args) = evaluated.args.named {
for named in &block.params.named {
let name = named.0;
if let Some(value) = args.get(name) {
if name.starts_with('$') {
ctx.scope.add_var(name, value.clone());
} else {
ctx.scope.add_var(format!("${}", name), value.clone());
}
} else if name.starts_with('$') {
ctx.scope
.add_var(name, UntaggedValue::nothing().into_untagged_value());
} else {
ctx.scope.add_var(
format!("${}", name),
UntaggedValue::nothing().into_untagged_value(),
);
}
}
} else {
for named in &block.params.named {
let name = named.0;
if name.starts_with('$') {
ctx.scope
.add_var(name, UntaggedValue::nothing().into_untagged_value());
} else {
ctx.scope.add_var(
format!("${}", name),
UntaggedValue::nothing().into_untagged_value(),
);
}
}
}
let result = run_block(&block, &ctx, input).await;
ctx.scope.exit_scope();
result.map(|x| x.to_output_stream())
}
fn is_binary(&self) -> bool {
false
}
fn is_internal(&self) -> bool {
false
}
fn examples(&self) -> Vec<Example> {
vec![]
}
}
#[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) -> Result<OutputStream, ShellError> {
if args.call_info.switch_present("help") {
let cl = self.0.clone();
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
UntaggedValue::string(get_help(&*cl, &args.scope)).into_value(Tag::unknown()),
))))
} else {
self.0.run(args).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,62 +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) -> 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,55 +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) -> 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,115 +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) -> Result<OutputStream, ShellError> {
operate(args).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) -> Result<OutputStream, ShellError> {
let (Arguments { replace, rest }, input) = args.process().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,136 +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, alias or custom command."
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
which(args).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! create_entry {
($arg:expr, $path:expr, $tag:expr, $is_builtin:expr) => {
entry(
$arg.clone(),
UntaggedValue::Primitive(Primitive::String($path.to_string())).into_value($tag.clone()),
$is_builtin,
$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) -> Result<OutputStream, ShellError> {
let mut output = vec![];
let scope = args.scope.clone();
let (WhichArgs { application, all }, _) = args.process().await?;
let external = application.starts_with('^');
let item = if external {
application.item[1..].to_string()
} else {
application.item.clone()
};
if !external {
if let Some(entry) = entry_for(&scope, &item, application.tag.clone()) {
output.push(ReturnSuccess::value(entry));
}
}
#[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())
}
}
fn entry_for(scope: &Scope, name: &str, tag: Tag) -> Option<Value> {
if scope.has_custom_command(name) {
Some(create_entry!(name, "Nushell custom command", tag, false))
} else if scope.has_command(name) {
Some(create_entry!(name, "Nushell built-in command", tag, true))
} else if scope.has_alias(name) {
Some(create_entry!(name, "Nushell alias", tag, false))
} else {
None
}
}
#[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;

View File

@ -256,7 +256,7 @@ pub fn completion_location(line: &str, block: &Block, pos: usize) -> Vec<Complet
mod tests {
use super::*;
use nu_parser::{classify_block, group, lex, ParserScope};
use nu_parser::{block, classify_block, lex, ParserScope};
use nu_protocol::{Signature, SyntaxShape};
#[derive(Clone, Debug)]
@ -307,7 +307,7 @@ mod tests {
pos: usize,
) -> Vec<LocationType> {
let (tokens, _) = lex(line, 0);
let (lite_block, _) = group(tokens);
let (lite_block, _) = block(tokens);
scope.enter_scope();
let (block, _) = classify_block(&lite_block, scope);

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,

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

@ -29,7 +29,7 @@ impl PathCompleter {
{
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,6 +1,7 @@
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::{atomic::Ordering, Arc};
@ -152,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;
@ -170,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(
@ -202,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
@ -273,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(
@ -372,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(
@ -448,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"),
@ -535,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,493 +0,0 @@
use nu_errors::ShellError;
use nu_parser::ParserScope;
use nu_protocol::hir::ClassifiedBlock;
use nu_protocol::{
Primitive, ReturnSuccess, ShellTypeName, Signature, SyntaxShape, UntaggedValue, Value,
};
use nu_source::{AnchorLocation, TaggedItem};
use crate::prelude::*;
use num_bigint::BigInt;
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, Let, Nth,
StrCollect, WholeStreamCommand, Wrap,
};
use crate::evaluation_context::EvaluationContext;
use nu_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 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(Let {}),
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, &ctx)?;
println!("{:#?}", block);
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 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(Let {}),
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, &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 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(Let {}),
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, &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: &EvaluationContext) -> Result<ClassifiedBlock, ShellError> {
//FIXME: do we still need this?
let line = if let Some(line) = line.strip_suffix('\n') {
line
} else {
line
};
let (lite_result, err) = nu_parser::lex(&line, 0);
if let Some(err) = err {
return Err(err.into());
}
let (lite_result, err) = nu_parser::group(lite_result);
if let Some(err) = err {
return Err(err.into());
}
// TODO ensure the command whose examples we're testing is actually in the pipeline
let (block, err) = nu_parser::classify_block(&lite_result, &ctx.scope);
Ok(ClassifiedBlock { block, failed: err })
}
async fn evaluate_block(
block: ClassifiedBlock,
ctx: &mut EvaluationContext,
) -> Result<Vec<Value>, ShellError> {
let input_stream = InputStream::empty();
let env = ctx.get_env();
ctx.scope.enter_scope();
ctx.scope.add_env(env);
let result = run_block(&block.block, ctx, input_stream).await;
ctx.scope.exit_scope();
let result = result?.drain_vec().await;
Ok(result)
}
// 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) -> Result<OutputStream, ShellError> {
let name_tag = args.call_info.name_tag.clone();
let (
Arguments {
path: mocked_path,
open: open_mock,
},
_input,
) = args.process().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) -> Result<OutputStream, ShellError> {
let name_tag = args.call_info.name_tag.clone();
let (MockEchoArgs { rest }, input) = args.process().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) -> 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,45 +14,23 @@ extern crate quickcheck;
extern crate quickcheck_macros;
mod cli;
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;
pub mod script;
mod line_editor;
mod shell;
pub mod types;
pub mod utils;
#[cfg(test)]
mod examples;
#[cfg(feature = "rustyline-support")]
pub use crate::cli::cli;
pub use crate::cli::{parse_and_eval, register_plugins, run_script_file};
pub use crate::commands::classified::block::run_block;
pub use crate::commands::command::{
whole_stream_command, CommandArgs, EvaluatedWholeStreamCommandArgs, Example, WholeStreamCommand,
};
pub use crate::commands::default_context::create_default_context;
pub use crate::commands::help::get_help;
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 nu_command::commands::default_context::create_default_context;
pub use nu_data::config;
pub use nu_data::dict::TaggedListBuilder;
pub use nu_data::primitive;

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)
);
});
nu_stream::InputStream::from_stream(objects.boxed())
} else {
$expr
}
}};
}
#[macro_export]
macro_rules! trace_out_stream {
(target: $target:tt, $desc:tt = $expr:expr) => {{
@ -68,44 +46,17 @@ macro_rules! trace_out_stream {
}};
}
pub(crate) use nu_protocol::{errln, out, outln, row};
use nu_source::HasFallibleSpan;
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::evaluate::scope::Scope;
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 bigdecimal::BigDecimal;
pub(crate) use futures::stream::BoxStream;
pub(crate) use futures::{Stream, StreamExt};
pub(crate) use nu_engine::Host;
#[allow(unused_imports)]
pub(crate) use nu_errors::ShellError;
pub(crate) use nu_parser::ParserScope;
pub(crate) use nu_source::{
b, AnchorLocation, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource, Span, SpannedItem, Tag,
TaggedItem, Text,
};
pub(crate) use nu_stream::{InputStream, InterruptibleStream, OutputStream};
#[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, Ordering};
pub(crate) use std::sync::Arc;
pub(crate) use async_trait::async_trait;
pub(crate) use indexmap::{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;
@ -122,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;
}
@ -157,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,7 @@ 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;

View File

@ -1,12 +1,8 @@
use std::borrow::Cow::{self, Owned};
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,
@ -123,7 +119,7 @@ impl rustyline::validate::Validator for NuValidator {
}
}
let (_, err) = nu_parser::group(tokens);
let (_, err) = nu_parser::block(tokens);
if let Some(err) = err {
if let nu_errors::ParseErrorReason::Eof { .. } = err.reason() {
@ -148,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,6 +1,8 @@
#![allow(dead_code)]
use crate::prelude::*;
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::ParserScope;
use nu_protocol::{
@ -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,
@ -296,7 +295,7 @@ fn get_shape_of_expr(expr: &SpannedExpression) -> Option<SyntaxShape> {
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),

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

@ -7,7 +7,7 @@ mod to_delimited_data;
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;
@ -20,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;
@ -30,7 +30,7 @@ pub(crate) mod date;
pub(crate) mod debug;
pub(crate) mod def;
pub(crate) mod default;
pub(crate) mod default_context;
pub mod default_context;
pub(crate) mod describe;
pub(crate) mod do_;
pub(crate) mod drop;
@ -136,9 +136,6 @@ 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 ansi::Ansi;
pub(crate) use append::Command as Append;
@ -263,8 +260,8 @@ 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;
@ -290,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> {
@ -302,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'),
@ -119,7 +119,7 @@ Format: #
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let (AnsiArgs { color, escape, osc }, _) = args.process().await?;
let (AnsiArgs { code, escape, osc }, _) = args.process().await?;
if let Some(e) = escape {
let esc_vec: Vec<char> = e.item.chars().collect();
@ -145,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);
@ -153,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()),
@ -222,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,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};

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;
@ -63,8 +63,7 @@ The file can contain several optional sections:
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(crate::commands::help::get_help(&Autoenv, &args.scope))
.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};

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};

View File

@ -1,8 +1,8 @@
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, Signature, UntaggedValue, Value};
@ -134,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).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());

View File

@ -1,8 +1,8 @@
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, CapturedBlock, ClassifiedCommand, Group, InternalCommand, Pipeline},
@ -81,22 +81,22 @@ async fn benchmark(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
let start_time = Instant::now();
#[cfg(feature = "rich-benchmark")]
let start = time().await;
// #[cfg(feature = "rich-benchmark")]
// let start = time().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);
@ -105,28 +105,28 @@ async fn benchmark(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
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).await
} else {
Err(ShellError::untagged_runtime_error(
"Could not retrieve 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>(

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)]

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};

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",
)
}

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,
@ -130,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};
@ -28,8 +28,7 @@ impl WholeStreamCommand for Chart {
}
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
UntaggedValue::string(crate::commands::help::get_help(&Chart, &args.scope))
.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;
@ -18,6 +18,7 @@ use nu_protocol::hir::Expression;
use nu_protocol::hir::{ExternalCommand, ExternalRedirection};
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,
@ -95,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"))]
{
@ -221,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(());
@ -464,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)
@ -533,15 +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_test_support::commands::ExternalBuilder;
// async fn read(mut stream: OutputStream) -> Option<Value> {
// match stream.try_next().await {
// Ok(val) => {
@ -562,7 +563,7 @@ 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, ExternalRedirection::Stdout)
@ -576,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;

View File

@ -1,6 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use futures::stream::StreamExt;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, Value};

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,7 +1,7 @@
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;

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};

View File

@ -1,8 +1,9 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use crate::{CommandArgs, 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;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};

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};
use nu_source::Tagged;
@ -21,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",
)
}

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue};
@ -36,6 +36,6 @@ 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,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};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};

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;

View File

@ -1,6 +1,6 @@
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};

View File

@ -1,19 +1,10 @@
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 {
@ -22,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",

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};
@ -21,8 +21,7 @@ impl WholeStreamCommand for Command {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(crate::commands::help::get_help(&Command, &args.scope))
.into_value(Tag::unknown()),
UntaggedValue::string(get_help(&Command, &args.scope)).into_value(Tag::unknown()),
)))
}
}

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
Dictionary, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
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};

View File

@ -1,6 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use chrono::{DateTime, Local};
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, UntaggedValue};

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
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};

View File

@ -1,6 +1,6 @@
use crate::commands::date::parser::{datetime_in_timezone, ParseErrorKind};
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;

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;

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};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{hir::CapturedBlock, Signature, SyntaxShape, Value};

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;

View File

@ -1,8 +1,10 @@
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 = EvaluationContext::basic()?;
let context = basic_evaluation_context()?;
{
use crate::commands::*;
@ -89,7 +91,6 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
whole_stream_command(StrFindReplace),
whole_stream_command(StrFrom),
whole_stream_command(StrSubstring),
whole_stream_command(StrSet),
whole_stream_command(StrToDatetime),
whole_stream_command(StrContains),
whole_stream_command(StrIndexOf),

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};

View File

@ -1,6 +1,6 @@
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::run_block;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{hir::CapturedBlock, hir::ExternalRedirection, Signature, SyntaxShape, Value};

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, SyntaxShape, UntaggedValue};
use nu_source::Tagged;

View File

@ -0,0 +1,173 @@
use crate::prelude::*;
use glob::*;
use nu_engine::WholeStreamCommand;
use nu_engine::{DirBuilder, DirInfo, FileInfo};
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape};
use nu_source::Tagged;
use std::path::PathBuf;
const NAME: &str = "du";
const GLOB_PARAMS: MatchOptions = MatchOptions {
case_sensitive: true,
require_literal_separator: true,
require_literal_leading_dot: false,
};
pub struct Du;
#[derive(Deserialize, Clone)]
pub struct DuArgs {
path: Option<Tagged<PathBuf>>,
all: bool,
deref: bool,
exclude: Option<Tagged<String>>,
#[serde(rename = "max-depth")]
max_depth: Option<Tagged<u64>>,
#[serde(rename = "min-size")]
min_size: Option<Tagged<u64>>,
}
#[async_trait]
impl WholeStreamCommand for Du {
fn name(&self) -> &str {
NAME
}
fn signature(&self) -> Signature {
Signature::build(NAME)
.optional("path", SyntaxShape::GlobPattern, "starting directory")
.switch(
"all",
"Output file sizes as well as directory sizes",
Some('a'),
)
.switch(
"deref",
"Dereference symlinks to their targets for size",
Some('r'),
)
.named(
"exclude",
SyntaxShape::GlobPattern,
"Exclude these file names",
Some('x'),
)
.named(
"max-depth",
SyntaxShape::Int,
"Directory recursion limit",
Some('d'),
)
.named(
"min-size",
SyntaxShape::Int,
"Exclude files below this size",
Some('m'),
)
}
fn usage(&self) -> &str {
"Find disk usage sizes of specified items"
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
du(args).await
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Disk usage of the current directory",
example: "du",
result: None,
}]
}
}
async fn du(args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let ctrl_c = args.ctrl_c.clone();
let ctrl_c_copy = ctrl_c.clone();
let (args, _): (DuArgs, _) = args.process().await?;
let exclude = args.exclude.map_or(Ok(None), move |x| {
Pattern::new(&x.item)
.map(Option::Some)
.map_err(|e| ShellError::labeled_error(e.msg, "glob error", x.tag.clone()))
})?;
let include_files = args.all;
let paths = match args.path {
Some(p) => {
let p = p.item.to_str().expect("Why isn't this encoded properly?");
glob::glob_with(p, GLOB_PARAMS)
}
None => glob::glob_with("*", GLOB_PARAMS),
}
.map_err(|e| ShellError::labeled_error(e.msg, "glob error", tag.clone()))?
.filter(move |p| {
if include_files {
true
} else {
match p {
Ok(f) if f.is_dir() => true,
Err(e) if e.path().is_dir() => true,
_ => false,
}
}
})
.map(|v| v.map_err(glob_err_into));
let all = args.all;
let deref = args.deref;
let max_depth = args.max_depth.map(|f| f.item);
let min_size = args.min_size.map(|f| f.item);
let params = DirBuilder {
tag: tag.clone(),
min: min_size,
deref,
exclude,
all,
};
let inp = futures::stream::iter(paths);
Ok(inp
.flat_map(move |path| match path {
Ok(p) => {
let mut output = vec![];
if p.is_dir() {
output.push(Ok(ReturnSuccess::Value(
DirInfo::new(p, &params, max_depth, ctrl_c.clone()).into(),
)));
} else {
for v in FileInfo::new(p, deref, tag.clone()).into_iter() {
output.push(Ok(ReturnSuccess::Value(v.into())));
}
}
futures::stream::iter(output)
}
Err(e) => futures::stream::iter(vec![Err(e)]),
})
.interruptible(ctrl_c_copy)
.to_output_stream())
}
fn glob_err_into(e: GlobError) -> ShellError {
let e = e.into_error();
ShellError::from(e)
}
#[cfg(test)]
mod tests {
use super::Du;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Du {})?)
}
}

View File

@ -1,6 +1,6 @@
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::run_block;
use nu_engine::WholeStreamCommand;
use futures::stream::once;
use nu_errors::ShellError;

View File

@ -1,6 +1,6 @@
use crate::commands::each::process_row;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
hir::CapturedBlock, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,

View File

@ -1,6 +1,6 @@
use crate::commands::each::group::run_block_on_vec;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
//use itertools::Itertools;
use nu_errors::ShellError;
use nu_protocol::{hir::CapturedBlock, Primitive, Signature, SyntaxShape, UntaggedValue};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::hir::Operator;
use nu_protocol::{
@ -76,6 +76,7 @@ struct RangeIterator {
end: Primitive,
tag: Tag,
is_end_inclusive: bool,
moves_up: bool,
}
impl RangeIterator {
@ -85,9 +86,15 @@ impl RangeIterator {
x => x,
};
let end = match range.to.0.item {
Primitive::Nothing => Primitive::Int(u64::MAX.into()),
x => x,
};
RangeIterator {
moves_up: start <= end,
curr: start,
end: range.to.0.item,
end,
tag,
is_end_inclusive: matches!(range.to.1, RangeInclusion::Inclusive),
}
@ -121,7 +128,9 @@ impl Iterator for RangeIterator {
use std::cmp::Ordering;
if (ordering == Ordering::Less) || (self.is_end_inclusive && ordering == Ordering::Equal) {
if self.moves_up
&& (ordering == Ordering::Less || self.is_end_inclusive && ordering == Ordering::Equal)
{
let output = UntaggedValue::Primitive(self.curr.clone()).into_value(self.tag.clone());
let next_value = nu_data::value::compute_values(
@ -130,6 +139,35 @@ impl Iterator for RangeIterator {
&UntaggedValue::int(1),
);
self.curr = match next_value {
Ok(result) => match result {
UntaggedValue::Primitive(p) => p,
_ => {
return Some(Err(ShellError::unimplemented(
"Internal error: expected a primitive result from increment",
)));
}
},
Err((left_type, right_type)) => {
return Some(Err(ShellError::coerce_error(
left_type.spanned(self.tag.span),
right_type.spanned(self.tag.span),
)));
}
};
Some(ReturnSuccess::value(output))
} else if !self.moves_up
&& (ordering == Ordering::Greater
|| self.is_end_inclusive && ordering == Ordering::Equal)
{
let output = UntaggedValue::Primitive(self.curr.clone()).into_value(self.tag.clone());
let next_value = nu_data::value::compute_values(
Operator::Plus,
&UntaggedValue::Primitive(self.curr.clone()),
&UntaggedValue::int(-1),
);
self.curr = match next_value {
Ok(result) => match result {
UntaggedValue::Primitive(p) => p,
@ -148,7 +186,6 @@ impl Iterator for RangeIterator {
};
Some(ReturnSuccess::value(output))
} else {
// TODO: add inclusive/exclusive ranges
None
}
}

View File

@ -1,6 +1,6 @@
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::run_block;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
hir::CapturedBlock, ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape,

View File

@ -1,6 +1,6 @@
use crate::commands::UnevaluatedCallInfo;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::UnevaluatedCallInfo;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::hir::ExternalRedirection;
use nu_protocol::{
@ -27,7 +27,7 @@ impl WholeStreamCommand for Enter {
Signature::build("enter")
.required(
"location",
SyntaxShape::Path,
SyntaxShape::FilePath,
"the location to create a new shell from",
)
.named(

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};
use nu_source::Tagged;

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, SyntaxShape};
use nu_source::Tagged;
@ -21,8 +21,11 @@ impl WholeStreamCommand for Exec {
fn signature(&self) -> Signature {
Signature::build("exec")
.required("command", SyntaxShape::Path, "the command to execute")
.rest(SyntaxShape::Pattern, "any additional arguments for command")
.required("command", SyntaxShape::FilePath, "the command to execute")
.rest(
SyntaxShape::GlobPattern,
"any additional arguments for command",
)
}
fn usage(&self) -> &str {

View File

@ -1,4 +1,3 @@
use crate::commands::command::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{CommandAction, ReturnSuccess, Signature};

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, SyntaxShape, UntaggedValue};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
Dictionary, ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value,

View File

@ -1,6 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*;
use nu_engine::evaluate_baseline_expr;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged;

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