diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index bb0cd0e9a9056..0d8e93ed94cbe 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -46,7 +46,7 @@ jobs: uses: hustcer/setup-nu@v3 if: github.repository == 'nushell/nightly' with: - version: 0.109.1 + version: 0.112.2 # Synchronize the main branch of nightly repo with the main branch of Nushell official repo - name: Prepare for Nightly Release @@ -71,7 +71,7 @@ jobs: shell: nu {0} run: | let date = date now | format date %m%d - let version = open Cargo.toml | get package.version + let version = open Cargo.toml | get workspace.package.version let sha_short = (git rev-parse --short origin/main | str trim | str substring 0..6) let latest_meta = http get https://api.github.com/repos/nushell/nightly/releases | sort-by -r created_at @@ -188,7 +188,7 @@ jobs: - name: Setup Nushell uses: hustcer/setup-nu@v3 with: - version: 0.109.1 + version: 0.112.2 - name: Release Nu Binary id: nu @@ -263,7 +263,7 @@ jobs: - name: Setup Nushell uses: hustcer/setup-nu@v3 with: - version: 0.109.1 + version: 0.112.2 # Keep the last a few releases - name: Delete Older Releases diff --git a/.github/workflows/release-msi.nu b/.github/workflows/release-msi.nu index df7bbb7f5383b..f75b34c4ad981 100755 --- a/.github/workflows/release-msi.nu +++ b/.github/workflows/release-msi.nu @@ -13,7 +13,7 @@ def build-msi [] { let target = $env.TARGET # We should read the version from the environment variable first # As we may build the MSI package for a specific version not the latest one - let version = $env.MSI_VERSION? | default (open Cargo.toml | get package.version) + let version = $env.MSI_VERSION? | default (open Cargo.toml | get workspace.package.version) let arch = if $nu.os-info.arch =~ 'x86_64' { 'x64' } else { 'arm64' } print $'Building msi package for (ansi g)($target)(ansi reset) with version (ansi g)($version)(ansi reset) from tag (ansi g)($env.REF)(ansi reset)...' diff --git a/.github/workflows/release-msi.yml b/.github/workflows/release-msi.yml index dc83108f250c9..9a97a86e4fcbf 100644 --- a/.github/workflows/release-msi.yml +++ b/.github/workflows/release-msi.yml @@ -58,7 +58,7 @@ jobs: - name: Setup Nushell uses: hustcer/setup-nu@v3 with: - version: 0.109.1 + version: 0.112.2 - name: Release MSI Packages id: nu diff --git a/.github/workflows/release-pkg.nu b/.github/workflows/release-pkg.nu index 447df21e1f43c..90f90c5e768cd 100755 --- a/.github/workflows/release-pkg.nu +++ b/.github/workflows/release-pkg.nu @@ -40,7 +40,7 @@ let target = $env.TARGET # Repo source dir like `/home/runner/work/nushell/nushell` let src = $env.GITHUB_WORKSPACE let dist = $'($env.GITHUB_WORKSPACE)/output' -let version = (open Cargo.toml | get package.version) +let version = (open Cargo.toml | get workspace.package.version) print $'Debugging info:' print { version: $version, bin: $bin, os: $os, target: $target, src: $src, dist: $dist }; hr-line -b diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e52922bcdf43b..22aa4b9da8827 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -94,7 +94,7 @@ jobs: - name: Setup Nushell uses: hustcer/setup-nu@v3 with: - version: 0.109.1 + version: 0.112.2 - name: Release Nu Binary id: nu diff --git a/Cargo.lock b/Cargo.lock index 841b42d766558..bc9205c3854f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2177,9 +2177,9 @@ dependencies = [ [[package]] name = "fff-grep" -version = "0.8.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a573d3815f0db13a1efbd44d5f990f3233143555652212a48adf88cce8f728cf" +checksum = "68286213d07412846c0010a0b227b79c08fbc214cf7822f85cabd9e3f36606ae" dependencies = [ "bstr", "memchr", @@ -2201,15 +2201,15 @@ dependencies = [ [[package]] name = "fff-query-parser" -version = "0.8.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea55fa73c4dde6d81e09d9042ac8ca481ea12a4324f88a9896b708f2a3e2925c" +checksum = "f5eb0a0363657b57a3a60d12a76a41f799406514b238123487e54290a6f1a62f" [[package]] name = "fff-search" -version = "0.8.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6144000c57f638a965ba41e3f7d2e6939468ce154bd6cd4de3029d976b2e3cc6" +checksum = "1b6b4517eb8a9b87a46d09e9958f2ddbc036440a9fb5d5ddfc05e6dcf4655ce2" dependencies = [ "ahash", "aho-corasick", @@ -4344,7 +4344,7 @@ dependencies = [ [[package]] name = "nu" -version = "0.113.0" +version = "0.113.1" dependencies = [ "assert_cmd", "crossterm", @@ -4402,7 +4402,7 @@ dependencies = [ [[package]] name = "nu-cli" -version = "0.113.0" +version = "0.113.1" dependencies = [ "chrono", "crossterm", @@ -4440,7 +4440,7 @@ dependencies = [ [[package]] name = "nu-cmd-base" -version = "0.113.0" +version = "0.113.1" dependencies = [ "indexmap 2.14.0", "miette", @@ -4452,7 +4452,7 @@ dependencies = [ [[package]] name = "nu-cmd-extra" -version = "0.113.0" +version = "0.113.1" dependencies = [ "fancy-regex", "heck", @@ -4480,7 +4480,7 @@ dependencies = [ [[package]] name = "nu-cmd-lang" -version = "0.113.0" +version = "0.113.1" dependencies = [ "itertools 0.14.0", "miette", @@ -4499,7 +4499,7 @@ dependencies = [ [[package]] name = "nu-cmd-plugin" -version = "0.113.0" +version = "0.113.1" dependencies = [ "itertools 0.14.0", "nu-engine", @@ -4510,7 +4510,7 @@ dependencies = [ [[package]] name = "nu-color-config" -version = "0.113.0" +version = "0.113.1" dependencies = [ "nu-ansi-term", "nu-engine", @@ -4522,7 +4522,7 @@ dependencies = [ [[package]] name = "nu-command" -version = "0.113.0" +version = "0.113.1" dependencies = [ "alphanumeric-sort", "arboard", @@ -4650,7 +4650,7 @@ dependencies = [ [[package]] name = "nu-derive-value" -version = "0.113.0" +version = "0.113.1" dependencies = [ "heck", "proc-macro-error2", @@ -4661,7 +4661,7 @@ dependencies = [ [[package]] name = "nu-engine" -version = "0.113.0" +version = "0.113.1" dependencies = [ "fancy-regex", "log", @@ -4674,7 +4674,7 @@ dependencies = [ [[package]] name = "nu-experimental" -version = "0.113.0" +version = "0.113.1" dependencies = [ "itertools 0.14.0", "thiserror 2.0.18", @@ -4682,7 +4682,7 @@ dependencies = [ [[package]] name = "nu-explore" -version = "0.113.0" +version = "0.113.1" dependencies = [ "ansi-str", "anyhow", @@ -4711,14 +4711,14 @@ dependencies = [ [[package]] name = "nu-glob" -version = "0.113.0" +version = "0.113.1" dependencies = [ "doc-comment", ] [[package]] name = "nu-heavy-utils" -version = "0.113.0" +version = "0.113.1" dependencies = [ "nu-protocol", "nu-test-support", @@ -4726,7 +4726,7 @@ dependencies = [ [[package]] name = "nu-json" -version = "0.113.0" +version = "0.113.1" dependencies = [ "fancy-regex", "linked-hash-map", @@ -4743,7 +4743,7 @@ dependencies = [ [[package]] name = "nu-lsp" -version = "0.113.0" +version = "0.113.1" dependencies = [ "assert-json-diff", "crossbeam-channel", @@ -4772,7 +4772,7 @@ dependencies = [ [[package]] name = "nu-mcp" -version = "0.113.0" +version = "0.113.1" dependencies = [ "bytes", "chrono", @@ -4798,7 +4798,7 @@ dependencies = [ [[package]] name = "nu-parser" -version = "0.113.0" +version = "0.113.1" dependencies = [ "bytesize", "chrono", @@ -4816,7 +4816,7 @@ dependencies = [ [[package]] name = "nu-path" -version = "0.113.0" +version = "0.113.1" dependencies = [ "dirs 6.0.0", "omnipath", @@ -4826,7 +4826,7 @@ dependencies = [ [[package]] name = "nu-plugin" -version = "0.113.0" +version = "0.113.1" dependencies = [ "log", "nix 0.31.2", @@ -4842,7 +4842,7 @@ dependencies = [ [[package]] name = "nu-plugin-core" -version = "0.113.0" +version = "0.113.1" dependencies = [ "interprocess", "log", @@ -4857,7 +4857,7 @@ dependencies = [ [[package]] name = "nu-plugin-engine" -version = "0.113.0" +version = "0.113.1" dependencies = [ "log", "nu-engine", @@ -4873,7 +4873,7 @@ dependencies = [ [[package]] name = "nu-plugin-protocol" -version = "0.113.0" +version = "0.113.1" dependencies = [ "nu-protocol", "nu-utils", @@ -4885,7 +4885,7 @@ dependencies = [ [[package]] name = "nu-plugin-test-support" -version = "0.113.0" +version = "0.113.1" dependencies = [ "nu-ansi-term", "nu-cmd-lang", @@ -4903,7 +4903,7 @@ dependencies = [ [[package]] name = "nu-pretty-hex" -version = "0.113.0" +version = "0.113.1" dependencies = [ "heapless", "nu-ansi-term", @@ -4912,7 +4912,7 @@ dependencies = [ [[package]] name = "nu-protocol" -version = "0.113.0" +version = "0.113.1" dependencies = [ "brotli", "bytes", @@ -4955,7 +4955,7 @@ dependencies = [ [[package]] name = "nu-std" -version = "0.113.0" +version = "0.113.1" dependencies = [ "log", "miette", @@ -4966,7 +4966,7 @@ dependencies = [ [[package]] name = "nu-system" -version = "0.113.0" +version = "0.113.1" dependencies = [ "chrono", "itertools 0.14.0", @@ -4986,7 +4986,7 @@ dependencies = [ [[package]] name = "nu-table" -version = "0.113.0" +version = "0.113.1" dependencies = [ "fancy-regex", "nu-ansi-term", @@ -4999,7 +4999,7 @@ dependencies = [ [[package]] name = "nu-term-grid" -version = "0.113.0" +version = "0.113.1" dependencies = [ "nu-utils", "unicode-width 0.2.2", @@ -5007,7 +5007,7 @@ dependencies = [ [[package]] name = "nu-test-support" -version = "0.113.0" +version = "0.113.1" dependencies = [ "bytes", "derive_more 2.1.1", @@ -5039,7 +5039,7 @@ dependencies = [ [[package]] name = "nu-test-support-macros" -version = "0.113.0" +version = "0.113.1" dependencies = [ "heck", "nu-experimental", @@ -5051,7 +5051,7 @@ dependencies = [ [[package]] name = "nu-utils" -version = "0.113.0" +version = "0.113.1" dependencies = [ "byteyarn", "crossterm", @@ -5075,7 +5075,7 @@ dependencies = [ [[package]] name = "nu_plugin_custom_values" -version = "0.1.0" +version = "0.113.1" dependencies = [ "nu-plugin", "nu-plugin-test-support", @@ -5086,7 +5086,7 @@ dependencies = [ [[package]] name = "nu_plugin_example" -version = "0.113.0" +version = "0.113.1" dependencies = [ "nu-cmd-lang", "nu-plugin", @@ -5096,7 +5096,7 @@ dependencies = [ [[package]] name = "nu_plugin_formats" -version = "0.113.0" +version = "0.113.1" dependencies = [ "chrono", "eml-parser", @@ -5111,7 +5111,7 @@ dependencies = [ [[package]] name = "nu_plugin_gstat" -version = "0.113.0" +version = "0.113.1" dependencies = [ "git2", "nu-plugin", @@ -5120,7 +5120,7 @@ dependencies = [ [[package]] name = "nu_plugin_inc" -version = "0.113.0" +version = "0.113.1" dependencies = [ "nu-plugin", "nu-protocol", @@ -5129,7 +5129,7 @@ dependencies = [ [[package]] name = "nu_plugin_polars" -version = "0.113.0" +version = "0.113.1" dependencies = [ "aws-config", "aws-credential-types", @@ -5171,7 +5171,7 @@ dependencies = [ [[package]] name = "nu_plugin_query" -version = "0.113.0" +version = "0.113.1" dependencies = [ "gjson", "nu-plugin", @@ -5186,7 +5186,7 @@ dependencies = [ [[package]] name = "nu_plugin_stress_internals" -version = "0.113.0" +version = "0.113.1" dependencies = [ "interprocess", "serde", @@ -5315,7 +5315,7 @@ dependencies = [ [[package]] name = "nuon" -version = "0.113.0" +version = "0.113.1" dependencies = [ "chrono", "nu-engine", diff --git a/Cargo.toml b/Cargo.toml index 1ec824bd00388..080d2fe8077f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,23 +1,26 @@ -[package] +[workspace.package] authors = ["The Nushell Project Developers"] +edition = "2024" +rust-version = "1.93.1" +license = "MIT" +version = "0.113.1" + +[package] +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +version.workspace = true build = "scripts/build.rs" default-run = "nu" description = "A new type of shell" documentation = "https://www.nushell.sh/book/" -edition.workspace = true exclude = ["images"] homepage = "https://www.nushell.sh" -license = "MIT" name = "nu" repository = "https://github.com/nushell/nushell" -rust-version.workspace = true -version = "0.113.0" autotests = false -[workspace.package] -edition = "2024" -rust-version = "1.93.1" - [[test]] name = "tests" path = "tests/main.rs" @@ -35,8 +38,8 @@ pkg-fmt = "zip" [package.metadata.winresource] LegalCopyright = "Copyright © 2019-2026 The Nushell Project Developers" FileDescription = "A new type of shell" -FileVersion = "0.113.0" -ProductVersion = "0.113.0" +FileVersion = "0.113.1" +ProductVersion = "0.113.1" ProductName = "Nushell" [workspace] @@ -83,6 +86,49 @@ members = [ ] [workspace.dependencies] + +nu-cli = { path = "crates/nu-cli", version = "0.113.1", default-features = false } +nu-cmd-base = { path = "crates/nu-cmd-base", version = "0.113.1", default-features = false } +nu-cmd-extra = { path = "crates/nu-cmd-extra", version = "0.113.1", default-features = false } +nu-cmd-lang = { path = "crates/nu-cmd-lang", version = "0.113.1", default-features = false } +nu-cmd-plugin = { path = "crates/nu-cmd-plugin", version = "0.113.1", default-features = false } +nu-color-config = { path = "crates/nu-color-config", version = "0.113.1", default-features = false } +nu-command = { path = "crates/nu-command", version = "0.113.1", default-features = false } +nu-derive-value = { path = "crates/nu-derive-value", version = "0.113.1", default-features = false } +nu-engine = { path = "crates/nu-engine", version = "0.113.1", default-features = false } +nu-experimental = { path = "crates/nu-experimental", version = "0.113.1", default-features = false } +nu-explore = { path = "crates/nu-explore", version = "0.113.1", default-features = false } +nu-glob = { path = "crates/nu-glob", version = "0.113.1", default-features = false } +nu-heavy-utils = { path = "crates/nu-heavy-utils", version = "0.113.1", default-features = false } +nu-json = { path = "crates/nu-json", version = "0.113.1", default-features = false } +nu-lsp = { path = "crates/nu-lsp", version = "0.113.1", default-features = false } +nu-mcp = { path = "crates/nu-mcp", version = "0.113.1", default-features = false } +nu-parser = { path = "crates/nu-parser", version = "0.113.1", default-features = false } +nu-path = { path = "crates/nu-path", version = "0.113.1", default-features = false } +nu-plugin = { path = "crates/nu-plugin", version = "0.113.1", default-features = false } +nu-plugin-core = { path = "crates/nu-plugin-core", version = "0.113.1", default-features = false } +nu-plugin-engine = { path = "crates/nu-plugin-engine", version = "0.113.1", default-features = false } +nu-plugin-protocol = { path = "crates/nu-plugin-protocol", version = "0.113.1", default-features = false } +nu-plugin-test-support = { path = "crates/nu-plugin-test-support", version = "0.113.1", default-features = false } +nu-pretty-hex = { path = "crates/nu-pretty-hex", version = "0.113.1", default-features = false } +nu-protocol = { path = "crates/nu-protocol", version = "0.113.1", default-features = false } +nu-std = { path = "crates/nu-std", version = "0.113.1", default-features = false } +nu-system = { path = "crates/nu-system", version = "0.113.1", default-features = false } +nu-table = { path = "crates/nu-table", version = "0.113.1", default-features = false } +nu-term-grid = { path = "crates/nu-term-grid", version = "0.113.1", default-features = false } +nu-test-support = { path = "crates/nu-test-support", version = "0.113.1", default-features = false } +nu-test-support-macros = { path = "crates/nu-test-support-macros", version = "0.113.1", default-features = false } +nu-utils = { path = "crates/nu-utils", version = "0.113.1", default-features = false } +nu_plugin_custom_values = { path = "crates/nu_plugin_custom_values", version = "0.113.1", default-features = false } +nu_plugin_example = { path = "crates/nu_plugin_example", version = "0.113.1", default-features = false } +nu_plugin_formats = { path = "crates/nu_plugin_formats", version = "0.113.1", default-features = false } +nu_plugin_gstat = { path = "crates/nu_plugin_gstat", version = "0.113.1", default-features = false } +nu_plugin_inc = { path = "crates/nu_plugin_inc", version = "0.113.1", default-features = false } +nu_plugin_polars = { path = "crates/nu_plugin_polars", version = "0.113.1", default-features = false } +nu_plugin_query = { path = "crates/nu_plugin_query", version = "0.113.1", default-features = false } +nu_plugin_stress_internals = { path = "crates/nu_plugin_stress_internals", version = "0.113.1", default-features = false } +nuon = { path = "crates/nuon", version = "0.113.1", default-features = false } + alphanumeric-sort = "1.5" ansi-str = "0.9" anyhow = "1.0.102" @@ -113,7 +159,7 @@ encoding_rs = "0.8" fancy-regex = "0.18" filesize = "0.2" filetime = "0.2.27" -fff-search = { version = "0.8.1", default-features = false } +fff-search = { version = "=0.8.4", default-features = false } fluent = "0.17.0" fuzzy-matcher = { version = "^0.3.7" } gatekeeper = "3.0.0" @@ -257,24 +303,24 @@ collapsible_match = "allow" workspace = true [dependencies] -nu-cli = { path = "./crates/nu-cli", version = "0.113.0" } -nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.113.0" } -nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.113.0" } -nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.113.0" } -nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.113.0", optional = true } -nu-command = { path = "./crates/nu-command", version = "0.113.0", default-features = false, features = ["os"] } -nu-engine = { path = "./crates/nu-engine", version = "0.113.0" } -nu-experimental = { path = "./crates/nu-experimental", version = "0.113.0" } -nu-explore = { path = "./crates/nu-explore", version = "0.113.0" } -nu-lsp = { path = "./crates/nu-lsp/", version = "0.113.0" } -nu-parser = { path = "./crates/nu-parser", version = "0.113.0" } -nu-path = { path = "./crates/nu-path", version = "0.113.0" } -nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.113.0" } -nu-protocol = { path = "./crates/nu-protocol", version = "0.113.0" } -nu-std = { path = "./crates/nu-std", version = "0.113.0" } -nu-system = { path = "./crates/nu-system", version = "0.113.0" } -nu-utils = { path = "./crates/nu-utils", version = "0.113.0" } -nu-mcp = { path = "./crates/nu-mcp", version = "0.113.0", optional = true } +nu-cli = { workspace = true } +nu-cmd-base = { workspace = true } +nu-cmd-extra = { workspace = true } +nu-cmd-lang = { workspace = true, features = ["os"] } +nu-cmd-plugin = { workspace = true, optional = true } +nu-command = { workspace = true, features = ["os"] } +nu-engine = { workspace = true, features = ["os"] } +nu-experimental = { workspace = true } +nu-explore = { workspace = true } +nu-lsp = { workspace = true } +nu-parser = { workspace = true } +nu-path = { workspace = true } +nu-plugin-engine = { workspace = true, features = ["local-socket"], optional = true } +nu-protocol = { workspace = true, features = ["os"] } +nu-std = { workspace = true } +nu-system = { workspace = true } +nu-utils = { workspace = true, features = ["os"] } +nu-mcp = { workspace = true, optional = true } reedline = { workspace = true, features = ["bashisms"] } crossterm = { workspace = true } @@ -305,10 +351,10 @@ nix = { workspace = true, default-features = false, features = [ ] } [dev-dependencies] -nu-test-support = { path = "./crates/nu-test-support", version = "0.113.0", features = ["os"] } -nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.113.0" } -nu-table = { path = "./crates/nu-table", version = "0.113.0" } -nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.113.0" } +nu-test-support = { path = "./crates/nu-test-support", version = "0.113.1", features = ["os"] } +nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.113.1" } +nu-table = { path = "./crates/nu-table", version = "0.113.1" } +nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.113.1" } assert_cmd = "2.2.1" dirs = { workspace = true } tango-bench = "0.7.2" diff --git a/crates/nu-cli/Cargo.toml b/crates/nu-cli/Cargo.toml index 503e4524f7784..c3eee8b95dd14 100644 --- a/crates/nu-cli/Cargo.toml +++ b/crates/nu-cli/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "CLI-related functionality for Nushell" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli" edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-cli" rust-version.workspace = true -version = "0.113.0" +version.workspace = true autotests = false [lib] @@ -19,26 +19,26 @@ path = "tests/main.rs" harness = false [dev-dependencies] -nu-cmd-lang = { path = "../nu-cmd-lang" } -nu-command = { path = "../nu-command" } -nu-std = { path = "../nu-std" } -nu-test-support = { path = "../nu-test-support" } +nu-cmd-lang = { workspace = true, features = ["os"] } +nu-command = { workspace = true, features = ["os"] } +nu-std.workspace = true +nu-test-support.workspace = true rstest = { workspace = true, default-features = false } tempfile = { workspace = true } [dependencies] -nu-cmd-base = { path = "../nu-cmd-base", version = "0.113.0" } -nu-command = { path = "../nu-command", version = "0.113.0", features = ["os"], default-features = false } -nu-engine = { path = "../nu-engine", version = "0.113.0", features = ["os"] } -nu-glob = { path = "../nu-glob", version = "0.113.0" } -nu-path = { path = "../nu-path", version = "0.113.0" } -nu-parser = { path = "../nu-parser", version = "0.113.0" } -nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.113.0", optional = true } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", features = ["os"] } -nu-utils = { path = "../nu-utils", version = "0.113.0" } -nu-color-config = { path = "../nu-color-config", version = "0.113.0" } -nu-experimental = { path = "../nu-experimental", version = "0.113.0" } -nu-ansi-term = { workspace = true } +nu-cmd-base.workspace = true +nu-command = { workspace = true, features = ["os"] } +nu-engine = { workspace = true, features = ["os"] } +nu-glob.workspace = true +nu-path.workspace = true +nu-parser.workspace = true +nu-plugin-engine = { workspace = true, optional = true } +nu-protocol = { workspace = true, features = ["os"] } +nu-utils.workspace = true +nu-color-config.workspace = true +nu-experimental.workspace = true +nu-ansi-term.workspace = true reedline = { workspace = true, features = ["bashisms"] } chrono = { default-features = false, features = ["std"], workspace = true } diff --git a/crates/nu-cli/src/repl.rs b/crates/nu-cli/src/repl.rs index 86482996fbf74..a23ffeff48ca1 100644 --- a/crates/nu-cli/src/repl.rs +++ b/crates/nu-cli/src/repl.rs @@ -539,6 +539,13 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) { perf!("reset signals", start_time, use_color); start_time = Instant::now(); + + // Juhan said to do this :) + let mut repl = engine_state.repl_state.lock().expect("repl state mutex"); + repl.cursor_pos = line_editor.current_insertion_point(); + repl.buffer = line_editor.current_buffer_contents().to_string(); + drop(repl); + // Check all the environment variables they ask for // fire the "env_change" hook if let Err(error) = hook::eval_env_change_hook( diff --git a/crates/nu-cmd-base/Cargo.toml b/crates/nu-cmd-base/Cargo.toml index fee95bdd8e49e..0db79a68b0e95 100644 --- a/crates/nu-cmd-base/Cargo.toml +++ b/crates/nu-cmd-base/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "The foundation tools to build Nushell commands." edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-cmd-base" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base" rust-version.workspace = true -version = "0.113.0" +version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -14,10 +14,10 @@ version = "0.113.0" workspace = true [dependencies] -nu-engine = { path = "../nu-engine", version = "0.113.0", default-features = false } -nu-parser = { path = "../nu-parser", version = "0.113.0" } -nu-path = { path = "../nu-path", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } +nu-engine.workspace = true +nu-parser.workspace = true +nu-path.workspace = true +nu-protocol.workspace = true indexmap = { workspace = true } miette = { workspace = true } diff --git a/crates/nu-cmd-extra/Cargo.toml b/crates/nu-cmd-extra/Cargo.toml index 9e80c1b6842d9..f0f2ebf5d0a32 100644 --- a/crates/nu-cmd-extra/Cargo.toml +++ b/crates/nu-cmd-extra/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell's extra commands that are not part of the 1.0 api standard." edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-cmd-extra" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-extra" rust-version.workspace = true -version = "0.113.0" +version.workspace = true autotests = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -24,14 +24,14 @@ path = "tests/main.rs" harness = false [dependencies] -nu-cmd-base = { path = "../nu-cmd-base", version = "0.113.0" } -nu-engine = { path = "../nu-engine", version = "0.113.0", default-features = false } -nu-heavy-utils = { path = "../nu-heavy-utils", version = "0.113.0" } -nu-json = { version = "0.113.0", path = "../nu-json" } -nu-parser = { path = "../nu-parser", version = "0.113.0" } -nu-pretty-hex = { version = "0.113.0", path = "../nu-pretty-hex" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } +nu-cmd-base.workspace = true +nu-engine.workspace = true +nu-heavy-utils.workspace = true +nu-json.workspace = true +nu-parser.workspace = true +nu-pretty-hex.workspace = true +nu-protocol.workspace = true +nu-utils.workspace = true # Potential dependencies for extras heck = { workspace = true } @@ -45,12 +45,13 @@ itertools = { workspace = true } mime = { workspace = true } [dev-dependencies] -nu-cmd-lang = { path = "../nu-cmd-lang" } -nu-command = { path = "../nu-command" } -nu-test-support = { path = "../nu-test-support" } +# "os" feature required for testing examples +nu-cmd-lang = { workspace = true, features = ["os"] } +nu-command = { workspace = true, features = ["os"] } +nu-test-support.workspace = true [build-dependencies] -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } +nu-protocol.workspace = true serde = { workspace = true } serde_json = { workspace = true } diff --git a/crates/nu-cmd-lang/Cargo.toml b/crates/nu-cmd-lang/Cargo.toml index 3bf1706fc6c50..1a5749a11d850 100644 --- a/crates/nu-cmd-lang/Cargo.toml +++ b/crates/nu-cmd-lang/Cargo.toml @@ -1,13 +1,13 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true build = "build.rs" description = "Nushell's core language commands" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-lang" edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-cmd-lang" rust-version.workspace = true -version = "0.113.0" +version.workspace = true [lib] bench = false @@ -16,12 +16,12 @@ bench = false workspace = true [dependencies] -nu-engine = { path = "../nu-engine", version = "0.113.0", default-features = false } -nu-experimental = { path = "../nu-experimental", version = "0.113.0" } -nu-parser = { path = "../nu-parser", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } -nu-cmd-base = { path = "../nu-cmd-base", version = "0.113.0" } +nu-engine.workspace = true +nu-experimental.workspace = true +nu-parser.workspace = true +nu-protocol.workspace = true +nu-utils.workspace = true +nu-cmd-base.workspace = true itertools = { workspace = true } semver = { workspace = true } @@ -31,7 +31,7 @@ shadow-rs = { version = "2.0", default-features = false } shadow-rs = { version = "2.0", default-features = false, features = ["build"] } [dev-dependencies] -nu-test-support = { path = "../nu-test-support"} +nu-test-support.workspace = true quickcheck = { workspace = true } quickcheck_macros = { workspace = true } diff --git a/crates/nu-cmd-plugin/Cargo.toml b/crates/nu-cmd-plugin/Cargo.toml index f3f90a63c84f1..cee2c4c4f19b3 100644 --- a/crates/nu-cmd-plugin/Cargo.toml +++ b/crates/nu-cmd-plugin/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Commands for managing Nushell plugins." edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-cmd-plugin" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-plugin" rust-version.workspace = true -version = "0.113.0" +version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -14,9 +14,9 @@ version = "0.113.0" workspace = true [dependencies] -nu-engine = { path = "../nu-engine", version = "0.113.0" } -nu-path = { path = "../nu-path", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", features = ["plugin"] } -nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.113.0" } +nu-engine.workspace = true +nu-path.workspace = true +nu-protocol = { workspace = true, features = ["plugin"] } +nu-plugin-engine.workspace = true itertools = { workspace = true } diff --git a/crates/nu-color-config/Cargo.toml b/crates/nu-color-config/Cargo.toml index f474bfab3dfde..8ed267d283a06 100644 --- a/crates/nu-color-config/Cargo.toml +++ b/crates/nu-color-config/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Color configuration code used by Nushell" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-color-config" edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-color-config" rust-version.workspace = true -version = "0.113.0" +version.workspace = true [lib] bench = false @@ -16,12 +16,12 @@ harness = false workspace = true [dependencies] -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } -nu-engine = { path = "../nu-engine", version = "0.113.0", default-features = false } -nu-json = { path = "../nu-json", version = "0.113.0" } -nu-ansi-term = { workspace = true } +nu-protocol.workspace = true +nu-engine.workspace = true +nu-json.workspace = true +nu-ansi-term.workspace = true serde = { workspace = true, features = ["derive"] } [dev-dependencies] -nu-test-support = { path = "../nu-test-support" } +nu-test-support.workspace = true diff --git a/crates/nu-command/Cargo.toml b/crates/nu-command/Cargo.toml index 5a94f66989e84..f82f6ae123f08 100644 --- a/crates/nu-command/Cargo.toml +++ b/crates/nu-command/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell's built-in commands" edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-command" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command" rust-version.workspace = true -version = "0.113.0" +version.workspace = true autotests = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -24,23 +24,23 @@ harness = false workspace = true [dependencies] -nu-ansi-term = { workspace = true } -nu-cmd-base = { path = "../nu-cmd-base", version = "0.113.0" } -nu-color-config = { path = "../nu-color-config", version = "0.113.0" } -nu-engine = { path = "../nu-engine", version = "0.113.0", default-features = false } -nu-experimental = { path = "../nu-experimental", version = "0.113.0" } -nu-glob = { path = "../nu-glob", version = "0.113.0" } -nu-json = { path = "../nu-json", version = "0.113.0", features = ["nu-protocol"] } -nu-parser = { path = "../nu-parser", version = "0.113.0" } -nu-path = { path = "../nu-path", version = "0.113.0" } -nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } -nu-system = { path = "../nu-system", version = "0.113.0" } -nu-table = { path = "../nu-table", version = "0.113.0" } -nu-term-grid = { path = "../nu-term-grid", version = "0.113.0" } -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } -nu-heavy-utils = { path = "../nu-heavy-utils", version = "0.113.0" } -nuon = { path = "../nuon", version = "0.113.0" } +nu-ansi-term.workspace = true +nu-cmd-base.workspace = true +nu-color-config.workspace = true +nu-engine.workspace = true +nu-experimental.workspace = true +nu-glob.workspace = true +nu-json = { workspace = true, features = ["nu-protocol", "preserve_order"] } +nu-parser.workspace = true +nu-path.workspace = true +nu-pretty-hex.workspace = true +nu-protocol.workspace = true +nu-system.workspace = true +nu-table.workspace = true +nu-term-grid.workspace = true +nu-utils.workspace = true +nu-heavy-utils.workspace = true +nuon.workspace = true alphanumeric-sort = { workspace = true } base64 = { workspace = true } @@ -195,6 +195,7 @@ default = ["os", "network", "rustls-tls", "sqlite"] os = [ # include other features "js", + "nu-cmd-lang/os", "nu-engine/os", "nu-protocol/os", "nu-utils/os", @@ -252,8 +253,8 @@ sqlite = ["rusqlite"] trash-support = ["trash"] [dev-dependencies] -nu-cmd-lang = { path = "../nu-cmd-lang" } -nu-test-support = { path = "../nu-test-support" } +nu-cmd-lang.workspace = true +nu-test-support.workspace = true dirs = { workspace = true } mockito = { workspace = true, default-features = false } diff --git a/crates/nu-command/src/filesystem/idx/dirs.rs b/crates/nu-command/src/filesystem/idx/dirs.rs index bd65ca9205b28..bec3dd8fe1f8d 100644 --- a/crates/nu-command/src/filesystem/idx/dirs.rs +++ b/crates/nu-command/src/filesystem/idx/dirs.rs @@ -10,30 +10,43 @@ impl Command for IdxDirs { fn signature(&self) -> Signature { Signature::build(self.name()) + .optional( + "query", + SyntaxShape::String, + "Optional fuzzy query to filter indexed directories.", + ) .input_output_types(vec![(Type::Nothing, Type::List(Box::new(Type::record())))]) .category(Category::FileSystem) } fn description(&self) -> &str { - "List indexed directories from idx state." + "List indexed directories, or fuzzy-match directories by query." } fn examples(&self) -> Vec> { - vec![Example { - description: "List all indexed directories", - example: "idx dirs", - result: None, - }] + vec![ + Example { + description: "List all indexed directories", + example: "idx dirs", + result: None, + }, + Example { + description: "Fuzzy-match indexed directories by query", + example: "idx dirs src", + result: None, + }, + ] } fn run( &self, engine_state: &EngineState, - _stack: &mut Stack, + stack: &mut Stack, call: &Call, _input: PipelineData, ) -> Result { + let query = call.opt::(engine_state, stack, 0)?; let signals = engine_state.signals(); - stream_dirs(call.head, signals) + stream_dirs(query, call.head, signals) } } diff --git a/crates/nu-command/src/filesystem/idx/files.rs b/crates/nu-command/src/filesystem/idx/files.rs index b2f3128a604d4..ac2c8ebe25610 100644 --- a/crates/nu-command/src/filesystem/idx/files.rs +++ b/crates/nu-command/src/filesystem/idx/files.rs @@ -12,16 +12,16 @@ impl Command for IdxFiles { fn signature(&self) -> Signature { Signature::build(self.name()) .optional( - "path", + "query", SyntaxShape::String, - "Optional path to lookup in index.", + "Optional fuzzy query to filter indexed files.", ) .input_output_types(vec![(Type::Nothing, Type::List(Box::new(Type::record())))]) .category(Category::FileSystem) } fn description(&self) -> &str { - "List indexed files, or lookup a specific indexed path." + "List indexed files, or fuzzy-match files by query." } fn examples(&self) -> Vec> { @@ -32,8 +32,8 @@ impl Command for IdxFiles { result: None, }, Example { - description: "Lookup a specific file path in the index", - example: "idx files src/main.rs", + description: "Fuzzy-match indexed files by query", + example: "idx files main", result: None, }, ] @@ -46,8 +46,8 @@ impl Command for IdxFiles { call: &Call, _input: PipelineData, ) -> Result { - let path = call.opt::(engine_state, stack, 0)?; + let query = call.opt::(engine_state, stack, 0)?; let signals = engine_state.signals(); - stream_files(path, call.head, signals) + stream_files(query, call.head, signals) } } diff --git a/crates/nu-command/src/filesystem/idx/find.rs b/crates/nu-command/src/filesystem/idx/find.rs index 47ac3dc74515c..5f8c7854fa9e8 100644 --- a/crates/nu-command/src/filesystem/idx/find.rs +++ b/crates/nu-command/src/filesystem/idx/find.rs @@ -18,7 +18,7 @@ impl Command for IdxFind { .named( "limit", SyntaxShape::Int, - "Maximum number of rows to return.", + "Maximum number of rows to return (default 100).", Some('l'), ) .input_output_types(vec![(Type::Nothing, Type::List(Box::new(Type::record())))]) diff --git a/crates/nu-command/src/filesystem/idx/import.rs b/crates/nu-command/src/filesystem/idx/import.rs index 71c36bf3ca172..8c6c7b9a81211 100644 --- a/crates/nu-command/src/filesystem/idx/import.rs +++ b/crates/nu-command/src/filesystem/idx/import.rs @@ -25,7 +25,7 @@ impl Command for IdxImport { } fn extra_description(&self) -> &str { - "Reads a SQLite snapshot created by `idx export` and hydrates the runtime from stored rows. Watch mode is not restored from the snapshot." + "Reads a SQLite snapshot created by `idx export` and auto-initializes idx runtime for immediate queries." } fn examples(&self) -> Vec> { diff --git a/crates/nu-command/src/filesystem/idx/init.rs b/crates/nu-command/src/filesystem/idx/init.rs index 64afa86039088..cdc64ccb57b65 100644 --- a/crates/nu-command/src/filesystem/idx/init.rs +++ b/crates/nu-command/src/filesystem/idx/init.rs @@ -17,6 +17,11 @@ impl Command for IdxInit { "Block until the initial scan completes before returning.", Some('w'), ) + .switch( + "follow-symlinks", + "Whether to follow symlinks when indexing.", + Some('f'), + ) .input_output_types(vec![(Type::Nothing, Type::record())]) .category(Category::FileSystem) } @@ -53,12 +58,13 @@ impl Command for IdxInit { ) -> Result { let path: Spanned = call.req(engine_state, stack, 0)?; let wait = call.has_flag(engine_state, stack, "wait")?; + let follow = call.has_flag(engine_state, stack, "follow-symlinks")?; let cwd = engine_state.cwd(Some(stack))?; let abs = nu_path::expand_path_with(path.item, cwd, true); // There is a functionality in fff-search to update the index via watch but it was non-trivial to get working // So, for now, let's always default to watch = false. let watch = false; - let status = init_runtime(&abs, watch, wait, call.head)?; + let status = init_runtime(&abs, watch, wait, follow, call.head)?; Ok(PipelineData::value(status.to_value(call.head), None)) } } diff --git a/crates/nu-command/src/filesystem/idx/state.rs b/crates/nu-command/src/filesystem/idx/state.rs index aac3bc6cefffa..7a321309d1b93 100644 --- a/crates/nu-command/src/filesystem/idx/state.rs +++ b/crates/nu-command/src/filesystem/idx/state.rs @@ -1,3 +1,13 @@ +//! In-process file indexing runtime for the `idx` command family. +//! +//! This module manages two types of index backends: +//! - **Live mode** (after `idx init`): Backed by a `fff-search` FilePicker that scans and watches the filesystem +//! - **Snapshot mode** (after `idx import`): Backed by pre-computed file/directory metadata restored from a snapshot +//! +//! The runtime is stored as a thread-safe singleton (`IDX_RUNTIME`) and can be accessed by all idx subcommands. +//! Public functions handle initialization, status reporting, and streaming results to Nushell. + +use chrono::{DateTime, Local, LocalResult, TimeZone, Utc}; use fff_search::{ FFFMode, FilePicker, FilePickerOptions, FuzzySearchOptions, GrepMode, GrepSearchOptions, MixedItemRef, PaginationArgs, QueryParser, SharedFilePicker, SharedFrecency, @@ -15,13 +25,54 @@ use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, Mutex, OnceLock}; use std::time::Duration; +/// Global in-process runtime for idx commands. +/// +/// The runtime is shared by all idx subcommands and can be backed either by +/// a live `fff-search` picker (after `idx init`) or by restored snapshot rows +/// (after `idx import`). pub struct IdxRuntime { pub base_path: PathBuf, pub watch: bool, pub shared_picker: SharedFilePicker, pub scan_start_time: Instant, pub scan_completed: Arc, - pub scan_duration_ms: Arc, + pub scan_duration_ns: Arc, + pub restored_files: Option>>, + pub restored_dirs: Option>>, + pub restored_arena_bytes_base: usize, + pub restored_arena_bytes_overflow: usize, +} + +#[derive(Clone, Debug)] +/// Snapshot-backed file row used by imported idx runtimes. +/// +/// Fields are restored from the SQLite snapshot database and are used for +/// fuzzy searching when the original filesystem may no longer be available. +pub struct IdxRestoredFile { + /// Relative path from the index base directory. + pub relative_path: String, + /// Absolute path to the file (may not exist on disk). + pub full_path: String, + /// Just the filename component without directory path. + pub file_name: String, + /// Parent directory path as a string. + pub directory: String, + /// File size in bytes. + pub size: u64, + /// Last modified timestamp as seconds since epoch. + pub modified: u64, +} + +#[derive(Clone, Debug)] +/// Snapshot-backed directory row used by imported idx runtimes. +/// +/// Fields are restored from the SQLite snapshot database for use in +/// fuzzy directory searches when the filesystem may not be available. +pub struct IdxRestoredDir { + /// Relative path from the index base directory. + pub relative_path: String, + /// Absolute path to the directory (may not exist on disk). + pub full_path: String, } /// A cloned snapshot of the current runtime state, obtained while holding the @@ -31,12 +82,13 @@ pub struct IdxRuntime { pub type RuntimeSnapshot = IdxRuntime; #[derive(Clone, Debug, Default)] +/// User-facing runtime status for `idx status`. pub struct IdxStatus { pub initialized: bool, pub base_path: String, pub watch: bool, pub scanning: bool, - pub scan_duration_ms: u128, + pub scan_duration_ns: u64, pub files: usize, pub dirs: usize, pub arena_bytes_base: usize, @@ -45,6 +97,7 @@ pub struct IdxStatus { } impl IdxStatus { + /// Convert status to Nushell record output. pub fn to_value(&self, span: Span) -> Value { Value::record( [ @@ -59,9 +112,9 @@ impl IdxStatus { ("watch".to_string(), Value::bool(self.watch, span)), ("scanning".to_string(), Value::bool(self.scanning, span)), ( - "scan_duration_ms".to_string(), - Value::int( - i64::try_from(self.scan_duration_ms).unwrap_or(i64::MAX), + "scan_duration".to_string(), + Value::duration( + i64::try_from(self.scan_duration_ns).unwrap_or(i64::MAX), span, ), ), @@ -74,28 +127,28 @@ impl IdxStatus { Value::int(i64::try_from(self.dirs).unwrap_or(i64::MAX), span), ), ( - "arena_bytes_base".to_string(), + "arena_size_base".to_string(), Value::filesize( i64::try_from(self.arena_bytes_base).unwrap_or(i64::MAX), span, ), ), ( - "arena_bytes_overflow".to_string(), + "arena_size_overflow".to_string(), Value::filesize( i64::try_from(self.arena_bytes_overflow).unwrap_or(i64::MAX), span, ), ), ( - "arena_bytes_untracked".to_string(), + "arena_size_untracked".to_string(), Value::filesize( i64::try_from(self.arena_bytes_untracked).unwrap_or(i64::MAX), span, ), ), ( - "arena_bytes_total".to_string(), + "arena_size_total".to_string(), Value::filesize( i64::try_from( self.arena_bytes_base @@ -120,6 +173,7 @@ fn runtime() -> &'static Mutex> { IDX_RUNTIME.get_or_init(|| Mutex::new(None)) } +/// Convert a `fff_search` error to a Nushell [`ShellError`]. fn fff_error(err: E, span: Span) -> ShellError { ShellError::Generic(GenericError::new( "idx operation failed", @@ -128,6 +182,50 @@ fn fff_error(err: E, span: Span) -> ShellError { )) } +/// Error when the idx runtime has not been initialized. +fn idx_not_initialized_error(span: Span) -> ShellError { + ShellError::Generic(GenericError::new( + "idx is not initialized", + "run `idx init ` first", + span, + )) +} + +/// Read lock on the shared FilePicker, returning a guard that dereferences to `Option`. +fn read_picker_guard<'a>( + shared_picker: &'a SharedFilePicker, + span: Span, +) -> Result> + 'a, ShellError> { + shared_picker.read().map_err(|err| fff_error(err, span)) +} + +/// Extract the FilePicker reference from a guard, or error if not initialized. +fn picker_from_guard(guard: &Option, span: Span) -> Result<&FilePicker, ShellError> { + guard + .as_ref() + .ok_or_else(|| idx_not_initialized_error(span)) +} + +/// Validate that the picker has been initialized. +/// +/// Returns an error if the runtime is not yet initialized or if the shared +/// picker lock is poisoned. +fn ensure_picker_initialized( + shared_picker: &SharedFilePicker, + span: Span, +) -> Result<(), ShellError> { + let guard = read_picker_guard(shared_picker, span)?; + let _ = picker_from_guard(&guard, span)?; + Ok(()) +} + +/// Shut down the shared FilePicker and its background workers cleanly. +/// +/// # Important +/// +/// Never hold the shared picker write lock while joining the watcher thread, +/// otherwise the owner thread can deadlock waiting for the same lock while +/// processing a final event batch. fn shutdown_shared_picker(shared_picker: &SharedFilePicker, span: Span) -> Result<(), ShellError> { // Important: never join the watcher thread while holding the shared // picker write lock, otherwise the owner thread can deadlock waiting for @@ -147,18 +245,19 @@ fn shutdown_shared_picker(shared_picker: &SharedFilePicker, span: Span) -> Resul Ok(()) } +/// Build an `IdxStatus` from the current FilePicker state. fn idx_status_from_picker( base_path: &Path, watch: bool, picker: &FilePicker, - scan_duration_ms: u128, + scan_duration_ns: u64, ) -> IdxStatus { IdxStatus { initialized: true, base_path: base_path.display().to_string(), watch, scanning: picker.is_scan_active(), - scan_duration_ms, + scan_duration_ns, files: picker.get_files().len(), dirs: picker.get_dirs().len(), arena_bytes_base: picker.arena_bytes().0, @@ -167,36 +266,86 @@ fn idx_status_from_picker( } } -fn elapsed_ms(scan_start: Instant) -> u64 { - u64::try_from(scan_start.elapsed().as_millis()).unwrap_or(u64::MAX) +/// Get elapsed nanoseconds since the given scan start time. +fn elapsed_ns(scan_start: Instant) -> u64 { + u64::try_from(scan_start.elapsed().as_nanos()).unwrap_or(u64::MAX) } +/// Compute the scan duration, freezing it once the scan completes. +/// +/// This uses atomic operations to ensure the completion time is recorded exactly once, +/// even if called concurrently from multiple threads. fn freeze_scan_duration_if_needed( scan_completed: &AtomicBool, - scan_duration_ms: &AtomicU64, + scan_duration_ns: &AtomicU64, scan_start: Instant, scanning: bool, -) -> u128 { +) -> u64 { if scan_completed.load(Ordering::Acquire) { - return u128::from(scan_duration_ms.load(Ordering::Acquire)); + return scan_duration_ns.load(Ordering::Acquire); } - let elapsed = elapsed_ms(scan_start); + let elapsed = elapsed_ns(scan_start); if !scanning { if scan_completed .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) .is_ok() { - scan_duration_ms.store(elapsed, Ordering::Release); - return u128::from(elapsed); + scan_duration_ns.store(elapsed, Ordering::Release); + return elapsed; } - return u128::from(scan_duration_ms.load(Ordering::Acquire)); + return scan_duration_ns.load(Ordering::Acquire); } - u128::from(elapsed) + elapsed +} + +/// Poll until the background scan completes or times out. +fn wait_for_scan_completion( + shared_picker: &SharedFilePicker, + timeout: Duration, + span: Span, +) -> Result<(), ShellError> { + let poll_interval = Duration::from_millis(10); + let startup_grace = Duration::from_millis(250); + let wait_start = Instant::now(); + let mut saw_active_scan = false; + + loop { + let guard = read_picker_guard(shared_picker, span)?; + let picker = picker_from_guard(&guard, span)?; + let scanning = picker.is_scan_active(); + drop(guard); + + if scanning { + saw_active_scan = true; + } + + if saw_active_scan && !scanning { + return Ok(()); + } + + if !saw_active_scan && !scanning && wait_start.elapsed() >= startup_grace { + return Ok(()); + } + + if wait_start.elapsed() >= timeout { + return Err(ShellError::Generic(GenericError::new( + "idx scan timed out", + "timed out waiting for the initial scan to finish (300 s). The index is still available with partial results.", + span, + ))); + } + + std::thread::sleep(poll_interval); + } } +/// Retrieve a thread-safe snapshot of the current idx runtime state. +/// +/// This is a cheap operation that clones only Arc/Copy data, so callers can +/// work with the snapshot after releasing the global lock. fn runtime_snapshot() -> Option { let guard = runtime().lock().ok()?; let runtime = guard.as_ref()?; @@ -206,31 +355,52 @@ fn runtime_snapshot() -> Option { shared_picker: runtime.shared_picker.clone(), scan_start_time: runtime.scan_start_time, scan_completed: runtime.scan_completed.clone(), - scan_duration_ms: runtime.scan_duration_ms.clone(), + scan_duration_ns: runtime.scan_duration_ns.clone(), + restored_files: runtime.restored_files.clone(), + restored_dirs: runtime.restored_dirs.clone(), + restored_arena_bytes_base: runtime.restored_arena_bytes_base, + restored_arena_bytes_overflow: runtime.restored_arena_bytes_overflow, }) } +/// Get a runtime snapshot, or error if the runtime is not initialized. fn require_runtime(span: Span) -> Result { - runtime_snapshot().ok_or_else(|| { - ShellError::Generic(GenericError::new( - "idx is not initialized", - "run `idx init ` first", - span, - )) - }) + runtime_snapshot().ok_or_else(|| idx_not_initialized_error(span)) } +/// Return the current idx runtime status. +/// +/// `scan_start_override` exists for callers that need deterministic status +/// snapshots while coordinating scan lifecycle checks. pub fn current_status(scan_start_override: Option) -> IdxStatus { let Some(snapshot) = runtime_snapshot() else { return IdxStatus::default(); }; + if let (Some(restored_files), Some(restored_dirs)) = ( + snapshot.restored_files.as_ref(), + snapshot.restored_dirs.as_ref(), + ) { + return IdxStatus { + initialized: true, + base_path: snapshot.base_path.display().to_string(), + watch: snapshot.watch, + scanning: false, + scan_duration_ns: 0, + files: restored_files.len(), + dirs: restored_dirs.len(), + arena_bytes_base: snapshot.restored_arena_bytes_base, + arena_bytes_overflow: snapshot.restored_arena_bytes_overflow, + arena_bytes_untracked: 0, + }; + } + let scan_start = scan_start_override.unwrap_or(snapshot.scan_start_time); let Ok(guard) = snapshot.shared_picker.read() else { let duration = freeze_scan_duration_if_needed( &snapshot.scan_completed, - &snapshot.scan_duration_ms, + &snapshot.scan_duration_ns, scan_start, false, ); @@ -239,7 +409,7 @@ pub fn current_status(scan_start_override: Option) -> IdxStatus { base_path: snapshot.base_path.display().to_string(), watch: snapshot.watch, scanning: false, - scan_duration_ms: duration, + scan_duration_ns: duration, ..Default::default() }; }; @@ -250,7 +420,7 @@ pub fn current_status(scan_start_override: Option) -> IdxStatus { let scanning = picker.is_scan_active(); let duration = freeze_scan_duration_if_needed( &snapshot.scan_completed, - &snapshot.scan_duration_ms, + &snapshot.scan_duration_ns, scan_start, scanning, ); @@ -259,10 +429,14 @@ pub fn current_status(scan_start_override: Option) -> IdxStatus { .unwrap_or_default() } +/// Initialize a live idx runtime backed by `fff-search`. +/// +/// When `wait` is true this blocks until the initial filesystem scan finishes. pub fn init_runtime( path: &Path, watch: bool, wait: bool, + follow_symlinks: bool, span: Span, ) -> Result { let shared_picker = SharedFilePicker::default(); @@ -278,6 +452,7 @@ pub fn init_runtime( mode: FFFMode::Ai, cache_budget: None, watch, + follow_symlinks, }, ) .map_err(|err| fff_error(err, span))?; @@ -299,7 +474,11 @@ pub fn init_runtime( shared_picker: shared_picker.clone(), scan_start_time: Instant::now(), scan_completed: Arc::new(AtomicBool::new(false)), - scan_duration_ms: Arc::new(AtomicU64::new(0)), + scan_duration_ns: Arc::new(AtomicU64::new(0)), + restored_files: None, + restored_dirs: None, + restored_arena_bytes_base: 0, + restored_arena_bytes_overflow: 0, }); // Drop the lock before potentially blocking on --wait so other threads @@ -317,13 +496,7 @@ pub fn init_runtime( // generous so that large repos complete without errors. if wait { const WAIT_TIMEOUT: Duration = Duration::from_secs(300); - if !shared_picker.wait_for_scan(WAIT_TIMEOUT) { - return Err(ShellError::Generic(GenericError::new( - "idx scan timed out", - "timed out waiting for the initial scan to finish (300 s). The index is still available with partial results.", - span, - ))); - } + wait_for_scan_completion(&shared_picker, WAIT_TIMEOUT, span)?; if watch && !shared_picker.wait_for_watcher(WAIT_TIMEOUT) { return Err(ShellError::Generic(GenericError::new( "idx watcher startup timed out", @@ -332,17 +505,10 @@ pub fn init_runtime( ))); } } - let status = IdxStatus { - initialized: true, - base_path: path.display().to_string(), - watch, - scanning: true, - ..Default::default() - }; - - Ok(status) + Ok(current_status(None)) } +/// Drop the active idx runtime and stop background workers. pub fn drop_runtime(span: Span) -> Result { let mut guard = runtime().lock().map_err(|_| { ShellError::Generic(GenericError::new( @@ -372,52 +538,145 @@ pub fn drop_runtime(span: Span) -> Result { )) } -pub fn stream_dirs(span: Span, signals: &Signals) -> Result { +/// Stream indexed directories, optionally filtered by a fuzzy query. +/// +/// Uses snapshot-backed rows when runtime comes from `idx import`, otherwise +/// reads from the live picker. +pub fn stream_dirs( + query: Option, + span: Span, + signals: &Signals, +) -> Result { let snapshot = require_runtime(span)?; - let guard = snapshot - .shared_picker - .read() - .map_err(|err| fff_error(err, span))?; - let picker = guard.as_ref().ok_or_else(|| { - ShellError::Generic(GenericError::new( - "idx is not initialized", - "run `idx init ` first", - span, - )) - })?; + if let Some(restored_dirs) = snapshot.restored_dirs.clone() { + let ranked_indices = query + .as_deref() + .map(|q| rank_snapshot_matches(&restored_dirs, q, |dir| &dir.relative_path)); + + let stream_signals = signals.clone(); + let stream: Box + Send> = match ranked_indices { + Some(indices) => { + let mut iter = indices.into_iter(); + let restored_dirs = restored_dirs.clone(); + Box::new(std::iter::from_fn(move || { + if let Err(err) = stream_signals.check(&span) { + return Some(Value::error(err, span)); + } + + let idx = iter.next()?; + restored_dirs + .get(idx) + .map(|item| build_restored_dir_record(item, span)) + })) + } + None => { + let mut idx = 0usize; + let restored_dirs = restored_dirs.clone(); + Box::new(std::iter::from_fn(move || { + if let Err(err) = stream_signals.check(&span) { + return Some(Value::error(err, span)); + } + + let item = restored_dirs.get(idx)?; + idx = idx.saturating_add(1); + Some(build_restored_dir_record(item, span)) + })) + } + }; + + return Ok(PipelineData::ListStream( + ListStream::new(stream, span, signals.clone()), + Some(PipelineMetadata::default()), + )); + } + + let shared_picker = snapshot.shared_picker.clone(); let base_path = snapshot.base_path.clone(); - let dirs_data: Vec<_> = picker - .get_dirs() - .iter() - .map(|item| { - let rel_path = item.relative_path(picker); - let full_path = item.absolute_path(picker, &base_path); - Value::record( - [ - ("relative_path".to_string(), Value::string(rel_path, span)), - ( - "full_path".to_string(), - Value::string(full_path.to_string_lossy().to_string(), span), - ), - ] - .into_iter() - .collect(), - span, - ) - }) - .collect(); + // Validate runtime before constructing the lazy iterator. + ensure_picker_initialized(&shared_picker, span)?; + + let stream: Box + Send> = if let Some(query) = query { + let shared_picker_for_query = shared_picker.clone(); + let matched_paths = { + let guard = read_picker_guard(&shared_picker_for_query, span)?; + let picker = picker_from_guard(&guard, span)?; + + let parser = QueryParser::default(); + let parsed = parser.parse(&query); + let options = FuzzySearchOptions { + max_threads: 0, + current_file: None, + project_path: None, + combo_boost_score_multiplier: 0, + min_combo_count: 0, + pagination: PaginationArgs { + offset: 0, + limit: picker.get_dirs().len(), + }, + }; + + picker + .fuzzy_search_directories(&parsed, options) + .items + .iter() + .map(|item| item.relative_path(picker)) + .collect::>() + }; - drop(guard); + let mut path_iter = matched_paths.into_iter(); + let stream_signals = signals.clone(); + let shared_picker = shared_picker.clone(); + Box::new(std::iter::from_fn(move || { + loop { + if let Err(err) = stream_signals.check(&span) { + return Some(Value::error(err, span)); + } - let stream_signals = signals.clone(); - let stream = dirs_data.into_iter().map(move |value| { - if let Err(err) = stream_signals.check(&span) { - return Value::error(err, span); - } - value - }); + let path = path_iter.next()?; + + let guard = match read_picker_guard(&shared_picker, span) { + Ok(guard) => guard, + Err(err) => return Some(Value::error(err, span)), + }; + let picker = match picker_from_guard(&guard, span) { + Ok(picker) => picker, + Err(err) => return Some(Value::error(err, span)), + }; + + let item = picker + .get_dirs() + .iter() + .find(|item| item.relative_path(picker) == path); + if let Some(item) = item { + return Some(build_dir_record(item, picker, &base_path, span)); + } + } + })) + } else { + let mut idx = 0usize; + let stream_signals = signals.clone(); + let shared_picker = shared_picker.clone(); + Box::new(std::iter::from_fn(move || { + if let Err(err) = stream_signals.check(&span) { + return Some(Value::error(err, span)); + } + + let guard = match read_picker_guard(&shared_picker, span) { + Ok(guard) => guard, + Err(err) => return Some(Value::error(err, span)), + }; + let picker = match picker_from_guard(&guard, span) { + Ok(picker) => picker, + Err(err) => return Some(Value::error(err, span)), + }; + + let item = picker.get_dirs().get(idx)?; + idx = idx.saturating_add(1); + Some(build_dir_record(item, picker, &base_path, span)) + })) + }; Ok(PipelineData::ListStream( ListStream::new(stream, span, signals.clone()), @@ -425,60 +684,145 @@ pub fn stream_dirs(span: Span, signals: &Signals) -> Result, + query: Option, span: Span, signals: &Signals, ) -> Result { let snapshot = require_runtime(span)?; - let guard = snapshot - .shared_picker - .read() - .map_err(|err| fff_error(err, span))?; - let picker = guard.as_ref().ok_or_else(|| { - ShellError::Generic(GenericError::new( - "idx is not initialized", - "run `idx init ` first", - span, - )) - })?; + if let Some(restored_files) = snapshot.restored_files.clone() { + let ranked_indices = query + .as_deref() + .map(|q| rank_snapshot_matches(&restored_files, q, |file| &file.relative_path)); + + let stream_signals = signals.clone(); + let stream: Box + Send> = match ranked_indices { + Some(indices) => { + let mut iter = indices.into_iter(); + let restored_files = restored_files.clone(); + Box::new(std::iter::from_fn(move || { + if let Err(err) = stream_signals.check(&span) { + return Some(Value::error(err, span)); + } + + let idx = iter.next()?; + restored_files + .get(idx) + .map(|item| build_restored_file_record(item, span)) + })) + } + None => { + let mut idx = 0usize; + let restored_files = restored_files.clone(); + Box::new(std::iter::from_fn(move || { + if let Err(err) = stream_signals.check(&span) { + return Some(Value::error(err, span)); + } + + let item = restored_files.get(idx)?; + idx = idx.saturating_add(1); + Some(build_restored_file_record(item, span)) + })) + } + }; + + return Ok(PipelineData::ListStream( + ListStream::new(stream, span, signals.clone()), + Some(PipelineMetadata::default()), + )); + } + + let shared_picker = snapshot.shared_picker.clone(); let base_path = snapshot.base_path.clone(); - let files_data: Vec<_> = if let Some(path_str) = path { - let lookup_path = Path::new(&path_str); + // Validate runtime before constructing the lazy iterator. + ensure_picker_initialized(&shared_picker, span)?; + + let stream: Box + Send> = if let Some(query) = query { + let shared_picker_for_query = shared_picker.clone(); + let matched_paths = { + let guard = read_picker_guard(&shared_picker_for_query, span)?; + let picker = picker_from_guard(&guard, span)?; + + let parser = QueryParser::default(); + let parsed = parser.parse(&query); + let options = FuzzySearchOptions { + max_threads: 0, + current_file: None, + project_path: None, + combo_boost_score_multiplier: 0, + min_combo_count: 0, + pagination: PaginationArgs { + offset: 0, + limit: picker.get_files().len(), + }, + }; + + picker + .fuzzy_search(&parsed, None, options) + .items + .iter() + .map(|item| item.relative_path(picker)) + .collect::>() + }; - // Try relative path first, then strip base_path prefix from absolute paths. - let item = picker.get_file_by_path(lookup_path).or_else(|| { - if lookup_path.is_absolute() { - lookup_path - .strip_prefix(&base_path) - .ok() - .and_then(|rel| picker.get_file_by_path(rel)) - } else { - None - } - }); + let mut path_iter = matched_paths.into_iter(); + let stream_signals = signals.clone(); + let shared_picker = shared_picker.clone(); + Box::new(std::iter::from_fn(move || { + loop { + if let Err(err) = stream_signals.check(&span) { + return Some(Value::error(err, span)); + } - item.map(|i| vec![build_file_record(i, picker, &base_path, span)]) - .unwrap_or_default() - } else { - picker - .get_files() - .iter() - .map(|item| build_file_record(item, picker, &base_path, span)) - .collect() - }; + let path = path_iter.next()?; - drop(guard); + let guard = match read_picker_guard(&shared_picker, span) { + Ok(guard) => guard, + Err(err) => return Some(Value::error(err, span)), + }; + let picker = match picker_from_guard(&guard, span) { + Ok(picker) => picker, + Err(err) => return Some(Value::error(err, span)), + }; - let stream_signals = signals.clone(); - let stream = files_data.into_iter().map(move |value| { - if let Err(err) = stream_signals.check(&span) { - return Value::error(err, span); - } - value - }); + let item = picker + .get_files() + .iter() + .find(|item| item.relative_path(picker) == path); + if let Some(item) = item { + return Some(build_file_record(item, picker, &base_path, span)); + } + } + })) + } else { + let mut idx = 0usize; + let stream_signals = signals.clone(); + let shared_picker = shared_picker.clone(); + Box::new(std::iter::from_fn(move || { + if let Err(err) = stream_signals.check(&span) { + return Some(Value::error(err, span)); + } + + let guard = match read_picker_guard(&shared_picker, span) { + Ok(guard) => guard, + Err(err) => return Some(Value::error(err, span)), + }; + let picker = match picker_from_guard(&guard, span) { + Ok(picker) => picker, + Err(err) => return Some(Value::error(err, span)), + }; + + let item = picker.get_files().get(idx)?; + idx = idx.saturating_add(1); + Some(build_file_record(item, picker, &base_path, span)) + })) + }; Ok(PipelineData::ListStream( ListStream::new(stream, span, signals.clone()), @@ -486,14 +830,38 @@ pub fn stream_files( )) } +/// Build a directory record from a live picker's DirItem. +fn build_dir_record( + item: &fff_search::DirItem, + picker: &FilePicker, + base_path: &Path, + span: Span, +) -> Value { + let rel_path = item.relative_path(picker); + let full_path = item.absolute_path(picker, base_path); + + build_record_from_cols( + [ + ("relative_path".to_string(), Value::string(rel_path, span)), + ( + "full_path".to_string(), + Value::string(full_path.to_string_lossy().to_string(), span), + ), + ], + span, + ) +} + +/// Build a file record from a live picker's FileItem. fn build_file_record( item: &fff_search::FileItem, picker: &FilePicker, base_path: &Path, span: Span, ) -> Value { + let file_name = item.file_name(picker); let full_path = item.absolute_path(picker, base_path); - Value::record( + build_record_from_cols( [ ( "relative_path".to_string(), @@ -505,7 +873,11 @@ fn build_file_record( ), ( "file_name".to_string(), - Value::string(item.file_name(picker), span), + Value::string(file_name.clone(), span), + ), + ( + "ext".to_string(), + Value::string(file_extension(&file_name), span), ), ( "directory".to_string(), @@ -513,23 +885,173 @@ fn build_file_record( ), ( "size".to_string(), - Value::int(i64::try_from(item.size).unwrap_or(i64::MAX), span), + Value::filesize(i64::try_from(item.size).unwrap_or(i64::MAX), span), ), ( "modified".to_string(), - Value::int(i64::try_from(item.modified).unwrap_or(i64::MAX), span), + modified_to_date_value(item.modified, span), ), - ] - .into_iter() - .collect(), + ], + span, + ) +} + +/// Build a directory record from a restored snapshot. +fn build_restored_dir_record(item: &IdxRestoredDir, span: Span) -> Value { + build_record_from_cols( + [ + ( + "relative_path".to_string(), + Value::string(item.relative_path.clone(), span), + ), + ( + "full_path".to_string(), + Value::string(item.full_path.clone(), span), + ), + ], + span, + ) +} + +/// Build a file record from a restored snapshot. +fn build_restored_file_record(item: &IdxRestoredFile, span: Span) -> Value { + build_record_from_cols( + [ + ( + "relative_path".to_string(), + Value::string(item.relative_path.clone(), span), + ), + ( + "full_path".to_string(), + Value::string(item.full_path.clone(), span), + ), + ( + "file_name".to_string(), + Value::string(item.file_name.clone(), span), + ), + ( + "ext".to_string(), + Value::string(file_extension(&item.file_name), span), + ), + ( + "directory".to_string(), + Value::string(item.directory.clone(), span), + ), + ( + "size".to_string(), + Value::filesize(i64::try_from(item.size).unwrap_or(i64::MAX), span), + ), + ( + "modified".to_string(), + modified_to_date_value(item.modified, span), + ), + ], span, ) } +/// Convert an indexed file timestamp (unix seconds) to a Nushell date value. +fn modified_to_date_value(modified: u64, span: Span) -> Value { + let to_fixed = |secs: i64| -> Option> { + let utc = match Utc.timestamp_opt(secs, 0) { + LocalResult::Single(ts) => ts, + _ => return None, + }; + let local = utc.with_timezone(&Local); + Some(local.with_timezone(local.offset())) + }; + + let secs = i64::try_from(modified).unwrap_or(i64::MAX); + if let Some(dt) = to_fixed(secs).or_else(|| to_fixed(0)) { + Value::date(dt, span) + } else { + Value::nothing(span) + } +} + +/// Extract a file extension without the leading dot. +fn file_extension(file_name: &str) -> String { + Path::new(file_name) + .extension() + .map(|ext| ext.to_string_lossy().to_string()) + .unwrap_or_default() +} + +/// Helper to construct a Nushell record from a small array of columns. +#[inline] +fn build_record_from_cols(cols: [(String, Value); N], span: Span) -> Value { + Value::record(cols.into_iter().collect(), span) +} + +/// Score how well a path matches a query using fuzzy matching heuristics. +/// +/// Returns `None` if no match found, `Some(score)` where higher scores are better matches. +/// Scoring prioritizes exact matches, prefix matches, substring matches, and finally +/// fuzzy character sequences. +fn score_snapshot_match(path: &str, query: &str) -> Option { + let query = query.trim(); + if query.is_empty() { + return Some(0); + } + + let path_lower = path.to_ascii_lowercase(); + let query_lower = query.to_ascii_lowercase(); + + if path_lower == query_lower { + return Some(4_000); + } + + if path_lower.starts_with(&query_lower) { + return Some(3_000); + } + + if let Some(pos) = path_lower.find(&query_lower) { + let proximity = i64::try_from(pos).unwrap_or(i64::MAX); + return Some(2_000_i64.saturating_sub(proximity)); + } + + let mut query_iter = query_lower.chars(); + let mut needle = query_iter.next()?; + for ch in path_lower.chars() { + if ch == needle { + if let Some(next) = query_iter.next() { + needle = next; + } else { + return Some(1_000); + } + } + } + + None +} + +/// Rank items by how well their keys match the query. +/// +/// Returns a vec of indices sorted by descending match score, with ties broken +/// by ascending original index to maintain stable order. +fn rank_snapshot_matches(items: &[T], query: &str, key: impl Fn(&T) -> &str) -> Vec { + let mut ranked = items + .iter() + .enumerate() + .filter_map(|(idx, item)| score_snapshot_match(key(item), query).map(|score| (idx, score))) + .collect::>(); + + ranked.sort_unstable_by(|(lhs_idx, lhs_score), (rhs_idx, rhs_score)| { + rhs_score.cmp(lhs_score).then_with(|| lhs_idx.cmp(rhs_idx)) + }); + + ranked.into_iter().map(|(idx, _)| idx).collect() +} + +/// Convert a usize to i64, saturating at i64::MAX to avoid overflow. fn usize_to_i64(value: usize) -> i64 { i64::try_from(value).unwrap_or(i64::MAX) } +/// Run a fuzzy find across indexed files and/or directories. +/// +/// For imported snapshots this uses lightweight in-memory ranking over +/// restored path metadata. pub fn stream_find( query: &str, files_only: bool, @@ -540,6 +1062,111 @@ pub fn stream_find( signals: &Signals, ) -> Result { let snapshot = require_runtime(span)?; + + if let (Some(restored_files), Some(restored_dirs)) = ( + snapshot.restored_files.clone(), + snapshot.restored_dirs.clone(), + ) { + let mut ranked_files = restored_files + .iter() + .enumerate() + .filter_map(|(idx, item)| { + score_snapshot_match(&item.relative_path, query).map(|score| ("file", idx, score)) + }) + .collect::>(); + + let mut ranked_dirs = restored_dirs + .iter() + .enumerate() + .filter_map(|(idx, item)| { + score_snapshot_match(&item.relative_path, query).map(|score| ("dir", idx, score)) + }) + .collect::>(); + + if files_only { + ranked_dirs.clear(); + } + if dirs_only { + ranked_files.clear(); + } + + let mut combined = Vec::with_capacity(ranked_files.len().saturating_add(ranked_dirs.len())); + combined.extend(ranked_files); + combined.extend(ranked_dirs); + combined.sort_unstable_by( + |(lhs_kind, lhs_idx, lhs_score), (rhs_kind, rhs_idx, rhs_score)| { + rhs_score + .cmp(lhs_score) + .then_with(|| lhs_kind.cmp(rhs_kind)) + .then_with(|| lhs_idx.cmp(rhs_idx)) + }, + ); + combined.truncate(limit); + + let find_data = combined + .into_iter() + .enumerate() + .map(|(rank, (kind, idx, score))| { + let path = if kind == "file" { + restored_files + .get(idx) + .map(|row| row.relative_path.clone()) + .unwrap_or_default() + } else { + restored_dirs + .get(idx) + .map(|row| row.relative_path.clone()) + .unwrap_or_default() + }; + + let mut cols = vec![ + ("kind".to_string(), Value::string(kind, span)), + ("path".to_string(), Value::string(path, span)), + ("rank".to_string(), Value::int(usize_to_i64(rank + 1), span)), + ("score".to_string(), Value::int(score, span)), + ]; + + if verbose { + if !files_only && !dirs_only { + cols.push(( + "score_details".to_string(), + Value::record( + [ + ("base_score".to_string(), Value::int(score, span)), + ("filename_bonus".to_string(), Value::int(0, span)), + ("special_filename_bonus".to_string(), Value::int(0, span)), + ("frecency_boost".to_string(), Value::int(0, span)), + ] + .into_iter() + .collect(), + span, + ), + )); + } else if files_only { + cols.push(("match_type".to_string(), Value::string("snapshot", span))); + } else { + cols.push(("exact_match".to_string(), Value::bool(false, span))); + } + } + + Value::record(cols.into_iter().collect(), span) + }) + .collect::>(); + + let stream_signals = signals.clone(); + let stream = find_data.into_iter().map(move |value| { + if let Err(err) = stream_signals.check(&span) { + return Value::error(err, span); + } + value + }); + + return Ok(PipelineData::ListStream( + ListStream::new(stream, span, signals.clone()), + Some(PipelineMetadata::default()), + )); + } + let guard = snapshot .shared_picker .read() @@ -725,20 +1352,12 @@ pub struct IdxSnapshotDir { pub is_overflow: bool, } +/// Persist the current idx runtime into a SQLite snapshot file. #[cfg(feature = "sqlite")] pub fn store_snapshot(path: &Path, span: Span) -> Result { let snapshot = require_runtime(span)?; - let guard = snapshot - .shared_picker - .read() - .map_err(|err| fff_error(err, span))?; - let picker = guard.as_ref().ok_or_else(|| { - ShellError::Generic(GenericError::new( - "idx is not initialized", - "run `idx init ` first", - span, - )) - })?; + let guard = read_picker_guard(&snapshot.shared_picker, span)?; + let picker = picker_from_guard(&guard, span)?; let files = picker .get_files() @@ -952,6 +1571,10 @@ pub fn store_snapshot(path: &Path, span: Span) -> Result { )) } +/// Restore idx runtime from a SQLite snapshot file. +/// +/// The restored runtime is immediately queryable by `idx files`, `idx dirs`, +/// `idx find`, and `idx status` without a filesystem scan. #[cfg(feature = "sqlite")] pub fn restore_snapshot(path: &Path, span: Span) -> Result { // Open SQLite database @@ -994,7 +1617,7 @@ pub fn restore_snapshot(path: &Path, span: Span) -> Result { )) })?; - let (version, base_path_str, watch, file_count, dir_count) = metadata; + let (version, base_path_str, _watch, _file_count, _dir_count) = metadata; if version != 1 { return Err(ShellError::Generic(GenericError::new( @@ -1109,19 +1732,79 @@ pub fn restore_snapshot(path: &Path, span: Span) -> Result { } } - // Create status from restored snapshot data (no live scanning) - let status = IdxStatus { - initialized: true, - base_path: base_path_str.clone(), - watch, - scanning: false, // offline restore doesn't scan - scan_duration_ms: 0, - files: file_count, - dirs: dir_count, - arena_bytes_base, - arena_bytes_overflow, - arena_bytes_untracked: 0, - }; + let restored_files = Arc::new( + files + .iter() + .map(|row| IdxRestoredFile { + relative_path: row.relative_path.clone(), + full_path: row.full_path.clone(), + file_name: row.file_name.clone(), + directory: row.directory.clone(), + size: row.size, + modified: row.modified, + }) + .collect::>(), + ); + + let restored_dirs = Arc::new( + dirs.iter() + .map(|row| IdxRestoredDir { + relative_path: row.relative_path.clone(), + full_path: row.full_path.clone(), + }) + .collect::>(), + ); + + let mut guard = runtime().lock().map_err(|_| { + ShellError::Generic(GenericError::new( + "idx runtime lock failed", + "idx runtime lock poisoned", + span, + )) + })?; + + let shared_picker = SharedFilePicker::default(); + let shared_frecency = SharedFrecency::noop(); + + // Try to initialize a live picker for the base_path to enable grep search. + // This happens in the background; if the path no longer exists, grep will + // simply return no results. + let _ = FilePicker::new_with_shared_state( + shared_picker.clone(), + shared_frecency, + FilePickerOptions { + base_path: base_path_str.clone(), + enable_mmap_cache: false, + enable_content_indexing: false, + mode: FFFMode::Ai, + cache_budget: None, + watch: false, + follow_symlinks: false, + }, + ); + + // Wait for the picker scan to complete so grep can search indexed content. + let _ = shared_picker.wait_for_scan(Duration::from_secs(300)); + + let previous = guard.replace(IdxRuntime { + base_path: PathBuf::from(&base_path_str), + watch: false, + shared_picker: shared_picker.clone(), + scan_start_time: Instant::now(), + scan_completed: Arc::new(AtomicBool::new(true)), + scan_duration_ns: Arc::new(AtomicU64::new(0)), + restored_files: Some(restored_files.clone()), + restored_dirs: Some(restored_dirs.clone()), + restored_arena_bytes_base: arena_bytes_base, + restored_arena_bytes_overflow: arena_bytes_overflow, + }); + drop(guard); + + if let Some(old_runtime) = previous { + let _ = shutdown_shared_picker(&old_runtime.shared_picker, span); + } + + let status = current_status(None); Ok(Value::record( [ @@ -1134,19 +1817,22 @@ pub fn restore_snapshot(path: &Path, span: Span) -> Result { "base_path".to_string(), Value::string(base_path_str.clone(), span), ), - ("watch".to_string(), Value::bool(watch, span)), + ("watch".to_string(), Value::bool(false, span)), ( "rehydration_mode".to_string(), - Value::string("offline_from_snapshot_rows", span), + Value::string("snapshot_runtime_restored", span), ), ("status".to_string(), status.to_value(span)), ( "restored_files".to_string(), - Value::int(i64::try_from(files.len()).unwrap_or(i64::MAX), span), + Value::int( + i64::try_from(restored_files.len()).unwrap_or(i64::MAX), + span, + ), ), ( "restored_dirs".to_string(), - Value::int(i64::try_from(dirs.len()).unwrap_or(i64::MAX), span), + Value::int(i64::try_from(restored_dirs.len()).unwrap_or(i64::MAX), span), ), ("format".to_string(), Value::string("sqlite", span)), ] @@ -1156,6 +1842,10 @@ pub fn restore_snapshot(path: &Path, span: Span) -> Result { )) } +/// Search indexed file contents (`idx search`). +/// +/// When backed by an imported snapshot, grep searches the live filesystem for the base_path. +/// If the base_path no longer exists or files have been moved, grep will return no results. pub fn stream_grep( patterns: &[String], mode: GrepMode, @@ -1164,17 +1854,9 @@ pub fn stream_grep( signals: &Signals, ) -> Result { let snapshot = require_runtime(span)?; - let guard = snapshot - .shared_picker - .read() - .map_err(|err| fff_error(err, span))?; - let picker = guard.as_ref().ok_or_else(|| { - ShellError::Generic(GenericError::new( - "idx is not initialized", - "run `idx init ` first", - span, - )) - })?; + + let guard = read_picker_guard(&snapshot.shared_picker, span)?; + let picker = picker_from_guard(&guard, span)?; let options = GrepSearchOptions { mode, @@ -1191,85 +1873,75 @@ pub fn stream_grep( picker.multi_grep(&refs, &[], &options) }; - let grep_data: Vec = result - .matches + let file_paths = result + .files .iter() - .map(|item| { - let path = result - .files - .get(item.file_index) - .map(|f| f.relative_path(picker)) - .unwrap_or_else(|| "".to_string()); - - let offsets = item - .match_byte_offsets - .iter() - .map(|(start, end)| { - let start = i64::from(*start); - let end = i64::from(*end); - Value::record( - [ - // ("start".to_string(), Value::int(start, span)), - // ("end".to_string(), Value::int(end, span)), - - // I'm guessing calculated offset to match start, end is more valuable - // than just the offset to start and end of the match - ( - "start".to_string(), - // byte_offset is the offset to the beginning of the line, - // so match start is offset + start - Value::int(start + item.byte_offset as i64, span), - ), - ( - "end".to_string(), - // byte_offset is the offset to the beginning of the line, - // so match end is offset + start + length or offset + end - Value::int(item.byte_offset as i64 + end, span), - ), - ] - .into_iter() - .collect(), - span, - ) - }) - .collect::>(); - - Value::record( - [ - ("path".to_string(), Value::string(path, span)), - ( - "line_number".to_string(), - Value::int(i64::try_from(item.line_number).unwrap_or(i64::MAX), span), - ), - ( - "column".to_string(), - Value::int(usize_to_i64(item.col), span), - ), - ( - "byte_offset".to_string(), - Value::int(i64::try_from(item.byte_offset).unwrap_or(i64::MAX), span), - ), - ( - "line".to_string(), - Value::string(item.line_content.clone(), span), - ), - ("matches".to_string(), Value::list(offsets, span)), - ] - .into_iter() - .collect(), - span, - ) - }) - .collect(); + .map(|f| f.relative_path(picker)) + .collect::>(); + let matches = result.matches; drop(guard); let stream_signals = signals.clone(); - let stream = grep_data.into_iter().map(move |value| { + let stream = matches.into_iter().map(move |item| { if let Err(err) = stream_signals.check(&span) { return Value::error(err, span); } - value + + let path = file_paths + .get(item.file_index) + .cloned() + .unwrap_or_else(|| "".to_string()); + + let offsets = item + .match_byte_offsets + .iter() + .map(|(start, end)| { + let start = i64::from(*start); + let end = i64::from(*end); + Value::record( + [ + ( + "start".to_string(), + Value::int(start + item.byte_offset as i64, span), + ), + ( + "end".to_string(), + Value::int(item.byte_offset as i64 + end, span), + ), + ] + .into_iter() + .collect(), + span, + ) + }) + .collect::>(); + + Value::record( + [ + ("path".to_string(), Value::string(path, span)), + ( + "line_number".to_string(), + Value::int(i64::try_from(item.line_number).unwrap_or(i64::MAX), span), + ), + ( + "column".to_string(), + Value::int(usize_to_i64(item.col), span), + ), + ( + "byte_offset".to_string(), + Value::int(i64::try_from(item.byte_offset).unwrap_or(i64::MAX), span), + ), + ( + "line".to_string(), + Value::string(item.line_content.clone(), span), + ), + ("matches".to_string(), Value::list(offsets, span)), + ] + .into_iter() + .collect(), + span, + ) }); Ok(PipelineData::ListStream( diff --git a/crates/nu-command/src/formats/to/yaml.rs b/crates/nu-command/src/formats/to/yaml.rs index 22859098ddb31..1c4e4bae992b4 100644 --- a/crates/nu-command/src/formats/to/yaml.rs +++ b/crates/nu-command/src/formats/to/yaml.rs @@ -1,18 +1,8 @@ use nu_engine::command_prelude::*; use nu_protocol::ast::PathMember; +use std::borrow::Cow; use std::fmt::Write as _; -/// YAML 1.1 boolean-like strings that need quoting when used as record keys. -const YAML_11_BOOLEANS: &[&str] = &[ - "y", "Y", "yes", "Yes", "YES", "n", "N", "no", "No", "NO", "on", "On", "ON", "off", "Off", - "OFF", -]; - -/// YAML special float and numeric strings that need quoting to preserve them as strings. -const YAML_SPECIAL_NUMERICS: &[&str] = &[ - ".inf", ".Inf", ".INF", "-.inf", "-.Inf", "-.INF", ".nan", ".NaN", ".NAN", -]; - #[derive(Clone)] pub struct ToYamlLike(&'static str); pub const TO_YAML: ToYamlLike = ToYamlLike("to yaml"); @@ -169,56 +159,70 @@ fn render_yaml_string(value: &str) -> String { } } -fn should_quote_yaml_key(key: &str) -> bool { - if key.is_empty() { - return true; - } - if key.chars().any(char::is_control) { - return true; - } - if key.starts_with(char::is_whitespace) || key.ends_with(char::is_whitespace) { - return true; - } - if YAML_11_BOOLEANS.contains(&key) { - return true; - } - if matches!( - key, - "~" | "null" | "Null" | "NULL" | "true" | "True" | "TRUE" | "false" | "False" | "FALSE" - ) { - return true; - } - // Check for YAML special numeric values (.inf, .nan) and hex/octal notation - if YAML_SPECIAL_NUMERICS.contains(&key) { - return true; - } - if key.starts_with("0x") || key.starts_with("0X") { - return true; - } - if key.starts_with("0o") || key.starts_with("0O") { - return true; - } - if key.parse::().is_ok() { - return true; - } - if key.parse::().is_ok() { - return true; - } - if key.parse::().is_ok() { - return true; +/// Returns true when a plain scalar would be resolved to a non-string type. +/// +/// We quote these values to preserve string semantics across Core-schema loaders +/// and to keep compatibility with YAML 1.1 boolean spellings. +fn has_yaml_non_string_semantics(string: &str) -> bool { + [ + // Canonical forms of the boolean values in the Core schema. + "true", "false", "True", "False", "TRUE", "FALSE", + // Canonical forms of the null value in the Core schema. + "null", "Null", "NULL", "~", + // Quote YAML 1.1 booleans for compatibility with 1.1 parsers. + "y", "Y", "n", "N", "yes", "Yes", "YES", "no", "No", "NO", "on", "On", "ON", "off", "Off", + "OFF", // YAML special float spellings. + ".inf", ".Inf", ".INF", "-.inf", "-.Inf", "-.INF", ".nan", ".NaN", ".NAN", + ] + .contains(&string) + || string.starts_with('.') + || string.starts_with("0x") + || string.starts_with("0X") + || string.starts_with("0o") + || string.starts_with("0O") + || string.parse::().is_ok() + || string.parse::().is_ok() + || string.parse::().is_ok() +} + +/// Returns true when a scalar must be quoted to remain valid and unambiguous. +/// +/// This helper applies YAML plain-scalar restrictions shared by keys and values. +fn should_quote_yaml_scalar(string: &str) -> bool { + fn needs_quotes_due_to_start(string: &str) -> bool { + let mut chars = string.chars(); + let Some(first) = chars.next() else { + return true; + }; + + match first { + // These may start a plain scalar only when followed by a non-space character. + '-' | '?' | ':' => chars.next().is_none_or(char::is_whitespace), + // These cannot start a plain scalar. + '[' | ']' | '{' | '}' | ',' | '#' | '&' | '*' | '!' | '|' | '>' | '\'' | '"' | '%' + | '@' | '`' => true, + _ => false, + } } - if !key - .chars() - .all(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '-' | '.' | '/')) + + if string.is_empty() + || string.starts_with(char::is_whitespace) + || string.ends_with(char::is_whitespace) + || string.chars().any(char::is_control) + || has_yaml_non_string_semantics(string) { return true; } - false + + // Plain scalars cannot contain these combinations. + let has_plain_ambiguity = string.contains(": ") || string.contains(" #"); + + needs_quotes_due_to_start(string) || has_plain_ambiguity } fn render_yaml_key(key: &serde_yaml::Value) -> String { match key { - serde_yaml::Value::String(key) if should_quote_yaml_key(key) => render_yaml_string(key), + serde_yaml::Value::String(key) if should_quote_yaml_scalar(key) => render_yaml_string(key), serde_yaml::Value::String(key) => key.clone(), _ => render_inline_yaml_value(key), } @@ -229,7 +233,10 @@ fn render_inline_yaml_value(value: &serde_yaml::Value) -> String { serde_yaml::Value::Null => "null".to_string(), serde_yaml::Value::Bool(value) => value.to_string(), serde_yaml::Value::Number(value) => value.to_string(), - serde_yaml::Value::String(value) => render_yaml_string(value), + serde_yaml::Value::String(value) if should_quote_yaml_scalar(value) => { + render_yaml_string(value) + } + serde_yaml::Value::String(value) => value.clone(), serde_yaml::Value::Sequence(values) => { let values = values .iter() @@ -258,11 +265,74 @@ fn render_inline_yaml_value(value: &serde_yaml::Value) -> String { } } +fn is_yaml_block_scalar_candidate(value: &str) -> bool { + (value.contains('\n') || value.contains('\r')) + && !value + .chars() + .any(|c| c.is_control() && !matches!(c, '\n' | '\r' | '\t')) +} + +fn normalize_yaml_line_breaks(value: &str) -> Cow<'_, str> { + if !value.contains('\r') { + return Cow::Borrowed(value); + } + + let mut normalized = String::with_capacity(value.len()); + let mut chars = value.chars().peekable(); + + while let Some(ch) = chars.next() { + if ch == '\r' { + if chars.peek() == Some(&'\n') { + chars.next(); + } + + normalized.push('\n'); + } else { + normalized.push(ch); + } + } + + Cow::Owned(normalized) +} + +fn yaml_block_chomping_indicator(value: &str) -> &'static str { + let trailing_newlines = value.chars().rev().take_while(|&c| c == '\n').count(); + + match trailing_newlines { + 0 => "-", + 1 => "", + _ => "+", + } +} + +fn write_yaml_block_scalar(output: &mut String, value: &str, body_indent: usize) { + let normalized = normalize_yaml_line_breaks(value); + let normalized = normalized.as_ref(); + let chomping = yaml_block_chomping_indicator(normalized); + + output.push('|'); + output.push_str(chomping); + output.push('\n'); + + let body = if chomping == "-" { + Cow::Owned(format!("{normalized}\n")) + } else { + Cow::Borrowed(normalized) + }; + + for line in body.split_terminator('\n') { + write_yaml_indent(output, body_indent); + output.push_str(line); + output.push('\n'); + } +} + fn is_inline_yaml_value(value: &serde_yaml::Value) -> bool { match value { serde_yaml::Value::Sequence(values) => values.is_empty(), serde_yaml::Value::Mapping(entries) => entries.is_empty(), serde_yaml::Value::Tagged(tagged) => is_inline_yaml_value(&tagged.value), + serde_yaml::Value::String(value) => !is_yaml_block_scalar_candidate(value), _ => true, } } @@ -281,6 +351,10 @@ fn write_yaml_value(output: &mut String, value: &serde_yaml::Value, indent: usiz serde_yaml::Value::Mapping(entries) if !entries.is_empty() => { write_yaml_mapping(output, entries, indent, ""); } + serde_yaml::Value::String(value) if is_yaml_block_scalar_candidate(value) => { + write_yaml_indent(output, indent); + write_yaml_block_scalar(output, value, indent + 2); + } serde_yaml::Value::Tagged(tagged) => write_yaml_value(output, &tagged.value, indent), _ => { write_yaml_indent(output, indent); @@ -293,6 +367,11 @@ fn write_yaml_value(output: &mut String, value: &serde_yaml::Value, indent: usiz fn write_yaml_sequence(output: &mut String, values: &[serde_yaml::Value], indent: usize) { for value in values { match value { + serde_yaml::Value::String(value) if is_yaml_block_scalar_candidate(value) => { + write_yaml_indent(output, indent); + output.push_str("- "); + write_yaml_block_scalar(output, value, indent + 2); + } serde_yaml::Value::Mapping(entries) if !entries.is_empty() => { write_yaml_mapping(output, entries, indent, "- "); } @@ -336,7 +415,12 @@ fn write_yaml_mapping( output.push_str(&render_yaml_key(key)); - if is_inline_yaml_value(value) { + if let serde_yaml::Value::String(value) = value + && is_yaml_block_scalar_candidate(value) + { + output.push_str(": "); + write_yaml_block_scalar(output, value, key_indent + 2); + } else if is_inline_yaml_value(value) { output.push_str(": "); output.push_str(&render_inline_yaml_value(value)); output.push('\n'); diff --git a/crates/nu-command/tests/commands/idx.rs b/crates/nu-command/tests/commands/idx.rs index 7df66e7b113c0..6f62d73d516ff 100644 --- a/crates/nu-command/tests/commands/idx.rs +++ b/crates/nu-command/tests/commands/idx.rs @@ -46,6 +46,22 @@ fn idx_status_reports_watch_disabled_by_default() -> Result { ) } +#[test] +#[serial] +fn idx_status_reports_scan_duration_as_duration() -> Result { + Playground::setup( + "idx_status_reports_scan_duration_as_duration", + |dirs, sandbox| { + sandbox.with_files(&[EmptyFile("timed.txt")]); + + test() + .cwd(dirs.test()) + .run("idx init . --wait; idx status | get scan_duration | describe") + .expect_value_eq("duration") + }, + ) +} + #[test] #[serial] fn idx_files_returns_records_with_full_path() -> Result { @@ -62,6 +78,90 @@ fn idx_files_returns_records_with_full_path() -> Result { ) } +#[test] +#[serial] +fn idx_files_returns_ext_and_native_types() -> Result { + Playground::setup("idx_files_returns_ext_and_native_types", |dirs, sandbox| { + sandbox.with_files(&[EmptyFile("quote.txt")]); + + test() + .cwd(dirs.test()) + .run("idx init . --wait; let row = (idx files quote | where file_name == quote.txt | first); let modified_kind = ($row.modified | describe | str downcase); ($row.ext == 'txt') and (($row.size | describe) == 'filesize') and ($modified_kind | str contains 'date')") + .expect_value_eq(true) + }) +} + +#[test] +#[serial] +fn idx_init_wait_reports_scanning_as_false() -> Result { + Playground::setup( + "idx_init_wait_reports_scanning_as_false", + |dirs, sandbox| { + sandbox.with_files(&[EmptyFile("scan-me.txt")]); + + test() + .cwd(dirs.test()) + .run("idx init . --wait | get scanning") + .expect_value_eq(false) + }, + ) +} + +#[test] +#[serial] +fn idx_init_wait_indexes_generated_files_before_returning() -> Result { + Playground::setup( + "idx_init_wait_indexes_generated_files_before_returning", + |dirs, _sandbox| { + test() + .cwd(dirs.test()) + .run("let expected = 600; 0..($expected - 1) | each {|i| touch $\"bulk-($i).txt\" }; idx init . --wait; idx files | where {|row| $row.file_name | str starts-with 'bulk-' } | length") + .expect_value_eq(600) + }, + ) +} + +#[test] +#[serial] +fn idx_init_wait_status_reports_indexed_file_count() -> Result { + Playground::setup( + "idx_init_wait_status_reports_indexed_file_count", + |dirs, sandbox| { + sandbox.with_files(&[ + EmptyFile("alpha.txt"), + EmptyFile("beta.txt"), + EmptyFile("gamma.txt"), + ]); + + test() + .cwd(dirs.test()) + .run("let status = (idx init . --wait); let counted = (idx files | length); ($status | get files) == $counted") + .expect_value_eq(true) + }, + ) +} + +#[test] +#[serial] +fn idx_files_optional_query_uses_fuzzy_matching() -> Result { + Playground::setup( + "idx_files_optional_query_uses_fuzzy_matching", + |dirs, sandbox| { + sandbox.mkdir("src"); + sandbox.with_files(&[ + EmptyFile("src/main.rs"), + EmptyFile("src/lib.rs"), + EmptyFile("README.md"), + ]); + + test() + .cwd(dirs.test()) + .run("idx init . --wait; idx files mai | where file_name == main.rs | length") + .expect_value_eq(1) + }, + ) +} + #[test] #[serial] fn idx_dirs_returns_records_with_full_path() -> Result { @@ -79,6 +179,27 @@ fn idx_dirs_returns_records_with_full_path() -> Result { ) } +#[test] +#[serial] +fn idx_dirs_optional_query_filters_results() -> Result { + Playground::setup( + "idx_dirs_optional_query_filters_results", + |dirs, sandbox| { + sandbox.mkdir("src/components"); + sandbox.mkdir("tests/fixtures"); + sandbox.with_files(&[ + EmptyFile("src/components/widget.nu"), + EmptyFile("tests/fixtures/spec.nu"), + ]); + + test() + .cwd(dirs.test()) + .run("idx init . --wait; idx dirs comp | get relative_path | any {|path| ($path | str contains 'src/components') or ($path | str contains 'src\\components') }") + .expect_value_eq(true) + }, + ) +} + #[test] #[serial] fn idx_find_defaults_to_files_and_dirs() -> Result { @@ -117,6 +238,90 @@ fn idx_export_and_import_roundtrip() -> Result { }) } +#[test] +#[serial] +fn idx_import_auto_initializes_runtime_for_queries() -> Result { + Playground::setup( + "idx_import_auto_initializes_runtime_for_queries", + |dirs, sandbox| { + sandbox.with_files(&[ + FileWithContent("searchable.txt", "hello from idx import"), + FileWithContent("other.txt", "unrelated"), + ]); + + test() + .cwd(dirs.test()) + .run("idx init . --wait; idx export snapshot.db | get stored") + .expect_value_eq(true)?; + + test() + .cwd(dirs.test()) + .run("idx drop | get dropped") + .expect_value_eq(true)?; + + test() + .cwd(dirs.test()) + .run("idx import snapshot.db; idx files searchable | where file_name == searchable.txt | length") + .expect_value_eq(1) + }, + ) +} + +#[test] +#[serial] +fn idx_import_restores_queryable_snapshot_when_files_are_gone() -> Result { + Playground::setup( + "idx_import_restores_queryable_snapshot_when_files_are_gone", + |dirs, sandbox| { + sandbox.with_files(&[ + FileWithContent("searchable.txt", "hello from idx import"), + FileWithContent("other.txt", "unrelated"), + ]); + + test() + .cwd(dirs.test()) + .run("idx init . --wait; idx export snapshot.db | get stored") + .expect_value_eq(true)?; + + test() + .cwd(dirs.test()) + .run("idx drop | get dropped") + .expect_value_eq(true)?; + + test() + .cwd(dirs.test()) + .run("rm searchable.txt other.txt; idx import snapshot.db; idx files searchable | where file_name == searchable.txt | length") + .expect_value_eq(1) + }, + ) +} + +#[test] +#[serial] +fn idx_search_works_on_imported_snapshot() -> Result { + Playground::setup("idx_search_works_on_imported_snapshot", |dirs, sandbox| { + sandbox.with_files(&[ + FileWithContent("searchable.txt", "hello from idx import"), + FileWithContent("other.txt", "unrelated content"), + ]); + + test() + .cwd(dirs.test()) + .run("idx init . --wait; idx export snapshot.db | get stored") + .expect_value_eq(true)?; + + test() + .cwd(dirs.test()) + .run("idx drop | get dropped") + .expect_value_eq(true)?; + + test() + .cwd(dirs.test()) + .run("idx import snapshot.db; idx search hello | where path == searchable.txt | length") + .expect_value_eq(1) + }) +} + #[test] #[serial] fn idx_search_finds_content() -> Result { diff --git a/crates/nu-command/tests/format_conversions/yaml.rs b/crates/nu-command/tests/format_conversions/yaml.rs index bde79a16ef6b2..358873beaf05f 100644 --- a/crates/nu-command/tests/format_conversions/yaml.rs +++ b/crates/nu-command/tests/format_conversions/yaml.rs @@ -79,14 +79,100 @@ fn convert_issue_16072_strings_are_quoted_in_output() -> Result { | to yaml "#; - test().run(code).expect_value_eq( - "value: 'off'\npath: '/dev/stdout'\nlisten: '0.0.0.0:8444,0.0.0.0:8445 ssl'\n", - ) + test() + .run(code) + .expect_value_eq("value: 'off'\npath: /dev/stdout\nlisten: 0.0.0.0:8444,0.0.0.0:8445 ssl\n") } #[test] fn convert_strings_with_colons_are_not_corrupted() -> Result { let code = "{addr: 'on:80'} | to yaml"; - test().run(code).expect_value_eq("addr: 'on:80'\n") + test().run(code).expect_value_eq("addr: on:80\n") +} + +#[test] +fn convert_multiline_string_uses_literal_block_scalar() -> Result { + let code = "{string: \"Hello\\nworld\"} | to yaml"; + + test() + .run(code) + .expect_value_eq("string: |-\n Hello\n world\n") +} + +#[test] +fn convert_multiline_sequence_item_uses_literal_block_scalar() -> Result { + let code = "[\"Hello\\nworld\"] | to yaml"; + + test().run(code).expect_value_eq("- |-\n Hello\n world\n") +} + +#[test] +fn convert_multiline_string_uses_chomping_indicators() -> Result { + test() + .run("{string: \"Hello\\nworld\"} | to yaml") + .expect_value_eq("string: |-\n Hello\n world\n")?; + + test() + .run("{string: \"Hello\\nworld\\n\"} | to yaml") + .expect_value_eq("string: |\n Hello\n world\n")?; + + test() + .run("{string: \"Hello\\nworld\\n\\n\"} | to yaml") + .expect_value_eq("string: |+\n Hello\n world\n \n") +} + +#[test] +fn convert_multiline_string_normalizes_crlf() -> Result { + let code = "{string: \"Hello\\r\\nworld\"} | to yaml"; + + test() + .run(code) + .expect_value_eq("string: |-\n Hello\n world\n") +} + +#[test] +fn multiline_string_roundtrips_through_yaml() -> Result { + let code = "{text: \"foo\\nbar\\n\\n\"} | to yaml | from yaml | get text"; + + test().run(code).expect_value_eq("foo\nbar\n\n") +} + +#[test] +fn convert_plain_strings_are_not_quoted_when_not_required() -> Result { + let code = r#" + '{"name":"kong","kind":"Deployment","env":"KONG_DATABASE","path":"/dev/stdout","addr":"on:80","hash":"abc#def"}' + | from json + | to yaml + "#; + + test().run(code).expect_value_eq( + "name: kong\nkind: Deployment\nenv: KONG_DATABASE\npath: /dev/stdout\naddr: on:80\nhash: abc#def\n", + ) +} + +#[test] +fn convert_strings_are_quoted_when_required_for_plain_scalars() -> Result { + let code = r#" + '["off","true","null","0","1.5","0x1","0o7",".inf",".nan","a: b","a #b","- x","? x",": x","[x","{x"," foo","foo "]' + | from json + | to yaml + "#; + + test().run(code).expect_value_eq( + "- 'off'\n- 'true'\n- 'null'\n- '0'\n- '1.5'\n- '0x1'\n- '0o7'\n- '.inf'\n- '.nan'\n- 'a: b'\n- 'a #b'\n- '- x'\n- '? x'\n- ': x'\n- '[x'\n- '{x'\n- ' foo'\n- 'foo '\n", + ) +} + +#[test] +fn convert_keys_are_quoted_only_when_required() -> Result { + let code = r#" + '{"kong":"ok","true":"bool-like","0":"numeric-like","a:b":"colon","a b":"space","abc#def":"hash-no-space","a: b":"colon-space","a #b":"hash-with-space"}' + | from json + | to yaml + "#; + + test().run(code).expect_value_eq( + "kong: ok\n'true': bool-like\n'0': numeric-like\na:b: colon\na b: space\nabc#def: hash-no-space\n'a: b': colon-space\n'a #b': hash-with-space\n", + ) } diff --git a/crates/nu-derive-value/Cargo.toml b/crates/nu-derive-value/Cargo.toml index b8b8e7111fe67..4ca0d5577167c 100644 --- a/crates/nu-derive-value/Cargo.toml +++ b/crates/nu-derive-value/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Macros implementation of #[derive(FromValue, IntoValue)]" edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-derive-value" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-derive-value" rust-version.workspace = true -version = "0.113.0" +version.workspace = true [lib] proc-macro = true diff --git a/crates/nu-engine/Cargo.toml b/crates/nu-engine/Cargo.toml index 3524c4bdc3e10..29ed01f7d385d 100644 --- a/crates/nu-engine/Cargo.toml +++ b/crates/nu-engine/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell's evaluation engine" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-engine" edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-engine" rust-version.workspace = true -version = "0.113.0" +version.workspace = true [lib] bench = false @@ -15,11 +15,11 @@ bench = false workspace = true [dependencies] -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } -nu-experimental = { path = "../nu-experimental", version = "0.113.0" } -nu-path = { path = "../nu-path", version = "0.113.0" } -nu-glob = { path = "../nu-glob", version = "0.113.0" } -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } +nu-protocol.workspace = true +nu-experimental.workspace = true +nu-path.workspace = true +nu-glob.workspace = true +nu-utils.workspace = true fancy-regex = { workspace = true } log = { workspace = true } diff --git a/crates/nu-experimental/Cargo.toml b/crates/nu-experimental/Cargo.toml index 773a354e1c422..848092b1f5edb 100644 --- a/crates/nu-experimental/Cargo.toml +++ b/crates/nu-experimental/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell experimental options" edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-experimental" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-experimental" rust-version.workspace = true -version = "0.113.0" +version.workspace = true [dependencies] itertools.workspace = true diff --git a/crates/nu-explore/Cargo.toml b/crates/nu-explore/Cargo.toml index 6272f9942150b..24a00e054a04b 100644 --- a/crates/nu-explore/Cargo.toml +++ b/crates/nu-explore/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell table pager" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-explore" edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-explore" rust-version.workspace = true -version = "0.113.0" +version.workspace = true [lib] bench = false @@ -15,16 +15,16 @@ bench = false workspace = true [dependencies] -nu-protocol = { path = "../nu-protocol", version = "0.113.0" } -nu-parser = { path = "../nu-parser", version = "0.113.0" } -nu-path = { path = "../nu-path", version = "0.113.0" } -nu-color-config = { path = "../nu-color-config", version = "0.113.0" } -nu-engine = { path = "../nu-engine", version = "0.113.0" } -nu-table = { path = "../nu-table", version = "0.113.0" } -nu-json = { path = "../nu-json", version = "0.113.0" } -nu-utils = { path = "../nu-utils", version = "0.113.0" } -nu-ansi-term = { workspace = true } -nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.113.0" } +nu-protocol = { workspace = true, features = ["os"] } +nu-path.workspace = true +nu-parser.workspace = true +nu-color-config.workspace = true +nu-engine = { workspace = true, features = ["os"] } +nu-table.workspace = true +nu-json.workspace = true +nu-utils.workspace = true +nu-ansi-term.workspace = true +nu-pretty-hex.workspace = true ansi-str = { workspace = true } anyhow = { workspace = true } diff --git a/crates/nu-glob/Cargo.toml b/crates/nu-glob/Cargo.toml index ee9f8ff4176fc..ae9b4728f96f5 100644 --- a/crates/nu-glob/Cargo.toml +++ b/crates/nu-glob/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nu-glob" -version = "0.113.0" +version.workspace = true authors = ["The Nushell Project Developers", "The Rust Project Developers"] license = "MIT/Apache-2.0" description = """ diff --git a/crates/nu-heavy-utils/Cargo.toml b/crates/nu-heavy-utils/Cargo.toml index 82b4bf2265ad9..2a8f9e1fc8d5b 100644 --- a/crates/nu-heavy-utils/Cargo.toml +++ b/crates/nu-heavy-utils/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "nu-heavy-utils" description = "Nushell utility types and functions with heavier dependencies" -authors = ["The Nushell Project Developers"] -license = "MIT" +authors.workspace = true +license.workspace = true repository = "https://github.com/nushell/nushell/tree/main/crates/nu-heavy-utils" -version = "0.113.0" +version.workspace = true edition.workspace = true rust-version.workspace = true autotests = false @@ -17,7 +17,7 @@ harness = false workspace = true [dependencies] -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } +nu-protocol.workspace = true [dev-dependencies] -nu-test-support = { path = "../nu-test-support" } +nu-test-support.workspace = true diff --git a/crates/nu-json/Cargo.toml b/crates/nu-json/Cargo.toml index ca90a837796f4..72862d9d086ca 100644 --- a/crates/nu-json/Cargo.toml +++ b/crates/nu-json/Cargo.toml @@ -7,9 +7,9 @@ description = "Fork of serde-hjson" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-json" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-json" -version = "0.113.0" +version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -17,12 +17,12 @@ version = "0.113.0" bench = false [features] -preserve_order = ["linked-hash-map", "linked-hash-map/serde_impl"] +preserve_order = ["linked-hash-map", "linked-hash-map/serde_impl", "serde_json/preserve_order"] default = ["preserve_order"] [dependencies] -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false, optional = true } +nu-utils.workspace = true +nu-protocol = { workspace = true, optional = true } linked-hash-map = { version = "0.5", optional = true } num-traits = { workspace = true } @@ -30,8 +30,8 @@ serde = { workspace = true } serde_json = { workspace = true } [dev-dependencies] -nu-test-support = { path = "../nu-test-support" } -nu-path = { path = "../nu-path" } +nu-test-support.workspace = true +nu-path.workspace = true serde_json = "1.0" fancy-regex = "0.18.0" diff --git a/crates/nu-lsp/Cargo.toml b/crates/nu-lsp/Cargo.toml index 0bb3c13b27d92..ce8907ea764b8 100644 --- a/crates/nu-lsp/Cargo.toml +++ b/crates/nu-lsp/Cargo.toml @@ -1,19 +1,19 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell's integrated LSP server" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-lsp" name = "nu-lsp" -version = "0.113.0" +version.workspace = true edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true [dependencies] -nu-cli = { path = "../nu-cli", version = "0.113.0" } -nu-glob = { path = "../nu-glob", version = "0.113.0" } -nu-parser = { path = "../nu-parser", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0" } -nu-utils = { path = "../nu-utils", version = "0.113.0" } +nu-cli.workspace = true +nu-glob.workspace = true +nu-parser.workspace = true +nu-protocol.workspace = true +nu-utils.workspace = true crossbeam-channel = { workspace = true } fancy-regex = { workspace = true } @@ -28,11 +28,11 @@ serde_json = { workspace = true } url = { workspace = true } [dev-dependencies] -nu-cmd-lang = { path = "../nu-cmd-lang" } -nu-command = { path = "../nu-command" } -nu-engine = { path = "../nu-engine" } -nu-std = { path = "../nu-std" } -nu-test-support = { path = "../nu-test-support" } +nu-cmd-lang = { workspace = true, features = ["os"] } +nu-command = { workspace = true, features = ["os"] } +nu-engine.workspace = true +nu-std.workspace = true +nu-test-support.workspace = true assert-json-diff = "2.0" rstest = { workspace = true, default-features = false } diff --git a/crates/nu-mcp/Cargo.toml b/crates/nu-mcp/Cargo.toml index 22be892966a04..2b456b9161c11 100644 --- a/crates/nu-mcp/Cargo.toml +++ b/crates/nu-mcp/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "nu-mcp" -version = "0.113.0" +version.workspace = true edition.workspace = true rust-version.workspace = true -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Modules to run a model context protocol (MCP) server that provides Nushell as a tool." repository = "https://github.com/nushell/nushell/tree/main/crates/nu-mcp" homepage = "https://www.nushell.sh" -license = "MIT" +license.workspace = true [target.'cfg(unix)'.dependencies] nix = { workspace = true, features = ["process"] } @@ -15,10 +15,10 @@ nix = { workspace = true, features = ["process"] } [dependencies] futures = "0.3.31" miette = { workspace = true } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", features = ["plugin"] } -nu-engine = { path = "../nu-engine", version = "0.113.0" } -nu-parser = { path = "../nu-parser", version = "0.113.0" } -nuon = { path = "../nuon", version = "0.113.0" } +nu-protocol = { workspace = true, features = ["plugin"] } +nu-engine = { workspace = true, features = ["plugin"] } +nu-parser.workspace = true +nuon.workspace = true rmcp = { version = "1.7.0", features = ["server", "transport-io", "schemars", "transport-streamable-http-server"] } hyper-util = { version = "0.1", features = ["tokio", "server-auto", "service"] } @@ -41,4 +41,4 @@ mcp = [] workspace = true [dev-dependencies] -nu-cmd-lang = { path = "../nu-cmd-lang" } +nu-cmd-lang = { workspace = true, features = ["os"] } diff --git a/crates/nu-parser/Cargo.toml b/crates/nu-parser/Cargo.toml index 42d5e52fdffc8..d5b47f2ee0c97 100644 --- a/crates/nu-parser/Cargo.toml +++ b/crates/nu-parser/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell's parser" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-parser" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-parser" -version = "0.113.0" +version.workspace = true exclude = ["/fuzz"] [lib] @@ -16,12 +16,12 @@ bench = false workspace = true [dependencies] -nu-engine = { path = "../nu-engine", version = "0.113.0", default-features = false } -nu-path = { path = "../nu-path", version = "0.113.0" } -nu-plugin-engine = { path = "../nu-plugin-engine", optional = true, version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } -nu-experimental = { path = "../nu-experimental", version = "0.113.0" } +nu-engine.workspace = true +nu-path.workspace = true +nu-plugin-engine = { workspace = true, optional = true } +nu-protocol.workspace = true +nu-utils.workspace = true +nu-experimental.workspace = true bytesize = { workspace = true } chrono = { default-features = false, features = ['std'], workspace = true } @@ -33,4 +33,4 @@ serde_json = { workspace = true } rstest = { workspace = true, default-features = false } [features] -plugin = ["nu-plugin-engine"] +plugin = ["nu-plugin-engine", "nu-engine/plugin"] diff --git a/crates/nu-parser/fuzz/Cargo.toml b/crates/nu-parser/fuzz/Cargo.toml index 1bea5cde10b54..6ade1db961ee5 100644 --- a/crates/nu-parser/fuzz/Cargo.toml +++ b/crates/nu-parser/fuzz/Cargo.toml @@ -9,8 +9,8 @@ cargo-fuzz = true [dependencies] libfuzzer-sys = "0.4" -nu-protocol = { path = "../../nu-protocol" } -nu-cmd-lang = { path = "../../nu-cmd-lang" } +nu-protocol.path = "../../nu-protocol" +nu-cmd-lang.path = "../../nu-cmd-lang" [dependencies.nu-parser] diff --git a/crates/nu-path/Cargo.toml b/crates/nu-path/Cargo.toml index 4614f9400d9bd..224224cd67061 100644 --- a/crates/nu-path/Cargo.toml +++ b/crates/nu-path/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Path handling library for Nushell" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-path" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-path" -version = "0.113.0" +version.workspace = true exclude = ["/fuzz"] [lib] diff --git a/crates/nu-plugin-core/Cargo.toml b/crates/nu-plugin-core/Cargo.toml index 828fe121bab10..707882f446222 100644 --- a/crates/nu-plugin-core/Cargo.toml +++ b/crates/nu-plugin-core/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Shared internal functionality to support Nushell plugins" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin-core" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-plugin-core" -version = "0.113.0" +version.workspace = true [lib] bench = false @@ -15,9 +15,9 @@ bench = false workspace = true [dependencies] -nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.113.0", default-features = false } -nu-protocol = { path = "../nu-protocol", version = "0.113.0" } -nu-utils = { path = "../nu-utils", version = "0.113.0" } +nu-plugin-protocol.workspace = true +nu-protocol.workspace = true +nu-utils.workspace = true rmp-serde = { workspace = true } serde = { workspace = true } diff --git a/crates/nu-plugin-engine/Cargo.toml b/crates/nu-plugin-engine/Cargo.toml index 03004779d719f..2a70c52b86e2a 100644 --- a/crates/nu-plugin-engine/Cargo.toml +++ b/crates/nu-plugin-engine/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Functionality for running Nushell plugins from a Nushell engine" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin-engine" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-plugin-engine" -version = "0.113.0" +version.workspace = true [lib] bench = false @@ -15,12 +15,12 @@ bench = false workspace = true [dependencies] -nu-engine = { path = "../nu-engine", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0" } -nu-system = { path = "../nu-system", version = "0.113.0" } -nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.113.0" } -nu-plugin-core = { path = "../nu-plugin-core", version = "0.113.0", default-features = false } -nu-utils = { path = "../nu-utils", version = "0.113.0" } +nu-engine = { workspace = true, features = ["plugin"] } +nu-protocol.workspace = true +nu-system.workspace = true +nu-plugin-protocol.workspace = true +nu-plugin-core.workspace = true +nu-utils.workspace = true serde = { workspace = true } log = { workspace = true } diff --git a/crates/nu-plugin-protocol/Cargo.toml b/crates/nu-plugin-protocol/Cargo.toml index 6b555c9d8c230..5cb5cfcd3e017 100644 --- a/crates/nu-plugin-protocol/Cargo.toml +++ b/crates/nu-plugin-protocol/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Protocol type definitions for Nushell plugins" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin-protocol" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-plugin-protocol" -version = "0.113.0" +version.workspace = true [lib] bench = false @@ -15,8 +15,8 @@ bench = false workspace = true [dependencies] -nu-protocol = { path = "../nu-protocol", version = "0.113.0", features = ["plugin"] } -nu-utils = { path = "../nu-utils", version = "0.113.0" } +nu-protocol = { workspace = true, features = ["plugin"] } +nu-utils.workspace = true rmp-serde = { workspace = true } serde = { workspace = true, features = ["derive"] } diff --git a/crates/nu-plugin-test-support/Cargo.toml b/crates/nu-plugin-test-support/Cargo.toml index 62c5875e83dbf..482a7adb508de 100644 --- a/crates/nu-plugin-test-support/Cargo.toml +++ b/crates/nu-plugin-test-support/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "nu-plugin-test-support" -version = "0.113.0" +version.workspace = true edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true description = "Testing support for Nushell plugins" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin-test-support" @@ -16,15 +16,15 @@ workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -nu-engine = { path = "../nu-engine", version = "0.113.0", features = ["plugin"] } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", features = ["plugin"] } -nu-parser = { path = "../nu-parser", version = "0.113.0", features = ["plugin"] } -nu-plugin = { path = "../nu-plugin", version = "0.113.0" } -nu-plugin-core = { path = "../nu-plugin-core", version = "0.113.0" } -nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.113.0" } -nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.113.0" } -nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.113.0" } -nu-ansi-term = { workspace = true } +nu-engine = { workspace = true, features = ["plugin"] } +nu-protocol = { workspace = true, features = ["plugin"] } +nu-parser = { workspace = true, features = ["plugin"] } +nu-plugin.workspace = true +nu-plugin-core.workspace = true +nu-plugin-engine.workspace = true +nu-plugin-protocol.workspace = true +nu-cmd-lang = { workspace = true, features = ["plugin"] } +nu-ansi-term.workspace = true similar = "3.1" [dev-dependencies] diff --git a/crates/nu-plugin/Cargo.toml b/crates/nu-plugin/Cargo.toml index f167aeee2f17c..38f59ba5d51db 100644 --- a/crates/nu-plugin/Cargo.toml +++ b/crates/nu-plugin/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Functionality for building Nushell plugins" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-plugin" -version = "0.113.0" +version.workspace = true [lib] bench = false @@ -15,11 +15,11 @@ bench = false workspace = true [dependencies] -nu-engine = { path = "../nu-engine", version = "0.113.0", features = ["plugin"] } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", features = ["plugin"] } -nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.113.0" } -nu-plugin-core = { path = "../nu-plugin-core", version = "0.113.0", default-features = false } -nu-utils = { path = "../nu-utils", version = "0.113.0" } +nu-engine = { workspace = true, features = ["plugin"] } +nu-protocol = { workspace = true, features = ["plugin"] } +nu-plugin-protocol.workspace = true +nu-plugin-core.workspace = true +nu-utils.workspace = true log = { workspace = true } thiserror = "2.0.18" diff --git a/crates/nu-pretty-hex/Cargo.toml b/crates/nu-pretty-hex/Cargo.toml index 7f280e32d45bf..136e607e8bd0b 100644 --- a/crates/nu-pretty-hex/Cargo.toml +++ b/crates/nu-pretty-hex/Cargo.toml @@ -4,9 +4,9 @@ description = "Pretty hex dump of bytes slice in the common style." repository = "https://github.com/nushell/nushell/tree/main/crates/nu-pretty-hex" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-pretty-hex" -version = "0.113.0" +version.workspace = true [lib] doctest = false @@ -18,7 +18,7 @@ bench = false workspace = true [dependencies] -nu-ansi-term = { workspace = true } +nu-ansi-term.workspace = true [dev-dependencies] heapless = { version = "0.9", default-features = false } diff --git a/crates/nu-protocol/Cargo.toml b/crates/nu-protocol/Cargo.toml index e32961e6a39c1..9114f9364ab98 100644 --- a/crates/nu-protocol/Cargo.toml +++ b/crates/nu-protocol/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell's internal protocols, including its abstract syntax tree" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-protocol" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-protocol" -version = "0.113.0" +version.workspace = true autotests = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -24,12 +24,12 @@ harness = false workspace = true [dependencies] -nu-derive-value = { path = "../nu-derive-value", version = "0.113.0" } -nu-glob = { path = "../nu-glob", version = "0.113.0" } -nu-path = { path = "../nu-path", version = "0.113.0" } -nu-system = { path = "../nu-system", version = "0.113.0" } -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } -nu-experimental = { path = "../nu-experimental", version = "0.113.0" } +nu-derive-value.workspace = true +nu-glob.workspace = true +nu-path.workspace = true +nu-system.workspace = true +nu-utils.workspace = true +nu-experimental.workspace = true brotli = { workspace = true, optional = true } bytes = { workspace = true } @@ -79,8 +79,8 @@ plugin = [ sqlite = [] [dev-dependencies] -nu-test-support = { path = "../nu-test-support", features = ["os"] } -nu-utils = { path = "../nu-utils" } +nu-test-support = { workspace = true, features = ["os"] } +nu-utils.workspace = true serde_json = { workspace = true } pretty_assertions = { workspace = true } diff --git a/crates/nu-std/Cargo.toml b/crates/nu-std/Cargo.toml index 59f0f96f7476e..8bf63a6751c6f 100644 --- a/crates/nu-std/Cargo.toml +++ b/crates/nu-std/Cargo.toml @@ -1,17 +1,17 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "The standard library of Nushell" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-std" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-std" -version = "0.113.0" +version.workspace = true [dependencies] -nu-parser = { version = "0.113.0", path = "../nu-parser" } -nu-protocol = { version = "0.113.0", path = "../nu-protocol", default-features = false } -nu-engine = { version = "0.113.0", path = "../nu-engine", default-features = false } +nu-parser.workspace = true +nu-protocol.workspace = true +nu-engine.workspace = true miette = { workspace = true, features = ["fancy-no-backtrace"] } log = "0.4" diff --git a/crates/nu-system/Cargo.toml b/crates/nu-system/Cargo.toml index b81aa96f91fd4..45788432b275f 100644 --- a/crates/nu-system/Cargo.toml +++ b/crates/nu-system/Cargo.toml @@ -3,10 +3,10 @@ authors = ["The Nushell Project Developers", "procs creators"] description = "Nushell system querying" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-system" name = "nu-system" -version = "0.113.0" +version.workspace = true edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -17,7 +17,7 @@ bench = false workspace = true [dependencies] -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } +nu-utils.workspace = true libc = { workspace = true } log = { workspace = true } diff --git a/crates/nu-table/Cargo.toml b/crates/nu-table/Cargo.toml index fbe13600c7339..bc1f5283ca105 100644 --- a/crates/nu-table/Cargo.toml +++ b/crates/nu-table/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell table printing" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-table" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-table" -version = "0.113.0" +version.workspace = true [lib] bench = false @@ -15,10 +15,10 @@ bench = false workspace = true [dependencies] -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } -nu-engine = { path = "../nu-engine", version = "0.113.0", default-features = false } -nu-color-config = { path = "../nu-color-config", version = "0.113.0" } +nu-protocol.workspace = true +nu-utils.workspace = true +nu-engine.workspace = true +nu-color-config.workspace = true nu-ansi-term = { workspace = true } fancy-regex = { workspace = true } tabled = { workspace = true, features = ["ansi"], default-features = false } diff --git a/crates/nu-term-grid/Cargo.toml b/crates/nu-term-grid/Cargo.toml index 38a4e3df526f0..dc8b269e293f2 100644 --- a/crates/nu-term-grid/Cargo.toml +++ b/crates/nu-term-grid/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell grid printing" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-term-grid" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-term-grid" -version = "0.113.0" +version.workspace = true [lib] bench = false @@ -15,6 +15,6 @@ bench = false workspace = true [dependencies] -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } +nu-utils.workspace = true unicode-width = { workspace = true } diff --git a/crates/nu-test-support-macros/Cargo.toml b/crates/nu-test-support-macros/Cargo.toml index 52c37c22646ef..19a2658ffb4b3 100644 --- a/crates/nu-test-support-macros/Cargo.toml +++ b/crates/nu-test-support-macros/Cargo.toml @@ -1,21 +1,21 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Macros for nu-test-support" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-test-support-macros" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-test-support-macros" -version = "0.113.0" +version.workspace = true [lib] proc-macro = true [dependencies] -nu-experimental = { path = "../nu-experimental", version = "0.113.0" } +nu-experimental.workspace = true heck = { workspace = true } proc-macro-error2 = { workspace = true } proc-macro2 = { workspace = true } quote = { workspace = true } -syn = { workspace = true, features = ["full"] } \ No newline at end of file +syn = { workspace = true, features = ["full"] } diff --git a/crates/nu-test-support/Cargo.toml b/crates/nu-test-support/Cargo.toml index 99f917fa58e20..fb44010e81258 100644 --- a/crates/nu-test-support/Cargo.toml +++ b/crates/nu-test-support/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Support for writing Nushell tests" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-test-support" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu-test-support" -version = "0.113.0" +version.workspace = true [lib] doctest = false @@ -27,18 +27,18 @@ network = ["nu-command/network"] rustls-tls = ["nu-command/rustls-tls"] [dependencies] -nu-cmd-extra = { path = "../nu-cmd-extra", version = "0.113.0", default-features = false } -nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.113.0", default-features = false } -nu-command = { path = "../nu-command", version = "0.113.0", default-features = false } -nu-engine = { path = "../nu-engine", version = "0.113.0", default-features = false } -nu-experimental = { path = "../nu-experimental", version = "0.113.0", default-features = false } -nu-glob = { path = "../nu-glob", version = "0.113.0", default-features = false } -nu-parser = { path = "../nu-parser", version = "0.113.0", default-features = false } -nu-path = { path = "../nu-path", version = "0.113.0", default-features = false } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } -nu-std = { path = "../nu-std", version = "0.113.0", default-features = false } -nu-test-support-macros = { path = "../nu-test-support-macros", version = "0.113.0", default-features = false } -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } +nu-cmd-extra.workspace = true +nu-cmd-lang.workspace = true +nu-command.workspace = true +nu-engine.workspace = true +nu-experimental.workspace = true +nu-glob.workspace = true +nu-parser.workspace = true +nu-path.workspace = true +nu-protocol.workspace = true +nu-std.workspace = true +nu-test-support-macros.workspace = true +nu-utils.workspace = true derive_more = { workspace = true } itertools = { workspace = true } @@ -54,8 +54,8 @@ which = { workspace = true } [dev-dependencies] # doc tests use the "os" feature of `nu-command` -nu-cmd-lang = { path = "../nu-cmd-lang", features = ["default"] } -nu-command = { path = "../nu-command", features = ["default"] } +nu-cmd-lang = { workspace = true, features = ["default"] } +nu-command = { workspace = true, features = ["default"] } bytes = { workspace = true } rstest = { workspace = true } diff --git a/crates/nu-utils/Cargo.toml b/crates/nu-utils/Cargo.toml index 85a70efcd0b80..bed3ecbeb5d15 100644 --- a/crates/nu-utils/Cargo.toml +++ b/crates/nu-utils/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell utility functions" edition.workspace = true -license = "MIT" +license.workspace = true name = "nu-utils" repository = "https://github.com/nushell/nushell/tree/main/crates/nu-utils" rust-version.workspace = true -version = "0.113.0" +version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [[bin]] diff --git a/crates/nu-utils/src/default_files/default_config.nu b/crates/nu-utils/src/default_files/default_config.nu index 8c51abd44e9b1..aba6625b8cd85 100644 --- a/crates/nu-utils/src/default_files/default_config.nu +++ b/crates/nu-utils/src/default_files/default_config.nu @@ -1,6 +1,6 @@ # Nushell Config File # -# version = "0.113.0" +# version = "0.113.1" $env.config.color_config = { separator: default leading_trailing_space_bg: { attr: n } diff --git a/crates/nu-utils/src/default_files/default_env.nu b/crates/nu-utils/src/default_files/default_env.nu index a16d713f7624c..522f1dedf6950 100644 --- a/crates/nu-utils/src/default_files/default_env.nu +++ b/crates/nu-utils/src/default_files/default_env.nu @@ -1,7 +1,7 @@ # Default Nushell Environment Config File # These "sensible defaults" are set before the user's `env.nu` is loaded # -# version = "0.113.0" +# version = "0.113.1" $env.PROMPT_COMMAND = {|| let dir = match (do -i { $env.PWD | path relative-to $nu.home-dir }) { @@ -33,4 +33,4 @@ $env.PROMPT_COMMAND_RIGHT = {|| } else { "" } ([$last_exit_code, (char space), $time_segment] | str join) -} \ No newline at end of file +} diff --git a/crates/nu-utils/src/default_files/doc_config.nu b/crates/nu-utils/src/default_files/doc_config.nu index 20e5f91bb51ac..a7bf60d20894d 100644 --- a/crates/nu-utils/src/default_files/doc_config.nu +++ b/crates/nu-utils/src/default_files/doc_config.nu @@ -3,7 +3,7 @@ # Warning: This file is intended for documentation purposes only and # is not intended to be used as an actual configuration file as-is. # -# version = "0.113.0" +# version = "0.113.1" # # A `config.nu` file is used to override default Nushell settings, # define (or import) custom commands, or run any other startup tasks. diff --git a/crates/nu-utils/src/default_files/doc_env.nu b/crates/nu-utils/src/default_files/doc_env.nu index 1dfdbefa2f1e7..58870d63ee101 100644 --- a/crates/nu-utils/src/default_files/doc_env.nu +++ b/crates/nu-utils/src/default_files/doc_env.nu @@ -1,6 +1,6 @@ # Nushell Environment Config File Documentation # -# version = "0.113.0" +# version = "0.113.1" # # Previously, environment variables were typically configured in `env.nu`. # In general, most configuration can and should be performed in `config.nu` @@ -8,4 +8,4 @@ # To pretty-print the in-shell documentation for Nushell's various configuration # settings, you can run: -config nu --doc | nu-highlight | less -R \ No newline at end of file +config nu --doc | nu-highlight | less -R diff --git a/crates/nu-utils/src/default_files/scaffold_config.nu b/crates/nu-utils/src/default_files/scaffold_config.nu index 2be44a302c6cc..009bfce2aef26 100644 --- a/crates/nu-utils/src/default_files/scaffold_config.nu +++ b/crates/nu-utils/src/default_files/scaffold_config.nu @@ -1,7 +1,7 @@ # config.nu # # Installed by: -# version = "0.113.0" +# version = "0.113.1" # # This file is used to override default Nushell settings, define # (or import) custom commands, or run any other startup tasks. diff --git a/crates/nu-utils/src/default_files/scaffold_env.nu b/crates/nu-utils/src/default_files/scaffold_env.nu index 80712a48482a5..33b5717958fa6 100644 --- a/crates/nu-utils/src/default_files/scaffold_env.nu +++ b/crates/nu-utils/src/default_files/scaffold_env.nu @@ -1,7 +1,7 @@ # env.nu # # Installed by: -# version = "0.113.0" +# version = "0.113.1" # # Previously, environment variables were typically configured in `env.nu`. # In general, most configuration can and should be performed in `config.nu` @@ -15,4 +15,4 @@ # Also see `help config env` for more options. # # You can remove these comments if you want or leave -# them for future reference. \ No newline at end of file +# them for future reference. diff --git a/crates/nu_plugin_custom_values/Cargo.toml b/crates/nu_plugin_custom_values/Cargo.toml index 666074fc57ffd..75d092ffdcd3f 100644 --- a/crates/nu_plugin_custom_values/Cargo.toml +++ b/crates/nu_plugin_custom_values/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nu_plugin_custom_values" repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_custom_values" -version = "0.1.0" +version.workspace = true edition.workspace = true rust-version.workspace = true publish = false @@ -15,10 +15,10 @@ bench = false workspace = true [dependencies] -nu-plugin = { path = "../nu-plugin", version = "0.113.0", features = [] } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", features = ["plugin"] } +nu-plugin = { workspace = true, features = [] } +nu-protocol = { workspace = true, features = ["plugin"] } serde = { workspace = true } typetag = "0.2" [dev-dependencies] -nu-plugin-test-support = { path = "../nu-plugin-test-support" } +nu-plugin-test-support.workspace = true diff --git a/crates/nu_plugin_example/Cargo.toml b/crates/nu_plugin_example/Cargo.toml index 2e28f966824fa..f8474f664e2f5 100644 --- a/crates/nu_plugin_example/Cargo.toml +++ b/crates/nu_plugin_example/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "A version incrementer plugin for Nushell" repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_example" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu_plugin_example" -version = "0.113.0" +version.workspace = true publish = false [[bin]] @@ -20,9 +20,9 @@ bench = false workspace = true [dependencies] -nu-plugin = { path = "../nu-plugin", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", features = ["plugin"] } +nu-plugin.workspace = true +nu-protocol = { workspace = true, features = ["plugin"] } [dev-dependencies] -nu-plugin-test-support = { path = "../nu-plugin-test-support" } -nu-cmd-lang = { path = "../nu-cmd-lang" } +nu-plugin-test-support.workspace = true +nu-cmd-lang.workspace = true diff --git a/crates/nu_plugin_formats/Cargo.toml b/crates/nu_plugin_formats/Cargo.toml index 0497a14142a3f..40fd5099db86c 100644 --- a/crates/nu_plugin_formats/Cargo.toml +++ b/crates/nu_plugin_formats/Cargo.toml @@ -1,20 +1,20 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "An I/O plugin for a set of file formats for Nushell" repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_formats" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu_plugin_formats" -version = "0.113.0" +version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lints] workspace = true [dependencies] -nu-plugin = { path = "../nu-plugin", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", features = ["plugin"] } +nu-plugin.workspace = true +nu-protocol = { workspace = true, features = ["plugin"] } indexmap = { workspace = true } eml-parser = "0.1" @@ -24,4 +24,4 @@ plist = "1.8" chrono = "0.4.41" # polars is requiring <= 0.4.41 [dev-dependencies] -nu-plugin-test-support = { path = "../nu-plugin-test-support" } +nu-plugin-test-support.workspace = true diff --git a/crates/nu_plugin_gstat/Cargo.toml b/crates/nu_plugin_gstat/Cargo.toml index 71a539e7fd774..9feeb018d3188 100644 --- a/crates/nu_plugin_gstat/Cargo.toml +++ b/crates/nu_plugin_gstat/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "A git status plugin for Nushell" repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_gstat" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu_plugin_gstat" -version = "0.113.0" +version.workspace = true [lib] doctest = false @@ -17,7 +17,7 @@ name = "nu_plugin_gstat" bench = false [dependencies] -nu-plugin = { path = "../nu-plugin", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0" } +nu-plugin.workspace = true +nu-protocol.workspace = true git2 = "0.20.4" diff --git a/crates/nu_plugin_inc/Cargo.toml b/crates/nu_plugin_inc/Cargo.toml index cffbb99f0f25b..c18168d18953c 100644 --- a/crates/nu_plugin_inc/Cargo.toml +++ b/crates/nu_plugin_inc/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "A version incrementer plugin for Nushell" repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_inc" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu_plugin_inc" -version = "0.113.0" +version.workspace = true [lib] doctest = false @@ -17,7 +17,7 @@ name = "nu_plugin_inc" bench = false [dependencies] -nu-plugin = { path = "../nu-plugin", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", features = ["plugin"] } +nu-plugin.workspace = true +nu-protocol = { workspace = true, features = ["plugin"] } semver = { workspace = true } diff --git a/crates/nu_plugin_nu_example/nu_plugin_nu_example.nu b/crates/nu_plugin_nu_example/nu_plugin_nu_example.nu index b405a1470d8cd..11448a4da01fc 100755 --- a/crates/nu_plugin_nu_example/nu_plugin_nu_example.nu +++ b/crates/nu_plugin_nu_example/nu_plugin_nu_example.nu @@ -6,7 +6,7 @@ # it also allows us to test the plugin interface with something manually implemented in a scripting # language without adding any extra dependencies to our tests. -const NUSHELL_VERSION = "0.113.0" +const NUSHELL_VERSION = "0.113.1" const PLUGIN_VERSION = "0.1.1" # bump if you change commands! def main [--stdio] { diff --git a/crates/nu_plugin_polars/Cargo.toml b/crates/nu_plugin_polars/Cargo.toml index 97429916910ba..de1e0b2b1bc31 100644 --- a/crates/nu_plugin_polars/Cargo.toml +++ b/crates/nu_plugin_polars/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Nushell dataframe plugin commands based on polars." edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu_plugin_polars" repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_polars" -version = "0.113.0" +version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -18,10 +18,10 @@ bench = false bench = false [dependencies] -nu-protocol = { path = "../nu-protocol", version = "0.113.0" } -nu-plugin = { path = "../nu-plugin", version = "0.113.0" } -nu-path = { path = "../nu-path", version = "0.113.0" } -nu-utils = { path = "../nu-utils", version = "0.113.0" } +nu-protocol.workspace = true +nu-plugin.workspace = true +nu-path.workspace = true +nu-utils.workspace = true # Potential dependencies for extras chrono = { workspace = true, features = [ @@ -106,10 +106,10 @@ optional = false version = "=0.53.0" [dev-dependencies] -nu-cmd-lang = { path = "../nu-cmd-lang" } -nu-engine = { path = "../nu-engine" } -nu-parser = { path = "../nu-parser" } -nu-command = { path = "../nu-command" } -nu-plugin-test-support = { path = "../nu-plugin-test-support" } +nu-cmd-lang = { workspace = true, features = ["plugin"] } +nu-engine = { workspace = true, features = ["plugin"] } +nu-parser = { workspace = true, features = ["plugin"] } +nu-command = { workspace = true, features = ["plugin"] } +nu-plugin-test-support.workspace = true tempfile.workspace = true diff --git a/crates/nu_plugin_python/nu_plugin_python_example.py b/crates/nu_plugin_python/nu_plugin_python_example.py index 1398b692718ac..6a69af252f6e9 100755 --- a/crates/nu_plugin_python/nu_plugin_python_example.py +++ b/crates/nu_plugin_python/nu_plugin_python_example.py @@ -27,7 +27,7 @@ import json -NUSHELL_VERSION = "0.113.0" +NUSHELL_VERSION = "0.113.1" PLUGIN_VERSION = "0.1.1" # bump if you change commands! @@ -265,4 +265,4 @@ def plugin(): if len(sys.argv) == 2 and sys.argv[1] == "--stdio": plugin() else: - print("Run me from inside nushell!") \ No newline at end of file + print("Run me from inside nushell!") diff --git a/crates/nu_plugin_query/Cargo.toml b/crates/nu_plugin_query/Cargo.toml index a0164485c7e2a..3353b20d0180a 100644 --- a/crates/nu_plugin_query/Cargo.toml +++ b/crates/nu_plugin_query/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "A Nushell plugin to query JSON, XML, and various web data" repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_query" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu_plugin_query" -version = "0.113.0" +version.workspace = true [lib] doctest = false @@ -17,8 +17,8 @@ name = "nu_plugin_query" bench = false [dependencies] -nu-plugin = { path = "../nu-plugin", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0" } +nu-plugin.workspace = true +nu-protocol.workspace = true gjson = "0.8.1" scraper = { default-features = false, version = "0.27" } diff --git a/crates/nu_plugin_stress_internals/Cargo.toml b/crates/nu_plugin_stress_internals/Cargo.toml index d61a756bdc1a0..40cab49afc67b 100644 --- a/crates/nu_plugin_stress_internals/Cargo.toml +++ b/crates/nu_plugin_stress_internals/Cargo.toml @@ -1,12 +1,12 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "A test plugin for Nushell to stress aspects of the internals" repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_stress_internals" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nu_plugin_stress_internals" -version = "0.113.0" +version.workspace = true publish = false [[bin]] diff --git a/crates/nuon/Cargo.toml b/crates/nuon/Cargo.toml index c546282b5dbdb..2107b777da2fa 100644 --- a/crates/nuon/Cargo.toml +++ b/crates/nuon/Cargo.toml @@ -1,20 +1,20 @@ [package] -authors = ["The Nushell Project Developers"] +authors.workspace = true description = "Support for the NUON format." repository = "https://github.com/nushell/nushell/tree/main/crates/nuon" edition.workspace = true rust-version.workspace = true -license = "MIT" +license.workspace = true name = "nuon" -version = "0.113.0" +version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -nu-parser = { path = "../nu-parser", version = "0.113.0" } -nu-protocol = { path = "../nu-protocol", version = "0.113.0", default-features = false } -nu-engine = { path = "../nu-engine", version = "0.113.0", default-features = false } -nu-utils = { path = "../nu-utils", version = "0.113.0", default-features = false } +nu-parser.workspace = true +nu-protocol.workspace = true +nu-engine.workspace = true +nu-utils.workspace = true [dev-dependencies] chrono = { workspace = true }