mirror of
https://github.com/nushell/nushell.git
synced 2025-07-01 15:11:52 +02:00
Compare commits
3 Commits
main
...
release/0.
Author | SHA1 | Date | |
---|---|---|---|
98521100ed | |||
985211a924 | |||
a3388b00ae |
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.7
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
||||
|
||||
- name: cargo fmt
|
||||
run: cargo fmt --all -- --check
|
||||
@ -65,7 +65,7 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.7
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
||||
|
||||
- name: Tests
|
||||
run: cargo test --workspace --profile ci --exclude nu_plugin_*
|
||||
@ -94,7 +94,7 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.7
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
||||
|
||||
- name: Install Nushell
|
||||
run: cargo install --path . --locked --force
|
||||
@ -145,7 +145,7 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.7
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
||||
|
||||
- name: Clippy
|
||||
run: cargo clippy --package nu_plugin_* -- $CLIPPY_OPTIONS
|
||||
@ -186,7 +186,7 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.7
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
||||
|
||||
- name: Add wasm32-unknown-unknown target
|
||||
run: rustup target add wasm32-unknown-unknown
|
||||
|
25
.github/workflows/friendly-config-reminder.yml
vendored
25
.github/workflows/friendly-config-reminder.yml
vendored
@ -1,25 +0,0 @@
|
||||
name: Comment on changes to the config
|
||||
on:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- 'crates/nu-protocol/src/config/**'
|
||||
jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check if there is already a bot comment
|
||||
uses: peter-evans/find-comment@v3
|
||||
id: fc
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-author: 'github-actions[bot]'
|
||||
body-includes: Hey, just a bot checking in!
|
||||
- name: Create comment if there is not
|
||||
if: steps.fc.outputs.comment-id == ''
|
||||
uses: peter-evans/create-or-update-comment@v4
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
Hey, just a bot checking in! You edited files related to the configuration.
|
||||
If you changed any of the default values or added a new config option, don't forget to update the [`doc_config.nu`](https://github.com/nushell/nushell/blob/main/crates/nu-utils/src/default_files/doc_config.nu) which documents the options for our users including the defaults provided by the Rust implementation.
|
||||
If you didn't make a change here, you can just ignore me.
|
27
.github/workflows/nightly-build.yml
vendored
27
.github/workflows/nightly-build.yml
vendored
@ -46,7 +46,7 @@ jobs:
|
||||
uses: hustcer/setup-nu@v3
|
||||
if: github.repository == 'nushell/nightly'
|
||||
with:
|
||||
version: 0.105.1
|
||||
version: 0.103.0
|
||||
|
||||
# Synchronize the main branch of nightly repo with the main branch of Nushell official repo
|
||||
- name: Prepare for Nightly Release
|
||||
@ -127,7 +127,6 @@ jobs:
|
||||
- armv7-unknown-linux-musleabihf
|
||||
- riscv64gc-unknown-linux-gnu
|
||||
- loongarch64-unknown-linux-gnu
|
||||
- loongarch64-unknown-linux-musl
|
||||
include:
|
||||
- target: aarch64-apple-darwin
|
||||
os: macos-latest
|
||||
@ -153,8 +152,6 @@ jobs:
|
||||
os: ubuntu-22.04
|
||||
- target: loongarch64-unknown-linux-gnu
|
||||
os: ubuntu-22.04
|
||||
- target: loongarch64-unknown-linux-musl
|
||||
os: ubuntu-22.04
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
@ -182,22 +179,36 @@ jobs:
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
|
||||
with:
|
||||
cache: false
|
||||
rustflags: ''
|
||||
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v3
|
||||
if: ${{ matrix.os != 'windows-11-arm' }}
|
||||
with:
|
||||
version: 0.105.1
|
||||
version: 0.103.0
|
||||
|
||||
- name: Release Nu Binary
|
||||
id: nu
|
||||
if: ${{ matrix.os != 'windows-11-arm' }}
|
||||
run: nu .github/workflows/release-pkg.nu
|
||||
env:
|
||||
OS: ${{ matrix.os }}
|
||||
REF: ${{ github.ref }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
|
||||
- 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
|
||||
if: ${{ failure() }}
|
||||
uses: JasonEtco/create-an-issue@v2
|
||||
@ -217,7 +228,9 @@ jobs:
|
||||
prerelease: true
|
||||
files: |
|
||||
${{ steps.nu.outputs.msi }}
|
||||
${{ 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:
|
||||
@ -263,7 +276,7 @@ jobs:
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v3
|
||||
with:
|
||||
version: 0.105.1
|
||||
version: 0.103.0
|
||||
|
||||
# Keep the last a few releases
|
||||
- name: Delete Older Releases
|
||||
|
62
.github/workflows/release-msi.nu
vendored
62
.github/workflows/release-msi.nu
vendored
@ -1,62 +0,0 @@
|
||||
#!/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
103
.github/workflows/release-msi.yml
vendored
@ -1,103 +0,0 @@
|
||||
#
|
||||
# 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: 0.105.1
|
||||
|
||||
- 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 }}
|
30
.github/workflows/release-pkg.nu
vendored
30
.github/workflows/release-pkg.nu
vendored
@ -8,10 +8,10 @@
|
||||
|
||||
# Instructions for manually creating an MSI for Winget Releases when they fail
|
||||
# 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
|
||||
# checkout the release you want to publish
|
||||
# 1. git checkout 0.103.0
|
||||
# 1. git checkout 0.86.0
|
||||
# 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. hide-env CARGO_TARGET_DIR
|
||||
@ -23,13 +23,19 @@
|
||||
# 7. $env.Path = ($env.Path | append 'c:\apps\7-zip')
|
||||
# make sure aria2c.exe is in your path https://github.com/aria2/aria2
|
||||
# 8. $env.Path = ($env.Path | append 'c:\path\to\aria2c')
|
||||
# make sure you have the wix 6.0 installed: dotnet tool install --global wix --version 6.0.0
|
||||
# then build nu*.exe and the MSI installer by running:
|
||||
# 9. source .github\workflows\release-pkg.nu
|
||||
# make sure you have the wixtools installed https://wixtoolset.org/
|
||||
# 9. $env.Path = ($env.Path | append 'C:\Users\dschroeder\AppData\Local\tauri\WixTools')
|
||||
# You need to run the release-pkg twice. The first pass, with _EXTRA_ as 'bin', makes the output
|
||||
# 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
|
||||
# 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
|
||||
# 10. open wix\bin\x64\Release\nu-0.103.0-x86_64-pc-windows-msvc.msi | hash sha256
|
||||
# 15. open target\wix\nu-0.74.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
|
||||
|
||||
|
||||
@ -79,14 +85,14 @@ if $os in ['macos-latest'] or $USE_UBUNTU {
|
||||
cargo-build-nu
|
||||
}
|
||||
'aarch64-unknown-linux-musl' => {
|
||||
aria2c https://github.com/nushell/integrations/releases/download/build-tools/aarch64-linux-musl-cross.tgz
|
||||
aria2c https://musl.cc/aarch64-linux-musl-cross.tgz
|
||||
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.CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER = 'aarch64-linux-musl-gcc'
|
||||
cargo-build-nu
|
||||
}
|
||||
'armv7-unknown-linux-musleabihf' => {
|
||||
aria2c https://github.com/nushell/integrations/releases/download/build-tools/armv7r-linux-musleabihf-cross.tgz
|
||||
aria2c https://musl.cc/armv7r-linux-musleabihf-cross.tgz
|
||||
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.CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABIHF_LINKER = 'armv7r-linux-musleabihf-gcc'
|
||||
@ -99,14 +105,6 @@ if $os in ['macos-latest'] or $USE_UBUNTU {
|
||||
$env.CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER = 'loongarch64-unknown-linux-gnu-gcc'
|
||||
cargo-build-nu
|
||||
}
|
||||
'loongarch64-unknown-linux-musl' => {
|
||||
print $"(ansi g)Downloading LoongArch64 musl cross-compilation toolchain...(ansi reset)"
|
||||
aria2c -q https://github.com/LoongsonLab/oscomp-toolchains-for-oskernel/releases/download/loongarch64-linux-musl-cross-gcc-13.2.0/loongarch64-linux-musl-cross.tgz
|
||||
tar -xf loongarch64-linux-musl-cross.tgz
|
||||
$env.PATH = ($env.PATH | split row (char esep) | prepend $'($env.PWD)/loongarch64-linux-musl-cross/bin')
|
||||
$env.CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_MUSL_LINKER = "loongarch64-linux-musl-gcc"
|
||||
cargo-build-nu
|
||||
}
|
||||
_ => {
|
||||
# musl-tools to fix 'Failed to find tool. Is `musl-gcc` installed?'
|
||||
# Actually just for x86_64-unknown-linux-musl target
|
||||
|
22
.github/workflows/release.yml
vendored
22
.github/workflows/release.yml
vendored
@ -35,7 +35,6 @@ jobs:
|
||||
- armv7-unknown-linux-musleabihf
|
||||
- riscv64gc-unknown-linux-gnu
|
||||
- loongarch64-unknown-linux-gnu
|
||||
- loongarch64-unknown-linux-musl
|
||||
include:
|
||||
- target: aarch64-apple-darwin
|
||||
os: macos-latest
|
||||
@ -61,8 +60,6 @@ jobs:
|
||||
os: ubuntu-22.04
|
||||
- target: loongarch64-unknown-linux-gnu
|
||||
os: ubuntu-22.04
|
||||
- target: loongarch64-unknown-linux-musl
|
||||
os: ubuntu-22.04
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
@ -93,17 +90,32 @@ jobs:
|
||||
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v3
|
||||
if: ${{ matrix.os != 'windows-11-arm' }}
|
||||
with:
|
||||
version: 0.105.1
|
||||
version: 0.103.0
|
||||
|
||||
- name: Release Nu Binary
|
||||
id: nu
|
||||
if: ${{ matrix.os != 'windows-11-arm' }}
|
||||
run: nu .github/workflows/release-pkg.nu
|
||||
env:
|
||||
OS: ${{ matrix.os }}
|
||||
REF: ${{ github.ref }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
|
||||
- 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.
|
||||
# See: https://github.com/softprops/action-gh-release/issues/445
|
||||
- name: Publish Archive
|
||||
@ -113,7 +125,9 @@ jobs:
|
||||
draft: true
|
||||
files: |
|
||||
${{ steps.nu.outputs.msi }}
|
||||
${{ steps.nu0.outputs.msi }}
|
||||
${{ steps.nu.outputs.archive }}
|
||||
${{ steps.nu0.outputs.archive }}
|
||||
env:
|
||||
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
|
||||
|
||||
- name: Check spelling
|
||||
uses: crate-ci/typos@v1.33.1
|
||||
uses: crate-ci/typos@v1.31.1
|
||||
|
5
.github/workflows/winget-submission.yml
vendored
5
.github/workflows/winget-submission.yml
vendored
@ -10,11 +10,6 @@ on:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
|
||||
winget:
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -32,17 +32,11 @@ unstable_cargo_features.txt
|
||||
# Helix configuration folder
|
||||
.helix/*
|
||||
.helix
|
||||
wix/bin/
|
||||
wix/obj/
|
||||
wix/nu/
|
||||
|
||||
# Coverage tools
|
||||
lcov.info
|
||||
tarpaulin-report.html
|
||||
|
||||
# benchmarking
|
||||
/tango
|
||||
|
||||
# Visual Studio
|
||||
.vs/*
|
||||
*.rsproj
|
||||
|
@ -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.
|
||||
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.
|
||||
4. If your PR includes any user-facing features (such as adding a flag to a command), clearly list them in the PR description.
|
||||
4. If your PR includes any use-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.
|
||||
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.
|
||||
|
642
Cargo.lock
generated
642
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
95
Cargo.toml
95
Cargo.toml
@ -4,14 +4,14 @@ build = "scripts/build.rs"
|
||||
default-run = "nu"
|
||||
description = "A new type of shell"
|
||||
documentation = "https://www.nushell.sh/book/"
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
exclude = ["images"]
|
||||
homepage = "https://www.nushell.sh"
|
||||
license = "MIT"
|
||||
name = "nu"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
rust-version = "1.86.0"
|
||||
version = "0.105.2"
|
||||
rust-version = "1.84.1"
|
||||
version = "0.104.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -63,15 +63,15 @@ members = [
|
||||
|
||||
[workspace.dependencies]
|
||||
alphanumeric-sort = "1.5"
|
||||
ansi-str = "0.9"
|
||||
ansi-str = "0.8"
|
||||
anyhow = "1.0.82"
|
||||
base64 = "0.22.1"
|
||||
bracoxide = "0.1.6"
|
||||
bracoxide = "0.1.5"
|
||||
brotli = "7.0"
|
||||
byteorder = "1.5"
|
||||
bytes = "1"
|
||||
bytesize = "1.3.3"
|
||||
calamine = "0.28"
|
||||
calamine = "0.27"
|
||||
chardetng = "0.1.17"
|
||||
chrono = { default-features = false, version = "0.4.34" }
|
||||
chrono-humanize = "0.2.3"
|
||||
@ -96,18 +96,18 @@ indexmap = "2.9"
|
||||
indicatif = "0.17"
|
||||
interprocess = "2.2.0"
|
||||
is_executable = "1.0"
|
||||
itertools = "0.14"
|
||||
itertools = "0.13"
|
||||
libc = "0.2"
|
||||
libproc = "0.14"
|
||||
log = "0.4"
|
||||
lru = "0.12"
|
||||
lscolors = { version = "0.20", default-features = false }
|
||||
lscolors = { version = "0.17", default-features = false }
|
||||
lsp-server = "0.7.8"
|
||||
lsp-types = { version = "0.97.0", features = ["proposed"] }
|
||||
lsp-textdocument = "0.4.2"
|
||||
mach2 = "0.4"
|
||||
md5 = { version = "0.10", package = "md-5" }
|
||||
miette = "7.6"
|
||||
miette = "7.5"
|
||||
mime = "0.3.17"
|
||||
mime_guess = "2.0"
|
||||
mockito = { version = "1.7", default-features = false }
|
||||
@ -133,7 +133,7 @@ procfs = "0.17.0"
|
||||
pwd = "1.3"
|
||||
quick-xml = "0.37.0"
|
||||
quickcheck = "1.0"
|
||||
quickcheck_macros = "1.1"
|
||||
quickcheck_macros = "1.0"
|
||||
quote = "1.0"
|
||||
rand = "0.9"
|
||||
getrandom = "0.2" # pick same version that rand requires
|
||||
@ -148,25 +148,23 @@ rstest = { version = "0.23", default-features = false }
|
||||
rstest_reuse = "0.7"
|
||||
rusqlite = "0.31"
|
||||
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" }
|
||||
serde = { version = "1.0" }
|
||||
serde_json = "1.0.97"
|
||||
serde_urlencoded = "0.7.1"
|
||||
serde_yaml = "0.9.33"
|
||||
sha2 = "0.10"
|
||||
strip-ansi-escapes = "0.2.1"
|
||||
strip-ansi-escapes = "0.2.0"
|
||||
strum = "0.26"
|
||||
strum_macros = "0.26"
|
||||
syn = "2.0"
|
||||
sysinfo = "0.33"
|
||||
tabled = { version = "0.20", default-features = false }
|
||||
tempfile = "3.20"
|
||||
titlecase = "3.6"
|
||||
tabled = { version = "0.17.0", default-features = false }
|
||||
tempfile = "3.15"
|
||||
titlecase = "3.5"
|
||||
toml = "0.8"
|
||||
trash = "5.2"
|
||||
update-informer = { version = "1.2.0", default-features = false, features = ["github", "ureq"] }
|
||||
update-informer = { version = "1.2.0", default-features = false, features = ["github", "native-tls", "ureq"] }
|
||||
umask = "2.1"
|
||||
unicode-segmentation = "1.12"
|
||||
unicode-width = "0.2"
|
||||
@ -184,39 +182,37 @@ uuid = "1.16.0"
|
||||
v_htmlescape = "0.15.0"
|
||||
wax = "0.6"
|
||||
web-time = "1.1.0"
|
||||
which = "8.0.0"
|
||||
which = "7.0.0"
|
||||
windows = "0.56"
|
||||
windows-sys = "0.48"
|
||||
winreg = "0.52"
|
||||
memchr = "2.7.4"
|
||||
webpki-roots = "1.0"
|
||||
|
||||
[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.
|
||||
# todo = "warn"
|
||||
unchecked_duration_subtraction = "warn"
|
||||
used_underscore_binding = "warn"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
nu-cli = { path = "./crates/nu-cli", version = "0.105.2" }
|
||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.105.2" }
|
||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.105.2" }
|
||||
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.105.2", optional = true }
|
||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.105.2" }
|
||||
nu-command = { path = "./crates/nu-command", version = "0.105.2", default-features = false, features = ["os"] }
|
||||
nu-engine = { path = "./crates/nu-engine", version = "0.105.2" }
|
||||
nu-explore = { path = "./crates/nu-explore", version = "0.105.2" }
|
||||
nu-lsp = { path = "./crates/nu-lsp/", version = "0.105.2" }
|
||||
nu-parser = { path = "./crates/nu-parser", version = "0.105.2" }
|
||||
nu-path = { path = "./crates/nu-path", version = "0.105.2" }
|
||||
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.105.2" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.105.2" }
|
||||
nu-std = { path = "./crates/nu-std", version = "0.105.2" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.105.2" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.105.2" }
|
||||
nu-cli = { path = "./crates/nu-cli", version = "0.104.1" }
|
||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.104.1" }
|
||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.104.1" }
|
||||
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.104.1", optional = true }
|
||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.104.1" }
|
||||
nu-command = { path = "./crates/nu-command", version = "0.104.1" }
|
||||
nu-engine = { path = "./crates/nu-engine", version = "0.104.1" }
|
||||
nu-explore = { path = "./crates/nu-explore", version = "0.104.1" }
|
||||
nu-lsp = { path = "./crates/nu-lsp/", version = "0.104.1" }
|
||||
nu-parser = { path = "./crates/nu-parser", version = "0.104.1" }
|
||||
nu-path = { path = "./crates/nu-path", version = "0.104.1" }
|
||||
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.104.1" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.104.1" }
|
||||
nu-std = { path = "./crates/nu-std", version = "0.104.1" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.104.1" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.104.1" }
|
||||
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
|
||||
|
||||
crossterm = { workspace = true }
|
||||
@ -245,9 +241,9 @@ nix = { workspace = true, default-features = false, features = [
|
||||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.105.2" }
|
||||
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.105.2" }
|
||||
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.105.2" }
|
||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.104.1" }
|
||||
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.104.1" }
|
||||
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.104.1" }
|
||||
assert_cmd = "2.0"
|
||||
dirs = { workspace = true }
|
||||
tango-bench = "0.6"
|
||||
@ -258,14 +254,10 @@ serial_test = "3.2"
|
||||
tempfile = { workspace = true }
|
||||
|
||||
[features]
|
||||
# Enable all features while still avoiding mutually exclusive features.
|
||||
# Use this if `--all-features` fails.
|
||||
full = ["plugin", "rustls-tls", "system-clipboard", "trash-support", "sqlite"]
|
||||
|
||||
plugin = [
|
||||
# crates
|
||||
"dep:nu-cmd-plugin",
|
||||
"dep:nu-plugin-engine",
|
||||
"nu-cmd-plugin",
|
||||
"nu-plugin-engine",
|
||||
|
||||
# features
|
||||
"nu-cli/plugin",
|
||||
@ -277,34 +269,31 @@ plugin = [
|
||||
"nu-protocol/plugin",
|
||||
]
|
||||
|
||||
native-tls = ["nu-command/native-tls"]
|
||||
rustls-tls = ["nu-command/rustls-tls"]
|
||||
|
||||
default = [
|
||||
"plugin",
|
||||
"trash-support",
|
||||
"sqlite",
|
||||
"rustls-tls"
|
||||
]
|
||||
stable = ["default"]
|
||||
# NOTE: individual features are also passed to `nu-cmd-lang` that uses them to generate the feature matrix in the `version` command
|
||||
|
||||
# Enable to statically link OpenSSL (perl is required, to build OpenSSL https://docs.rs/openssl/latest/openssl/);
|
||||
# otherwise the system version will be used. Not enabled by default because it takes a while to build
|
||||
static-link-openssl = ["dep:openssl"]
|
||||
static-link-openssl = ["dep:openssl", "nu-cmd-lang/static-link-openssl"]
|
||||
|
||||
# Optional system clipboard support in `reedline`, this behavior has problematic compatibility with some systems.
|
||||
# Missing X server/ Wayland can cause issues
|
||||
system-clipboard = [
|
||||
"reedline/system_clipboard",
|
||||
"nu-cli/system-clipboard",
|
||||
"nu-cmd-lang/system-clipboard",
|
||||
]
|
||||
|
||||
# Stable (Default)
|
||||
trash-support = ["nu-command/trash-support"]
|
||||
trash-support = ["nu-command/trash-support", "nu-cmd-lang/trash-support"]
|
||||
|
||||
# SQLite commands for nushell
|
||||
sqlite = ["nu-command/sqlite", "nu-std/sqlite"]
|
||||
sqlite = ["nu-command/sqlite", "nu-cmd-lang/sqlite", "nu-std/sqlite"]
|
||||
|
||||
[profile.release]
|
||||
opt-level = "s" # Optimize for size
|
||||
@ -334,7 +323,7 @@ bench = false
|
||||
# To use a development version of a dependency please use a global override here
|
||||
# changing versions in each sub-crate of the workspace is tedious
|
||||
[patch.crates-io]
|
||||
reedline = { git = "https://github.com/nushell/reedline", branch = "main" }
|
||||
# reedline = { git = "https://github.com/nushell/reedline", branch = "main" }
|
||||
# nu-ansi-term = {git = "https://github.com/nushell/nu-ansi-term.git", branch = "main"}
|
||||
|
||||
# Run all benchmarks with `cargo bench`
|
||||
|
@ -222,7 +222,6 @@ Please submit an issue or PR to be added to this list.
|
||||
- [Dorothy](http://github.com/bevry/dorothy)
|
||||
- [Direnv](https://github.com/direnv/direnv/blob/master/docs/hook.md#nushell)
|
||||
- [x-cmd](https://x-cmd.com/mod/nu)
|
||||
- [vfox](https://github.com/version-fox/vfox)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -2,8 +2,8 @@ use nu_cli::{eval_source, evaluate_commands};
|
||||
use nu_plugin_core::{Encoder, EncodingType};
|
||||
use nu_plugin_protocol::{PluginCallResponse, PluginOutput};
|
||||
use nu_protocol::{
|
||||
PipelineData, Signals, Span, Spanned, Value,
|
||||
engine::{EngineState, Stack},
|
||||
PipelineData, Signals, Span, Spanned, Value,
|
||||
};
|
||||
use nu_std::load_standard_library;
|
||||
use nu_utils::{get_default_config, get_default_env};
|
||||
@ -11,9 +11,9 @@ use std::{
|
||||
fmt::Write,
|
||||
hint::black_box,
|
||||
rc::Rc,
|
||||
sync::{Arc, atomic::AtomicBool},
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
};
|
||||
use tango_bench::{IntoBenchmarks, benchmark_fn, tango_benchmarks, tango_main};
|
||||
use tango_bench::{benchmark_fn, tango_benchmarks, tango_main, IntoBenchmarks};
|
||||
|
||||
fn load_bench_commands() -> EngineState {
|
||||
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(
|
||||
name: impl Into<String>,
|
||||
command: impl Into<String> + Clone,
|
||||
name: &str,
|
||||
command: &str,
|
||||
stack: Stack,
|
||||
engine: EngineState,
|
||||
) -> impl IntoBenchmarks {
|
||||
let commands = Spanned {
|
||||
span: Span::unknown(),
|
||||
item: command.into(),
|
||||
item: command.to_string(),
|
||||
};
|
||||
[benchmark_fn(name, move |b| {
|
||||
let commands = commands.clone();
|
||||
@ -175,8 +175,8 @@ fn create_example_table_nrows(n: usize) -> String {
|
||||
|
||||
fn bench_record_create(n: usize) -> impl IntoBenchmarks {
|
||||
bench_command(
|
||||
format!("record_create_{n}"),
|
||||
create_flat_record_string(n),
|
||||
&format!("record_create_{n}"),
|
||||
&create_flat_record_string(n),
|
||||
Stack::new(),
|
||||
setup_engine(),
|
||||
)
|
||||
@ -186,7 +186,7 @@ fn bench_record_flat_access(n: usize) -> impl IntoBenchmarks {
|
||||
let setup_command = create_flat_record_string(n);
|
||||
let (stack, engine) = setup_stack_and_engine_from_command(&setup_command);
|
||||
bench_command(
|
||||
format!("record_flat_access_{n}"),
|
||||
&format!("record_flat_access_{n}"),
|
||||
"$record.col_0 | ignore",
|
||||
stack,
|
||||
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 nested_access = ".col".repeat(n);
|
||||
bench_command(
|
||||
format!("record_nested_access_{n}"),
|
||||
format!("$record{nested_access} | ignore"),
|
||||
&format!("record_nested_access_{n}"),
|
||||
&format!("$record{} | ignore", nested_access),
|
||||
stack,
|
||||
engine,
|
||||
)
|
||||
@ -213,13 +213,13 @@ fn bench_record_insert(n: usize, m: usize) -> impl IntoBenchmarks {
|
||||
write!(insert, " | insert col_{i} {i}").unwrap();
|
||||
}
|
||||
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 {
|
||||
bench_command(
|
||||
format!("table_create_{n}"),
|
||||
create_example_table_nrows(n),
|
||||
&format!("table_create_{n}"),
|
||||
&create_example_table_nrows(n),
|
||||
Stack::new(),
|
||||
setup_engine(),
|
||||
)
|
||||
@ -229,7 +229,7 @@ fn bench_table_get(n: usize) -> impl IntoBenchmarks {
|
||||
let setup_command = create_example_table_nrows(n);
|
||||
let (stack, engine) = setup_stack_and_engine_from_command(&setup_command);
|
||||
bench_command(
|
||||
format!("table_get_{n}"),
|
||||
&format!("table_get_{n}"),
|
||||
"$table | get bar | math sum | ignore",
|
||||
stack,
|
||||
engine,
|
||||
@ -240,7 +240,7 @@ fn bench_table_select(n: usize) -> impl IntoBenchmarks {
|
||||
let setup_command = create_example_table_nrows(n);
|
||||
let (stack, engine) = setup_stack_and_engine_from_command(&setup_command);
|
||||
bench_command(
|
||||
format!("table_select_{n}"),
|
||||
&format!("table_select_{n}"),
|
||||
"$table | select foo baz | ignore",
|
||||
stack,
|
||||
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();
|
||||
}
|
||||
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 {
|
||||
@ -266,15 +266,15 @@ fn bench_table_insert_col(n: usize, m: usize) -> impl IntoBenchmarks {
|
||||
write!(insert, " | insert col_{i} {i}").unwrap();
|
||||
}
|
||||
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 {
|
||||
let engine = setup_engine();
|
||||
let stack = Stack::new();
|
||||
bench_command(
|
||||
format!("eval_interleave_{n}"),
|
||||
format!("seq 1 {n} | wrap a | interleave {{ seq 1 {n} | wrap b }} | ignore"),
|
||||
&format!("eval_interleave_{n}"),
|
||||
&format!("seq 1 {n} | wrap a | interleave {{ seq 1 {n} | wrap b }} | ignore"),
|
||||
stack,
|
||||
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))));
|
||||
let stack = Stack::new();
|
||||
bench_command(
|
||||
format!("eval_interleave_with_interrupt_{n}"),
|
||||
format!("seq 1 {n} | wrap a | interleave {{ seq 1 {n} | wrap b }} | ignore"),
|
||||
&format!("eval_interleave_with_interrupt_{n}"),
|
||||
&format!("seq 1 {n} | wrap a | interleave {{ seq 1 {n} | wrap b }} | ignore"),
|
||||
stack,
|
||||
engine,
|
||||
)
|
||||
@ -296,8 +296,8 @@ fn bench_eval_for(n: usize) -> impl IntoBenchmarks {
|
||||
let engine = setup_engine();
|
||||
let stack = Stack::new();
|
||||
bench_command(
|
||||
format!("eval_for_{n}"),
|
||||
format!("(for $x in (1..{n}) {{ 1 }}) | ignore"),
|
||||
&format!("eval_for_{n}"),
|
||||
&format!("(for $x in (1..{n}) {{ 1 }}) | ignore"),
|
||||
stack,
|
||||
engine,
|
||||
)
|
||||
@ -307,8 +307,8 @@ fn bench_eval_each(n: usize) -> impl IntoBenchmarks {
|
||||
let engine = setup_engine();
|
||||
let stack = Stack::new();
|
||||
bench_command(
|
||||
format!("eval_each_{n}"),
|
||||
format!("(1..{n}) | each {{|_| 1 }} | ignore"),
|
||||
&format!("eval_each_{n}"),
|
||||
&format!("(1..{n}) | each {{|_| 1 }} | ignore"),
|
||||
stack,
|
||||
engine,
|
||||
)
|
||||
@ -318,8 +318,8 @@ fn bench_eval_par_each(n: usize) -> impl IntoBenchmarks {
|
||||
let engine = setup_engine();
|
||||
let stack = Stack::new();
|
||||
bench_command(
|
||||
format!("eval_par_each_{n}"),
|
||||
format!("(1..{n}) | par-each -t 2 {{|_| 1 }} | ignore"),
|
||||
&format!("eval_par_each_{n}"),
|
||||
&format!("(1..{}) | par-each -t 2 {{|_| 1 }} | ignore", n),
|
||||
stack,
|
||||
engine,
|
||||
)
|
||||
@ -357,7 +357,7 @@ fn encode_json(row_cnt: usize, col_cnt: usize) -> impl IntoBenchmarks {
|
||||
let encoder = Rc::new(EncodingType::try_from_bytes(b"json").unwrap());
|
||||
|
||||
[benchmark_fn(
|
||||
format!("encode_json_{row_cnt}_{col_cnt}"),
|
||||
format!("encode_json_{}_{}", row_cnt, col_cnt),
|
||||
move |b| {
|
||||
let encoder = encoder.clone();
|
||||
let test_data = test_data.clone();
|
||||
@ -377,7 +377,7 @@ fn encode_msgpack(row_cnt: usize, col_cnt: usize) -> impl IntoBenchmarks {
|
||||
let encoder = Rc::new(EncodingType::try_from_bytes(b"msgpack").unwrap());
|
||||
|
||||
[benchmark_fn(
|
||||
format!("encode_msgpack_{row_cnt}_{col_cnt}"),
|
||||
format!("encode_msgpack_{}_{}", row_cnt, col_cnt),
|
||||
move |b| {
|
||||
let encoder = encoder.clone();
|
||||
let test_data = test_data.clone();
|
||||
@ -399,7 +399,7 @@ fn decode_json(row_cnt: usize, col_cnt: usize) -> impl IntoBenchmarks {
|
||||
encoder.encode(&test_data, &mut res).unwrap();
|
||||
|
||||
[benchmark_fn(
|
||||
format!("decode_json_{row_cnt}_{col_cnt}"),
|
||||
format!("decode_json_{}_{}", row_cnt, col_cnt),
|
||||
move |b| {
|
||||
let res = res.clone();
|
||||
b.iter(move || {
|
||||
@ -422,7 +422,7 @@ fn decode_msgpack(row_cnt: usize, col_cnt: usize) -> impl IntoBenchmarks {
|
||||
encoder.encode(&test_data, &mut res).unwrap();
|
||||
|
||||
[benchmark_fn(
|
||||
format!("decode_msgpack_{row_cnt}_{col_cnt}"),
|
||||
format!("decode_msgpack_{}_{}", row_cnt, col_cnt),
|
||||
move |b| {
|
||||
let res = res.clone();
|
||||
b.iter(move || {
|
||||
|
@ -2,32 +2,32 @@
|
||||
authors = ["The Nushell Project Developers"]
|
||||
description = "CLI-related functionality for Nushell"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.105.2"
|
||||
version = "0.104.1"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.105.2" }
|
||||
nu-command = { path = "../nu-command", version = "0.105.2" }
|
||||
nu-std = { path = "../nu-std", version = "0.105.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.105.2" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.104.1" }
|
||||
nu-command = { path = "../nu-command", version = "0.104.1" }
|
||||
nu-std = { path = "../nu-std", version = "0.104.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.104.1" }
|
||||
rstest = { workspace = true, default-features = false }
|
||||
tempfile = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.105.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.105.2", features = ["os"] }
|
||||
nu-glob = { path = "../nu-glob", version = "0.105.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.105.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.105.2" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.105.2", optional = true }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.105.2", features = ["os"] }
|
||||
nu-utils = { path = "../nu-utils", version = "0.105.2" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.105.2" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.104.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.104.1", features = ["os"] }
|
||||
nu-glob = { path = "../nu-glob", version = "0.104.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.104.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.104.1" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.104.1", optional = true }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.104.1", features = ["os"] }
|
||||
nu-utils = { path = "../nu-utils", version = "0.104.1" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.104.1" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
|
||||
|
||||
|
@ -1,8 +1,5 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::{
|
||||
HistoryFileFormat,
|
||||
shell_error::{self, io::IoError},
|
||||
};
|
||||
use nu_protocol::{shell_error::io::IoError, HistoryFileFormat};
|
||||
use reedline::{
|
||||
FileBackedHistory, History as ReedlineHistory, HistoryItem, SearchDirection, SearchQuery,
|
||||
SqliteBackedHistory,
|
||||
@ -97,7 +94,7 @@ impl Command for History {
|
||||
})
|
||||
})
|
||||
.ok_or(IoError::new(
|
||||
shell_error::io::ErrorKind::FileNotFound,
|
||||
std::io::ErrorKind::NotFound,
|
||||
head,
|
||||
history_path,
|
||||
))?
|
||||
@ -113,7 +110,7 @@ impl Command for History {
|
||||
})
|
||||
})
|
||||
.ok_or(IoError::new(
|
||||
shell_error::io::ErrorKind::FileNotFound,
|
||||
std::io::ErrorKind::NotFound,
|
||||
head,
|
||||
history_path,
|
||||
))?
|
||||
|
@ -2,8 +2,8 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::{
|
||||
HistoryFileFormat,
|
||||
shell_error::{self, io::IoError},
|
||||
HistoryFileFormat,
|
||||
};
|
||||
|
||||
use reedline::{
|
||||
@ -26,7 +26,7 @@ impl Command for HistoryImport {
|
||||
|
||||
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:
|
||||
command, start_timestamp, hostname, cwd, duration, exit_status.
|
||||
command_line, id, 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.
|
||||
|
||||
@ -48,7 +48,8 @@ Note that history item IDs are ignored when importing from file."#
|
||||
vec![
|
||||
Example {
|
||||
example: "history import",
|
||||
description: "Append all items from history in the other format to the current history",
|
||||
description:
|
||||
"Append all items from history in the other format to the current history",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
@ -197,7 +198,7 @@ fn item_from_record(mut rec: Record, span: Span) -> Result<HistoryItem, ShellErr
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: format!("missing column: {}", fields::COMMAND_LINE),
|
||||
span,
|
||||
});
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
@ -282,22 +283,22 @@ fn backup(path: &Path, span: Span) -> Result<Option<PathBuf>, ShellError> {
|
||||
PathBuf::from(path),
|
||||
"history path exists but is not a file",
|
||||
)
|
||||
.into());
|
||||
.into())
|
||||
}
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None),
|
||||
Err(e) => {
|
||||
return Err(IoError::new_internal(
|
||||
e,
|
||||
e.kind(),
|
||||
"Could not get metadata",
|
||||
nu_protocol::location!(),
|
||||
)
|
||||
.into());
|
||||
.into())
|
||||
}
|
||||
}
|
||||
let bak_path = find_backup_path(path, span)?;
|
||||
std::fs::copy(path, &bak_path).map_err(|err| {
|
||||
IoError::new_internal(
|
||||
err.not_found_as(NotFound::File),
|
||||
err.kind(),
|
||||
"Could not copy backup",
|
||||
nu_protocol::location!(),
|
||||
)
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crossterm::{
|
||||
QueueableCommand, event::Event, event::KeyCode, event::KeyEvent, execute, terminal,
|
||||
event::Event, event::KeyCode, event::KeyEvent, execute, terminal, QueueableCommand,
|
||||
};
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::shell_error::io::IoError;
|
||||
use std::io::{Write, stdout};
|
||||
use std::io::{stdout, Write};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct KeybindingsListen;
|
||||
@ -42,7 +42,7 @@ impl Command for KeybindingsListen {
|
||||
Err(e) => {
|
||||
terminal::disable_raw_mode().map_err(|err| {
|
||||
IoError::new_internal(
|
||||
err,
|
||||
err.kind(),
|
||||
"Could not disable raw mode",
|
||||
nu_protocol::location!(),
|
||||
)
|
||||
@ -71,10 +71,18 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
|
||||
let config = engine_state.get_config();
|
||||
|
||||
stdout().flush().map_err(|err| {
|
||||
IoError::new_internal(err, "Could not flush stdout", nu_protocol::location!())
|
||||
IoError::new_internal(
|
||||
err.kind(),
|
||||
"Could not flush stdout",
|
||||
nu_protocol::location!(),
|
||||
)
|
||||
})?;
|
||||
terminal::enable_raw_mode().map_err(|err| {
|
||||
IoError::new_internal(err, "Could not enable raw mode", nu_protocol::location!())
|
||||
IoError::new_internal(
|
||||
err.kind(),
|
||||
"Could not enable raw mode",
|
||||
nu_protocol::location!(),
|
||||
)
|
||||
})?;
|
||||
|
||||
if config.use_kitty_protocol {
|
||||
@ -106,7 +114,7 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
|
||||
|
||||
loop {
|
||||
let event = crossterm::event::read().map_err(|err| {
|
||||
IoError::new_internal(err, "Could not read event", nu_protocol::location!())
|
||||
IoError::new_internal(err.kind(), "Could not read event", nu_protocol::location!())
|
||||
})?;
|
||||
if event == Event::Key(KeyCode::Esc.into()) {
|
||||
break;
|
||||
@ -128,7 +136,7 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
|
||||
};
|
||||
stdout.queue(crossterm::style::Print(o)).map_err(|err| {
|
||||
IoError::new_internal(
|
||||
err,
|
||||
err.kind(),
|
||||
"Could not print output record",
|
||||
nu_protocol::location!(),
|
||||
)
|
||||
@ -136,10 +144,14 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
|
||||
stdout
|
||||
.queue(crossterm::style::Print("\r\n"))
|
||||
.map_err(|err| {
|
||||
IoError::new_internal(err, "Could not print linebreak", nu_protocol::location!())
|
||||
IoError::new_internal(
|
||||
err.kind(),
|
||||
"Could not print linebreak",
|
||||
nu_protocol::location!(),
|
||||
)
|
||||
})?;
|
||||
stdout.flush().map_err(|err| {
|
||||
IoError::new_internal(err, "Could not flush", nu_protocol::location!())
|
||||
IoError::new_internal(err.kind(), "Could not flush", nu_protocol::location!())
|
||||
})?;
|
||||
}
|
||||
|
||||
@ -151,7 +163,11 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
|
||||
}
|
||||
|
||||
terminal::disable_raw_mode().map_err(|err| {
|
||||
IoError::new_internal(err, "Could not disable raw mode", nu_protocol::location!())
|
||||
IoError::new_internal(
|
||||
err.kind(),
|
||||
"Could not disable raw mode",
|
||||
nu_protocol::location!(),
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(Value::nothing(Span::unknown()))
|
||||
|
@ -1,11 +1,11 @@
|
||||
use super::{SemanticSuggestion, completion_options::NuMatcher};
|
||||
use super::{completion_options::NuMatcher, SemanticSuggestion};
|
||||
use crate::{
|
||||
SuggestionKind,
|
||||
completions::{Completer, CompletionOptions},
|
||||
SuggestionKind,
|
||||
};
|
||||
use nu_protocol::{
|
||||
Span,
|
||||
engine::{Stack, StateWorkingSet},
|
||||
Span,
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
|
||||
@ -33,12 +33,13 @@ impl Completer for AttributeCompletion {
|
||||
suggestion: Suggestion {
|
||||
value: String::from_utf8_lossy(name).into_owned(),
|
||||
description: desc,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: span.start - offset,
|
||||
end: span.end - offset,
|
||||
},
|
||||
append_whitespace: false,
|
||||
..Default::default()
|
||||
},
|
||||
kind: Some(SuggestionKind::Command(ty, Some(decl_id))),
|
||||
});
|
||||
@ -69,12 +70,13 @@ impl Completer for AttributableCompletion {
|
||||
suggestion: Suggestion {
|
||||
value: cmd.name().into(),
|
||||
description: Some(cmd.description().into()),
|
||||
style: None,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: span.start - offset,
|
||||
end: span.end - offset,
|
||||
},
|
||||
append_whitespace: false,
|
||||
..Default::default()
|
||||
},
|
||||
kind: Some(SuggestionKind::Command(cmd.command_type(), None)),
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::completions::CompletionOptions;
|
||||
use nu_protocol::{
|
||||
DeclId, Span,
|
||||
engine::{Stack, StateWorkingSet},
|
||||
DeclId, Span,
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::completions::{Completer, CompletionOptions, SemanticSuggestion, SuggestionKind};
|
||||
use nu_engine::{column::get_columns, eval_variable};
|
||||
use nu_protocol::{
|
||||
ShellError, Span, Value,
|
||||
ast::{Expr, Expression, FullCellPath, PathMember},
|
||||
engine::{Stack, StateWorkingSet},
|
||||
eval_const::eval_constant,
|
||||
ShellError, Span, Value,
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
|
||||
@ -103,9 +101,7 @@ pub(crate) fn eval_cell_path(
|
||||
} else {
|
||||
eval_constant(working_set, head)
|
||||
}?;
|
||||
head_value
|
||||
.follow_cell_path(path_members)
|
||||
.map(Cow::into_owned)
|
||||
head_value.follow_cell_path(path_members, false)
|
||||
}
|
||||
|
||||
fn get_suggestions_by_value(
|
||||
@ -118,7 +114,7 @@ fn get_suggestions_by_value(
|
||||
|| s.chars()
|
||||
.any(|c: char| !(c.is_ascii_alphabetic() || ['_', '-'].contains(&c)))
|
||||
{
|
||||
format!("{s:?}")
|
||||
format!("{:?}", s)
|
||||
} else {
|
||||
s
|
||||
};
|
||||
|
@ -1,16 +1,16 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
SuggestionKind,
|
||||
completions::{Completer, CompletionOptions},
|
||||
SuggestionKind,
|
||||
};
|
||||
use nu_protocol::{
|
||||
Span,
|
||||
engine::{CommandType, Stack, StateWorkingSet},
|
||||
Span,
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
|
||||
use super::{SemanticSuggestion, completion_options::NuMatcher};
|
||||
use super::{completion_options::NuMatcher, SemanticSuggestion};
|
||||
|
||||
pub struct CommandCompletion {
|
||||
/// Whether to include internal commands
|
||||
@ -52,7 +52,7 @@ impl CommandCompletion {
|
||||
continue;
|
||||
};
|
||||
let value = if matched_internal(&name) {
|
||||
format!("^{name}")
|
||||
format!("^{}", name)
|
||||
} else {
|
||||
name.clone()
|
||||
};
|
||||
|
@ -1,17 +1,17 @@
|
||||
use crate::completions::{
|
||||
base::{SemanticSuggestion, SuggestionKind},
|
||||
AttributableCompletion, AttributeCompletion, CellPathCompletion, CommandCompletion, Completer,
|
||||
CompletionOptions, CustomCompletion, DirectoryCompletion, DotNuCompletion,
|
||||
ExportableCompletion, FileCompletion, FlagCompletion, OperatorCompletion, VariableCompletion,
|
||||
base::{SemanticSuggestion, SuggestionKind},
|
||||
};
|
||||
use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
|
||||
use nu_engine::eval_block;
|
||||
use nu_parser::{flatten_expression, parse, parse_module_file_or_dir};
|
||||
use nu_protocol::{
|
||||
PipelineData, Span, Type, Value,
|
||||
ast::{Argument, Block, Expr, Expression, FindMapResult, ListItem, Traverse},
|
||||
debugger::WithoutDebug,
|
||||
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
||||
PipelineData, Span, Type, Value,
|
||||
};
|
||||
use reedline::{Completer as ReedlineCompleter, Suggestion};
|
||||
use std::sync::Arc;
|
||||
@ -176,7 +176,7 @@ impl NuCompleter {
|
||||
&mut working_set,
|
||||
Some("completer"),
|
||||
// Add a placeholder `a` to the end
|
||||
format!("{line}a").as_bytes(),
|
||||
format!("{}a", line).as_bytes(),
|
||||
false,
|
||||
);
|
||||
self.fetch_completions_by_block(block, &working_set, pos, offset, line, true)
|
||||
@ -466,14 +466,6 @@ impl NuCompleter {
|
||||
return suggestions;
|
||||
}
|
||||
}
|
||||
// for external path arguments with spaces, please check issue #15790
|
||||
if suggestions.is_empty() {
|
||||
let (new_span, prefix) =
|
||||
strip_placeholder_if_any(working_set, &span, strip);
|
||||
let ctx = Context::new(working_set, new_span, prefix, offset);
|
||||
suggestions.extend(self.process_completion(&mut FileCompletion, &ctx));
|
||||
return suggestions;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -850,7 +842,7 @@ mod completer_tests {
|
||||
for (line, has_result, begins_with, expected_values) in dataset {
|
||||
let result = completer.fetch_completions_at(line, line.len());
|
||||
// Test whether the result is empty or not
|
||||
assert_eq!(!result.is_empty(), has_result, "line: {line}");
|
||||
assert_eq!(!result.is_empty(), has_result, "line: {}", line);
|
||||
|
||||
// Test whether the result begins with the expected value
|
||||
result
|
||||
@ -865,7 +857,8 @@ mod completer_tests {
|
||||
.filter(|x| *x)
|
||||
.count(),
|
||||
expected_values.len(),
|
||||
"line: {line}"
|
||||
"line: {}",
|
||||
line
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
use super::{MatchAlgorithm, completion_options::NuMatcher};
|
||||
use super::{completion_options::NuMatcher, MatchAlgorithm};
|
||||
use crate::completions::CompletionOptions;
|
||||
use nu_ansi_term::Style;
|
||||
use nu_engine::env_to_string;
|
||||
use nu_path::dots::expand_ndots;
|
||||
use nu_path::{expand_to_real_path, home_dir};
|
||||
use nu_protocol::{
|
||||
Span,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
Span,
|
||||
};
|
||||
use nu_utils::IgnoreCaseExt;
|
||||
use nu_utils::get_ls_colors;
|
||||
use std::path::{Component, MAIN_SEPARATOR as SEP, Path, PathBuf, is_separator};
|
||||
use nu_utils::IgnoreCaseExt;
|
||||
use std::path::{is_separator, Component, Path, PathBuf, MAIN_SEPARATOR as SEP};
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct PathBuiltFromString {
|
||||
@ -39,10 +39,8 @@ fn complete_rec(
|
||||
isdir: bool,
|
||||
enable_exact_match: bool,
|
||||
) -> Vec<PathBuiltFromString> {
|
||||
let has_more = !partial.is_empty() && (partial.len() > 1 || isdir);
|
||||
|
||||
if let Some((&base, rest)) = partial.split_first() {
|
||||
if base.chars().all(|c| c == '.') && has_more {
|
||||
if base.chars().all(|c| c == '.') && (isdir || !rest.is_empty()) {
|
||||
let built_paths: Vec<_> = built_paths
|
||||
.iter()
|
||||
.map(|built| {
|
||||
@ -66,9 +64,6 @@ fn complete_rec(
|
||||
let prefix = partial.first().unwrap_or(&"");
|
||||
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 {
|
||||
let mut path = built.cwd.clone();
|
||||
for part in &built.parts {
|
||||
@ -88,56 +83,48 @@ fn complete_rec(
|
||||
built.isdir = entry_isdir && !entry.path().is_symlink();
|
||||
|
||||
if !want_directory || entry_isdir {
|
||||
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;
|
||||
matcher.add(entry_name.clone(), (entry_name, built));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matcher.add(entry_name, built);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't show longer completions if we have a single exact match (#13204, #14794)
|
||||
if !multiple_exact_matches {
|
||||
if let Some(built) = exact_match {
|
||||
return complete_rec(
|
||||
&partial[1..],
|
||||
&[built],
|
||||
options,
|
||||
want_directory,
|
||||
isdir,
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if has_more {
|
||||
let mut completions = vec![];
|
||||
for built in matcher.results() {
|
||||
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.
|
||||
// Serves as confirmation to ignore longer completions for
|
||||
// components in between.
|
||||
if !rest.is_empty() || isdir {
|
||||
// Don't show longer completions if we have an exact match (#13204, #14794)
|
||||
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(
|
||||
&partial[1..],
|
||||
rest,
|
||||
&[built],
|
||||
options,
|
||||
want_directory,
|
||||
isdir,
|
||||
false,
|
||||
exact_match,
|
||||
));
|
||||
if exact_match {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
completions.push(built);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
completions.push(built);
|
||||
}
|
||||
}
|
||||
}
|
||||
completions
|
||||
} else {
|
||||
matcher.results()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -314,7 +301,7 @@ pub fn escape_path(path: String) -> String {
|
||||
if path.contains('\'') {
|
||||
// decide to use double quotes
|
||||
// Path as Debug will do the escaping for `"`, `\`
|
||||
format!("{path:?}")
|
||||
format!("{:?}", path)
|
||||
} else {
|
||||
format!("'{path}'")
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ use nu_parser::trim_quotes_str;
|
||||
use nu_protocol::{CompletionAlgorithm, CompletionSort};
|
||||
use nu_utils::IgnoreCaseExt;
|
||||
use nucleo_matcher::{
|
||||
Config, Matcher, Utf32Str,
|
||||
pattern::{Atom, AtomKind, CaseMatching, Normalization},
|
||||
Config, Matcher, Utf32Str,
|
||||
};
|
||||
use std::{borrow::Cow, fmt::Display};
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
use crate::completions::{
|
||||
Completer, CompletionOptions, MatchAlgorithm, SemanticSuggestion,
|
||||
completer::map_value_completions,
|
||||
completer::map_value_completions, Completer, CompletionOptions, MatchAlgorithm,
|
||||
SemanticSuggestion,
|
||||
};
|
||||
use nu_engine::eval_call;
|
||||
use nu_protocol::{
|
||||
DeclId, PipelineData, Span, Type, Value,
|
||||
ast::{Argument, Call, Expr, Expression},
|
||||
debugger::WithoutDebug,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
DeclId, PipelineData, Span, Type, Value,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -106,9 +106,7 @@ impl<T: Completer> Completer for CustomCompletion<T> {
|
||||
let positional =
|
||||
options.get("positional").and_then(|val| val.as_bool().ok());
|
||||
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
|
||||
.get("completion_algorithm")
|
||||
|
@ -1,15 +1,15 @@
|
||||
use crate::completions::{
|
||||
completion_common::{adjust_if_intermediate, complete_item, AdjustView},
|
||||
Completer, CompletionOptions,
|
||||
completion_common::{AdjustView, adjust_if_intermediate, complete_item},
|
||||
};
|
||||
use nu_protocol::{
|
||||
Span,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
Span,
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
use std::path::Path;
|
||||
|
||||
use super::{SemanticSuggestion, SuggestionKind, completion_common::FileSuggestion};
|
||||
use super::{completion_common::FileSuggestion, SemanticSuggestion, SuggestionKind};
|
||||
|
||||
pub struct DirectoryCompletion;
|
||||
|
||||
|
@ -1,18 +1,17 @@
|
||||
use crate::completions::{
|
||||
Completer, CompletionOptions, SemanticSuggestion, SuggestionKind,
|
||||
completion_common::{FileSuggestion, surround_remove},
|
||||
completion_common::{surround_remove, FileSuggestion},
|
||||
completion_options::NuMatcher,
|
||||
file_path_completion,
|
||||
file_path_completion, Completer, CompletionOptions, SemanticSuggestion, SuggestionKind,
|
||||
};
|
||||
use nu_path::expand_tilde;
|
||||
use nu_protocol::{
|
||||
Span,
|
||||
engine::{Stack, StateWorkingSet, VirtualPath},
|
||||
Span,
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
path::{MAIN_SEPARATOR_STR, PathBuf, is_separator},
|
||||
path::{is_separator, PathBuf, MAIN_SEPARATOR_STR},
|
||||
};
|
||||
|
||||
pub struct DotNuCompletion {
|
||||
@ -129,7 +128,7 @@ impl Completer for DotNuCompletion {
|
||||
.take_while(|c| "`'\"".contains(*c))
|
||||
.collect::<String>();
|
||||
for path in ["std", "std-rfc"] {
|
||||
let path = format!("{surround_prefix}{path}");
|
||||
let path = format!("{}{}", surround_prefix, path);
|
||||
matcher.add(
|
||||
path.clone(),
|
||||
FileSuggestion {
|
||||
@ -146,7 +145,7 @@ impl Completer for DotNuCompletion {
|
||||
for sub_vp_id in sub_paths {
|
||||
let (path, sub_vp) = working_set.get_virtual_path(*sub_vp_id);
|
||||
let path = path
|
||||
.strip_prefix(&format!("{base_dir}/"))
|
||||
.strip_prefix(&format!("{}/", base_dir))
|
||||
.unwrap_or(path)
|
||||
.to_string();
|
||||
matcher.add(
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::completions::{
|
||||
Completer, CompletionOptions, SemanticSuggestion, SuggestionKind,
|
||||
completion_common::surround_remove, completion_options::NuMatcher,
|
||||
completion_common::surround_remove, completion_options::NuMatcher, Completer,
|
||||
CompletionOptions, SemanticSuggestion, SuggestionKind,
|
||||
};
|
||||
use nu_protocol::{
|
||||
ModuleId, Span,
|
||||
engine::{Stack, StateWorkingSet},
|
||||
ModuleId, Span,
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
use crate::completions::{
|
||||
completion_common::{adjust_if_intermediate, complete_item, AdjustView},
|
||||
Completer, CompletionOptions,
|
||||
completion_common::{AdjustView, adjust_if_intermediate, complete_item},
|
||||
};
|
||||
use nu_protocol::{
|
||||
Span,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
Span,
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
use std::path::Path;
|
||||
|
||||
use super::{SemanticSuggestion, SuggestionKind, completion_common::FileSuggestion};
|
||||
use super::{completion_common::FileSuggestion, SemanticSuggestion, SuggestionKind};
|
||||
|
||||
pub struct FileCompletion;
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::completions::{
|
||||
Completer, CompletionOptions, SemanticSuggestion, SuggestionKind, completion_options::NuMatcher,
|
||||
completion_options::NuMatcher, Completer, CompletionOptions, SemanticSuggestion, SuggestionKind,
|
||||
};
|
||||
use nu_protocol::{
|
||||
DeclId, Span,
|
||||
engine::{Stack, StateWorkingSet},
|
||||
DeclId, Span,
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
|
||||
|
@ -24,7 +24,7 @@ pub use custom_completions::CustomCompletion;
|
||||
pub use directory_completions::DirectoryCompletion;
|
||||
pub use dotnu_completions::DotNuCompletion;
|
||||
pub use exportable_completions::ExportableCompletion;
|
||||
pub use file_completions::{FileCompletion, file_path_completion};
|
||||
pub use file_completions::{file_path_completion, FileCompletion};
|
||||
pub use flag_completions::FlagCompletion;
|
||||
pub use operator_completions::OperatorCompletion;
|
||||
pub use variable_completions::VariableCompletion;
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::completions::{
|
||||
Completer, CompletionOptions, SemanticSuggestion, SuggestionKind, completion_options::NuMatcher,
|
||||
completion_options::NuMatcher, Completer, CompletionOptions, SemanticSuggestion, SuggestionKind,
|
||||
};
|
||||
use nu_protocol::{
|
||||
ENV_VARIABLE_ID, Span, Type, Value,
|
||||
ast::{self, Comparison, Expr, Expression},
|
||||
engine::{Stack, StateWorkingSet},
|
||||
Span, Type, Value, ENV_VARIABLE_ID,
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
use strum::{EnumMessage, IntoEnumIterator};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::completions::{Completer, CompletionOptions, SemanticSuggestion, SuggestionKind};
|
||||
use nu_protocol::{
|
||||
Span, VarId,
|
||||
engine::{Stack, StateWorkingSet},
|
||||
Span, VarId,
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
|
||||
|
@ -2,11 +2,10 @@ use crate::util::eval_source;
|
||||
#[cfg(feature = "plugin")]
|
||||
use nu_path::canonicalize_with;
|
||||
#[cfg(feature = "plugin")]
|
||||
use nu_protocol::{ParseError, PluginRegistryFile, Spanned, engine::StateWorkingSet};
|
||||
use nu_protocol::{engine::StateWorkingSet, ParseError, PluginRegistryFile, Spanned};
|
||||
use nu_protocol::{
|
||||
PipelineData,
|
||||
engine::{EngineState, Stack},
|
||||
report_shell_error,
|
||||
report_shell_error, PipelineData,
|
||||
};
|
||||
#[cfg(feature = "plugin")]
|
||||
use nu_utils::perf;
|
||||
@ -19,7 +18,7 @@ const OLD_PLUGIN_FILE: &str = "plugin.nu";
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
pub fn read_plugin_file(engine_state: &mut EngineState, plugin_file: Option<Spanned<String>>) {
|
||||
use nu_protocol::{ShellError, shell_error::io::IoError};
|
||||
use nu_protocol::{shell_error::io::IoError, ShellError};
|
||||
use std::path::Path;
|
||||
|
||||
let span = plugin_file.as_ref().map(|s| s.span);
|
||||
@ -80,7 +79,7 @@ pub fn read_plugin_file(engine_state: &mut EngineState, plugin_file: Option<Span
|
||||
report_shell_error(
|
||||
engine_state,
|
||||
&ShellError::Io(IoError::new_internal_with_path(
|
||||
err,
|
||||
err.kind(),
|
||||
"Could not open plugin registry file",
|
||||
nu_protocol::location!(),
|
||||
plugin_path,
|
||||
@ -231,8 +230,8 @@ pub fn eval_config_contents(
|
||||
#[cfg(feature = "plugin")]
|
||||
pub fn migrate_old_plugin_file(engine_state: &EngineState) -> bool {
|
||||
use nu_protocol::{
|
||||
PluginExample, PluginIdentity, PluginRegistryItem, PluginRegistryItemData, PluginSignature,
|
||||
ShellError, shell_error::io::IoError,
|
||||
shell_error::io::IoError, PluginExample, PluginIdentity, PluginRegistryItem,
|
||||
PluginRegistryItemData, PluginSignature, ShellError,
|
||||
};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
@ -323,7 +322,7 @@ pub fn migrate_old_plugin_file(engine_state: &EngineState) -> bool {
|
||||
if let Err(err) = std::fs::File::create(&new_plugin_file_path)
|
||||
.map_err(|err| {
|
||||
IoError::new_internal_with_path(
|
||||
err,
|
||||
err.kind(),
|
||||
"Could not create new plugin file",
|
||||
nu_protocol::location!(),
|
||||
new_plugin_file_path.clone(),
|
||||
|
@ -2,11 +2,10 @@ use log::info;
|
||||
use nu_engine::eval_block;
|
||||
use nu_parser::parse;
|
||||
use nu_protocol::{
|
||||
PipelineData, ShellError, Spanned, Value,
|
||||
cli_error::report_compile_error,
|
||||
debugger::WithoutDebug,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
report_parse_error, report_parse_warning,
|
||||
report_parse_error, report_parse_warning, PipelineData, ShellError, Spanned, Value,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -4,12 +4,12 @@ use nu_engine::eval_block;
|
||||
use nu_parser::parse;
|
||||
use nu_path::canonicalize_with;
|
||||
use nu_protocol::{
|
||||
PipelineData, ShellError, Span, Value,
|
||||
cli_error::report_compile_error,
|
||||
debugger::WithoutDebug,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
report_parse_error, report_parse_warning,
|
||||
shell_error::io::*,
|
||||
PipelineData, ShellError, Span, Value,
|
||||
};
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
@ -28,7 +28,7 @@ pub fn evaluate_file(
|
||||
|
||||
let file_path = canonicalize_with(&path, cwd).map_err(|err| {
|
||||
IoError::new_internal_with_path(
|
||||
err.not_found_as(NotFound::File),
|
||||
err.kind().not_found_as(NotFound::File),
|
||||
"Could not access file",
|
||||
nu_protocol::location!(),
|
||||
PathBuf::from(&path),
|
||||
@ -47,7 +47,7 @@ pub fn evaluate_file(
|
||||
|
||||
let file = std::fs::read(&file_path).map_err(|err| {
|
||||
IoError::new_internal_with_path(
|
||||
err.not_found_as(NotFound::File),
|
||||
err.kind().not_found_as(NotFound::File),
|
||||
"Could not read file",
|
||||
nu_protocol::location!(),
|
||||
file_path.clone(),
|
||||
|
@ -18,7 +18,7 @@ mod validation;
|
||||
pub use commands::add_cli_context;
|
||||
pub use completions::{FileCompletion, NuCompleter, SemanticSuggestion, SuggestionKind};
|
||||
pub use config_files::eval_config_contents;
|
||||
pub use eval_cmds::{EvaluateCommandsOpts, evaluate_commands};
|
||||
pub use eval_cmds::{evaluate_commands, EvaluateCommandsOpts};
|
||||
pub use eval_file::evaluate_file;
|
||||
pub use menus::NuHelpCompleter;
|
||||
pub use nu_highlight::NuHighlight;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use nu_engine::documentation::{FormatterValue, HelpStyle, get_flags_section};
|
||||
use nu_protocol::{Config, engine::EngineState, levenshtein_distance};
|
||||
use nu_engine::documentation::{get_flags_section, HelpStyle};
|
||||
use nu_protocol::{engine::EngineState, levenshtein_distance, Config};
|
||||
use nu_utils::IgnoreCaseExt;
|
||||
use reedline::{Completer, Suggestion};
|
||||
use std::{fmt::Write, sync::Arc};
|
||||
@ -66,11 +66,8 @@ impl NuHelpCompleter {
|
||||
let _ = write!(long_desc, "Usage:\r\n > {}\r\n", sig.call_signature());
|
||||
|
||||
if !sig.named.is_empty() {
|
||||
long_desc.push_str(&get_flags_section(&sig, &help_style, |v| match v {
|
||||
FormatterValue::DefaultValue(value) => {
|
||||
value.to_parsable_string(", ", &self.config)
|
||||
}
|
||||
FormatterValue::CodeString(text) => text.to_string(),
|
||||
long_desc.push_str(&get_flags_section(&sig, &help_style, |v| {
|
||||
v.to_parsable_string(", ", &self.config)
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
use nu_engine::eval_block;
|
||||
use nu_protocol::{
|
||||
BlockId, IntoPipelineData, Span, Value,
|
||||
debugger::WithoutDebug,
|
||||
engine::{EngineState, Stack},
|
||||
BlockId, IntoPipelineData, Span, Value,
|
||||
};
|
||||
use reedline::{Completer, Suggestion, menu_functions::parse_selection_char};
|
||||
use reedline::{menu_functions::parse_selection_char, Completer, Suggestion};
|
||||
use std::sync::Arc;
|
||||
|
||||
const SELECTION_CHAR: char = '!';
|
||||
|
@ -3,8 +3,6 @@ use std::sync::Arc;
|
||||
use nu_engine::command_prelude::*;
|
||||
use reedline::{Highlighter, StyledText};
|
||||
|
||||
use crate::syntax_highlight::highlight_syntax;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NuHighlight;
|
||||
|
||||
@ -16,11 +14,6 @@ impl Command for NuHighlight {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("nu-highlight")
|
||||
.category(Category::Strings)
|
||||
.switch(
|
||||
"reject-garbage",
|
||||
"Return an error if invalid syntax (garbage) was encountered",
|
||||
Some('r'),
|
||||
)
|
||||
.input_output_types(vec![(Type::String, Type::String)])
|
||||
}
|
||||
|
||||
@ -39,33 +32,19 @@ impl Command for NuHighlight {
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let reject_garbage = call.has_flag(engine_state, stack, "reject-garbage")?;
|
||||
let head = call.head;
|
||||
|
||||
let signals = engine_state.signals();
|
||||
|
||||
let engine_state = Arc::new(engine_state.clone());
|
||||
let stack = Arc::new(stack.clone());
|
||||
let highlighter = crate::NuHighlighter {
|
||||
engine_state: Arc::new(engine_state.clone()),
|
||||
stack: Arc::new(stack.clone()),
|
||||
};
|
||||
|
||||
input.map(
|
||||
move |x| match x.coerce_into_string() {
|
||||
Ok(line) => {
|
||||
let result = highlight_syntax(&engine_state, &stack, &line, line.len());
|
||||
|
||||
let highlights = match (reject_garbage, result.found_garbage) {
|
||||
(false, _) => result.text,
|
||||
(true, None) => result.text,
|
||||
(true, Some(span)) => {
|
||||
let error = ShellError::OutsideSpannedLabeledError {
|
||||
src: line,
|
||||
error: "encountered invalid syntax while highlighting".into(),
|
||||
msg: "invalid syntax".into(),
|
||||
span,
|
||||
};
|
||||
return Value::error(error, head);
|
||||
}
|
||||
};
|
||||
|
||||
let highlights = highlighter.highlight(&line, line.len());
|
||||
Value::string(highlights.render_simple(), head)
|
||||
}
|
||||
Err(err) => Value::error(err, head),
|
||||
|
@ -2,9 +2,8 @@ use crate::NushellPrompt;
|
||||
use log::{trace, warn};
|
||||
use nu_engine::ClosureEvalOnce;
|
||||
use nu_protocol::{
|
||||
Config, PipelineData, Value,
|
||||
engine::{EngineState, Stack},
|
||||
report_shell_error,
|
||||
report_shell_error, Config, PipelineData, Value,
|
||||
};
|
||||
use reedline::Prompt;
|
||||
|
||||
|
@ -1,20 +1,19 @@
|
||||
use crate::{NuHelpCompleter, menus::NuMenuCompleter};
|
||||
use crate::{menus::NuMenuCompleter, NuHelpCompleter};
|
||||
use crossterm::event::{KeyCode, KeyModifiers};
|
||||
use nu_ansi_term::Style;
|
||||
use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
|
||||
use nu_engine::eval_block;
|
||||
use nu_parser::parse;
|
||||
use nu_protocol::{
|
||||
Config, EditBindings, FromValue, ParsedKeybinding, ParsedMenu, PipelineData, Record,
|
||||
ShellError, Span, Type, Value,
|
||||
debugger::WithoutDebug,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
extract_value,
|
||||
extract_value, Config, EditBindings, FromValue, ParsedKeybinding, ParsedMenu, PipelineData,
|
||||
Record, ShellError, Span, Type, Value,
|
||||
};
|
||||
use reedline::{
|
||||
default_emacs_keybindings, default_vi_insert_keybindings, default_vi_normal_keybindings,
|
||||
ColumnarMenu, DescriptionMenu, DescriptionMode, EditCommand, IdeMenu, Keybindings, ListMenu,
|
||||
MenuBuilder, Reedline, ReedlineEvent, ReedlineMenu, default_emacs_keybindings,
|
||||
default_vi_insert_keybindings, default_vi_normal_keybindings,
|
||||
MenuBuilder, Reedline, ReedlineEvent, ReedlineMenu,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -6,12 +6,12 @@ use crate::prompt_update::{
|
||||
VSCODE_PRE_EXECUTION_MARKER,
|
||||
};
|
||||
use crate::{
|
||||
NuHighlighter, NuValidator, NushellPrompt,
|
||||
completions::NuCompleter,
|
||||
nu_highlight::NoOpHighlighter,
|
||||
prompt_update,
|
||||
reedline_config::{KeybindingsMode, add_menus, create_keybindings},
|
||||
reedline_config::{add_menus, create_keybindings, KeybindingsMode},
|
||||
util::eval_source,
|
||||
NuHighlighter, NuValidator, NushellPrompt,
|
||||
};
|
||||
use crossterm::cursor::SetCursorStyle;
|
||||
use log::{error, trace, warn};
|
||||
@ -23,15 +23,14 @@ use nu_engine::env_to_strings;
|
||||
use nu_engine::exit::cleanup_exit;
|
||||
use nu_parser::{lex, parse, trim_quotes_str};
|
||||
use nu_protocol::shell_error::io::IoError;
|
||||
use nu_protocol::{BannerKind, shell_error};
|
||||
use nu_protocol::{
|
||||
HistoryConfig, HistoryFileFormat, PipelineData, ShellError, Span, Spanned, Value,
|
||||
config::NuCursorShape,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
report_shell_error,
|
||||
report_shell_error, HistoryConfig, HistoryFileFormat, PipelineData, ShellError, Span, Spanned,
|
||||
Value,
|
||||
};
|
||||
use nu_utils::{
|
||||
filesystem::{PermissionResult, have_permission},
|
||||
filesystem::{have_permission, PermissionResult},
|
||||
perf,
|
||||
};
|
||||
use reedline::{
|
||||
@ -43,7 +42,7 @@ use std::{
|
||||
collections::HashMap,
|
||||
env::temp_dir,
|
||||
io::{self, IsTerminal, Write},
|
||||
panic::{AssertUnwindSafe, catch_unwind},
|
||||
panic::{catch_unwind, AssertUnwindSafe},
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
@ -145,8 +144,8 @@ pub fn evaluate_repl(
|
||||
|
||||
if load_std_lib.is_none() {
|
||||
match engine_state.get_config().show_banner {
|
||||
BannerKind::None => {}
|
||||
BannerKind::Short => {
|
||||
Value::Bool { val: false, .. } => {}
|
||||
Value::String { ref val, .. } if val == "short" => {
|
||||
eval_source(
|
||||
engine_state,
|
||||
&mut unique_stack,
|
||||
@ -156,7 +155,7 @@ pub fn evaluate_repl(
|
||||
false,
|
||||
);
|
||||
}
|
||||
BannerKind::Full => {
|
||||
_ => {
|
||||
eval_source(
|
||||
engine_state,
|
||||
&mut unique_stack,
|
||||
@ -239,7 +238,7 @@ fn escape_special_vscode_bytes(input: &str) -> Result<String, ShellError> {
|
||||
|
||||
match byte {
|
||||
// Escape bytes below 0x20
|
||||
b if b < 0x20 => format!("\\x{byte:02X}").into_bytes(),
|
||||
b if b < 0x20 => format!("\\x{:02X}", byte).into_bytes(),
|
||||
// Escape semicolon as \x3B
|
||||
b';' => "\\x3B".to_string().into_bytes(),
|
||||
// Escape backslash as \\
|
||||
@ -855,7 +854,7 @@ fn do_auto_cd(
|
||||
report_shell_error(
|
||||
engine_state,
|
||||
&ShellError::Io(IoError::new_with_additional_context(
|
||||
shell_error::io::ErrorKind::DirectoryNotFound,
|
||||
std::io::ErrorKind::NotFound,
|
||||
span,
|
||||
PathBuf::from(&path),
|
||||
"Cannot change directory",
|
||||
@ -869,7 +868,7 @@ fn do_auto_cd(
|
||||
report_shell_error(
|
||||
engine_state,
|
||||
&ShellError::Io(IoError::new_with_additional_context(
|
||||
shell_error::io::ErrorKind::from_std(std::io::ErrorKind::PermissionDenied),
|
||||
std::io::ErrorKind::PermissionDenied,
|
||||
span,
|
||||
PathBuf::from(path),
|
||||
"Cannot change directory",
|
||||
@ -1097,7 +1096,8 @@ fn run_shell_integration_osc633(
|
||||
// If we're in vscode, run their specific ansi escape sequence.
|
||||
// This is helpful for ctrl+g to change directories in the terminal.
|
||||
run_ansi_sequence(&format!(
|
||||
"{VSCODE_CWD_PROPERTY_MARKER_PREFIX}{path}{VSCODE_CWD_PROPERTY_MARKER_SUFFIX}"
|
||||
"{}{}{}",
|
||||
VSCODE_CWD_PROPERTY_MARKER_PREFIX, path, VSCODE_CWD_PROPERTY_MARKER_SUFFIX
|
||||
));
|
||||
|
||||
perf!(
|
||||
@ -1113,7 +1113,10 @@ fn run_shell_integration_osc633(
|
||||
|
||||
//OSC 633 ; E ; <commandline> [; <nonce] ST - Explicitly set the command line with an optional nonce.
|
||||
run_ansi_sequence(&format!(
|
||||
"{VSCODE_COMMANDLINE_MARKER_PREFIX}{replaced_cmd_text}{VSCODE_COMMANDLINE_MARKER_SUFFIX}"
|
||||
"{}{}{}",
|
||||
VSCODE_COMMANDLINE_MARKER_PREFIX,
|
||||
replaced_cmd_text,
|
||||
VSCODE_COMMANDLINE_MARKER_SUFFIX
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -1448,7 +1451,7 @@ fn are_session_ids_in_sync() {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_auto_cd {
|
||||
use super::{ReplOperation, do_auto_cd, escape_special_vscode_bytes, parse_operation};
|
||||
use super::{do_auto_cd, escape_special_vscode_bytes, parse_operation, ReplOperation};
|
||||
use nu_path::AbsolutePath;
|
||||
use nu_protocol::engine::{EngineState, Stack};
|
||||
use tempfile::tempdir;
|
||||
@ -1489,7 +1492,7 @@ mod test_auto_cd {
|
||||
// Parse the input. It must be an auto-cd operation.
|
||||
let op = parse_operation(input.to_string(), &engine_state, &stack).unwrap();
|
||||
let ReplOperation::AutoCd { cwd, target, span } = op else {
|
||||
panic!("'{input}' was not parsed into an auto-cd operation")
|
||||
panic!("'{}' was not parsed into an auto-cd operation", input)
|
||||
};
|
||||
|
||||
// Perform the auto-cd operation.
|
||||
|
@ -2,11 +2,11 @@ use log::trace;
|
||||
use nu_ansi_term::Style;
|
||||
use nu_color_config::{get_matching_brackets_style, get_shape_color};
|
||||
use nu_engine::env;
|
||||
use nu_parser::{FlatShape, flatten_block, parse};
|
||||
use nu_parser::{flatten_block, parse, FlatShape};
|
||||
use nu_protocol::{
|
||||
Span,
|
||||
ast::{Block, Expr, Expression, PipelineRedirection, RecordItem},
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
Span,
|
||||
};
|
||||
use reedline::{Highlighter, StyledText};
|
||||
use std::sync::Arc;
|
||||
@ -17,32 +17,12 @@ pub struct NuHighlighter {
|
||||
}
|
||||
|
||||
impl Highlighter for NuHighlighter {
|
||||
fn highlight(&self, line: &str, cursor: usize) -> StyledText {
|
||||
let result = highlight_syntax(&self.engine_state, &self.stack, line, cursor);
|
||||
result.text
|
||||
}
|
||||
}
|
||||
|
||||
/// Result of a syntax highlight operation
|
||||
#[derive(Default)]
|
||||
pub(crate) struct HighlightResult {
|
||||
/// The highlighted text
|
||||
pub(crate) text: StyledText,
|
||||
/// The span of any garbage that was highlighted
|
||||
pub(crate) found_garbage: Option<Span>,
|
||||
}
|
||||
|
||||
pub(crate) fn highlight_syntax(
|
||||
engine_state: &EngineState,
|
||||
stack: &Stack,
|
||||
line: &str,
|
||||
cursor: usize,
|
||||
) -> HighlightResult {
|
||||
fn highlight(&self, line: &str, _cursor: usize) -> StyledText {
|
||||
trace!("highlighting: {}", line);
|
||||
|
||||
let config = stack.get_config(engine_state);
|
||||
let config = self.stack.get_config(&self.engine_state);
|
||||
let highlight_resolved_externals = config.highlight_resolved_externals;
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
let mut working_set = StateWorkingSet::new(&self.engine_state);
|
||||
let block = parse(&mut working_set, None, line.as_bytes(), false);
|
||||
let (shapes, global_span_offset) = {
|
||||
let mut shapes = flatten_block(&working_set, &block);
|
||||
@ -55,8 +35,11 @@ pub(crate) fn highlight_syntax(
|
||||
working_set.get_span_contents(Span::new(span.start, span.end));
|
||||
|
||||
let str_word = String::from_utf8_lossy(str_contents).to_string();
|
||||
let paths = env::path_str(engine_state, stack, *span).ok();
|
||||
let res = if let Ok(cwd) = engine_state.cwd(Some(stack)) {
|
||||
let paths = env::path_str(&self.engine_state, &self.stack, *span).ok();
|
||||
#[allow(deprecated)]
|
||||
let res = if let Ok(cwd) =
|
||||
env::current_dir_str(&self.engine_state, &self.stack)
|
||||
{
|
||||
which::which_in(str_word, paths.as_ref(), cwd).ok()
|
||||
} else {
|
||||
which::which_in_global(str_word, paths.as_ref())
|
||||
@ -69,13 +52,13 @@ pub(crate) fn highlight_syntax(
|
||||
}
|
||||
}
|
||||
}
|
||||
(shapes, engine_state.next_span_start())
|
||||
(shapes, self.engine_state.next_span_start())
|
||||
};
|
||||
|
||||
let mut result = HighlightResult::default();
|
||||
let mut output = StyledText::default();
|
||||
let mut last_seen_span = global_span_offset;
|
||||
|
||||
let global_cursor_offset = cursor + global_span_offset;
|
||||
let global_cursor_offset = _cursor + global_span_offset;
|
||||
let matching_brackets_pos = find_matching_brackets(
|
||||
line,
|
||||
&working_set,
|
||||
@ -97,28 +80,18 @@ pub(crate) fn highlight_syntax(
|
||||
let gap = line
|
||||
[(last_seen_span - global_span_offset)..(shape.0.start - global_span_offset)]
|
||||
.to_string();
|
||||
result.text.push((Style::new(), gap));
|
||||
output.push((Style::new(), gap));
|
||||
}
|
||||
let next_token = line
|
||||
[(shape.0.start - global_span_offset)..(shape.0.end - global_span_offset)]
|
||||
.to_string();
|
||||
|
||||
let mut add_colored_token = |shape: &FlatShape, text: String| {
|
||||
result
|
||||
.text
|
||||
.push((get_shape_color(shape.as_str(), &config), text));
|
||||
output.push((get_shape_color(shape.as_str(), &config), text));
|
||||
};
|
||||
|
||||
match shape.1 {
|
||||
FlatShape::Garbage => {
|
||||
result.found_garbage.get_or_insert_with(|| {
|
||||
Span::new(
|
||||
shape.0.start - global_span_offset,
|
||||
shape.0.end - global_span_offset,
|
||||
)
|
||||
});
|
||||
add_colored_token(&shape.1, next_token)
|
||||
}
|
||||
FlatShape::Garbage => add_colored_token(&shape.1, next_token),
|
||||
FlatShape::Nothing => add_colored_token(&shape.1, next_token),
|
||||
FlatShape::Binary => add_colored_token(&shape.1, next_token),
|
||||
FlatShape::Bool => add_colored_token(&shape.1, next_token),
|
||||
@ -158,7 +131,7 @@ pub(crate) fn highlight_syntax(
|
||||
if highlight {
|
||||
style = get_matching_brackets_style(style, &config);
|
||||
}
|
||||
result.text.push((style, text));
|
||||
output.push((style, text));
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,10 +153,11 @@ pub(crate) fn highlight_syntax(
|
||||
|
||||
let remainder = line[(last_seen_span - global_span_offset)..].to_string();
|
||||
if !remainder.is_empty() {
|
||||
result.text.push((Style::new(), remainder));
|
||||
output.push((Style::new(), remainder));
|
||||
}
|
||||
|
||||
result
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
fn split_span_by_highlight_positions(
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
use nu_cmd_base::hook::eval_hook;
|
||||
use nu_engine::{eval_block, eval_block_with_early_return};
|
||||
use nu_parser::{Token, TokenContents, lex, parse, unescape_unquote_string};
|
||||
use nu_parser::{lex, parse, unescape_unquote_string, Token, TokenContents};
|
||||
use nu_protocol::{
|
||||
PipelineData, ShellError, Span, Value,
|
||||
cli_error::report_compile_error,
|
||||
debugger::WithoutDebug,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
report_parse_error, report_parse_warning, report_shell_error,
|
||||
report_parse_error, report_parse_warning, report_shell_error, PipelineData, ShellError, Span,
|
||||
Value,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use nu_utils::enable_vt_processing;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use nu_parser::parse;
|
||||
use nu_protocol::{
|
||||
ParseError,
|
||||
engine::{EngineState, StateWorkingSet},
|
||||
ParseError,
|
||||
};
|
||||
use reedline::{ValidationResult, Validator};
|
||||
use std::sync::Arc;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use nu_protocol::HistoryFileFormat;
|
||||
use nu_test_support::{Outcome, nu};
|
||||
use nu_test_support::{nu, Outcome};
|
||||
use reedline::{
|
||||
FileBackedHistory, History, HistoryItem, HistoryItemId, ReedlineError, SearchQuery,
|
||||
SqliteBackedHistory,
|
||||
|
@ -1,24 +1,22 @@
|
||||
pub mod support;
|
||||
|
||||
use std::{
|
||||
fs::{FileType, ReadDir, read_dir},
|
||||
path::{MAIN_SEPARATOR, PathBuf},
|
||||
fs::{read_dir, FileType, ReadDir},
|
||||
path::{PathBuf, MAIN_SEPARATOR},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use nu_cli::NuCompleter;
|
||||
use nu_engine::eval_block;
|
||||
use nu_parser::parse;
|
||||
use nu_path::{AbsolutePathBuf, expand_tilde};
|
||||
use nu_protocol::{Config, PipelineData, debugger::WithoutDebug, engine::StateWorkingSet};
|
||||
use nu_path::expand_tilde;
|
||||
use nu_protocol::{debugger::WithoutDebug, engine::StateWorkingSet, Config, PipelineData};
|
||||
use nu_std::load_standard_library;
|
||||
use nu_test_support::fs;
|
||||
use reedline::{Completer, Suggestion};
|
||||
use rstest::{fixture, rstest};
|
||||
use support::{
|
||||
completions_helpers::{
|
||||
new_dotnu_engine, new_engine_helper, new_external_engine, new_partial_engine,
|
||||
new_quote_engine,
|
||||
new_dotnu_engine, new_external_engine, new_partial_engine, new_quote_engine,
|
||||
},
|
||||
file, folder, match_suggestions, match_suggestions_by_string, new_engine,
|
||||
};
|
||||
@ -125,7 +123,7 @@ fn custom_completer_with_options(
|
||||
global_opts,
|
||||
completions
|
||||
.iter()
|
||||
.map(|comp| format!("'{comp}'"))
|
||||
.map(|comp| format!("'{}'", comp))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
completer_opts,
|
||||
@ -718,16 +716,6 @@ fn external_completer_fallback() {
|
||||
let expected = [folder("test_a"), file("test_a_symlink"), folder("test_b")];
|
||||
let suggestions = run_external_completion(block, input);
|
||||
match_suggestions_by_string(&expected, &suggestions);
|
||||
|
||||
// issue #15790
|
||||
let input = "foo `dir with space/`";
|
||||
let expected = vec!["`dir with space/bar baz`", "`dir with space/foo`"];
|
||||
let suggestions = run_external_completion_within_pwd(
|
||||
block,
|
||||
input,
|
||||
fs::fixtures().join("external_completions"),
|
||||
);
|
||||
match_suggestions(&expected, &suggestions);
|
||||
}
|
||||
|
||||
/// Fallback to external completions for flags of `sudo`
|
||||
@ -1591,25 +1579,16 @@ fn attribute_completions() {
|
||||
// Create a 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
|
||||
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
|
||||
// Test completions for the 'ls' flags
|
||||
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_suggestions_by_string(&attribute_names, &suggestions);
|
||||
match_suggestions(&expected, &suggestions);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -2115,15 +2094,11 @@ fn alias_of_another_alias() {
|
||||
match_suggestions(&expected_paths, &suggestions)
|
||||
}
|
||||
|
||||
fn run_external_completion_within_pwd(
|
||||
completer: &str,
|
||||
input: &str,
|
||||
pwd: AbsolutePathBuf,
|
||||
) -> Vec<Suggestion> {
|
||||
fn run_external_completion(completer: &str, input: &str) -> Vec<Suggestion> {
|
||||
let completer = format!("$env.config.completions.external.completer = {completer}");
|
||||
|
||||
// Create a new engine
|
||||
let (_, _, mut engine_state, mut stack) = new_engine_helper(pwd);
|
||||
let (_, _, mut engine_state, mut stack) = new_engine();
|
||||
let (block, delta) = {
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
let block = parse(&mut working_set, None, completer.as_bytes(), false);
|
||||
@ -2147,10 +2122,6 @@ fn run_external_completion_within_pwd(
|
||||
completer.complete(input, input.len())
|
||||
}
|
||||
|
||||
fn run_external_completion(completer: &str, input: &str) -> Vec<Suggestion> {
|
||||
run_external_completion_within_pwd(completer, input, fs::fixtures().join("completions"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_command_completion() {
|
||||
let (_, _, engine, stack) = new_engine();
|
||||
@ -2375,32 +2346,6 @@ fn exact_match() {
|
||||
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"]
|
||||
#[rstest]
|
||||
fn alias_offset_bug_7648() {
|
||||
|
@ -2,9 +2,9 @@ use nu_engine::eval_block;
|
||||
use nu_parser::parse;
|
||||
use nu_path::{AbsolutePathBuf, PathBuf};
|
||||
use nu_protocol::{
|
||||
PipelineData, ShellError, Span, Value,
|
||||
debugger::WithoutDebug,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
PipelineData, ShellError, Span, Value,
|
||||
};
|
||||
use nu_test_support::fs;
|
||||
use reedline::Suggestion;
|
||||
@ -14,8 +14,11 @@ fn create_default_context() -> EngineState {
|
||||
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context())
|
||||
}
|
||||
|
||||
pub fn new_engine_helper(pwd: AbsolutePathBuf) -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||
let pwd_str = pwd
|
||||
/// creates a new engine with the current path into the completions fixtures folder
|
||||
pub fn new_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||
// Target folder inside assets
|
||||
let dir = fs::fixtures().join("completions");
|
||||
let dir_str = dir
|
||||
.clone()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
@ -33,13 +36,13 @@ pub fn new_engine_helper(pwd: AbsolutePathBuf) -> (AbsolutePathBuf, String, Engi
|
||||
// Add pwd as env var
|
||||
stack.add_env_var(
|
||||
"PWD".to_string(),
|
||||
Value::string(pwd_str.clone(), nu_protocol::Span::new(0, pwd_str.len())),
|
||||
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, pwd_str.len()),
|
||||
nu_protocol::Span::new(0, dir_str.len()),
|
||||
),
|
||||
);
|
||||
#[cfg(windows)]
|
||||
@ -47,7 +50,7 @@ pub fn new_engine_helper(pwd: AbsolutePathBuf) -> (AbsolutePathBuf, String, Engi
|
||||
"Path".to_string(),
|
||||
Value::string(
|
||||
"c:\\some\\path;c:\\some\\other\\path".to_string(),
|
||||
nu_protocol::Span::new(0, pwd_str.len()),
|
||||
nu_protocol::Span::new(0, dir_str.len()),
|
||||
),
|
||||
);
|
||||
#[cfg(not(windows))]
|
||||
@ -55,7 +58,7 @@ pub fn new_engine_helper(pwd: AbsolutePathBuf) -> (AbsolutePathBuf, String, Engi
|
||||
"PATH".to_string(),
|
||||
Value::string(
|
||||
"/some/path:/some/other/path".to_string(),
|
||||
nu_protocol::Span::new(0, pwd_str.len()),
|
||||
nu_protocol::Span::new(0, dir_str.len()),
|
||||
),
|
||||
);
|
||||
|
||||
@ -63,12 +66,7 @@ pub fn new_engine_helper(pwd: AbsolutePathBuf) -> (AbsolutePathBuf, String, Engi
|
||||
let merge_result = engine_state.merge_env(&mut stack);
|
||||
assert!(merge_result.is_ok());
|
||||
|
||||
(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"))
|
||||
(dir, dir_str, engine_state, stack)
|
||||
}
|
||||
|
||||
/// Adds pseudo PATH env for external completion tests
|
||||
@ -90,13 +88,23 @@ pub fn new_external_engine() -> EngineState {
|
||||
engine
|
||||
}
|
||||
|
||||
/// creates a new engine with the current path in the dotnu_completions fixtures folder
|
||||
/// creates a new engine with the current path into the completions fixtures folder
|
||||
pub fn new_dotnu_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||
// Target folder inside assets
|
||||
let dir = fs::fixtures().join("dotnu_completions");
|
||||
let (dir, dir_str, mut engine_state, mut stack) = new_engine_helper(dir);
|
||||
let dir_str = dir
|
||||
.clone()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap_or_default();
|
||||
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
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
let var_id = working_set.add_variable(
|
||||
@ -114,6 +122,15 @@ pub fn new_dotnu_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||
);
|
||||
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(
|
||||
"NU_LIB_DIRS".into(),
|
||||
Value::test_list(vec![
|
||||
@ -130,11 +147,73 @@ pub fn new_dotnu_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||
}
|
||||
|
||||
pub fn new_quote_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||
new_engine_helper(fs::fixtures().join("quoted_completions"))
|
||||
// Target folder inside assets
|
||||
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) {
|
||||
new_engine_helper(fs::fixtures().join("partial_completions"))
|
||||
// Target folder inside assets
|
||||
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
|
||||
@ -194,15 +273,13 @@ pub fn merge_input(
|
||||
|
||||
engine_state.merge_delta(delta)?;
|
||||
|
||||
assert!(
|
||||
eval_block::<WithoutDebug>(
|
||||
assert!(eval_block::<WithoutDebug>(
|
||||
engine_state,
|
||||
stack,
|
||||
&block,
|
||||
PipelineData::Value(Value::nothing(Span::unknown()), None),
|
||||
)
|
||||
.is_ok()
|
||||
);
|
||||
.is_ok());
|
||||
|
||||
// Merge environment into the permanent state
|
||||
engine_state.merge_env(stack)
|
||||
|
@ -1,11 +1,11 @@
|
||||
[package]
|
||||
authors = ["The Nushell Project Developers"]
|
||||
description = "The foundation tools to build Nushell commands."
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-base"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
|
||||
version = "0.105.2"
|
||||
version = "0.104.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -13,10 +13,10 @@ version = "0.105.2"
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.105.2", default-features = false }
|
||||
nu-parser = { path = "../nu-parser", version = "0.105.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.105.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.105.2", default-features = false }
|
||||
nu-engine = { path = "../nu-engine", version = "0.104.1", default-features = false }
|
||||
nu-parser = { path = "../nu-parser", version = "0.104.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.104.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.104.1", default-features = false }
|
||||
|
||||
indexmap = { workspace = true }
|
||||
miette = { workspace = true }
|
||||
|
@ -1,4 +1,4 @@
|
||||
use indexmap::{IndexSet, indexset};
|
||||
use indexmap::{indexset, IndexSet};
|
||||
use nu_protocol::Value;
|
||||
|
||||
pub fn merge_descriptors(values: &[Value]) -> Vec<String> {
|
||||
|
@ -1,11 +1,11 @@
|
||||
use miette::Result;
|
||||
use nu_engine::{eval_block, eval_block_with_early_return, redirect_env};
|
||||
use nu_engine::{eval_block, eval_block_with_early_return};
|
||||
use nu_parser::parse;
|
||||
use nu_protocol::{
|
||||
PipelineData, PositionalArg, ShellError, Span, Type, Value, VarId,
|
||||
cli_error::{report_parse_error, report_shell_error},
|
||||
debugger::WithoutDebug,
|
||||
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
||||
PipelineData, PositionalArg, ShellError, Span, Type, Value, VarId,
|
||||
};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
@ -325,7 +325,19 @@ fn run_hook(
|
||||
}
|
||||
|
||||
// If all went fine, preserve the environment of the called block
|
||||
redirect_env(engine_state, stack, &callee_stack);
|
||||
let caller_env_vars = stack.get_env_var_names(engine_state);
|
||||
|
||||
// remove env vars that are present in the caller but not in the callee
|
||||
// (the callee hid them)
|
||||
for var in caller_env_vars.iter() {
|
||||
if !callee_stack.has_env_var(engine_state, var) {
|
||||
stack.remove_env_var(engine_state, var);
|
||||
}
|
||||
}
|
||||
|
||||
// add new env vars from callee to caller
|
||||
for (var, value) in callee_stack.get_stack_env_vars() {
|
||||
stack.add_env_var(var, value);
|
||||
}
|
||||
Ok(pipeline_data)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use nu_protocol::{PipelineData, ShellError, Signals, Span, Value, ast::CellPath};
|
||||
use nu_protocol::{ast::CellPath, PipelineData, ShellError, Signals, Span, Value};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait CmdArgument {
|
||||
|
@ -3,6 +3,3 @@ pub mod formats;
|
||||
pub mod hook;
|
||||
pub mod input_handler;
|
||||
pub mod util;
|
||||
mod wrap_call;
|
||||
|
||||
pub use wrap_call::*;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use nu_protocol::{
|
||||
Range, ShellError, Span, Value,
|
||||
engine::{EngineState, Stack},
|
||||
Range, ShellError, Span, Value,
|
||||
};
|
||||
use std::ops::Bound;
|
||||
|
||||
|
@ -1,101 +0,0 @@
|
||||
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]
|
||||
authors = ["The Nushell Project Developers"]
|
||||
description = "Nushell's extra commands that are not part of the 1.0 api standard."
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-extra"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-extra"
|
||||
version = "0.105.2"
|
||||
version = "0.104.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -16,13 +16,13 @@ bench = false
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.105.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.105.2", default-features = false }
|
||||
nu-json = { version = "0.105.2", path = "../nu-json" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.105.2" }
|
||||
nu-pretty-hex = { version = "0.105.2", path = "../nu-pretty-hex" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.105.2", default-features = false }
|
||||
nu-utils = { path = "../nu-utils", version = "0.105.2", default-features = false }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.104.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.104.1", default-features = false }
|
||||
nu-json = { version = "0.104.1", path = "../nu-json" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.104.1" }
|
||||
nu-pretty-hex = { version = "0.104.1", path = "../nu-pretty-hex" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.104.1", default-features = false }
|
||||
nu-utils = { path = "../nu-utils", version = "0.104.1", default-features = false }
|
||||
|
||||
# Potential dependencies for extras
|
||||
heck = { workspace = true }
|
||||
@ -37,6 +37,6 @@ itertools = { workspace = true }
|
||||
mime = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.105.2" }
|
||||
nu-command = { path = "../nu-command", version = "0.105.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.105.2" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.104.1" }
|
||||
nu-command = { path = "../nu-command", version = "0.104.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.104.1" }
|
||||
|
@ -16,8 +16,8 @@ mod test_examples {
|
||||
};
|
||||
|
||||
use nu_protocol::{
|
||||
Type,
|
||||
engine::{Command, EngineState, StateWorkingSet},
|
||||
Type,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
|
||||
|
@ -65,7 +65,7 @@ impl Command for BitsAnd {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "Endian must be one of native, little, big".to_string(),
|
||||
span: endian.span,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -113,7 +113,8 @@ impl Command for BitsAnd {
|
||||
])),
|
||||
},
|
||||
Example {
|
||||
description: "Apply bitwise and to binary data of varying lengths with specified endianness",
|
||||
description:
|
||||
"Apply bitwise and to binary data of varying lengths with specified endianness",
|
||||
example: "0x[c0 ff ee] | bits and 0x[ff] --endian big",
|
||||
result: Some(Value::test_binary(vec![0x00, 0x00, 0xee])),
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{NumberBytes, get_number_bytes};
|
||||
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||
use super::{get_number_bytes, NumberBytes};
|
||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -100,7 +100,8 @@ impl Command for BitsNot {
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Apply logical negation to a list of numbers, treat input as 2 bytes number",
|
||||
description:
|
||||
"Apply logical negation to a list of numbers, treat input as 2 bytes number",
|
||||
example: "[4 3 2] | bits not --number-bytes 2",
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
@ -112,7 +113,8 @@ impl Command for BitsNot {
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Apply logical negation to a list of numbers, treat input as signed number",
|
||||
description:
|
||||
"Apply logical negation to a list of numbers, treat input as signed number",
|
||||
example: "[4 3 2] | bits not --signed",
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
|
@ -66,7 +66,7 @@ impl Command for BitsOr {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "Endian must be one of native, little, big".to_string(),
|
||||
span: endian.span,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -106,7 +106,8 @@ impl Command for BitsOr {
|
||||
result: Some(Value::test_binary(vec![0xca, 0xfe])),
|
||||
},
|
||||
Example {
|
||||
description: "Apply bitwise or to binary data of varying lengths with specified endianness",
|
||||
description:
|
||||
"Apply bitwise or to binary data of varying lengths with specified endianness",
|
||||
example: "0x[c0 ff ee] | bits or 0x[ff] --endian big",
|
||||
result: Some(Value::test_binary(vec![0xc0, 0xff, 0xff])),
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{InputNumType, NumberBytes, get_input_num_type, get_number_bytes};
|
||||
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
struct Arguments {
|
||||
@ -222,8 +222,7 @@ fn rotate_bytes_and_bits_left(data: &[u8], byte_shift: usize, bit_shift: usize)
|
||||
debug_assert!(byte_shift < data.len());
|
||||
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");
|
||||
let mut bytes = Vec::with_capacity(data.len());
|
||||
let mut next_index = byte_shift;
|
||||
for _ in 0..data.len() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{InputNumType, NumberBytes, get_input_num_type, get_number_bytes};
|
||||
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
struct Arguments {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{InputNumType, NumberBytes, get_input_num_type, get_number_bytes};
|
||||
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
||||
use itertools::Itertools;
|
||||
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
use std::iter;
|
||||
@ -237,8 +237,7 @@ 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> {
|
||||
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"
|
||||
);
|
||||
data.iter()
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{InputNumType, NumberBytes, get_input_num_type, get_number_bytes};
|
||||
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
struct Arguments {
|
||||
|
@ -66,7 +66,7 @@ impl Command for BitsXor {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "Endian must be one of native, little, big".to_string(),
|
||||
span: endian.span,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -106,7 +106,8 @@ impl Command for BitsXor {
|
||||
result: Some(Value::test_binary(vec![0x70, 0x40])),
|
||||
},
|
||||
Example {
|
||||
description: "Apply bitwise xor to binary data of varying lengths with specified endianness",
|
||||
description:
|
||||
"Apply bitwise xor to binary data of varying lengths with specified endianness",
|
||||
example: "0x[ca fe] | bits xor 0x[aa] --endian big",
|
||||
result: Some(Value::test_binary(vec![0xca, 0x54])),
|
||||
},
|
||||
|
@ -1,4 +1,4 @@
|
||||
use nu_engine::{ClosureEval, ClosureEvalOnce, command_prelude::*};
|
||||
use nu_engine::{command_prelude::*, ClosureEval, ClosureEvalOnce};
|
||||
use nu_protocol::engine::Closure;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{VerticalDirection, vertical_rotate_value};
|
||||
use super::{vertical_rotate_value, VerticalDirection};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{HorizontalDirection, horizontal_rotate_value};
|
||||
use super::{horizontal_rotate_value, HorizontalDirection};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{HorizontalDirection, horizontal_rotate_value};
|
||||
use super::{horizontal_rotate_value, HorizontalDirection};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{VerticalDirection, vertical_rotate_value};
|
||||
use super::{vertical_rotate_value, VerticalDirection};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -44,12 +44,14 @@ impl Command for Rotate {
|
||||
"column0" => Value::test_int(2),
|
||||
"column1" => Value::test_string("b"),
|
||||
}),
|
||||
])),
|
||||
],
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Rotate 2x3 table clockwise",
|
||||
example: "[[a b]; [1 2] [3 4] [5 6]] | rotate",
|
||||
result: Some(Value::test_list(vec![
|
||||
result: Some(Value::test_list(
|
||||
vec![
|
||||
Value::test_record(record! {
|
||||
"column0" => Value::test_int(5),
|
||||
"column1" => Value::test_int(3),
|
||||
@ -62,12 +64,14 @@ impl Command for Rotate {
|
||||
"column2" => Value::test_int(2),
|
||||
"column3" => Value::test_string("b"),
|
||||
}),
|
||||
])),
|
||||
],
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Rotate table clockwise and change columns names",
|
||||
example: "[[a b]; [1 2]] | rotate col_a col_b",
|
||||
result: Some(Value::test_list(vec![
|
||||
result: Some(Value::test_list(
|
||||
vec![
|
||||
Value::test_record(record! {
|
||||
"col_a" => Value::test_int(1),
|
||||
"col_b" => Value::test_string("a"),
|
||||
@ -76,12 +80,14 @@ impl Command for Rotate {
|
||||
"col_a" => Value::test_int(2),
|
||||
"col_b" => Value::test_string("b"),
|
||||
}),
|
||||
])),
|
||||
],
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Rotate table counter clockwise",
|
||||
example: "[[a b]; [1 2]] | rotate --ccw",
|
||||
result: Some(Value::test_list(vec![
|
||||
result: Some(Value::test_list(
|
||||
vec![
|
||||
Value::test_record(record! {
|
||||
"column0" => Value::test_string("b"),
|
||||
"column1" => Value::test_int(2),
|
||||
@ -90,12 +96,14 @@ impl Command for Rotate {
|
||||
"column0" => Value::test_string("a"),
|
||||
"column1" => Value::test_int(1),
|
||||
}),
|
||||
])),
|
||||
],
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Rotate table counter-clockwise",
|
||||
example: "[[a b]; [1 2] [3 4] [5 6]] | rotate --ccw",
|
||||
result: Some(Value::test_list(vec![
|
||||
result: Some(Value::test_list(
|
||||
vec![
|
||||
Value::test_record(record! {
|
||||
"column0" => Value::test_string("b"),
|
||||
"column1" => Value::test_int(2),
|
||||
@ -108,12 +116,14 @@ impl Command for Rotate {
|
||||
"column2" => Value::test_int(3),
|
||||
"column3" => Value::test_int(5),
|
||||
}),
|
||||
])),
|
||||
],
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Rotate table counter-clockwise and change columns names",
|
||||
example: "[[a b]; [1 2]] | rotate --ccw col_a col_b",
|
||||
result: Some(Value::test_list(vec![
|
||||
result: Some(Value::test_list(
|
||||
vec![
|
||||
Value::test_record(record! {
|
||||
"col_a" => Value::test_string("b"),
|
||||
"col_b" => Value::test_int(2),
|
||||
@ -122,7 +132,8 @@ impl Command for Rotate {
|
||||
"col_a" => Value::test_string("a"),
|
||||
"col_b" => Value::test_int(1),
|
||||
}),
|
||||
])),
|
||||
],
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use nu_engine::{ClosureEval, command_prelude::*};
|
||||
use nu_protocol::{PipelineIterator, engine::Closure};
|
||||
use nu_engine::{command_prelude::*, ClosureEval};
|
||||
use nu_protocol::{engine::Closure, PipelineIterator};
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -12,10 +12,7 @@ impl Command for UpdateCells {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("update cells")
|
||||
.input_output_types(vec![
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.input_output_types(vec![(Type::table(), Type::table())])
|
||||
.required(
|
||||
"closure",
|
||||
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
||||
@ -80,15 +77,6 @@ impl Command for UpdateCells {
|
||||
"2021-11-18" => Value::test_string(""),
|
||||
})])),
|
||||
},
|
||||
Example {
|
||||
example: r#"{a: 1, b: 2, c: 3} | update cells { $in + 10 }"#,
|
||||
description: "Update each value in a record.",
|
||||
result: Some(Value::test_record(record! {
|
||||
"a" => Value::test_int(11),
|
||||
"b" => Value::test_int(12),
|
||||
"c" => Value::test_int(13),
|
||||
})),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@ -97,7 +85,7 @@ impl Command for UpdateCells {
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
mut input: PipelineData,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let closure: Closure = call.req(engine_state, stack, 0)?;
|
||||
@ -114,51 +102,14 @@ impl Command for UpdateCells {
|
||||
|
||||
let metadata = input.metadata();
|
||||
|
||||
match input {
|
||||
PipelineData::Value(
|
||||
Value::Record {
|
||||
ref mut val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) => {
|
||||
let val = val.to_mut();
|
||||
update_record(
|
||||
val,
|
||||
&mut ClosureEval::new(engine_state, stack, closure),
|
||||
internal_span,
|
||||
columns.as_ref(),
|
||||
);
|
||||
Ok(input)
|
||||
}
|
||||
_ => Ok(UpdateCellIterator {
|
||||
Ok(UpdateCellIterator {
|
||||
iter: input.into_iter(),
|
||||
closure: ClosureEval::new(engine_state, stack, closure),
|
||||
columns,
|
||||
span: head,
|
||||
}
|
||||
.into_pipeline_data(head, engine_state.signals().clone())
|
||||
.set_metadata(metadata)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_record(
|
||||
record: &mut Record,
|
||||
closure: &mut ClosureEval,
|
||||
span: Span,
|
||||
cols: Option<&HashSet<String>>,
|
||||
) {
|
||||
if let Some(columns) = cols {
|
||||
for (col, val) in record.iter_mut() {
|
||||
if columns.contains(col) {
|
||||
*val = eval_value(closure, span, std::mem::take(val));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (_, val) in record.iter_mut() {
|
||||
*val = eval_value(closure, span, std::mem::take(val))
|
||||
}
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +128,18 @@ impl Iterator for UpdateCellIterator {
|
||||
|
||||
let value = if let Value::Record { val, .. } = &mut value {
|
||||
let val = val.to_mut();
|
||||
update_record(val, &mut self.closure, self.span, self.columns.as_ref());
|
||||
if let Some(columns) = &self.columns {
|
||||
for (col, val) in val.iter_mut() {
|
||||
if columns.contains(col) {
|
||||
*val = eval_value(&mut self.closure, self.span, std::mem::take(val));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (_, val) in val.iter_mut() {
|
||||
*val = eval_value(&mut self.closure, self.span, std::mem::take(val))
|
||||
}
|
||||
}
|
||||
|
||||
value
|
||||
} else {
|
||||
eval_value(&mut self.closure, self.span, value)
|
||||
|
@ -101,7 +101,7 @@ impl Command for ToHtml {
|
||||
.named(
|
||||
"theme",
|
||||
SyntaxShape::String,
|
||||
"the name of the theme to use (github, blulocolight, ...); case-insensitive",
|
||||
"the name of the theme to use (github, blulocolight, ...)",
|
||||
Some('t'),
|
||||
)
|
||||
.switch(
|
||||
@ -163,16 +163,9 @@ fn get_theme_from_asset_file(
|
||||
) -> Result<HashMap<&'static str, String>, ShellError> {
|
||||
let theme_name = match theme {
|
||||
Some(s) => &s.item,
|
||||
None => {
|
||||
return Ok(convert_html_theme_to_hash_map(
|
||||
is_dark,
|
||||
&HtmlTheme::default(),
|
||||
));
|
||||
}
|
||||
None => "default", // There is no theme named "default" so this will be HtmlTheme::default(), which is "nu_default".
|
||||
};
|
||||
|
||||
let theme_span = theme.map(|s| s.span).unwrap_or(Span::unknown());
|
||||
|
||||
// 228 themes come from
|
||||
// https://github.com/mbadolato/iTerm2-Color-Schemes/tree/master/windowsterminal
|
||||
// we should find a hit on any name in there
|
||||
@ -182,17 +175,8 @@ fn get_theme_from_asset_file(
|
||||
let th = asset
|
||||
.themes
|
||||
.into_iter()
|
||||
.find(|n| n.name.eq_ignore_case(theme_name)); // case insensitive search
|
||||
|
||||
let th = match th {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: format!("Unknown HTML theme '{theme_name}'"),
|
||||
span: theme_span,
|
||||
});
|
||||
}
|
||||
};
|
||||
.find(|n| n.name.eq_ignore_case(theme_name)) // case insensitive search
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(convert_html_theme_to_hash_map(is_dark, &th))
|
||||
}
|
||||
@ -273,20 +257,18 @@ fn to_html(
|
||||
None => head,
|
||||
};
|
||||
|
||||
let color_hm = match get_theme_from_asset_file(dark, theme.as_ref()) {
|
||||
let color_hm = get_theme_from_asset_file(dark, theme.as_ref());
|
||||
let color_hm = match color_hm {
|
||||
Ok(c) => c,
|
||||
Err(e) => match e {
|
||||
ShellError::TypeMismatch {
|
||||
err_message,
|
||||
span: _,
|
||||
} => {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message,
|
||||
span: theme_span,
|
||||
});
|
||||
_ => {
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Error finding theme name".into(),
|
||||
msg: "Error finding theme name".into(),
|
||||
span: Some(theme_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
}
|
||||
_ => return Err(e),
|
||||
},
|
||||
};
|
||||
|
||||
// change the color of the page
|
||||
@ -721,87 +703,4 @@ mod tests {
|
||||
|
||||
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::{Gradient, Rgb, build_all_gradient_text, gradient::TargetGround};
|
||||
use nu_ansi_term::{build_all_gradient_text, gradient::TargetGround, Gradient, Rgb};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -71,22 +71,26 @@ impl Command for SubCommand {
|
||||
vec![
|
||||
Example {
|
||||
description: "draw text in a gradient with foreground start and end colors",
|
||||
example: "'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff' --fgend '0xe81cff'",
|
||||
example:
|
||||
"'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff' --fgend '0xe81cff'",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "draw text in a gradient with foreground start and end colors and background start and end colors",
|
||||
example: "'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff' --fgend '0xe81cff' --bgstart '0xe81cff' --bgend '0x40c9ff'",
|
||||
example:
|
||||
"'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff' --fgend '0xe81cff' --bgstart '0xe81cff' --bgend '0x40c9ff'",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "draw text in a gradient by specifying foreground start color - end color is assumed to be black",
|
||||
example: "'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff'",
|
||||
example:
|
||||
"'Hello, Nushell! This is a gradient.' | ansi gradient --fgstart '0x40c9ff'",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "draw text in a gradient by specifying foreground end color - start color is assumed to be black",
|
||||
example: "'Hello, Nushell! This is a gradient.' | ansi gradient --fgend '0xe81cff'",
|
||||
example:
|
||||
"'Hello, Nushell! This is a gradient.' | ansi gradient --fgend '0xe81cff'",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
@ -296,7 +300,7 @@ fn action(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{SubCommand, action};
|
||||
use super::{action, SubCommand};
|
||||
use nu_ansi_term::Rgb;
|
||||
use nu_protocol::{Span, Value};
|
||||
|
||||
@ -310,9 +314,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_fg_gradient() {
|
||||
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_end = Rgb::from_hex_string("0xe81cff".to_string());
|
||||
let actual = action(
|
||||
|
@ -1,9 +1,9 @@
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
use nu_protocol::{Signals, shell_error::io::IoError};
|
||||
use nu_protocol::{shell_error::io::IoError, Signals};
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
struct Arguments {
|
||||
@ -68,33 +68,42 @@ impl Command for FormatBits {
|
||||
Example {
|
||||
description: "convert a binary value into a string, padded to 8 places with 0s",
|
||||
example: "0x[1] | format bits",
|
||||
result: Some(Value::string("00000001", Span::test_data())),
|
||||
result: Some(Value::string("00000001",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert an int into a string, padded to 8 places with 0s",
|
||||
example: "1 | format bits",
|
||||
result: Some(Value::string("00000001", Span::test_data())),
|
||||
result: Some(Value::string("00000001",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a filesize value into a string, padded to 8 places with 0s",
|
||||
example: "1b | format bits",
|
||||
result: Some(Value::string("00000001", Span::test_data())),
|
||||
result: Some(Value::string("00000001",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a duration value into a string, padded to 8 places with 0s",
|
||||
example: "1ns | format bits",
|
||||
result: Some(Value::string("00000001", Span::test_data())),
|
||||
result: Some(Value::string("00000001",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a boolean value into a string, padded to 8 places with 0s",
|
||||
example: "true | format bits",
|
||||
result: Some(Value::string("00000001", Span::test_data())),
|
||||
result: Some(Value::string("00000001",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a string into a raw binary string, padded with 0s to 8 places",
|
||||
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(),
|
||||
)),
|
||||
},
|
||||
@ -134,7 +143,7 @@ fn byte_stream_to_bits(stream: ByteStream, head: Span) -> ByteStream {
|
||||
let mut byte = [0];
|
||||
if reader
|
||||
.read(&mut byte[..])
|
||||
.map_err(|err| IoError::new(err, head, None))?
|
||||
.map_err(|err| IoError::new(err.kind(), head, None))?
|
||||
> 0
|
||||
{
|
||||
// Format the byte as bits
|
||||
@ -161,28 +170,28 @@ fn convert_to_smallest_number_type(num: i64, span: Span) -> Value {
|
||||
let bytes = v.to_ne_bytes();
|
||||
let mut raw_string = "".to_string();
|
||||
for ch in bytes {
|
||||
raw_string.push_str(&format!("{ch:08b} "));
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
} else if let Some(v) = num.to_i16() {
|
||||
let bytes = v.to_ne_bytes();
|
||||
let mut raw_string = "".to_string();
|
||||
for ch in bytes {
|
||||
raw_string.push_str(&format!("{ch:08b} "));
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
} else if let Some(v) = num.to_i32() {
|
||||
let bytes = v.to_ne_bytes();
|
||||
let mut raw_string = "".to_string();
|
||||
for ch in bytes {
|
||||
raw_string.push_str(&format!("{ch:08b} "));
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
} else {
|
||||
let bytes = num.to_ne_bytes();
|
||||
let mut raw_string = "".to_string();
|
||||
for ch in bytes {
|
||||
raw_string.push_str(&format!("{ch:08b} "));
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
}
|
||||
@ -193,7 +202,7 @@ fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
|
||||
Value::Binary { val, .. } => {
|
||||
let mut raw_string = "".to_string();
|
||||
for ch in val {
|
||||
raw_string.push_str(&format!("{ch:08b} "));
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
}
|
||||
@ -204,7 +213,7 @@ fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
|
||||
let raw_bytes = val.as_bytes();
|
||||
let mut raw_string = "".to_string();
|
||||
for ch in raw_bytes {
|
||||
raw_string.push_str(&format!("{ch:08b} "));
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::{Config, ListStream, ast::PathMember, casing::Casing, engine::StateWorkingSet};
|
||||
use nu_protocol::{ast::PathMember, engine::StateWorkingSet, Config, ListStream};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FormatPattern;
|
||||
@ -214,7 +214,7 @@ fn format(
|
||||
wrong_type: val.get_type().to_string(),
|
||||
dst_span: head_span,
|
||||
src_span: val.span(),
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -251,14 +251,14 @@ fn format_record(
|
||||
val: path.to_string(),
|
||||
span: *span,
|
||||
optional: false,
|
||||
casing: Casing::Sensitive,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let expanded_string = data_as_value
|
||||
.follow_cell_path(&path_members)?
|
||||
.to_expanded_string(", ", config);
|
||||
output.push_str(expanded_string.as_str())
|
||||
match data_as_value.clone().follow_cell_path(&path_members, false) {
|
||||
Ok(value_at_column) => {
|
||||
output.push_str(value_at_column.to_expanded_string(", ", config).as_str())
|
||||
}
|
||||
Err(se) => return Err(se),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use nu_cmd_base::input_handler::{CellPathOnlyArgs, operate};
|
||||
use nu_cmd_base::input_handler::{operate, CellPathOnlyArgs};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -16,11 +16,6 @@ impl Command for FormatNumber {
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("format number")
|
||||
.input_output_types(vec![(Type::Number, Type::record())])
|
||||
.switch(
|
||||
"no-prefix",
|
||||
"don't include the binary, hex or octal prefixes",
|
||||
Some('n'),
|
||||
)
|
||||
.category(Category::Conversions)
|
||||
}
|
||||
|
||||
@ -29,36 +24,20 @@ impl Command for FormatNumber {
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
vec![Example {
|
||||
description: "Get a record containing multiple formats for the number 42",
|
||||
example: "42 | format number",
|
||||
result: Some(Value::test_record(record! {
|
||||
"binary" => Value::test_string("0b101010"),
|
||||
"debug" => Value::test_string("42"),
|
||||
"display" => Value::test_string("42"),
|
||||
"binary" => Value::test_string("0b101010"),
|
||||
"lowerexp" => Value::test_string("4.2e1"),
|
||||
"upperexp" => Value::test_string("4.2E1"),
|
||||
"lowerhex" => Value::test_string("0x2a"),
|
||||
"upperhex" => Value::test_string("0x2A"),
|
||||
"octal" => Value::test_string("0o52"),
|
||||
"upperexp" => Value::test_string("4.2E1"),
|
||||
"upperhex" => Value::test_string("0x2A"),
|
||||
})),
|
||||
},
|
||||
Example {
|
||||
description: "Format float without prefixes",
|
||||
example: "3.14 | format number --no-prefix",
|
||||
result: Some(Value::test_record(record! {
|
||||
"debug" => Value::test_string("3.14"),
|
||||
"display" => Value::test_string("3.14"),
|
||||
"binary" => Value::test_string("100000000001001000111101011100001010001111010111000010100011111"),
|
||||
"lowerexp" => Value::test_string("3.14e0"),
|
||||
"upperexp" => Value::test_string("3.14E0"),
|
||||
"lowerhex" => Value::test_string("40091eb851eb851f"),
|
||||
"upperhex" => Value::test_string("40091EB851EB851F"),
|
||||
"octal" => Value::test_string("400110753412172702437"),
|
||||
})),
|
||||
},
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
fn run(
|
||||
@ -80,24 +59,14 @@ pub(crate) fn format_number(
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
let args = CellPathOnlyArgs::from(cell_paths);
|
||||
if call.has_flag(engine_state, stack, "no-prefix")? {
|
||||
operate(
|
||||
action_no_prefix,
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
engine_state.signals(),
|
||||
)
|
||||
} else {
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
}
|
||||
|
||||
fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||
match input {
|
||||
Value::Float { val, .. } => format_f64(*val, false, span),
|
||||
Value::Int { val, .. } => format_i64(*val, false, span),
|
||||
Value::Filesize { val, .. } => format_i64(val.get(), false, span),
|
||||
Value::Float { val, .. } => format_f64(*val, span),
|
||||
Value::Int { val, .. } => format_i64(*val, span),
|
||||
Value::Filesize { val, .. } => format_i64(val.get(), span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::error(
|
||||
@ -112,80 +81,33 @@ fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||
}
|
||||
}
|
||||
|
||||
fn action_no_prefix(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||
match input {
|
||||
Value::Float { val, .. } => format_f64(*val, true, span),
|
||||
Value::Int { val, .. } => format_i64(*val, true, span),
|
||||
Value::Filesize { val, .. } => format_i64(val.get(), true, span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "float, int, or filesize".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
},
|
||||
span,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_i64(num: i64, no_prefix: bool, span: Span) -> Value {
|
||||
fn format_i64(num: i64, span: Span) -> Value {
|
||||
Value::record(
|
||||
record! {
|
||||
"binary" => Value::string(format!("{num:#b}"), span),
|
||||
"debug" => Value::string(format!("{num:#?}"), span),
|
||||
"display" => Value::string(format!("{num}"), span),
|
||||
"binary" => Value::string(
|
||||
if no_prefix { format!("{num:b}") } else { format!("{num:#b}") },
|
||||
span,
|
||||
),
|
||||
"lowerexp" => Value::string(format!("{num:#e}"), span),
|
||||
"lowerhex" => Value::string(format!("{num:#x}"), span),
|
||||
"octal" => Value::string(format!("{num:#o}"), span),
|
||||
"upperexp" => Value::string(format!("{num:#E}"), span),
|
||||
"lowerhex" => Value::string(
|
||||
if no_prefix { format!("{num:x}") } else { format!("{num:#x}") },
|
||||
span,
|
||||
),
|
||||
"upperhex" => Value::string(
|
||||
if no_prefix { format!("{num:X}") } else { format!("{num:#X}") },
|
||||
span,
|
||||
),
|
||||
"octal" => Value::string(
|
||||
if no_prefix { format!("{num:o}") } else { format!("{num:#o}") },
|
||||
span,
|
||||
)
|
||||
"upperhex" => Value::string(format!("{num:#X}"), span),
|
||||
},
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
fn format_f64(num: f64, no_prefix: bool, span: Span) -> Value {
|
||||
fn format_f64(num: f64, span: Span) -> Value {
|
||||
Value::record(
|
||||
record! {
|
||||
"binary" => Value::string(format!("{:b}", num.to_bits()), span),
|
||||
"debug" => Value::string(format!("{num:#?}"), span),
|
||||
"display" => Value::string(format!("{num}"), span),
|
||||
"binary" => Value::string(
|
||||
if no_prefix {
|
||||
format!("{:b}", num.to_bits())
|
||||
} else {
|
||||
format!("{:#b}", num.to_bits())
|
||||
},
|
||||
span,
|
||||
),
|
||||
"lowerexp" => Value::string(format!("{num:#e}"), span),
|
||||
"lowerhex" => Value::string(format!("{:0x}", num.to_bits()), span),
|
||||
"octal" => Value::string(format!("{:0o}", num.to_bits()), span),
|
||||
"upperexp" => Value::string(format!("{num:#E}"), span),
|
||||
"lowerhex" => Value::string(
|
||||
if no_prefix { format!("{:x}", num.to_bits()) } else { format!("{:#x}", num.to_bits()) },
|
||||
span,
|
||||
),
|
||||
"upperhex" => Value::string(
|
||||
if no_prefix { format!("{:X}", num.to_bits()) } else { format!("{:#X}", num.to_bits()) },
|
||||
span,
|
||||
),
|
||||
"octal" => Value::string(
|
||||
if no_prefix { format!("{:o}", num.to_bits()) } else { format!("{:#o}", num.to_bits()) },
|
||||
span,
|
||||
)
|
||||
"upperhex" => Value::string(format!("{:0X}", num.to_bits()), span),
|
||||
},
|
||||
span,
|
||||
)
|
||||
|
@ -14,7 +14,7 @@ pub use snake_case::StrSnakeCase;
|
||||
pub use str_::Str;
|
||||
pub use title_case::StrTitleCase;
|
||||
|
||||
use nu_cmd_base::input_handler::{CmdArgument, operate as general_operate};
|
||||
use nu_cmd_base::input_handler::{operate as general_operate, CmdArgument};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
struct Arguments<F: Fn(&str) -> String + Send + Sync + 'static> {
|
||||
|
@ -3,10 +3,10 @@ authors = ["The Nushell Project Developers"]
|
||||
build = "build.rs"
|
||||
description = "Nushell's core language commands"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-lang"
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-lang"
|
||||
version = "0.105.2"
|
||||
version = "0.104.1"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
@ -15,22 +15,20 @@ bench = false
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.105.2", default-features = false }
|
||||
nu-parser = { path = "../nu-parser", version = "0.105.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.105.2", default-features = false }
|
||||
nu-utils = { path = "../nu-utils", version = "0.105.2", default-features = false }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.105.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.104.1", default-features = false }
|
||||
nu-parser = { path = "../nu-parser", version = "0.104.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.104.1", default-features = false }
|
||||
nu-utils = { path = "../nu-utils", version = "0.104.1", default-features = false }
|
||||
|
||||
itertools = { workspace = true }
|
||||
shadow-rs = { version = "1.2", default-features = false }
|
||||
shadow-rs = { version = "1.1", default-features = false }
|
||||
|
||||
[build-dependencies]
|
||||
shadow-rs = { version = "1.2", default-features = false, features = ["build"] }
|
||||
shadow-rs = { version = "1.1", default-features = false, features = ["build"] }
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = { workspace = true }
|
||||
quickcheck_macros = { workspace = true }
|
||||
miette = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["os"]
|
||||
@ -43,3 +41,8 @@ plugin = [
|
||||
"nu-protocol/plugin",
|
||||
"os",
|
||||
]
|
||||
|
||||
trash-support = []
|
||||
sqlite = []
|
||||
static-link-openssl = []
|
||||
system-clipboard = []
|
||||
|
@ -1,148 +0,0 @@
|
||||
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,9 +1,7 @@
|
||||
mod category;
|
||||
mod deprecated;
|
||||
mod example;
|
||||
mod search_terms;
|
||||
|
||||
pub use category::AttrCategory;
|
||||
pub use deprecated::AttrDeprecated;
|
||||
pub use example::AttrExample;
|
||||
pub use search_terms::AttrSearchTerms;
|
||||
|
@ -34,15 +34,10 @@ impl Command for Break {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
_call: &Call,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
eprintln!(
|
||||
"Tried to execute 'run' for the 'break' command: this code path should never be reached in IR mode"
|
||||
);
|
||||
unreachable!()
|
||||
Err(ShellError::Break { span: call.head })
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use nu_engine::{command_prelude::*, get_eval_block, redirect_env};
|
||||
use nu_protocol::{DataSource, PipelineMetadata, engine::Closure};
|
||||
use nu_protocol::{engine::Closure, DataSource, PipelineMetadata};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Collect;
|
||||
|
@ -41,17 +41,35 @@ impl Command for Const {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
_call: &Call,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
eprintln!(
|
||||
"Tried to execute 'run' for the 'const' command: this code path should never be reached in IR mode"
|
||||
);
|
||||
unreachable!()
|
||||
let call = call.assert_ast_call()?;
|
||||
let var_id = if let Some(id) = call.positional_nth(0).and_then(|pos| pos.as_var()) {
|
||||
id
|
||||
} else {
|
||||
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(
|
||||
|
@ -33,15 +33,10 @@ impl Command for Continue {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
_call: &Call,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
eprintln!(
|
||||
"Tried to execute 'run' for the 'continue' command: this code path should never be reached in IR mode"
|
||||
);
|
||||
unreachable!()
|
||||
Err(ShellError::Continue { span: call.head })
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::{
|
||||
BlockId, ByteStreamSource, Category, PipelineMetadata, Signature,
|
||||
engine::{Closure, StateWorkingSet},
|
||||
BlockId, ByteStreamSource, Category, PipelineMetadata, Signature,
|
||||
};
|
||||
use std::any::type_name;
|
||||
#[derive(Clone)]
|
||||
@ -72,7 +72,8 @@ impl Command for Describe {
|
||||
},
|
||||
Example {
|
||||
description: "Describe the type of a record in a detailed way",
|
||||
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",
|
||||
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",
|
||||
result: Some(Value::test_record(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>"),
|
||||
@ -190,7 +191,7 @@ impl Command for Describe {
|
||||
Example {
|
||||
description: "Describe the type of a stream with detailed information",
|
||||
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!(
|
||||
// "type" => Value::test_string("stream"),
|
||||
// "origin" => Value::test_string("nushell"),
|
||||
@ -208,13 +209,13 @@ impl Command for Describe {
|
||||
Example {
|
||||
description: "Describe a stream of data, collecting it first",
|
||||
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)")),
|
||||
},
|
||||
Example {
|
||||
description: "Describe the input but do not collect streams",
|
||||
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")),
|
||||
},
|
||||
]
|
||||
@ -296,7 +297,7 @@ fn run(
|
||||
} else {
|
||||
let value = stream.into_value();
|
||||
let base_description = value.get_type().to_string();
|
||||
Value::string(format!("{base_description} (stream)"), head)
|
||||
Value::string(format!("{} (stream)", base_description), head)
|
||||
}
|
||||
}
|
||||
PipelineData::Value(value, ..) => {
|
||||
|
@ -2,7 +2,7 @@ use nu_engine::{command_prelude::*, get_eval_block_with_early_return, redirect_e
|
||||
#[cfg(feature = "os")]
|
||||
use nu_protocol::process::{ChildPipe, ChildProcess};
|
||||
use nu_protocol::{
|
||||
ByteStream, ByteStreamSource, OutDest, engine::Closure, shell_error::io::IoError,
|
||||
engine::Closure, shell_error::io::IoError, ByteStream, ByteStreamSource, OutDest,
|
||||
};
|
||||
|
||||
use std::{
|
||||
@ -107,14 +107,14 @@ impl Command for Do {
|
||||
let mut buf = Vec::new();
|
||||
stdout.read_to_end(&mut buf).map_err(|err| {
|
||||
IoError::new_internal(
|
||||
err,
|
||||
err.kind(),
|
||||
"Could not read stdout to end",
|
||||
nu_protocol::location!(),
|
||||
)
|
||||
})?;
|
||||
Ok::<_, ShellError>(buf)
|
||||
})
|
||||
.map_err(|err| IoError::new(err, head, None))
|
||||
.map_err(|err| IoError::new(err.kind(), head, None))
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
@ -126,7 +126,7 @@ impl Command for Do {
|
||||
let mut buf = String::new();
|
||||
stderr
|
||||
.read_to_string(&mut buf)
|
||||
.map_err(|err| IoError::new(err, span, None))?;
|
||||
.map_err(|err| IoError::new(err.kind(), span, None))?;
|
||||
buf
|
||||
}
|
||||
};
|
||||
|
@ -63,7 +63,8 @@ little reason to use this over just writing the values as-is."#
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Returns the piped-in value, by using the special $in variable to obtain it.",
|
||||
description:
|
||||
"Returns the piped-in value, by using the special $in variable to obtain it.",
|
||||
example: "echo $in",
|
||||
result: None,
|
||||
},
|
||||
|
@ -76,7 +76,8 @@ impl Command for ErrorMake {
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Create a custom error for a custom command that shows the span of the argument",
|
||||
description:
|
||||
"Create a custom error for a custom command that shows the span of the argument",
|
||||
example: r#"def foo [x] {
|
||||
error make {
|
||||
msg: "this is fishy"
|
||||
@ -105,7 +106,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
||||
span: throw_span,
|
||||
help: None,
|
||||
inner: vec![],
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -118,7 +119,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
};
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return ShellError::GenericError {
|
||||
@ -127,7 +128,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -145,7 +146,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
};
|
||||
}
|
||||
}
|
||||
// correct return: no label
|
||||
None => {
|
||||
@ -155,7 +156,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
||||
span: throw_span,
|
||||
help,
|
||||
inner: vec![],
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -179,7 +180,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
||||
span: Some(label_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
};
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return ShellError::GenericError {
|
||||
@ -188,7 +189,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
||||
span: Some(label_span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -201,7 +202,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
||||
span: Some(value.span()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
};
|
||||
}
|
||||
}
|
||||
// correct return: label, no span
|
||||
None => {
|
||||
@ -211,7 +212,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
||||
span: throw_span,
|
||||
help,
|
||||
inner: vec![],
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -229,7 +230,7 @@ fn make_other_error(value: &Value, throw_span: Option<Span>) -> ShellError {
|
||||
error: "invalid error format.".into(),
|
||||
msg: "`$.label.start` should be smaller than `$.label.end`".into(),
|
||||
span: Some(label_span),
|
||||
help: Some(format!("{span_start} > {span_end}")),
|
||||
help: Some(format!("{} > {}", span_start, span_end)),
|
||||
inner: vec![],
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::engine::CommandType;
|
||||
use nu_engine::{command_prelude::*, get_eval_block, get_eval_expression};
|
||||
use nu_protocol::{engine::CommandType, Signals};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct For;
|
||||
@ -43,17 +43,83 @@ impl Command for For {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
_call: &Call,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
eprintln!(
|
||||
"Tried to execute 'run' for the 'for' command: this code path should never be reached in IR mode"
|
||||
);
|
||||
unreachable!()
|
||||
let call = call.assert_ast_call()?;
|
||||
let head = call.head;
|
||||
let var_id = call
|
||||
.positional_nth(0)
|
||||
.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> {
|
||||
|
@ -1,4 +1,6 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_engine::{
|
||||
command_prelude::*, get_eval_block, get_eval_expression, get_eval_expression_with_input,
|
||||
};
|
||||
use nu_protocol::{
|
||||
engine::{CommandType, StateWorkingSet},
|
||||
eval_const::{eval_const_subexpression, eval_constant, eval_constant_with_input},
|
||||
@ -58,6 +60,8 @@ impl Command for If {
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
let call = call.assert_ast_call()?;
|
||||
let cond = call.positional_nth(0).expect("checked through parser");
|
||||
let then_block = call
|
||||
@ -93,17 +97,43 @@ impl Command for If {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
eprintln!(
|
||||
"Tried to execute 'run' for the 'if' command: this code path should never be reached in IR mode"
|
||||
);
|
||||
unreachable!()
|
||||
let call = call.assert_ast_call()?;
|
||||
let cond = call.positional_nth(0).expect("checked through parser");
|
||||
let then_block = call
|
||||
.positional_nth(1)
|
||||
.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> {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::{ByteStreamSource, OutDest, engine::StateWorkingSet};
|
||||
use nu_protocol::{engine::StateWorkingSet, ByteStreamSource, OutDest};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Ignore;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_engine::{command_prelude::*, get_eval_block};
|
||||
use nu_protocol::engine::CommandType;
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -41,17 +41,47 @@ impl Command for Let {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
eprintln!(
|
||||
"Tried to execute 'run' for the 'let' command: this code path should never be reached in IR mode"
|
||||
);
|
||||
unreachable!()
|
||||
let call = call.assert_ast_call()?;
|
||||
let var_id = call
|
||||
.positional_nth(0)
|
||||
.expect("checked through parser")
|
||||
.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> {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_engine::{command_prelude::*, get_eval_block};
|
||||
use nu_protocol::engine::CommandType;
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -32,17 +32,37 @@ impl Command for Loop {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
_call: &Call,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
eprintln!(
|
||||
"Tried to execute 'run' for the 'loop' command: this code path should never be reached in IR mode"
|
||||
);
|
||||
unreachable!()
|
||||
let call = call.assert_ast_call()?;
|
||||
let head = call.head;
|
||||
let block_id = call
|
||||
.positional_nth(0)
|
||||
.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> {
|
||||
|
@ -1,5 +1,7 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::engine::CommandType;
|
||||
use nu_engine::{
|
||||
command_prelude::*, get_eval_block, get_eval_expression, get_eval_expression_with_input,
|
||||
};
|
||||
use nu_protocol::engine::{CommandType, Matcher};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Match;
|
||||
@ -36,31 +38,62 @@ impl Command for Match {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
eprintln!(
|
||||
"Tried to execute 'run' for the 'match' command: this code path should never be reached in IR mode"
|
||||
);
|
||||
unreachable!()
|
||||
let call = call.assert_ast_call()?;
|
||||
let value: Value = call.req(engine_state, stack, 0)?;
|
||||
let matches = call
|
||||
.positional_nth(1)
|
||||
.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> {
|
||||
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 {
|
||||
description: "Match on a value in range",
|
||||
example: "match 3 { 1..10 => 'yes!' }",
|
||||
|
@ -69,5 +69,5 @@ pub use return_::Return;
|
||||
pub use scope::*;
|
||||
pub use try_::Try;
|
||||
pub use use_::Use;
|
||||
pub use version::{VERSION_NU_FEATURES, Version};
|
||||
pub use version::Version;
|
||||
pub use while_::While;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_engine::{command_prelude::*, get_eval_block};
|
||||
use nu_protocol::engine::CommandType;
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -41,17 +41,47 @@ impl Command for Mut {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
eprintln!(
|
||||
"Tried to execute 'run' for the 'mut' command: this code path should never be reached in IR mode"
|
||||
);
|
||||
unreachable!()
|
||||
let call = call.assert_ast_call()?;
|
||||
let var_id = call
|
||||
.positional_nth(0)
|
||||
.expect("checked through parser")
|
||||
.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> {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user