Compare commits

..

1 Commits

Author SHA1 Message Date
Darren Schroeder
70859ffe70
Revert "Fix issue with head on separation lines (#13291)"
This reverts commit 32db5d3aa3.
2024-07-08 13:24:19 -05:00
408 changed files with 3762 additions and 15395 deletions

View File

@ -26,13 +26,6 @@ updates:
patterns:
- "polars"
- "polars-*"
# uutils/coreutils also versions all their workspace crates the same at the moment
# Most of them have bleeding edge version requirements (some not)
# see: https://github.com/uutils/coreutils/blob/main/Cargo.toml
uutils:
patterns:
- "uucore"
- "uu_*"
- package-ecosystem: "github-actions"
directory: "/"
schedule:

View File

@ -161,7 +161,7 @@ jobs:
# REF: https://github.com/marketplace/actions/gh-release
# Create a release only in nushell/nightly repo
- name: Publish Archive
uses: softprops/action-gh-release@v2.0.8
uses: softprops/action-gh-release@v2.0.6
if: ${{ startsWith(github.repository, 'nushell/nightly') }}
with:
prerelease: true

View File

@ -161,12 +161,8 @@ if $os in ['macos-latest'] or $USE_UBUNTU {
let releaseStem = $'($bin)-($version)-($target)'
print $'(char nl)Download less related stuffs...'; hr-line
# todo: less-v661 is out but is released as a zip file. maybe we should switch to that and extract it?
aria2c https://github.com/jftuga/less-Windows/releases/download/less-v608/less.exe -o less.exe
# the below was renamed because it was failing to download for darren. it should work but it wasn't
# todo: maybe we should get rid of this aria2c dependency and just use http get?
#aria2c https://raw.githubusercontent.com/jftuga/less-Windows/master/LICENSE -o LICENSE-for-less.txt
aria2c https://github.com/jftuga/less-Windows/blob/master/LICENSE -o LICENSE-for-less.txt
aria2c https://raw.githubusercontent.com/jftuga/less-Windows/master/LICENSE -o LICENSE-for-less.txt
# Create Windows msi release package
if (get-env _EXTRA_) == 'msi' {

View File

@ -91,7 +91,7 @@ jobs:
# REF: https://github.com/marketplace/actions/gh-release
- name: Publish Archive
uses: softprops/action-gh-release@v2.0.8
uses: softprops/action-gh-release@v2.0.6
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
draft: true

View File

@ -10,4 +10,4 @@ jobs:
uses: actions/checkout@v4.1.7
- name: Check spelling
uses: crate-ci/typos@v1.23.5
uses: crate-ci/typos@v1.22.9

192
Cargo.lock generated
View File

@ -605,7 +605,7 @@ dependencies = [
"encoding_rs",
"log",
"once_cell",
"quick-xml 0.31.0",
"quick-xml",
"serde",
"zip",
]
@ -1219,24 +1219,24 @@ dependencies = [
]
[[package]]
name = "dirs"
version = "5.0.1"
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"dirs-sys",
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys"
version = "0.4.1"
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.48.0",
"winapi",
]
[[package]]
@ -2342,9 +2342,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.155"
version = "0.2.154"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
[[package]]
name = "libflate"
@ -2868,12 +2868,12 @@ dependencies = [
[[package]]
name = "nu"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"assert_cmd",
"crossterm",
"ctrlc",
"dirs",
"dirs-next",
"log",
"miette",
"mimalloc",
@ -2900,7 +2900,6 @@ dependencies = [
"openssl",
"pretty_assertions",
"reedline",
"regex",
"rstest",
"serde_json",
"serial_test",
@ -2913,16 +2912,16 @@ dependencies = [
[[package]]
name = "nu-ansi-term"
version = "0.50.1"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14"
dependencies = [
"windows-sys 0.52.0",
"windows-sys 0.48.0",
]
[[package]]
name = "nu-cli"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"chrono",
"crossterm",
@ -2957,7 +2956,7 @@ dependencies = [
[[package]]
name = "nu-cmd-base"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"indexmap",
"miette",
@ -2969,7 +2968,7 @@ dependencies = [
[[package]]
name = "nu-cmd-extra"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"fancy-regex",
"heck 0.5.0",
@ -2994,7 +2993,7 @@ dependencies = [
[[package]]
name = "nu-cmd-lang"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"itertools 0.12.1",
"nu-engine",
@ -3006,7 +3005,7 @@ dependencies = [
[[package]]
name = "nu-cmd-plugin"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"itertools 0.12.1",
"nu-engine",
@ -3017,7 +3016,7 @@ dependencies = [
[[package]]
name = "nu-color-config"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"nu-ansi-term",
"nu-engine",
@ -3029,7 +3028,7 @@ dependencies = [
[[package]]
name = "nu-command"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"alphanumeric-sort",
"base64 0.22.1",
@ -3047,7 +3046,7 @@ dependencies = [
"deunicode",
"dialoguer",
"digest",
"dirs",
"dirs-next",
"dtparse",
"encoding_rs",
"fancy-regex",
@ -3094,7 +3093,7 @@ dependencies = [
"pretty_assertions",
"print-positions",
"procfs",
"quick-xml 0.31.0",
"quick-xml",
"quickcheck",
"quickcheck_macros",
"rand",
@ -3139,7 +3138,7 @@ dependencies = [
[[package]]
name = "nu-derive-value"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"convert_case",
"proc-macro-error",
@ -3150,19 +3149,17 @@ dependencies = [
[[package]]
name = "nu-engine"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"log",
"nu-glob",
"nu-path",
"nu-protocol",
"nu-utils",
"terminal_size",
]
[[package]]
name = "nu-explore"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"ansi-str",
"anyhow",
@ -3187,19 +3184,16 @@ dependencies = [
[[package]]
name = "nu-glob"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"doc-comment",
]
[[package]]
name = "nu-json"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"fancy-regex",
"linked-hash-map",
"nu-path",
"nu-test-support",
"num-traits",
"serde",
"serde_json",
@ -3207,7 +3201,7 @@ dependencies = [
[[package]]
name = "nu-lsp"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"assert-json-diff",
"crossbeam-channel",
@ -3228,7 +3222,7 @@ dependencies = [
[[package]]
name = "nu-parser"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"bytesize",
"chrono",
@ -3244,16 +3238,16 @@ dependencies = [
[[package]]
name = "nu-path"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"dirs",
"dirs-next",
"omnipath",
"pwd",
]
[[package]]
name = "nu-plugin"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"log",
"nix",
@ -3261,7 +3255,6 @@ dependencies = [
"nu-plugin-core",
"nu-plugin-protocol",
"nu-protocol",
"nu-utils",
"serde",
"thiserror",
"typetag",
@ -3269,7 +3262,7 @@ dependencies = [
[[package]]
name = "nu-plugin-core"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"interprocess",
"log",
@ -3283,7 +3276,7 @@ dependencies = [
[[package]]
name = "nu-plugin-engine"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"log",
"nu-engine",
@ -3291,7 +3284,6 @@ dependencies = [
"nu-plugin-protocol",
"nu-protocol",
"nu-system",
"nu-utils",
"serde",
"typetag",
"windows 0.54.0",
@ -3299,7 +3291,7 @@ dependencies = [
[[package]]
name = "nu-plugin-protocol"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"bincode",
"nu-protocol",
@ -3311,7 +3303,7 @@ dependencies = [
[[package]]
name = "nu-plugin-test-support"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"nu-ansi-term",
"nu-cmd-lang",
@ -3329,7 +3321,7 @@ dependencies = [
[[package]]
name = "nu-pretty-hex"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"heapless",
"nu-ansi-term",
@ -3338,18 +3330,15 @@ dependencies = [
[[package]]
name = "nu-protocol"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"brotli",
"byte-unit",
"chrono",
"chrono-humanize",
"convert_case",
"dirs",
"dirs-sys",
"fancy-regex",
"indexmap",
"log",
"lru",
"miette",
"nix",
@ -3370,12 +3359,11 @@ dependencies = [
"tempfile",
"thiserror",
"typetag",
"windows-sys 0.48.0",
]
[[package]]
name = "nu-std"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"log",
"miette",
@ -3386,7 +3374,7 @@ dependencies = [
[[package]]
name = "nu-system"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"chrono",
"itertools 0.12.1",
@ -3404,7 +3392,7 @@ dependencies = [
[[package]]
name = "nu-table"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"fancy-regex",
"nu-ansi-term",
@ -3418,7 +3406,7 @@ dependencies = [
[[package]]
name = "nu-term-grid"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"nu-utils",
"unicode-width",
@ -3426,7 +3414,7 @@ dependencies = [
[[package]]
name = "nu-test-support"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"nu-glob",
"nu-path",
@ -3438,7 +3426,7 @@ dependencies = [
[[package]]
name = "nu-utils"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"crossterm_winapi",
"log",
@ -3464,7 +3452,7 @@ dependencies = [
[[package]]
name = "nu_plugin_example"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"nu-cmd-lang",
"nu-plugin",
@ -3474,22 +3462,20 @@ dependencies = [
[[package]]
name = "nu_plugin_formats"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"chrono",
"eml-parser",
"ical",
"indexmap",
"nu-plugin",
"nu-plugin-test-support",
"nu-protocol",
"plist",
"rust-ini",
]
[[package]]
name = "nu_plugin_gstat"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"git2",
"nu-plugin",
@ -3498,7 +3484,7 @@ dependencies = [
[[package]]
name = "nu_plugin_inc"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"nu-plugin",
"nu-protocol",
@ -3507,7 +3493,7 @@ dependencies = [
[[package]]
name = "nu_plugin_polars"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"chrono",
"chrono-tz 0.9.0",
@ -3541,7 +3527,7 @@ dependencies = [
[[package]]
name = "nu_plugin_query"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"gjson",
"nu-plugin",
@ -3556,7 +3542,7 @@ dependencies = [
[[package]]
name = "nu_plugin_stress_internals"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"interprocess",
"serde",
@ -3682,7 +3668,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "nuon"
version = "0.96.2"
version = "0.95.1"
dependencies = [
"chrono",
"fancy-regex",
@ -3779,9 +3765,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "open"
version = "5.3.0"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3"
checksum = "9d2c909a3fce3bd80efef4cd1c6c056bd9376a8fe06fcfdbebaf32cb485a7e37"
dependencies = [
"is-wsl",
"libc",
@ -3790,9 +3776,9 @@ dependencies = [
[[package]]
name = "openssl"
version = "0.10.66"
version = "0.10.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
dependencies = [
"bitflags 2.5.0",
"cfg-if",
@ -3831,9 +3817,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.103"
version = "0.9.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2"
dependencies = [
"cc",
"libc",
@ -3842,12 +3828,6 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "ordered-multimap"
version = "0.7.3"
@ -4150,19 +4130,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "plist"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
dependencies = [
"base64 0.22.1",
"indexmap",
"quick-xml 0.32.0",
"serde",
"time",
]
[[package]]
name = "polars"
version = "0.41.2"
@ -4831,15 +4798,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "quick-xml"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
dependencies = [
"memchr",
]
[[package]]
name = "quickcheck"
version = "1.0.3"
@ -5029,8 +4987,8 @@ dependencies = [
[[package]]
name = "reedline"
version = "0.33.0"
source = "git+https://github.com/nushell/reedline?branch=main#919292e40fd417e3da882692021961b444150c59"
version = "0.32.0"
source = "git+https://github.com/nushell/reedline?branch=main#480059a3f52cf919341cda88e8c544edd846bc73"
dependencies = [
"arboard",
"chrono",
@ -5244,9 +5202,9 @@ dependencies = [
[[package]]
name = "rust-embed"
version = "8.5.0"
version = "8.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0"
checksum = "19549741604902eb99a7ed0ee177a0663ee1eda51a29f71401f166e47e77806a"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
@ -5613,9 +5571,9 @@ dependencies = [
[[package]]
name = "shadow-rs"
version = "0.30.0"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d253e54681d4be0161e965db57974ae642a0b6aaeb18a999424c4dab062be8c5"
checksum = "0a600f795d0894cda22235b44eea4b85c2a35b405f65523645ac8e35b306817a"
dependencies = [
"const_format",
"is_debug",
@ -5690,9 +5648,9 @@ checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
[[package]]
name = "similar"
version = "2.6.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e"
checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640"
[[package]]
name = "simplelog"
@ -6507,9 +6465,9 @@ checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "ureq"
version = "2.10.0"
version = "2.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72139d247e5f97a3eff96229a7ae85ead5328a39efe76f8bf5a06313d505b6ea"
checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd"
dependencies = [
"base64 0.22.1",
"encoding_rs",
@ -6666,9 +6624,9 @@ checksum = "425a23c7b7145bc7620c9c445817c37b1f78b6790aee9f208133f3c028975b60"
[[package]]
name = "uuid"
version = "1.10.0"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439"
dependencies = [
"getrandom",
"serde",
@ -6896,7 +6854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283"
dependencies = [
"proc-macro2",
"quick-xml 0.31.0",
"quick-xml",
"quote",
]

View File

@ -10,8 +10,8 @@ homepage = "https://www.nushell.sh"
license = "MIT"
name = "nu"
repository = "https://github.com/nushell/nushell"
rust-version = "1.78.0"
version = "0.96.2"
rust-version = "1.77.2"
version = "0.95.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -83,8 +83,7 @@ ctrlc = "3.4"
deunicode = "1.6.0"
dialoguer = { default-features = false, version = "0.11" }
digest = { default-features = false, version = "0.10" }
dirs = "5.0"
dirs-sys = "0.4"
dirs-next = "2.0"
dtparse = "2.0"
encoding_rs = "0.8"
fancy-regex = "0.13"
@ -116,12 +115,12 @@ mockito = { version = "1.4", default-features = false }
native-tls = "0.2"
nix = { version = "0.28", default-features = false }
notify-debouncer-full = { version = "0.3", default-features = false }
nu-ansi-term = "0.50.1"
nu-ansi-term = "0.50.0"
num-format = "0.4"
num-traits = "0.2"
omnipath = "0.1"
once_cell = "1.18"
open = "5.3"
open = "5.2"
os_pipe = { version = "1.2", features = ["io_safety"] }
pathdiff = "0.2"
percent-encoding = "2"
@ -138,7 +137,7 @@ quote = "1.0"
rand = "0.8"
ratatui = "0.26"
rayon = "1.10"
reedline = "0.33.0"
reedline = "0.32.0"
regex = "1.9.5"
rmp = "0.8"
rmp-serde = "1.3"
@ -146,7 +145,7 @@ ropey = "1.6.1"
roxmltree = "0.19"
rstest = { version = "0.18", default-features = false }
rusqlite = "0.31"
rust-embed = "8.5.0"
rust-embed = "8.4.0"
same-file = "1.0"
serde = { version = "1.0", default-features = false }
serde_json = "1.0"
@ -165,7 +164,7 @@ trash = "3.3"
umask = "2.1"
unicode-segmentation = "1.11"
unicode-width = "0.1"
ureq = { version = "2.10", default-features = false }
ureq = { version = "2.9", default-features = false }
url = "2.2"
uu_cp = "0.0.27"
uu_mkdir = "0.0.27"
@ -174,36 +173,35 @@ uu_mv = "0.0.27"
uu_whoami = "0.0.27"
uu_uname = "0.0.27"
uucore = "0.0.27"
uuid = "1.10.0"
uuid = "1.9.1"
v_htmlescape = "0.15.0"
wax = "0.6"
which = "6.0.0"
windows = "0.54"
windows-sys = "0.48"
winreg = "0.52"
[dependencies]
nu-cli = { path = "./crates/nu-cli", version = "0.96.2" }
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.96.2" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.96.2" }
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.96.2", optional = true }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.96.2" }
nu-command = { path = "./crates/nu-command", version = "0.96.2" }
nu-engine = { path = "./crates/nu-engine", version = "0.96.2" }
nu-explore = { path = "./crates/nu-explore", version = "0.96.2" }
nu-lsp = { path = "./crates/nu-lsp/", version = "0.96.2" }
nu-parser = { path = "./crates/nu-parser", version = "0.96.2" }
nu-path = { path = "./crates/nu-path", version = "0.96.2" }
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.96.2" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.96.2" }
nu-std = { path = "./crates/nu-std", version = "0.96.2" }
nu-system = { path = "./crates/nu-system", version = "0.96.2" }
nu-utils = { path = "./crates/nu-utils", version = "0.96.2" }
nu-cli = { path = "./crates/nu-cli", version = "0.95.1" }
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.95.1" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.95.1" }
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.95.1", optional = true }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.95.1" }
nu-command = { path = "./crates/nu-command", version = "0.95.1" }
nu-engine = { path = "./crates/nu-engine", version = "0.95.1" }
nu-explore = { path = "./crates/nu-explore", version = "0.95.1" }
nu-lsp = { path = "./crates/nu-lsp/", version = "0.95.1" }
nu-parser = { path = "./crates/nu-parser", version = "0.95.1" }
nu-path = { path = "./crates/nu-path", version = "0.95.1" }
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.95.1" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.95.1" }
nu-std = { path = "./crates/nu-std", version = "0.95.1" }
nu-system = { path = "./crates/nu-system", version = "0.95.1" }
nu-utils = { path = "./crates/nu-utils", version = "0.95.1" }
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
crossterm = { workspace = true }
ctrlc = { workspace = true }
dirs = { workspace = true }
dirs-next = { workspace = true }
log = { workspace = true }
miette = { workspace = true, features = ["fancy-no-backtrace", "fancy"] }
mimalloc = { version = "0.1.42", default-features = false, optional = true }
@ -227,14 +225,13 @@ nix = { workspace = true, default-features = false, features = [
] }
[dev-dependencies]
nu-test-support = { path = "./crates/nu-test-support", version = "0.96.2" }
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.96.2" }
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.96.2" }
nu-test-support = { path = "./crates/nu-test-support", version = "0.95.1" }
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.95.1" }
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.95.1" }
assert_cmd = "2.0"
dirs = { workspace = true }
dirs-next = { workspace = true }
tango-bench = "0.5"
pretty_assertions = { workspace = true }
regex = { workspace = true }
rstest = { workspace = true, default-features = false }
serial_test = "3.1"
tempfile = { workspace = true }
@ -313,4 +310,4 @@ reedline = { git = "https://github.com/nushell/reedline", branch = "main" }
# Run individual benchmarks like `cargo bench -- <regex>` e.g. `cargo bench -- parse`
[[bench]]
name = "benchmarks"
harness = false
harness = false

View File

@ -1,29 +0,0 @@
# Security Policy
As a shell and programming language Nushell provides you with great powers and the potential to do dangerous things to your computer and data. Whenever there is a risk that a malicious actor can abuse a bug or a violation of documented behavior/assumptions in Nushell to harm you this is a *security* risk.
We want to fix those issues without exposing our users to unnecessary risk. Thus we want to explain our security policy.
Additional issues may be part of *safety* where the behavior of Nushell as designed and implemented can cause unintended harm or a bug causes damage without the involvement of a third party.
## Supported Versions
As Nushell is still under very active pre-stable development, the only version the core team prioritizes for security and safety fixes is the [most recent version as published on GitHub](https://github.com/nushell/nushell/releases/latest).
Only if you provide a strong reasoning and the necessary resources, will we consider blessing a backported fix with an official patch release for a previous version.
## Reporting a Vulnerability
If you suspect that a bug or behavior of Nushell can affect security or may be potentially exploitable, please report the issue to us in private.
Either reach out to the core team on [our Discord server](https://discord.gg/NtAbbGn) to arrange a private channel or use the [GitHub vulnerability reporting form](https://github.com/nushell/nushell/security/advisories/new).
Please try to answer the following questions:
- How can we reach you for further questions?
- What is the bug? Which system of Nushell may be affected?
- Do you have proof-of-concept for a potential exploit or have you observed an exploit in the wild?
- What is your assessment of the severity based on what could be impacted should the bug be exploited?
- Are additional people aware of the issue or deserve credit for identifying the issue?
We will try to get back to you within a week with:
- acknowledging the receipt of the report
- an initial plan of how we want to address this including the primary points of contact for further communication
- our preliminary assessment of how severe we judge the issue
- a proposal for how we can coordinate responsible disclosure (e.g. how we ship the bugfix, if we need to coordinate with distribution maintainers, when you can release a blog post if you want to etc.)
For purely *safety* related issues where the impact is severe by direct user action instead of malicious input or third parties, feel free to open a regular issue. If we deem that there may be an additional *security* risk on a *safety* issue we may continue discussions in a restricted forum.

View File

@ -45,10 +45,6 @@ fn setup_stack_and_engine_from_command(command: &str) -> (Stack, EngineState) {
};
let mut stack = Stack::new();
// Support running benchmarks with IR mode
stack.use_ir = std::env::var_os("NU_USE_IR").is_some();
evaluate_commands(
&commands,
&mut engine,

View File

@ -5,27 +5,27 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
edition = "2021"
license = "MIT"
name = "nu-cli"
version = "0.96.2"
version = "0.95.1"
[lib]
bench = false
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.96.2" }
nu-command = { path = "../nu-command", version = "0.96.2" }
nu-test-support = { path = "../nu-test-support", version = "0.96.2" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.95.1" }
nu-command = { path = "../nu-command", version = "0.95.1" }
nu-test-support = { path = "../nu-test-support", version = "0.95.1" }
rstest = { workspace = true, default-features = false }
tempfile = { workspace = true }
[dependencies]
nu-cmd-base = { path = "../nu-cmd-base", version = "0.96.2" }
nu-engine = { path = "../nu-engine", version = "0.96.2" }
nu-path = { path = "../nu-path", version = "0.96.2" }
nu-parser = { path = "../nu-parser", version = "0.96.2" }
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.96.2", optional = true }
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
nu-utils = { path = "../nu-utils", version = "0.96.2" }
nu-color-config = { path = "../nu-color-config", version = "0.96.2" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.95.1" }
nu-engine = { path = "../nu-engine", version = "0.95.1" }
nu-path = { path = "../nu-path", version = "0.95.1" }
nu-parser = { path = "../nu-parser", version = "0.95.1" }
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.95.1", optional = true }
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
nu-utils = { path = "../nu-utils", version = "0.95.1" }
nu-color-config = { path = "../nu-color-config", version = "0.95.1" }
nu-ansi-term = { workspace = true }
reedline = { workspace = true, features = ["bashisms", "sqlite"] }

View File

@ -1,7 +0,0 @@
This crate implements the core functionality of the interactive Nushell REPL and interfaces with `reedline`.
Currently implements the syntax highlighting and completions logic.
Furthermore includes a few commands that are specific to `reedline`
## Internal Nushell crate
This crate implements components of Nushell and is not designed to support plugin authors or other users directly.

View File

@ -67,7 +67,7 @@ impl Command for History {
} else {
let history_reader: Option<Box<dyn ReedlineHistory>> = match history.file_format {
HistoryFileFormat::Sqlite => {
SqliteBackedHistory::with_file(history_path.clone().into(), None, None)
SqliteBackedHistory::with_file(history_path.clone(), None, None)
.map(|inner| {
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
boxed
@ -77,7 +77,7 @@ impl Command for History {
HistoryFileFormat::PlainText => FileBackedHistory::with_file(
history.max_size as usize,
history_path.clone().into(),
history_path.clone(),
)
.map(|inner| {
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
@ -156,34 +156,58 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
//2. Create a record of either short or long columns and values
let item_id_value = Value::int(
entry
.id
.and_then(|id| id.to_string().parse::<i64>().ok())
.unwrap_or_default(),
match entry.id {
Some(id) => {
let ids = id.to_string();
match ids.parse::<i64>() {
Ok(i) => i,
_ => 0i64,
}
}
None => 0i64,
},
head,
);
let start_timestamp_value = Value::string(
entry
.start_timestamp
.map(|time| time.to_string())
.unwrap_or_default(),
match entry.start_timestamp {
Some(time) => time.to_string(),
None => "".into(),
},
head,
);
let command_value = Value::string(entry.command_line, head);
let session_id_value = Value::int(
entry
.session_id
.and_then(|id| id.to_string().parse::<i64>().ok())
.unwrap_or_default(),
match entry.session_id {
Some(sid) => {
let sids = sid.to_string();
match sids.parse::<i64>() {
Ok(i) => i,
_ => 0i64,
}
}
None => 0i64,
},
head,
);
let hostname_value = Value::string(
match entry.hostname {
Some(host) => host,
None => "".into(),
},
head,
);
let cwd_value = Value::string(
match entry.cwd {
Some(cwd) => cwd,
None => "".into(),
},
head,
);
let hostname_value = Value::string(entry.hostname.unwrap_or_default(), head);
let cwd_value = Value::string(entry.cwd.unwrap_or_default(), head);
let duration_value = Value::duration(
entry
.duration
.and_then(|d| d.as_nanos().try_into().ok())
.unwrap_or(0),
match entry.duration {
Some(d) => d.as_nanos().try_into().unwrap_or(0),
None => 0,
},
head,
);
let exit_status_value = Value::int(entry.exit_status.unwrap_or(0), head);

View File

@ -49,26 +49,22 @@ impl Command for KeybindingsList {
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let all_options = ["modifiers", "keycodes", "edits", "modes", "events"];
let presence = all_options
.iter()
.map(|option| call.has_flag(engine_state, stack, option))
.collect::<Result<Vec<_>, ShellError>>()?;
let no_option_specified = presence.iter().all(|present| !*present);
let records = all_options
.iter()
.zip(presence)
.filter(|(_, present)| no_option_specified || *present)
.flat_map(|(option, _)| get_records(option, call.head))
.collect();
let records = if call.named_len() == 0 {
let all_options = ["modifiers", "keycodes", "edits", "modes", "events"];
all_options
.iter()
.flat_map(|argument| get_records(argument, call.head))
.collect()
} else {
call.named_iter()
.flat_map(|(argument, _, _)| get_records(argument.item.as_str(), call.head))
.collect()
};
Ok(Value::list(records, call.head).into_pipeline_data())
}

View File

@ -1,5 +1,5 @@
use crate::{
completions::{Completer, CompletionOptions, MatchAlgorithm},
completions::{Completer, CompletionOptions, MatchAlgorithm, SortBy},
SuggestionKind,
};
use nu_parser::FlatShape;
@ -99,9 +99,10 @@ impl CommandCompletion {
suggestion: Suggestion {
value: String::from_utf8_lossy(&x.0).to_string(),
description: x.1,
style: None,
extra: None,
span: reedline::Span::new(span.start - offset, span.end - offset),
append_whitespace: true,
..Suggestion::default()
},
kind: Some(SuggestionKind::Command(x.2)),
})
@ -117,9 +118,11 @@ impl CommandCompletion {
.map(move |x| SemanticSuggestion {
suggestion: Suggestion {
value: x,
description: None,
style: None,
extra: None,
span: reedline::Span::new(span.start - offset, span.end - offset),
append_whitespace: true,
..Suggestion::default()
},
// TODO: is there a way to create a test?
kind: None,
@ -133,9 +136,11 @@ impl CommandCompletion {
results.push(SemanticSuggestion {
suggestion: Suggestion {
value: format!("^{}", external.suggestion.value),
description: None,
style: None,
extra: None,
span: external.suggestion.span,
append_whitespace: true,
..Suggestion::default()
},
kind: external.kind,
})
@ -193,7 +198,11 @@ impl Completer for CommandCompletion {
};
if !subcommands.is_empty() {
return sort_suggestions(&String::from_utf8_lossy(&prefix), subcommands, options);
return sort_suggestions(
&String::from_utf8_lossy(&prefix),
subcommands,
SortBy::LevenshteinDistance,
);
}
let config = working_set.get_config();
@ -218,7 +227,11 @@ impl Completer for CommandCompletion {
vec![]
};
sort_suggestions(&String::from_utf8_lossy(&prefix), commands, options)
sort_suggestions(
&String::from_utf8_lossy(&prefix),
commands,
SortBy::LevenshteinDistance,
)
}
}

View File

@ -48,7 +48,6 @@ impl NuCompleter {
let options = CompletionOptions {
case_sensitive: config.case_sensitive_completions,
match_algorithm: config.completion_algorithm.into(),
sort: config.completion_sort,
..Default::default()
};
@ -444,11 +443,14 @@ pub fn map_value_completions<'a>(
return Some(SemanticSuggestion {
suggestion: Suggestion {
value: s,
description: None,
style: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
end: span.end - offset,
},
..Suggestion::default()
append_whitespace: false,
},
kind: Some(SuggestionKind::Type(x.get_type())),
});
@ -458,11 +460,14 @@ pub fn map_value_completions<'a>(
if let Ok(record) = x.as_record() {
let mut suggestion = Suggestion {
value: String::from(""), // Initialize with empty string
description: None,
style: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
end: span.end - offset,
},
..Suggestion::default()
append_whitespace: false,
};
// Iterate the cols looking for `value` and `description`

View File

@ -2,18 +2,19 @@ use crate::{
completions::{matches, CompletionOptions},
SemanticSuggestion,
};
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
use nu_ansi_term::Style;
use nu_engine::env_to_string;
use nu_path::{expand_to_real_path, home_dir};
use nu_protocol::{
engine::{EngineState, Stack, StateWorkingSet},
CompletionSort, Span,
levenshtein_distance, Span,
};
use nu_utils::get_ls_colors;
use std::path::{is_separator, Component, Path, PathBuf, MAIN_SEPARATOR as SEP};
use std::path::{
is_separator, Component, Path, PathBuf, MAIN_SEPARATOR as SEP, MAIN_SEPARATOR_STR,
};
use super::MatchAlgorithm;
use super::SortBy;
#[derive(Clone, Default)]
pub struct PathBuiltFromString {
@ -21,21 +22,12 @@ pub struct PathBuiltFromString {
isdir: bool,
}
/// Recursively goes through paths that match a given `partial`.
/// built: State struct for a valid matching path built so far.
///
/// `isdir`: whether the current partial path has a trailing slash.
/// Parsing a path string into a pathbuf loses that bit of information.
///
/// want_directory: Whether we want only directories as completion matches.
/// Some commands like `cd` can only be run on directories whereas others
/// like `ls` can be run on regular files as well.
pub fn complete_rec(
fn complete_rec(
partial: &[&str],
built: &PathBuiltFromString,
cwd: &Path,
options: &CompletionOptions,
want_directory: bool,
dir: bool,
isdir: bool,
) -> Vec<PathBuiltFromString> {
let mut completions = vec![];
@ -45,7 +37,7 @@ pub fn complete_rec(
let mut built = built.clone();
built.parts.push(base.to_string());
built.isdir = true;
return complete_rec(rest, &built, cwd, options, want_directory, isdir);
return complete_rec(rest, &built, cwd, options, dir, isdir);
}
}
@ -66,41 +58,24 @@ pub fn complete_rec(
built.parts.push(entry_name.clone());
built.isdir = entry_isdir;
if !want_directory || entry_isdir {
if !dir || entry_isdir {
entries.push((entry_name, built));
}
}
let prefix = partial.first().unwrap_or(&"");
let sorted_entries = sort_completions(prefix, entries, options, |(entry, _)| entry);
let sorted_entries = sort_completions(prefix, entries, SortBy::Ascending, |(entry, _)| entry);
for (entry_name, built) in sorted_entries {
match partial.split_first() {
Some((base, rest)) => {
if matches(base, &entry_name, options) {
// We use `isdir` to confirm that the current component has
// at least one next component or a slash.
// Serves as confirmation to ignore longer completions for
// components in between.
if !rest.is_empty() || isdir {
completions.extend(complete_rec(
rest,
&built,
cwd,
options,
want_directory,
isdir,
));
completions.extend(complete_rec(rest, &built, cwd, options, dir, isdir));
} else {
completions.push(built);
}
}
if entry_name.eq(base)
&& matches!(options.match_algorithm, MatchAlgorithm::Prefix)
&& isdir
{
break;
}
}
None => {
completions.push(built);
@ -118,16 +93,16 @@ enum OriginalCwd {
}
impl OriginalCwd {
fn apply(&self, mut p: PathBuiltFromString, path_separator: char) -> String {
fn apply(&self, mut p: PathBuiltFromString) -> String {
match self {
Self::None => {}
Self::Home => p.parts.insert(0, "~".to_string()),
Self::Prefix(s) => p.parts.insert(0, s.clone()),
};
let mut ret = p.parts.join(&path_separator.to_string());
let mut ret = p.parts.join(MAIN_SEPARATOR_STR);
if p.isdir {
ret.push(path_separator);
ret.push(SEP);
}
ret
}
@ -158,14 +133,6 @@ pub fn complete_item(
) -> Vec<(nu_protocol::Span, String, Option<Style>)> {
let partial = surround_remove(partial);
let isdir = partial.ends_with(is_separator);
#[cfg(unix)]
let path_separator = SEP;
#[cfg(windows)]
let path_separator = partial
.chars()
.rfind(|c: &char| is_separator(*c))
.unwrap_or(SEP);
let cwd_pathbuf = Path::new(cwd).to_path_buf();
let ls_colors = (engine_state.config.use_ls_colors_completions
&& engine_state.config.use_ansi_coloring)
@ -203,7 +170,7 @@ pub fn complete_item(
}
Some(Component::Normal(home)) if home.to_string_lossy() == "~" => {
components.next();
cwd = home_dir().map(Into::into).unwrap_or(cwd_pathbuf);
cwd = home_dir().unwrap_or(cwd_pathbuf);
prefix_len = 1;
original_cwd = OriginalCwd::Home;
}
@ -228,7 +195,7 @@ pub fn complete_item(
)
.into_iter()
.map(|p| {
let path = original_cwd.apply(p, path_separator);
let path = original_cwd.apply(p);
let style = ls_colors.as_ref().map(|lsc| {
lsc.style_for_path_with_metadata(
&path,
@ -306,37 +273,33 @@ pub fn adjust_if_intermediate(
pub fn sort_suggestions(
prefix: &str,
items: Vec<SemanticSuggestion>,
options: &CompletionOptions,
sort_by: SortBy,
) -> Vec<SemanticSuggestion> {
sort_completions(prefix, items, options, |it| &it.suggestion.value)
sort_completions(prefix, items, sort_by, |it| &it.suggestion.value)
}
/// # Arguments
/// * `prefix` - What the user's typed, for sorting by fuzzy matcher score
/// * `prefix` - What the user's typed, for sorting by Levenshtein distance
pub fn sort_completions<T>(
prefix: &str,
mut items: Vec<T>,
options: &CompletionOptions,
sort_by: SortBy,
get_value: fn(&T) -> &str,
) -> Vec<T> {
// Sort items
if options.sort == CompletionSort::Smart && options.match_algorithm == MatchAlgorithm::Fuzzy {
let mut matcher = SkimMatcherV2::default();
if options.case_sensitive {
matcher = matcher.respect_case();
} else {
matcher = matcher.ignore_case();
};
items.sort_by(|a, b| {
let a_str = get_value(a);
let b_str = get_value(b);
let a_score = matcher.fuzzy_match(a_str, prefix).unwrap_or_default();
let b_score = matcher.fuzzy_match(b_str, prefix).unwrap_or_default();
b_score.cmp(&a_score).then(a_str.cmp(b_str))
});
} else {
items.sort_by(|a, b| get_value(a).cmp(get_value(b)));
}
match sort_by {
SortBy::LevenshteinDistance => {
items.sort_by(|a, b| {
let a_distance = levenshtein_distance(prefix, get_value(a));
let b_distance = levenshtein_distance(prefix, get_value(b));
a_distance.cmp(&b_distance)
});
}
SortBy::Ascending => {
items.sort_by(|a, b| get_value(a).cmp(get_value(b)));
}
SortBy::None => {}
};
items
}

View File

@ -1,10 +1,17 @@
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
use nu_parser::trim_quotes_str;
use nu_protocol::{CompletionAlgorithm, CompletionSort};
use nu_protocol::CompletionAlgorithm;
use std::fmt::Display;
#[derive(Copy, Clone)]
pub enum SortBy {
LevenshteinDistance,
Ascending,
None,
}
/// Describes how suggestions should be matched.
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug)]
pub enum MatchAlgorithm {
/// Only show suggestions which begin with the given input
///
@ -89,7 +96,6 @@ pub struct CompletionOptions {
pub case_sensitive: bool,
pub positional: bool,
pub match_algorithm: MatchAlgorithm,
pub sort: CompletionSort,
}
impl Default for CompletionOptions {
@ -98,7 +104,6 @@ impl Default for CompletionOptions {
case_sensitive: true,
positional: true,
match_algorithm: MatchAlgorithm::Prefix,
sort: Default::default(),
}
}
}

View File

@ -1,13 +1,13 @@
use crate::completions::{
completer::map_value_completions, Completer, CompletionOptions, MatchAlgorithm,
SemanticSuggestion,
SemanticSuggestion, SortBy,
};
use nu_engine::eval_call;
use nu_protocol::{
ast::{Argument, Call, Expr, Expression},
debugger::WithoutDebug,
engine::{Stack, StateWorkingSet},
CompletionSort, PipelineData, Span, Type, Value,
PipelineData, Span, Type, Value,
};
use nu_utils::IgnoreCaseExt;
use std::collections::HashMap;
@ -18,6 +18,7 @@ pub struct CustomCompletion {
stack: Stack,
decl_id: usize,
line: String,
sort_by: SortBy,
}
impl CustomCompletion {
@ -26,6 +27,7 @@ impl CustomCompletion {
stack,
decl_id,
line,
sort_by: SortBy::None,
}
}
}
@ -91,6 +93,10 @@ impl Completer for CustomCompletion {
.and_then(|val| val.as_bool().ok())
.unwrap_or(false);
if should_sort {
self.sort_by = SortBy::Ascending;
}
custom_completion_options = Some(CompletionOptions {
case_sensitive: options
.get("case_sensitive")
@ -108,11 +114,6 @@ impl Completer for CustomCompletion {
.unwrap_or(MatchAlgorithm::Prefix),
None => completion_options.match_algorithm,
},
sort: if should_sort {
CompletionSort::Alphabetical
} else {
CompletionSort::Smart
},
});
}
@ -123,11 +124,12 @@ impl Completer for CustomCompletion {
})
.unwrap_or_default();
let options = custom_completion_options
.as_ref()
.unwrap_or(completion_options);
let suggestions = filter(&prefix, suggestions, completion_options);
sort_suggestions(&String::from_utf8_lossy(&prefix), suggestions, options)
let suggestions = if let Some(custom_completion_options) = custom_completion_options {
filter(&prefix, suggestions, &custom_completion_options)
} else {
filter(&prefix, suggestions, completion_options)
};
sort_suggestions(&String::from_utf8_lossy(&prefix), suggestions, self.sort_by)
}
}

View File

@ -48,12 +48,14 @@ impl Completer for DirectoryCompletion {
.map(move |x| SemanticSuggestion {
suggestion: Suggestion {
value: x.1,
description: None,
style: x.2,
extra: None,
span: reedline::Span {
start: x.0.start - offset,
end: x.0.end - offset,
},
..Suggestion::default()
append_whitespace: false,
},
// TODO????
kind: None,

View File

@ -6,7 +6,7 @@ use nu_protocol::{
use reedline::Suggestion;
use std::path::{is_separator, Path, MAIN_SEPARATOR as SEP, MAIN_SEPARATOR_STR};
use super::{completion_common::sort_suggestions, SemanticSuggestion};
use super::{completion_common::sort_suggestions, SemanticSuggestion, SortBy};
#[derive(Clone, Default)]
pub struct DotNuCompletion {}
@ -116,13 +116,14 @@ impl Completer for DotNuCompletion {
.map(move |x| SemanticSuggestion {
suggestion: Suggestion {
value: x.1,
description: None,
style: x.2,
extra: None,
span: reedline::Span {
start: x.0.start - offset,
end: x.0.end - offset,
},
append_whitespace: true,
..Suggestion::default()
},
// TODO????
kind: None,
@ -130,6 +131,6 @@ impl Completer for DotNuCompletion {
})
.collect();
sort_suggestions(&prefix_str, output, options)
sort_suggestions(&prefix_str, output, SortBy::Ascending)
}
}

View File

@ -53,12 +53,14 @@ impl Completer for FileCompletion {
.map(move |x| SemanticSuggestion {
suggestion: Suggestion {
value: x.1,
description: None,
style: x.2,
extra: None,
span: reedline::Span {
start: x.0.start - offset,
end: x.0.end - offset,
},
..Suggestion::default()
append_whitespace: false,
},
// TODO????
kind: None,

View File

@ -1,4 +1,6 @@
use crate::completions::{completion_common::sort_suggestions, Completer, CompletionOptions};
use crate::completions::{
completion_common::sort_suggestions, Completer, CompletionOptions, SortBy,
};
use nu_protocol::{
ast::{Expr, Expression},
engine::{Stack, StateWorkingSet},
@ -49,12 +51,13 @@ impl Completer for FlagCompletion {
suggestion: Suggestion {
value: String::from_utf8_lossy(&named).to_string(),
description: Some(flag_desc.to_string()),
style: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
end: span.end - offset,
},
append_whitespace: true,
..Suggestion::default()
},
// TODO????
kind: None,
@ -75,12 +78,13 @@ impl Completer for FlagCompletion {
suggestion: Suggestion {
value: String::from_utf8_lossy(&named).to_string(),
description: Some(flag_desc.to_string()),
style: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
end: span.end - offset,
},
append_whitespace: true,
..Suggestion::default()
},
// TODO????
kind: None,
@ -88,7 +92,7 @@ impl Completer for FlagCompletion {
}
}
return sort_suggestions(&String::from_utf8_lossy(&prefix), output, options);
return sort_suggestions(&String::from_utf8_lossy(&prefix), output, SortBy::Ascending);
}
vec![]

View File

@ -13,7 +13,7 @@ mod variable_completions;
pub use base::{Completer, SemanticSuggestion, SuggestionKind};
pub use command_completions::CommandCompletion;
pub use completer::NuCompleter;
pub use completion_options::{CompletionOptions, MatchAlgorithm};
pub use completion_options::{CompletionOptions, MatchAlgorithm, SortBy};
pub use custom_completions::CustomCompletion;
pub use directory_completions::DirectoryCompletion;
pub use dotnu_completions::DotNuCompletion;

View File

@ -9,7 +9,7 @@ use nu_protocol::{
use reedline::Suggestion;
use std::str;
use super::completion_common::sort_suggestions;
use super::{completion_common::sort_suggestions, SortBy};
#[derive(Clone)]
pub struct VariableCompletion {
@ -72,7 +72,7 @@ impl Completer for VariableCompletion {
}
}
return sort_suggestions(&prefix_str, output, options);
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
}
} else {
// No nesting provided, return all env vars
@ -85,15 +85,18 @@ impl Completer for VariableCompletion {
output.push(SemanticSuggestion {
suggestion: Suggestion {
value: env_var.0,
description: None,
style: None,
extra: None,
span: current_span,
..Suggestion::default()
append_whitespace: false,
},
kind: Some(SuggestionKind::Type(env_var.1.get_type())),
});
}
}
return sort_suggestions(&prefix_str, output, options);
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
}
}
@ -117,7 +120,7 @@ impl Completer for VariableCompletion {
}
}
return sort_suggestions(&prefix_str, output, options);
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
}
}
@ -139,7 +142,7 @@ impl Completer for VariableCompletion {
}
}
return sort_suggestions(&prefix_str, output, options);
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
}
}
}
@ -154,8 +157,11 @@ impl Completer for VariableCompletion {
output.push(SemanticSuggestion {
suggestion: Suggestion {
value: builtin.to_string(),
description: None,
style: None,
extra: None,
span: current_span,
..Suggestion::default()
append_whitespace: false,
},
// TODO is there a way to get the VarId to get the type???
kind: None,
@ -178,8 +184,11 @@ impl Completer for VariableCompletion {
output.push(SemanticSuggestion {
suggestion: Suggestion {
value: String::from_utf8_lossy(v.0).to_string(),
description: None,
style: None,
extra: None,
span: current_span,
..Suggestion::default()
append_whitespace: false,
},
kind: Some(SuggestionKind::Type(
working_set.get_variable(*v.1).ty.clone(),
@ -206,8 +215,11 @@ impl Completer for VariableCompletion {
output.push(SemanticSuggestion {
suggestion: Suggestion {
value: String::from_utf8_lossy(v.0).to_string(),
description: None,
style: None,
extra: None,
span: current_span,
..Suggestion::default()
append_whitespace: false,
},
kind: Some(SuggestionKind::Type(
working_set.get_variable(*v.1).ty.clone(),
@ -217,7 +229,7 @@ impl Completer for VariableCompletion {
}
}
output = sort_suggestions(&prefix_str, output, options);
output = sort_suggestions(&prefix_str, output, SortBy::Ascending);
output.dedup(); // TODO: Removes only consecutive duplicates, is it intended?
@ -243,8 +255,11 @@ fn nested_suggestions(
output.push(SemanticSuggestion {
suggestion: Suggestion {
value: col.clone(),
description: None,
style: None,
extra: None,
span: current_span,
..Suggestion::default()
append_whitespace: false,
},
kind: Some(kind.clone()),
});
@ -257,8 +272,11 @@ fn nested_suggestions(
output.push(SemanticSuggestion {
suggestion: Suggestion {
value: column_name,
description: None,
style: None,
extra: None,
span: current_span,
..Suggestion::default()
append_whitespace: false,
},
kind: Some(kind.clone()),
});

View File

@ -192,8 +192,7 @@ pub fn add_plugin_file(
} else if let Some(mut plugin_path) = nu_path::config_dir() {
// Path to store plugins signatures
plugin_path.push(storage_path);
let mut plugin_path =
canonicalize_with(&plugin_path, &cwd).unwrap_or(plugin_path.into());
let mut plugin_path = canonicalize_with(&plugin_path, &cwd).unwrap_or(plugin_path);
plugin_path.push(PLUGIN_FILE);
let plugin_path = canonicalize_with(&plugin_path, &cwd).unwrap_or(plugin_path);
engine_state.plugin_path = Some(plugin_path);
@ -248,7 +247,7 @@ pub(crate) fn get_history_path(storage_path: &str, mode: HistoryFileFormat) -> O
HistoryFileFormat::PlainText => HISTORY_FILE_TXT,
HistoryFileFormat::Sqlite => HISTORY_FILE_SQLITE,
});
history_path.into()
history_path
})
}

View File

@ -53,8 +53,9 @@ pub fn evaluate_commands(
// Parse the source code
let (block, delta) = {
if let Some(ref t_mode) = table_mode {
Arc::make_mut(&mut engine_state.config).table_mode =
t_mode.coerce_str()?.parse().unwrap_or_default();
let mut config = engine_state.get_config().clone();
config.table_mode = t_mode.coerce_str()?.parse().unwrap_or_default();
engine_state.set_config(config);
}
let mut working_set = StateWorkingSet::new(engine_state);
@ -69,11 +70,6 @@ pub fn evaluate_commands(
std::process::exit(1);
}
if let Some(err) = working_set.compile_errors.first() {
report_error(&working_set, err);
// Not a fatal error, for now
}
(output, working_set.render())
};

View File

@ -76,21 +76,12 @@ pub fn evaluate_file(
trace!("parsing file: {}", file_path_str);
let block = parse(&mut working_set, Some(file_path_str), &file, false);
if let Some(warning) = working_set.parse_warnings.first() {
report_error(&working_set, warning);
}
// If any parse errors were found, report the first error and exit.
if let Some(err) = working_set.parse_errors.first() {
report_error(&working_set, err);
std::process::exit(1);
}
if let Some(err) = working_set.compile_errors.first() {
report_error(&working_set, err);
// Not a fatal error, for now
}
// Look for blocks whose name starts with "main" and replace it with the filename.
for block in working_set.delta.blocks.iter_mut().map(Arc::make_mut) {
if block.signature.name == "main" {

View File

@ -1,4 +1,3 @@
#![doc = include_str!("../README.md")]
mod commands;
mod completions;
mod config_files;

View File

@ -1,34 +1,25 @@
use nu_engine::documentation::{get_flags_section, HelpStyle};
use nu_protocol::{engine::EngineState, levenshtein_distance, Config};
use nu_engine::documentation::get_flags_section;
use nu_protocol::{engine::EngineState, levenshtein_distance};
use nu_utils::IgnoreCaseExt;
use reedline::{Completer, Suggestion};
use std::{fmt::Write, sync::Arc};
pub struct NuHelpCompleter {
engine_state: Arc<EngineState>,
config: Arc<Config>,
}
pub struct NuHelpCompleter(Arc<EngineState>);
impl NuHelpCompleter {
pub fn new(engine_state: Arc<EngineState>, config: Arc<Config>) -> Self {
Self {
engine_state,
config,
}
pub fn new(engine_state: Arc<EngineState>) -> Self {
Self(engine_state)
}
fn completion_helper(&self, line: &str, pos: usize) -> Vec<Suggestion> {
let folded_line = line.to_folded_case();
let mut help_style = HelpStyle::default();
help_style.update_from_config(&self.engine_state, &self.config);
let mut commands = self
.engine_state
.0
.get_decls_sorted(false)
.into_iter()
.filter_map(|(_, decl_id)| {
let decl = self.engine_state.get_decl(decl_id);
let decl = self.0.get_decl(decl_id);
(decl.name().to_folded_case().contains(&folded_line)
|| decl.usage().to_folded_case().contains(&folded_line)
|| decl
@ -63,8 +54,8 @@ impl NuHelpCompleter {
let _ = write!(long_desc, "Usage:\r\n > {}\r\n", sig.call_signature());
if !sig.named.is_empty() {
long_desc.push_str(&get_flags_section(&sig, &help_style, |v| {
v.to_parsable_string(", ", &self.config)
long_desc.push_str(&get_flags_section(Some(&*self.0.clone()), &sig, |v| {
v.to_parsable_string(", ", &self.0.config)
}))
}
@ -80,7 +71,7 @@ impl NuHelpCompleter {
let opt_suffix = if let Some(value) = &positional.default_value {
format!(
" (optional, default: {})",
&value.to_parsable_string(", ", &self.config),
&value.to_parsable_string(", ", &self.0.config),
)
} else {
(" (optional)").to_string()
@ -110,12 +101,13 @@ impl NuHelpCompleter {
Suggestion {
value: decl.name().into(),
description: Some(long_desc),
style: None,
extra: Some(extra),
span: reedline::Span {
start: pos - line.len(),
end: pos,
},
..Suggestion::default()
append_whitespace: false,
}
})
.collect()
@ -146,8 +138,7 @@ mod test {
) {
let engine_state =
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context());
let config = engine_state.get_config().clone();
let mut completer = NuHelpCompleter::new(engine_state.into(), config);
let mut completer = NuHelpCompleter::new(engine_state.into());
let suggestions = completer.complete(line, end);
assert_eq!(

View File

@ -142,9 +142,10 @@ fn convert_to_suggestions(
vec![Suggestion {
value: text,
description,
style: None,
extra,
span,
..Suggestion::default()
append_whitespace: false,
}]
}
Value::List { vals, .. } => vals
@ -153,6 +154,9 @@ fn convert_to_suggestions(
.collect(),
_ => vec![Suggestion {
value: format!("Not a record: {value:?}"),
description: None,
style: None,
extra: None,
span: reedline::Span {
start: if only_buffer_difference {
pos - line.len()
@ -165,7 +169,7 @@ fn convert_to_suggestions(
line.len()
},
},
..Suggestion::default()
append_whitespace: false,
}],
}
}

View File

@ -1,5 +1,3 @@
use std::sync::Arc;
use nu_engine::command_prelude::*;
use reedline::{Highlighter, StyledText};
@ -35,10 +33,13 @@ impl Command for NuHighlight {
let head = call.head;
let signals = engine_state.signals();
let engine_state = std::sync::Arc::new(engine_state.clone());
let config = engine_state.get_config().clone();
let highlighter = crate::NuHighlighter {
engine_state: Arc::new(engine_state.clone()),
stack: Arc::new(stack.clone()),
engine_state,
stack: std::sync::Arc::new(stack.clone()),
config,
};
input.map(

View File

@ -77,19 +77,13 @@ pub(crate) fn add_menus(
mut line_editor: Reedline,
engine_state_ref: Arc<EngineState>,
stack: &Stack,
config: Arc<Config>,
config: &Config,
) -> Result<Reedline, ShellError> {
//log::trace!("add_menus: config: {:#?}", &config);
line_editor = line_editor.clear_menus();
for menu in &config.menus {
line_editor = add_menu(
line_editor,
menu,
engine_state_ref.clone(),
stack,
config.clone(),
)?
line_editor = add_menu(line_editor, menu, engine_state_ref.clone(), stack, config)?
}
// Checking if the default menus have been added from the config file
@ -106,7 +100,7 @@ pub(crate) fn add_menus(
if !config
.menus
.iter()
.any(|menu| menu.name.to_expanded_string("", &config) == name)
.any(|menu| menu.name.to_expanded_string("", config) == name)
{
let (block, delta) = {
let mut working_set = StateWorkingSet::new(&engine_state);
@ -143,7 +137,7 @@ pub(crate) fn add_menus(
&menu,
new_engine_state_ref.clone(),
stack,
config.clone(),
config,
)?;
}
}
@ -157,27 +151,27 @@ fn add_menu(
menu: &ParsedMenu,
engine_state: Arc<EngineState>,
stack: &Stack,
config: Arc<Config>,
config: &Config,
) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span();
if let Value::Record { val, .. } = &menu.menu_type {
let layout = extract_value("layout", val, span)?.to_expanded_string("", &config);
let layout = extract_value("layout", val, span)?.to_expanded_string("", config);
match layout.as_str() {
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, &config),
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config),
"list" => add_list_menu(line_editor, menu, engine_state, stack, config),
"ide" => add_ide_menu(line_editor, menu, engine_state, stack, config),
"description" => add_description_menu(line_editor, menu, engine_state, stack, config),
_ => Err(ShellError::UnsupportedConfigValue {
expected: "columnar, list, ide or description".to_string(),
value: menu.menu_type.to_abbreviated_string(&config),
value: menu.menu_type.to_abbreviated_string(config),
span: menu.menu_type.span(),
}),
}
} else {
Err(ShellError::UnsupportedConfigValue {
expected: "only record type".to_string(),
value: menu.menu_type.to_abbreviated_string(&config),
value: menu.menu_type.to_abbreviated_string(config),
span: menu.menu_type.span(),
})
}
@ -193,29 +187,6 @@ fn get_style(record: &Record, name: &str, span: Span) -> Option<Style> {
})
}
fn set_menu_style<M: MenuBuilder>(mut menu: M, style: &Value) -> M {
let span = style.span();
let Value::Record { val, .. } = &style else {
return menu;
};
if let Some(style) = get_style(val, "text", span) {
menu = menu.with_text_style(style);
}
if let Some(style) = get_style(val, "selected_text", span) {
menu = menu.with_selected_text_style(style);
}
if let Some(style) = get_style(val, "description_text", span) {
menu = menu.with_description_text_style(style);
}
if let Some(style) = get_style(val, "match_text", span) {
menu = menu.with_match_text_style(style);
}
if let Some(style) = get_style(val, "selected_match_text", span) {
menu = menu.with_selected_match_text_style(style);
}
menu
}
// Adds a columnar menu to the editor engine
pub(crate) fn add_columnar_menu(
line_editor: Reedline,
@ -254,7 +225,24 @@ pub(crate) fn add_columnar_menu(
};
}
columnar_menu = set_menu_style(columnar_menu, &menu.style);
let span = menu.style.span();
if let Value::Record { val, .. } = &menu.style {
if let Some(style) = get_style(val, "text", span) {
columnar_menu = columnar_menu.with_text_style(style);
}
if let Some(style) = get_style(val, "selected_text", span) {
columnar_menu = columnar_menu.with_selected_text_style(style);
}
if let Some(style) = get_style(val, "description_text", span) {
columnar_menu = columnar_menu.with_description_text_style(style);
}
if let Some(style) = get_style(val, "match_text", span) {
columnar_menu = columnar_menu.with_match_text_style(style);
}
if let Some(style) = get_style(val, "selected_match_text", span) {
columnar_menu = columnar_menu.with_selected_match_text_style(style);
}
}
let marker = menu.marker.to_expanded_string("", config);
columnar_menu = columnar_menu.with_marker(&marker);
@ -294,9 +282,9 @@ pub(crate) fn add_list_menu(
menu: &ParsedMenu,
engine_state: Arc<EngineState>,
stack: &Stack,
config: Arc<Config>,
config: &Config,
) -> Result<Reedline, ShellError> {
let name = menu.name.to_expanded_string("", &config);
let name = menu.name.to_expanded_string("", config);
let mut list_menu = ListMenu::default().with_name(&name);
let span = menu.menu_type.span();
@ -310,9 +298,20 @@ pub(crate) fn add_list_menu(
};
}
list_menu = set_menu_style(list_menu, &menu.style);
let span = menu.style.span();
if let Value::Record { val, .. } = &menu.style {
if let Some(style) = get_style(val, "text", span) {
list_menu = list_menu.with_text_style(style);
}
if let Some(style) = get_style(val, "selected_text", span) {
list_menu = list_menu.with_selected_text_style(style);
}
if let Some(style) = get_style(val, "description_text", span) {
list_menu = list_menu.with_description_text_style(style);
}
}
let marker = menu.marker.to_expanded_string("", &config);
let marker = menu.marker.to_expanded_string("", config);
list_menu = list_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -338,7 +337,7 @@ pub(crate) fn add_list_menu(
}
_ => Err(ShellError::UnsupportedConfigValue {
expected: "block or omitted value".to_string(),
value: menu.source.to_abbreviated_string(&config),
value: menu.source.to_abbreviated_string(config),
span: menu.source.span(),
}),
}
@ -350,10 +349,10 @@ pub(crate) fn add_ide_menu(
menu: &ParsedMenu,
engine_state: Arc<EngineState>,
stack: &Stack,
config: Arc<Config>,
config: &Config,
) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span();
let name = menu.name.to_expanded_string("", &config);
let name = menu.name.to_expanded_string("", config);
let mut ide_menu = IdeMenu::default().with_name(&name);
if let Value::Record { val, .. } = &menu.menu_type {
@ -418,7 +417,7 @@ pub(crate) fn add_ide_menu(
} else {
return Err(ShellError::UnsupportedConfigValue {
expected: "bool or record".to_string(),
value: border.to_abbreviated_string(&config),
value: border.to_abbreviated_string(config),
span: border.span(),
});
}
@ -442,7 +441,7 @@ pub(crate) fn add_ide_menu(
_ => {
return Err(ShellError::UnsupportedConfigValue {
expected: "\"left\", \"right\" or \"prefer_right\"".to_string(),
value: description_mode.to_abbreviated_string(&config),
value: description_mode.to_abbreviated_string(config),
span: description_mode.span(),
});
}
@ -491,9 +490,26 @@ pub(crate) fn add_ide_menu(
};
}
ide_menu = set_menu_style(ide_menu, &menu.style);
let span = menu.style.span();
if let Value::Record { val, .. } = &menu.style {
if let Some(style) = get_style(val, "text", span) {
ide_menu = ide_menu.with_text_style(style);
}
if let Some(style) = get_style(val, "selected_text", span) {
ide_menu = ide_menu.with_selected_text_style(style);
}
if let Some(style) = get_style(val, "description_text", span) {
ide_menu = ide_menu.with_description_text_style(style);
}
if let Some(style) = get_style(val, "match_text", span) {
ide_menu = ide_menu.with_match_text_style(style);
}
if let Some(style) = get_style(val, "selected_match_text", span) {
ide_menu = ide_menu.with_selected_match_text_style(style);
}
}
let marker = menu.marker.to_expanded_string("", &config);
let marker = menu.marker.to_expanded_string("", config);
ide_menu = ide_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -519,7 +535,7 @@ pub(crate) fn add_ide_menu(
}
_ => Err(ShellError::UnsupportedConfigValue {
expected: "block or omitted value".to_string(),
value: menu.source.to_abbreviated_string(&config),
value: menu.source.to_abbreviated_string(config),
span,
}),
}
@ -531,9 +547,9 @@ pub(crate) fn add_description_menu(
menu: &ParsedMenu,
engine_state: Arc<EngineState>,
stack: &Stack,
config: Arc<Config>,
config: &Config,
) -> Result<Reedline, ShellError> {
let name = menu.name.to_expanded_string("", &config);
let name = menu.name.to_expanded_string("", config);
let mut description_menu = DescriptionMenu::default().with_name(&name);
let span = menu.menu_type.span();
@ -579,9 +595,20 @@ pub(crate) fn add_description_menu(
};
}
description_menu = set_menu_style(description_menu, &menu.style);
let span = menu.style.span();
if let Value::Record { val, .. } = &menu.style {
if let Some(style) = get_style(val, "text", span) {
description_menu = description_menu.with_text_style(style);
}
if let Some(style) = get_style(val, "selected_text", span) {
description_menu = description_menu.with_selected_text_style(style);
}
if let Some(style) = get_style(val, "description_text", span) {
description_menu = description_menu.with_description_text_style(style);
}
}
let marker = menu.marker.to_expanded_string("", &config);
let marker = menu.marker.to_expanded_string("", config);
description_menu = description_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -590,7 +617,7 @@ pub(crate) fn add_description_menu(
let span = menu.source.span();
match &menu.source {
Value::Nothing { .. } => {
let completer = Box::new(NuHelpCompleter::new(engine_state, config));
let completer = Box::new(NuHelpCompleter::new(engine_state));
Ok(line_editor.with_menu(ReedlineMenu::WithCompleter {
menu: Box::new(description_menu),
completer,
@ -611,7 +638,7 @@ pub(crate) fn add_description_menu(
}
_ => Err(ShellError::UnsupportedConfigValue {
expected: "closure or omitted value".to_string(),
value: menu.source.to_abbreviated_string(&config),
value: menu.source.to_abbreviated_string(config),
span: menu.source.span(),
}),
}

View File

@ -268,9 +268,6 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
if let Err(err) = engine_state.merge_env(&mut stack, cwd) {
report_error_new(engine_state, &err);
}
// Check whether $env.NU_USE_IR is set, so that the user can change it in the REPL
// Temporary while IR eval is optional
stack.use_ir = stack.has_env_var(engine_state, "NU_USE_IR");
perf!("merge env", start_time, use_color);
start_time = std::time::Instant::now();
@ -297,7 +294,7 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
perf!("env-change hook", start_time, use_color);
let engine_reference = Arc::new(engine_state.clone());
let config = stack.get_config(engine_state);
let config = engine_state.get_config();
start_time = std::time::Instant::now();
// Find the configured cursor shapes for each mode
@ -323,6 +320,7 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
engine_state: engine_reference.clone(),
// STACK-REFERENCE 1
stack: stack_arc.clone(),
config: config.clone(),
}))
.with_validator(Box::new(NuValidator {
engine_state: engine_reference.clone(),
@ -338,7 +336,6 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
.with_cwd(Some(
engine_state
.cwd(None)
.map(|cwd| cwd.into_std_path_buf())
.unwrap_or_default()
.to_string_lossy()
.to_string(),
@ -1337,26 +1334,20 @@ fn are_session_ids_in_sync() {
#[cfg(test)]
mod test_auto_cd {
use super::{do_auto_cd, parse_operation, ReplOperation};
use nu_path::AbsolutePath;
use nu_protocol::engine::{EngineState, Stack};
use std::path::Path;
use tempfile::tempdir;
/// Create a symlink. Works on both Unix and Windows.
#[cfg(any(unix, windows))]
fn symlink(
original: impl AsRef<AbsolutePath>,
link: impl AsRef<AbsolutePath>,
) -> std::io::Result<()> {
let original = original.as_ref();
let link = link.as_ref();
fn symlink(original: impl AsRef<Path>, link: impl AsRef<Path>) -> std::io::Result<()> {
#[cfg(unix)]
{
std::os::unix::fs::symlink(original, link)
}
#[cfg(windows)]
{
if original.is_dir() {
if original.as_ref().is_dir() {
std::os::windows::fs::symlink_dir(original, link)
} else {
std::os::windows::fs::symlink_file(original, link)
@ -1368,11 +1359,11 @@ mod test_auto_cd {
/// `before`, and after `input` is parsed and evaluated, PWD should be
/// changed to `after`.
#[track_caller]
fn check(before: impl AsRef<AbsolutePath>, input: &str, after: impl AsRef<AbsolutePath>) {
fn check(before: impl AsRef<Path>, input: &str, after: impl AsRef<Path>) {
// Setup EngineState and Stack.
let mut engine_state = EngineState::new();
let mut stack = Stack::new();
stack.set_cwd(before.as_ref()).unwrap();
stack.set_cwd(before).unwrap();
// Parse the input. It must be an auto-cd operation.
let op = parse_operation(input.to_string(), &engine_state, &stack).unwrap();
@ -1388,66 +1379,54 @@ mod test_auto_cd {
// don't have to be byte-wise equal (on Windows, the 8.3 filename
// conversion messes things up),
let updated_cwd = std::fs::canonicalize(updated_cwd).unwrap();
let after = std::fs::canonicalize(after.as_ref()).unwrap();
let after = std::fs::canonicalize(after).unwrap();
assert_eq!(updated_cwd, after);
}
#[test]
fn auto_cd_root() {
let tempdir = tempdir().unwrap();
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
let input = if cfg!(windows) { r"C:\" } else { "/" };
let root = AbsolutePath::try_new(input).unwrap();
check(tempdir, input, root);
let root = if cfg!(windows) { r"C:\" } else { "/" };
check(&tempdir, root, root);
}
#[test]
fn auto_cd_tilde() {
let tempdir = tempdir().unwrap();
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
let home = nu_path::home_dir().unwrap();
check(tempdir, "~", home);
check(&tempdir, "~", home);
}
#[test]
fn auto_cd_dot() {
let tempdir = tempdir().unwrap();
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
check(tempdir, ".", tempdir);
check(&tempdir, ".", &tempdir);
}
#[test]
fn auto_cd_double_dot() {
let tempdir = tempdir().unwrap();
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
let dir = tempdir.join("foo");
let dir = tempdir.path().join("foo");
std::fs::create_dir_all(&dir).unwrap();
check(dir, "..", tempdir);
check(dir, "..", &tempdir);
}
#[test]
fn auto_cd_triple_dot() {
let tempdir = tempdir().unwrap();
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
let dir = tempdir.join("foo").join("bar");
let dir = tempdir.path().join("foo").join("bar");
std::fs::create_dir_all(&dir).unwrap();
check(dir, "...", tempdir);
check(dir, "...", &tempdir);
}
#[test]
fn auto_cd_relative() {
let tempdir = tempdir().unwrap();
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
let foo = tempdir.join("foo");
let bar = tempdir.join("bar");
let foo = tempdir.path().join("foo");
let bar = tempdir.path().join("bar");
std::fs::create_dir_all(&foo).unwrap();
std::fs::create_dir_all(&bar).unwrap();
let input = if cfg!(windows) { r"..\bar" } else { "../bar" };
check(foo, input, bar);
}
@ -1455,35 +1434,32 @@ mod test_auto_cd {
#[test]
fn auto_cd_trailing_slash() {
let tempdir = tempdir().unwrap();
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
let dir = tempdir.join("foo");
let dir = tempdir.path().join("foo");
std::fs::create_dir_all(&dir).unwrap();
let input = if cfg!(windows) { r"foo\" } else { "foo/" };
check(tempdir, input, dir);
check(&tempdir, input, dir);
}
#[test]
fn auto_cd_symlink() {
let tempdir = tempdir().unwrap();
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
let dir = tempdir.join("foo");
let dir = tempdir.path().join("foo");
std::fs::create_dir_all(&dir).unwrap();
let link = tempdir.join("link");
let link = tempdir.path().join("link");
symlink(&dir, &link).unwrap();
let input = if cfg!(windows) { r".\link" } else { "./link" };
check(tempdir, input, link);
check(&tempdir, input, link);
}
#[test]
#[should_panic(expected = "was not parsed into an auto-cd operation")]
fn auto_cd_nonexistent_directory() {
let tempdir = tempdir().unwrap();
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
let dir = tempdir.path().join("foo");
let dir = tempdir.join("foo");
let input = if cfg!(windows) { r"foo\" } else { "foo/" };
check(tempdir, input, dir);
check(&tempdir, input, dir);
}
}

View File

@ -6,7 +6,7 @@ use nu_parser::{flatten_block, parse, FlatShape};
use nu_protocol::{
ast::{Block, Expr, Expression, PipelineRedirection, RecordItem},
engine::{EngineState, Stack, StateWorkingSet},
Span,
Config, Span,
};
use reedline::{Highlighter, StyledText};
use std::sync::Arc;
@ -14,14 +14,15 @@ use std::sync::Arc;
pub struct NuHighlighter {
pub engine_state: Arc<EngineState>,
pub stack: Arc<Stack>,
pub config: Config,
}
impl Highlighter for NuHighlighter {
fn highlight(&self, line: &str, _cursor: usize) -> StyledText {
trace!("highlighting: {}", line);
let config = self.stack.get_config(&self.engine_state);
let highlight_resolved_externals = config.highlight_resolved_externals;
let highlight_resolved_externals =
self.engine_state.get_config().highlight_resolved_externals;
let mut working_set = StateWorkingSet::new(&self.engine_state);
let block = parse(&mut working_set, None, line.as_bytes(), false);
let (shapes, global_span_offset) = {
@ -87,7 +88,7 @@ impl Highlighter for NuHighlighter {
.to_string();
let mut add_colored_token = |shape: &FlatShape, text: String| {
output.push((get_shape_color(shape.as_str(), &config), text));
output.push((get_shape_color(shape.as_str(), &self.config), text));
};
match shape.1 {
@ -127,9 +128,9 @@ impl Highlighter for NuHighlighter {
let start = part.start - span.start;
let end = part.end - span.start;
let text = next_token[start..end].to_string();
let mut style = get_shape_color(shape.as_str(), &config);
let mut style = get_shape_color(shape.as_str(), &self.config);
if highlight {
style = get_matching_brackets_style(style, &config);
style = get_matching_brackets_style(style, &self.config);
}
output.push((style, text));
}
@ -429,14 +430,6 @@ fn find_matching_block_end_in_expr(
)
}),
Expr::Collect(_, expr) => find_matching_block_end_in_expr(
line,
working_set,
expr,
global_span_offset,
global_cursor_offset,
),
Expr::Block(block_id)
| Expr::Closure(block_id)
| Expr::RowCondition(block_id)

View File

@ -262,11 +262,6 @@ fn evaluate_source(
return Ok(Some(1));
}
if let Some(err) = working_set.compile_errors.first() {
report_error(&working_set, err);
// Not a fatal error, for now
}
(output, working_set.render())
};
@ -321,10 +316,16 @@ mod test {
let env = engine_state.render_env_vars();
assert!(matches!(env.get("FOO"), Some(&Value::String { val, .. }) if val == "foo"));
assert!(matches!(env.get("SYMBOLS"), Some(&Value::String { val, .. }) if val == symbols));
assert!(matches!(env.get(symbols), Some(&Value::String { val, .. }) if val == "symbols"));
assert!(env.contains_key("PWD"));
assert!(
matches!(env.get(&"FOO".to_string()), Some(&Value::String { val, .. }) if val == "foo")
);
assert!(
matches!(env.get(&"SYMBOLS".to_string()), Some(&Value::String { val, .. }) if val == symbols)
);
assert!(
matches!(env.get(&symbols.to_string()), Some(&Value::String { val, .. }) if val == "symbols")
);
assert!(env.get(&"PWD".to_string()).is_some());
assert_eq!(env.len(), 4);
}
}

View File

@ -1,7 +0,0 @@
use nu_test_support::nu;
#[test]
fn not_empty() {
let result = nu!("keybindings list | is-not-empty");
assert_eq!(result.out, "true");
}

View File

@ -1,2 +1 @@
mod keybindings_list;
mod nu_highlight;

View File

@ -32,6 +32,7 @@ fn completer() -> NuCompleter {
fn completer_strings() -> NuCompleter {
// Create a new engine
let (dir, _, mut engine, mut stack) = new_engine();
// Add record value as example
let record = r#"def animals [] { ["cat", "dog", "eel" ] }
def my-command [animal: string@animals] { print $animal }"#;
@ -89,12 +90,14 @@ fn subcommand_completer() -> NuCompleter {
// Create a new engine
let (dir, _, mut engine, mut stack) = new_engine();
// Use fuzzy matching, because subcommands are sorted by Levenshtein distance,
// and that's not very useful with prefix matching
let commands = r#"
$env.config.completions.algorithm = "fuzzy"
def foo [] {}
def "foo bar" [] {}
def "foo abaz" [] {}
def "foo aabcrr" [] {}
def "foo aabrr" [] {}
def food [] {}
"#;
assert!(support::merge_input(commands.as_bytes(), &mut engine, &mut stack, dir).is_ok());
@ -103,22 +106,6 @@ fn subcommand_completer() -> NuCompleter {
NuCompleter::new(Arc::new(engine), Arc::new(stack))
}
/// Use fuzzy completions but sort in alphabetical order
#[fixture]
fn fuzzy_alpha_sort_completer() -> NuCompleter {
// Create a new engine
let (dir, _, mut engine, mut stack) = new_engine();
let config = r#"
$env.config.completions.algorithm = "fuzzy"
$env.config.completions.sort = "alphabetical"
"#;
assert!(support::merge_input(config.as_bytes(), &mut engine, &mut stack, dir).is_ok());
// Instantiate a new completer
NuCompleter::new(Arc::new(engine), Arc::new(stack))
}
#[test]
fn variables_dollar_sign_with_variablecompletion() {
let (_, _, engine, stack) = new_engine();
@ -136,28 +123,28 @@ fn variables_double_dash_argument_with_flagcompletion(mut completer: NuCompleter
let suggestions = completer.complete("tst --", 6);
let expected: Vec<String> = vec!["--help".into(), "--mod".into()];
// dbg!(&expected, &suggestions);
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn variables_single_dash_argument_with_flagcompletion(mut completer: NuCompleter) {
let suggestions = completer.complete("tst -", 5);
let expected: Vec<String> = vec!["--help".into(), "--mod".into(), "-h".into(), "-s".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn variables_command_with_commandcompletion(mut completer_strings: NuCompleter) {
let suggestions = completer_strings.complete("my-c ", 4);
let expected: Vec<String> = vec!["my-command".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn variables_subcommands_with_customcompletion(mut completer_strings: NuCompleter) {
let suggestions = completer_strings.complete("my-command ", 11);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
@ -166,7 +153,7 @@ fn variables_customcompletion_subcommands_with_customcompletion_2(
) {
let suggestions = completer_strings.complete("my-command ", 11);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[test]
@ -195,19 +182,19 @@ fn dotnu_completions() {
let completion_str = "source-env ".to_string();
let suggestions = completer.complete(&completion_str, completion_str.len());
match_suggestions(&expected, &suggestions);
match_suggestions(expected.clone(), suggestions);
// Test use completion
let completion_str = "use ".to_string();
let suggestions = completer.complete(&completion_str, completion_str.len());
match_suggestions(&expected, &suggestions);
match_suggestions(expected.clone(), suggestions);
// Test overlay use completion
let completion_str = "overlay use ".to_string();
let suggestions = completer.complete(&completion_str, completion_str.len());
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[test]
@ -271,22 +258,8 @@ fn file_completions() {
folder(dir.join(".hidden_folder")),
];
#[cfg(windows)]
{
let separator = '/';
let target_dir = format!("cp {dir_str}{separator}");
let slash_suggestions = completer.complete(&target_dir, target_dir.len());
let expected_slash_paths: Vec<String> = expected_paths
.iter()
.map(|s| s.replace('\\', "/"))
.collect();
match_suggestions(&expected_slash_paths, &slash_suggestions);
}
// Match the results
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
// Test completions for a file
let target_dir = format!("cp {}", folder(dir.join("another")));
@ -296,91 +269,17 @@ fn file_completions() {
let expected_paths: Vec<String> = vec![file(dir.join("another").join("newfile"))];
// Match the results
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
// Test completions for hidden files
let target_dir = format!("ls {}{MAIN_SEPARATOR}.", folder(dir.join(".hidden_folder")));
let target_dir = format!("ls {}/.", folder(dir.join(".hidden_folder")));
let suggestions = completer.complete(&target_dir, target_dir.len());
let expected_paths: Vec<String> =
vec![file(dir.join(".hidden_folder").join(".hidden_subfile"))];
#[cfg(windows)]
{
let target_dir = format!("ls {}/.", folder(dir.join(".hidden_folder")));
let slash_suggestions = completer.complete(&target_dir, target_dir.len());
let expected_slash: Vec<String> = expected_paths
.iter()
.map(|s| s.replace('\\', "/"))
.collect();
match_suggestions(&expected_slash, &slash_suggestions);
}
// Match the results
match_suggestions(&expected_paths, &suggestions);
}
#[cfg(windows)]
#[test]
fn file_completions_with_mixed_separators() {
// Create a new engine
let (dir, dir_str, engine, stack) = new_dotnu_engine();
// Instantiate a new completer
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
// Create Expected values
let expected_paths: Vec<String> = vec![
file(dir.join("lib-dir1").join("bar.nu")),
file(dir.join("lib-dir1").join("baz.nu")),
file(dir.join("lib-dir1").join("xyzzy.nu")),
];
let expecetd_slash_paths: Vec<String> = expected_paths
.iter()
.map(|s| s.replace(MAIN_SEPARATOR, "/"))
.collect();
let target_dir = format!("ls {dir_str}/lib-dir1/");
let suggestions = completer.complete(&target_dir, target_dir.len());
match_suggestions(&expecetd_slash_paths, &suggestions);
let target_dir = format!("cp {dir_str}\\lib-dir1/");
let suggestions = completer.complete(&target_dir, target_dir.len());
match_suggestions(&expecetd_slash_paths, &suggestions);
let target_dir = format!("ls {dir_str}/lib-dir1\\/");
let suggestions = completer.complete(&target_dir, target_dir.len());
match_suggestions(&expecetd_slash_paths, &suggestions);
let target_dir = format!("ls {dir_str}\\lib-dir1\\/");
let suggestions = completer.complete(&target_dir, target_dir.len());
match_suggestions(&expecetd_slash_paths, &suggestions);
let target_dir = format!("ls {dir_str}\\lib-dir1\\");
let suggestions = completer.complete(&target_dir, target_dir.len());
match_suggestions(&expected_paths, &suggestions);
let target_dir = format!("ls {dir_str}/lib-dir1\\");
let suggestions = completer.complete(&target_dir, target_dir.len());
match_suggestions(&expected_paths, &suggestions);
let target_dir = format!("ls {dir_str}/lib-dir1/\\");
let suggestions = completer.complete(&target_dir, target_dir.len());
match_suggestions(&expected_paths, &suggestions);
let target_dir = format!("ls {dir_str}\\lib-dir1/\\");
let suggestions = completer.complete(&target_dir, target_dir.len());
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
}
#[test]
@ -404,7 +303,7 @@ fn partial_completions() {
];
// Match the results
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
// Test completions for the files whose name begin with "h"
// and are present under directories whose names begin with "pa"
@ -425,7 +324,7 @@ fn partial_completions() {
];
// Match the results
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
// Test completion for all files under directories whose names begin with "pa"
let dir_str = folder(dir.join("pa"));
@ -446,7 +345,7 @@ fn partial_completions() {
];
// Match the results
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
// Test completion for a single file
let dir_str = file(dir.join("fi").join("so"));
@ -457,7 +356,7 @@ fn partial_completions() {
let expected_paths: Vec<String> = vec![file(dir.join("final_partial").join("somefile"))];
// Match the results
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
// Test completion where there is a sneaky `..` in the path
let dir_str = file(dir.join("par").join("..").join("fi").join("so"));
@ -493,7 +392,7 @@ fn partial_completions() {
];
// Match the results
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
// Test completion for all files under directories whose names begin with "pa"
let file_str = file(dir.join("partial-a").join("have"));
@ -507,7 +406,7 @@ fn partial_completions() {
];
// Match the results
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
// Test completion for all files under directories whose names begin with "pa"
let file_str = file(dir.join("partial-a").join("have_ext."));
@ -521,7 +420,7 @@ fn partial_completions() {
];
// Match the results
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
}
#[test]
@ -556,16 +455,15 @@ fn command_ls_with_filecompletion() {
".hidden_folder/".to_string(),
];
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
let target_dir = "ls custom_completion.";
let suggestions = completer.complete(target_dir, target_dir.len());
let expected_paths: Vec<String> = vec!["custom_completion.nu".to_string()];
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions)
}
#[test]
fn command_open_with_filecompletion() {
let (_, _, engine, stack) = new_engine();
@ -598,14 +496,14 @@ fn command_open_with_filecompletion() {
".hidden_folder/".to_string(),
];
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
let target_dir = "open custom_completion.";
let suggestions = completer.complete(target_dir, target_dir.len());
let expected_paths: Vec<String> = vec!["custom_completion.nu".to_string()];
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions)
}
#[test]
@ -640,7 +538,7 @@ fn command_rm_with_globcompletion() {
".hidden_folder/".to_string(),
];
match_suggestions(&expected_paths, &suggestions)
match_suggestions(expected_paths, suggestions)
}
#[test]
@ -675,7 +573,7 @@ fn command_cp_with_globcompletion() {
".hidden_folder/".to_string(),
];
match_suggestions(&expected_paths, &suggestions)
match_suggestions(expected_paths, suggestions)
}
#[test]
@ -710,7 +608,7 @@ fn command_save_with_filecompletion() {
".hidden_folder/".to_string(),
];
match_suggestions(&expected_paths, &suggestions)
match_suggestions(expected_paths, suggestions)
}
#[test]
@ -745,7 +643,7 @@ fn command_touch_with_filecompletion() {
".hidden_folder/".to_string(),
];
match_suggestions(&expected_paths, &suggestions)
match_suggestions(expected_paths, suggestions)
}
#[test]
@ -780,7 +678,7 @@ fn command_watch_with_filecompletion() {
".hidden_folder/".to_string(),
];
match_suggestions(&expected_paths, &suggestions)
match_suggestions(expected_paths, suggestions)
}
#[rstest]
@ -788,19 +686,19 @@ fn subcommand_completions(mut subcommand_completer: NuCompleter) {
let prefix = "foo br";
let suggestions = subcommand_completer.complete(prefix, prefix.len());
match_suggestions(
&vec!["foo bar".to_string(), "foo aabcrr".to_string()],
&suggestions,
vec!["foo bar".to_string(), "foo aabrr".to_string()],
suggestions,
);
let prefix = "foo b";
let suggestions = subcommand_completer.complete(prefix, prefix.len());
match_suggestions(
&vec![
vec![
"foo bar".to_string(),
"foo aabcrr".to_string(),
"foo abaz".to_string(),
"foo aabrr".to_string(),
],
&suggestions,
suggestions,
);
}
@ -823,10 +721,10 @@ fn file_completion_quoted() {
"`te#st.txt`".to_string(),
"`te'st.txt`".to_string(),
"`te(st).txt`".to_string(),
format!("`{}`", folder("test dir")),
format!("`{}`", folder("test dir".into())),
];
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
let dir: PathBuf = "test dir".into();
let target_dir = format!("open '{}'", folder(dir.clone()));
@ -837,7 +735,7 @@ fn file_completion_quoted() {
format!("`{}`", file(dir.join("single quote"))),
];
match_suggestions(&expected_paths, &suggestions)
match_suggestions(expected_paths, suggestions)
}
#[test]
@ -872,7 +770,7 @@ fn flag_completions() {
];
// Match results
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[test]
@ -896,21 +794,8 @@ fn folder_with_directorycompletions() {
folder(dir.join(".hidden_folder")),
];
#[cfg(windows)]
{
let target_dir = format!("cd {dir_str}/");
let slash_suggestions = completer.complete(&target_dir, target_dir.len());
let expected_slash_paths: Vec<String> = expected_paths
.iter()
.map(|s| s.replace('\\', "/"))
.collect();
match_suggestions(&expected_slash_paths, &slash_suggestions);
}
// Match the results
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
}
#[test]
@ -948,11 +833,11 @@ fn variables_completions() {
"plugin-path".into(),
"startup-time".into(),
"temp-path".into(),
"vendor-autoload-dirs".into(),
"vendor-autoload-dir".into(),
];
// Match results
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
// Test completions for $nu.h (filter)
let suggestions = completer.complete("$nu.h", 5);
@ -966,7 +851,7 @@ fn variables_completions() {
];
// Match results
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
// Test completions for $nu.os-info
let suggestions = completer.complete("$nu.os-info.", 12);
@ -978,7 +863,7 @@ fn variables_completions() {
"name".into(),
];
// Match results
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
// Test completions for custom var
let suggestions = completer.complete("$actor.", 7);
@ -988,7 +873,7 @@ fn variables_completions() {
let expected: Vec<String> = vec!["age".into(), "name".into()];
// Match results
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
// Test completions for custom var (filtering)
let suggestions = completer.complete("$actor.n", 8);
@ -998,7 +883,7 @@ fn variables_completions() {
let expected: Vec<String> = vec!["name".into()];
// Match results
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
// Test completions for $env
let suggestions = completer.complete("$env.", 5);
@ -1011,7 +896,7 @@ fn variables_completions() {
let expected: Vec<String> = vec!["PATH".into(), "PWD".into(), "TEST".into()];
// Match results
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
// Test completions for $env
let suggestions = completer.complete("$env.T", 6);
@ -1021,12 +906,12 @@ fn variables_completions() {
let expected: Vec<String> = vec!["TEST".into()];
// Match results
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
let suggestions = completer.complete("$", 1);
let expected: Vec<String> = vec!["$actor".into(), "$env".into(), "$in".into(), "$nu".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[test]
@ -1045,7 +930,7 @@ fn alias_of_command_and_flags() {
#[cfg(not(windows))]
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
match_suggestions(&expected_paths, &suggestions)
match_suggestions(expected_paths, suggestions)
}
#[test]
@ -1064,7 +949,7 @@ fn alias_of_basic_command() {
#[cfg(not(windows))]
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
match_suggestions(&expected_paths, &suggestions)
match_suggestions(expected_paths, suggestions)
}
#[test]
@ -1086,7 +971,7 @@ fn alias_of_another_alias() {
#[cfg(not(windows))]
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
match_suggestions(&expected_paths, &suggestions)
match_suggestions(expected_paths, suggestions)
}
fn run_external_completion(completer: &str, input: &str) -> Vec<Suggestion> {
@ -1149,35 +1034,35 @@ fn unknown_command_completion() {
".hidden_folder/".to_string(),
];
match_suggestions(&expected_paths, &suggestions)
match_suggestions(expected_paths, suggestions)
}
#[rstest]
fn flagcompletion_triggers_after_cursor(mut completer: NuCompleter) {
let suggestions = completer.complete("tst -h", 5);
let expected: Vec<String> = vec!["--help".into(), "--mod".into(), "-h".into(), "-s".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn customcompletion_triggers_after_cursor(mut completer_strings: NuCompleter) {
let suggestions = completer_strings.complete("my-command c", 11);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn customcompletion_triggers_after_cursor_piped(mut completer_strings: NuCompleter) {
let suggestions = completer_strings.complete("my-command c | ls", 11);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn flagcompletion_triggers_after_cursor_piped(mut completer: NuCompleter) {
let suggestions = completer.complete("tst -h | ls", 5);
let expected: Vec<String> = vec!["--help".into(), "--mod".into(), "-h".into(), "-s".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[test]
@ -1211,88 +1096,77 @@ fn filecompletions_triggers_after_cursor() {
".hidden_folder/".to_string(),
];
match_suggestions(&expected_paths, &suggestions);
match_suggestions(expected_paths, suggestions);
}
#[rstest]
fn extern_custom_completion_positional(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam ", 5);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn extern_custom_completion_long_flag_1(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam --foo=", 11);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn extern_custom_completion_long_flag_2(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam --foo ", 11);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn extern_custom_completion_long_flag_short(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam -f ", 8);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn extern_custom_completion_short_flag(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam -b ", 8);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn extern_complete_flags(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam -", 6);
let expected: Vec<String> = vec!["--foo".into(), "-b".into(), "-f".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn custom_completer_triggers_cursor_before_word(mut custom_completer: NuCompleter) {
let suggestions = custom_completer.complete("cmd foo bar", 8);
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn custom_completer_triggers_cursor_on_word_left_boundary(mut custom_completer: NuCompleter) {
let suggestions = custom_completer.complete("cmd foo bar", 8);
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn custom_completer_triggers_cursor_next_to_word(mut custom_completer: NuCompleter) {
let suggestions = custom_completer.complete("cmd foo bar", 11);
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "bar".into()];
match_suggestions(&expected, &suggestions);
match_suggestions(expected, suggestions);
}
#[rstest]
fn custom_completer_triggers_cursor_after_word(mut custom_completer: NuCompleter) {
let suggestions = custom_completer.complete("cmd foo bar ", 12);
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "bar".into(), "".into()];
match_suggestions(&expected, &suggestions);
}
#[rstest]
fn sort_fuzzy_completions_in_alphabetical_order(mut fuzzy_alpha_sort_completer: NuCompleter) {
let suggestions = fuzzy_alpha_sort_completer.complete("ls nu", 5);
// Even though "nushell" is a better match, it should come second because
// the completions should be sorted in alphabetical order
match_suggestions(
&vec!["custom_completion.nu".into(), "nushell".into()],
&suggestions,
);
match_suggestions(expected, suggestions);
}
#[ignore = "was reverted, still needs fixing"]

View File

@ -1,6 +1,5 @@
use nu_engine::eval_block;
use nu_parser::parse;
use nu_path::{AbsolutePathBuf, PathBuf};
use nu_protocol::{
debugger::WithoutDebug,
engine::{EngineState, Stack, StateWorkingSet},
@ -8,14 +7,14 @@ use nu_protocol::{
};
use nu_test_support::fs;
use reedline::Suggestion;
use std::path::MAIN_SEPARATOR;
use std::path::{PathBuf, MAIN_SEPARATOR};
fn create_default_context() -> EngineState {
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context())
}
// creates a new engine with the current path into the completions fixtures folder
pub fn new_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
pub fn new_engine() -> (PathBuf, String, EngineState, Stack) {
// Target folder inside assets
let dir = fs::fixtures().join("completions");
let dir_str = dir
@ -70,7 +69,7 @@ pub fn new_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
}
// creates a new engine with the current path into the completions fixtures folder
pub fn new_dotnu_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
pub fn new_dotnu_engine() -> (PathBuf, String, EngineState, Stack) {
// Target folder inside assets
let dir = fs::fixtures().join("dotnu_completions");
let dir_str = dir
@ -115,7 +114,7 @@ pub fn new_dotnu_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
(dir, dir_str, engine_state, stack)
}
pub fn new_quote_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
pub fn new_quote_engine() -> (PathBuf, String, EngineState, Stack) {
// Target folder inside assets
let dir = fs::fixtures().join("quoted_completions");
let dir_str = dir
@ -150,7 +149,7 @@ pub fn new_quote_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
(dir, dir_str, engine_state, stack)
}
pub fn new_partial_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
pub fn new_partial_engine() -> (PathBuf, String, EngineState, Stack) {
// Target folder inside assets
let dir = fs::fixtures().join("partial_completions");
let dir_str = dir
@ -186,7 +185,7 @@ pub fn new_partial_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
}
// match a list of suggestions with the expected values
pub fn match_suggestions(expected: &Vec<String>, suggestions: &Vec<Suggestion>) {
pub fn match_suggestions(expected: Vec<String>, suggestions: Vec<Suggestion>) {
let expected_len = expected.len();
let suggestions_len = suggestions.len();
if expected_len != suggestions_len {
@ -196,25 +195,26 @@ pub fn match_suggestions(expected: &Vec<String>, suggestions: &Vec<Suggestion>)
Expected: {expected:#?}\n"
)
}
let suggestoins_str = suggestions
.iter()
.map(|it| it.value.clone())
.collect::<Vec<_>>();
assert_eq!(expected, &suggestoins_str);
assert_eq!(
expected,
suggestions
.into_iter()
.map(|it| it.value)
.collect::<Vec<_>>()
);
}
// append the separator to the converted path
pub fn folder(path: impl Into<PathBuf>) -> String {
pub fn folder(path: PathBuf) -> String {
let mut converted_path = file(path);
converted_path.push(MAIN_SEPARATOR);
converted_path
}
// convert a given path to string
pub fn file(path: impl Into<PathBuf>) -> String {
path.into().into_os_string().into_string().unwrap()
pub fn file(path: PathBuf) -> String {
path.into_os_string().into_string().unwrap_or_default()
}
// merge_input executes the given input into the engine
@ -223,7 +223,7 @@ pub fn merge_input(
input: &[u8],
engine_state: &mut EngineState,
stack: &mut Stack,
dir: AbsolutePathBuf,
dir: PathBuf,
) -> Result<(), ShellError> {
let (block, delta) = {
let mut working_set = StateWorkingSet::new(engine_state);

View File

@ -5,15 +5,15 @@ edition = "2021"
license = "MIT"
name = "nu-cmd-base"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
version = "0.96.2"
version = "0.95.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.96.2" }
nu-parser = { path = "../nu-parser", version = "0.96.2" }
nu-path = { path = "../nu-path", version = "0.96.2" }
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
nu-engine = { path = "../nu-engine", version = "0.95.1" }
nu-parser = { path = "../nu-parser", version = "0.95.1" }
nu-path = { path = "../nu-path", version = "0.95.1" }
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
indexmap = { workspace = true }
miette = { workspace = true }

View File

@ -1,5 +0,0 @@
Utilities used by the different `nu-command`/`nu-cmd-*` crates, should not contain any full `Command` implementations.
## Internal Nushell crate
This crate implements components of Nushell and is not designed to support plugin authors or other users directly.

View File

@ -1,4 +1,3 @@
#![doc = include_str!("../README.md")]
pub mod formats;
pub mod hook;
pub mod input_handler;

View File

@ -1,28 +1,21 @@
use nu_path::AbsolutePathBuf;
use nu_protocol::{
engine::{EngineState, Stack},
Range, ShellError, Span, Value,
};
use std::ops::Bound;
use std::{ops::Bound, path::PathBuf};
pub fn get_init_cwd() -> AbsolutePathBuf {
std::env::current_dir()
.ok()
.and_then(|path| AbsolutePathBuf::try_from(path).ok())
.or_else(|| {
std::env::var("PWD")
.ok()
.and_then(|path| AbsolutePathBuf::try_from(path).ok())
})
.or_else(nu_path::home_dir)
.expect("Failed to get current working directory")
pub fn get_init_cwd() -> PathBuf {
std::env::current_dir().unwrap_or_else(|_| {
std::env::var("PWD")
.map(Into::into)
.unwrap_or_else(|_| nu_path::home_dir().unwrap_or_default())
})
}
pub fn get_guaranteed_cwd(engine_state: &EngineState, stack: &Stack) -> AbsolutePathBuf {
pub fn get_guaranteed_cwd(engine_state: &EngineState, stack: &Stack) -> PathBuf {
engine_state
.cwd(Some(stack))
.ok()
.unwrap_or_else(get_init_cwd)
.unwrap_or(crate::util::get_init_cwd())
}
type MakeRangeError = fn(&str, Span) -> ShellError;

View File

@ -5,7 +5,7 @@ edition = "2021"
license = "MIT"
name = "nu-cmd-extra"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-extra"
version = "0.96.2"
version = "0.95.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -13,13 +13,13 @@ version = "0.96.2"
bench = false
[dependencies]
nu-cmd-base = { path = "../nu-cmd-base", version = "0.96.2" }
nu-engine = { path = "../nu-engine", version = "0.96.2" }
nu-json = { version = "0.96.2", path = "../nu-json" }
nu-parser = { path = "../nu-parser", version = "0.96.2" }
nu-pretty-hex = { version = "0.96.2", path = "../nu-pretty-hex" }
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
nu-utils = { path = "../nu-utils", version = "0.96.2" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.95.1" }
nu-engine = { path = "../nu-engine", version = "0.95.1" }
nu-json = { version = "0.95.1", path = "../nu-json" }
nu-parser = { path = "../nu-parser", version = "0.95.1" }
nu-pretty-hex = { version = "0.95.1", path = "../nu-pretty-hex" }
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
nu-utils = { path = "../nu-utils", version = "0.95.1" }
# Potential dependencies for extras
heck = { workspace = true }
@ -33,6 +33,6 @@ v_htmlescape = { workspace = true }
itertools = { workspace = true }
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.96.2" }
nu-command = { path = "../nu-command", version = "0.96.2" }
nu-test-support = { path = "../nu-test-support", version = "0.96.2" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.95.1" }
nu-command = { path = "../nu-command", version = "0.95.1" }
nu-test-support = { path = "../nu-test-support", version = "0.95.1" }

View File

@ -239,7 +239,7 @@ fn to_html(
let partial = call.has_flag(engine_state, stack, "partial")?;
let list = call.has_flag(engine_state, stack, "list")?;
let theme: Option<Spanned<String>> = call.get_flag(engine_state, stack, "theme")?;
let config = &stack.get_config(engine_state);
let config = engine_state.get_config();
let vec_of_values = input.into_iter().collect::<Vec<Value>>();
let headers = merge_descriptors(&vec_of_values);

View File

@ -1,5 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::{ast::PathMember, engine::StateWorkingSet, Config, ListStream};
use nu_protocol::{ast::PathMember, engine::StateWorkingSet, ListStream};
#[derive(Clone)]
pub struct FormatPattern;
@ -43,8 +43,6 @@ impl Command for FormatPattern {
let it_id = working_set.add_variable(b"$it".to_vec(), call.head, Type::Any, false);
stack.add_var(it_id, input_val.clone());
let config = stack.get_config(engine_state);
match specified_pattern {
Err(e) => Err(e),
Ok(pattern) => {
@ -58,7 +56,7 @@ impl Command for FormatPattern {
string_span.start + 1,
)?;
format(input_val, &ops, engine_state, &config, call.head)
format(input_val, &ops, engine_state, call.head)
}
}
}
@ -183,30 +181,33 @@ fn format(
input_data: Value,
format_operations: &[FormatOperation],
engine_state: &EngineState,
config: &Config,
head_span: Span,
) -> Result<PipelineData, ShellError> {
let data_as_value = input_data;
// We can only handle a Record or a List of Records
match data_as_value {
Value::Record { .. } => match format_record(format_operations, &data_as_value, config) {
Ok(value) => Ok(PipelineData::Value(Value::string(value, head_span), None)),
Err(value) => Err(value),
},
Value::Record { .. } => {
match format_record(format_operations, &data_as_value, engine_state) {
Ok(value) => Ok(PipelineData::Value(Value::string(value, head_span), None)),
Err(value) => Err(value),
}
}
Value::List { vals, .. } => {
let mut list = vec![];
for val in vals.iter() {
match val {
Value::Record { .. } => match format_record(format_operations, val, config) {
Ok(value) => {
list.push(Value::string(value, head_span));
Value::Record { .. } => {
match format_record(format_operations, val, engine_state) {
Ok(value) => {
list.push(Value::string(value, head_span));
}
Err(value) => {
return Err(value);
}
}
Err(value) => {
return Err(value);
}
},
}
Value::Error { error, .. } => return Err(*error.clone()),
_ => {
return Err(ShellError::OnlySupportsThisInputType {
@ -236,8 +237,9 @@ fn format(
fn format_record(
format_operations: &[FormatOperation],
data_as_value: &Value,
config: &Config,
engine_state: &EngineState,
) -> Result<String, ShellError> {
let config = engine_state.get_config();
let mut output = String::new();
for op in format_operations {

View File

@ -1,4 +1,3 @@
#![doc = include_str!("../README.md")]
mod example_test;
pub mod extra;
pub use extra::*;

View File

@ -6,22 +6,22 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-lang"
edition = "2021"
license = "MIT"
name = "nu-cmd-lang"
version = "0.96.2"
version = "0.95.1"
[lib]
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.96.2" }
nu-parser = { path = "../nu-parser", version = "0.96.2" }
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
nu-utils = { path = "../nu-utils", version = "0.96.2" }
nu-engine = { path = "../nu-engine", version = "0.95.1" }
nu-parser = { path = "../nu-parser", version = "0.95.1" }
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
nu-utils = { path = "../nu-utils", version = "0.95.1" }
itertools = { workspace = true }
shadow-rs = { version = "0.30", default-features = false }
shadow-rs = { version = "0.29", default-features = false }
[build-dependencies]
shadow-rs = { version = "0.30", default-features = false }
shadow-rs = { version = "0.29", default-features = false }
[features]
mimalloc = []

View File

@ -21,9 +21,7 @@ impl Command for Break {
fn extra_usage(&self) -> &str {
r#"This command is a parser keyword. For details, check:
https://www.nushell.sh/book/thinking_in_nu.html
break can only be used in while, loop, and for loops. It can not be used with each or other filter commands"#
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn command_type(&self) -> CommandType {

View File

@ -46,9 +46,6 @@ impl Command for Const {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
// This is compiled specially by the IR compiler. The code here is never used when
// running in IR mode.
let call = call.assert_ast_call()?;
let var_id = if let Some(id) = call.positional_nth(0).and_then(|pos| pos.as_var()) {
id
} else {

View File

@ -21,9 +21,7 @@ impl Command for Continue {
fn extra_usage(&self) -> &str {
r#"This command is a parser keyword. For details, check:
https://www.nushell.sh/book/thinking_in_nu.html
continue can only be used in while, loop, and for loops. It can not be used with each or other filter commands"#
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn command_type(&self) -> CommandType {

View File

@ -81,10 +81,6 @@ impl Command for Do {
bind_args_to(&mut callee_stack, &block.signature, rest, head)?;
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
// Applies to all block evaluation once set true
callee_stack.use_ir = caller_stack.has_env_var(engine_state, "NU_USE_IR");
let result = eval_block_with_early_return(engine_state, &mut callee_stack, block, input);
if has_env {

View File

@ -48,9 +48,6 @@ impl Command for For {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
// This is compiled specially by the IR compiler. The code here is never used when
// running in IR mode.
let call = call.assert_ast_call()?;
let head = call.head;
let var_id = call
.positional_nth(0)

View File

@ -60,9 +60,6 @@ impl Command for If {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
// This is compiled specially by the IR compiler. The code here is never used when
// running in IR mode.
let call = call.assert_ast_call()?;
let cond = call.positional_nth(0).expect("checked through parser");
let then_block = call
.positional_nth(1)
@ -102,9 +99,6 @@ impl Command for If {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
// This is compiled specially by the IR compiler. The code here is never used when
// running in IR mode.
let call = call.assert_ast_call()?;
let cond = call.positional_nth(0).expect("checked through parser");
let then_block = call
.positional_nth(1)

View File

@ -46,9 +46,6 @@ impl Command for Let {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
// This is compiled specially by the IR compiler. The code here is never used when
// running in IR mode.
let call = call.assert_ast_call()?;
let var_id = call
.positional_nth(0)
.expect("checked through parser")

View File

@ -37,9 +37,6 @@ impl Command for Loop {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
// This is compiled specially by the IR compiler. The code here is never used when
// running in IR mode.
let call = call.assert_ast_call()?;
let head = call.head;
let block_id = call
.positional_nth(0)

View File

@ -43,9 +43,6 @@ impl Command for Match {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
// This is compiled specially by the IR compiler. The code here is never used when
// running in IR mode.
let call = call.assert_ast_call()?;
let value: Value = call.req(engine_state, stack, 0)?;
let matches = call
.positional_nth(1)

View File

@ -46,9 +46,6 @@ impl Command for Mut {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
// This is compiled specially by the IR compiler. The code here is never used when
// running in IR mode.
let call = call.assert_ast_call()?;
let var_id = call
.positional_nth(0)
.expect("checked through parser")

View File

@ -65,9 +65,9 @@ impl Command for OverlayUse {
name_arg.item = trim_quotes_str(&name_arg.item).to_string();
let maybe_origin_module_id =
if let Some(overlay_expr) = call.get_parser_info(caller_stack, "overlay_expr") {
if let Some(overlay_expr) = call.get_parser_info("overlay_expr") {
if let Expr::Overlay(module_id) = &overlay_expr.expr {
*module_id
module_id
} else {
return Err(ShellError::NushellFailedSpanned {
msg: "Not an overlay".to_string(),
@ -110,7 +110,7 @@ impl Command for OverlayUse {
// a) adding a new overlay
// b) refreshing an active overlay (the origin module changed)
let module = engine_state.get_module(module_id);
let module = engine_state.get_module(*module_id);
// Evaluate the export-env block (if any) and keep its environment
if let Some(block_id) = module.env_block {
@ -118,7 +118,7 @@ impl Command for OverlayUse {
&name_arg.item,
engine_state,
caller_stack,
get_dirs_var_from_call(caller_stack, call),
get_dirs_var_from_call(call),
)?;
let block = engine_state.get_block(block_id);

View File

@ -47,9 +47,6 @@ impl Command for Try {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
// This is compiled specially by the IR compiler. The code here is never used when
// running in IR mode.
let call = call.assert_ast_call()?;
let try_block = call
.positional_nth(0)
.expect("checked through parser")

View File

@ -57,7 +57,7 @@ This command is a parser keyword. For details, check:
let Some(Expression {
expr: Expr::ImportPattern(import_pattern),
..
}) = call.get_parser_info(caller_stack, "import_pattern")
}) = call.get_parser_info("import_pattern")
else {
return Err(ShellError::GenericError {
error: "Unexpected import".into(),
@ -68,9 +68,6 @@ This command is a parser keyword. For details, check:
});
};
// Necessary so that we can modify the stack.
let import_pattern = import_pattern.clone();
if let Some(module_id) = import_pattern.head.id {
// Add constants
for var_id in &import_pattern.constants {
@ -102,7 +99,7 @@ This command is a parser keyword. For details, check:
&module_arg_str,
engine_state,
caller_stack,
get_dirs_var_from_call(caller_stack, call),
get_dirs_var_from_call(call),
)?;
let maybe_parent = maybe_file_path
.as_ref()

View File

@ -46,9 +46,6 @@ impl Command for While {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
// This is compiled specially by the IR compiler. The code here is never used when
// running in IR mode.
let call = call.assert_ast_call()?;
let head = call.head;
let cond = call.positional_nth(0).expect("checked through parser");
let block_id = call

View File

@ -4,7 +4,7 @@ use nu_protocol::{
ast::Block,
debugger::WithoutDebug,
engine::{StateDelta, StateWorkingSet},
report_error_new, Range,
Range,
};
use std::{
sync::Arc,
@ -72,7 +72,7 @@ pub fn check_example_input_and_output_types_match_command_signature(
witnessed_type_transformations
}
pub fn eval_pipeline_without_terminal_expression(
fn eval_pipeline_without_terminal_expression(
src: &str,
cwd: &std::path::Path,
engine_state: &mut Box<EngineState>,
@ -124,10 +124,7 @@ pub fn eval_block(
nu_engine::eval_block::<WithoutDebug>(engine_state, &mut stack, &block, input)
.and_then(|data| data.into_value(Span::test_data()))
.unwrap_or_else(|err| {
report_error_new(engine_state, &err);
panic!("test eval error in `{}`: {:?}", "TODO", err)
})
.unwrap_or_else(|err| panic!("test eval error in `{}`: {:?}", "TODO", err))
}
pub fn check_example_evaluates_to_expected_output(

View File

@ -1,4 +1,3 @@
#![doc = include_str!("../README.md")]
mod core_commands;
mod default_context;
pub mod example_support;

View File

@ -5,15 +5,15 @@ edition = "2021"
license = "MIT"
name = "nu-cmd-plugin"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-plugin"
version = "0.96.2"
version = "0.95.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.96.2" }
nu-path = { path = "../nu-path", version = "0.96.2" }
nu-protocol = { path = "../nu-protocol", version = "0.96.2", features = ["plugin"] }
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.96.2" }
nu-engine = { path = "../nu-engine", version = "0.95.1" }
nu-path = { path = "../nu-path", version = "0.95.1" }
nu-protocol = { path = "../nu-protocol", version = "0.95.1", features = ["plugin"] }
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.95.1" }
itertools = { workspace = true }

View File

@ -5,18 +5,18 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-color-confi
edition = "2021"
license = "MIT"
name = "nu-color-config"
version = "0.96.2"
version = "0.95.1"
[lib]
bench = false
[dependencies]
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
nu-engine = { path = "../nu-engine", version = "0.96.2" }
nu-json = { path = "../nu-json", version = "0.96.2" }
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
nu-engine = { path = "../nu-engine", version = "0.95.1" }
nu-json = { path = "../nu-json", version = "0.95.1" }
nu-ansi-term = { workspace = true }
serde = { workspace = true, features = ["derive"] }
[dev-dependencies]
nu-test-support = { path = "../nu-test-support", version = "0.96.2" }
nu-test-support = { path = "../nu-test-support", version = "0.95.1" }

View File

@ -1,5 +0,0 @@
Logic to resolve colors for syntax highlighting and output formatting
## Internal Nushell crate
This crate implements components of Nushell and is not designed to support plugin authors or other users directly.

View File

@ -1,4 +1,3 @@
#![doc = include_str!("../README.md")]
mod color_config;
mod matching_brackets_style;
mod nu_style;

View File

@ -1,6 +1,6 @@
use crate::{color_record_to_nustyle, lookup_ansi_color_style, text_style::Alignment, TextStyle};
use nu_ansi_term::{Color, Style};
use nu_engine::ClosureEvalOnce;
use nu_engine::{env::get_config, ClosureEvalOnce};
use nu_protocol::{
cli_error::CliError,
engine::{Closure, EngineState, Stack, StateWorkingSet},
@ -114,7 +114,7 @@ impl<'a> StyleComputer<'a> {
// The main constructor.
pub fn from_config(engine_state: &'a EngineState, stack: &'a Stack) -> StyleComputer<'a> {
let config = stack.get_config(engine_state);
let config = get_config(engine_state, stack);
// Create the hashmap
#[rustfmt::skip]

View File

@ -5,7 +5,7 @@ edition = "2021"
license = "MIT"
name = "nu-command"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command"
version = "0.96.2"
version = "0.95.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -13,21 +13,21 @@ version = "0.96.2"
bench = false
[dependencies]
nu-cmd-base = { path = "../nu-cmd-base", version = "0.96.2" }
nu-color-config = { path = "../nu-color-config", version = "0.96.2" }
nu-engine = { path = "../nu-engine", version = "0.96.2" }
nu-glob = { path = "../nu-glob", version = "0.96.2" }
nu-json = { path = "../nu-json", version = "0.96.2" }
nu-parser = { path = "../nu-parser", version = "0.96.2" }
nu-path = { path = "../nu-path", version = "0.96.2" }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.96.2" }
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
nu-system = { path = "../nu-system", version = "0.96.2" }
nu-table = { path = "../nu-table", version = "0.96.2" }
nu-term-grid = { path = "../nu-term-grid", version = "0.96.2" }
nu-utils = { path = "../nu-utils", version = "0.96.2" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.95.1" }
nu-color-config = { path = "../nu-color-config", version = "0.95.1" }
nu-engine = { path = "../nu-engine", version = "0.95.1" }
nu-glob = { path = "../nu-glob", version = "0.95.1" }
nu-json = { path = "../nu-json", version = "0.95.1" }
nu-parser = { path = "../nu-parser", version = "0.95.1" }
nu-path = { path = "../nu-path", version = "0.95.1" }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.95.1" }
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
nu-system = { path = "../nu-system", version = "0.95.1" }
nu-table = { path = "../nu-table", version = "0.95.1" }
nu-term-grid = { path = "../nu-term-grid", version = "0.95.1" }
nu-utils = { path = "../nu-utils", version = "0.95.1" }
nu-ansi-term = { workspace = true }
nuon = { path = "../nuon", version = "0.96.2" }
nuon = { path = "../nuon", version = "0.95.1" }
alphanumeric-sort = { workspace = true }
base64 = { workspace = true }
@ -137,10 +137,10 @@ sqlite = ["rusqlite"]
trash-support = ["trash"]
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.96.2" }
nu-test-support = { path = "../nu-test-support", version = "0.96.2" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.95.1" }
nu-test-support = { path = "../nu-test-support", version = "0.95.1" }
dirs = { workspace = true }
dirs-next = { workspace = true }
mockito = { workspace = true, default-features = false }
quickcheck = { workspace = true }
quickcheck_macros = { workspace = true }

View File

@ -1,7 +0,0 @@
This crate contains the majority of our commands
We allow ourselves to move some of the commands in `nu-command` to `nu-cmd-*` crates as needed.
## Internal Nushell crate
This crate implements components of Nushell and is not designed to support plugin authors or other users directly.

View File

@ -49,8 +49,10 @@ impl Command for BytesBuild {
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let mut output = vec![];
let eval_expression = get_eval_expression(engine_state);
for val in call.rest_iter_flattened(engine_state, stack, eval_expression, 0)? {
for val in call.rest_iter_flattened(0, |expr| {
let eval_expression = get_eval_expression(engine_state);
eval_expression(engine_state, stack, expr)
})? {
let val_span = val.span();
match val {
Value::Binary { mut val, .. } => output.append(&mut val),

View File

@ -177,9 +177,11 @@ fn run_histogram(
match v {
// parse record, and fill valid value to actual input.
Value::Record { val, .. } => {
if let Some(v) = val.get(col_name) {
if let Ok(v) = HashableValue::from_value(v.clone(), head_span) {
inputs.push(v);
for (c, v) in val.iter() {
if c == col_name {
if let Ok(v) = HashableValue::from_value(v.clone(), head_span) {
inputs.push(v);
}
}
}
}

View File

@ -150,9 +150,13 @@ fn fill(
FillAlignment::Left
};
let width = width_arg.unwrap_or(1);
let width = if let Some(arg) = width_arg { arg } else { 1 };
let character = character_arg.unwrap_or_else(|| " ".to_string());
let character = if let Some(arg) = character_arg {
arg
} else {
" ".to_string()
};
let arg = Arguments {
width,

View File

@ -379,47 +379,42 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
// If input is not a timestamp, try parsing it as a string
let span = input.span();
let parse_as_string = |val: &str| {
match dateformat {
Some(dt) => match DateTime::parse_from_str(val, &dt.0) {
Ok(d) => Value::date ( d, head ),
Err(reason) => {
match NaiveDateTime::parse_from_str(val, &dt.0) {
Ok(d) => Value::date (
DateTime::from_naive_utc_and_offset(
d,
*Local::now().offset(),
),
head,
),
Err(_) => {
Value::error (
ShellError::CantConvert { to_type: format!("could not parse as datetime using format '{}'", dt.0), from_type: reason.to_string(), span: head, help: Some("you can use `into datetime` without a format string to enable flexible parsing".to_string()) },
match input {
Value::String { val, .. } => {
match dateformat {
Some(dt) => match DateTime::parse_from_str(val, &dt.0) {
Ok(d) => Value::date ( d, head ),
Err(reason) => {
match NaiveDateTime::parse_from_str(val, &dt.0) {
Ok(d) => Value::date (
DateTime::from_naive_utc_and_offset(
d,
*Local::now().offset(),
),
head,
)
),
Err(_) => {
Value::error (
ShellError::CantConvert { to_type: format!("could not parse as datetime using format '{}'", dt.0), from_type: reason.to_string(), span: head, help: Some("you can use `into datetime` without a format string to enable flexible parsing".to_string()) },
head,
)
}
}
}
}
},
},
// Tries to automatically parse the date
// (i.e. without a format string)
// and assumes the system's local timezone if none is specified
None => match parse_date_from_string(val, span) {
Ok(date) => Value::date (
date,
span,
),
Err(err) => err,
},
// Tries to automatically parse the date
// (i.e. without a format string)
// and assumes the system's local timezone if none is specified
None => match parse_date_from_string(val, span) {
Ok(date) => Value::date (
date,
span,
),
Err(err) => err,
},
}
}
};
match input {
Value::String { val, .. } => parse_as_string(val),
Value::Int { val, .. } => parse_as_string(&val.to_string()),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::error(
@ -580,24 +575,6 @@ mod tests {
assert_eq!(actual, expected)
}
#[test]
fn takes_int_with_formatstring() {
let date_int = Value::test_int(1_614_434_140);
let fmt_options = Some(DatetimeFormat("%s".to_string()));
let args = Arguments {
zone_options: None,
format_options: fmt_options,
cell_paths: None,
};
let actual = action(&date_int, &args, Span::test_data());
let expected = Value::date(
DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z").unwrap(),
Span::test_data(),
);
assert_eq!(actual, expected)
}
#[test]
fn takes_timestamp() {
let date_str = Value::test_string("1614434140000000000");

View File

@ -1,5 +1,3 @@
use std::sync::Arc;
use nu_cmd_base::input_handler::{operate, CmdArgument};
use nu_engine::command_prelude::*;
use nu_protocol::{into_code, Config};
@ -9,7 +7,7 @@ use num_format::ToFormattedString;
struct Arguments {
decimals_value: Option<i64>,
cell_paths: Option<Vec<CellPath>>,
config: Arc<Config>,
config: Config,
}
impl CmdArgument for Arguments {
@ -176,7 +174,7 @@ fn string_helper(
})
}
} else {
let config = stack.get_config(engine_state);
let config = engine_state.get_config().clone();
let args = Arguments {
decimals_value,
cell_paths,

View File

@ -424,7 +424,11 @@ pub fn value_to_sql(value: Value) -> Result<Box<dyn rusqlite::ToSql>, ShellError
Value::Filesize { val, .. } => Box::new(val),
Value::Duration { val, .. } => Box::new(val),
Value::Date { val, .. } => Box::new(val),
Value::String { val, .. } => Box::new(val),
Value::String { val, .. } => {
// don't store ansi escape sequences in the database
// escape single quotes
Box::new(nu_utils::strip_ansi_unlikely(&val).into_owned())
}
Value::Binary { val, .. } => Box::new(val),
Value::Nothing { .. } => Box::new(rusqlite::types::Null),
val => {

View File

@ -33,7 +33,7 @@ impl Command for Debug {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let config = stack.get_config(engine_state);
let config = engine_state.get_config().clone();
let raw = call.has_flag(engine_state, stack, "raw")?;
// Should PipelineData::Empty result in an error here?

View File

@ -1,6 +1,6 @@
use nu_engine::{command_prelude::*, get_eval_expression};
use nu_protocol::{
ast::{self, Argument, Block, Expr, Expression},
ast::{Argument, Block, Expr, Expression},
engine::Closure,
};
@ -106,7 +106,7 @@ pub fn get_pipeline_elements(
fn get_arguments(
engine_state: &EngineState,
stack: &mut Stack,
call: &ast::Call,
call: &Call,
eval_expression_fn: fn(&EngineState, &mut Stack, &Expression) -> Result<Value, ShellError>,
) -> Vec<Value> {
let mut arg_value = vec![];

View File

@ -28,10 +28,6 @@ impl Command for Metadata {
.category(Category::Debug)
}
fn requires_ast_for_arguments(&self) -> bool {
true
}
fn run(
&self,
engine_state: &EngineState,
@ -39,7 +35,7 @@ impl Command for Metadata {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let arg = call.positional_nth(stack, 0);
let arg = call.positional_nth(0);
let head = call.head;
match arg {

View File

@ -42,32 +42,32 @@ impl Command for MetadataSet {
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
mut input: PipelineData,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let ds_fp: Option<String> = call.get_flag(engine_state, stack, "datasource-filepath")?;
let ds_ls = call.has_flag(engine_state, stack, "datasource-ls")?;
let content_type: Option<String> = call.get_flag(engine_state, stack, "content-type")?;
let mut metadata = match &mut input {
PipelineData::Value(_, metadata)
| PipelineData::ListStream(_, metadata)
| PipelineData::ByteStream(_, metadata) => metadata.take().unwrap_or_default(),
PipelineData::Empty => return Err(ShellError::PipelineEmpty { dst_span: head }),
};
if let Some(content_type) = content_type {
metadata.content_type = Some(content_type);
}
let signals = engine_state.signals().clone();
let metadata = input
.metadata()
.clone()
.unwrap_or_default()
.with_content_type(content_type);
match (ds_fp, ds_ls) {
(Some(path), false) => metadata.data_source = DataSource::FilePath(path.into()),
(None, true) => metadata.data_source = DataSource::Ls,
(Some(_), true) => (), // TODO: error here
(None, false) => (),
(Some(path), false) => Ok(input.into_pipeline_data_with_metadata(
head,
signals,
metadata.with_data_source(DataSource::FilePath(path.into())),
)),
(None, true) => Ok(input.into_pipeline_data_with_metadata(
head,
signals,
metadata.with_data_source(DataSource::Ls),
)),
_ => Ok(input.into_pipeline_data_with_metadata(head, signals, metadata)),
}
Ok(input.set_metadata(Some(metadata)))
}
fn examples(&self) -> Vec<Example> {
@ -85,9 +85,7 @@ impl Command for MetadataSet {
Example {
description: "Set the metadata of a file path",
example: "'crates' | metadata set --content-type text/plain | metadata",
result: Some(Value::test_record(record! {
"content_type" => Value::test_string("text/plain"),
})),
result: Some(Value::record(record!("content_type" => Value::string("text/plain", Span::test_data())), Span::test_data())),
},
]
}

View File

@ -10,7 +10,6 @@ mod profile;
mod timeit;
mod view;
mod view_files;
mod view_ir;
mod view_source;
mod view_span;
@ -26,6 +25,5 @@ pub use profile::DebugProfile;
pub use timeit::TimeIt;
pub use view::View;
pub use view_files::ViewFiles;
pub use view_ir::ViewIr;
pub use view_source::ViewSource;
pub use view_span::ViewSpan;

View File

@ -1,8 +1,5 @@
use nu_engine::{command_prelude::*, ClosureEvalOnce};
use nu_protocol::{
debugger::{Profiler, ProfilerOptions},
engine::Closure,
};
use nu_protocol::{debugger::Profiler, engine::Closure};
#[derive(Clone)]
pub struct DebugProfile;
@ -31,7 +28,6 @@ impl Command for DebugProfile {
Some('v'),
)
.switch("expr", "Collect expression types", Some('x'))
.switch("instructions", "Collect IR instructions", Some('i'))
.switch("lines", "Collect line numbers", Some('l'))
.named(
"max-depth",
@ -95,23 +91,19 @@ confusing the id/parent_id hierarchy. The --expr flag is helpful for investigati
let collect_expanded_source = call.has_flag(engine_state, stack, "expanded-source")?;
let collect_values = call.has_flag(engine_state, stack, "values")?;
let collect_exprs = call.has_flag(engine_state, stack, "expr")?;
let collect_instructions = call.has_flag(engine_state, stack, "instructions")?;
let collect_lines = call.has_flag(engine_state, stack, "lines")?;
let max_depth = call
.get_flag(engine_state, stack, "max-depth")?
.unwrap_or(2);
let profiler = Profiler::new(
ProfilerOptions {
max_depth,
collect_spans,
collect_source: true,
collect_expanded_source,
collect_values,
collect_exprs,
collect_instructions,
collect_lines,
},
max_depth,
collect_spans,
true,
collect_expanded_source,
collect_values,
collect_exprs,
collect_lines,
call.span(),
);

View File

@ -32,10 +32,6 @@ impl Command for TimeIt {
vec!["timing", "timer", "benchmark", "measure"]
}
fn requires_ast_for_arguments(&self) -> bool {
true
}
fn run(
&self,
engine_state: &EngineState,
@ -43,14 +39,13 @@ impl Command for TimeIt {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
// reset outdest, so the command can write to stdout and stderr.
let stack = &mut stack.push_redirection(None, None);
let command_to_run = call.positional_nth(stack, 0);
let command_to_run = call.positional_nth(0);
// Get the start time after all other computation has been done.
let start_time = Instant::now();
// reset outdest, so the command can write to stdout and stderr.
let stack = &mut stack.push_redirection(None, None);
if let Some(command_to_run) = command_to_run {
if let Some(block_id) = command_to_run.as_block() {
let eval_block = get_eval_block(engine_state);
@ -58,8 +53,7 @@ impl Command for TimeIt {
eval_block(engine_state, stack, block, input)?
} else {
let eval_expression_with_input = get_eval_expression_with_input(engine_state);
let expression = &command_to_run.clone();
eval_expression_with_input(engine_state, stack, expression, input)?.0
eval_expression_with_input(engine_state, stack, command_to_run, input)?.0
}
} else {
PipelineData::empty()

View File

@ -1,171 +0,0 @@
use nu_engine::command_prelude::*;
#[derive(Clone)]
pub struct ViewIr;
impl Command for ViewIr {
fn name(&self) -> &str {
"view ir"
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.required(
"target",
SyntaxShape::Any,
"The name or block to view compiled code for.",
)
.switch(
"json",
"Dump the raw block data as JSON (unstable).",
Some('j'),
)
.switch(
"decl-id",
"Integer is a declaration ID rather than a block ID.",
Some('d'),
)
.input_output_type(Type::Nothing, Type::String)
.category(Category::Debug)
}
fn usage(&self) -> &str {
"View the compiled IR code for a block of code."
}
fn extra_usage(&self) -> &str {
"
The target can be a closure, the name of a custom command, or an internal block
ID. Closure literals within IR dumps often reference the block by ID (e.g.
`closure(3231)`), so this provides an easy way to read the IR of any embedded
closures.
The --decl-id option is provided to use a declaration ID instead, which can be
found on `call` instructions. This is sometimes better than using the name, as
the declaration may not be in scope.
"
.trim()
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let target: Value = call.req(engine_state, stack, 0)?;
let json = call.has_flag(engine_state, stack, "json")?;
let is_decl_id = call.has_flag(engine_state, stack, "decl-id")?;
let block_id = match target {
Value::Closure { ref val, .. } => val.block_id,
// Decl by name
Value::String { ref val, .. } => {
if let Some(decl_id) = engine_state.find_decl(val.as_bytes(), &[]) {
let decl = engine_state.get_decl(decl_id);
decl.block_id().ok_or_else(|| ShellError::GenericError {
error: format!("Can't view IR for `{val}`"),
msg: "not a custom command".into(),
span: Some(target.span()),
help: Some("internal commands don't have Nushell source code".into()),
inner: vec![],
})?
} else {
return Err(ShellError::GenericError {
error: format!("Can't view IR for `{val}`"),
msg: "can't find a command with this name".into(),
span: Some(target.span()),
help: None,
inner: vec![],
});
}
}
// Decl by ID - IR dump always shows name of decl, but sometimes it isn't in scope
Value::Int { val, .. } if is_decl_id => {
let decl_id = val
.try_into()
.ok()
.filter(|id| *id < engine_state.num_decls())
.ok_or_else(|| ShellError::IncorrectValue {
msg: "not a valid decl id".into(),
val_span: target.span(),
call_span: call.head,
})?;
let decl = engine_state.get_decl(decl_id);
decl.block_id().ok_or_else(|| ShellError::GenericError {
error: format!("Can't view IR for `{}`", decl.name()),
msg: "not a custom command".into(),
span: Some(target.span()),
help: Some("internal commands don't have Nushell source code".into()),
inner: vec![],
})?
}
// Block by ID - often shows up in IR
Value::Int { val, .. } => val.try_into().map_err(|_| ShellError::IncorrectValue {
msg: "not a valid block id".into(),
val_span: target.span(),
call_span: call.head,
})?,
// Pass through errors
Value::Error { error, .. } => return Err(*error),
_ => {
return Err(ShellError::TypeMismatch {
err_message: "expected closure, string, or int".into(),
span: call.head,
})
}
};
let Some(block) = engine_state.try_get_block(block_id) else {
return Err(ShellError::GenericError {
error: format!("Unknown block ID: {block_id}"),
msg: "ensure the block ID is correct and try again".into(),
span: Some(target.span()),
help: None,
inner: vec![],
});
};
let ir_block = block
.ir_block
.as_ref()
.ok_or_else(|| ShellError::GenericError {
error: "Can't view IR for this block".into(),
msg: "block is missing compiled representation".into(),
span: block.span,
help: Some("the IrBlock is probably missing due to a compilation error".into()),
inner: vec![],
})?;
let formatted = if json {
let formatted_instructions = ir_block
.instructions
.iter()
.map(|instruction| {
instruction
.display(engine_state, &ir_block.data)
.to_string()
})
.collect::<Vec<_>>();
serde_json::to_string_pretty(&serde_json::json!({
"block_id": block_id,
"span": block.span,
"ir_block": ir_block,
"formatted_instructions": formatted_instructions,
}))
.map_err(|err| ShellError::GenericError {
error: "JSON serialization failed".into(),
msg: err.to_string(),
span: Some(call.head),
help: None,
inner: vec![],
})?
} else {
format!("{}", ir_block.display(engine_state))
};
Ok(Value::string(formatted, call.head).into_pipeline_data())
}
}

View File

@ -31,7 +31,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
All,
Any,
Append,
Chunks,
Columns,
Compact,
Default,
@ -155,7 +154,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
TimeIt,
View,
ViewFiles,
ViewIr,
ViewSource,
ViewSpan,
};
@ -291,6 +289,7 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
ToText,
ToToml,
ToTsv,
Touch,
Upsert,
Where,
ToXml,
@ -397,7 +396,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
RandomFloat,
RandomInt,
RandomUuid,
RandomBinary
};
// Generators

View File

@ -60,13 +60,12 @@ impl Command for ConfigEnv {
let (editor_name, editor_args) = get_editor(engine_state, stack, call.head)?;
let paths = nu_engine::env::path_str(engine_state, stack, call.head)?;
let cwd = engine_state.cwd(Some(stack))?;
let editor_executable = crate::which(&editor_name, &paths, cwd.as_ref()).ok_or(
ShellError::ExternalCommand {
let editor_executable =
crate::which(&editor_name, &paths, &cwd).ok_or(ShellError::ExternalCommand {
label: format!("`{editor_name}` not found"),
help: "Failed to find the editor executable".into(),
span: call.head,
},
)?;
})?;
let Some(env_path) = engine_state.get_config_path("env-path") else {
return Err(ShellError::GenericError {

View File

@ -64,13 +64,12 @@ impl Command for ConfigNu {
let (editor_name, editor_args) = get_editor(engine_state, stack, call.head)?;
let paths = nu_engine::env::path_str(engine_state, stack, call.head)?;
let cwd = engine_state.cwd(Some(stack))?;
let editor_executable = crate::which(&editor_name, &paths, cwd.as_ref()).ok_or(
ShellError::ExternalCommand {
let editor_executable =
crate::which(&editor_name, &paths, &cwd).ok_or(ShellError::ExternalCommand {
label: format!("`{editor_name}` not found"),
help: "Failed to find the editor executable".into(),
span: call.head,
},
)?;
})?;
let Some(config_path) = engine_state.get_config_path("config-path") else {
return Err(ShellError::GenericError {

View File

@ -33,10 +33,6 @@ impl Command for ExportEnv {
CommandType::Keyword
}
fn requires_ast_for_arguments(&self) -> bool {
true
}
fn run(
&self,
engine_state: &EngineState,
@ -45,7 +41,7 @@ impl Command for ExportEnv {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let block_id = call
.positional_nth(caller_stack, 0)
.positional_nth(0)
.expect("checked through parser")
.as_block()
.expect("internal error: missing block");

View File

@ -56,7 +56,7 @@ impl Command for SourceEnv {
&source_filename.item,
engine_state,
caller_stack,
get_dirs_var_from_call(caller_stack, call),
get_dirs_var_from_call(call),
)? {
PathBuf::from(&path)
} else {

View File

@ -31,7 +31,7 @@ mod test_examples {
check_example_evaluates_to_expected_output,
check_example_input_and_output_types_match_command_signature,
};
use nu_cmd_lang::{Break, Describe, Echo, If, Let, Mut};
use nu_cmd_lang::{Break, Echo, If, Let, Mut};
use nu_protocol::{
engine::{Command, EngineState, StateWorkingSet},
Type,
@ -81,7 +81,6 @@ mod test_examples {
working_set.add_decl(Box::new(Break));
working_set.add_decl(Box::new(Date));
working_set.add_decl(Box::new(Default));
working_set.add_decl(Box::new(Describe));
working_set.add_decl(Box::new(Each));
working_set.add_decl(Box::new(Echo));
working_set.add_decl(Box::new(Enumerate));

View File

@ -43,10 +43,7 @@ impl Command for Cd {
// If getting PWD failed, default to the initial directory. This way, the
// user can use `cd` to recover PWD to a good state.
let cwd = engine_state
.cwd(Some(stack))
.ok()
.unwrap_or_else(get_init_cwd);
let cwd = engine_state.cwd(Some(stack)).unwrap_or(get_init_cwd());
let path_val = {
if let Some(path) = path_val {
@ -65,7 +62,7 @@ impl Command for Cd {
if let Some(oldpwd) = stack.get_env_var(engine_state, "OLDPWD") {
oldpwd.to_path()?
} else {
cwd.into()
cwd
}
} else {
// Trim whitespace from the end of path.
@ -134,7 +131,7 @@ impl Command for Cd {
result: None,
},
Example {
description: r#"Change to the previous working directory (same as "cd $env.OLDPWD")"#,
description: "Change to the previous working directory ($OLDPWD)",
example: r#"cd -"#,
result: None,
},
@ -143,16 +140,6 @@ impl Command for Cd {
example: r#"def --env gohome [] { cd ~ }"#,
result: None,
},
Example {
description: "Move two directories up in the tree (the parent directory's parent). Additional dots can be added for additional levels.",
example: r#"cd ..."#,
result: None,
},
Example {
description: "The cd command itself is often optional. Simply entering a path to a directory will cd to it.",
example: r#"/home"#,
result: None,
},
]
}
}

View File

@ -102,7 +102,7 @@ impl Command for Du {
let current_dir = current_dir(engine_state, stack)?;
let paths = get_rest_for_glob_pattern(engine_state, stack, call, 0)?;
let paths = if !call.has_positional_args(stack, 0) {
let paths = if call.rest_iter(0).count() == 0 {
None
} else {
Some(paths)

View File

@ -108,7 +108,7 @@ impl Command for Ls {
};
let pattern_arg = get_rest_for_glob_pattern(engine_state, stack, call, 0)?;
let input_pattern_arg = if !call.has_positional_args(stack, 0) {
let input_pattern_arg = if call.rest_iter(0).count() == 0 {
None
} else {
Some(pattern_arg)

View File

@ -1,7 +1,7 @@
use super::util::get_rest_for_glob_pattern;
#[allow(deprecated)]
use nu_engine::{command_prelude::*, current_dir, get_eval_block};
use nu_protocol::{ast, ByteStream, DataSource, NuGlob, PipelineMetadata};
use nu_protocol::{ByteStream, DataSource, NuGlob, PipelineMetadata};
use std::path::Path;
#[cfg(feature = "sqlite")]
@ -56,7 +56,7 @@ impl Command for Open {
let mut paths = get_rest_for_glob_pattern(engine_state, stack, call, 0)?;
let eval_block = get_eval_block(engine_state);
if paths.is_empty() && !call.has_positional_args(stack, 0) {
if paths.is_empty() && call.rest_iter(0).next().is_none() {
// try to use path from pipeline input if there were no positional or spread args
let (filename, span) = match input {
PipelineData::Value(val, ..) => {
@ -180,8 +180,7 @@ impl Command for Open {
let block = engine_state.get_block(block_id);
eval_block(engine_state, stack, block, stream)
} else {
let call = ast::Call::new(call_span);
decl.run(engine_state, stack, &(&call).into(), stream)
decl.run(engine_state, stack, &Call::new(call_span), stream)
};
output.push(command_output.map_err(|inner| {
ShellError::GenericError{

View File

@ -135,9 +135,12 @@ fn rm(
let home: Option<String> = nu_path::home_dir().map(|path| {
{
if path.exists() {
nu_path::canonicalize_with(&path, &currentdir_path).unwrap_or(path.into())
match nu_path::canonicalize_with(&path, &currentdir_path) {
Ok(canon_path) => canon_path,
Err(_) => path,
}
} else {
path.into()
path
}
}
.to_string_lossy()
@ -167,7 +170,7 @@ fn rm(
}
let span = call.head;
let rm_always_trash = stack.get_config(engine_state).rm_always_trash;
let rm_always_trash = engine_state.get_config().rm_always_trash;
if !TRASH_SUPPORTED {
if rm_always_trash {

View File

@ -4,8 +4,10 @@ use nu_engine::get_eval_block;
use nu_engine::{command_prelude::*, current_dir};
use nu_path::expand_path_with;
use nu_protocol::{
ast, byte_stream::copy_with_signals, process::ChildPipe, ByteStreamSource, DataSource, OutDest,
PipelineMetadata, Signals,
ast::{Expr, Expression},
byte_stream::copy_with_signals,
process::ChildPipe,
ByteStreamSource, DataSource, OutDest, PipelineMetadata, Signals,
};
use std::{
fs::File,
@ -67,6 +69,24 @@ impl Command for Save {
let append = call.has_flag(engine_state, stack, "append")?;
let force = call.has_flag(engine_state, stack, "force")?;
let progress = call.has_flag(engine_state, stack, "progress")?;
let out_append = if let Some(Expression {
expr: Expr::Bool(out_append),
..
}) = call.get_parser_info("out-append")
{
*out_append
} else {
false
};
let err_append = if let Some(Expression {
expr: Expr::Bool(err_append),
..
}) = call.get_parser_info("err-append")
{
*err_append
} else {
false
};
let span = call.head;
#[allow(deprecated)]
@ -89,7 +109,14 @@ impl Command for Save {
PipelineData::ByteStream(stream, metadata) => {
check_saving_to_source_file(metadata.as_ref(), &path, stderr_path.as_ref())?;
let (file, stderr_file) = get_files(&path, stderr_path.as_ref(), append, force)?;
let (file, stderr_file) = get_files(
&path,
stderr_path.as_ref(),
append,
out_append,
err_append,
force,
)?;
let size = stream.known_size();
let signals = engine_state.signals();
@ -121,11 +148,9 @@ impl Command for Save {
} else {
match stderr {
ChildPipe::Pipe(mut pipe) => {
io::copy(&mut pipe, &mut io::stderr())
}
ChildPipe::Tee(mut tee) => {
io::copy(&mut tee, &mut io::stderr())
io::copy(&mut pipe, &mut io::sink())
}
ChildPipe::Tee(mut tee) => io::copy(&mut tee, &mut io::sink()),
}
.err_span(span)?;
}
@ -196,7 +221,14 @@ impl Command for Save {
stderr_path.as_ref(),
)?;
let (mut file, _) = get_files(&path, stderr_path.as_ref(), append, force)?;
let (mut file, _) = get_files(
&path,
stderr_path.as_ref(),
append,
out_append,
err_append,
force,
)?;
for val in ls {
file.write_all(&value_to_bytes(val)?)
.map_err(|err| ShellError::IOError {
@ -226,7 +258,14 @@ impl Command for Save {
input_to_bytes(input, Path::new(&path.item), raw, engine_state, stack, span)?;
// Only open file after successful conversion
let (mut file, _) = get_files(&path, stderr_path.as_ref(), append, force)?;
let (mut file, _) = get_files(
&path,
stderr_path.as_ref(),
append,
out_append,
err_append,
force,
)?;
file.write_all(&bytes).map_err(|err| ShellError::IOError {
msg: err.to_string(),
@ -358,8 +397,7 @@ fn convert_to_extension(
let eval_block = get_eval_block(engine_state);
eval_block(engine_state, stack, block, input)
} else {
let call = ast::Call::new(span);
decl.run(engine_state, stack, &(&call).into(), input)
decl.run(engine_state, stack, &Call::new(span), input)
}
} else {
Ok(input)
@ -435,17 +473,19 @@ fn get_files(
path: &Spanned<PathBuf>,
stderr_path: Option<&Spanned<PathBuf>>,
append: bool,
out_append: bool,
err_append: bool,
force: bool,
) -> Result<(File, Option<File>), ShellError> {
// First check both paths
let (path, path_span) = prepare_path(path, append, force)?;
let (path, path_span) = prepare_path(path, append || out_append, force)?;
let stderr_path_and_span = stderr_path
.as_ref()
.map(|stderr_path| prepare_path(stderr_path, append, force))
.map(|stderr_path| prepare_path(stderr_path, append || err_append, force))
.transpose()?;
// Only if both files can be used open and possibly truncate them
let file = open_file(path, path_span, append)?;
let file = open_file(path, path_span, append || out_append)?;
let stderr_file = stderr_path_and_span
.map(|(stderr_path, stderr_path_span)| {
@ -458,7 +498,7 @@ fn get_files(
inner: vec![],
})
} else {
open_file(stderr_path, stderr_path_span, append)
open_file(stderr_path, stderr_path_span, append || err_append)
}
})
.transpose()?;

View File

@ -86,22 +86,17 @@ impl Command for UCp {
},
Example {
description: "Copy only if source file is newer than target file",
example: "cp -u myfile newfile",
example: "cp -u a b",
result: None,
},
Example {
description: "Copy file preserving mode and timestamps attributes",
example: "cp --preserve [ mode timestamps ] myfile newfile",
example: "cp --preserve [ mode timestamps ] a b",
result: None,
},
Example {
description: "Copy file erasing all attributes",
example: "cp --preserve [] myfile newfile",
result: None,
},
Example {
description: "Copy file to a directory three levels above its current location",
example: "cp myfile ....",
example: "cp --preserve [] a b",
result: None,
},
]
@ -240,7 +235,7 @@ impl Command for UCp {
for (sources, need_expand_tilde) in sources.iter_mut() {
for src in sources.iter_mut() {
if !src.is_absolute() {
*src = nu_path::expand_path_with(&*src, &cwd, *need_expand_tilde);
*src = nu_path::expand_path_with(&src, &cwd, *need_expand_tilde);
}
}
}

View File

@ -30,21 +30,11 @@ impl Command for UMv {
example: "mv test.txt my/subdirectory",
result: None,
},
Example {
description: "Move only if source file is newer than target file",
example: "mv -u new/test.txt old/",
result: None,
},
Example {
description: "Move many files into a directory",
example: "mv *.txt my/subdirectory",
result: None,
},
Example {
description: r#"Move a file into the "my" directory two levels up in the directory tree"#,
example: "mv test.txt .../my/",
result: None,
},
]
}
@ -59,11 +49,6 @@ impl Command for UMv {
.switch("verbose", "explain what is being done.", Some('v'))
.switch("progress", "display a progress bar", Some('p'))
.switch("interactive", "prompt before overwriting", Some('i'))
.switch(
"update",
"move and overwrite only when the SOURCE file is newer than the destination file or when the destination file is missing",
Some('u')
)
.switch("no-clobber", "do not overwrite an existing file", Some('n'))
.rest(
"paths",
@ -92,11 +77,6 @@ impl Command for UMv {
} else {
uu_mv::OverwriteMode::Force
};
let update = if call.has_flag(engine_state, stack, "update")? {
UpdateMode::ReplaceIfOlder
} else {
UpdateMode::ReplaceAll
};
#[allow(deprecated)]
let cwd = current_dir(engine_state, stack)?;
@ -161,7 +141,7 @@ impl Command for UMv {
for (files, need_expand_tilde) in files.iter_mut() {
for src in files.iter_mut() {
if !src.is_absolute() {
*src = nu_path::expand_path_with(&*src, &cwd, *need_expand_tilde);
*src = nu_path::expand_path_with(&src, &cwd, *need_expand_tilde);
}
}
}
@ -184,7 +164,7 @@ impl Command for UMv {
verbose,
suffix: String::from("~"),
backup: BackupMode::NoBackup,
update,
update: UpdateMode::ReplaceAll,
target_dir: None,
no_target_dir: false,
strip_slashes: false,

View File

@ -1,6 +1,6 @@
use dialoguer::Input;
use nu_engine::{command_prelude::*, get_eval_expression};
use nu_protocol::{FromValue, NuGlob};
use nu_protocol::{ast::Expr, FromValue, NuGlob};
use std::{
error::Error,
path::{Path, PathBuf},
@ -92,19 +92,42 @@ pub fn is_older(src: &Path, dst: &Path) -> Option<bool> {
/// Get rest arguments from given `call`, starts with `starting_pos`.
///
/// It's similar to `call.rest`, except that it always returns NuGlob.
/// It's similar to `call.rest`, except that it always returns NuGlob. And if input argument has
/// Type::Glob, the NuGlob is unquoted, which means it's required to expand.
pub fn get_rest_for_glob_pattern(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
starting_pos: usize,
) -> Result<Vec<Spanned<NuGlob>>, ShellError> {
let mut output = vec![];
let eval_expression = get_eval_expression(engine_state);
call.rest_iter_flattened(engine_state, stack, eval_expression, starting_pos)?
.into_iter()
// This used to be much more complex, but I think `FromValue` should be able to handle the
// nuance here.
.map(FromValue::from_value)
.collect()
for result in call.rest_iter_flattened(starting_pos, |expr| {
let result = eval_expression(engine_state, stack, expr);
match result {
Err(e) => Err(e),
Ok(result) => {
let span = result.span();
// convert from string to quoted string if expr is a variable
// or string interpolation
match result {
Value::String { val, .. }
if matches!(
&expr.expr,
Expr::FullCellPath(_) | Expr::StringInterpolation(_)
) =>
{
// should not expand if given input type is not glob.
Ok(Value::glob(val, expr.ty != Type::Glob, span))
}
other => Ok(other),
}
}
}
})? {
output.push(FromValue::from_value(result)?);
}
Ok(output)
}

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