mirror of
https://github.com/nushell/nushell.git
synced 2025-07-08 02:17:22 +02:00
Compare commits
119 Commits
Author | SHA1 | Date | |
---|---|---|---|
1fe62ee613 | |||
126d11fcb7 | |||
ea4f8ff400 | |||
ebcdf5a8b1 | |||
440b9c8e1f | |||
96a886eb84 | |||
61d59f13fa | |||
5da7dcdbdb | |||
f92f11c0cf | |||
3bf96523a4 | |||
8d46398e13 | |||
461d558983 | |||
65c9160170 | |||
e3124d3561 | |||
b886fd364c | |||
21d949207f | |||
4a9e2ac37b | |||
9cc74e7a9f | |||
4adcf079e2 | |||
81cec2e50f | |||
ed7b2615c1 | |||
74e0e4f092 | |||
42fc9f52a1 | |||
c563e0cfb0 | |||
8671a3dbbd | |||
fc813af4c8 | |||
b83aa17c96 | |||
c7e10c3c57 | |||
e7d2717424 | |||
222c307648 | |||
eb9eb09ac5 | |||
6eacbabe17 | |||
33303f083c | |||
483974311d | |||
179ea5ae87 | |||
bdc7cdbcc4 | |||
2b524cd861 | |||
ad9f051d61 | |||
cfbe835910 | |||
8896ba80a4 | |||
803c24f9ce | |||
2f74574e35 | |||
8b9f02246f | |||
d9ecb7da93 | |||
18ce5de500 | |||
fbde02370a | |||
13452a7aa2 | |||
a8c49857d9 | |||
90afb65329 | |||
ff4907ed3b | |||
cbd7608898 | |||
adc9bbdc18 | |||
37bc922a67 | |||
ae51f6d722 | |||
1b2079ffdb | |||
9a968c4bdd | |||
89df01f829 | |||
dbb30cc9e0 | |||
02d63705cc | |||
ea97229688 | |||
6bf955a5a5 | |||
f90035e084 | |||
cc8b623ff8 | |||
60cb13c493 | |||
c10e483683 | |||
2d0c7b2214 | |||
88d421dcb6 | |||
7c50f7c714 | |||
bc043dcaeb | |||
10be753ab7 | |||
6906a0ca50 | |||
833471241a | |||
c4dcfdb77b | |||
1e8876b076 | |||
5483519c7d | |||
457f162fd9 | |||
58a8f30a25 | |||
70ba5d9d68 | |||
7b88bda9a1 | |||
bb37306d07 | |||
505cc014ac | |||
ff79959fdf | |||
8c2b1a22d4 | |||
3d62753e80 | |||
36c30ade3a | |||
e0eb29f161 | |||
c2ac8f730e | |||
1a0986903f | |||
0f25641722 | |||
7d6d48f3f7 | |||
6a8c183c1a | |||
0beb28e827 | |||
8352a09117 | |||
a9252c5075 | |||
73fbe26ef9 | |||
52fa9a978b | |||
d4357ad981 | |||
a0d7c1a4fd | |||
a340511e95 | |||
426e64501d | |||
b0d68c31e8 | |||
583cb96cff | |||
ff8831318d | |||
ce308ee461 | |||
21388175b8 | |||
520f11fb8f | |||
39b95fc59e | |||
63e68934f6 | |||
acc152564c | |||
8f63db4c95 | |||
cb133ed387 | |||
a7547a54bc | |||
d1969a3c9a | |||
ce582cdafb | |||
55de232a1c | |||
deca337a56 | |||
60e9f469af | |||
b500ac57c2 | |||
eadb8da9f7 |
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4.1.7
|
- uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
- name: Setup Rust toolchain and cache
|
- name: Setup Rust toolchain and cache
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
|
||||||
|
|
||||||
- name: cargo fmt
|
- name: cargo fmt
|
||||||
run: cargo fmt --all -- --check
|
run: cargo fmt --all -- --check
|
||||||
@ -65,7 +65,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4.1.7
|
- uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
- name: Setup Rust toolchain and cache
|
- name: Setup Rust toolchain and cache
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
|
||||||
|
|
||||||
- name: Tests
|
- name: Tests
|
||||||
run: cargo test --workspace --profile ci --exclude nu_plugin_*
|
run: cargo test --workspace --profile ci --exclude nu_plugin_*
|
||||||
@ -94,7 +94,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4.1.7
|
- uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
- name: Setup Rust toolchain and cache
|
- name: Setup Rust toolchain and cache
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
|
||||||
|
|
||||||
- name: Install Nushell
|
- name: Install Nushell
|
||||||
run: cargo install --path . --locked --force
|
run: cargo install --path . --locked --force
|
||||||
@ -145,7 +145,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4.1.7
|
- uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
- name: Setup Rust toolchain and cache
|
- name: Setup Rust toolchain and cache
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
|
||||||
|
|
||||||
- name: Clippy
|
- name: Clippy
|
||||||
run: cargo clippy --package nu_plugin_* -- $CLIPPY_OPTIONS
|
run: cargo clippy --package nu_plugin_* -- $CLIPPY_OPTIONS
|
||||||
@ -186,7 +186,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4.1.7
|
- uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
- name: Setup Rust toolchain and cache
|
- name: Setup Rust toolchain and cache
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
|
||||||
|
|
||||||
- name: Add wasm32-unknown-unknown target
|
- name: Add wasm32-unknown-unknown target
|
||||||
run: rustup target add wasm32-unknown-unknown
|
run: rustup target add wasm32-unknown-unknown
|
||||||
|
148
.github/workflows/nightly-build.yml
vendored
148
.github/workflows/nightly-build.yml
vendored
@ -4,17 +4,18 @@
|
|||||||
# 2. https://github.com/JasonEtco/create-an-issue
|
# 2. https://github.com/JasonEtco/create-an-issue
|
||||||
# 3. https://docs.github.com/en/actions/learn-github-actions/variables
|
# 3. https://docs.github.com/en/actions/learn-github-actions/variables
|
||||||
# 4. https://github.com/actions/github-script
|
# 4. https://github.com/actions/github-script
|
||||||
|
# 5. https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds
|
||||||
#
|
#
|
||||||
name: Nightly Build
|
name: Nightly Build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- nightly # Just for test purpose only with the nightly repo
|
- nightly # Just for test purpose only with the nightly repo
|
||||||
# This schedule will run only from the default branch
|
# This schedule will run only from the default branch
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '15 0 * * *' # run at 00:15 AM UTC
|
- cron: '15 0 * * *' # run at 00:15 AM UTC
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@ -26,6 +27,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# This job is required by the release job, so we should make it run both from Nushell repo and nightly repo
|
# This job is required by the release job, so we should make it run both from Nushell repo and nightly repo
|
||||||
# if: github.repository == 'nushell/nightly'
|
# if: github.repository == 'nushell/nightly'
|
||||||
|
# Map a step output to a job output
|
||||||
|
outputs:
|
||||||
|
skip: ${{ steps.vars.outputs.skip }}
|
||||||
|
build_date: ${{ steps.vars.outputs.build_date }}
|
||||||
|
nightly_tag: ${{ steps.vars.outputs.nightly_tag }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@ -58,16 +64,53 @@ jobs:
|
|||||||
# All the changes will be overwritten by the upstream main branch
|
# All the changes will be overwritten by the upstream main branch
|
||||||
git reset --hard src/main
|
git reset --hard src/main
|
||||||
git push origin main -f
|
git push origin main -f
|
||||||
let sha_short = (git rev-parse --short origin/main | str trim | str substring 0..7)
|
|
||||||
let tag_name = $'nightly-($sha_short)'
|
- name: Create Tag and Output Tag Name
|
||||||
if (git ls-remote --tags origin $tag_name | is-empty) {
|
if: github.repository == 'nushell/nightly'
|
||||||
git tag -a $tag_name -m $'Nightly build from ($sha_short)'
|
id: vars
|
||||||
|
shell: nu {0}
|
||||||
|
run: |
|
||||||
|
let date = date now | format date %m%d
|
||||||
|
let version = open Cargo.toml | get 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
|
||||||
|
| where tag_name =~ nightly
|
||||||
|
| get tag_name?.0? | default ''
|
||||||
|
| parse '{version}-nightly.{build}+{hash}'
|
||||||
|
if ($latest_meta.0?.hash? | default '') == $sha_short {
|
||||||
|
print $'(ansi g)Latest nightly build is up-to-date, skip rebuilding.(ansi reset)'
|
||||||
|
$'skip=true(char nl)' o>> $env.GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
let prev_ver = $latest_meta.0?.version? | default '0.0.0'
|
||||||
|
let build = if ($latest_meta | is-empty) or ($version != $prev_ver) { 1 } else {
|
||||||
|
($latest_meta | get build?.0? | default 0 | into int) + 1
|
||||||
|
}
|
||||||
|
let nightly_tag = $'($version)-nightly.($build)+($sha_short)'
|
||||||
|
$'build_date=($date)(char nl)' o>> $env.GITHUB_OUTPUT
|
||||||
|
$'nightly_tag=($nightly_tag)(char nl)' o>> $env.GITHUB_OUTPUT
|
||||||
|
if (git ls-remote --tags origin $nightly_tag | is-empty) {
|
||||||
|
ls **/Cargo.toml | each {|file|
|
||||||
|
open --raw $file.name
|
||||||
|
| str replace --all $'version = "($version)"' $'version = "($version)-nightly.($build)"'
|
||||||
|
| save --force $file.name
|
||||||
|
}
|
||||||
|
# Disable the following two workflows for the automatic committed changes
|
||||||
|
rm .github/workflows/ci.yml
|
||||||
|
rm .github/workflows/audit.yml
|
||||||
|
|
||||||
|
git add .
|
||||||
|
git commit -m $'Update version to ($version)-nightly.($build)'
|
||||||
|
git tag -a $nightly_tag -m $'Nightly build from ($sha_short)'
|
||||||
git push origin --tags
|
git push origin --tags
|
||||||
|
git push origin main -f
|
||||||
}
|
}
|
||||||
|
|
||||||
standard:
|
release:
|
||||||
name: Nu
|
name: Nu
|
||||||
needs: prepare
|
needs: prepare
|
||||||
|
if: needs.prepare.outputs.skip != 'true'
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@ -84,24 +127,15 @@ jobs:
|
|||||||
- armv7-unknown-linux-musleabihf
|
- armv7-unknown-linux-musleabihf
|
||||||
- riscv64gc-unknown-linux-gnu
|
- riscv64gc-unknown-linux-gnu
|
||||||
- loongarch64-unknown-linux-gnu
|
- loongarch64-unknown-linux-gnu
|
||||||
extra: ['bin']
|
|
||||||
include:
|
include:
|
||||||
- target: aarch64-apple-darwin
|
- target: aarch64-apple-darwin
|
||||||
os: macos-latest
|
os: macos-latest
|
||||||
- target: x86_64-apple-darwin
|
- target: x86_64-apple-darwin
|
||||||
os: macos-latest
|
os: macos-latest
|
||||||
- target: x86_64-pc-windows-msvc
|
- target: x86_64-pc-windows-msvc
|
||||||
extra: 'bin'
|
|
||||||
os: windows-latest
|
|
||||||
- target: x86_64-pc-windows-msvc
|
|
||||||
extra: msi
|
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
- target: aarch64-pc-windows-msvc
|
- target: aarch64-pc-windows-msvc
|
||||||
extra: 'bin'
|
os: windows-11-arm
|
||||||
os: windows-latest
|
|
||||||
- target: aarch64-pc-windows-msvc
|
|
||||||
extra: msi
|
|
||||||
os: windows-latest
|
|
||||||
- target: x86_64-unknown-linux-gnu
|
- target: x86_64-unknown-linux-gnu
|
||||||
os: ubuntu-22.04
|
os: ubuntu-22.04
|
||||||
- target: x86_64-unknown-linux-musl
|
- target: x86_64-unknown-linux-musl
|
||||||
@ -120,40 +154,64 @@ jobs:
|
|||||||
os: ubuntu-22.04
|
os: ubuntu-22.04
|
||||||
|
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: main
|
ref: main
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install Wix Toolset 6 for Windows
|
||||||
|
shell: pwsh
|
||||||
|
if: ${{ startsWith(matrix.os, 'windows') }}
|
||||||
|
run: |
|
||||||
|
dotnet tool install --global wix --version 6.0.0
|
||||||
|
dotnet workload install wix
|
||||||
|
$wixPath = "$env:USERPROFILE\.dotnet\tools"
|
||||||
|
echo "$wixPath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
$env:PATH = "$wixPath;$env:PATH"
|
||||||
|
wix --version
|
||||||
|
|
||||||
- name: Update Rust Toolchain Target
|
- name: Update Rust Toolchain Target
|
||||||
run: |
|
run: |
|
||||||
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
|
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
|
||||||
|
|
||||||
- name: Setup Rust toolchain and cache
|
- name: Setup Rust toolchain and cache
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
|
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
|
||||||
with:
|
with:
|
||||||
rustflags: ''
|
rustflags: ''
|
||||||
|
|
||||||
- name: Setup Nushell
|
- name: Setup Nushell
|
||||||
uses: hustcer/setup-nu@v3
|
uses: hustcer/setup-nu@v3
|
||||||
|
if: ${{ matrix.os != 'windows-11-arm' }}
|
||||||
with:
|
with:
|
||||||
version: 0.103.0
|
version: 0.103.0
|
||||||
|
|
||||||
- name: Release Nu Binary
|
- name: Release Nu Binary
|
||||||
id: nu
|
id: nu
|
||||||
|
if: ${{ matrix.os != 'windows-11-arm' }}
|
||||||
run: nu .github/workflows/release-pkg.nu
|
run: nu .github/workflows/release-pkg.nu
|
||||||
env:
|
env:
|
||||||
OS: ${{ matrix.os }}
|
OS: ${{ matrix.os }}
|
||||||
REF: ${{ github.ref }}
|
REF: ${{ github.ref }}
|
||||||
TARGET: ${{ matrix.target }}
|
TARGET: ${{ matrix.target }}
|
||||||
_EXTRA_: ${{ matrix.extra }}
|
|
||||||
|
- name: Build Nu for Windows ARM64
|
||||||
|
id: nu0
|
||||||
|
shell: pwsh
|
||||||
|
if: ${{ matrix.os == 'windows-11-arm' }}
|
||||||
|
run: |
|
||||||
|
$env:OS = 'windows'
|
||||||
|
$env:REF = '${{ github.ref }}'
|
||||||
|
$env:TARGET = '${{ matrix.target }}'
|
||||||
|
cargo build --release --all --target aarch64-pc-windows-msvc
|
||||||
|
cp ./target/${{ matrix.target }}/release/nu.exe .
|
||||||
|
./nu.exe -c 'version'
|
||||||
|
./nu.exe ${{github.workspace}}/.github/workflows/release-pkg.nu
|
||||||
|
|
||||||
- name: Create an Issue for Release Failure
|
- name: Create an Issue for Release Failure
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
uses: JasonEtco/create-an-issue@v2.9.2
|
uses: JasonEtco/create-an-issue@v2
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
@ -161,13 +219,6 @@ jobs:
|
|||||||
search_existing: open
|
search_existing: open
|
||||||
filename: .github/AUTO_ISSUE_TEMPLATE/nightly-build-fail.md
|
filename: .github/AUTO_ISSUE_TEMPLATE/nightly-build-fail.md
|
||||||
|
|
||||||
- name: Set Outputs of Short SHA
|
|
||||||
id: vars
|
|
||||||
run: |
|
|
||||||
echo "date=$(date -u +'%Y-%m-%d')" >> $GITHUB_OUTPUT
|
|
||||||
sha_short=$(git rev-parse --short HEAD)
|
|
||||||
echo "sha_short=${sha_short:0:7}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# REF: https://github.com/marketplace/actions/gh-release
|
# REF: https://github.com/marketplace/actions/gh-release
|
||||||
# Create a release only in nushell/nightly repo
|
# Create a release only in nushell/nightly repo
|
||||||
- name: Publish Archive
|
- name: Publish Archive
|
||||||
@ -175,9 +226,39 @@ jobs:
|
|||||||
if: ${{ startsWith(github.repository, 'nushell/nightly') }}
|
if: ${{ startsWith(github.repository, 'nushell/nightly') }}
|
||||||
with:
|
with:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
files: ${{ steps.nu.outputs.archive }}
|
files: |
|
||||||
tag_name: nightly-${{ steps.vars.outputs.sha_short }}
|
${{ steps.nu.outputs.msi }}
|
||||||
name: Nu-nightly-${{ steps.vars.outputs.date }}-${{ steps.vars.outputs.sha_short }}
|
${{ steps.nu0.outputs.msi }}
|
||||||
|
${{ steps.nu.outputs.archive }}
|
||||||
|
${{ steps.nu0.outputs.archive }}
|
||||||
|
tag_name: ${{ needs.prepare.outputs.nightly_tag }}
|
||||||
|
name: ${{ needs.prepare.outputs.build_date }}-${{ needs.prepare.outputs.nightly_tag }}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
sha256sum:
|
||||||
|
needs: [prepare, release]
|
||||||
|
name: Create Sha256sum
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository == 'nushell/nightly'
|
||||||
|
steps:
|
||||||
|
- name: Download Release Archives
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: >-
|
||||||
|
gh release download ${{ needs.prepare.outputs.nightly_tag }}
|
||||||
|
--repo ${{ github.repository }}
|
||||||
|
--pattern '*'
|
||||||
|
--dir release
|
||||||
|
- name: Create Checksums
|
||||||
|
run: cd release && shasum -a 256 * > ../SHA256SUMS
|
||||||
|
- name: Publish Checksums
|
||||||
|
uses: softprops/action-gh-release@v2.0.9
|
||||||
|
with:
|
||||||
|
draft: false
|
||||||
|
prerelease: true
|
||||||
|
files: SHA256SUMS
|
||||||
|
tag_name: ${{ needs.prepare.outputs.nightly_tag }}
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
@ -185,12 +266,9 @@ jobs:
|
|||||||
name: Cleanup
|
name: Cleanup
|
||||||
# Should only run in nushell/nightly repo
|
# Should only run in nushell/nightly repo
|
||||||
if: github.repository == 'nushell/nightly'
|
if: github.repository == 'nushell/nightly'
|
||||||
|
needs: [release, sha256sum]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
# Sleep for 30 minutes, waiting for the release to be published
|
|
||||||
- name: Waiting for Release
|
|
||||||
run: sleep 1800
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: main
|
ref: main
|
||||||
@ -205,7 +283,7 @@ jobs:
|
|||||||
shell: nu {0}
|
shell: nu {0}
|
||||||
run: |
|
run: |
|
||||||
let KEEP_COUNT = 10
|
let KEEP_COUNT = 10
|
||||||
let deprecated = (http get https://api.github.com/repos/nushell/nightly/releases | sort-by -r created_at | select tag_name id | range $KEEP_COUNT..)
|
let deprecated = (http get https://api.github.com/repos/nushell/nightly/releases | sort-by -r created_at | select tag_name id | slice $KEEP_COUNT..)
|
||||||
for release in $deprecated {
|
for release in $deprecated {
|
||||||
print $'Deleting tag ($release.tag_name)'
|
print $'Deleting tag ($release.tag_name)'
|
||||||
git push origin --delete $release.tag_name
|
git push origin --delete $release.tag_name
|
||||||
|
62
.github/workflows/release-msi.nu
vendored
Executable file
62
.github/workflows/release-msi.nu
vendored
Executable file
@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env nu
|
||||||
|
|
||||||
|
# Created: 2025/05/21 19:05:20
|
||||||
|
# Description:
|
||||||
|
# A script to build Windows MSI packages for NuShell. Need wix 6.0 to be installed.
|
||||||
|
# The script will download the specified NuShell release, extract it, and create an MSI package.
|
||||||
|
# Can be run locally or in GitHub Actions.
|
||||||
|
# To run this script locally:
|
||||||
|
# load-env { TARGET: 'x86_64-pc-windows-msvc' REF: '0.103.0' GITHUB_REPOSITORY: 'nushell/nushell' }
|
||||||
|
# nu .github/workflows/release-msi.nu
|
||||||
|
|
||||||
|
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 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)...'
|
||||||
|
fetch-nu-pkg
|
||||||
|
# Create extra Windows msi release package if dotnet and wix are available
|
||||||
|
let installed = [dotnet wix] | all { (which $in | length) > 0 }
|
||||||
|
if $installed and (wix --version | split row . | first | into int) >= 6 {
|
||||||
|
|
||||||
|
print $'(char nl)Start creating Windows msi package with the following contents...'
|
||||||
|
cd wix; hr-line
|
||||||
|
cp nu/README.txt .
|
||||||
|
ls -f nu/* | print
|
||||||
|
./nu/nu.exe -c $'NU_RELEASE_VERSION=($version) dotnet build -c Release -p:Platform=($arch)'
|
||||||
|
glob **/*.msi | print
|
||||||
|
# Workaround for https://github.com/softprops/action-gh-release/issues/280
|
||||||
|
let wixRelease = (glob **/*.msi | where $it =~ bin | get 0 | str replace --all '\' '/')
|
||||||
|
let msi = $'($wixRelease | path dirname)/nu-($version)-($target).msi'
|
||||||
|
mv $wixRelease $msi
|
||||||
|
print $'MSI archive: ---> ($msi)';
|
||||||
|
# Run only in GitHub Actions
|
||||||
|
if ($env.GITHUB_ACTIONS? | default false | into bool) {
|
||||||
|
echo $"msi=($msi)(char nl)" o>> $env.GITHUB_OUTPUT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def fetch-nu-pkg [] {
|
||||||
|
mkdir wix/nu
|
||||||
|
# See: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables
|
||||||
|
gh release download $env.REF --repo $env.GITHUB_REPOSITORY --pattern $'*-($env.TARGET).zip' --dir wix/nu
|
||||||
|
cd wix/nu
|
||||||
|
let pkg = ls *.zip | get name.0
|
||||||
|
unzip $pkg
|
||||||
|
rm $pkg
|
||||||
|
ls | print
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print a horizontal line marker
|
||||||
|
def 'hr-line' [
|
||||||
|
--blank-line(-b)
|
||||||
|
] {
|
||||||
|
print $'(ansi g)---------------------------------------------------------------------------->(ansi reset)'
|
||||||
|
if $blank_line { char nl }
|
||||||
|
}
|
||||||
|
|
||||||
|
alias main = build-msi
|
103
.github/workflows/release-msi.yml
vendored
Normal file
103
.github/workflows/release-msi.yml
vendored
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#
|
||||||
|
# REF:
|
||||||
|
# 1. https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrixinclude
|
||||||
|
#
|
||||||
|
name: Build Windows MSI
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
required: true
|
||||||
|
description: 'Tag to Rebuild MSI'
|
||||||
|
version:
|
||||||
|
description: 'Version of Rebuild MSI'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Nu
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
- x86_64-pc-windows-msvc
|
||||||
|
- aarch64-pc-windows-msvc
|
||||||
|
extra: ['bin']
|
||||||
|
|
||||||
|
include:
|
||||||
|
- target: x86_64-pc-windows-msvc
|
||||||
|
os: windows-latest
|
||||||
|
- target: aarch64-pc-windows-msvc
|
||||||
|
os: windows-11-arm
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Wix Toolset 6 for Windows
|
||||||
|
shell: pwsh
|
||||||
|
if: ${{ startsWith(matrix.os, 'windows') }}
|
||||||
|
run: |
|
||||||
|
dotnet tool install --global wix --version 6.0.0
|
||||||
|
dotnet workload install wix
|
||||||
|
$wixPath = "$env:USERPROFILE\.dotnet\tools"
|
||||||
|
echo "$wixPath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
$env:PATH = "$wixPath;$env:PATH"
|
||||||
|
wix --version
|
||||||
|
|
||||||
|
- name: Setup Nushell
|
||||||
|
uses: hustcer/setup-nu@v3
|
||||||
|
with:
|
||||||
|
version: nightly
|
||||||
|
|
||||||
|
- name: Release MSI Packages
|
||||||
|
id: nu
|
||||||
|
run: nu .github/workflows/release-msi.nu
|
||||||
|
env:
|
||||||
|
OS: ${{ matrix.os }}
|
||||||
|
REF: ${{ inputs.tag }}
|
||||||
|
TARGET: ${{ matrix.target }}
|
||||||
|
MSI_VERSION: ${{ inputs.version }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# REF: https://github.com/marketplace/actions/gh-release
|
||||||
|
- name: Publish Archive
|
||||||
|
uses: softprops/action-gh-release@v2.0.5
|
||||||
|
with:
|
||||||
|
tag_name: ${{ inputs.tag }}
|
||||||
|
files: ${{ steps.nu.outputs.msi }}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
sha256sum:
|
||||||
|
needs: release
|
||||||
|
name: Create Sha256sum
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download Release Archives
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: >-
|
||||||
|
gh release download ${{ inputs.tag }}
|
||||||
|
--repo ${{ github.repository }}
|
||||||
|
--pattern '*'
|
||||||
|
--dir release
|
||||||
|
- name: Create Checksums
|
||||||
|
run: cd release && rm -f SHA256SUMS && shasum -a 256 * > ../SHA256SUMS
|
||||||
|
- name: Publish Checksums
|
||||||
|
uses: softprops/action-gh-release@v2.0.5
|
||||||
|
with:
|
||||||
|
files: SHA256SUMS
|
||||||
|
tag_name: ${{ inputs.tag }}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
85
.github/workflows/release-pkg.nu
vendored
85
.github/workflows/release-pkg.nu
vendored
@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
# Instructions for manually creating an MSI for Winget Releases when they fail
|
# Instructions for manually creating an MSI for Winget Releases when they fail
|
||||||
# Added 2022-11-29 when Windows packaging wouldn't work
|
# Added 2022-11-29 when Windows packaging wouldn't work
|
||||||
# Updated again on 2023-02-23 because msis are still failing validation
|
# Updated again on 2023-02-23 because MSIs are still failing validation
|
||||||
# To run this manual for windows here are the steps I take
|
# To run this manual for windows here are the steps I take
|
||||||
# checkout the release you want to publish
|
# checkout the release you want to publish
|
||||||
# 1. git checkout 0.86.0
|
# 1. git checkout 0.103.0
|
||||||
# unset CARGO_TARGET_DIR if set (I have to do this in the parent shell to get it to work)
|
# unset CARGO_TARGET_DIR if set (I have to do this in the parent shell to get it to work)
|
||||||
# 2. $env:CARGO_TARGET_DIR = ""
|
# 2. $env:CARGO_TARGET_DIR = ""
|
||||||
# 2. hide-env CARGO_TARGET_DIR
|
# 2. hide-env CARGO_TARGET_DIR
|
||||||
@ -23,19 +23,13 @@
|
|||||||
# 7. $env.Path = ($env.Path | append 'c:\apps\7-zip')
|
# 7. $env.Path = ($env.Path | append 'c:\apps\7-zip')
|
||||||
# make sure aria2c.exe is in your path https://github.com/aria2/aria2
|
# make sure aria2c.exe is in your path https://github.com/aria2/aria2
|
||||||
# 8. $env.Path = ($env.Path | append 'c:\path\to\aria2c')
|
# 8. $env.Path = ($env.Path | append 'c:\path\to\aria2c')
|
||||||
# make sure you have the wixtools installed https://wixtoolset.org/
|
# make sure you have the wix 6.0 installed: dotnet tool install --global wix --version 6.0.0
|
||||||
# 9. $env.Path = ($env.Path | append 'C:\Users\dschroeder\AppData\Local\tauri\WixTools')
|
# then build nu*.exe and the MSI installer by running:
|
||||||
# You need to run the release-pkg twice. The first pass, with _EXTRA_ as 'bin', makes the output
|
# 9. source .github\workflows\release-pkg.nu
|
||||||
# folder and builds everything. The second pass, that generates the msi file, with _EXTRA_ as 'msi'
|
|
||||||
# 10. $env._EXTRA_ = 'bin'
|
|
||||||
# 11. source .github\workflows\release-pkg.nu
|
|
||||||
# 12. cd ..
|
|
||||||
# 13. $env._EXTRA_ = 'msi'
|
|
||||||
# 14. source .github\workflows\release-pkg.nu
|
|
||||||
# After msi is generated, you have to update winget-pkgs repo, you'll need to patch the release
|
# After msi is generated, you have to update winget-pkgs repo, you'll need to patch the release
|
||||||
# by deleting the existing msi and uploading this new msi. Then you'll need to update the hash
|
# by deleting the existing msi and uploading this new msi. Then you'll need to update the hash
|
||||||
# on the winget-pkgs PR. To generate the hash, run this command
|
# on the winget-pkgs PR. To generate the hash, run this command
|
||||||
# 15. open target\wix\nu-0.74.0-x86_64-pc-windows-msvc.msi | hash sha256
|
# 10. open wix\bin\x64\Release\nu-0.103.0-x86_64-pc-windows-msvc.msi | hash sha256
|
||||||
# Then, just take the output and put it in the winget-pkgs PR for the hash on the msi
|
# Then, just take the output and put it in the winget-pkgs PR for the hash on the msi
|
||||||
|
|
||||||
|
|
||||||
@ -85,14 +79,14 @@ if $os in ['macos-latest'] or $USE_UBUNTU {
|
|||||||
cargo-build-nu
|
cargo-build-nu
|
||||||
}
|
}
|
||||||
'aarch64-unknown-linux-musl' => {
|
'aarch64-unknown-linux-musl' => {
|
||||||
aria2c https://musl.cc/aarch64-linux-musl-cross.tgz
|
aria2c https://github.com/nushell/integrations/releases/download/build-tools/aarch64-linux-musl-cross.tgz
|
||||||
tar -xf aarch64-linux-musl-cross.tgz -C $env.HOME
|
tar -xf aarch64-linux-musl-cross.tgz -C $env.HOME
|
||||||
$env.PATH = ($env.PATH | split row (char esep) | prepend $'($env.HOME)/aarch64-linux-musl-cross/bin')
|
$env.PATH = ($env.PATH | split row (char esep) | prepend $'($env.HOME)/aarch64-linux-musl-cross/bin')
|
||||||
$env.CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER = 'aarch64-linux-musl-gcc'
|
$env.CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER = 'aarch64-linux-musl-gcc'
|
||||||
cargo-build-nu
|
cargo-build-nu
|
||||||
}
|
}
|
||||||
'armv7-unknown-linux-musleabihf' => {
|
'armv7-unknown-linux-musleabihf' => {
|
||||||
aria2c https://musl.cc/armv7r-linux-musleabihf-cross.tgz
|
aria2c https://github.com/nushell/integrations/releases/download/build-tools/armv7r-linux-musleabihf-cross.tgz
|
||||||
tar -xf armv7r-linux-musleabihf-cross.tgz -C $env.HOME
|
tar -xf armv7r-linux-musleabihf-cross.tgz -C $env.HOME
|
||||||
$env.PATH = ($env.PATH | split row (char esep) | prepend $'($env.HOME)/armv7r-linux-musleabihf-cross/bin')
|
$env.PATH = ($env.PATH | split row (char esep) | prepend $'($env.HOME)/armv7r-linux-musleabihf-cross/bin')
|
||||||
$env.CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABIHF_LINKER = 'armv7r-linux-musleabihf-gcc'
|
$env.CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABIHF_LINKER = 'armv7r-linux-musleabihf-gcc'
|
||||||
@ -175,37 +169,13 @@ if $os in ['macos-latest'] or $USE_UBUNTU {
|
|||||||
tar -czf $archive $dest
|
tar -czf $archive $dest
|
||||||
print $'archive: ---> ($archive)'; ls $archive
|
print $'archive: ---> ($archive)'; ls $archive
|
||||||
# REF: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
|
# REF: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
|
||||||
echo $"archive=($archive)" | save --append $env.GITHUB_OUTPUT
|
echo $"archive=($archive)(char nl)" o>> $env.GITHUB_OUTPUT
|
||||||
|
|
||||||
} else if $os =~ 'windows' {
|
} else if $os =~ 'windows' {
|
||||||
|
|
||||||
let releaseStem = $'($bin)-($version)-($target)'
|
let releaseStem = $'($bin)-($version)-($target)'
|
||||||
|
let arch = if $nu.os-info.arch =~ 'x86_64' { 'x64' } else { 'arm64' }
|
||||||
print $'(char nl)Download less related stuffs...'; hr-line
|
fetch-less $arch
|
||||||
# todo: less-v661 is out but is released as a zip file. maybe we should switch to that and extract it?
|
|
||||||
aria2c https://github.com/jftuga/less-Windows/releases/download/less-v608/less.exe -o less.exe
|
|
||||||
# the below was renamed because it was failing to download for darren. it should work but it wasn't
|
|
||||||
# todo: maybe we should get rid of this aria2c dependency and just use http get?
|
|
||||||
#aria2c https://raw.githubusercontent.com/jftuga/less-Windows/master/LICENSE -o LICENSE-for-less.txt
|
|
||||||
aria2c https://github.com/jftuga/less-Windows/blob/master/LICENSE -o LICENSE-for-less.txt
|
|
||||||
|
|
||||||
# Create Windows msi release package
|
|
||||||
if (get-env _EXTRA_) == 'msi' {
|
|
||||||
|
|
||||||
let wixRelease = $'($src)/target/wix/($releaseStem).msi'
|
|
||||||
print $'(char nl)Start creating Windows msi package with the following contents...'
|
|
||||||
cd $src; hr-line
|
|
||||||
# Wix need the binaries be stored in target/release/
|
|
||||||
cp -r ($'($dist)/*' | into glob) target/release/
|
|
||||||
ls target/release/* | print
|
|
||||||
cargo install cargo-wix --version 0.3.8
|
|
||||||
cargo wix --no-build --nocapture --package nu --output $wixRelease
|
|
||||||
# Workaround for https://github.com/softprops/action-gh-release/issues/280
|
|
||||||
let archive = ($wixRelease | str replace --all '\' '/')
|
|
||||||
print $'archive: ---> ($archive)';
|
|
||||||
echo $"archive=($archive)" | save --append $env.GITHUB_OUTPUT
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
print $'(char nl)(ansi g)Archive contents:(ansi reset)'; hr-line; ls | print
|
print $'(char nl)(ansi g)Archive contents:(ansi reset)'; hr-line; ls | print
|
||||||
let archive = $'($dist)/($releaseStem).zip'
|
let archive = $'($dist)/($releaseStem).zip'
|
||||||
@ -215,11 +185,42 @@ if $os in ['macos-latest'] or $USE_UBUNTU {
|
|||||||
# Workaround for https://github.com/softprops/action-gh-release/issues/280
|
# Workaround for https://github.com/softprops/action-gh-release/issues/280
|
||||||
let archive = ($pkg | get 0 | str replace --all '\' '/')
|
let archive = ($pkg | get 0 | str replace --all '\' '/')
|
||||||
print $'archive: ---> ($archive)'
|
print $'archive: ---> ($archive)'
|
||||||
echo $"archive=($archive)" | save --append $env.GITHUB_OUTPUT
|
echo $"archive=($archive)(char nl)" o>> $env.GITHUB_OUTPUT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Create extra Windows msi release package if dotnet and wix are available
|
||||||
|
let installed = [dotnet wix] | all { (which $in | length) > 0 }
|
||||||
|
if $installed and (wix --version | split row . | first | into int) >= 6 {
|
||||||
|
|
||||||
|
print $'(char nl)Start creating Windows msi package with the following contents...'
|
||||||
|
cd $src; cd wix; hr-line; mkdir nu
|
||||||
|
# Wix need the binaries be stored in nu folder
|
||||||
|
cp -r ($'($dist)/*' | into glob) nu/
|
||||||
|
cp $'($dist)/README.txt' .
|
||||||
|
ls -f nu/* | print
|
||||||
|
./nu/nu.exe -c $'NU_RELEASE_VERSION=($version) dotnet build -c Release -p:Platform=($arch)'
|
||||||
|
glob **/*.msi | print
|
||||||
|
# Workaround for https://github.com/softprops/action-gh-release/issues/280
|
||||||
|
let wixRelease = (glob **/*.msi | where $it =~ bin | get 0 | str replace --all '\' '/')
|
||||||
|
let msi = $'($wixRelease | path dirname)/nu-($version)-($target).msi'
|
||||||
|
mv $wixRelease $msi
|
||||||
|
print $'MSI archive: ---> ($msi)';
|
||||||
|
echo $"msi=($msi)(char nl)" o>> $env.GITHUB_OUTPUT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def fetch-less [
|
||||||
|
arch: string = 'x64' # The architecture to fetch
|
||||||
|
] {
|
||||||
|
let less_zip = $'less-($arch).zip'
|
||||||
|
print $'Fetching less archive: (ansi g)($less_zip)(ansi reset)'
|
||||||
|
let url = $'https://github.com/jftuga/less-Windows/releases/download/less-v668/($less_zip)'
|
||||||
|
http get https://github.com/jftuga/less-Windows/blob/master/LICENSE | save -rf LICENSE-for-less.txt
|
||||||
|
http get $url | save -rf $less_zip
|
||||||
|
unzip $less_zip
|
||||||
|
rm $less_zip lesskey.exe
|
||||||
|
}
|
||||||
|
|
||||||
def 'cargo-build-nu' [] {
|
def 'cargo-build-nu' [] {
|
||||||
if $os =~ 'windows' {
|
if $os =~ 'windows' {
|
||||||
cargo build --release --all --target $target
|
cargo build --release --all --target $target
|
||||||
|
46
.github/workflows/release.yml
vendored
46
.github/workflows/release.yml
vendored
@ -35,24 +35,15 @@ jobs:
|
|||||||
- armv7-unknown-linux-musleabihf
|
- armv7-unknown-linux-musleabihf
|
||||||
- riscv64gc-unknown-linux-gnu
|
- riscv64gc-unknown-linux-gnu
|
||||||
- loongarch64-unknown-linux-gnu
|
- loongarch64-unknown-linux-gnu
|
||||||
extra: ['bin']
|
|
||||||
include:
|
include:
|
||||||
- target: aarch64-apple-darwin
|
- target: aarch64-apple-darwin
|
||||||
os: macos-latest
|
os: macos-latest
|
||||||
- target: x86_64-apple-darwin
|
- target: x86_64-apple-darwin
|
||||||
os: macos-latest
|
os: macos-latest
|
||||||
- target: x86_64-pc-windows-msvc
|
- target: x86_64-pc-windows-msvc
|
||||||
extra: 'bin'
|
|
||||||
os: windows-latest
|
|
||||||
- target: x86_64-pc-windows-msvc
|
|
||||||
extra: msi
|
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
- target: aarch64-pc-windows-msvc
|
- target: aarch64-pc-windows-msvc
|
||||||
extra: 'bin'
|
os: windows-11-arm
|
||||||
os: windows-latest
|
|
||||||
- target: aarch64-pc-windows-msvc
|
|
||||||
extra: msi
|
|
||||||
os: windows-latest
|
|
||||||
- target: x86_64-unknown-linux-gnu
|
- target: x86_64-unknown-linux-gnu
|
||||||
os: ubuntu-22.04
|
os: ubuntu-22.04
|
||||||
- target: x86_64-unknown-linux-musl
|
- target: x86_64-unknown-linux-musl
|
||||||
@ -75,12 +66,23 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Wix Toolset 6 for Windows
|
||||||
|
shell: pwsh
|
||||||
|
if: ${{ startsWith(matrix.os, 'windows') }}
|
||||||
|
run: |
|
||||||
|
dotnet tool install --global wix --version 6.0.0
|
||||||
|
dotnet workload install wix
|
||||||
|
$wixPath = "$env:USERPROFILE\.dotnet\tools"
|
||||||
|
echo "$wixPath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
$env:PATH = "$wixPath;$env:PATH"
|
||||||
|
wix --version
|
||||||
|
|
||||||
- name: Update Rust Toolchain Target
|
- name: Update Rust Toolchain Target
|
||||||
run: |
|
run: |
|
||||||
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
|
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
|
||||||
|
|
||||||
- name: Setup Rust toolchain
|
- name: Setup Rust toolchain
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
|
||||||
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
|
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
|
||||||
with:
|
with:
|
||||||
cache: false
|
cache: false
|
||||||
@ -88,17 +90,31 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup Nushell
|
- name: Setup Nushell
|
||||||
uses: hustcer/setup-nu@v3
|
uses: hustcer/setup-nu@v3
|
||||||
|
if: ${{ matrix.os != 'windows-11-arm' }}
|
||||||
with:
|
with:
|
||||||
version: 0.103.0
|
version: 0.103.0
|
||||||
|
|
||||||
- name: Release Nu Binary
|
- name: Release Nu Binary
|
||||||
id: nu
|
id: nu
|
||||||
|
if: ${{ matrix.os != 'windows-11-arm' }}
|
||||||
run: nu .github/workflows/release-pkg.nu
|
run: nu .github/workflows/release-pkg.nu
|
||||||
env:
|
env:
|
||||||
OS: ${{ matrix.os }}
|
OS: ${{ matrix.os }}
|
||||||
REF: ${{ github.ref }}
|
REF: ${{ github.ref }}
|
||||||
TARGET: ${{ matrix.target }}
|
TARGET: ${{ matrix.target }}
|
||||||
_EXTRA_: ${{ matrix.extra }}
|
|
||||||
|
- name: Build Nu for Windows ARM64
|
||||||
|
id: nu0
|
||||||
|
shell: pwsh
|
||||||
|
if: ${{ matrix.os == 'windows-11-arm' }}
|
||||||
|
run: |
|
||||||
|
$env:OS = 'windows'
|
||||||
|
$env:REF = '${{ github.ref }}'
|
||||||
|
$env:TARGET = '${{ matrix.target }}'
|
||||||
|
cargo build --release --all --target aarch64-pc-windows-msvc
|
||||||
|
cp ./target/${{ matrix.target }}/release/nu.exe .
|
||||||
|
./nu.exe -c 'version'
|
||||||
|
./nu.exe ${{github.workspace}}/.github/workflows/release-pkg.nu
|
||||||
|
|
||||||
# WARN: Don't upgrade this action due to the release per asset issue.
|
# WARN: Don't upgrade this action due to the release per asset issue.
|
||||||
# See: https://github.com/softprops/action-gh-release/issues/445
|
# See: https://github.com/softprops/action-gh-release/issues/445
|
||||||
@ -107,7 +123,11 @@ jobs:
|
|||||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
with:
|
with:
|
||||||
draft: true
|
draft: true
|
||||||
files: ${{ steps.nu.outputs.archive }}
|
files: |
|
||||||
|
${{ steps.nu.outputs.msi }}
|
||||||
|
${{ steps.nu0.outputs.msi }}
|
||||||
|
${{ steps.nu.outputs.archive }}
|
||||||
|
${{ steps.nu0.outputs.archive }}
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
2
.github/workflows/typos.yml
vendored
2
.github/workflows/typos.yml
vendored
@ -10,4 +10,4 @@ jobs:
|
|||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
- name: Check spelling
|
- name: Check spelling
|
||||||
uses: crate-ci/typos@v1.31.1
|
uses: crate-ci/typos@v1.33.1
|
||||||
|
4
.github/workflows/winget-submission.yml
vendored
4
.github/workflows/winget-submission.yml
vendored
@ -25,5 +25,5 @@ jobs:
|
|||||||
installers-regex: 'msvc\.msi$'
|
installers-regex: 'msvc\.msi$'
|
||||||
version: ${{ inputs.tag_name || github.event.release.tag_name }}
|
version: ${{ inputs.tag_name || github.event.release.tag_name }}
|
||||||
release-tag: ${{ inputs.tag_name || github.event.release.tag_name }}
|
release-tag: ${{ inputs.tag_name || github.event.release.tag_name }}
|
||||||
token: ${{ secrets.NUSHELL_PAT }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
fork-user: fdncred
|
fork-user: nushell
|
||||||
|
@ -31,7 +31,7 @@ The review process can be summarized as follows:
|
|||||||
1. You want to make some change to Nushell that is more involved than simple bug-fixing.
|
1. You want to make some change to Nushell that is more involved than simple bug-fixing.
|
||||||
2. Go to [Discord](https://discordapp.com/invite/NtAbbGn) or a [GitHub issue](https://github.com/nushell/nushell/issues/new/choose) and chat with some core team members and/or other contributors about it.
|
2. Go to [Discord](https://discordapp.com/invite/NtAbbGn) or a [GitHub issue](https://github.com/nushell/nushell/issues/new/choose) and chat with some core team members and/or other contributors about it.
|
||||||
3. After getting a green light from the core team, implement the feature, open a pull request (PR) and write a concise but comprehensive description of the change.
|
3. After getting a green light from the core team, implement the feature, open a pull request (PR) and write a concise but comprehensive description of the change.
|
||||||
4. If your PR includes any use-facing features (such as adding a flag to a command), clearly list them in the PR description.
|
4. If your PR includes any user-facing features (such as adding a flag to a command), clearly list them in the PR description.
|
||||||
5. Then, core team members and other regular contributors will review the PR and suggest changes.
|
5. Then, core team members and other regular contributors will review the PR and suggest changes.
|
||||||
6. When we all agree, the PR will be merged.
|
6. When we all agree, the PR will be merged.
|
||||||
7. If your PR includes any user-facing features, make sure the changes are also reflected in [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged.
|
7. If your PR includes any user-facing features, make sure the changes are also reflected in [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged.
|
||||||
|
551
Cargo.lock
generated
551
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
69
Cargo.toml
69
Cargo.toml
@ -4,14 +4,14 @@ build = "scripts/build.rs"
|
|||||||
default-run = "nu"
|
default-run = "nu"
|
||||||
description = "A new type of shell"
|
description = "A new type of shell"
|
||||||
documentation = "https://www.nushell.sh/book/"
|
documentation = "https://www.nushell.sh/book/"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
exclude = ["images"]
|
exclude = ["images"]
|
||||||
homepage = "https://www.nushell.sh"
|
homepage = "https://www.nushell.sh"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu"
|
name = "nu"
|
||||||
repository = "https://github.com/nushell/nushell"
|
repository = "https://github.com/nushell/nushell"
|
||||||
rust-version = "1.84.1"
|
rust-version = "1.85.1"
|
||||||
version = "0.104.0"
|
version = "0.105.1"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@ -66,12 +66,12 @@ alphanumeric-sort = "1.5"
|
|||||||
ansi-str = "0.8"
|
ansi-str = "0.8"
|
||||||
anyhow = "1.0.82"
|
anyhow = "1.0.82"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
bracoxide = "0.1.5"
|
bracoxide = "0.1.6"
|
||||||
brotli = "7.0"
|
brotli = "7.0"
|
||||||
byteorder = "1.5"
|
byteorder = "1.5"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
bytesize = "1.3.3"
|
bytesize = "1.3.3"
|
||||||
calamine = "0.27"
|
calamine = "0.26"
|
||||||
chardetng = "0.1.17"
|
chardetng = "0.1.17"
|
||||||
chrono = { default-features = false, version = "0.4.34" }
|
chrono = { default-features = false, version = "0.4.34" }
|
||||||
chrono-humanize = "0.2.3"
|
chrono-humanize = "0.2.3"
|
||||||
@ -96,18 +96,18 @@ indexmap = "2.9"
|
|||||||
indicatif = "0.17"
|
indicatif = "0.17"
|
||||||
interprocess = "2.2.0"
|
interprocess = "2.2.0"
|
||||||
is_executable = "1.0"
|
is_executable = "1.0"
|
||||||
itertools = "0.13"
|
itertools = "0.14"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
libproc = "0.14"
|
libproc = "0.14"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
lru = "0.12"
|
lru = "0.12"
|
||||||
lscolors = { version = "0.17", default-features = false }
|
lscolors = { version = "0.20", default-features = false }
|
||||||
lsp-server = "0.7.8"
|
lsp-server = "0.7.8"
|
||||||
lsp-types = { version = "0.97.0", features = ["proposed"] }
|
lsp-types = { version = "0.97.0", features = ["proposed"] }
|
||||||
lsp-textdocument = "0.4.2"
|
lsp-textdocument = "0.4.2"
|
||||||
mach2 = "0.4"
|
mach2 = "0.4"
|
||||||
md5 = { version = "0.10", package = "md-5" }
|
md5 = { version = "0.10", package = "md-5" }
|
||||||
miette = "7.5"
|
miette = "7.6"
|
||||||
mime = "0.3.17"
|
mime = "0.3.17"
|
||||||
mime_guess = "2.0"
|
mime_guess = "2.0"
|
||||||
mockito = { version = "1.7", default-features = false }
|
mockito = { version = "1.7", default-features = false }
|
||||||
@ -133,7 +133,7 @@ procfs = "0.17.0"
|
|||||||
pwd = "1.3"
|
pwd = "1.3"
|
||||||
quick-xml = "0.37.0"
|
quick-xml = "0.37.0"
|
||||||
quickcheck = "1.0"
|
quickcheck = "1.0"
|
||||||
quickcheck_macros = "1.0"
|
quickcheck_macros = "1.1"
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
rand = "0.9"
|
rand = "0.9"
|
||||||
getrandom = "0.2" # pick same version that rand requires
|
getrandom = "0.2" # pick same version that rand requires
|
||||||
@ -148,6 +148,8 @@ rstest = { version = "0.23", default-features = false }
|
|||||||
rstest_reuse = "0.7"
|
rstest_reuse = "0.7"
|
||||||
rusqlite = "0.31"
|
rusqlite = "0.31"
|
||||||
rust-embed = "8.7.0"
|
rust-embed = "8.7.0"
|
||||||
|
rustls = { version = "0.23", default-features = false, features = ["std", "tls12"] }
|
||||||
|
rustls-native-certs = "0.8"
|
||||||
scopeguard = { version = "1.2.0" }
|
scopeguard = { version = "1.2.0" }
|
||||||
serde = { version = "1.0" }
|
serde = { version = "1.0" }
|
||||||
serde_json = "1.0.97"
|
serde_json = "1.0.97"
|
||||||
@ -159,12 +161,12 @@ strum = "0.26"
|
|||||||
strum_macros = "0.26"
|
strum_macros = "0.26"
|
||||||
syn = "2.0"
|
syn = "2.0"
|
||||||
sysinfo = "0.33"
|
sysinfo = "0.33"
|
||||||
tabled = { version = "0.17.0", default-features = false }
|
tabled = { version = "0.20", default-features = false }
|
||||||
tempfile = "3.15"
|
tempfile = "3.20"
|
||||||
titlecase = "3.5"
|
titlecase = "3.5"
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
trash = "5.2"
|
trash = "5.2"
|
||||||
update-informer = { version = "1.2.0", default-features = false, features = ["github", "native-tls", "ureq"] }
|
update-informer = { version = "1.2.0", default-features = false, features = ["github", "ureq"] }
|
||||||
umask = "2.1"
|
umask = "2.1"
|
||||||
unicode-segmentation = "1.12"
|
unicode-segmentation = "1.12"
|
||||||
unicode-width = "0.2"
|
unicode-width = "0.2"
|
||||||
@ -187,6 +189,7 @@ windows = "0.56"
|
|||||||
windows-sys = "0.48"
|
windows-sys = "0.48"
|
||||||
winreg = "0.52"
|
winreg = "0.52"
|
||||||
memchr = "2.7.4"
|
memchr = "2.7.4"
|
||||||
|
webpki-roots = "1.0"
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
# Warning: workspace lints affect library code as well as tests, so don't enable lints that would be too noisy in tests like that.
|
# Warning: workspace lints affect library code as well as tests, so don't enable lints that would be too noisy in tests like that.
|
||||||
@ -197,22 +200,22 @@ unchecked_duration_subtraction = "warn"
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-cli = { path = "./crates/nu-cli", version = "0.104.0" }
|
nu-cli = { path = "./crates/nu-cli", version = "0.105.1" }
|
||||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.104.0" }
|
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.105.1" }
|
||||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.104.0" }
|
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.105.1" }
|
||||||
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.104.0", optional = true }
|
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.105.1", optional = true }
|
||||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.104.0" }
|
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.105.1" }
|
||||||
nu-command = { path = "./crates/nu-command", version = "0.104.0" }
|
nu-command = { path = "./crates/nu-command", version = "0.105.1", default-features = false, features = ["os"] }
|
||||||
nu-engine = { path = "./crates/nu-engine", version = "0.104.0" }
|
nu-engine = { path = "./crates/nu-engine", version = "0.105.1" }
|
||||||
nu-explore = { path = "./crates/nu-explore", version = "0.104.0" }
|
nu-explore = { path = "./crates/nu-explore", version = "0.105.1" }
|
||||||
nu-lsp = { path = "./crates/nu-lsp/", version = "0.104.0" }
|
nu-lsp = { path = "./crates/nu-lsp/", version = "0.105.1" }
|
||||||
nu-parser = { path = "./crates/nu-parser", version = "0.104.0" }
|
nu-parser = { path = "./crates/nu-parser", version = "0.105.1" }
|
||||||
nu-path = { path = "./crates/nu-path", version = "0.104.0" }
|
nu-path = { path = "./crates/nu-path", version = "0.105.1" }
|
||||||
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.104.0" }
|
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.105.1" }
|
||||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.104.0" }
|
nu-protocol = { path = "./crates/nu-protocol", version = "0.105.1" }
|
||||||
nu-std = { path = "./crates/nu-std", version = "0.104.0" }
|
nu-std = { path = "./crates/nu-std", version = "0.105.1" }
|
||||||
nu-system = { path = "./crates/nu-system", version = "0.104.0" }
|
nu-system = { path = "./crates/nu-system", version = "0.105.1" }
|
||||||
nu-utils = { path = "./crates/nu-utils", version = "0.104.0" }
|
nu-utils = { path = "./crates/nu-utils", version = "0.105.1" }
|
||||||
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
|
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
|
||||||
|
|
||||||
crossterm = { workspace = true }
|
crossterm = { workspace = true }
|
||||||
@ -241,9 +244,9 @@ nix = { workspace = true, default-features = false, features = [
|
|||||||
] }
|
] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.104.0" }
|
nu-test-support = { path = "./crates/nu-test-support", version = "0.105.1" }
|
||||||
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.104.0" }
|
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.105.1" }
|
||||||
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.104.0" }
|
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.105.1" }
|
||||||
assert_cmd = "2.0"
|
assert_cmd = "2.0"
|
||||||
dirs = { workspace = true }
|
dirs = { workspace = true }
|
||||||
tango-bench = "0.6"
|
tango-bench = "0.6"
|
||||||
@ -269,10 +272,14 @@ plugin = [
|
|||||||
"nu-protocol/plugin",
|
"nu-protocol/plugin",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
native-tls = ["nu-command/native-tls"]
|
||||||
|
rustls-tls = ["nu-command/rustls-tls"]
|
||||||
|
|
||||||
default = [
|
default = [
|
||||||
"plugin",
|
"plugin",
|
||||||
"trash-support",
|
"trash-support",
|
||||||
"sqlite",
|
"sqlite",
|
||||||
|
"rustls-tls"
|
||||||
]
|
]
|
||||||
stable = ["default"]
|
stable = ["default"]
|
||||||
# NOTE: individual features are also passed to `nu-cmd-lang` that uses them to generate the feature matrix in the `version` command
|
# NOTE: individual features are also passed to `nu-cmd-lang` that uses them to generate the feature matrix in the `version` command
|
||||||
|
@ -222,6 +222,7 @@ Please submit an issue or PR to be added to this list.
|
|||||||
- [Dorothy](http://github.com/bevry/dorothy)
|
- [Dorothy](http://github.com/bevry/dorothy)
|
||||||
- [Direnv](https://github.com/direnv/direnv/blob/master/docs/hook.md#nushell)
|
- [Direnv](https://github.com/direnv/direnv/blob/master/docs/hook.md#nushell)
|
||||||
- [x-cmd](https://x-cmd.com/mod/nu)
|
- [x-cmd](https://x-cmd.com/mod/nu)
|
||||||
|
- [vfox](https://github.com/version-fox/vfox)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ use nu_cli::{eval_source, evaluate_commands};
|
|||||||
use nu_plugin_core::{Encoder, EncodingType};
|
use nu_plugin_core::{Encoder, EncodingType};
|
||||||
use nu_plugin_protocol::{PluginCallResponse, PluginOutput};
|
use nu_plugin_protocol::{PluginCallResponse, PluginOutput};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{EngineState, Stack},
|
|
||||||
PipelineData, Signals, Span, Spanned, Value,
|
PipelineData, Signals, Span, Spanned, Value,
|
||||||
|
engine::{EngineState, Stack},
|
||||||
};
|
};
|
||||||
use nu_std::load_standard_library;
|
use nu_std::load_standard_library;
|
||||||
use nu_utils::{get_default_config, get_default_env};
|
use nu_utils::{get_default_config, get_default_env};
|
||||||
@ -11,9 +11,9 @@ use std::{
|
|||||||
fmt::Write,
|
fmt::Write,
|
||||||
hint::black_box,
|
hint::black_box,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{atomic::AtomicBool, Arc},
|
sync::{Arc, atomic::AtomicBool},
|
||||||
};
|
};
|
||||||
use tango_bench::{benchmark_fn, tango_benchmarks, tango_main, IntoBenchmarks};
|
use tango_bench::{IntoBenchmarks, benchmark_fn, tango_benchmarks, tango_main};
|
||||||
|
|
||||||
fn load_bench_commands() -> EngineState {
|
fn load_bench_commands() -> EngineState {
|
||||||
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context())
|
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context())
|
||||||
@ -68,14 +68,14 @@ fn encoding_test_data(row_cnt: usize, col_cnt: usize) -> Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn bench_command(
|
fn bench_command(
|
||||||
name: &str,
|
name: impl Into<String>,
|
||||||
command: &str,
|
command: impl Into<String> + Clone,
|
||||||
stack: Stack,
|
stack: Stack,
|
||||||
engine: EngineState,
|
engine: EngineState,
|
||||||
) -> impl IntoBenchmarks {
|
) -> impl IntoBenchmarks {
|
||||||
let commands = Spanned {
|
let commands = Spanned {
|
||||||
span: Span::unknown(),
|
span: Span::unknown(),
|
||||||
item: command.to_string(),
|
item: command.into(),
|
||||||
};
|
};
|
||||||
[benchmark_fn(name, move |b| {
|
[benchmark_fn(name, move |b| {
|
||||||
let commands = commands.clone();
|
let commands = commands.clone();
|
||||||
@ -175,8 +175,8 @@ fn create_example_table_nrows(n: usize) -> String {
|
|||||||
|
|
||||||
fn bench_record_create(n: usize) -> impl IntoBenchmarks {
|
fn bench_record_create(n: usize) -> impl IntoBenchmarks {
|
||||||
bench_command(
|
bench_command(
|
||||||
&format!("record_create_{n}"),
|
format!("record_create_{n}"),
|
||||||
&create_flat_record_string(n),
|
create_flat_record_string(n),
|
||||||
Stack::new(),
|
Stack::new(),
|
||||||
setup_engine(),
|
setup_engine(),
|
||||||
)
|
)
|
||||||
@ -186,7 +186,7 @@ fn bench_record_flat_access(n: usize) -> impl IntoBenchmarks {
|
|||||||
let setup_command = create_flat_record_string(n);
|
let setup_command = create_flat_record_string(n);
|
||||||
let (stack, engine) = setup_stack_and_engine_from_command(&setup_command);
|
let (stack, engine) = setup_stack_and_engine_from_command(&setup_command);
|
||||||
bench_command(
|
bench_command(
|
||||||
&format!("record_flat_access_{n}"),
|
format!("record_flat_access_{n}"),
|
||||||
"$record.col_0 | ignore",
|
"$record.col_0 | ignore",
|
||||||
stack,
|
stack,
|
||||||
engine,
|
engine,
|
||||||
@ -198,8 +198,8 @@ fn bench_record_nested_access(n: usize) -> impl IntoBenchmarks {
|
|||||||
let (stack, engine) = setup_stack_and_engine_from_command(&setup_command);
|
let (stack, engine) = setup_stack_and_engine_from_command(&setup_command);
|
||||||
let nested_access = ".col".repeat(n);
|
let nested_access = ".col".repeat(n);
|
||||||
bench_command(
|
bench_command(
|
||||||
&format!("record_nested_access_{n}"),
|
format!("record_nested_access_{n}"),
|
||||||
&format!("$record{} | ignore", nested_access),
|
format!("$record{} | ignore", nested_access),
|
||||||
stack,
|
stack,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
@ -213,13 +213,13 @@ fn bench_record_insert(n: usize, m: usize) -> impl IntoBenchmarks {
|
|||||||
write!(insert, " | insert col_{i} {i}").unwrap();
|
write!(insert, " | insert col_{i} {i}").unwrap();
|
||||||
}
|
}
|
||||||
insert.push_str(" | ignore");
|
insert.push_str(" | ignore");
|
||||||
bench_command(&format!("record_insert_{n}_{m}"), &insert, stack, engine)
|
bench_command(format!("record_insert_{n}_{m}"), insert, stack, engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_table_create(n: usize) -> impl IntoBenchmarks {
|
fn bench_table_create(n: usize) -> impl IntoBenchmarks {
|
||||||
bench_command(
|
bench_command(
|
||||||
&format!("table_create_{n}"),
|
format!("table_create_{n}"),
|
||||||
&create_example_table_nrows(n),
|
create_example_table_nrows(n),
|
||||||
Stack::new(),
|
Stack::new(),
|
||||||
setup_engine(),
|
setup_engine(),
|
||||||
)
|
)
|
||||||
@ -229,7 +229,7 @@ fn bench_table_get(n: usize) -> impl IntoBenchmarks {
|
|||||||
let setup_command = create_example_table_nrows(n);
|
let setup_command = create_example_table_nrows(n);
|
||||||
let (stack, engine) = setup_stack_and_engine_from_command(&setup_command);
|
let (stack, engine) = setup_stack_and_engine_from_command(&setup_command);
|
||||||
bench_command(
|
bench_command(
|
||||||
&format!("table_get_{n}"),
|
format!("table_get_{n}"),
|
||||||
"$table | get bar | math sum | ignore",
|
"$table | get bar | math sum | ignore",
|
||||||
stack,
|
stack,
|
||||||
engine,
|
engine,
|
||||||
@ -240,7 +240,7 @@ fn bench_table_select(n: usize) -> impl IntoBenchmarks {
|
|||||||
let setup_command = create_example_table_nrows(n);
|
let setup_command = create_example_table_nrows(n);
|
||||||
let (stack, engine) = setup_stack_and_engine_from_command(&setup_command);
|
let (stack, engine) = setup_stack_and_engine_from_command(&setup_command);
|
||||||
bench_command(
|
bench_command(
|
||||||
&format!("table_select_{n}"),
|
format!("table_select_{n}"),
|
||||||
"$table | select foo baz | ignore",
|
"$table | select foo baz | ignore",
|
||||||
stack,
|
stack,
|
||||||
engine,
|
engine,
|
||||||
@ -255,7 +255,7 @@ fn bench_table_insert_row(n: usize, m: usize) -> impl IntoBenchmarks {
|
|||||||
write!(insert, " | insert {i} {{ foo: 0, bar: 1, baz: {i} }}").unwrap();
|
write!(insert, " | insert {i} {{ foo: 0, bar: 1, baz: {i} }}").unwrap();
|
||||||
}
|
}
|
||||||
insert.push_str(" | ignore");
|
insert.push_str(" | ignore");
|
||||||
bench_command(&format!("table_insert_row_{n}_{m}"), &insert, stack, engine)
|
bench_command(format!("table_insert_row_{n}_{m}"), insert, stack, engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_table_insert_col(n: usize, m: usize) -> impl IntoBenchmarks {
|
fn bench_table_insert_col(n: usize, m: usize) -> impl IntoBenchmarks {
|
||||||
@ -266,15 +266,15 @@ fn bench_table_insert_col(n: usize, m: usize) -> impl IntoBenchmarks {
|
|||||||
write!(insert, " | insert col_{i} {i}").unwrap();
|
write!(insert, " | insert col_{i} {i}").unwrap();
|
||||||
}
|
}
|
||||||
insert.push_str(" | ignore");
|
insert.push_str(" | ignore");
|
||||||
bench_command(&format!("table_insert_col_{n}_{m}"), &insert, stack, engine)
|
bench_command(format!("table_insert_col_{n}_{m}"), insert, stack, engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_eval_interleave(n: usize) -> impl IntoBenchmarks {
|
fn bench_eval_interleave(n: usize) -> impl IntoBenchmarks {
|
||||||
let engine = setup_engine();
|
let engine = setup_engine();
|
||||||
let stack = Stack::new();
|
let stack = Stack::new();
|
||||||
bench_command(
|
bench_command(
|
||||||
&format!("eval_interleave_{n}"),
|
format!("eval_interleave_{n}"),
|
||||||
&format!("seq 1 {n} | wrap a | interleave {{ seq 1 {n} | wrap b }} | ignore"),
|
format!("seq 1 {n} | wrap a | interleave {{ seq 1 {n} | wrap b }} | ignore"),
|
||||||
stack,
|
stack,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
@ -285,8 +285,8 @@ fn bench_eval_interleave_with_interrupt(n: usize) -> impl IntoBenchmarks {
|
|||||||
engine.set_signals(Signals::new(Arc::new(AtomicBool::new(false))));
|
engine.set_signals(Signals::new(Arc::new(AtomicBool::new(false))));
|
||||||
let stack = Stack::new();
|
let stack = Stack::new();
|
||||||
bench_command(
|
bench_command(
|
||||||
&format!("eval_interleave_with_interrupt_{n}"),
|
format!("eval_interleave_with_interrupt_{n}"),
|
||||||
&format!("seq 1 {n} | wrap a | interleave {{ seq 1 {n} | wrap b }} | ignore"),
|
format!("seq 1 {n} | wrap a | interleave {{ seq 1 {n} | wrap b }} | ignore"),
|
||||||
stack,
|
stack,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
@ -296,8 +296,8 @@ fn bench_eval_for(n: usize) -> impl IntoBenchmarks {
|
|||||||
let engine = setup_engine();
|
let engine = setup_engine();
|
||||||
let stack = Stack::new();
|
let stack = Stack::new();
|
||||||
bench_command(
|
bench_command(
|
||||||
&format!("eval_for_{n}"),
|
format!("eval_for_{n}"),
|
||||||
&format!("(for $x in (1..{n}) {{ 1 }}) | ignore"),
|
format!("(for $x in (1..{n}) {{ 1 }}) | ignore"),
|
||||||
stack,
|
stack,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
@ -307,8 +307,8 @@ fn bench_eval_each(n: usize) -> impl IntoBenchmarks {
|
|||||||
let engine = setup_engine();
|
let engine = setup_engine();
|
||||||
let stack = Stack::new();
|
let stack = Stack::new();
|
||||||
bench_command(
|
bench_command(
|
||||||
&format!("eval_each_{n}"),
|
format!("eval_each_{n}"),
|
||||||
&format!("(1..{n}) | each {{|_| 1 }} | ignore"),
|
format!("(1..{n}) | each {{|_| 1 }} | ignore"),
|
||||||
stack,
|
stack,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
@ -318,8 +318,8 @@ fn bench_eval_par_each(n: usize) -> impl IntoBenchmarks {
|
|||||||
let engine = setup_engine();
|
let engine = setup_engine();
|
||||||
let stack = Stack::new();
|
let stack = Stack::new();
|
||||||
bench_command(
|
bench_command(
|
||||||
&format!("eval_par_each_{n}"),
|
format!("eval_par_each_{n}"),
|
||||||
&format!("(1..{}) | par-each -t 2 {{|_| 1 }} | ignore", n),
|
format!("(1..{}) | par-each -t 2 {{|_| 1 }} | ignore", n),
|
||||||
stack,
|
stack,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
|
@ -2,32 +2,32 @@
|
|||||||
authors = ["The Nushell Project Developers"]
|
authors = ["The Nushell Project Developers"]
|
||||||
description = "CLI-related functionality for Nushell"
|
description = "CLI-related functionality for Nushell"
|
||||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
|
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-cli"
|
name = "nu-cli"
|
||||||
version = "0.104.0"
|
version = "0.105.1"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
bench = false
|
bench = false
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.104.0" }
|
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.105.1" }
|
||||||
nu-command = { path = "../nu-command", version = "0.104.0" }
|
nu-command = { path = "../nu-command", version = "0.105.1" }
|
||||||
nu-std = { path = "../nu-std", version = "0.104.0" }
|
nu-std = { path = "../nu-std", version = "0.105.1" }
|
||||||
nu-test-support = { path = "../nu-test-support", version = "0.104.0" }
|
nu-test-support = { path = "../nu-test-support", version = "0.105.1" }
|
||||||
rstest = { workspace = true, default-features = false }
|
rstest = { workspace = true, default-features = false }
|
||||||
tempfile = { workspace = true }
|
tempfile = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.104.0" }
|
nu-cmd-base = { path = "../nu-cmd-base", version = "0.105.1" }
|
||||||
nu-engine = { path = "../nu-engine", version = "0.104.0", features = ["os"] }
|
nu-engine = { path = "../nu-engine", version = "0.105.1", features = ["os"] }
|
||||||
nu-glob = { path = "../nu-glob", version = "0.104.0" }
|
nu-glob = { path = "../nu-glob", version = "0.105.1" }
|
||||||
nu-path = { path = "../nu-path", version = "0.104.0" }
|
nu-path = { path = "../nu-path", version = "0.105.1" }
|
||||||
nu-parser = { path = "../nu-parser", version = "0.104.0" }
|
nu-parser = { path = "../nu-parser", version = "0.105.1" }
|
||||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.104.0", optional = true }
|
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.105.1", optional = true }
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.104.0", features = ["os"] }
|
nu-protocol = { path = "../nu-protocol", version = "0.105.1", features = ["os"] }
|
||||||
nu-utils = { path = "../nu-utils", version = "0.104.0" }
|
nu-utils = { path = "../nu-utils", version = "0.105.1" }
|
||||||
nu-color-config = { path = "../nu-color-config", version = "0.104.0" }
|
nu-color-config = { path = "../nu-color-config", version = "0.105.1" }
|
||||||
nu-ansi-term = { workspace = true }
|
nu-ansi-term = { workspace = true }
|
||||||
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
|
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::{shell_error::io::IoError, HistoryFileFormat};
|
use nu_protocol::{
|
||||||
|
HistoryFileFormat,
|
||||||
|
shell_error::{self, io::IoError},
|
||||||
|
};
|
||||||
use reedline::{
|
use reedline::{
|
||||||
FileBackedHistory, History as ReedlineHistory, HistoryItem, SearchDirection, SearchQuery,
|
FileBackedHistory, History as ReedlineHistory, HistoryItem, SearchDirection, SearchQuery,
|
||||||
SqliteBackedHistory,
|
SqliteBackedHistory,
|
||||||
@ -94,7 +97,7 @@ impl Command for History {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.ok_or(IoError::new(
|
.ok_or(IoError::new(
|
||||||
std::io::ErrorKind::NotFound,
|
shell_error::io::ErrorKind::FileNotFound,
|
||||||
head,
|
head,
|
||||||
history_path,
|
history_path,
|
||||||
))?
|
))?
|
||||||
@ -110,7 +113,7 @@ impl Command for History {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.ok_or(IoError::new(
|
.ok_or(IoError::new(
|
||||||
std::io::ErrorKind::NotFound,
|
shell_error::io::ErrorKind::FileNotFound,
|
||||||
head,
|
head,
|
||||||
history_path,
|
history_path,
|
||||||
))?
|
))?
|
||||||
|
@ -2,8 +2,8 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
shell_error::{self, io::IoError},
|
|
||||||
HistoryFileFormat,
|
HistoryFileFormat,
|
||||||
|
shell_error::{self, io::IoError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use reedline::{
|
use reedline::{
|
||||||
@ -26,7 +26,7 @@ impl Command for HistoryImport {
|
|||||||
|
|
||||||
fn extra_description(&self) -> &str {
|
fn extra_description(&self) -> &str {
|
||||||
r#"Can import history from input, either successive command lines or more detailed records. If providing records, available fields are:
|
r#"Can import history from input, either successive command lines or more detailed records. If providing records, available fields are:
|
||||||
command_line, id, start_timestamp, hostname, cwd, duration, exit_status.
|
command, start_timestamp, hostname, cwd, duration, exit_status.
|
||||||
|
|
||||||
If no input is provided, will import all history items from existing history in the other format: if current history is stored in sqlite, it will store it in plain text and vice versa.
|
If no input is provided, will import all history items from existing history in the other format: if current history is stored in sqlite, it will store it in plain text and vice versa.
|
||||||
|
|
||||||
@ -48,8 +48,7 @@ Note that history item IDs are ignored when importing from file."#
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
example: "history import",
|
example: "history import",
|
||||||
description:
|
description: "Append all items from history in the other format to the current history",
|
||||||
"Append all items from history in the other format to the current history",
|
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
@ -198,7 +197,7 @@ fn item_from_record(mut rec: Record, span: Span) -> Result<HistoryItem, ShellErr
|
|||||||
return Err(ShellError::TypeMismatch {
|
return Err(ShellError::TypeMismatch {
|
||||||
err_message: format!("missing column: {}", fields::COMMAND_LINE),
|
err_message: format!("missing column: {}", fields::COMMAND_LINE),
|
||||||
span,
|
span,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -283,22 +282,22 @@ fn backup(path: &Path, span: Span) -> Result<Option<PathBuf>, ShellError> {
|
|||||||
PathBuf::from(path),
|
PathBuf::from(path),
|
||||||
"history path exists but is not a file",
|
"history path exists but is not a file",
|
||||||
)
|
)
|
||||||
.into())
|
.into());
|
||||||
}
|
}
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None),
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(IoError::new_internal(
|
return Err(IoError::new_internal(
|
||||||
e.kind(),
|
e,
|
||||||
"Could not get metadata",
|
"Could not get metadata",
|
||||||
nu_protocol::location!(),
|
nu_protocol::location!(),
|
||||||
)
|
)
|
||||||
.into())
|
.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let bak_path = find_backup_path(path, span)?;
|
let bak_path = find_backup_path(path, span)?;
|
||||||
std::fs::copy(path, &bak_path).map_err(|err| {
|
std::fs::copy(path, &bak_path).map_err(|err| {
|
||||||
IoError::new_internal(
|
IoError::new_internal(
|
||||||
err.kind(),
|
err.not_found_as(NotFound::File),
|
||||||
"Could not copy backup",
|
"Could not copy backup",
|
||||||
nu_protocol::location!(),
|
nu_protocol::location!(),
|
||||||
)
|
)
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::Event, event::KeyCode, event::KeyEvent, execute, terminal, QueueableCommand,
|
QueueableCommand, event::Event, event::KeyCode, event::KeyEvent, execute, terminal,
|
||||||
};
|
};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::shell_error::io::IoError;
|
use nu_protocol::shell_error::io::IoError;
|
||||||
use std::io::{stdout, Write};
|
use std::io::{Write, stdout};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct KeybindingsListen;
|
pub struct KeybindingsListen;
|
||||||
@ -42,7 +42,7 @@ impl Command for KeybindingsListen {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
terminal::disable_raw_mode().map_err(|err| {
|
terminal::disable_raw_mode().map_err(|err| {
|
||||||
IoError::new_internal(
|
IoError::new_internal(
|
||||||
err.kind(),
|
err,
|
||||||
"Could not disable raw mode",
|
"Could not disable raw mode",
|
||||||
nu_protocol::location!(),
|
nu_protocol::location!(),
|
||||||
)
|
)
|
||||||
@ -71,18 +71,10 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
|
|||||||
let config = engine_state.get_config();
|
let config = engine_state.get_config();
|
||||||
|
|
||||||
stdout().flush().map_err(|err| {
|
stdout().flush().map_err(|err| {
|
||||||
IoError::new_internal(
|
IoError::new_internal(err, "Could not flush stdout", nu_protocol::location!())
|
||||||
err.kind(),
|
|
||||||
"Could not flush stdout",
|
|
||||||
nu_protocol::location!(),
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
terminal::enable_raw_mode().map_err(|err| {
|
terminal::enable_raw_mode().map_err(|err| {
|
||||||
IoError::new_internal(
|
IoError::new_internal(err, "Could not enable raw mode", nu_protocol::location!())
|
||||||
err.kind(),
|
|
||||||
"Could not enable raw mode",
|
|
||||||
nu_protocol::location!(),
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if config.use_kitty_protocol {
|
if config.use_kitty_protocol {
|
||||||
@ -114,7 +106,7 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
let event = crossterm::event::read().map_err(|err| {
|
let event = crossterm::event::read().map_err(|err| {
|
||||||
IoError::new_internal(err.kind(), "Could not read event", nu_protocol::location!())
|
IoError::new_internal(err, "Could not read event", nu_protocol::location!())
|
||||||
})?;
|
})?;
|
||||||
if event == Event::Key(KeyCode::Esc.into()) {
|
if event == Event::Key(KeyCode::Esc.into()) {
|
||||||
break;
|
break;
|
||||||
@ -136,7 +128,7 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
|
|||||||
};
|
};
|
||||||
stdout.queue(crossterm::style::Print(o)).map_err(|err| {
|
stdout.queue(crossterm::style::Print(o)).map_err(|err| {
|
||||||
IoError::new_internal(
|
IoError::new_internal(
|
||||||
err.kind(),
|
err,
|
||||||
"Could not print output record",
|
"Could not print output record",
|
||||||
nu_protocol::location!(),
|
nu_protocol::location!(),
|
||||||
)
|
)
|
||||||
@ -144,14 +136,10 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
|
|||||||
stdout
|
stdout
|
||||||
.queue(crossterm::style::Print("\r\n"))
|
.queue(crossterm::style::Print("\r\n"))
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
IoError::new_internal(
|
IoError::new_internal(err, "Could not print linebreak", nu_protocol::location!())
|
||||||
err.kind(),
|
|
||||||
"Could not print linebreak",
|
|
||||||
nu_protocol::location!(),
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
stdout.flush().map_err(|err| {
|
stdout.flush().map_err(|err| {
|
||||||
IoError::new_internal(err.kind(), "Could not flush", nu_protocol::location!())
|
IoError::new_internal(err, "Could not flush", nu_protocol::location!())
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,11 +151,7 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
terminal::disable_raw_mode().map_err(|err| {
|
terminal::disable_raw_mode().map_err(|err| {
|
||||||
IoError::new_internal(
|
IoError::new_internal(err, "Could not disable raw mode", nu_protocol::location!())
|
||||||
err.kind(),
|
|
||||||
"Could not disable raw mode",
|
|
||||||
nu_protocol::location!(),
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(Value::nothing(Span::unknown()))
|
Ok(Value::nothing(Span::unknown()))
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use super::{completion_options::NuMatcher, SemanticSuggestion};
|
use super::{SemanticSuggestion, completion_options::NuMatcher};
|
||||||
use crate::{
|
use crate::{
|
||||||
completions::{Completer, CompletionOptions},
|
|
||||||
SuggestionKind,
|
SuggestionKind,
|
||||||
|
completions::{Completer, CompletionOptions},
|
||||||
};
|
};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{Stack, StateWorkingSet},
|
|
||||||
Span,
|
Span,
|
||||||
|
engine::{Stack, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
|
|
||||||
@ -33,13 +33,12 @@ impl Completer for AttributeCompletion {
|
|||||||
suggestion: Suggestion {
|
suggestion: Suggestion {
|
||||||
value: String::from_utf8_lossy(name).into_owned(),
|
value: String::from_utf8_lossy(name).into_owned(),
|
||||||
description: desc,
|
description: desc,
|
||||||
style: None,
|
|
||||||
extra: None,
|
|
||||||
span: reedline::Span {
|
span: reedline::Span {
|
||||||
start: span.start - offset,
|
start: span.start - offset,
|
||||||
end: span.end - offset,
|
end: span.end - offset,
|
||||||
},
|
},
|
||||||
append_whitespace: false,
|
append_whitespace: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
kind: Some(SuggestionKind::Command(ty, Some(decl_id))),
|
kind: Some(SuggestionKind::Command(ty, Some(decl_id))),
|
||||||
});
|
});
|
||||||
@ -70,13 +69,12 @@ impl Completer for AttributableCompletion {
|
|||||||
suggestion: Suggestion {
|
suggestion: Suggestion {
|
||||||
value: cmd.name().into(),
|
value: cmd.name().into(),
|
||||||
description: Some(cmd.description().into()),
|
description: Some(cmd.description().into()),
|
||||||
style: None,
|
|
||||||
extra: None,
|
|
||||||
span: reedline::Span {
|
span: reedline::Span {
|
||||||
start: span.start - offset,
|
start: span.start - offset,
|
||||||
end: span.end - offset,
|
end: span.end - offset,
|
||||||
},
|
},
|
||||||
append_whitespace: false,
|
append_whitespace: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
kind: Some(SuggestionKind::Command(cmd.command_type(), None)),
|
kind: Some(SuggestionKind::Command(cmd.command_type(), None)),
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::completions::CompletionOptions;
|
use crate::completions::CompletionOptions;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{Stack, StateWorkingSet},
|
|
||||||
DeclId, Span,
|
DeclId, Span,
|
||||||
|
engine::{Stack, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::completions::{Completer, CompletionOptions, SemanticSuggestion, SuggestionKind};
|
use crate::completions::{Completer, CompletionOptions, SemanticSuggestion, SuggestionKind};
|
||||||
use nu_engine::{column::get_columns, eval_variable};
|
use nu_engine::{column::get_columns, eval_variable};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
ShellError, Span, Value,
|
||||||
ast::{Expr, Expression, FullCellPath, PathMember},
|
ast::{Expr, Expression, FullCellPath, PathMember},
|
||||||
engine::{Stack, StateWorkingSet},
|
engine::{Stack, StateWorkingSet},
|
||||||
eval_const::eval_constant,
|
eval_const::eval_constant,
|
||||||
ShellError, Span, Value,
|
|
||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
|
|
||||||
@ -101,7 +103,9 @@ pub(crate) fn eval_cell_path(
|
|||||||
} else {
|
} else {
|
||||||
eval_constant(working_set, head)
|
eval_constant(working_set, head)
|
||||||
}?;
|
}?;
|
||||||
head_value.follow_cell_path(path_members, false)
|
head_value
|
||||||
|
.follow_cell_path(path_members)
|
||||||
|
.map(Cow::into_owned)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_suggestions_by_value(
|
fn get_suggestions_by_value(
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
completions::{Completer, CompletionOptions},
|
|
||||||
SuggestionKind,
|
SuggestionKind,
|
||||||
|
completions::{Completer, CompletionOptions},
|
||||||
};
|
};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{CommandType, Stack, StateWorkingSet},
|
|
||||||
Span,
|
Span,
|
||||||
|
engine::{CommandType, Stack, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
|
|
||||||
use super::{completion_options::NuMatcher, SemanticSuggestion};
|
use super::{SemanticSuggestion, completion_options::NuMatcher};
|
||||||
|
|
||||||
pub struct CommandCompletion {
|
pub struct CommandCompletion {
|
||||||
/// Whether to include internal commands
|
/// Whether to include internal commands
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
use crate::completions::{
|
use crate::completions::{
|
||||||
base::{SemanticSuggestion, SuggestionKind},
|
|
||||||
AttributableCompletion, AttributeCompletion, CellPathCompletion, CommandCompletion, Completer,
|
AttributableCompletion, AttributeCompletion, CellPathCompletion, CommandCompletion, Completer,
|
||||||
CompletionOptions, CustomCompletion, DirectoryCompletion, DotNuCompletion,
|
CompletionOptions, CustomCompletion, DirectoryCompletion, DotNuCompletion,
|
||||||
ExportableCompletion, FileCompletion, FlagCompletion, OperatorCompletion, VariableCompletion,
|
ExportableCompletion, FileCompletion, FlagCompletion, OperatorCompletion, VariableCompletion,
|
||||||
|
base::{SemanticSuggestion, SuggestionKind},
|
||||||
};
|
};
|
||||||
use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
|
use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
|
||||||
use nu_engine::eval_block;
|
use nu_engine::eval_block;
|
||||||
use nu_parser::{flatten_expression, parse, parse_module_file_or_dir};
|
use nu_parser::{flatten_expression, parse, parse_module_file_or_dir};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
PipelineData, Span, Type, Value,
|
||||||
ast::{Argument, Block, Expr, Expression, FindMapResult, ListItem, Traverse},
|
ast::{Argument, Block, Expr, Expression, FindMapResult, ListItem, Traverse},
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
||||||
PipelineData, Span, Type, Value,
|
|
||||||
};
|
};
|
||||||
use reedline::{Completer as ReedlineCompleter, Suggestion};
|
use reedline::{Completer as ReedlineCompleter, Suggestion};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
use super::{completion_options::NuMatcher, MatchAlgorithm};
|
use super::{MatchAlgorithm, completion_options::NuMatcher};
|
||||||
use crate::completions::CompletionOptions;
|
use crate::completions::CompletionOptions;
|
||||||
use nu_ansi_term::Style;
|
use nu_ansi_term::Style;
|
||||||
use nu_engine::env_to_string;
|
use nu_engine::env_to_string;
|
||||||
use nu_path::dots::expand_ndots;
|
use nu_path::dots::expand_ndots;
|
||||||
use nu_path::{expand_to_real_path, home_dir};
|
use nu_path::{expand_to_real_path, home_dir};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
|
||||||
Span,
|
Span,
|
||||||
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use nu_utils::get_ls_colors;
|
|
||||||
use nu_utils::IgnoreCaseExt;
|
use nu_utils::IgnoreCaseExt;
|
||||||
use std::path::{is_separator, Component, Path, PathBuf, MAIN_SEPARATOR as SEP};
|
use nu_utils::get_ls_colors;
|
||||||
|
use std::path::{Component, MAIN_SEPARATOR as SEP, Path, PathBuf, is_separator};
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct PathBuiltFromString {
|
pub struct PathBuiltFromString {
|
||||||
@ -39,8 +39,10 @@ fn complete_rec(
|
|||||||
isdir: bool,
|
isdir: bool,
|
||||||
enable_exact_match: bool,
|
enable_exact_match: bool,
|
||||||
) -> Vec<PathBuiltFromString> {
|
) -> Vec<PathBuiltFromString> {
|
||||||
|
let has_more = !partial.is_empty() && (partial.len() > 1 || isdir);
|
||||||
|
|
||||||
if let Some((&base, rest)) = partial.split_first() {
|
if let Some((&base, rest)) = partial.split_first() {
|
||||||
if base.chars().all(|c| c == '.') && (isdir || !rest.is_empty()) {
|
if base.chars().all(|c| c == '.') && has_more {
|
||||||
let built_paths: Vec<_> = built_paths
|
let built_paths: Vec<_> = built_paths
|
||||||
.iter()
|
.iter()
|
||||||
.map(|built| {
|
.map(|built| {
|
||||||
@ -64,6 +66,9 @@ fn complete_rec(
|
|||||||
let prefix = partial.first().unwrap_or(&"");
|
let prefix = partial.first().unwrap_or(&"");
|
||||||
let mut matcher = NuMatcher::new(prefix, options);
|
let mut matcher = NuMatcher::new(prefix, options);
|
||||||
|
|
||||||
|
let mut exact_match = None;
|
||||||
|
// Only relevant for case insensitive matching
|
||||||
|
let mut multiple_exact_matches = false;
|
||||||
for built in built_paths {
|
for built in built_paths {
|
||||||
let mut path = built.cwd.clone();
|
let mut path = built.cwd.clone();
|
||||||
for part in &built.parts {
|
for part in &built.parts {
|
||||||
@ -83,48 +88,56 @@ fn complete_rec(
|
|||||||
built.isdir = entry_isdir && !entry.path().is_symlink();
|
built.isdir = entry_isdir && !entry.path().is_symlink();
|
||||||
|
|
||||||
if !want_directory || entry_isdir {
|
if !want_directory || entry_isdir {
|
||||||
matcher.add(entry_name.clone(), (entry_name, built));
|
if enable_exact_match && !multiple_exact_matches && has_more {
|
||||||
|
let matches = if options.case_sensitive {
|
||||||
|
entry_name.eq(prefix)
|
||||||
|
} else {
|
||||||
|
entry_name.eq_ignore_case(prefix)
|
||||||
|
};
|
||||||
|
if matches {
|
||||||
|
if exact_match.is_none() {
|
||||||
|
exact_match = Some(built.clone());
|
||||||
|
} else {
|
||||||
|
multiple_exact_matches = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut completions = vec![];
|
matcher.add(entry_name, built);
|
||||||
for (entry_name, built) in matcher.results() {
|
}
|
||||||
match partial.split_first() {
|
}
|
||||||
Some((base, rest)) => {
|
}
|
||||||
// We use `isdir` to confirm that the current component has
|
|
||||||
// at least one next component or a slash.
|
// Don't show longer completions if we have a single exact match (#13204, #14794)
|
||||||
// Serves as confirmation to ignore longer completions for
|
if !multiple_exact_matches {
|
||||||
// components in between.
|
if let Some(built) = exact_match {
|
||||||
if !rest.is_empty() || isdir {
|
return complete_rec(
|
||||||
// Don't show longer completions if we have an exact match (#13204, #14794)
|
&partial[1..],
|
||||||
let exact_match = enable_exact_match
|
|
||||||
&& (if options.case_sensitive {
|
|
||||||
entry_name.eq(base)
|
|
||||||
} else {
|
|
||||||
entry_name.eq_ignore_case(base)
|
|
||||||
});
|
|
||||||
completions.extend(complete_rec(
|
|
||||||
rest,
|
|
||||||
&[built],
|
&[built],
|
||||||
options,
|
options,
|
||||||
want_directory,
|
want_directory,
|
||||||
isdir,
|
isdir,
|
||||||
exact_match,
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if has_more {
|
||||||
|
let mut completions = vec![];
|
||||||
|
for built in matcher.results() {
|
||||||
|
completions.extend(complete_rec(
|
||||||
|
&partial[1..],
|
||||||
|
&[built],
|
||||||
|
options,
|
||||||
|
want_directory,
|
||||||
|
isdir,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
if exact_match {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completions.push(built);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
completions.push(built);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
completions
|
completions
|
||||||
|
} else {
|
||||||
|
matcher.results()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -2,8 +2,8 @@ use nu_parser::trim_quotes_str;
|
|||||||
use nu_protocol::{CompletionAlgorithm, CompletionSort};
|
use nu_protocol::{CompletionAlgorithm, CompletionSort};
|
||||||
use nu_utils::IgnoreCaseExt;
|
use nu_utils::IgnoreCaseExt;
|
||||||
use nucleo_matcher::{
|
use nucleo_matcher::{
|
||||||
pattern::{Atom, AtomKind, CaseMatching, Normalization},
|
|
||||||
Config, Matcher, Utf32Str,
|
Config, Matcher, Utf32Str,
|
||||||
|
pattern::{Atom, AtomKind, CaseMatching, Normalization},
|
||||||
};
|
};
|
||||||
use std::{borrow::Cow, fmt::Display};
|
use std::{borrow::Cow, fmt::Display};
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use crate::completions::{
|
use crate::completions::{
|
||||||
completer::map_value_completions, Completer, CompletionOptions, MatchAlgorithm,
|
Completer, CompletionOptions, MatchAlgorithm, SemanticSuggestion,
|
||||||
SemanticSuggestion,
|
completer::map_value_completions,
|
||||||
};
|
};
|
||||||
use nu_engine::eval_call;
|
use nu_engine::eval_call;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
DeclId, PipelineData, Span, Type, Value,
|
||||||
ast::{Argument, Call, Expr, Expression},
|
ast::{Argument, Call, Expr, Expression},
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
DeclId, PipelineData, Span, Type, Value,
|
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@ -106,7 +106,9 @@ impl<T: Completer> Completer for CustomCompletion<T> {
|
|||||||
let positional =
|
let positional =
|
||||||
options.get("positional").and_then(|val| val.as_bool().ok());
|
options.get("positional").and_then(|val| val.as_bool().ok());
|
||||||
if positional.is_some() {
|
if positional.is_some() {
|
||||||
log::warn!("Use of the positional option is deprecated. Use the substring match algorithm instead.");
|
log::warn!(
|
||||||
|
"Use of the positional option is deprecated. Use the substring match algorithm instead."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if let Some(algorithm) = options
|
if let Some(algorithm) = options
|
||||||
.get("completion_algorithm")
|
.get("completion_algorithm")
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
use crate::completions::{
|
use crate::completions::{
|
||||||
completion_common::{adjust_if_intermediate, complete_item, AdjustView},
|
|
||||||
Completer, CompletionOptions,
|
Completer, CompletionOptions,
|
||||||
|
completion_common::{AdjustView, adjust_if_intermediate, complete_item},
|
||||||
};
|
};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
|
||||||
Span,
|
Span,
|
||||||
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use super::{completion_common::FileSuggestion, SemanticSuggestion, SuggestionKind};
|
use super::{SemanticSuggestion, SuggestionKind, completion_common::FileSuggestion};
|
||||||
|
|
||||||
pub struct DirectoryCompletion;
|
pub struct DirectoryCompletion;
|
||||||
|
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
use crate::completions::{
|
use crate::completions::{
|
||||||
completion_common::{surround_remove, FileSuggestion},
|
Completer, CompletionOptions, SemanticSuggestion, SuggestionKind,
|
||||||
|
completion_common::{FileSuggestion, surround_remove},
|
||||||
completion_options::NuMatcher,
|
completion_options::NuMatcher,
|
||||||
file_path_completion, Completer, CompletionOptions, SemanticSuggestion, SuggestionKind,
|
file_path_completion,
|
||||||
};
|
};
|
||||||
use nu_path::expand_tilde;
|
use nu_path::expand_tilde;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{Stack, StateWorkingSet, VirtualPath},
|
|
||||||
Span,
|
Span,
|
||||||
|
engine::{Stack, StateWorkingSet, VirtualPath},
|
||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
path::{is_separator, PathBuf, MAIN_SEPARATOR_STR},
|
path::{MAIN_SEPARATOR_STR, PathBuf, is_separator},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct DotNuCompletion {
|
pub struct DotNuCompletion {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use crate::completions::{
|
use crate::completions::{
|
||||||
completion_common::surround_remove, completion_options::NuMatcher, Completer,
|
Completer, CompletionOptions, SemanticSuggestion, SuggestionKind,
|
||||||
CompletionOptions, SemanticSuggestion, SuggestionKind,
|
completion_common::surround_remove, completion_options::NuMatcher,
|
||||||
};
|
};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{Stack, StateWorkingSet},
|
|
||||||
ModuleId, Span,
|
ModuleId, Span,
|
||||||
|
engine::{Stack, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
use crate::completions::{
|
use crate::completions::{
|
||||||
completion_common::{adjust_if_intermediate, complete_item, AdjustView},
|
|
||||||
Completer, CompletionOptions,
|
Completer, CompletionOptions,
|
||||||
|
completion_common::{AdjustView, adjust_if_intermediate, complete_item},
|
||||||
};
|
};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
|
||||||
Span,
|
Span,
|
||||||
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use super::{completion_common::FileSuggestion, SemanticSuggestion, SuggestionKind};
|
use super::{SemanticSuggestion, SuggestionKind, completion_common::FileSuggestion};
|
||||||
|
|
||||||
pub struct FileCompletion;
|
pub struct FileCompletion;
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::completions::{
|
use crate::completions::{
|
||||||
completion_options::NuMatcher, Completer, CompletionOptions, SemanticSuggestion, SuggestionKind,
|
Completer, CompletionOptions, SemanticSuggestion, SuggestionKind, completion_options::NuMatcher,
|
||||||
};
|
};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{Stack, StateWorkingSet},
|
|
||||||
DeclId, Span,
|
DeclId, Span,
|
||||||
|
engine::{Stack, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ pub use custom_completions::CustomCompletion;
|
|||||||
pub use directory_completions::DirectoryCompletion;
|
pub use directory_completions::DirectoryCompletion;
|
||||||
pub use dotnu_completions::DotNuCompletion;
|
pub use dotnu_completions::DotNuCompletion;
|
||||||
pub use exportable_completions::ExportableCompletion;
|
pub use exportable_completions::ExportableCompletion;
|
||||||
pub use file_completions::{file_path_completion, FileCompletion};
|
pub use file_completions::{FileCompletion, file_path_completion};
|
||||||
pub use flag_completions::FlagCompletion;
|
pub use flag_completions::FlagCompletion;
|
||||||
pub use operator_completions::OperatorCompletion;
|
pub use operator_completions::OperatorCompletion;
|
||||||
pub use variable_completions::VariableCompletion;
|
pub use variable_completions::VariableCompletion;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use crate::completions::{
|
use crate::completions::{
|
||||||
completion_options::NuMatcher, Completer, CompletionOptions, SemanticSuggestion, SuggestionKind,
|
Completer, CompletionOptions, SemanticSuggestion, SuggestionKind, completion_options::NuMatcher,
|
||||||
};
|
};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
ENV_VARIABLE_ID, Span, Type, Value,
|
||||||
ast::{self, Comparison, Expr, Expression},
|
ast::{self, Comparison, Expr, Expression},
|
||||||
engine::{Stack, StateWorkingSet},
|
engine::{Stack, StateWorkingSet},
|
||||||
Span, Type, Value, ENV_VARIABLE_ID,
|
|
||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
use strum::{EnumMessage, IntoEnumIterator};
|
use strum::{EnumMessage, IntoEnumIterator};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::completions::{Completer, CompletionOptions, SemanticSuggestion, SuggestionKind};
|
use crate::completions::{Completer, CompletionOptions, SemanticSuggestion, SuggestionKind};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{Stack, StateWorkingSet},
|
|
||||||
Span, VarId,
|
Span, VarId,
|
||||||
|
engine::{Stack, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
|
|
||||||
|
@ -2,10 +2,11 @@ use crate::util::eval_source;
|
|||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
use nu_path::canonicalize_with;
|
use nu_path::canonicalize_with;
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
use nu_protocol::{engine::StateWorkingSet, ParseError, PluginRegistryFile, Spanned};
|
use nu_protocol::{ParseError, PluginRegistryFile, Spanned, engine::StateWorkingSet};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
PipelineData,
|
||||||
engine::{EngineState, Stack},
|
engine::{EngineState, Stack},
|
||||||
report_shell_error, PipelineData,
|
report_shell_error,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
use nu_utils::perf;
|
use nu_utils::perf;
|
||||||
@ -18,7 +19,7 @@ const OLD_PLUGIN_FILE: &str = "plugin.nu";
|
|||||||
|
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
pub fn read_plugin_file(engine_state: &mut EngineState, plugin_file: Option<Spanned<String>>) {
|
pub fn read_plugin_file(engine_state: &mut EngineState, plugin_file: Option<Spanned<String>>) {
|
||||||
use nu_protocol::{shell_error::io::IoError, ShellError};
|
use nu_protocol::{ShellError, shell_error::io::IoError};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
let span = plugin_file.as_ref().map(|s| s.span);
|
let span = plugin_file.as_ref().map(|s| s.span);
|
||||||
@ -79,7 +80,7 @@ pub fn read_plugin_file(engine_state: &mut EngineState, plugin_file: Option<Span
|
|||||||
report_shell_error(
|
report_shell_error(
|
||||||
engine_state,
|
engine_state,
|
||||||
&ShellError::Io(IoError::new_internal_with_path(
|
&ShellError::Io(IoError::new_internal_with_path(
|
||||||
err.kind(),
|
err,
|
||||||
"Could not open plugin registry file",
|
"Could not open plugin registry file",
|
||||||
nu_protocol::location!(),
|
nu_protocol::location!(),
|
||||||
plugin_path,
|
plugin_path,
|
||||||
@ -230,8 +231,8 @@ pub fn eval_config_contents(
|
|||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
pub fn migrate_old_plugin_file(engine_state: &EngineState) -> bool {
|
pub fn migrate_old_plugin_file(engine_state: &EngineState) -> bool {
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
shell_error::io::IoError, PluginExample, PluginIdentity, PluginRegistryItem,
|
PluginExample, PluginIdentity, PluginRegistryItem, PluginRegistryItemData, PluginSignature,
|
||||||
PluginRegistryItemData, PluginSignature, ShellError,
|
ShellError, shell_error::io::IoError,
|
||||||
};
|
};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
@ -322,7 +323,7 @@ pub fn migrate_old_plugin_file(engine_state: &EngineState) -> bool {
|
|||||||
if let Err(err) = std::fs::File::create(&new_plugin_file_path)
|
if let Err(err) = std::fs::File::create(&new_plugin_file_path)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
IoError::new_internal_with_path(
|
IoError::new_internal_with_path(
|
||||||
err.kind(),
|
err,
|
||||||
"Could not create new plugin file",
|
"Could not create new plugin file",
|
||||||
nu_protocol::location!(),
|
nu_protocol::location!(),
|
||||||
new_plugin_file_path.clone(),
|
new_plugin_file_path.clone(),
|
||||||
|
@ -2,10 +2,11 @@ use log::info;
|
|||||||
use nu_engine::eval_block;
|
use nu_engine::eval_block;
|
||||||
use nu_parser::parse;
|
use nu_parser::parse;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
PipelineData, ShellError, Spanned, Value,
|
||||||
cli_error::report_compile_error,
|
cli_error::report_compile_error,
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
report_parse_error, report_parse_warning, PipelineData, ShellError, Spanned, Value,
|
report_parse_error, report_parse_warning,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -4,12 +4,12 @@ use nu_engine::eval_block;
|
|||||||
use nu_parser::parse;
|
use nu_parser::parse;
|
||||||
use nu_path::canonicalize_with;
|
use nu_path::canonicalize_with;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
PipelineData, ShellError, Span, Value,
|
||||||
cli_error::report_compile_error,
|
cli_error::report_compile_error,
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
report_parse_error, report_parse_warning,
|
report_parse_error, report_parse_warning,
|
||||||
shell_error::io::*,
|
shell_error::io::*,
|
||||||
PipelineData, ShellError, Span, Value,
|
|
||||||
};
|
};
|
||||||
use std::{path::PathBuf, sync::Arc};
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ pub fn evaluate_file(
|
|||||||
|
|
||||||
let file_path = canonicalize_with(&path, cwd).map_err(|err| {
|
let file_path = canonicalize_with(&path, cwd).map_err(|err| {
|
||||||
IoError::new_internal_with_path(
|
IoError::new_internal_with_path(
|
||||||
err.kind().not_found_as(NotFound::File),
|
err.not_found_as(NotFound::File),
|
||||||
"Could not access file",
|
"Could not access file",
|
||||||
nu_protocol::location!(),
|
nu_protocol::location!(),
|
||||||
PathBuf::from(&path),
|
PathBuf::from(&path),
|
||||||
@ -47,7 +47,7 @@ pub fn evaluate_file(
|
|||||||
|
|
||||||
let file = std::fs::read(&file_path).map_err(|err| {
|
let file = std::fs::read(&file_path).map_err(|err| {
|
||||||
IoError::new_internal_with_path(
|
IoError::new_internal_with_path(
|
||||||
err.kind().not_found_as(NotFound::File),
|
err.not_found_as(NotFound::File),
|
||||||
"Could not read file",
|
"Could not read file",
|
||||||
nu_protocol::location!(),
|
nu_protocol::location!(),
|
||||||
file_path.clone(),
|
file_path.clone(),
|
||||||
|
@ -18,7 +18,7 @@ mod validation;
|
|||||||
pub use commands::add_cli_context;
|
pub use commands::add_cli_context;
|
||||||
pub use completions::{FileCompletion, NuCompleter, SemanticSuggestion, SuggestionKind};
|
pub use completions::{FileCompletion, NuCompleter, SemanticSuggestion, SuggestionKind};
|
||||||
pub use config_files::eval_config_contents;
|
pub use config_files::eval_config_contents;
|
||||||
pub use eval_cmds::{evaluate_commands, EvaluateCommandsOpts};
|
pub use eval_cmds::{EvaluateCommandsOpts, evaluate_commands};
|
||||||
pub use eval_file::evaluate_file;
|
pub use eval_file::evaluate_file;
|
||||||
pub use menus::NuHelpCompleter;
|
pub use menus::NuHelpCompleter;
|
||||||
pub use nu_highlight::NuHighlight;
|
pub use nu_highlight::NuHighlight;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_engine::documentation::{get_flags_section, HelpStyle};
|
use nu_engine::documentation::{HelpStyle, get_flags_section};
|
||||||
use nu_protocol::{engine::EngineState, levenshtein_distance, Config};
|
use nu_protocol::{Config, engine::EngineState, levenshtein_distance};
|
||||||
use nu_utils::IgnoreCaseExt;
|
use nu_utils::IgnoreCaseExt;
|
||||||
use reedline::{Completer, Suggestion};
|
use reedline::{Completer, Suggestion};
|
||||||
use std::{fmt::Write, sync::Arc};
|
use std::{fmt::Write, sync::Arc};
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use nu_engine::eval_block;
|
use nu_engine::eval_block;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
BlockId, IntoPipelineData, Span, Value,
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{EngineState, Stack},
|
engine::{EngineState, Stack},
|
||||||
BlockId, IntoPipelineData, Span, Value,
|
|
||||||
};
|
};
|
||||||
use reedline::{menu_functions::parse_selection_char, Completer, Suggestion};
|
use reedline::{Completer, Suggestion, menu_functions::parse_selection_char};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
const SELECTION_CHAR: char = '!';
|
const SELECTION_CHAR: char = '!';
|
||||||
|
@ -2,8 +2,9 @@ use crate::NushellPrompt;
|
|||||||
use log::{trace, warn};
|
use log::{trace, warn};
|
||||||
use nu_engine::ClosureEvalOnce;
|
use nu_engine::ClosureEvalOnce;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
Config, PipelineData, Value,
|
||||||
engine::{EngineState, Stack},
|
engine::{EngineState, Stack},
|
||||||
report_shell_error, Config, PipelineData, Value,
|
report_shell_error,
|
||||||
};
|
};
|
||||||
use reedline::Prompt;
|
use reedline::Prompt;
|
||||||
|
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
use crate::{menus::NuMenuCompleter, NuHelpCompleter};
|
use crate::{NuHelpCompleter, menus::NuMenuCompleter};
|
||||||
use crossterm::event::{KeyCode, KeyModifiers};
|
use crossterm::event::{KeyCode, KeyModifiers};
|
||||||
use nu_ansi_term::Style;
|
use nu_ansi_term::Style;
|
||||||
use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
|
use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
|
||||||
use nu_engine::eval_block;
|
use nu_engine::eval_block;
|
||||||
use nu_parser::parse;
|
use nu_parser::parse;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
Config, EditBindings, FromValue, ParsedKeybinding, ParsedMenu, PipelineData, Record,
|
||||||
|
ShellError, Span, Type, Value,
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
extract_value, Config, EditBindings, FromValue, ParsedKeybinding, ParsedMenu, PipelineData,
|
extract_value,
|
||||||
Record, ShellError, Span, Type, Value,
|
|
||||||
};
|
};
|
||||||
use reedline::{
|
use reedline::{
|
||||||
default_emacs_keybindings, default_vi_insert_keybindings, default_vi_normal_keybindings,
|
|
||||||
ColumnarMenu, DescriptionMenu, DescriptionMode, EditCommand, IdeMenu, Keybindings, ListMenu,
|
ColumnarMenu, DescriptionMenu, DescriptionMode, EditCommand, IdeMenu, Keybindings, ListMenu,
|
||||||
MenuBuilder, Reedline, ReedlineEvent, ReedlineMenu,
|
MenuBuilder, Reedline, ReedlineEvent, ReedlineMenu, default_emacs_keybindings,
|
||||||
|
default_vi_insert_keybindings, default_vi_normal_keybindings,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -6,12 +6,12 @@ use crate::prompt_update::{
|
|||||||
VSCODE_PRE_EXECUTION_MARKER,
|
VSCODE_PRE_EXECUTION_MARKER,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
NuHighlighter, NuValidator, NushellPrompt,
|
||||||
completions::NuCompleter,
|
completions::NuCompleter,
|
||||||
nu_highlight::NoOpHighlighter,
|
nu_highlight::NoOpHighlighter,
|
||||||
prompt_update,
|
prompt_update,
|
||||||
reedline_config::{add_menus, create_keybindings, KeybindingsMode},
|
reedline_config::{KeybindingsMode, add_menus, create_keybindings},
|
||||||
util::eval_source,
|
util::eval_source,
|
||||||
NuHighlighter, NuValidator, NushellPrompt,
|
|
||||||
};
|
};
|
||||||
use crossterm::cursor::SetCursorStyle;
|
use crossterm::cursor::SetCursorStyle;
|
||||||
use log::{error, trace, warn};
|
use log::{error, trace, warn};
|
||||||
@ -22,15 +22,16 @@ use nu_color_config::StyleComputer;
|
|||||||
use nu_engine::env_to_strings;
|
use nu_engine::env_to_strings;
|
||||||
use nu_engine::exit::cleanup_exit;
|
use nu_engine::exit::cleanup_exit;
|
||||||
use nu_parser::{lex, parse, trim_quotes_str};
|
use nu_parser::{lex, parse, trim_quotes_str};
|
||||||
|
use nu_protocol::shell_error;
|
||||||
use nu_protocol::shell_error::io::IoError;
|
use nu_protocol::shell_error::io::IoError;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
HistoryConfig, HistoryFileFormat, PipelineData, ShellError, Span, Spanned, Value,
|
||||||
config::NuCursorShape,
|
config::NuCursorShape,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
report_shell_error, HistoryConfig, HistoryFileFormat, PipelineData, ShellError, Span, Spanned,
|
report_shell_error,
|
||||||
Value,
|
|
||||||
};
|
};
|
||||||
use nu_utils::{
|
use nu_utils::{
|
||||||
filesystem::{have_permission, PermissionResult},
|
filesystem::{PermissionResult, have_permission},
|
||||||
perf,
|
perf,
|
||||||
};
|
};
|
||||||
use reedline::{
|
use reedline::{
|
||||||
@ -42,7 +43,7 @@ use std::{
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
env::temp_dir,
|
env::temp_dir,
|
||||||
io::{self, IsTerminal, Write},
|
io::{self, IsTerminal, Write},
|
||||||
panic::{catch_unwind, AssertUnwindSafe},
|
panic::{AssertUnwindSafe, catch_unwind},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
@ -854,7 +855,7 @@ fn do_auto_cd(
|
|||||||
report_shell_error(
|
report_shell_error(
|
||||||
engine_state,
|
engine_state,
|
||||||
&ShellError::Io(IoError::new_with_additional_context(
|
&ShellError::Io(IoError::new_with_additional_context(
|
||||||
std::io::ErrorKind::NotFound,
|
shell_error::io::ErrorKind::DirectoryNotFound,
|
||||||
span,
|
span,
|
||||||
PathBuf::from(&path),
|
PathBuf::from(&path),
|
||||||
"Cannot change directory",
|
"Cannot change directory",
|
||||||
@ -868,7 +869,7 @@ fn do_auto_cd(
|
|||||||
report_shell_error(
|
report_shell_error(
|
||||||
engine_state,
|
engine_state,
|
||||||
&ShellError::Io(IoError::new_with_additional_context(
|
&ShellError::Io(IoError::new_with_additional_context(
|
||||||
std::io::ErrorKind::PermissionDenied,
|
shell_error::io::ErrorKind::from_std(std::io::ErrorKind::PermissionDenied),
|
||||||
span,
|
span,
|
||||||
PathBuf::from(path),
|
PathBuf::from(path),
|
||||||
"Cannot change directory",
|
"Cannot change directory",
|
||||||
@ -1451,7 +1452,7 @@ fn are_session_ids_in_sync() {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_auto_cd {
|
mod test_auto_cd {
|
||||||
use super::{do_auto_cd, escape_special_vscode_bytes, parse_operation, ReplOperation};
|
use super::{ReplOperation, do_auto_cd, escape_special_vscode_bytes, parse_operation};
|
||||||
use nu_path::AbsolutePath;
|
use nu_path::AbsolutePath;
|
||||||
use nu_protocol::engine::{EngineState, Stack};
|
use nu_protocol::engine::{EngineState, Stack};
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
@ -2,11 +2,11 @@ use log::trace;
|
|||||||
use nu_ansi_term::Style;
|
use nu_ansi_term::Style;
|
||||||
use nu_color_config::{get_matching_brackets_style, get_shape_color};
|
use nu_color_config::{get_matching_brackets_style, get_shape_color};
|
||||||
use nu_engine::env;
|
use nu_engine::env;
|
||||||
use nu_parser::{flatten_block, parse, FlatShape};
|
use nu_parser::{FlatShape, flatten_block, parse};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
Span,
|
||||||
ast::{Block, Expr, Expression, PipelineRedirection, RecordItem},
|
ast::{Block, Expr, Expression, PipelineRedirection, RecordItem},
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
Span,
|
|
||||||
};
|
};
|
||||||
use reedline::{Highlighter, StyledText};
|
use reedline::{Highlighter, StyledText};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
use nu_cmd_base::hook::eval_hook;
|
use nu_cmd_base::hook::eval_hook;
|
||||||
use nu_engine::{eval_block, eval_block_with_early_return};
|
use nu_engine::{eval_block, eval_block_with_early_return};
|
||||||
use nu_parser::{lex, parse, unescape_unquote_string, Token, TokenContents};
|
use nu_parser::{Token, TokenContents, lex, parse, unescape_unquote_string};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
PipelineData, ShellError, Span, Value,
|
||||||
cli_error::report_compile_error,
|
cli_error::report_compile_error,
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
report_parse_error, report_parse_warning, report_shell_error, PipelineData, ShellError, Span,
|
report_parse_error, report_parse_warning, report_shell_error,
|
||||||
Value,
|
|
||||||
};
|
};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use nu_utils::enable_vt_processing;
|
use nu_utils::enable_vt_processing;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use nu_parser::parse;
|
use nu_parser::parse;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{EngineState, StateWorkingSet},
|
|
||||||
ParseError,
|
ParseError,
|
||||||
|
engine::{EngineState, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use reedline::{ValidationResult, Validator};
|
use reedline::{ValidationResult, Validator};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_protocol::HistoryFileFormat;
|
use nu_protocol::HistoryFileFormat;
|
||||||
use nu_test_support::{nu, Outcome};
|
use nu_test_support::{Outcome, nu};
|
||||||
use reedline::{
|
use reedline::{
|
||||||
FileBackedHistory, History, HistoryItem, HistoryItemId, ReedlineError, SearchQuery,
|
FileBackedHistory, History, HistoryItem, HistoryItemId, ReedlineError, SearchQuery,
|
||||||
SqliteBackedHistory,
|
SqliteBackedHistory,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
pub mod support;
|
pub mod support;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::{read_dir, FileType, ReadDir},
|
fs::{FileType, ReadDir, read_dir},
|
||||||
path::{PathBuf, MAIN_SEPARATOR},
|
path::{MAIN_SEPARATOR, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ use nu_cli::NuCompleter;
|
|||||||
use nu_engine::eval_block;
|
use nu_engine::eval_block;
|
||||||
use nu_parser::parse;
|
use nu_parser::parse;
|
||||||
use nu_path::expand_tilde;
|
use nu_path::expand_tilde;
|
||||||
use nu_protocol::{debugger::WithoutDebug, engine::StateWorkingSet, Config, PipelineData};
|
use nu_protocol::{Config, PipelineData, debugger::WithoutDebug, engine::StateWorkingSet};
|
||||||
use nu_std::load_standard_library;
|
use nu_std::load_standard_library;
|
||||||
use reedline::{Completer, Suggestion};
|
use reedline::{Completer, Suggestion};
|
||||||
use rstest::{fixture, rstest};
|
use rstest::{fixture, rstest};
|
||||||
@ -1579,16 +1579,25 @@ fn attribute_completions() {
|
|||||||
// Create a new engine
|
// Create a new engine
|
||||||
let (_, _, engine, stack) = new_engine();
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
// Compile a list of built-in attribute names (without the "attr " prefix)
|
||||||
|
let attribute_names: Vec<String> = engine
|
||||||
|
.get_signatures_and_declids(false)
|
||||||
|
.into_iter()
|
||||||
|
.map(|(sig, _)| sig.name)
|
||||||
|
.filter(|name| name.starts_with("attr "))
|
||||||
|
.map(|name| name[5..].to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Make sure we actually found some attributes so the test is valid
|
||||||
|
assert!(attribute_names.contains(&String::from("example")));
|
||||||
|
|
||||||
// Instantiate a new completer
|
// Instantiate a new completer
|
||||||
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
|
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
|
||||||
// Test completions for the 'ls' flags
|
// Test completions for the 'ls' flags
|
||||||
let suggestions = completer.complete("@", 1);
|
let suggestions = completer.complete("@", 1);
|
||||||
|
|
||||||
// Only checking for the builtins and not the std attributes
|
|
||||||
let expected: Vec<_> = vec!["category", "example", "search-terms"];
|
|
||||||
|
|
||||||
// Match results
|
// Match results
|
||||||
match_suggestions(&expected, &suggestions);
|
match_suggestions_by_string(&attribute_names, &suggestions);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -2346,6 +2355,32 @@ fn exact_match() {
|
|||||||
assert!(suggestions.len() > 1);
|
assert!(suggestions.len() > 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(windows), not(target_os = "macos")))]
|
||||||
|
#[test]
|
||||||
|
fn exact_match_case_insensitive() {
|
||||||
|
use nu_test_support::playground::Playground;
|
||||||
|
use support::completions_helpers::new_engine_helper;
|
||||||
|
|
||||||
|
Playground::setup("exact_match_case_insensitive", |dirs, playground| {
|
||||||
|
playground.mkdir("AA/foo");
|
||||||
|
playground.mkdir("aa/foo");
|
||||||
|
playground.mkdir("aaa/foo");
|
||||||
|
|
||||||
|
let (dir, _, engine, stack) = new_engine_helper(dirs.test().into());
|
||||||
|
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
|
||||||
|
|
||||||
|
let target = format!("open {}", folder(dir.join("aa")));
|
||||||
|
match_suggestions(
|
||||||
|
&vec![
|
||||||
|
folder(dir.join("AA").join("foo")).as_str(),
|
||||||
|
folder(dir.join("aa").join("foo")).as_str(),
|
||||||
|
folder(dir.join("aaa").join("foo")).as_str(),
|
||||||
|
],
|
||||||
|
&completer.complete(&target, target.len()),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[ignore = "was reverted, still needs fixing"]
|
#[ignore = "was reverted, still needs fixing"]
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn alias_offset_bug_7648() {
|
fn alias_offset_bug_7648() {
|
||||||
|
@ -2,9 +2,9 @@ use nu_engine::eval_block;
|
|||||||
use nu_parser::parse;
|
use nu_parser::parse;
|
||||||
use nu_path::{AbsolutePathBuf, PathBuf};
|
use nu_path::{AbsolutePathBuf, PathBuf};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
PipelineData, ShellError, Span, Value,
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
PipelineData, ShellError, Span, Value,
|
|
||||||
};
|
};
|
||||||
use nu_test_support::fs;
|
use nu_test_support::fs;
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
@ -14,11 +14,8 @@ fn create_default_context() -> EngineState {
|
|||||||
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context())
|
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// creates a new engine with the current path into the completions fixtures folder
|
pub fn new_engine_helper(pwd: AbsolutePathBuf) -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||||
pub fn new_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
let pwd_str = pwd
|
||||||
// Target folder inside assets
|
|
||||||
let dir = fs::fixtures().join("completions");
|
|
||||||
let dir_str = dir
|
|
||||||
.clone()
|
.clone()
|
||||||
.into_os_string()
|
.into_os_string()
|
||||||
.into_string()
|
.into_string()
|
||||||
@ -36,13 +33,13 @@ pub fn new_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
|||||||
// Add pwd as env var
|
// Add pwd as env var
|
||||||
stack.add_env_var(
|
stack.add_env_var(
|
||||||
"PWD".to_string(),
|
"PWD".to_string(),
|
||||||
Value::string(dir_str.clone(), nu_protocol::Span::new(0, dir_str.len())),
|
Value::string(pwd_str.clone(), nu_protocol::Span::new(0, pwd_str.len())),
|
||||||
);
|
);
|
||||||
stack.add_env_var(
|
stack.add_env_var(
|
||||||
"TEST".to_string(),
|
"TEST".to_string(),
|
||||||
Value::string(
|
Value::string(
|
||||||
"NUSHELL".to_string(),
|
"NUSHELL".to_string(),
|
||||||
nu_protocol::Span::new(0, dir_str.len()),
|
nu_protocol::Span::new(0, pwd_str.len()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -50,7 +47,7 @@ pub fn new_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
|||||||
"Path".to_string(),
|
"Path".to_string(),
|
||||||
Value::string(
|
Value::string(
|
||||||
"c:\\some\\path;c:\\some\\other\\path".to_string(),
|
"c:\\some\\path;c:\\some\\other\\path".to_string(),
|
||||||
nu_protocol::Span::new(0, dir_str.len()),
|
nu_protocol::Span::new(0, pwd_str.len()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
@ -58,7 +55,7 @@ pub fn new_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
|||||||
"PATH".to_string(),
|
"PATH".to_string(),
|
||||||
Value::string(
|
Value::string(
|
||||||
"/some/path:/some/other/path".to_string(),
|
"/some/path:/some/other/path".to_string(),
|
||||||
nu_protocol::Span::new(0, dir_str.len()),
|
nu_protocol::Span::new(0, pwd_str.len()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -66,7 +63,12 @@ pub fn new_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
|||||||
let merge_result = engine_state.merge_env(&mut stack);
|
let merge_result = engine_state.merge_env(&mut stack);
|
||||||
assert!(merge_result.is_ok());
|
assert!(merge_result.is_ok());
|
||||||
|
|
||||||
(dir, dir_str, engine_state, stack)
|
(pwd, pwd_str, engine_state, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// creates a new engine with the current path in the completions fixtures folder
|
||||||
|
pub fn new_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||||
|
new_engine_helper(fs::fixtures().join("completions"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds pseudo PATH env for external completion tests
|
/// Adds pseudo PATH env for external completion tests
|
||||||
@ -88,23 +90,13 @@ pub fn new_external_engine() -> EngineState {
|
|||||||
engine
|
engine
|
||||||
}
|
}
|
||||||
|
|
||||||
/// creates a new engine with the current path into the completions fixtures folder
|
/// creates a new engine with the current path in the dotnu_completions fixtures folder
|
||||||
pub fn new_dotnu_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
pub fn new_dotnu_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||||
// Target folder inside assets
|
// Target folder inside assets
|
||||||
let dir = fs::fixtures().join("dotnu_completions");
|
let dir = fs::fixtures().join("dotnu_completions");
|
||||||
let dir_str = dir
|
let (dir, dir_str, mut engine_state, mut stack) = new_engine_helper(dir);
|
||||||
.clone()
|
|
||||||
.into_os_string()
|
|
||||||
.into_string()
|
|
||||||
.unwrap_or_default();
|
|
||||||
let dir_span = nu_protocol::Span::new(0, dir_str.len());
|
let dir_span = nu_protocol::Span::new(0, dir_str.len());
|
||||||
|
|
||||||
// Create a new engine with default context
|
|
||||||
let mut engine_state = create_default_context();
|
|
||||||
|
|
||||||
// Add $nu
|
|
||||||
engine_state.generate_nu_constant();
|
|
||||||
|
|
||||||
// const $NU_LIB_DIRS
|
// const $NU_LIB_DIRS
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
let var_id = working_set.add_variable(
|
let var_id = working_set.add_variable(
|
||||||
@ -122,15 +114,6 @@ pub fn new_dotnu_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
|||||||
);
|
);
|
||||||
let _ = engine_state.merge_delta(working_set.render());
|
let _ = engine_state.merge_delta(working_set.render());
|
||||||
|
|
||||||
// New stack
|
|
||||||
let mut stack = Stack::new();
|
|
||||||
|
|
||||||
// Add pwd as env var
|
|
||||||
stack.add_env_var("PWD".to_string(), Value::string(dir_str.clone(), dir_span));
|
|
||||||
stack.add_env_var(
|
|
||||||
"TEST".to_string(),
|
|
||||||
Value::string("NUSHELL".to_string(), dir_span),
|
|
||||||
);
|
|
||||||
stack.add_env_var(
|
stack.add_env_var(
|
||||||
"NU_LIB_DIRS".into(),
|
"NU_LIB_DIRS".into(),
|
||||||
Value::test_list(vec![
|
Value::test_list(vec![
|
||||||
@ -147,73 +130,11 @@ pub fn new_dotnu_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_quote_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
pub fn new_quote_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||||
// Target folder inside assets
|
new_engine_helper(fs::fixtures().join("quoted_completions"))
|
||||||
let dir = fs::fixtures().join("quoted_completions");
|
|
||||||
let dir_str = dir
|
|
||||||
.clone()
|
|
||||||
.into_os_string()
|
|
||||||
.into_string()
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
// Create a new engine with default context
|
|
||||||
let mut engine_state = create_default_context();
|
|
||||||
|
|
||||||
// New stack
|
|
||||||
let mut stack = Stack::new();
|
|
||||||
|
|
||||||
// Add pwd as env var
|
|
||||||
stack.add_env_var(
|
|
||||||
"PWD".to_string(),
|
|
||||||
Value::string(dir_str.clone(), nu_protocol::Span::new(0, dir_str.len())),
|
|
||||||
);
|
|
||||||
stack.add_env_var(
|
|
||||||
"TEST".to_string(),
|
|
||||||
Value::string(
|
|
||||||
"NUSHELL".to_string(),
|
|
||||||
nu_protocol::Span::new(0, dir_str.len()),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Merge environment into the permanent state
|
|
||||||
let merge_result = engine_state.merge_env(&mut stack);
|
|
||||||
assert!(merge_result.is_ok());
|
|
||||||
|
|
||||||
(dir, dir_str, engine_state, stack)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_partial_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
pub fn new_partial_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||||
// Target folder inside assets
|
new_engine_helper(fs::fixtures().join("partial_completions"))
|
||||||
let dir = fs::fixtures().join("partial_completions");
|
|
||||||
let dir_str = dir
|
|
||||||
.clone()
|
|
||||||
.into_os_string()
|
|
||||||
.into_string()
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
// Create a new engine with default context
|
|
||||||
let mut engine_state = create_default_context();
|
|
||||||
|
|
||||||
// New stack
|
|
||||||
let mut stack = Stack::new();
|
|
||||||
|
|
||||||
// Add pwd as env var
|
|
||||||
stack.add_env_var(
|
|
||||||
"PWD".to_string(),
|
|
||||||
Value::string(dir_str.clone(), nu_protocol::Span::new(0, dir_str.len())),
|
|
||||||
);
|
|
||||||
stack.add_env_var(
|
|
||||||
"TEST".to_string(),
|
|
||||||
Value::string(
|
|
||||||
"NUSHELL".to_string(),
|
|
||||||
nu_protocol::Span::new(0, dir_str.len()),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Merge environment into the permanent state
|
|
||||||
let merge_result = engine_state.merge_env(&mut stack);
|
|
||||||
assert!(merge_result.is_ok());
|
|
||||||
|
|
||||||
(dir, dir_str, engine_state, stack)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// match a list of suggestions with the expected values
|
/// match a list of suggestions with the expected values
|
||||||
@ -273,13 +194,15 @@ pub fn merge_input(
|
|||||||
|
|
||||||
engine_state.merge_delta(delta)?;
|
engine_state.merge_delta(delta)?;
|
||||||
|
|
||||||
assert!(eval_block::<WithoutDebug>(
|
assert!(
|
||||||
|
eval_block::<WithoutDebug>(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
&block,
|
&block,
|
||||||
PipelineData::Value(Value::nothing(Span::unknown()), None),
|
PipelineData::Value(Value::nothing(Span::unknown()), None),
|
||||||
)
|
)
|
||||||
.is_ok());
|
.is_ok()
|
||||||
|
);
|
||||||
|
|
||||||
// Merge environment into the permanent state
|
// Merge environment into the permanent state
|
||||||
engine_state.merge_env(stack)
|
engine_state.merge_env(stack)
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["The Nushell Project Developers"]
|
authors = ["The Nushell Project Developers"]
|
||||||
description = "The foundation tools to build Nushell commands."
|
description = "The foundation tools to build Nushell commands."
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-cmd-base"
|
name = "nu-cmd-base"
|
||||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
|
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
|
||||||
version = "0.104.0"
|
version = "0.105.1"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@ -13,10 +13,10 @@ version = "0.104.0"
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-engine = { path = "../nu-engine", version = "0.104.0", default-features = false }
|
nu-engine = { path = "../nu-engine", version = "0.105.1", default-features = false }
|
||||||
nu-parser = { path = "../nu-parser", version = "0.104.0" }
|
nu-parser = { path = "../nu-parser", version = "0.105.1" }
|
||||||
nu-path = { path = "../nu-path", version = "0.104.0" }
|
nu-path = { path = "../nu-path", version = "0.105.1" }
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.104.0", default-features = false }
|
nu-protocol = { path = "../nu-protocol", version = "0.105.1", default-features = false }
|
||||||
|
|
||||||
indexmap = { workspace = true }
|
indexmap = { workspace = true }
|
||||||
miette = { workspace = true }
|
miette = { workspace = true }
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use indexmap::{indexset, IndexSet};
|
use indexmap::{IndexSet, indexset};
|
||||||
use nu_protocol::Value;
|
use nu_protocol::Value;
|
||||||
|
|
||||||
pub fn merge_descriptors(values: &[Value]) -> Vec<String> {
|
pub fn merge_descriptors(values: &[Value]) -> Vec<String> {
|
||||||
|
@ -2,10 +2,10 @@ use miette::Result;
|
|||||||
use nu_engine::{eval_block, eval_block_with_early_return};
|
use nu_engine::{eval_block, eval_block_with_early_return};
|
||||||
use nu_parser::parse;
|
use nu_parser::parse;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
|
PipelineData, PositionalArg, ShellError, Span, Type, Value, VarId,
|
||||||
cli_error::{report_parse_error, report_shell_error},
|
cli_error::{report_parse_error, report_shell_error},
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
||||||
PipelineData, PositionalArg, ShellError, Span, Type, Value, VarId,
|
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_protocol::{ast::CellPath, PipelineData, ShellError, Signals, Span, Value};
|
use nu_protocol::{PipelineData, ShellError, Signals, Span, Value, ast::CellPath};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub trait CmdArgument {
|
pub trait CmdArgument {
|
||||||
|
@ -3,3 +3,6 @@ pub mod formats;
|
|||||||
pub mod hook;
|
pub mod hook;
|
||||||
pub mod input_handler;
|
pub mod input_handler;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
mod wrap_call;
|
||||||
|
|
||||||
|
pub use wrap_call::*;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{EngineState, Stack},
|
|
||||||
Range, ShellError, Span, Value,
|
Range, ShellError, Span, Value,
|
||||||
|
engine::{EngineState, Stack},
|
||||||
};
|
};
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
|
|
||||||
|
101
crates/nu-cmd-base/src/wrap_call.rs
Normal file
101
crates/nu-cmd-base/src/wrap_call.rs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::{
|
||||||
|
DeclId, FromValue, ShellError, Span,
|
||||||
|
engine::{Call, EngineState, Stack, StateWorkingSet},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A helper utility to aid in implementing commands which have the same behavior for `run` and `run_const`.
|
||||||
|
///
|
||||||
|
/// Only supports functions in [`Call`] and [`CallExt`] which have a `const` suffix.
|
||||||
|
///
|
||||||
|
/// To use, the actual command logic should be moved to a function. Then, `eval` and `eval_const` can be implemented like this:
|
||||||
|
/// ```rust
|
||||||
|
/// # use nu_engine::command_prelude::*;
|
||||||
|
/// # use nu_cmd_base::WrapCall;
|
||||||
|
/// # fn do_command_logic(call: WrapCall) -> Result<PipelineData, ShellError> { Ok(PipelineData::Empty) }
|
||||||
|
///
|
||||||
|
/// # struct Command {}
|
||||||
|
/// # impl Command {
|
||||||
|
/// fn run(&self, engine_state: &EngineState, stack: &mut Stack, call: &Call) -> Result<PipelineData, ShellError> {
|
||||||
|
/// let call = WrapCall::Eval(engine_state, stack, call);
|
||||||
|
/// do_command_logic(call)
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn run_const(&self, working_set: &StateWorkingSet, call: &Call) -> Result<PipelineData, ShellError> {
|
||||||
|
/// let call = WrapCall::ConstEval(working_set, call);
|
||||||
|
/// do_command_logic(call)
|
||||||
|
/// }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Then, the typical [`Call`] and [`CallExt`] operations can be called using destructuring:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use nu_engine::command_prelude::*;
|
||||||
|
/// # use nu_cmd_base::WrapCall;
|
||||||
|
/// # let call = WrapCall::Eval(&EngineState::new(), &mut Stack::new(), &Call::new(Span::unknown()));
|
||||||
|
/// # fn do_command_logic(call: WrapCall) -> Result<(), ShellError> {
|
||||||
|
/// let (call, required): (_, String) = call.req(0)?;
|
||||||
|
/// let (call, flag): (_, Option<i64>) = call.get_flag("number")?;
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// A new `WrapCall` instance has to be returned after each function to ensure
|
||||||
|
/// that there is only ever one copy of mutable [`Stack`] reference.
|
||||||
|
pub enum WrapCall<'a> {
|
||||||
|
Eval(&'a EngineState, &'a mut Stack, &'a Call<'a>),
|
||||||
|
ConstEval(&'a StateWorkingSet<'a>, &'a Call<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Macro to choose between the non-const and const versions of each [`Call`]/[`CallExt`] function
|
||||||
|
macro_rules! proxy {
|
||||||
|
($self:ident , $eval:ident , $const:ident , $( $args:expr ),*) => {
|
||||||
|
match $self {
|
||||||
|
WrapCall::Eval(engine_state, stack, call) => {
|
||||||
|
Call::$eval(call, engine_state, stack, $( $args ),*)
|
||||||
|
.map(|val| (WrapCall::Eval(engine_state, stack, call), val))
|
||||||
|
},
|
||||||
|
WrapCall::ConstEval(working_set, call) => {
|
||||||
|
Call::$const(call, working_set, $( $args ),*)
|
||||||
|
.map(|val| (WrapCall::ConstEval(working_set, call), val))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WrapCall<'_> {
|
||||||
|
pub fn head(&self) -> Span {
|
||||||
|
match self {
|
||||||
|
WrapCall::Eval(_, _, call) => call.head,
|
||||||
|
WrapCall::ConstEval(_, call) => call.head,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decl_id(&self) -> DeclId {
|
||||||
|
match self {
|
||||||
|
WrapCall::Eval(_, _, call) => call.decl_id,
|
||||||
|
WrapCall::ConstEval(_, call) => call.decl_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_flag<T: FromValue>(self, flag_name: &str) -> Result<(Self, bool), ShellError> {
|
||||||
|
proxy!(self, has_flag, has_flag_const, flag_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_flag<T: FromValue>(self, name: &str) -> Result<(Self, Option<T>), ShellError> {
|
||||||
|
proxy!(self, get_flag, get_flag_const, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn req<T: FromValue>(self, pos: usize) -> Result<(Self, T), ShellError> {
|
||||||
|
proxy!(self, req, req_const, pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rest<T: FromValue>(self, pos: usize) -> Result<(Self, Vec<T>), ShellError> {
|
||||||
|
proxy!(self, rest, rest_const, pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn opt<T: FromValue>(self, pos: usize) -> Result<(Self, Option<T>), ShellError> {
|
||||||
|
proxy!(self, opt, opt_const, pos)
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["The Nushell Project Developers"]
|
authors = ["The Nushell Project Developers"]
|
||||||
description = "Nushell's extra commands that are not part of the 1.0 api standard."
|
description = "Nushell's extra commands that are not part of the 1.0 api standard."
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-cmd-extra"
|
name = "nu-cmd-extra"
|
||||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-extra"
|
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-extra"
|
||||||
version = "0.104.0"
|
version = "0.105.1"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@ -16,13 +16,13 @@ bench = false
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.104.0" }
|
nu-cmd-base = { path = "../nu-cmd-base", version = "0.105.1" }
|
||||||
nu-engine = { path = "../nu-engine", version = "0.104.0", default-features = false }
|
nu-engine = { path = "../nu-engine", version = "0.105.1", default-features = false }
|
||||||
nu-json = { version = "0.104.0", path = "../nu-json" }
|
nu-json = { version = "0.105.1", path = "../nu-json" }
|
||||||
nu-parser = { path = "../nu-parser", version = "0.104.0" }
|
nu-parser = { path = "../nu-parser", version = "0.105.1" }
|
||||||
nu-pretty-hex = { version = "0.104.0", path = "../nu-pretty-hex" }
|
nu-pretty-hex = { version = "0.105.1", path = "../nu-pretty-hex" }
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.104.0", default-features = false }
|
nu-protocol = { path = "../nu-protocol", version = "0.105.1", default-features = false }
|
||||||
nu-utils = { path = "../nu-utils", version = "0.104.0", default-features = false }
|
nu-utils = { path = "../nu-utils", version = "0.105.1", default-features = false }
|
||||||
|
|
||||||
# Potential dependencies for extras
|
# Potential dependencies for extras
|
||||||
heck = { workspace = true }
|
heck = { workspace = true }
|
||||||
@ -37,6 +37,6 @@ itertools = { workspace = true }
|
|||||||
mime = { workspace = true }
|
mime = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.104.0" }
|
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.105.1" }
|
||||||
nu-command = { path = "../nu-command", version = "0.104.0" }
|
nu-command = { path = "../nu-command", version = "0.105.1" }
|
||||||
nu-test-support = { path = "../nu-test-support", version = "0.104.0" }
|
nu-test-support = { path = "../nu-test-support", version = "0.105.1" }
|
||||||
|
@ -16,8 +16,8 @@ mod test_examples {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{Command, EngineState, StateWorkingSet},
|
|
||||||
Type,
|
Type,
|
||||||
|
engine::{Command, EngineState, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ impl Command for BitsAnd {
|
|||||||
return Err(ShellError::TypeMismatch {
|
return Err(ShellError::TypeMismatch {
|
||||||
err_message: "Endian must be one of native, little, big".to_string(),
|
err_message: "Endian must be one of native, little, big".to_string(),
|
||||||
span: endian.span,
|
span: endian.span,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -113,8 +113,7 @@ impl Command for BitsAnd {
|
|||||||
])),
|
])),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description:
|
description: "Apply bitwise and to binary data of varying lengths with specified endianness",
|
||||||
"Apply bitwise and to binary data of varying lengths with specified endianness",
|
|
||||||
example: "0x[c0 ff ee] | bits and 0x[ff] --endian big",
|
example: "0x[c0 ff ee] | bits and 0x[ff] --endian big",
|
||||||
result: Some(Value::test_binary(vec![0x00, 0x00, 0xee])),
|
result: Some(Value::test_binary(vec![0x00, 0x00, 0xee])),
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::{get_number_bytes, NumberBytes};
|
use super::{NumberBytes, get_number_bytes};
|
||||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -100,8 +100,7 @@ impl Command for BitsNot {
|
|||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description:
|
description: "Apply logical negation to a list of numbers, treat input as 2 bytes number",
|
||||||
"Apply logical negation to a list of numbers, treat input as 2 bytes number",
|
|
||||||
example: "[4 3 2] | bits not --number-bytes 2",
|
example: "[4 3 2] | bits not --number-bytes 2",
|
||||||
result: Some(Value::list(
|
result: Some(Value::list(
|
||||||
vec![
|
vec![
|
||||||
@ -113,8 +112,7 @@ impl Command for BitsNot {
|
|||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description:
|
description: "Apply logical negation to a list of numbers, treat input as signed number",
|
||||||
"Apply logical negation to a list of numbers, treat input as signed number",
|
|
||||||
example: "[4 3 2] | bits not --signed",
|
example: "[4 3 2] | bits not --signed",
|
||||||
result: Some(Value::list(
|
result: Some(Value::list(
|
||||||
vec![
|
vec![
|
||||||
|
@ -66,7 +66,7 @@ impl Command for BitsOr {
|
|||||||
return Err(ShellError::TypeMismatch {
|
return Err(ShellError::TypeMismatch {
|
||||||
err_message: "Endian must be one of native, little, big".to_string(),
|
err_message: "Endian must be one of native, little, big".to_string(),
|
||||||
span: endian.span,
|
span: endian.span,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -106,8 +106,7 @@ impl Command for BitsOr {
|
|||||||
result: Some(Value::test_binary(vec![0xca, 0xfe])),
|
result: Some(Value::test_binary(vec![0xca, 0xfe])),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description:
|
description: "Apply bitwise or to binary data of varying lengths with specified endianness",
|
||||||
"Apply bitwise or to binary data of varying lengths with specified endianness",
|
|
||||||
example: "0x[c0 ff ee] | bits or 0x[ff] --endian big",
|
example: "0x[c0 ff ee] | bits or 0x[ff] --endian big",
|
||||||
result: Some(Value::test_binary(vec![0xc0, 0xff, 0xff])),
|
result: Some(Value::test_binary(vec![0xc0, 0xff, 0xff])),
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
use super::{InputNumType, NumberBytes, get_input_num_type, get_number_bytes};
|
||||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
@ -222,7 +222,8 @@ fn rotate_bytes_and_bits_left(data: &[u8], byte_shift: usize, bit_shift: usize)
|
|||||||
debug_assert!(byte_shift < data.len());
|
debug_assert!(byte_shift < data.len());
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
(1..8).contains(&bit_shift),
|
(1..8).contains(&bit_shift),
|
||||||
"Bit shifts of 0 can't be handled by this impl and everything else should be part of the byteshift");
|
"Bit shifts of 0 can't be handled by this impl and everything else should be part of the byteshift"
|
||||||
|
);
|
||||||
let mut bytes = Vec::with_capacity(data.len());
|
let mut bytes = Vec::with_capacity(data.len());
|
||||||
let mut next_index = byte_shift;
|
let mut next_index = byte_shift;
|
||||||
for _ in 0..data.len() {
|
for _ in 0..data.len() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
use super::{InputNumType, NumberBytes, get_input_num_type, get_number_bytes};
|
||||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
use super::{InputNumType, NumberBytes, get_input_num_type, get_number_bytes};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
@ -237,7 +237,8 @@ fn shift_bytes_left(data: &[u8], byte_shift: usize) -> Vec<u8> {
|
|||||||
|
|
||||||
fn shift_bytes_and_bits_left(data: &[u8], byte_shift: usize, bit_shift: usize) -> Vec<u8> {
|
fn shift_bytes_and_bits_left(data: &[u8], byte_shift: usize, bit_shift: usize) -> Vec<u8> {
|
||||||
use itertools::Position::*;
|
use itertools::Position::*;
|
||||||
debug_assert!((1..8).contains(&bit_shift),
|
debug_assert!(
|
||||||
|
(1..8).contains(&bit_shift),
|
||||||
"Bit shifts of 0 can't be handled by this impl and everything else should be part of the byteshift"
|
"Bit shifts of 0 can't be handled by this impl and everything else should be part of the byteshift"
|
||||||
);
|
);
|
||||||
data.iter()
|
data.iter()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
use super::{InputNumType, NumberBytes, get_input_num_type, get_number_bytes};
|
||||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
|
@ -66,7 +66,7 @@ impl Command for BitsXor {
|
|||||||
return Err(ShellError::TypeMismatch {
|
return Err(ShellError::TypeMismatch {
|
||||||
err_message: "Endian must be one of native, little, big".to_string(),
|
err_message: "Endian must be one of native, little, big".to_string(),
|
||||||
span: endian.span,
|
span: endian.span,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -106,8 +106,7 @@ impl Command for BitsXor {
|
|||||||
result: Some(Value::test_binary(vec![0x70, 0x40])),
|
result: Some(Value::test_binary(vec![0x70, 0x40])),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description:
|
description: "Apply bitwise xor to binary data of varying lengths with specified endianness",
|
||||||
"Apply bitwise xor to binary data of varying lengths with specified endianness",
|
|
||||||
example: "0x[ca fe] | bits xor 0x[aa] --endian big",
|
example: "0x[ca fe] | bits xor 0x[aa] --endian big",
|
||||||
result: Some(Value::test_binary(vec![0xca, 0x54])),
|
result: Some(Value::test_binary(vec![0xca, 0x54])),
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_engine::{command_prelude::*, ClosureEval, ClosureEvalOnce};
|
use nu_engine::{ClosureEval, ClosureEvalOnce, command_prelude::*};
|
||||||
use nu_protocol::engine::Closure;
|
use nu_protocol::engine::Closure;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{vertical_rotate_value, VerticalDirection};
|
use super::{VerticalDirection, vertical_rotate_value};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{horizontal_rotate_value, HorizontalDirection};
|
use super::{HorizontalDirection, horizontal_rotate_value};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{horizontal_rotate_value, HorizontalDirection};
|
use super::{HorizontalDirection, horizontal_rotate_value};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{vertical_rotate_value, VerticalDirection};
|
use super::{VerticalDirection, vertical_rotate_value};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -44,14 +44,12 @@ impl Command for Rotate {
|
|||||||
"column0" => Value::test_int(2),
|
"column0" => Value::test_int(2),
|
||||||
"column1" => Value::test_string("b"),
|
"column1" => Value::test_string("b"),
|
||||||
}),
|
}),
|
||||||
],
|
])),
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Rotate 2x3 table clockwise",
|
description: "Rotate 2x3 table clockwise",
|
||||||
example: "[[a b]; [1 2] [3 4] [5 6]] | rotate",
|
example: "[[a b]; [1 2] [3 4] [5 6]] | rotate",
|
||||||
result: Some(Value::test_list(
|
result: Some(Value::test_list(vec![
|
||||||
vec![
|
|
||||||
Value::test_record(record! {
|
Value::test_record(record! {
|
||||||
"column0" => Value::test_int(5),
|
"column0" => Value::test_int(5),
|
||||||
"column1" => Value::test_int(3),
|
"column1" => Value::test_int(3),
|
||||||
@ -64,14 +62,12 @@ impl Command for Rotate {
|
|||||||
"column2" => Value::test_int(2),
|
"column2" => Value::test_int(2),
|
||||||
"column3" => Value::test_string("b"),
|
"column3" => Value::test_string("b"),
|
||||||
}),
|
}),
|
||||||
],
|
])),
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Rotate table clockwise and change columns names",
|
description: "Rotate table clockwise and change columns names",
|
||||||
example: "[[a b]; [1 2]] | rotate col_a col_b",
|
example: "[[a b]; [1 2]] | rotate col_a col_b",
|
||||||
result: Some(Value::test_list(
|
result: Some(Value::test_list(vec![
|
||||||
vec![
|
|
||||||
Value::test_record(record! {
|
Value::test_record(record! {
|
||||||
"col_a" => Value::test_int(1),
|
"col_a" => Value::test_int(1),
|
||||||
"col_b" => Value::test_string("a"),
|
"col_b" => Value::test_string("a"),
|
||||||
@ -80,14 +76,12 @@ impl Command for Rotate {
|
|||||||
"col_a" => Value::test_int(2),
|
"col_a" => Value::test_int(2),
|
||||||
"col_b" => Value::test_string("b"),
|
"col_b" => Value::test_string("b"),
|
||||||
}),
|
}),
|
||||||
],
|
])),
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Rotate table counter clockwise",
|
description: "Rotate table counter clockwise",
|
||||||
example: "[[a b]; [1 2]] | rotate --ccw",
|
example: "[[a b]; [1 2]] | rotate --ccw",
|
||||||
result: Some(Value::test_list(
|
result: Some(Value::test_list(vec![
|
||||||
vec![
|
|
||||||
Value::test_record(record! {
|
Value::test_record(record! {
|
||||||
"column0" => Value::test_string("b"),
|
"column0" => Value::test_string("b"),
|
||||||
"column1" => Value::test_int(2),
|
"column1" => Value::test_int(2),
|
||||||
@ -96,14 +90,12 @@ impl Command for Rotate {
|
|||||||
"column0" => Value::test_string("a"),
|
"column0" => Value::test_string("a"),
|
||||||
"column1" => Value::test_int(1),
|
"column1" => Value::test_int(1),
|
||||||
}),
|
}),
|
||||||
],
|
])),
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Rotate table counter-clockwise",
|
description: "Rotate table counter-clockwise",
|
||||||
example: "[[a b]; [1 2] [3 4] [5 6]] | rotate --ccw",
|
example: "[[a b]; [1 2] [3 4] [5 6]] | rotate --ccw",
|
||||||
result: Some(Value::test_list(
|
result: Some(Value::test_list(vec![
|
||||||
vec![
|
|
||||||
Value::test_record(record! {
|
Value::test_record(record! {
|
||||||
"column0" => Value::test_string("b"),
|
"column0" => Value::test_string("b"),
|
||||||
"column1" => Value::test_int(2),
|
"column1" => Value::test_int(2),
|
||||||
@ -116,14 +108,12 @@ impl Command for Rotate {
|
|||||||
"column2" => Value::test_int(3),
|
"column2" => Value::test_int(3),
|
||||||
"column3" => Value::test_int(5),
|
"column3" => Value::test_int(5),
|
||||||
}),
|
}),
|
||||||
],
|
])),
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Rotate table counter-clockwise and change columns names",
|
description: "Rotate table counter-clockwise and change columns names",
|
||||||
example: "[[a b]; [1 2]] | rotate --ccw col_a col_b",
|
example: "[[a b]; [1 2]] | rotate --ccw col_a col_b",
|
||||||
result: Some(Value::test_list(
|
result: Some(Value::test_list(vec![
|
||||||
vec![
|
|
||||||
Value::test_record(record! {
|
Value::test_record(record! {
|
||||||
"col_a" => Value::test_string("b"),
|
"col_a" => Value::test_string("b"),
|
||||||
"col_b" => Value::test_int(2),
|
"col_b" => Value::test_int(2),
|
||||||
@ -132,8 +122,7 @@ impl Command for Rotate {
|
|||||||
"col_a" => Value::test_string("a"),
|
"col_a" => Value::test_string("a"),
|
||||||
"col_b" => Value::test_int(1),
|
"col_b" => Value::test_int(1),
|
||||||
}),
|
}),
|
||||||
],
|
])),
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_engine::{command_prelude::*, ClosureEval};
|
use nu_engine::{ClosureEval, command_prelude::*};
|
||||||
use nu_protocol::{engine::Closure, PipelineIterator};
|
use nu_protocol::{PipelineIterator, engine::Closure};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -101,7 +101,7 @@ impl Command for ToHtml {
|
|||||||
.named(
|
.named(
|
||||||
"theme",
|
"theme",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
"the name of the theme to use (github, blulocolight, ...)",
|
"the name of the theme to use (github, blulocolight, ...); case-insensitive",
|
||||||
Some('t'),
|
Some('t'),
|
||||||
)
|
)
|
||||||
.switch(
|
.switch(
|
||||||
@ -163,9 +163,16 @@ fn get_theme_from_asset_file(
|
|||||||
) -> Result<HashMap<&'static str, String>, ShellError> {
|
) -> Result<HashMap<&'static str, String>, ShellError> {
|
||||||
let theme_name = match theme {
|
let theme_name = match theme {
|
||||||
Some(s) => &s.item,
|
Some(s) => &s.item,
|
||||||
None => "default", // There is no theme named "default" so this will be HtmlTheme::default(), which is "nu_default".
|
None => {
|
||||||
|
return Ok(convert_html_theme_to_hash_map(
|
||||||
|
is_dark,
|
||||||
|
&HtmlTheme::default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let theme_span = theme.map(|s| s.span).unwrap_or(Span::unknown());
|
||||||
|
|
||||||
// 228 themes come from
|
// 228 themes come from
|
||||||
// https://github.com/mbadolato/iTerm2-Color-Schemes/tree/master/windowsterminal
|
// https://github.com/mbadolato/iTerm2-Color-Schemes/tree/master/windowsterminal
|
||||||
// we should find a hit on any name in there
|
// we should find a hit on any name in there
|
||||||
@ -175,8 +182,17 @@ fn get_theme_from_asset_file(
|
|||||||
let th = asset
|
let th = asset
|
||||||
.themes
|
.themes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find(|n| n.name.eq_ignore_case(theme_name)) // case insensitive search
|
.find(|n| n.name.eq_ignore_case(theme_name)); // case insensitive search
|
||||||
.unwrap_or_default();
|
|
||||||
|
let th = match th {
|
||||||
|
Some(t) => t,
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::TypeMismatch {
|
||||||
|
err_message: format!("Unknown HTML theme '{}'", theme_name),
|
||||||
|
span: theme_span,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(convert_html_theme_to_hash_map(is_dark, &th))
|
Ok(convert_html_theme_to_hash_map(is_dark, &th))
|
||||||
}
|
}
|
||||||
@ -257,18 +273,20 @@ fn to_html(
|
|||||||
None => head,
|
None => head,
|
||||||
};
|
};
|
||||||
|
|
||||||
let color_hm = get_theme_from_asset_file(dark, theme.as_ref());
|
let color_hm = match get_theme_from_asset_file(dark, theme.as_ref()) {
|
||||||
let color_hm = match color_hm {
|
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
_ => {
|
Err(e) => match e {
|
||||||
return Err(ShellError::GenericError {
|
ShellError::TypeMismatch {
|
||||||
error: "Error finding theme name".into(),
|
err_message,
|
||||||
msg: "Error finding theme name".into(),
|
span: _,
|
||||||
span: Some(theme_span),
|
} => {
|
||||||
help: None,
|
return Err(ShellError::TypeMismatch {
|
||||||
inner: vec![],
|
err_message,
|
||||||
})
|
span: theme_span,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
_ => return Err(e),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// change the color of the page
|
// change the color of the page
|
||||||
@ -703,4 +721,90 @@ mod tests {
|
|||||||
|
|
||||||
test_examples(ToHtml {})
|
test_examples(ToHtml {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_theme_from_asset_file_returns_default() {
|
||||||
|
let result = super::get_theme_from_asset_file(false, None);
|
||||||
|
|
||||||
|
assert!(result.is_ok(), "Expected Ok result for None theme");
|
||||||
|
|
||||||
|
let theme_map = result.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
theme_map.get("background").map(String::as_str),
|
||||||
|
Some("white"),
|
||||||
|
"Expected default background color to be white"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
theme_map.get("foreground").map(String::as_str),
|
||||||
|
Some("black"),
|
||||||
|
"Expected default foreground color to be black"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
theme_map.contains_key("red"),
|
||||||
|
"Expected default theme to have a 'red' color"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
theme_map.contains_key("bold_green"),
|
||||||
|
"Expected default theme to have a 'bold_green' color"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn returns_a_valid_theme() {
|
||||||
|
let theme_name = "Dracula".to_string().into_spanned(Span::new(0, 7));
|
||||||
|
let result = super::get_theme_from_asset_file(false, Some(&theme_name));
|
||||||
|
|
||||||
|
assert!(result.is_ok(), "Expected Ok result for valid theme");
|
||||||
|
let theme_map = result.unwrap();
|
||||||
|
let required_keys = [
|
||||||
|
"background",
|
||||||
|
"foreground",
|
||||||
|
"red",
|
||||||
|
"green",
|
||||||
|
"blue",
|
||||||
|
"bold_red",
|
||||||
|
"bold_green",
|
||||||
|
"bold_blue",
|
||||||
|
];
|
||||||
|
|
||||||
|
for key in required_keys {
|
||||||
|
assert!(
|
||||||
|
theme_map.contains_key(key),
|
||||||
|
"Expected theme to contain key '{}'",
|
||||||
|
key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fails_with_unknown_theme_name() {
|
||||||
|
let result = super::get_theme_from_asset_file(
|
||||||
|
false,
|
||||||
|
Some(&"doesnt-exist".to_string().into_spanned(Span::new(0, 13))),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(result.is_err(), "Expected error for invalid theme name");
|
||||||
|
|
||||||
|
if let Err(err) = result {
|
||||||
|
assert!(
|
||||||
|
matches!(err, ShellError::TypeMismatch { .. }),
|
||||||
|
"Expected TypeMismatch error, got: {:?}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
|
||||||
|
if let ShellError::TypeMismatch { err_message, span } = err {
|
||||||
|
assert!(
|
||||||
|
err_message.contains("doesnt-exist"),
|
||||||
|
"Error message should mention theme name, got: {}",
|
||||||
|
err_message
|
||||||
|
);
|
||||||
|
assert_eq!(span.start, 0);
|
||||||
|
assert_eq!(span.end, 13);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_ansi_term::{build_all_gradient_text, gradient::TargetGround, Gradient, Rgb};
|
use nu_ansi_term::{Gradient, Rgb, build_all_gradient_text, gradient::TargetGround};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -71,26 +71,22 @@ impl Command for SubCommand {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "draw text in a gradient with foreground start and end colors",
|
description: "draw text in a gradient with foreground start and end colors",
|
||||||
example:
|
example: "'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff' --fgend '0xe81cff'",
|
||||||
"'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff' --fgend '0xe81cff'",
|
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "draw text in a gradient with foreground start and end colors and background start and end colors",
|
description: "draw text in a gradient with foreground start and end colors and background start and end colors",
|
||||||
example:
|
example: "'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff' --fgend '0xe81cff' --bgstart '0xe81cff' --bgend '0x40c9ff'",
|
||||||
"'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff' --fgend '0xe81cff' --bgstart '0xe81cff' --bgend '0x40c9ff'",
|
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "draw text in a gradient by specifying foreground start color - end color is assumed to be black",
|
description: "draw text in a gradient by specifying foreground start color - end color is assumed to be black",
|
||||||
example:
|
example: "'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff'",
|
||||||
"'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff'",
|
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "draw text in a gradient by specifying foreground end color - start color is assumed to be black",
|
description: "draw text in a gradient by specifying foreground end color - start color is assumed to be black",
|
||||||
example:
|
example: "'Hello, Nushell! This is a gradient.' | ansi gradient --fgend '0xe81cff'",
|
||||||
"'Hello, Nushell! This is a gradient.' | ansi gradient --fgend '0xe81cff'",
|
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -300,7 +296,7 @@ fn action(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{action, SubCommand};
|
use super::{SubCommand, action};
|
||||||
use nu_ansi_term::Rgb;
|
use nu_ansi_term::Rgb;
|
||||||
use nu_protocol::{Span, Value};
|
use nu_protocol::{Span, Value};
|
||||||
|
|
||||||
@ -314,7 +310,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fg_gradient() {
|
fn test_fg_gradient() {
|
||||||
let input_string = Value::test_string("Hello, World!");
|
let input_string = Value::test_string("Hello, World!");
|
||||||
let expected = Value::test_string("\u{1b}[38;2;64;201;255mH\u{1b}[38;2;76;187;254me\u{1b}[38;2;89;174;254ml\u{1b}[38;2;102;160;254ml\u{1b}[38;2;115;147;254mo\u{1b}[38;2;128;133;254m,\u{1b}[38;2;141;120;254m \u{1b}[38;2;153;107;254mW\u{1b}[38;2;166;94;254mo\u{1b}[38;2;179;80;254mr\u{1b}[38;2;192;67;254ml\u{1b}[38;2;205;53;254md\u{1b}[38;2;218;40;254m!\u{1b}[0m");
|
let expected = Value::test_string(
|
||||||
|
"\u{1b}[38;2;64;201;255mH\u{1b}[38;2;76;187;254me\u{1b}[38;2;89;174;254ml\u{1b}[38;2;102;160;254ml\u{1b}[38;2;115;147;254mo\u{1b}[38;2;128;133;254m,\u{1b}[38;2;141;120;254m \u{1b}[38;2;153;107;254mW\u{1b}[38;2;166;94;254mo\u{1b}[38;2;179;80;254mr\u{1b}[38;2;192;67;254ml\u{1b}[38;2;205;53;254md\u{1b}[38;2;218;40;254m!\u{1b}[0m",
|
||||||
|
);
|
||||||
let fg_start = Rgb::from_hex_string("0x40c9ff".to_string());
|
let fg_start = Rgb::from_hex_string("0x40c9ff".to_string());
|
||||||
let fg_end = Rgb::from_hex_string("0xe81cff".to_string());
|
let fg_end = Rgb::from_hex_string("0xe81cff".to_string());
|
||||||
let actual = action(
|
let actual = action(
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
use nu_protocol::{shell_error::io::IoError, Signals};
|
use nu_protocol::{Signals, shell_error::io::IoError};
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
@ -68,42 +68,33 @@ impl Command for FormatBits {
|
|||||||
Example {
|
Example {
|
||||||
description: "convert a binary value into a string, padded to 8 places with 0s",
|
description: "convert a binary value into a string, padded to 8 places with 0s",
|
||||||
example: "0x[1] | format bits",
|
example: "0x[1] | format bits",
|
||||||
result: Some(Value::string("00000001",
|
result: Some(Value::string("00000001", Span::test_data())),
|
||||||
Span::test_data(),
|
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "convert an int into a string, padded to 8 places with 0s",
|
description: "convert an int into a string, padded to 8 places with 0s",
|
||||||
example: "1 | format bits",
|
example: "1 | format bits",
|
||||||
result: Some(Value::string("00000001",
|
result: Some(Value::string("00000001", Span::test_data())),
|
||||||
Span::test_data(),
|
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "convert a filesize value into a string, padded to 8 places with 0s",
|
description: "convert a filesize value into a string, padded to 8 places with 0s",
|
||||||
example: "1b | format bits",
|
example: "1b | format bits",
|
||||||
result: Some(Value::string("00000001",
|
result: Some(Value::string("00000001", Span::test_data())),
|
||||||
Span::test_data(),
|
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "convert a duration value into a string, padded to 8 places with 0s",
|
description: "convert a duration value into a string, padded to 8 places with 0s",
|
||||||
example: "1ns | format bits",
|
example: "1ns | format bits",
|
||||||
result: Some(Value::string("00000001",
|
result: Some(Value::string("00000001", Span::test_data())),
|
||||||
Span::test_data(),
|
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "convert a boolean value into a string, padded to 8 places with 0s",
|
description: "convert a boolean value into a string, padded to 8 places with 0s",
|
||||||
example: "true | format bits",
|
example: "true | format bits",
|
||||||
result: Some(Value::string("00000001",
|
result: Some(Value::string("00000001", Span::test_data())),
|
||||||
Span::test_data(),
|
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "convert a string into a raw binary string, padded with 0s to 8 places",
|
description: "convert a string into a raw binary string, padded with 0s to 8 places",
|
||||||
example: "'nushell.sh' | format bits",
|
example: "'nushell.sh' | format bits",
|
||||||
result: Some(Value::string("01101110 01110101 01110011 01101000 01100101 01101100 01101100 00101110 01110011 01101000",
|
result: Some(Value::string(
|
||||||
|
"01101110 01110101 01110011 01101000 01100101 01101100 01101100 00101110 01110011 01101000",
|
||||||
Span::test_data(),
|
Span::test_data(),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
@ -143,7 +134,7 @@ fn byte_stream_to_bits(stream: ByteStream, head: Span) -> ByteStream {
|
|||||||
let mut byte = [0];
|
let mut byte = [0];
|
||||||
if reader
|
if reader
|
||||||
.read(&mut byte[..])
|
.read(&mut byte[..])
|
||||||
.map_err(|err| IoError::new(err.kind(), head, None))?
|
.map_err(|err| IoError::new(err, head, None))?
|
||||||
> 0
|
> 0
|
||||||
{
|
{
|
||||||
// Format the byte as bits
|
// Format the byte as bits
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::{ast::PathMember, engine::StateWorkingSet, Config, ListStream};
|
use nu_protocol::{Config, ListStream, ast::PathMember, casing::Casing, engine::StateWorkingSet};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FormatPattern;
|
pub struct FormatPattern;
|
||||||
@ -214,7 +214,7 @@ fn format(
|
|||||||
wrong_type: val.get_type().to_string(),
|
wrong_type: val.get_type().to_string(),
|
||||||
dst_span: head_span,
|
dst_span: head_span,
|
||||||
src_span: val.span(),
|
src_span: val.span(),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,14 +251,14 @@ fn format_record(
|
|||||||
val: path.to_string(),
|
val: path.to_string(),
|
||||||
span: *span,
|
span: *span,
|
||||||
optional: false,
|
optional: false,
|
||||||
|
casing: Casing::Sensitive,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
match data_as_value.clone().follow_cell_path(&path_members, false) {
|
|
||||||
Ok(value_at_column) => {
|
let expanded_string = data_as_value
|
||||||
output.push_str(value_at_column.to_expanded_string(", ", config).as_str())
|
.follow_cell_path(&path_members)?
|
||||||
}
|
.to_expanded_string(", ", config);
|
||||||
Err(se) => return Err(se),
|
output.push_str(expanded_string.as_str())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_cmd_base::input_handler::{operate, CellPathOnlyArgs};
|
use nu_cmd_base::input_handler::{CellPathOnlyArgs, operate};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -14,7 +14,7 @@ pub use snake_case::StrSnakeCase;
|
|||||||
pub use str_::Str;
|
pub use str_::Str;
|
||||||
pub use title_case::StrTitleCase;
|
pub use title_case::StrTitleCase;
|
||||||
|
|
||||||
use nu_cmd_base::input_handler::{operate as general_operate, CmdArgument};
|
use nu_cmd_base::input_handler::{CmdArgument, operate as general_operate};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
struct Arguments<F: Fn(&str) -> String + Send + Sync + 'static> {
|
struct Arguments<F: Fn(&str) -> String + Send + Sync + 'static> {
|
||||||
|
@ -3,10 +3,10 @@ authors = ["The Nushell Project Developers"]
|
|||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
description = "Nushell's core language commands"
|
description = "Nushell's core language commands"
|
||||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-lang"
|
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-lang"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-cmd-lang"
|
name = "nu-cmd-lang"
|
||||||
version = "0.104.0"
|
version = "0.105.1"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
bench = false
|
bench = false
|
||||||
@ -15,10 +15,11 @@ bench = false
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-engine = { path = "../nu-engine", version = "0.104.0", default-features = false }
|
nu-engine = { path = "../nu-engine", version = "0.105.1", default-features = false }
|
||||||
nu-parser = { path = "../nu-parser", version = "0.104.0" }
|
nu-parser = { path = "../nu-parser", version = "0.105.1" }
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.104.0", default-features = false }
|
nu-protocol = { path = "../nu-protocol", version = "0.105.1", default-features = false }
|
||||||
nu-utils = { path = "../nu-utils", version = "0.104.0", default-features = false }
|
nu-utils = { path = "../nu-utils", version = "0.105.1", default-features = false }
|
||||||
|
nu-cmd-base = { path = "../nu-cmd-base", version = "0.105.1" }
|
||||||
|
|
||||||
itertools = { workspace = true }
|
itertools = { workspace = true }
|
||||||
shadow-rs = { version = "1.1", default-features = false }
|
shadow-rs = { version = "1.1", default-features = false }
|
||||||
@ -29,6 +30,7 @@ shadow-rs = { version = "1.1", default-features = false, features = ["build"] }
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
quickcheck = { workspace = true }
|
quickcheck = { workspace = true }
|
||||||
quickcheck_macros = { workspace = true }
|
quickcheck_macros = { workspace = true }
|
||||||
|
miette = { workspace = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["os"]
|
default = ["os"]
|
||||||
|
148
crates/nu-cmd-lang/src/core_commands/attr/deprecated.rs
Normal file
148
crates/nu-cmd-lang/src/core_commands/attr/deprecated.rs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
use nu_cmd_base::WrapCall;
|
||||||
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AttrDeprecated;
|
||||||
|
|
||||||
|
impl Command for AttrDeprecated {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"attr deprecated"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("attr deprecated")
|
||||||
|
.input_output_types(vec![
|
||||||
|
(Type::Nothing, Type::Nothing),
|
||||||
|
(Type::Nothing, Type::String),
|
||||||
|
])
|
||||||
|
.optional(
|
||||||
|
"message",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Help message to include with deprecation warning.",
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"flag",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Mark a flag as deprecated rather than the command",
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"since",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Denote a version when this item was deprecated",
|
||||||
|
Some('s'),
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"remove",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Denote a version when this item will be removed",
|
||||||
|
Some('r'),
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"report",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"How to warn about this item. One of: first (default), every",
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.category(Category::Core)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"Attribute for marking a command or flag as deprecated."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_description(&self) -> &str {
|
||||||
|
"Mark a command (default) or flag/switch (--flag) as deprecated. By default, only the first usage will trigger a deprecation warning.
|
||||||
|
|
||||||
|
A help message can be included to provide more context for the deprecation, such as what to use as a replacement.
|
||||||
|
|
||||||
|
Also consider setting the category to deprecated with @category deprecated"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let call = WrapCall::Eval(engine_state, stack, call);
|
||||||
|
Ok(deprecated_record(call)?.into_pipeline_data())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_const(
|
||||||
|
&self,
|
||||||
|
working_set: &StateWorkingSet,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let call = WrapCall::ConstEval(working_set, call);
|
||||||
|
Ok(deprecated_record(call)?.into_pipeline_data())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_const(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Add a deprecation warning to a custom command",
|
||||||
|
example: r###"@deprecated
|
||||||
|
def outdated [] {}"###,
|
||||||
|
result: Some(Value::nothing(Span::test_data())),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Add a deprecation warning with a custom message",
|
||||||
|
example: r###"@deprecated "Use my-new-command instead."
|
||||||
|
@category deprecated
|
||||||
|
def my-old-command [] {}"###,
|
||||||
|
result: Some(Value::string(
|
||||||
|
"Use my-new-command instead.",
|
||||||
|
Span::test_data(),
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deprecated_record(call: WrapCall) -> Result<Value, ShellError> {
|
||||||
|
let (call, message): (_, Option<Spanned<String>>) = call.opt(0)?;
|
||||||
|
let (call, flag): (_, Option<Spanned<String>>) = call.get_flag("flag")?;
|
||||||
|
let (call, since): (_, Option<Spanned<String>>) = call.get_flag("since")?;
|
||||||
|
let (call, remove): (_, Option<Spanned<String>>) = call.get_flag("remove")?;
|
||||||
|
let (call, report): (_, Option<Spanned<String>>) = call.get_flag("report")?;
|
||||||
|
|
||||||
|
let mut record = Record::new();
|
||||||
|
if let Some(message) = message {
|
||||||
|
record.push("help", Value::string(message.item, message.span))
|
||||||
|
}
|
||||||
|
if let Some(flag) = flag {
|
||||||
|
record.push("flag", Value::string(flag.item, flag.span))
|
||||||
|
}
|
||||||
|
if let Some(since) = since {
|
||||||
|
record.push("since", Value::string(since.item, since.span))
|
||||||
|
}
|
||||||
|
if let Some(remove) = remove {
|
||||||
|
record.push("expected_removal", Value::string(remove.item, remove.span))
|
||||||
|
}
|
||||||
|
|
||||||
|
let report = if let Some(Spanned { item, span }) = report {
|
||||||
|
match item.as_str() {
|
||||||
|
"every" => Value::string(item, span),
|
||||||
|
"first" => Value::string(item, span),
|
||||||
|
_ => {
|
||||||
|
return Err(ShellError::IncorrectValue {
|
||||||
|
msg: "The report mode must be one of: every, first".into(),
|
||||||
|
val_span: span,
|
||||||
|
call_span: call.head(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Value::string("first", call.head())
|
||||||
|
};
|
||||||
|
record.push("report", report);
|
||||||
|
|
||||||
|
Ok(Value::record(record, call.head()))
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
mod category;
|
mod category;
|
||||||
|
mod deprecated;
|
||||||
mod example;
|
mod example;
|
||||||
mod search_terms;
|
mod search_terms;
|
||||||
|
|
||||||
pub use category::AttrCategory;
|
pub use category::AttrCategory;
|
||||||
|
pub use deprecated::AttrDeprecated;
|
||||||
pub use example::AttrExample;
|
pub use example::AttrExample;
|
||||||
pub use search_terms::AttrSearchTerms;
|
pub use search_terms::AttrSearchTerms;
|
||||||
|
@ -34,10 +34,15 @@ impl Command for Break {
|
|||||||
&self,
|
&self,
|
||||||
_engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
Err(ShellError::Break { span: call.head })
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
|
// running in IR mode.
|
||||||
|
eprintln!(
|
||||||
|
"Tried to execute 'run' for the 'break' command: this code path should never be reached in IR mode"
|
||||||
|
);
|
||||||
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block, redirect_env};
|
use nu_engine::{command_prelude::*, get_eval_block, redirect_env};
|
||||||
use nu_protocol::{engine::Closure, DataSource, PipelineMetadata};
|
use nu_protocol::{DataSource, PipelineMetadata, engine::Closure};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Collect;
|
pub struct Collect;
|
||||||
|
@ -41,35 +41,17 @@ impl Command for Const {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
eprintln!(
|
||||||
let var_id = if let Some(id) = call.positional_nth(0).and_then(|pos| pos.as_var()) {
|
"Tried to execute 'run' for the 'const' command: this code path should never be reached in IR mode"
|
||||||
id
|
);
|
||||||
} else {
|
unreachable!()
|
||||||
return Err(ShellError::NushellFailedSpanned {
|
|
||||||
msg: "Could not get variable".to_string(),
|
|
||||||
label: "variable not added by the parser".to_string(),
|
|
||||||
span: call.head,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(constval) = &engine_state.get_var(var_id).const_val {
|
|
||||||
stack.add_var(var_id, constval.clone());
|
|
||||||
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
} else {
|
|
||||||
Err(ShellError::NushellFailedSpanned {
|
|
||||||
msg: "Missing Constant".to_string(),
|
|
||||||
label: "constant not added by the parser".to_string(),
|
|
||||||
span: call.head,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_const(
|
fn run_const(
|
||||||
|
@ -33,10 +33,15 @@ impl Command for Continue {
|
|||||||
&self,
|
&self,
|
||||||
_engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
Err(ShellError::Continue { span: call.head })
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
|
// running in IR mode.
|
||||||
|
eprintln!(
|
||||||
|
"Tried to execute 'run' for the 'continue' command: this code path should never be reached in IR mode"
|
||||||
|
);
|
||||||
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{Closure, StateWorkingSet},
|
|
||||||
BlockId, ByteStreamSource, Category, PipelineMetadata, Signature,
|
BlockId, ByteStreamSource, Category, PipelineMetadata, Signature,
|
||||||
|
engine::{Closure, StateWorkingSet},
|
||||||
};
|
};
|
||||||
use std::any::type_name;
|
use std::any::type_name;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -72,8 +72,7 @@ impl Command for Describe {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Describe the type of a record in a detailed way",
|
description: "Describe the type of a record in a detailed way",
|
||||||
example:
|
example: "{shell:'true', uwu:true, features: {bugs:false, multiplatform:true, speed: 10}, fib: [1 1 2 3 5 8], on_save: {|x| $'Saving ($x)'}, first_commit: 2019-05-10, my_duration: (4min + 20sec)} | describe -d",
|
||||||
"{shell:'true', uwu:true, features: {bugs:false, multiplatform:true, speed: 10}, fib: [1 1 2 3 5 8], on_save: {|x| $'Saving ($x)'}, first_commit: 2019-05-10, my_duration: (4min + 20sec)} | describe -d",
|
|
||||||
result: Some(Value::test_record(record!(
|
result: Some(Value::test_record(record!(
|
||||||
"type" => Value::test_string("record"),
|
"type" => Value::test_string("record"),
|
||||||
"detailed_type" => Value::test_string("record<shell: string, uwu: bool, features: record<bugs: bool, multiplatform: bool, speed: int>, fib: list<int>, on_save: closure, first_commit: datetime, my_duration: duration>"),
|
"detailed_type" => Value::test_string("record<shell: string, uwu: bool, features: record<bugs: bool, multiplatform: bool, speed: int>, fib: list<int>, on_save: closure, first_commit: datetime, my_duration: duration>"),
|
||||||
@ -191,7 +190,7 @@ impl Command for Describe {
|
|||||||
Example {
|
Example {
|
||||||
description: "Describe the type of a stream with detailed information",
|
description: "Describe the type of a stream with detailed information",
|
||||||
example: "[1 2 3] | each {|i| echo $i} | describe -d",
|
example: "[1 2 3] | each {|i| echo $i} | describe -d",
|
||||||
result: None // Give "Running external commands not supported" error
|
result: None, // Give "Running external commands not supported" error
|
||||||
// result: Some(Value::test_record(record!(
|
// result: Some(Value::test_record(record!(
|
||||||
// "type" => Value::test_string("stream"),
|
// "type" => Value::test_string("stream"),
|
||||||
// "origin" => Value::test_string("nushell"),
|
// "origin" => Value::test_string("nushell"),
|
||||||
@ -209,13 +208,13 @@ impl Command for Describe {
|
|||||||
Example {
|
Example {
|
||||||
description: "Describe a stream of data, collecting it first",
|
description: "Describe a stream of data, collecting it first",
|
||||||
example: "[1 2 3] | each {|i| echo $i} | describe",
|
example: "[1 2 3] | each {|i| echo $i} | describe",
|
||||||
result: None // Give "Running external commands not supported" error
|
result: None, // Give "Running external commands not supported" error
|
||||||
// result: Some(Value::test_string("list<int> (stream)")),
|
// result: Some(Value::test_string("list<int> (stream)")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Describe the input but do not collect streams",
|
description: "Describe the input but do not collect streams",
|
||||||
example: "[1 2 3] | each {|i| echo $i} | describe --no-collect",
|
example: "[1 2 3] | each {|i| echo $i} | describe --no-collect",
|
||||||
result: None // Give "Running external commands not supported" error
|
result: None, // Give "Running external commands not supported" error
|
||||||
// result: Some(Value::test_string("stream")),
|
// result: Some(Value::test_string("stream")),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -2,7 +2,7 @@ use nu_engine::{command_prelude::*, get_eval_block_with_early_return, redirect_e
|
|||||||
#[cfg(feature = "os")]
|
#[cfg(feature = "os")]
|
||||||
use nu_protocol::process::{ChildPipe, ChildProcess};
|
use nu_protocol::process::{ChildPipe, ChildProcess};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::Closure, shell_error::io::IoError, ByteStream, ByteStreamSource, OutDest,
|
ByteStream, ByteStreamSource, OutDest, engine::Closure, shell_error::io::IoError,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
@ -107,14 +107,14 @@ impl Command for Do {
|
|||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
stdout.read_to_end(&mut buf).map_err(|err| {
|
stdout.read_to_end(&mut buf).map_err(|err| {
|
||||||
IoError::new_internal(
|
IoError::new_internal(
|
||||||
err.kind(),
|
err,
|
||||||
"Could not read stdout to end",
|
"Could not read stdout to end",
|
||||||
nu_protocol::location!(),
|
nu_protocol::location!(),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
Ok::<_, ShellError>(buf)
|
Ok::<_, ShellError>(buf)
|
||||||
})
|
})
|
||||||
.map_err(|err| IoError::new(err.kind(), head, None))
|
.map_err(|err| IoError::new(err, head, None))
|
||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ impl Command for Do {
|
|||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
stderr
|
stderr
|
||||||
.read_to_string(&mut buf)
|
.read_to_string(&mut buf)
|
||||||
.map_err(|err| IoError::new(err.kind(), span, None))?;
|
.map_err(|err| IoError::new(err, span, None))?;
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -63,8 +63,7 @@ little reason to use this over just writing the values as-is."#
|
|||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description:
|
description: "Returns the piped-in value, by using the special $in variable to obtain it.",
|
||||||
"Returns the piped-in value, by using the special $in variable to obtain it.",
|
|
||||||
example: "echo $in",
|
example: "echo $in",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
|
@ -76,8 +76,7 @@ impl Command for ErrorMake {
|
|||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description:
|
description: "Create a custom error for a custom command that shows the span of the argument",
|
||||||
"Create a custom error for a custom command that shows the span of the argument",
|
|
||||||
example: r#"def foo [x] {
|
example: r#"def foo [x] {
|
||||||
error make {
|
error make {
|
||||||
msg: "this is fishy"
|
msg: "this is fishy"
|
||||||
@ -106,7 +105,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
|||||||
span: throw_span,
|
span: throw_span,
|
||||||
help: None,
|
help: None,
|
||||||
inner: vec![],
|
inner: vec![],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -119,7 +118,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
|||||||
span: Some(span),
|
span: Some(span),
|
||||||
help: None,
|
help: None,
|
||||||
inner: vec![],
|
inner: vec![],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return ShellError::GenericError {
|
return ShellError::GenericError {
|
||||||
@ -128,7 +127,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
|||||||
span: Some(span),
|
span: Some(span),
|
||||||
help: None,
|
help: None,
|
||||||
inner: vec![],
|
inner: vec![],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -146,7 +145,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
|||||||
span: Some(span),
|
span: Some(span),
|
||||||
help: None,
|
help: None,
|
||||||
inner: vec![],
|
inner: vec![],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
// correct return: no label
|
// correct return: no label
|
||||||
None => {
|
None => {
|
||||||
@ -156,7 +155,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
|||||||
span: throw_span,
|
span: throw_span,
|
||||||
help,
|
help,
|
||||||
inner: vec![],
|
inner: vec![],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -180,7 +179,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
|||||||
span: Some(label_span),
|
span: Some(label_span),
|
||||||
help: None,
|
help: None,
|
||||||
inner: vec![],
|
inner: vec![],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return ShellError::GenericError {
|
return ShellError::GenericError {
|
||||||
@ -189,7 +188,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
|||||||
span: Some(label_span),
|
span: Some(label_span),
|
||||||
help: None,
|
help: None,
|
||||||
inner: vec![],
|
inner: vec![],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -202,7 +201,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
|||||||
span: Some(value.span()),
|
span: Some(value.span()),
|
||||||
help: None,
|
help: None,
|
||||||
inner: vec![],
|
inner: vec![],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
// correct return: label, no span
|
// correct return: label, no span
|
||||||
None => {
|
None => {
|
||||||
@ -212,7 +211,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
|||||||
span: throw_span,
|
span: throw_span,
|
||||||
help,
|
help,
|
||||||
inner: vec![],
|
inner: vec![],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block, get_eval_expression};
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::{engine::CommandType, Signals};
|
use nu_protocol::engine::CommandType;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct For;
|
pub struct For;
|
||||||
@ -43,83 +43,17 @@ impl Command for For {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
eprintln!(
|
||||||
let head = call.head;
|
"Tried to execute 'run' for the 'for' command: this code path should never be reached in IR mode"
|
||||||
let var_id = call
|
);
|
||||||
.positional_nth(0)
|
unreachable!()
|
||||||
.expect("checked through parser")
|
|
||||||
.as_var()
|
|
||||||
.expect("internal error: missing variable");
|
|
||||||
|
|
||||||
let keyword_expr = call
|
|
||||||
.positional_nth(1)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_keyword()
|
|
||||||
.expect("internal error: missing keyword");
|
|
||||||
|
|
||||||
let block_id = call
|
|
||||||
.positional_nth(2)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing block");
|
|
||||||
|
|
||||||
let eval_expression = get_eval_expression(engine_state);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
|
|
||||||
let value = eval_expression(engine_state, stack, keyword_expr)?;
|
|
||||||
|
|
||||||
let engine_state = engine_state.clone();
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
|
|
||||||
let stack = &mut stack.push_redirection(None, None);
|
|
||||||
|
|
||||||
let span = value.span();
|
|
||||||
match value {
|
|
||||||
Value::List { vals, .. } => {
|
|
||||||
for x in vals.into_iter() {
|
|
||||||
engine_state.signals().check(head)?;
|
|
||||||
|
|
||||||
// with_env() is used here to ensure that each iteration uses
|
|
||||||
// a different set of environment variables.
|
|
||||||
// Hence, a 'cd' in the first loop won't affect the next loop.
|
|
||||||
|
|
||||||
stack.add_var(var_id, x);
|
|
||||||
|
|
||||||
match eval_block(&engine_state, stack, block, PipelineData::empty()) {
|
|
||||||
Err(ShellError::Break { .. }) => break,
|
|
||||||
Err(ShellError::Continue { .. }) => continue,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
Ok(data) => data.drain()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Value::Range { val, .. } => {
|
|
||||||
for x in val.into_range_iter(span, Signals::empty()) {
|
|
||||||
engine_state.signals().check(head)?;
|
|
||||||
stack.add_var(var_id, x);
|
|
||||||
|
|
||||||
match eval_block(&engine_state, stack, block, PipelineData::empty()) {
|
|
||||||
Err(ShellError::Break { .. }) => break,
|
|
||||||
Err(ShellError::Continue { .. }) => continue,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
Ok(data) => data.drain()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x => {
|
|
||||||
stack.add_var(var_id, x);
|
|
||||||
|
|
||||||
eval_block(&engine_state, stack, block, PipelineData::empty())?.into_value(head)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
use nu_engine::{
|
use nu_engine::command_prelude::*;
|
||||||
command_prelude::*, get_eval_block, get_eval_expression, get_eval_expression_with_input,
|
|
||||||
};
|
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{CommandType, StateWorkingSet},
|
engine::{CommandType, StateWorkingSet},
|
||||||
eval_const::{eval_const_subexpression, eval_constant, eval_constant_with_input},
|
eval_const::{eval_const_subexpression, eval_constant, eval_constant_with_input},
|
||||||
@ -60,8 +58,6 @@ impl Command for If {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
|
||||||
// running in IR mode.
|
|
||||||
let call = call.assert_ast_call()?;
|
let call = call.assert_ast_call()?;
|
||||||
let cond = call.positional_nth(0).expect("checked through parser");
|
let cond = call.positional_nth(0).expect("checked through parser");
|
||||||
let then_block = call
|
let then_block = call
|
||||||
@ -97,43 +93,17 @@ impl Command for If {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
eprintln!(
|
||||||
let cond = call.positional_nth(0).expect("checked through parser");
|
"Tried to execute 'run' for the 'if' command: this code path should never be reached in IR mode"
|
||||||
let then_block = call
|
);
|
||||||
.positional_nth(1)
|
unreachable!()
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing block");
|
|
||||||
let else_case = call.positional_nth(2);
|
|
||||||
|
|
||||||
let eval_expression = get_eval_expression(engine_state);
|
|
||||||
let eval_expression_with_input = get_eval_expression_with_input(engine_state);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
|
|
||||||
if eval_expression(engine_state, stack, cond)?.as_bool()? {
|
|
||||||
let block = engine_state.get_block(then_block);
|
|
||||||
eval_block(engine_state, stack, block, input)
|
|
||||||
} else if let Some(else_case) = else_case {
|
|
||||||
if let Some(else_expr) = else_case.as_keyword() {
|
|
||||||
if let Some(block_id) = else_expr.as_block() {
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
eval_block(engine_state, stack, block, input)
|
|
||||||
} else {
|
|
||||||
eval_expression_with_input(engine_state, stack, else_expr, input)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
eval_expression_with_input(engine_state, stack, else_case, input)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::{engine::StateWorkingSet, ByteStreamSource, OutDest};
|
use nu_protocol::{ByteStreamSource, OutDest, engine::StateWorkingSet};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Ignore;
|
pub struct Ignore;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block};
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::engine::CommandType;
|
use nu_protocol::engine::CommandType;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -41,47 +41,17 @@ impl Command for Let {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
eprintln!(
|
||||||
let var_id = call
|
"Tried to execute 'run' for the 'let' command: this code path should never be reached in IR mode"
|
||||||
.positional_nth(0)
|
);
|
||||||
.expect("checked through parser")
|
unreachable!()
|
||||||
.as_var()
|
|
||||||
.expect("internal error: missing variable");
|
|
||||||
|
|
||||||
let block_id = call
|
|
||||||
.positional_nth(1)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing right hand side");
|
|
||||||
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
let stack = &mut stack.start_collect_value();
|
|
||||||
let pipeline_data = eval_block(engine_state, stack, block, input)?;
|
|
||||||
let value = pipeline_data.into_value(call.head)?;
|
|
||||||
|
|
||||||
// if given variable type is Glob, and our result is string
|
|
||||||
// then nushell need to convert from Value::String to Value::Glob
|
|
||||||
// it's assigned by demand, then it's not quoted, and it's required to expand
|
|
||||||
// if we pass it to other commands.
|
|
||||||
let var_type = &engine_state.get_var(var_id).ty;
|
|
||||||
let val_span = value.span();
|
|
||||||
let value = match value {
|
|
||||||
Value::String { val, .. } if var_type == &Type::Glob => {
|
|
||||||
Value::glob(val, false, val_span)
|
|
||||||
}
|
|
||||||
value => value,
|
|
||||||
};
|
|
||||||
|
|
||||||
stack.add_var(var_id, value);
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block};
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::engine::CommandType;
|
use nu_protocol::engine::CommandType;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -32,37 +32,17 @@ impl Command for Loop {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
eprintln!(
|
||||||
let head = call.head;
|
"Tried to execute 'run' for the 'loop' command: this code path should never be reached in IR mode"
|
||||||
let block_id = call
|
);
|
||||||
.positional_nth(0)
|
unreachable!()
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing block");
|
|
||||||
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
|
|
||||||
let stack = &mut stack.push_redirection(None, None);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
engine_state.signals().check(head)?;
|
|
||||||
|
|
||||||
match eval_block(engine_state, stack, block, PipelineData::empty()) {
|
|
||||||
Err(ShellError::Break { .. }) => break,
|
|
||||||
Err(ShellError::Continue { .. }) => continue,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
Ok(data) => data.drain()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use nu_engine::{
|
use nu_engine::command_prelude::*;
|
||||||
command_prelude::*, get_eval_block, get_eval_expression, get_eval_expression_with_input,
|
use nu_protocol::engine::CommandType;
|
||||||
};
|
|
||||||
use nu_protocol::engine::{CommandType, Matcher};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Match;
|
pub struct Match;
|
||||||
@ -38,62 +36,31 @@ impl Command for Match {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
eprintln!(
|
||||||
let value: Value = call.req(engine_state, stack, 0)?;
|
"Tried to execute 'run' for the 'match' command: this code path should never be reached in IR mode"
|
||||||
let matches = call
|
);
|
||||||
.positional_nth(1)
|
unreachable!()
|
||||||
.expect("checked through parser")
|
|
||||||
.as_match_block()
|
|
||||||
.expect("missing match block");
|
|
||||||
|
|
||||||
let eval_expression = get_eval_expression(engine_state);
|
|
||||||
let eval_expression_with_input = get_eval_expression_with_input(engine_state);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
|
|
||||||
let mut match_variables = vec![];
|
|
||||||
for (pattern, expr) in matches {
|
|
||||||
if pattern.match_value(&value, &mut match_variables) {
|
|
||||||
// This case does match, go ahead and return the evaluated expression
|
|
||||||
for (id, value) in match_variables.drain(..) {
|
|
||||||
stack.add_var(id, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
let guard_matches = if let Some(guard) = &pattern.guard {
|
|
||||||
let Value::Bool { val, .. } = eval_expression(engine_state, stack, guard)?
|
|
||||||
else {
|
|
||||||
return Err(ShellError::MatchGuardNotBool { span: guard.span });
|
|
||||||
};
|
|
||||||
|
|
||||||
val
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
};
|
|
||||||
|
|
||||||
if guard_matches {
|
|
||||||
return if let Some(block_id) = expr.as_block() {
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
eval_block(engine_state, stack, block, input)
|
|
||||||
} else {
|
|
||||||
eval_expression_with_input(engine_state, stack, expr, input)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match_variables.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(PipelineData::Empty)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Match on a value",
|
||||||
|
example: "match 3 { 1 => 'one', 2 => 'two', 3 => 'three' }",
|
||||||
|
result: Some(Value::test_string("three")),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Match against alternative values",
|
||||||
|
example: "match 'three' { 1 | 'one' => '-', 2 | 'two' => '--', 3 | 'three' => '---' }",
|
||||||
|
result: Some(Value::test_string("---")),
|
||||||
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Match on a value in range",
|
description: "Match on a value in range",
|
||||||
example: "match 3 { 1..10 => 'yes!' }",
|
example: "match 3 { 1..10 => 'yes!' }",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block};
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::engine::CommandType;
|
use nu_protocol::engine::CommandType;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -41,47 +41,17 @@ impl Command for Mut {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
eprintln!(
|
||||||
let var_id = call
|
"Tried to execute 'run' for the 'mut' command: this code path should never be reached in IR mode"
|
||||||
.positional_nth(0)
|
);
|
||||||
.expect("checked through parser")
|
unreachable!()
|
||||||
.as_var()
|
|
||||||
.expect("internal error: missing variable");
|
|
||||||
|
|
||||||
let block_id = call
|
|
||||||
.positional_nth(1)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing right hand side");
|
|
||||||
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
let stack = &mut stack.start_collect_value();
|
|
||||||
let pipeline_data = eval_block(engine_state, stack, block, input)?;
|
|
||||||
let value = pipeline_data.into_value(call.head)?;
|
|
||||||
|
|
||||||
// if given variable type is Glob, and our result is string
|
|
||||||
// then nushell need to convert from Value::String to Value::Glob
|
|
||||||
// it's assigned by demand, then it's not quoted, and it's required to expand
|
|
||||||
// if we pass it to other commands.
|
|
||||||
let var_type = &engine_state.get_var(var_id).ty;
|
|
||||||
let val_span = value.span();
|
|
||||||
let value = match value {
|
|
||||||
Value::String { val, .. } if var_type == &Type::Glob => {
|
|
||||||
Value::glob(val, false, val_span)
|
|
||||||
}
|
|
||||||
value => value,
|
|
||||||
};
|
|
||||||
|
|
||||||
stack.add_var(var_id, value);
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -76,7 +76,7 @@ impl Command for OverlayHide {
|
|||||||
return Err(ShellError::EnvVarNotFoundAtRuntime {
|
return Err(ShellError::EnvVarNotFoundAtRuntime {
|
||||||
envvar_name: name.item,
|
envvar_name: name.item,
|
||||||
span: name.span,
|
span: name.span,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_engine::command_prelude::*;
|
use nu_engine::{command_prelude::*, redirect_env};
|
||||||
use nu_protocol::engine::CommandType;
|
use nu_protocol::engine::CommandType;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -18,6 +18,11 @@ impl Command for OverlayNew {
|
|||||||
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
||||||
.allow_variants_without_examples(true)
|
.allow_variants_without_examples(true)
|
||||||
.required("name", SyntaxShape::String, "Name of the overlay.")
|
.required("name", SyntaxShape::String, "Name of the overlay.")
|
||||||
|
.switch(
|
||||||
|
"reload",
|
||||||
|
"If the overlay already exists, reload its environment.",
|
||||||
|
Some('r'),
|
||||||
|
)
|
||||||
// TODO:
|
// TODO:
|
||||||
// .switch(
|
// .switch(
|
||||||
// "prefix",
|
// "prefix",
|
||||||
@ -41,13 +46,20 @@ This command is a parser keyword. For details, check:
|
|||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
caller_stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let name_arg: Spanned<String> = call.req(engine_state, stack, 0)?;
|
let name_arg: Spanned<String> = call.req(engine_state, caller_stack, 0)?;
|
||||||
|
let reload = call.has_flag(engine_state, caller_stack, "reload")?;
|
||||||
|
|
||||||
stack.add_overlay(name_arg.item);
|
if reload {
|
||||||
|
let callee_stack = caller_stack.clone();
|
||||||
|
caller_stack.add_overlay(name_arg.item);
|
||||||
|
redirect_env(engine_state, caller_stack, &callee_stack);
|
||||||
|
} else {
|
||||||
|
caller_stack.add_overlay(name_arg.item);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(PipelineData::empty())
|
Ok(PipelineData::empty())
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use nu_engine::{
|
|||||||
command_prelude::*, find_in_dirs_env, get_dirs_var_from_call, get_eval_block, redirect_env,
|
command_prelude::*, find_in_dirs_env, get_dirs_var_from_call, get_eval_block, redirect_env,
|
||||||
};
|
};
|
||||||
use nu_parser::trim_quotes_str;
|
use nu_parser::trim_quotes_str;
|
||||||
use nu_protocol::{ast::Expr, engine::CommandType, ModuleId};
|
use nu_protocol::{ModuleId, ast::Expr, engine::CommandType};
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
@ -35,17 +35,17 @@ impl Command for Return {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let return_value: Option<Value> = call.opt(engine_state, stack, 0)?;
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
let value = return_value.unwrap_or(Value::nothing(call.head));
|
// running in IR mode.
|
||||||
Err(ShellError::Return {
|
eprintln!(
|
||||||
span: call.head,
|
"Tried to execute 'run' for the 'return' command: this code path should never be reached in IR mode"
|
||||||
value: Box::new(value),
|
);
|
||||||
})
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user