mirror of
https://github.com/nushell/nushell.git
synced 2025-07-01 07:00:37 +02:00
Compare commits
110 Commits
Author | SHA1 | Date | |
---|---|---|---|
2590fcbe5c | |||
09691ff866 | |||
16db368232 | |||
df87d90b8c | |||
f2f01b8a4d | |||
6c0190cd38 | |||
b26246bf12 | |||
36a4effbb2 | |||
9fca417f8c | |||
d09e1148b2 | |||
493bc2b1c9 | |||
74b812228c | |||
649b3804c1 | |||
df6a53f52e | |||
c4af5df828 | |||
f94a3e15f5 | |||
75782f0f50 | |||
2b06ce27d3 | |||
72c241348b | |||
ab2d2db987 | |||
07e05ef183 | |||
a986de8ad0 | |||
22cfe4391e | |||
97d17311f4 | |||
0f6fd30619 | |||
e1ebd461d2 | |||
f000d5d0a1 | |||
574c5961c8 | |||
69708f7244 | |||
62c5df5fc6 | |||
92c855a412 | |||
d395816929 | |||
5e34ef6dff | |||
d567c58cc1 | |||
4e0d7bc77c | |||
32581497ef | |||
d6df367c6b | |||
4e6327de1d | |||
b3d8666db0 | |||
1de7c3d033 | |||
962b258cc6 | |||
59697cab63 | |||
349af05da8 | |||
b3b3cf0689 | |||
5d59234f8d | |||
4f7b423f36 | |||
f7043bf690 | |||
1297499d7a | |||
bd0baa961c | |||
4ee536f044 | |||
8581bec891 | |||
8bcbc8eeb3 | |||
c164ef5489 | |||
cc3653cfd9 | |||
7fc65067cf | |||
f9ae882012 | |||
1d80a68f4c | |||
fda69354db | |||
cc5c4d38bb | |||
0fa0c25fb3 | |||
55eafadf02 | |||
51c74eebd0 | |||
ae9f4135c0 | |||
4e2d3ceaaf | |||
c9c6bd4836 | |||
d90420ac4c | |||
260ff99710 | |||
08014c6a98 | |||
66cedf0b3a | |||
707a4ebc15 | |||
d95375d494 | |||
1c1c58e802 | |||
7fe05b8296 | |||
17ef531905 | |||
b8e2bdd6b1 | |||
88817a8f10 | |||
3e8ce43dcb | |||
9d8845d7ad | |||
52578ba483 | |||
991a4801b1 | |||
02b2c55146 | |||
0abe753003 | |||
487fafbca3 | |||
188a352c6f | |||
e11b400a75 | |||
6db5692be4 | |||
ead4029d49 | |||
9bd408449e | |||
2b7390c2a1 | |||
ab961a78cb | |||
65c639cf13 | |||
0cf5dc11e3 | |||
b873fa7a5f | |||
ee563ecf4e | |||
183b35d683 | |||
463dd48180 | |||
1bd3fdd912 | |||
de71cbdd43 | |||
c9b87c4c03 | |||
38848082ae | |||
b6728efcd4 | |||
cd814851da | |||
6646daab45 | |||
ba483155d7 | |||
63abe1cb3e | |||
28db8022fe | |||
7dcc08985c | |||
55acdaaf8c | |||
575c07c9c4 | |||
325f45fa66 |
12
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
12
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -4,14 +4,14 @@ body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the Bug
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: To Reproduce
|
||||
label: How to reproduce
|
||||
description: Steps to reproduce the behavior
|
||||
placeholder: |
|
||||
1.
|
||||
@ -38,11 +38,11 @@ body:
|
||||
id: config
|
||||
attributes:
|
||||
label: Configuration
|
||||
description: "Please run `> version | pivot` and paste the output to show OS, features, etc"
|
||||
description: "Please run `> version | pivot key value | to md` and paste the output to show OS, features, etc"
|
||||
placeholder: |
|
||||
> version | pivot
|
||||
> version | pivot key value | to md
|
||||
╭───┬────────────────────┬───────────────────────────────────────────────────────────────────────╮
|
||||
│ # │ Column0 │ Column1 │
|
||||
│ # │ key │ value │
|
||||
├───┼────────────────────┼───────────────────────────────────────────────────────────────────────┤
|
||||
│ 0 │ version │ 0.24.1 │
|
||||
│ 1 │ build_os │ macos-x86_64 │
|
||||
@ -59,7 +59,7 @@ body:
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
validations:
|
||||
required: false
|
||||
|
4
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
4
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@ -4,7 +4,7 @@ body:
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Related Problem
|
||||
label: Related problem
|
||||
description: Is your feature request related to a problem? Please describe.
|
||||
placeholder: |
|
||||
A clear and concise description of what the problem is.
|
||||
@ -28,7 +28,7 @@ body:
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context and Details
|
||||
label: Additional context and details
|
||||
description: Add any other context or screenshots about the feature request here.
|
||||
validations:
|
||||
required: false
|
||||
|
118
.github/workflows/docker-publish.yml
vendored
118
.github/workflows/docker-publish.yml
vendored
@ -1,118 +0,0 @@
|
||||
name: Publish consumable Docker images
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ['v?[0-9]+.[0-9]+.[0-9]+*']
|
||||
|
||||
jobs:
|
||||
compile:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- x86_64-unknown-linux-musl
|
||||
- x86_64-unknown-linux-gnu
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install rust-embedded/cross
|
||||
env: { VERSION: v0.1.16 }
|
||||
run: >-
|
||||
wget -nv https://github.com/rust-embedded/cross/releases/download/${VERSION}/cross-${VERSION}-x86_64-unknown-linux-gnu.tar.gz
|
||||
-O- | sudo tar xz -C /usr/local/bin/
|
||||
- name: compile for specific target
|
||||
env: { arch: '${{ matrix.arch }}' }
|
||||
run: |
|
||||
cross build --target ${{ matrix.arch }} --release
|
||||
# leave only the executable file
|
||||
rm -frd target/${{ matrix.arch }}/release/{*/*,*.d,*.rlib,.fingerprint}
|
||||
find . -empty -delete
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ${{ matrix.arch }}
|
||||
path: target/${{ matrix.arch }}/release
|
||||
|
||||
docker:
|
||||
name: Build and publish docker images
|
||||
needs: compile
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_REGISTRY: quay.io/nushell
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_REGISTRY }}
|
||||
DOCKER_USER: ${{ secrets.DOCKER_USER }}
|
||||
strategy:
|
||||
matrix:
|
||||
tag:
|
||||
- alpine
|
||||
- slim
|
||||
- debian
|
||||
- glibc-busybox
|
||||
- musl-busybox
|
||||
- musl-distroless
|
||||
- glibc-distroless
|
||||
- glibc
|
||||
- musl
|
||||
include:
|
||||
- { tag: alpine, base-image: alpine, arch: x86_64-unknown-linux-musl, plugin: true, use-patch: false}
|
||||
- { tag: slim, base-image: 'debian:stable-slim', arch: x86_64-unknown-linux-gnu, plugin: true, use-patch: false}
|
||||
- { tag: debian, base-image: debian, arch: x86_64-unknown-linux-gnu, plugin: true, use-patch: false}
|
||||
- { tag: glibc-busybox, base-image: 'busybox:glibc', arch: x86_64-unknown-linux-gnu, plugin: false, use-patch: true }
|
||||
- { tag: musl-busybox, base-image: 'busybox:musl', arch: x86_64-unknown-linux-musl, plugin: false, use-patch: false}
|
||||
- { tag: musl-distroless, base-image: 'gcr.io/distroless/static', arch: x86_64-unknown-linux-musl, plugin: false, use-patch: false}
|
||||
- { tag: glibc-distroless, base-image: 'gcr.io/distroless/cc', arch: x86_64-unknown-linux-gnu, plugin: false, use-patch: true }
|
||||
- { tag: glibc, base-image: scratch, arch: x86_64-unknown-linux-gnu, plugin: false, use-patch: false}
|
||||
- { tag: musl, base-image: scratch, arch: x86_64-unknown-linux-musl, plugin: false, use-patch: false}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/download-artifact@master
|
||||
with: { name: '${{ matrix.arch }}', path: target/release }
|
||||
- name: Build and publish exact version
|
||||
run: |-
|
||||
export DOCKER_TAG=${GITHUB_REF##*/}-${{ matrix.tag }}
|
||||
export NU_BINS=target/release/$( [ ${{ matrix.plugin }} = true ] && echo nu* || echo nu )
|
||||
export PATCH=$([ ${{ matrix.use-patch }} = true ] && echo .${{ matrix.tag }} || echo '')
|
||||
chmod +x $NU_BINS
|
||||
|
||||
echo ${DOCKER_PASSWORD} | docker login ${DOCKER_REGISTRY} -u ${DOCKER_USER} --password-stdin
|
||||
docker-compose --file docker/docker-compose.package.yml build
|
||||
docker-compose --file docker/docker-compose.package.yml push # exact version
|
||||
env:
|
||||
BASE_IMAGE: ${{ matrix.base-image }}
|
||||
|
||||
#region semantics tagging
|
||||
- name: Retag and push with suffixed version
|
||||
run: |-
|
||||
VERSION=${GITHUB_REF##*/}
|
||||
|
||||
latest_version=${VERSION%%%.*}-${{ matrix.tag }}
|
||||
latest_feature=${VERSION%%.*}-${{ matrix.tag }}
|
||||
latest_patch=${VERSION%.*}-${{ matrix.tag }}
|
||||
exact_version=${VERSION}-${{ matrix.tag }}
|
||||
|
||||
tags=( ${latest_version} ${latest_feature} ${latest_patch} ${exact_version} )
|
||||
|
||||
for tag in ${tags[@]}; do
|
||||
docker tag ${DOCKER_REGISTRY}/nu:${VERSION}-${{ matrix.tag }} ${DOCKER_REGISTRY}/nu:${tag}
|
||||
docker push ${DOCKER_REGISTRY}/nu:${tag}
|
||||
done
|
||||
|
||||
# latest version
|
||||
docker tag ${DOCKER_REGISTRY}/nu:${VERSION}-${{ matrix.tag }} ${DOCKER_REGISTRY}/nu:${{ matrix.tag }}
|
||||
docker push ${DOCKER_REGISTRY}/nu:${{ matrix.tag }}
|
||||
|
||||
- name: Retag and push debian as latest
|
||||
if: matrix.tag == 'debian'
|
||||
run: |-
|
||||
VERSION=${GITHUB_REF##*/}
|
||||
|
||||
# ${latest features} ${latest patch} ${exact version}
|
||||
tags=( ${VERSION%%.*} ${VERSION%.*} ${VERSION} )
|
||||
|
||||
for tag in ${tags[@]}; do
|
||||
docker tag ${DOCKER_REGISTRY}/nu:${VERSION}-${{ matrix.tag }} ${DOCKER_REGISTRY}/nu:${tag}
|
||||
docker push ${DOCKER_REGISTRY}/nu:${tag}
|
||||
done
|
||||
|
||||
# latest version
|
||||
docker tag ${DOCKER_REGISTRY}/nu:${{ matrix.tag }} ${DOCKER_REGISTRY}/nu:latest
|
||||
docker push ${DOCKER_REGISTRY}/nu:latest
|
||||
#endregion semantics tagging
|
271
.github/workflows/release.yml
vendored
271
.github/workflows/release.yml
vendored
@ -1,6 +1,7 @@
|
||||
name: Create Release Draft
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags: ['[0-9]+.[0-9]+.[0-9]+*']
|
||||
|
||||
@ -28,6 +29,96 @@ jobs:
|
||||
command: build
|
||||
args: --release --all --features=extra
|
||||
|
||||
- name: Compress binaries (nu)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu
|
||||
|
||||
- name: Compress binaries (nu_plugin_inc)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_inc
|
||||
|
||||
- name: Compress binaries (nu_plugin_match)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_match
|
||||
|
||||
- name: Compress binaries (nu_plugin_textview)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_textview
|
||||
|
||||
- name: Compress binaries (nu_plugin_binaryview)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_binaryview
|
||||
|
||||
- name: Compress binaries (nu_plugin_chart_bar)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_chart_bar
|
||||
|
||||
- name: Compress binaries (nu_plugin_chart_line)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_chart_line
|
||||
|
||||
- name: Compress binaries (nu_plugin_from_bson)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_from_bson
|
||||
|
||||
- name: Compress binaries (nu_plugin_from_sqlite)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_from_sqlite
|
||||
|
||||
- name: Compress binaries (nu_plugin_from_mp4)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_from_mp4
|
||||
|
||||
- name: Compress binaries (nu_plugin_query_json)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_query_json
|
||||
|
||||
- name: Compress binaries (nu_plugin_s3)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_s3
|
||||
|
||||
- name: Compress binaries (nu_plugin_selector)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_selector
|
||||
|
||||
- name: Compress binaries (nu_plugin_start)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_start
|
||||
|
||||
- name: Compress binaries (nu_plugin_to_bson)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_to_bson
|
||||
|
||||
- name: Compress binaries (nu_plugin_to_sqlite)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_to_sqlite
|
||||
|
||||
- name: Compress binaries (nu_plugin_tree)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_tree
|
||||
|
||||
- name: Compress binaries (nu_plugin_xpath)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_xpath
|
||||
|
||||
- name: Create output directory
|
||||
run: mkdir output
|
||||
|
||||
@ -70,6 +161,96 @@ jobs:
|
||||
command: build
|
||||
args: --release --all --features=extra
|
||||
|
||||
- name: Compress binaries (nu)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu
|
||||
|
||||
- name: Compress binaries (nu_plugin_inc)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_inc
|
||||
|
||||
- name: Compress binaries (nu_plugin_match)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_match
|
||||
|
||||
- name: Compress binaries (nu_plugin_textview)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_textview
|
||||
|
||||
- name: Compress binaries (nu_plugin_binaryview)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_binaryview
|
||||
|
||||
- name: Compress binaries (nu_plugin_chart_bar)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_chart_bar
|
||||
|
||||
- name: Compress binaries (nu_plugin_chart_line)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_chart_line
|
||||
|
||||
- name: Compress binaries (nu_plugin_from_bson)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_from_bson
|
||||
|
||||
- name: Compress binaries (nu_plugin_from_sqlite)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_from_sqlite
|
||||
|
||||
- name: Compress binaries (nu_plugin_from_mp4)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_from_mp4
|
||||
|
||||
- name: Compress binaries (nu_plugin_query_json)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_query_json
|
||||
|
||||
- name: Compress binaries (nu_plugin_s3)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_s3
|
||||
|
||||
- name: Compress binaries (nu_plugin_selector)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_selector
|
||||
|
||||
- name: Compress binaries (nu_plugin_start)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_start
|
||||
|
||||
- name: Compress binaries (nu_plugin_to_bson)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_to_bson
|
||||
|
||||
- name: Compress binaries (nu_plugin_to_sqlite)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_to_sqlite
|
||||
|
||||
- name: Compress binaries (nu_plugin_tree)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_tree
|
||||
|
||||
- name: Compress binaries (nu_plugin_xpath)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_xpath
|
||||
|
||||
- name: Create output directory
|
||||
run: mkdir output
|
||||
|
||||
@ -114,6 +295,96 @@ jobs:
|
||||
command: build
|
||||
args: --release --all --features=extra
|
||||
|
||||
- name: Compress binaries (nu.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_inc.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_inc.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_match.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_match.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_textview.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_textview.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_binaryview.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_binaryview.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_chart_bar.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_chart_bar.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_chart_line.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_chart_line.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_from_bson.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_from_bson.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_from_sqlite.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_from_sqlite.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_from_mp4.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_from_mp4.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_query_json.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_query_json.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_s3.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_s3.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_selector.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_selector.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_start.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_start.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_to_bson.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_to_bson.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_to_sqlite.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_to_sqlite.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_tree.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_tree.exe
|
||||
|
||||
- name: Compress binaries (nu_plugin_xpath.exe)
|
||||
uses: svenstaro/upx-action@v2
|
||||
with:
|
||||
file: target/release/nu_plugin_xpath.exe
|
||||
|
||||
- name: Create output directory
|
||||
run: mkdir output
|
||||
|
||||
|
11
.github/workflows/stale.yml
vendored
11
.github/workflows/stale.yml
vendored
@ -19,11 +19,10 @@ jobs:
|
||||
operations-per-run: 520
|
||||
enable-statistics: true
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: 'This issue is being marked stale because it has been open for 90 days without activity. If you feel that this is in error, please comment below and we will keep it marked as active.'
|
||||
stale-pr-message: 'This PR is being marked stale because it has been open for 45 days without activity. If this PR is still active, please comment below and we will keep it marked as active.'
|
||||
close-issue-message: 'This issue has been marked stale for more than 10 days without activity. Closing this issue, but if you find that the issue is still valid, please reopen.'
|
||||
close-pr-message: 'This PR has been marked stale for more than 10 days without activity. Closing this PR, but if you are still working on it, please reopen.'
|
||||
close-issue-message: 'This issue has been marked stale for more than 100000 days without activity. Closing this issue, but if you find that the issue is still valid, please reopen.'
|
||||
close-pr-message: 'This PR has been marked stale for more than 100 days without activity. Closing this PR, but if you are still working on it, please reopen.'
|
||||
days-before-issue-stale: 90
|
||||
days-before-pr-stale: 45
|
||||
days-before-issue-close: 10
|
||||
days-before-pr-close: 10
|
||||
days-before-issue-close: 100000
|
||||
days-before-pr-close: 100
|
||||
exempt-issue-labels: 'exempt,keep'
|
||||
|
2
.gitpod.Dockerfile
vendored
2
.gitpod.Dockerfile
vendored
@ -2,7 +2,7 @@ FROM gitpod/workspace-full
|
||||
|
||||
# Gitpod will not rebuild Nushell's dev image unless *some* change is made to this Dockerfile.
|
||||
# To force a rebuild, simply increase this counter:
|
||||
ENV TRIGGER_REBUILD 1
|
||||
ENV TRIGGER_REBUILD 2
|
||||
|
||||
USER gitpod
|
||||
|
||||
|
2967
Cargo.lock
generated
2967
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
102
Cargo.toml
102
Cargo.toml
@ -10,7 +10,7 @@ license = "MIT"
|
||||
name = "nu"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
version = "0.35.0"
|
||||
version = "0.40.0"
|
||||
|
||||
[workspace]
|
||||
members = ["crates/*/"]
|
||||
@ -18,38 +18,34 @@ members = ["crates/*/"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-cli = { version = "0.35.0", path="./crates/nu-cli", default-features=false }
|
||||
nu-command = { version = "0.35.0", path="./crates/nu-command" }
|
||||
nu-completion = { version = "0.35.0", path="./crates/nu-completion" }
|
||||
nu-data = { version = "0.35.0", path="./crates/nu-data" }
|
||||
nu-engine = { version = "0.35.0", path="./crates/nu-engine" }
|
||||
nu-errors = { version = "0.35.0", path="./crates/nu-errors" }
|
||||
nu-parser = { version = "0.35.0", path="./crates/nu-parser" }
|
||||
nu-path = { version = "0.35.0", path="./crates/nu-path" }
|
||||
nu-plugin = { version = "0.35.0", path="./crates/nu-plugin" }
|
||||
nu-protocol = { version = "0.35.0", path="./crates/nu-protocol" }
|
||||
nu-source = { version = "0.35.0", path="./crates/nu-source" }
|
||||
nu-value-ext = { version = "0.35.0", path="./crates/nu-value-ext" }
|
||||
nu-cli = { version = "0.40.0", path="./crates/nu-cli", default-features=false }
|
||||
nu-command = { version = "0.40.0", path="./crates/nu-command" }
|
||||
nu-completion = { version = "0.40.0", path="./crates/nu-completion" }
|
||||
nu-data = { version = "0.40.0", path="./crates/nu-data" }
|
||||
nu-engine = { version = "0.40.0", path="./crates/nu-engine" }
|
||||
nu-errors = { version = "0.40.0", path="./crates/nu-errors" }
|
||||
nu-parser = { version = "0.40.0", path="./crates/nu-parser" }
|
||||
nu-path = { version = "0.40.0", path="./crates/nu-path" }
|
||||
nu-plugin = { version = "0.40.0", path="./crates/nu-plugin" }
|
||||
nu-protocol = { version = "0.40.0", path="./crates/nu-protocol" }
|
||||
nu-source = { version = "0.40.0", path="./crates/nu-source" }
|
||||
nu-value-ext = { version = "0.40.0", path="./crates/nu-value-ext" }
|
||||
|
||||
nu_plugin_binaryview = { version = "0.35.0", path="./crates/nu_plugin_binaryview", optional=true }
|
||||
nu_plugin_chart = { version = "0.35.0", path="./crates/nu_plugin_chart", optional=true }
|
||||
nu_plugin_fetch = { version = "0.35.0", path="./crates/nu_plugin_fetch", optional=true }
|
||||
nu_plugin_from_bson = { version = "0.35.0", path="./crates/nu_plugin_from_bson", optional=true }
|
||||
nu_plugin_from_sqlite = { version = "0.35.0", path="./crates/nu_plugin_from_sqlite", optional=true }
|
||||
nu_plugin_inc = { version = "0.35.0", path="./crates/nu_plugin_inc", optional=true }
|
||||
nu_plugin_match = { version = "0.35.0", path="./crates/nu_plugin_match", optional=true }
|
||||
nu_plugin_post = { version = "0.35.0", path="./crates/nu_plugin_post", optional=true }
|
||||
nu_plugin_ps = { version = "0.35.0", path="./crates/nu_plugin_ps", optional=true }
|
||||
nu_plugin_query_json = { version = "0.35.0", path="./crates/nu_plugin_query_json", optional=true }
|
||||
nu_plugin_s3 = { version = "0.35.0", path="./crates/nu_plugin_s3", optional=true }
|
||||
nu_plugin_selector = { version = "0.35.0", path="./crates/nu_plugin_selector", optional=true }
|
||||
nu_plugin_start = { version = "0.35.0", path="./crates/nu_plugin_start", optional=true }
|
||||
nu_plugin_sys = { version = "0.35.0", path="./crates/nu_plugin_sys", optional=true }
|
||||
nu_plugin_textview = { version = "0.35.0", path="./crates/nu_plugin_textview", optional=true }
|
||||
nu_plugin_to_bson = { version = "0.35.0", path="./crates/nu_plugin_to_bson", optional=true }
|
||||
nu_plugin_to_sqlite = { version = "0.35.0", path="./crates/nu_plugin_to_sqlite", optional=true }
|
||||
nu_plugin_tree = { version = "0.35.0", path="./crates/nu_plugin_tree", optional=true }
|
||||
nu_plugin_xpath = { version = "0.35.0", path="./crates/nu_plugin_xpath", optional=true }
|
||||
nu_plugin_binaryview = { version = "0.40.0", path="./crates/nu_plugin_binaryview", optional=true }
|
||||
nu_plugin_chart = { version = "0.40.0", path="./crates/nu_plugin_chart", optional=true }
|
||||
nu_plugin_from_bson = { version = "0.40.0", path="./crates/nu_plugin_from_bson", optional=true }
|
||||
nu_plugin_from_sqlite = { version = "0.40.0", path="./crates/nu_plugin_from_sqlite", optional=true }
|
||||
nu_plugin_inc = { version = "0.40.0", path="./crates/nu_plugin_inc", optional=true }
|
||||
nu_plugin_match = { version = "0.40.0", path="./crates/nu_plugin_match", optional=true }
|
||||
nu_plugin_query_json = { version = "0.40.0", path="./crates/nu_plugin_query_json", optional=true }
|
||||
nu_plugin_s3 = { version = "0.40.0", path="./crates/nu_plugin_s3", optional=true }
|
||||
nu_plugin_selector = { version = "0.40.0", path="./crates/nu_plugin_selector", optional=true }
|
||||
nu_plugin_start = { version = "0.40.0", path="./crates/nu_plugin_start", optional=true }
|
||||
nu_plugin_textview = { version = "0.40.0", path="./crates/nu_plugin_textview", optional=true }
|
||||
nu_plugin_to_bson = { version = "0.40.0", path="./crates/nu_plugin_to_bson", optional=true }
|
||||
nu_plugin_to_sqlite = { version = "0.40.0", path="./crates/nu_plugin_to_sqlite", optional=true }
|
||||
nu_plugin_tree = { version = "0.40.0", path="./crates/nu_plugin_tree", optional=true }
|
||||
nu_plugin_xpath = { version = "0.40.0", path="./crates/nu_plugin_xpath", optional=true }
|
||||
|
||||
# Required to bootstrap the main binary
|
||||
ctrlc = { version="3.1.7", optional=true }
|
||||
@ -57,8 +53,7 @@ futures = { version="0.3.12", features=["compat", "io-compat"] }
|
||||
itertools = "0.10.0"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { version = "0.35.0", path="./crates/nu-test-support" }
|
||||
dunce = "1.0.1"
|
||||
nu-test-support = { version = "0.40.0", path="./crates/nu-test-support" }
|
||||
serial_test = "0.5.1"
|
||||
hamcrest2 = "0.3.0"
|
||||
rstest = "0.10.0"
|
||||
@ -66,6 +61,8 @@ rstest = "0.10.0"
|
||||
[build-dependencies]
|
||||
|
||||
[features]
|
||||
fetch-support = ["nu-command/fetch", "nu-command/post"]
|
||||
sys-support = ["nu-command/sys", "nu-command/ps"]
|
||||
ctrlc-support = ["nu-cli/ctrlc", "nu-command/ctrlc"]
|
||||
rustyline-support = ["nu-cli/rustyline-support", "nu-command/rustyline-support"]
|
||||
term-support = ["nu-command/term"]
|
||||
@ -74,15 +71,13 @@ which-support = ["nu-command/which", "nu-engine/which"]
|
||||
|
||||
default = [
|
||||
"nu-cli/shadow-rs",
|
||||
"sys",
|
||||
"ps",
|
||||
"sys-support",
|
||||
"ctrlc-support",
|
||||
"which-support",
|
||||
"term-support",
|
||||
"rustyline-support",
|
||||
"match",
|
||||
"post",
|
||||
"fetch",
|
||||
"fetch-support",
|
||||
"zip-support",
|
||||
"dataframe",
|
||||
]
|
||||
@ -110,12 +105,8 @@ extra = [
|
||||
wasi = ["inc", "match", "match", "tree", "rustyline-support"]
|
||||
|
||||
# Stable (Default)
|
||||
fetch = ["nu_plugin_fetch"]
|
||||
inc = ["nu_plugin_inc"]
|
||||
match = ["nu_plugin_match"]
|
||||
post = ["nu_plugin_post"]
|
||||
ps = ["nu_plugin_ps"]
|
||||
sys = ["nu_plugin_sys"]
|
||||
textview = ["nu_plugin_textview"]
|
||||
|
||||
# Extra
|
||||
@ -136,9 +127,6 @@ tree = ["nu_plugin_tree"]
|
||||
xpath = ["nu_plugin_xpath"]
|
||||
zip-support = ["nu-command/zip"]
|
||||
|
||||
#This is disabled in extra for now
|
||||
table-pager = ["nu-command/table-pager"]
|
||||
|
||||
#dataframe feature for nushell
|
||||
dataframe = [
|
||||
"nu-engine/dataframe",
|
||||
@ -146,10 +134,12 @@ dataframe = [
|
||||
"nu-command/dataframe",
|
||||
"nu-value-ext/dataframe",
|
||||
"nu-data/dataframe",
|
||||
"nu_plugin_post/dataframe",
|
||||
"nu_plugin_to_bson/dataframe",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
opt-level = "s" # Optimize for size.
|
||||
|
||||
# Core plugins that ship with `cargo install nu` by default
|
||||
# Currently, Cargo limits us to installing only one binary
|
||||
# unless we use [[bin]], so we use this as a workaround
|
||||
@ -163,31 +153,11 @@ name = "nu_plugin_core_inc"
|
||||
path = "src/plugins/nu_plugin_core_inc.rs"
|
||||
required-features = ["inc"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_ps"
|
||||
path = "src/plugins/nu_plugin_core_ps.rs"
|
||||
required-features = ["ps"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_sys"
|
||||
path = "src/plugins/nu_plugin_core_sys.rs"
|
||||
required-features = ["sys"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_fetch"
|
||||
path = "src/plugins/nu_plugin_core_fetch.rs"
|
||||
required-features = ["fetch"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_match"
|
||||
path = "src/plugins/nu_plugin_core_match.rs"
|
||||
required-features = ["match"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_post"
|
||||
path = "src/plugins/nu_plugin_core_post.rs"
|
||||
required-features = ["post"]
|
||||
|
||||
# Extra plugins
|
||||
|
||||
[[bin]]
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 - 2021 Yehuda Katz, Jonathan Turner
|
||||
Copyright (c) 2019 - 2021 Nushell Project
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
59
README.md
59
README.md
@ -68,7 +68,7 @@ cargo install nu
|
||||
To install Nu via the [Windows Package Manager](https://aka.ms/winget-cli):
|
||||
|
||||
```shell
|
||||
winget install nu
|
||||
winget install nushell
|
||||
```
|
||||
|
||||
You can also build Nu yourself with all the bells and whistles (be sure to have installed the [dependencies](https://www.nushell.sh/book/installation.html#dependencies) for your platform), once you have checked out this repo with git:
|
||||
@ -76,53 +76,6 @@ You can also build Nu yourself with all the bells and whistles (be sure to have
|
||||
```shell
|
||||
cargo build --workspace --features=extra
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
#### Quickstart
|
||||
|
||||
Want to try Nu right away? Execute the following to get started.
|
||||
|
||||
```shell
|
||||
docker run -it quay.io/nushell/nu:latest
|
||||
```
|
||||
|
||||
#### Guide
|
||||
|
||||
If you want to pull a pre-built container, you can browse tags for the [nushell organization](https://quay.io/organization/nushell)
|
||||
on Quay.io. Pulling a container would come down to:
|
||||
|
||||
```shell
|
||||
docker pull quay.io/nushell/nu
|
||||
docker pull quay.io/nushell/nu-base
|
||||
```
|
||||
|
||||
Both "nu-base" and "nu" provide the nu binary, however, nu-base also includes the source code at `/code`
|
||||
in the container and all dependencies.
|
||||
|
||||
Optionally, you can also build the containers locally using the [dockerfiles provided](docker):
|
||||
To build the base image:
|
||||
|
||||
```shell
|
||||
docker build -f docker/Dockerfile.nu-base -t nushell/nu-base .
|
||||
```
|
||||
|
||||
And then to build the smaller container (using a Multistage build):
|
||||
|
||||
```shell
|
||||
docker build -f docker/Dockerfile -t nushell/nu .
|
||||
```
|
||||
|
||||
Either way, you can run either container as follows:
|
||||
|
||||
```shell
|
||||
docker run -it nushell/nu-base
|
||||
docker run -it nushell/nu
|
||||
/> exit
|
||||
```
|
||||
|
||||
The second container is a bit smaller if the size is important to you.
|
||||
|
||||
### Packaging status
|
||||
|
||||
[](https://repology.org/project/nushell/versions)
|
||||
@ -310,9 +263,15 @@ Nu is in heavy development and will naturally change as it matures and people us
|
||||
| Completions | | | X | | | Completions for filepaths |
|
||||
| Type-checking | | | X | | | Commands check basic types, but input/output isn't checked |
|
||||
|
||||
## Current Roadmap
|
||||
## Officially Supported By
|
||||
|
||||
We've added a `Roadmap Board` to help collaboratively capture the direction we're going for the current release and capture some important issues we'd like to see in Nushell. You can find the Roadmap [here](https://github.com/nushell/nushell/projects/2).
|
||||
Please submit an issue or PR to be added to this list.
|
||||
|
||||
### Integrations
|
||||
- [zoxide](https://github.com/ajeetdsouza/zoxide)
|
||||
- [starship](https://github.com/starship/starship)
|
||||
### Mentions
|
||||
- [The Python Launcher for Unix](https://github.com/brettcannon/python-launcher#how-do-i-get-a-table-of-python-executables-in-nushell)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -9,7 +9,7 @@ description = "Library for ANSI terminal colors and styles (bold, underline)"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-ansi-term"
|
||||
version = "0.35.0"
|
||||
version = "0.40.0"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
@ -21,7 +21,6 @@ derive_serde_style = ["serde"]
|
||||
[dependencies]
|
||||
overload = "0.1.1"
|
||||
serde = { version="1.0.90", features=["derive"], optional=true }
|
||||
itertools = "0.10.0"
|
||||
|
||||
# [dependencies.serde]
|
||||
# version = "1.0.90"
|
||||
|
@ -93,7 +93,7 @@ pub static RESET: &str = "\x1B[0m";
|
||||
|
||||
impl Color {
|
||||
fn write_foreground_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
|
||||
match *self {
|
||||
match self {
|
||||
Color::Black => write!(f, "30"),
|
||||
Color::Red => write!(f, "31"),
|
||||
Color::Green => write!(f, "32"),
|
||||
@ -103,8 +103,8 @@ impl Color {
|
||||
Color::Magenta => write!(f, "35"),
|
||||
Color::Cyan => write!(f, "36"),
|
||||
Color::White => write!(f, "37"),
|
||||
Color::Fixed(num) => write!(f, "38;5;{}", &num),
|
||||
Color::Rgb(r, g, b) => write!(f, "38;2;{};{};{}", &r, &g, &b),
|
||||
Color::Fixed(num) => write!(f, "38;5;{}", num),
|
||||
Color::Rgb(r, g, b) => write!(f, "38;2;{};{};{}", r, g, b),
|
||||
Color::DarkGray => write!(f, "90"),
|
||||
Color::LightRed => write!(f, "91"),
|
||||
Color::LightGreen => write!(f, "92"),
|
||||
@ -118,7 +118,7 @@ impl Color {
|
||||
}
|
||||
|
||||
fn write_background_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
|
||||
match *self {
|
||||
match self {
|
||||
Color::Black => write!(f, "40"),
|
||||
Color::Red => write!(f, "41"),
|
||||
Color::Green => write!(f, "42"),
|
||||
@ -128,8 +128,8 @@ impl Color {
|
||||
Color::Magenta => write!(f, "45"),
|
||||
Color::Cyan => write!(f, "46"),
|
||||
Color::White => write!(f, "47"),
|
||||
Color::Fixed(num) => write!(f, "48;5;{}", &num),
|
||||
Color::Rgb(r, g, b) => write!(f, "48;2;{};{};{}", &r, &g, &b),
|
||||
Color::Fixed(num) => write!(f, "48;5;{}", num),
|
||||
Color::Rgb(r, g, b) => write!(f, "48;2;{};{};{}", r, g, b),
|
||||
Color::DarkGray => write!(f, "100"),
|
||||
Color::LightRed => write!(f, "101"),
|
||||
Color::LightGreen => write!(f, "102"),
|
||||
|
@ -297,7 +297,7 @@ mod tests {
|
||||
fn no_control_codes_for_plain() {
|
||||
let one = Style::default().paint("one");
|
||||
let two = Style::default().paint("two");
|
||||
let output = format!("{}", AnsiStrings(&[one, two]));
|
||||
assert_eq!(&*output, "onetwo");
|
||||
let output = AnsiStrings(&[one, two]).to_string();
|
||||
assert_eq!(output, "onetwo");
|
||||
}
|
||||
}
|
||||
|
@ -602,18 +602,18 @@ mod serde_json_tests {
|
||||
|
||||
#[test]
|
||||
fn color_deserialization() {
|
||||
let colors = &[
|
||||
let colors = [
|
||||
Color::Red,
|
||||
Color::Blue,
|
||||
Color::Rgb(123, 123, 123),
|
||||
Color::Fixed(255),
|
||||
];
|
||||
|
||||
for color in colors.iter() {
|
||||
for color in colors {
|
||||
let serialized = serde_json::to_string(&color).unwrap();
|
||||
let deserialized: Color = serde_json::from_str(&serialized).unwrap();
|
||||
|
||||
assert_eq!(color, &deserialized);
|
||||
assert_eq!(color, deserialized);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,6 @@ mod test {
|
||||
assert_eq!(unstyled_len(&a), 18);
|
||||
|
||||
let l2 = [Black.paint("st"), Red.paint("-second"), White.paint("-t")];
|
||||
assert_eq!(sub_string(3, 11, &a).as_slice(), &l2);
|
||||
assert_eq!(sub_string(3, 11, &a), l2);
|
||||
}
|
||||
}
|
||||
|
@ -4,29 +4,30 @@ description = "CLI for nushell"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.35.0"
|
||||
version = "0.40.0"
|
||||
build = "build.rs"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
nu-completion = { version = "0.35.0", path="../nu-completion" }
|
||||
nu-command = { version = "0.35.0", path="../nu-command" }
|
||||
nu-data = { version = "0.35.0", path="../nu-data" }
|
||||
nu-engine = { version = "0.35.0", path="../nu-engine" }
|
||||
nu-errors = { version = "0.35.0", path="../nu-errors" }
|
||||
nu-parser = { version = "0.35.0", path="../nu-parser" }
|
||||
nu-protocol = { version = "0.35.0", path="../nu-protocol" }
|
||||
nu-source = { version = "0.35.0", path="../nu-source" }
|
||||
nu-stream = { version = "0.35.0", path="../nu-stream" }
|
||||
nu-ansi-term = { version = "0.35.0", path="../nu-ansi-term" }
|
||||
nu-completion = { version = "0.40.0", path="../nu-completion" }
|
||||
nu-command = { version = "0.40.0", path="../nu-command" }
|
||||
nu-data = { version = "0.40.0", path="../nu-data" }
|
||||
nu-engine = { version = "0.40.0", path="../nu-engine" }
|
||||
nu-errors = { version = "0.40.0", path="../nu-errors" }
|
||||
nu-parser = { version = "0.40.0", path="../nu-parser" }
|
||||
nu-protocol = { version = "0.40.0", path="../nu-protocol" }
|
||||
nu-source = { version = "0.40.0", path="../nu-source" }
|
||||
nu-stream = { version = "0.40.0", path="../nu-stream" }
|
||||
nu-ansi-term = { version = "0.40.0", path="../nu-ansi-term" }
|
||||
nu-path = { version = "0.40.0", path="../nu-path" }
|
||||
|
||||
indexmap ="1.6.1"
|
||||
log = "0.4.14"
|
||||
pretty_env_logger = "0.4.0"
|
||||
strip-ansi-escapes = "0.1.0"
|
||||
rustyline = { version="8.1.0", optional=true }
|
||||
rustyline = { version="9.0.0", optional=true }
|
||||
ctrlc = { version="3.1.7", optional=true }
|
||||
shadow-rs = { version="0.6", default-features=false, optional=true }
|
||||
serde = { version="1.0.123", features=["derive"] }
|
||||
|
@ -508,14 +508,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn can_use_loglevels() -> Result<(), ShellError> {
|
||||
for level in &["error", "warn", "info", "debug", "trace"] {
|
||||
for level in ["error", "warn", "info", "debug", "trace"] {
|
||||
let ui = cli_app();
|
||||
let args = format!("nu --loglevel={}", *level);
|
||||
let args = format!("nu --loglevel={}", level);
|
||||
ui.parse(&args)?;
|
||||
assert_eq!(ui.loglevel().unwrap(), Ok(level.to_string()));
|
||||
|
||||
let ui = cli_app();
|
||||
let args = format!("nu -l {}", *level);
|
||||
let args = format!("nu -l {}", level);
|
||||
ui.parse(&args)?;
|
||||
assert_eq!(ui.loglevel().unwrap(), Ok(level.to_string()));
|
||||
}
|
||||
@ -541,11 +541,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn can_use_test_binaries() -> Result<(), ShellError> {
|
||||
for binarie_name in &[
|
||||
for binarie_name in [
|
||||
"echo_env", "cococo", "iecho", "fail", "nonu", "chop", "repeater", "meow",
|
||||
] {
|
||||
let ui = cli_app();
|
||||
let args = format!("nu --testbin={}", *binarie_name);
|
||||
let args = format!("nu --testbin={}", binarie_name);
|
||||
ui.parse(&args)?;
|
||||
assert_eq!(ui.testbin().unwrap(), Ok(binarie_name.to_string()));
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ impl Options {
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &str) -> Option<Value> {
|
||||
self.inner.borrow().get(key).map(Clone::clone)
|
||||
self.inner.borrow().get(key).cloned()
|
||||
}
|
||||
|
||||
pub fn put(&self, key: &str, value: Value) {
|
||||
|
@ -67,48 +67,37 @@ impl OptionsParser for NuParser {
|
||||
}
|
||||
};
|
||||
|
||||
let value =
|
||||
value
|
||||
.map(|v| match k.as_ref() {
|
||||
"testbin" => {
|
||||
if let Ok(name) = v.as_string() {
|
||||
if testbins().iter().any(|n| name == *n) {
|
||||
Some(v)
|
||||
} else {
|
||||
Some(
|
||||
UntaggedValue::Error(
|
||||
ShellError::untagged_runtime_error(
|
||||
format!("{} is not supported.", name),
|
||||
),
|
||||
)
|
||||
.into_value(v.tag),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Some(v)
|
||||
}
|
||||
let value = value.map(|v| match k.as_ref() {
|
||||
"testbin" => {
|
||||
if let Ok(name) = v.as_string() {
|
||||
if testbins().iter().any(|n| name == *n) {
|
||||
v
|
||||
} else {
|
||||
UntaggedValue::Error(ShellError::untagged_runtime_error(
|
||||
format!("{} is not supported.", name),
|
||||
))
|
||||
.into_value(v.tag)
|
||||
}
|
||||
"loglevel" => {
|
||||
if let Ok(name) = v.as_string() {
|
||||
if loglevels().iter().any(|n| name == *n) {
|
||||
Some(v)
|
||||
} else {
|
||||
Some(
|
||||
UntaggedValue::Error(
|
||||
ShellError::untagged_runtime_error(
|
||||
format!("{} is not supported.", name),
|
||||
),
|
||||
)
|
||||
.into_value(v.tag),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Some(v)
|
||||
}
|
||||
} else {
|
||||
v
|
||||
}
|
||||
}
|
||||
"loglevel" => {
|
||||
if let Ok(name) = v.as_string() {
|
||||
if loglevels().iter().any(|n| name == *n) {
|
||||
v
|
||||
} else {
|
||||
UntaggedValue::Error(ShellError::untagged_runtime_error(
|
||||
format!("{} is not supported.", name),
|
||||
))
|
||||
.into_value(v.tag)
|
||||
}
|
||||
_ => Some(v),
|
||||
})
|
||||
.flatten();
|
||||
} else {
|
||||
v
|
||||
}
|
||||
}
|
||||
_ => v,
|
||||
});
|
||||
|
||||
if let Some(value) = value {
|
||||
options.put(k, value);
|
||||
|
@ -24,6 +24,7 @@ use rustyline::{self, error::ReadlineError};
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ParserScope;
|
||||
use nu_path::expand_tilde;
|
||||
use nu_protocol::{hir::ExternalRedirection, ConfigPath, UntaggedValue, Value};
|
||||
|
||||
use log::trace;
|
||||
@ -31,9 +32,12 @@ use std::error::Error;
|
||||
use std::iter::Iterator;
|
||||
use std::path::PathBuf;
|
||||
|
||||
// Name of environment variable where the prompt could be stored
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
const PROMPT_COMMAND: &str = "PROMPT_COMMAND";
|
||||
|
||||
pub fn search_paths() -> Vec<std::path::PathBuf> {
|
||||
use std::env;
|
||||
|
||||
let mut search_paths = Vec::new();
|
||||
|
||||
// Automatically add path `nu` is in as a search path
|
||||
@ -51,7 +55,7 @@ pub fn search_paths() -> Vec<std::path::PathBuf> {
|
||||
{
|
||||
for pipeline in pipelines {
|
||||
if let Ok(plugin_dir) = pipeline.as_string() {
|
||||
search_paths.push(PathBuf::from(plugin_dir));
|
||||
search_paths.push(expand_tilde(plugin_dir));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,6 +87,66 @@ pub fn run_script_file(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
fn default_prompt_string(cwd: &str) -> String {
|
||||
format!(
|
||||
"{}{}{}{}{}{}> ",
|
||||
Color::Green.bold().prefix().to_string(),
|
||||
cwd,
|
||||
nu_ansi_term::ansi::RESET,
|
||||
Color::Cyan.bold().prefix().to_string(),
|
||||
current_branch(),
|
||||
nu_ansi_term::ansi::RESET
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
fn evaluate_prompt_string(prompt_line: &str, context: &EvaluationContext, cwd: &str) -> String {
|
||||
context.scope.enter_scope();
|
||||
let (prompt_block, err) = nu_parser::parse(prompt_line, 0, &context.scope);
|
||||
|
||||
if err.is_some() {
|
||||
context.scope.exit_scope();
|
||||
default_prompt_string(cwd)
|
||||
} else {
|
||||
let run_result = run_block(
|
||||
&prompt_block,
|
||||
context,
|
||||
InputStream::empty(),
|
||||
ExternalRedirection::Stdout,
|
||||
);
|
||||
context.scope.exit_scope();
|
||||
|
||||
match run_result {
|
||||
Ok(result) => match result.collect_string(Tag::unknown()) {
|
||||
Ok(string_result) => {
|
||||
let errors = context.get_errors();
|
||||
maybe_print_errors(context, Text::from(prompt_line));
|
||||
context.clear_errors();
|
||||
|
||||
if !errors.is_empty() {
|
||||
"> ".into()
|
||||
} else {
|
||||
string_result.item
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
context.host().lock().print_err(e, &Text::from(prompt_line));
|
||||
context.clear_errors();
|
||||
|
||||
"> ".into()
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
context.host().lock().print_err(e, &Text::from(prompt_line));
|
||||
context.clear_errors();
|
||||
|
||||
"> ".into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
pub fn cli(
|
||||
context: EvaluationContext,
|
||||
@ -102,7 +166,10 @@ pub fn cli(
|
||||
// Store cmd duration in an env var
|
||||
context.scope.add_env_var(
|
||||
"CMD_DURATION_MS",
|
||||
format!("{}", startup_commands_start_time.elapsed().as_millis()),
|
||||
startup_commands_start_time
|
||||
.elapsed()
|
||||
.as_millis()
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
if options.perf {
|
||||
@ -235,72 +302,17 @@ pub fn cli(
|
||||
|
||||
let cwd = context.shell_manager().path();
|
||||
|
||||
let colored_prompt = {
|
||||
if let Some(prompt) = &prompt {
|
||||
let prompt_line = prompt.as_string()?;
|
||||
|
||||
context.scope.enter_scope();
|
||||
let (prompt_block, err) = nu_parser::parse(&prompt_line, 0, &context.scope);
|
||||
|
||||
if err.is_some() {
|
||||
context.scope.exit_scope();
|
||||
|
||||
format!(
|
||||
"{}{}{}{}{}{}> ",
|
||||
Color::Green.bold().prefix().to_string(),
|
||||
cwd,
|
||||
nu_ansi_term::ansi::RESET,
|
||||
Color::Cyan.bold().prefix().to_string(),
|
||||
current_branch(),
|
||||
nu_ansi_term::ansi::RESET
|
||||
)
|
||||
// Check if the PROMPT_COMMAND env variable is set. This env variable
|
||||
// contains nu code that is used to overwrite the prompt
|
||||
let colored_prompt = match context.scope.get_env(PROMPT_COMMAND) {
|
||||
Some(env_prompt) => evaluate_prompt_string(&env_prompt, &context, &cwd),
|
||||
None => {
|
||||
if let Some(prompt) = &prompt {
|
||||
let prompt_line = prompt.as_string()?;
|
||||
evaluate_prompt_string(&prompt_line, &context, &cwd)
|
||||
} else {
|
||||
let run_result = run_block(
|
||||
&prompt_block,
|
||||
&context,
|
||||
InputStream::empty(),
|
||||
ExternalRedirection::Stdout,
|
||||
);
|
||||
context.scope.exit_scope();
|
||||
|
||||
match run_result {
|
||||
Ok(result) => match result.collect_string(Tag::unknown()) {
|
||||
Ok(string_result) => {
|
||||
let errors = context.get_errors();
|
||||
maybe_print_errors(&context, Text::from(prompt_line));
|
||||
context.clear_errors();
|
||||
|
||||
if !errors.is_empty() {
|
||||
"> ".to_string()
|
||||
} else {
|
||||
string_result.item
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
context.host().lock().print_err(e, &Text::from(prompt_line));
|
||||
context.clear_errors();
|
||||
|
||||
"> ".to_string()
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
context.host().lock().print_err(e, &Text::from(prompt_line));
|
||||
context.clear_errors();
|
||||
|
||||
"> ".to_string()
|
||||
}
|
||||
}
|
||||
default_prompt_string(&cwd)
|
||||
}
|
||||
} else {
|
||||
format!(
|
||||
"{}{}{}{}{}{}> ",
|
||||
Color::Green.bold().prefix().to_string(),
|
||||
cwd,
|
||||
nu_ansi_term::ansi::RESET,
|
||||
Color::Cyan.bold().prefix().to_string(),
|
||||
current_branch(),
|
||||
nu_ansi_term::ansi::RESET
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
@ -345,7 +357,7 @@ pub fn cli(
|
||||
// Store cmd duration in an env var
|
||||
context.scope.add_env_var(
|
||||
"CMD_DURATION_MS",
|
||||
format!("{}", cmd_start_time.elapsed().as_millis()),
|
||||
cmd_start_time.elapsed().as_millis().to_string(),
|
||||
);
|
||||
|
||||
match line {
|
||||
@ -360,7 +372,7 @@ pub fn cli(
|
||||
LineResult::ClearHistory => {
|
||||
if options.save_history {
|
||||
rl.clear_history();
|
||||
let _ = rl.append_history(&history_path);
|
||||
std::fs::remove_file(&history_path)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,8 +401,7 @@ pub fn cli(
|
||||
.lock()
|
||||
.global_config
|
||||
.as_ref()
|
||||
.map(|cfg| cfg.var("ctrlc_exit"))
|
||||
.flatten()
|
||||
.and_then(|cfg| cfg.var("ctrlc_exit"))
|
||||
.map(|ctrl_c| ctrl_c.is_true())
|
||||
.unwrap_or(false); // default behavior is to allow CTRL-C spamming similar to other shells
|
||||
|
||||
@ -432,6 +443,7 @@ pub fn cli(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
pub fn load_local_cfg_if_present(context: &EvaluationContext) {
|
||||
trace!("Loading local cfg if present");
|
||||
match config::loadable_cfg_exists_in_dir(PathBuf::from(context.shell_manager().path())) {
|
||||
|
@ -461,7 +461,7 @@ pub(crate) fn load_keybindings(
|
||||
if let Ok(contents) = contents {
|
||||
let keybindings: Keybindings = serde_yaml::from_str(&contents)?;
|
||||
// eprintln!("{:#?}", keybindings);
|
||||
for keybinding in keybindings.into_iter() {
|
||||
for keybinding in keybindings {
|
||||
let (k, b) = convert_keybinding(keybinding);
|
||||
// eprintln!("{:?} {:?}", k, b);
|
||||
|
||||
|
@ -76,6 +76,8 @@ pub fn default_rustyline_editor_configuration() -> Editor<Helper> {
|
||||
let config = Config::builder()
|
||||
.check_cursor_position(true)
|
||||
.color_mode(ColorMode::Forced)
|
||||
.history_ignore_dups(false)
|
||||
.max_history_size(10_000)
|
||||
.build();
|
||||
let mut rl: Editor<_> = Editor::with_config(config);
|
||||
|
||||
|
@ -5,52 +5,48 @@ description = "CLI for nushell"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-command"
|
||||
version = "0.35.0"
|
||||
version = "0.40.0"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
nu-data = { version = "0.35.0", path="../nu-data" }
|
||||
nu-engine = { version = "0.35.0", path="../nu-engine" }
|
||||
nu-errors = { version = "0.35.0", path="../nu-errors" }
|
||||
nu-json = { version = "0.35.0", path="../nu-json" }
|
||||
nu-path = { version = "0.35.0", path="../nu-path" }
|
||||
nu-parser = { version = "0.35.0", path="../nu-parser" }
|
||||
nu-plugin = { version = "0.35.0", path="../nu-plugin" }
|
||||
nu-protocol = { version = "0.35.0", path="../nu-protocol" }
|
||||
nu-source = { version = "0.35.0", path="../nu-source" }
|
||||
nu-stream = { version = "0.35.0", path="../nu-stream" }
|
||||
nu-table = { version = "0.35.0", path="../nu-table" }
|
||||
nu-test-support = { version = "0.35.0", path="../nu-test-support" }
|
||||
nu-value-ext = { version = "0.35.0", path="../nu-value-ext" }
|
||||
nu-ansi-term = { version = "0.35.0", path="../nu-ansi-term" }
|
||||
nu-pretty-hex = { version = "0.35.0", path="../nu-pretty-hex" }
|
||||
nu-data = { version = "0.40.0", path="../nu-data" }
|
||||
nu-engine = { version = "0.40.0", path="../nu-engine" }
|
||||
nu-errors = { version = "0.40.0", path="../nu-errors" }
|
||||
nu-json = { version = "0.40.0", path="../nu-json" }
|
||||
nu-path = { version = "0.40.0", path="../nu-path" }
|
||||
nu-parser = { version = "0.40.0", path="../nu-parser" }
|
||||
nu-plugin = { version = "0.40.0", path="../nu-plugin" }
|
||||
nu-protocol = { version = "0.40.0", path="../nu-protocol" }
|
||||
nu-serde = { version = "0.40.0", path="../nu-serde" }
|
||||
nu-source = { version = "0.40.0", path="../nu-source" }
|
||||
nu-stream = { version = "0.40.0", path="../nu-stream" }
|
||||
nu-table = { version = "0.40.0", path="../nu-table" }
|
||||
nu-test-support = { version = "0.40.0", path="../nu-test-support" }
|
||||
nu-value-ext = { version = "0.40.0", path="../nu-value-ext" }
|
||||
nu-ansi-term = { version = "0.40.0", path="../nu-ansi-term" }
|
||||
nu-pretty-hex = { version = "0.40.0", path="../nu-pretty-hex" }
|
||||
|
||||
url = "2.2.1"
|
||||
mime = "0.3.16"
|
||||
Inflector = "0.11"
|
||||
arboard = { version="1.1.0", optional=true }
|
||||
base64 = "0.13.0"
|
||||
bigdecimal = { version="0.2.0", features=["serde"] }
|
||||
byte-unit = "4.0.9"
|
||||
bytes = "1.0.1"
|
||||
bigdecimal = { package = "bigdecimal-rs", version = "0.2.1", features = ["serde"] }
|
||||
calamine = "0.18.0"
|
||||
chrono = { version="0.4.19", features=["serde"] }
|
||||
chrono-tz = "0.5.3"
|
||||
codespan-reporting = "0.11.0"
|
||||
crossterm = { version="0.19.0", optional=true }
|
||||
csv = "1.1.3"
|
||||
ctrlc = { version="3.1.7", optional=true }
|
||||
derive-new = "0.5.8"
|
||||
directories-next = "2.0.0"
|
||||
dirs-next = "2.0.0"
|
||||
dtparse = "1.2.0"
|
||||
dunce = "1.0.1"
|
||||
eml-parser = "0.1.0"
|
||||
encoding_rs = "0.8.28"
|
||||
filesize = "0.2.0"
|
||||
fs_extra = "1.2.0"
|
||||
futures = { version="0.3.12", features=["compat", "io-compat"] }
|
||||
getset = "0.1.1"
|
||||
glob = "0.3.0"
|
||||
htmlescape = "0.3.1"
|
||||
ical = "0.7.0"
|
||||
@ -60,48 +56,42 @@ lazy_static = "1.*"
|
||||
log = "0.4.14"
|
||||
md-5 = "0.9.1"
|
||||
meval = "0.2.0"
|
||||
minus = { version="3.4.0", optional=true, features=["async_std_lib", "search"] }
|
||||
num-bigint = { version="0.3.1", features=["serde"] }
|
||||
num-format = { version="0.4.0", features=["with-num-bigint"] }
|
||||
num-traits = "0.2.14"
|
||||
parking_lot = "0.11.1"
|
||||
pin-utils = "0.1.0"
|
||||
query_interface = "0.3.5"
|
||||
quick-xml = "0.22"
|
||||
rand = "0.8"
|
||||
rayon = "1.5.0"
|
||||
regex = "1.4.3"
|
||||
reqwest = {version = "0.11", optional = true }
|
||||
roxmltree = "0.14.0"
|
||||
rust-embed = "5.9.0"
|
||||
rustyline = { version="8.1.0", optional=true }
|
||||
rustyline = { version="9.0.0", optional=true }
|
||||
serde = { version="1.0.123", features=["derive"] }
|
||||
serde_bytes = "0.11.5"
|
||||
serde_ini = "0.2.0"
|
||||
serde_json = "1.0.61"
|
||||
serde_urlencoded = "0.7.0"
|
||||
serde_yaml = "0.8.16"
|
||||
sha2 = "0.9.3"
|
||||
strip-ansi-escapes = "0.1.0"
|
||||
sxd-document = "0.3.2"
|
||||
sxd-xpath = "0.4.2"
|
||||
tempfile = "3.2.0"
|
||||
sysinfo = { version = "0.20.2", optional = true }
|
||||
thiserror = "1.0.26"
|
||||
term = { version="0.7.0", optional=true }
|
||||
term_size = "0.3.2"
|
||||
termcolor = "1.1.2"
|
||||
titlecase = "1.1.0"
|
||||
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
||||
toml = "0.5.8"
|
||||
trash = { version="1.3.0", optional=true }
|
||||
unicode-segmentation = "1.8"
|
||||
url = "2.2.0"
|
||||
uuid_crate = { package="uuid", version="0.8.2", features=["v4"], optional=true }
|
||||
which = { version="4.1.0", optional=true }
|
||||
zip = { version="0.5.9", optional=true }
|
||||
digest = "0.9.0"
|
||||
|
||||
[dependencies.polars]
|
||||
version = "0.14.8"
|
||||
version = "0.17.0"
|
||||
optional = true
|
||||
features = ["parquet", "json", "random", "pivot", "strings", "is_in"]
|
||||
features = ["parquet", "json", "random", "pivot", "strings", "is_in", "temporal", "cum_agg", "rolling_window"]
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
umask = "1.0.0"
|
||||
@ -110,13 +100,8 @@ users = "0.11.0"
|
||||
# TODO this will be possible with new dependency resolver
|
||||
# (currently on nightly behind -Zfeatures=itarget):
|
||||
# https://github.com/rust-lang/cargo/issues/7914
|
||||
#[target.'cfg(not(windows))'.dependencies]
|
||||
#num-format = {version = "0.4", features = ["with-system-locale"]}
|
||||
|
||||
[dependencies.rusqlite]
|
||||
features = ["bundled", "blob"]
|
||||
optional = true
|
||||
version = "0.25.3"
|
||||
# [target.'cfg(not(windows))'.dependencies]
|
||||
# num-format = { version = "0.4", features = ["with-system-locale"] }
|
||||
|
||||
[build-dependencies]
|
||||
shadow-rs = "0.6"
|
||||
@ -131,5 +116,8 @@ clipboard-cli = ["arboard"]
|
||||
rustyline-support = ["rustyline"]
|
||||
stable = []
|
||||
trash-support = ["trash"]
|
||||
table-pager = ["minus", "crossterm"]
|
||||
dataframe = ["nu-protocol/dataframe", "polars"]
|
||||
fetch = ["reqwest", "tokio"]
|
||||
post = ["reqwest", "tokio"]
|
||||
sys = ["sysinfo"]
|
||||
ps = ["sysinfo"]
|
||||
|
@ -4,7 +4,10 @@ use nu_engine::{MaybeTextCodec, StringOrBinary};
|
||||
use nu_test_support::NATIVE_PATH_ENV_VAR;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
#[allow(unused)]
|
||||
use std::env;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::mpsc;
|
||||
use std::{borrow::Cow, io::BufReader};
|
||||
@ -17,6 +20,9 @@ use nu_protocol::hir::{ExternalCommand, ExternalRedirection};
|
||||
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
|
||||
use nu_source::Tag;
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
use which::which_in;
|
||||
|
||||
pub(crate) fn run_external_command(
|
||||
command: ExternalCommand,
|
||||
context: &mut EvaluationContext,
|
||||
@ -104,7 +110,7 @@ fn run_with_stdin(
|
||||
let process_args = command_args
|
||||
.iter()
|
||||
.map(|(arg, _is_literal)| {
|
||||
let arg = nu_path::expand_tilde_string(Cow::Borrowed(arg));
|
||||
let arg = nu_path::expand_tilde(arg).to_string_lossy().to_string();
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
@ -141,6 +147,79 @@ fn run_with_stdin(
|
||||
)
|
||||
}
|
||||
|
||||
/// Spawn a direct exe
|
||||
#[allow(unused)]
|
||||
fn spawn_exe(full_path: PathBuf, args: &[String]) -> Command {
|
||||
let mut process = Command::new(full_path);
|
||||
for arg in args {
|
||||
process.arg(&arg);
|
||||
}
|
||||
process
|
||||
}
|
||||
|
||||
/// Spawn a cmd command with `cmd /c args...`
|
||||
fn spawn_cmd_command(command: &ExternalCommand, args: &[String]) -> Command {
|
||||
let mut process = Command::new("cmd");
|
||||
process.arg("/c");
|
||||
process.arg(&command.name);
|
||||
for arg in args {
|
||||
// Clean the args before we use them:
|
||||
// https://stackoverflow.com/questions/1200235/how-to-pass-a-quoted-pipe-character-to-cmd-exe
|
||||
// cmd.exe needs to have a caret to escape a pipe
|
||||
let arg = arg.replace("|", "^|");
|
||||
process.arg(&arg);
|
||||
}
|
||||
process
|
||||
}
|
||||
|
||||
/// Spawn a sh command with `sh -c args...`
|
||||
fn spawn_sh_command(command: &ExternalCommand, args: &[String]) -> Command {
|
||||
let cmd_with_args = vec![command.name.clone(), args.join(" ")].join(" ");
|
||||
let mut process = Command::new("sh");
|
||||
process.arg("-c").arg(cmd_with_args);
|
||||
process
|
||||
}
|
||||
|
||||
/// a function to spawn any external command
|
||||
#[allow(unused)] // for minimal builds cwd is unused
|
||||
fn spawn_any(command: &ExternalCommand, args: &[String], cwd: &str) -> Command {
|
||||
// resolve the executable name if it is spawnable directly
|
||||
#[cfg(feature = "which")]
|
||||
// TODO add more available paths to `env::var_os("PATH")`?
|
||||
if let Result::Ok(full_path) = which_in(&command.name, env::var_os("PATH"), cwd) {
|
||||
if let Some(extension) = full_path.extension() {
|
||||
#[cfg(windows)]
|
||||
if extension.eq_ignore_ascii_case("exe") {
|
||||
// if exe spawn it directly
|
||||
return spawn_exe(full_path, args);
|
||||
} else {
|
||||
// TODO implement special care for various executable types such as .bat, .ps1, .cmd, etc
|
||||
// https://github.com/mklement0/Native/blob/e0e0b8785cad39a73053e35084d1f60d87fbac58/Native.psm1#L749
|
||||
// otherwise shell out to cmd
|
||||
return spawn_cmd_command(command, args);
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
if !["sh", "bash"]
|
||||
.iter()
|
||||
.any(|ext| extension.eq_ignore_ascii_case(ext))
|
||||
{
|
||||
// if exe spawn it directly
|
||||
return spawn_exe(full_path, args);
|
||||
} else {
|
||||
// otherwise shell out to sh
|
||||
return spawn_sh_command(command, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
// in all the other cases shell out
|
||||
if cfg!(windows) {
|
||||
spawn_cmd_command(command, args)
|
||||
} else {
|
||||
// TODO what happens if that os doesn't support spawning sh?
|
||||
spawn_sh_command(command, args)
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn(
|
||||
command: &ExternalCommand,
|
||||
path: &str,
|
||||
@ -151,31 +230,7 @@ fn spawn(
|
||||
) -> Result<InputStream, ShellError> {
|
||||
let command = command.clone();
|
||||
|
||||
let mut process = {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let mut process = Command::new("cmd");
|
||||
process.arg("/c");
|
||||
process.arg(&command.name);
|
||||
for arg in args {
|
||||
// Clean the args before we use them:
|
||||
// https://stackoverflow.com/questions/1200235/how-to-pass-a-quoted-pipe-character-to-cmd-exe
|
||||
// cmd.exe needs to have a caret to escape a pipe
|
||||
let arg = arg.replace("|", "^|");
|
||||
process.arg(&arg);
|
||||
}
|
||||
process
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let cmd_with_args = vec![command.name.clone(), args.join(" ")].join(" ");
|
||||
let mut process = Command::new("sh");
|
||||
process.arg("-c").arg(cmd_with_args);
|
||||
process
|
||||
}
|
||||
};
|
||||
|
||||
let mut process = spawn_any(&command, args, path);
|
||||
process.current_dir(path);
|
||||
trace!(target: "nu::run::external", "cwd = {:?}", &path);
|
||||
|
||||
@ -454,7 +509,7 @@ fn spawn(
|
||||
Ok(stream.into_input_stream())
|
||||
}
|
||||
Err(e) => Err(ShellError::labeled_error(
|
||||
format!("{}", e),
|
||||
e.to_string(),
|
||||
"failed to spawn",
|
||||
&command.name_tag,
|
||||
)),
|
||||
|
@ -22,6 +22,7 @@ impl WholeStreamCommand for Histogram {
|
||||
None,
|
||||
)
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column name to give the histogram's frequency column",
|
||||
)
|
||||
|
@ -38,7 +38,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
},
|
||||
Example {
|
||||
description: "Set coloring options",
|
||||
example: "config set color_config [[header_align header_bold]; [left $true]]",
|
||||
example: "config set color_config [[header_align header_color]; [left white_bold]]",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
|
@ -13,6 +13,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into binary").rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column paths to convert to binary (for table input)",
|
||||
)
|
||||
|
118
crates/nu-command/src/commands/conversions/into/column_path.rs
Normal file
118
crates/nu-command/src/commands/conversions/into/column_path.rs
Normal file
@ -0,0 +1,118 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ColumnPath, Primitive, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"into column_path"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into column_path").rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"values to convert to column_path",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Convert value to column path"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
into_filepath(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Convert string to column_path in table",
|
||||
example: "echo [[name]; ['/dev/null'] ['C:\\Program Files'] ['../../Cargo.toml']] | into column_path name",
|
||||
result: Some(vec![
|
||||
UntaggedValue::row(indexmap! {
|
||||
"name".to_string() => UntaggedValue::column_path("/dev/null", Span::unknown()).into(),
|
||||
})
|
||||
.into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"name".to_string() => UntaggedValue::column_path("C:\\Program Files", Span::unknown()).into(),
|
||||
})
|
||||
.into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"name".to_string() => UntaggedValue::column_path("../../Cargo.toml", Span::unknown()).into(),
|
||||
})
|
||||
.into(),
|
||||
]),
|
||||
},
|
||||
Example {
|
||||
description: "Convert string to column_path",
|
||||
example: "echo 'Cargo.toml' | into column_path",
|
||||
result: Some(vec![UntaggedValue::column_path("Cargo.toml", Span::unknown()).into()]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn into_filepath(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let column_paths: Vec<ColumnPath> = args.rest(0)?;
|
||||
|
||||
Ok(args
|
||||
.input
|
||||
.map(move |v| {
|
||||
if column_paths.is_empty() {
|
||||
action(&v, v.tag())
|
||||
} else {
|
||||
let mut ret = v;
|
||||
for path in &column_paths {
|
||||
ret = ret.swap_data_by_column_path(
|
||||
path,
|
||||
Box::new(move |old| action(old, old.tag())),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
})
|
||||
.into_input_stream())
|
||||
}
|
||||
|
||||
pub fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
let tag = tag.into();
|
||||
match &input.value {
|
||||
UntaggedValue::Primitive(prim) => Ok(UntaggedValue::column_path(
|
||||
match prim {
|
||||
Primitive::String(a_string) => a_string,
|
||||
_ => {
|
||||
return Err(ShellError::unimplemented(
|
||||
"'into column_path' for non-string primitives",
|
||||
))
|
||||
}
|
||||
},
|
||||
Span::unknown(),
|
||||
)
|
||||
.into_value(&tag)),
|
||||
UntaggedValue::Row(_) => Err(ShellError::labeled_error(
|
||||
"specify column name to use, with 'into column_path COLUMN'",
|
||||
"found table",
|
||||
tag,
|
||||
)),
|
||||
_ => Err(ShellError::unimplemented(
|
||||
"'into column_path' for unsupported type",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::SubCommand;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into path").rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column paths to convert to filepath (for table input)",
|
||||
)
|
||||
|
182
crates/nu-command/src/commands/conversions/into/filesize.rs
Normal file
182
crates/nu-command/src/commands/conversions/into/filesize.rs
Normal file
@ -0,0 +1,182 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ColumnPath, Primitive, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use num_bigint::ToBigInt;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"into filesize"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into filesize").rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column paths to convert to filesize (for table input)",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Convert value to filesize"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
into_filesize(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Convert string to filesize in table",
|
||||
example: "echo [[bytes]; ['5'] [3.2] [4] [2kb]] | into filesize bytes",
|
||||
result: Some(vec![
|
||||
UntaggedValue::row(indexmap! {
|
||||
"bytes".to_string() => UntaggedValue::filesize(5).into(),
|
||||
})
|
||||
.into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"bytes".to_string() => UntaggedValue::filesize(3).into(),
|
||||
})
|
||||
.into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"bytes".to_string() => UntaggedValue::filesize(4).into(),
|
||||
})
|
||||
.into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"bytes".to_string() => UntaggedValue::filesize(2000).into(),
|
||||
})
|
||||
.into(),
|
||||
]),
|
||||
},
|
||||
Example {
|
||||
description: "Convert string to filesize",
|
||||
example: "echo '2' | into filesize",
|
||||
result: Some(vec![UntaggedValue::filesize(2).into()]),
|
||||
},
|
||||
Example {
|
||||
description: "Convert decimal to filesize",
|
||||
example: "echo 8.3 | into filesize",
|
||||
result: Some(vec![UntaggedValue::filesize(8).into()]),
|
||||
},
|
||||
Example {
|
||||
description: "Convert int to filesize",
|
||||
example: "echo 5 | into filesize",
|
||||
result: Some(vec![UntaggedValue::filesize(5).into()]),
|
||||
},
|
||||
Example {
|
||||
description: "Convert file size to filesize",
|
||||
example: "echo 4KB | into filesize",
|
||||
result: Some(vec![UntaggedValue::filesize(4000).into()]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn into_filesize(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let column_paths: Vec<ColumnPath> = args.rest(0)?;
|
||||
|
||||
Ok(args
|
||||
.input
|
||||
.map(move |v| {
|
||||
if column_paths.is_empty() {
|
||||
action(&v, v.tag())
|
||||
} else {
|
||||
let mut ret = v;
|
||||
for path in &column_paths {
|
||||
ret = ret.swap_data_by_column_path(
|
||||
path,
|
||||
Box::new(move |old| action(old, old.tag())),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
})
|
||||
.into_input_stream())
|
||||
}
|
||||
|
||||
pub fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
let tag = tag.into();
|
||||
match &input.value {
|
||||
UntaggedValue::Primitive(prim) => Ok(UntaggedValue::filesize(match prim {
|
||||
Primitive::String(a_string) => match int_from_string(a_string.trim(), &tag) {
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
},
|
||||
Primitive::Decimal(dec) => match dec.to_bigint() {
|
||||
Some(n) => match n.to_u64() {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
return Err(ShellError::unimplemented(
|
||||
"failed to convert decimal to filesize",
|
||||
));
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(ShellError::unimplemented(
|
||||
"failed to convert decimal to filesize",
|
||||
));
|
||||
}
|
||||
},
|
||||
Primitive::Int(n_ref) => (*n_ref).try_into().map_err(|_| {
|
||||
ShellError::unimplemented("cannot convert negative integer to filesize")
|
||||
})?,
|
||||
Primitive::Filesize(a_filesize) => *a_filesize,
|
||||
_ => {
|
||||
return Err(ShellError::unimplemented(
|
||||
"'into filesize' for non-numeric primitives",
|
||||
))
|
||||
}
|
||||
})
|
||||
.into_value(&tag)),
|
||||
UntaggedValue::Row(_) => Err(ShellError::labeled_error(
|
||||
"specify column name to use, with 'into filesize COLUMN'",
|
||||
"found table",
|
||||
tag,
|
||||
)),
|
||||
_ => Err(ShellError::unimplemented(
|
||||
"'into filesize' for unsupported type",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn int_from_string(a_string: &str, tag: &Tag) -> Result<u64, ShellError> {
|
||||
match a_string.parse::<u64>() {
|
||||
Ok(n) => Ok(n),
|
||||
Err(_) => match a_string.parse::<f64>() {
|
||||
Ok(f) => match f.to_u64() {
|
||||
Some(i) => Ok(i),
|
||||
None => Err(ShellError::labeled_error(
|
||||
"Could not convert string value to filesize",
|
||||
"original value",
|
||||
tag.clone(),
|
||||
)),
|
||||
},
|
||||
Err(_) => Err(ShellError::labeled_error(
|
||||
"Could not convert string value to filesize",
|
||||
"original value",
|
||||
tag.clone(),
|
||||
)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::SubCommand;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into int").rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column paths to convert to int (for table input)",
|
||||
)
|
||||
|
@ -1,10 +1,14 @@
|
||||
mod binary;
|
||||
mod column_path;
|
||||
mod command;
|
||||
mod filepath;
|
||||
mod filesize;
|
||||
mod int;
|
||||
pub mod string;
|
||||
|
||||
pub use self::filesize::SubCommand as IntoFilesize;
|
||||
pub use binary::SubCommand as IntoBinary;
|
||||
pub use column_path::SubCommand as IntoColumnPath;
|
||||
pub use command::Command as Into;
|
||||
pub use filepath::SubCommand as IntoFilepath;
|
||||
pub use int::SubCommand as IntoInt;
|
||||
|
@ -20,6 +20,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into string")
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column paths to convert to string (for table input)",
|
||||
)
|
||||
@ -158,7 +159,7 @@ pub fn action(
|
||||
}
|
||||
|
||||
fn format_int(int: i64) -> String {
|
||||
format!("{}", int)
|
||||
int.to_string()
|
||||
|
||||
// TODO once platform-specific dependencies are stable (see Cargo.toml)
|
||||
// #[cfg(windows)]
|
||||
@ -175,7 +176,7 @@ fn format_int(int: i64) -> String {
|
||||
}
|
||||
|
||||
fn format_bigint(int: &BigInt) -> String {
|
||||
format!("{}", int)
|
||||
int.to_string()
|
||||
|
||||
// TODO once platform-specific dependencies are stable (see Cargo.toml)
|
||||
// #[cfg(windows)]
|
||||
@ -229,7 +230,7 @@ fn format_decimal(mut decimal: BigDecimal, digits: Option<u64>, group_digits: bo
|
||||
let format_default_loc = |int_part: BigInt| {
|
||||
let loc = Locale::en;
|
||||
//TODO: when num_format is available for recent bigint, replace this with the locale-based format
|
||||
let (int_str, sep) = (format!("{}", int_part), String::from(loc.decimal()));
|
||||
let (int_str, sep) = (int_part.to_string(), String::from(loc.decimal()));
|
||||
|
||||
format!("{}{}{}", int_str, sep, dec_str)
|
||||
};
|
||||
|
@ -2,7 +2,7 @@ use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
||||
|
||||
pub struct Alias;
|
||||
|
||||
@ -15,7 +15,7 @@ impl WholeStreamCommand for Alias {
|
||||
Signature::build("alias")
|
||||
.required("name", SyntaxShape::String, "the name of the alias")
|
||||
.required("equals", SyntaxShape::String, "the equals sign")
|
||||
.rest(SyntaxShape::Any, "the expansion for the alias")
|
||||
.rest("rest", SyntaxShape::Any, "the expansion for the alias")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -35,6 +35,18 @@ impl WholeStreamCommand for Alias {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alias(_: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn alias(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
// TODO: is there a better way of checking whether no arguments were passed?
|
||||
if args.nth(0).is_none() {
|
||||
let aliases = UntaggedValue::string(
|
||||
&args
|
||||
.scope()
|
||||
.get_aliases()
|
||||
.iter()
|
||||
.map(|val| format!("{} = '{}'", val.0, val.1.iter().map(|x| &x.item).join(" ")))
|
||||
.join("\n"),
|
||||
);
|
||||
return Ok(OutputStream::one(aliases));
|
||||
}
|
||||
Ok(OutputStream::empty())
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ impl WholeStreamCommand for Do {
|
||||
"ignore errors as the block runs",
|
||||
Some('i'),
|
||||
)
|
||||
.rest(SyntaxShape::Any, "the parameter(s) for the block")
|
||||
.rest("rest", SyntaxShape::Any, "the parameter(s) for the block")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -12,7 +12,7 @@ impl WholeStreamCommand for Echo {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("echo").rest(SyntaxShape::Any, "the values to echo")
|
||||
Signature::build("echo").rest("rest", SyntaxShape::Any, "the values to echo")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
109
crates/nu-command/src/commands/core_commands/error/make.rs
Normal file
109
crates/nu-command/src/commands/core_commands/error/make.rs
Normal file
@ -0,0 +1,109 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, Signature, UntaggedValue, Value};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"error make"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("error make")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Create an error."
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let input = args.input;
|
||||
|
||||
Ok(input
|
||||
.map(|value| {
|
||||
make_error(&value)
|
||||
.map(|err| UntaggedValue::Error(err).into_value(value.tag()))
|
||||
.unwrap_or_else(|| {
|
||||
UntaggedValue::Error(ShellError::untagged_runtime_error(
|
||||
"Creating error value not supported.",
|
||||
))
|
||||
.into_value(value.tag())
|
||||
})
|
||||
})
|
||||
.into_output_stream())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Creates a labeled error",
|
||||
example: r#"[
|
||||
[ msg, labels, span];
|
||||
["The message", "Helpful message here", ([[start, end]; [0, 141]])]
|
||||
] | error make"#,
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn make_error(value: &Value) -> Option<ShellError> {
|
||||
if let Value {
|
||||
value: UntaggedValue::Row(dict),
|
||||
..
|
||||
} = value
|
||||
{
|
||||
let msg = dict.get_data_by_key("msg".spanned_unknown());
|
||||
|
||||
let labels =
|
||||
dict.get_data_by_key("labels".spanned_unknown())
|
||||
.and_then(|table| match &table.value {
|
||||
UntaggedValue::Table(_) => table
|
||||
.table_entries()
|
||||
.map(|value| value.as_string().ok())
|
||||
.collect(),
|
||||
UntaggedValue::Primitive(Primitive::String(label)) => {
|
||||
Some(vec![label.to_string()])
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let _anchor = dict.get_data_by_key("tag".spanned_unknown());
|
||||
let span = dict.get_data_by_key("span".spanned_unknown());
|
||||
|
||||
if msg.is_none() || labels.is_none() || span.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let msg = msg.and_then(|msg| msg.as_string().ok());
|
||||
|
||||
if let Some(labels) = labels {
|
||||
if labels.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
return Some(ShellError::labeled_error(
|
||||
msg.expect("Message will always be present."),
|
||||
&labels[0],
|
||||
span.map(|data| match data {
|
||||
Value {
|
||||
value: UntaggedValue::Row(vals),
|
||||
..
|
||||
} => match (vals.entries.get("start"), vals.entries.get("end")) {
|
||||
(Some(start), Some(end)) => {
|
||||
let start = start.as_usize().ok().unwrap_or(0);
|
||||
let end = end.as_usize().ok().unwrap_or(0);
|
||||
|
||||
Span::new(start, end)
|
||||
}
|
||||
(_, _) => Span::unknown(),
|
||||
},
|
||||
_ => Span::unknown(),
|
||||
})
|
||||
.unwrap_or_else(Span::unknown),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
mod make;
|
||||
|
||||
pub use make::SubCommand as ErrorMake;
|
110
crates/nu-command/src/commands/core_commands/find.rs
Normal file
110
crates/nu-command/src/commands/core_commands/find.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Dictionary, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
pub struct Find;
|
||||
|
||||
impl WholeStreamCommand for Find {
|
||||
fn name(&self) -> &str {
|
||||
"find"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("find").rest("rest", SyntaxShape::String, "search term")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Find text in the output of a previous command"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
find(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Search pipeline output for multiple terms",
|
||||
example: r#"ls | find toml md sh"#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Search strings for term(s)",
|
||||
example: r#"echo Cargo.toml | find toml"#,
|
||||
result: Some(vec![Value::from("Cargo.toml")]),
|
||||
},
|
||||
Example {
|
||||
description: "Search a number list for term(s)",
|
||||
example: r#"[1 2 3 4 5] | find 5"#,
|
||||
result: Some(vec![UntaggedValue::int(5).into()]),
|
||||
},
|
||||
Example {
|
||||
description: "Search string list for term(s)",
|
||||
example: r#"[moe larry curly] | find l"#,
|
||||
result: Some(vec![Value::from("larry"), Value::from("curly")]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn row_contains(row: &Dictionary, search_terms: Vec<String>) -> bool {
|
||||
for term in search_terms {
|
||||
for (k, v) in &row.entries {
|
||||
let key = k.to_string().trim().to_lowercase();
|
||||
let value = v.convert_to_string().trim().to_lowercase();
|
||||
if key.contains(&term) || value.contains(&term) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn find(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let rest: Vec<Value> = args.rest(0)?;
|
||||
|
||||
Ok(args
|
||||
.input
|
||||
.filter(move |row| match &row.value {
|
||||
UntaggedValue::Row(row) => {
|
||||
let sterms: Vec<String> = rest
|
||||
.iter()
|
||||
.map(|t| t.convert_to_string().trim().to_lowercase())
|
||||
.collect();
|
||||
row_contains(row, sterms)
|
||||
}
|
||||
UntaggedValue::Primitive(_p) => {
|
||||
// eprint!("prim {}", p.type_name());
|
||||
let sterms: Vec<String> = rest
|
||||
.iter()
|
||||
.map(|t| t.convert_to_string().trim().to_lowercase())
|
||||
.collect();
|
||||
|
||||
let prim_string = &row.convert_to_string().trim().to_lowercase();
|
||||
for term in sterms {
|
||||
if prim_string.contains(&term) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
.into_output_stream())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Find;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Find {})
|
||||
}
|
||||
}
|
@ -1,14 +1,12 @@
|
||||
use crate::prelude::*;
|
||||
use crate::TaggedListBuilder;
|
||||
use nu_engine::documentation::generate_docs;
|
||||
use nu_engine::{Command, WholeStreamCommand};
|
||||
use nu_engine::{documentation::generate_docs, Command, WholeStreamCommand};
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
NamedType, PositionalType, ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder,
|
||||
UntaggedValue, Value,
|
||||
Dictionary, NamedType, PositionalType, ReturnSuccess, Signature, SyntaxShape,
|
||||
TaggedDictBuilder, UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::Tag;
|
||||
use nu_source::{SpannedItem, Tagged};
|
||||
use nu_source::{SpannedItem, Tag, Tagged};
|
||||
use nu_value_ext::ValueExt;
|
||||
|
||||
pub struct Help;
|
||||
@ -19,7 +17,18 @@ impl WholeStreamCommand for Help {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("help").rest(SyntaxShape::String, "the name of command to get help on")
|
||||
Signature::build("help")
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::String,
|
||||
"the name of command to get help on",
|
||||
)
|
||||
.named(
|
||||
"find",
|
||||
SyntaxShape::String,
|
||||
"string to find in command usage",
|
||||
Some('f'),
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -29,14 +38,81 @@ impl WholeStreamCommand for Help {
|
||||
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
help(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "show all commands and sub-commands",
|
||||
example: "help commands",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "generate documentation",
|
||||
example: "help generate_docs",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "show help for single command",
|
||||
example: "help match",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "show help for single sub-command",
|
||||
example: "help str lpad",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "search for string in command usage",
|
||||
example: "help --find char",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn help(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let scope = args.scope().clone();
|
||||
|
||||
let find: Option<Tagged<String>> = args.get_flag("find")?;
|
||||
let rest: Vec<Tagged<String>> = args.rest(0)?;
|
||||
|
||||
if let Some(f) = find {
|
||||
let search_string = f.item;
|
||||
let full_commands = scope.get_commands_info();
|
||||
let mut found_cmds_vec = Vec::new();
|
||||
|
||||
for (key, cmd) in full_commands {
|
||||
let mut indexmap = IndexMap::new();
|
||||
|
||||
let c = cmd.usage().to_string();
|
||||
let e = cmd.extra_usage().to_string();
|
||||
if key.to_lowercase().contains(&search_string)
|
||||
|| c.to_lowercase().contains(&search_string)
|
||||
|| e.to_lowercase().contains(&search_string)
|
||||
{
|
||||
indexmap.insert(
|
||||
"name".to_string(),
|
||||
UntaggedValue::string(key).into_value(&name),
|
||||
);
|
||||
|
||||
indexmap.insert(
|
||||
"usage".to_string(),
|
||||
UntaggedValue::string(cmd.usage().to_string()).into_value(&name),
|
||||
);
|
||||
|
||||
indexmap.insert(
|
||||
"extra_usage".to_string(),
|
||||
UntaggedValue::string(cmd.extra_usage().to_string()).into_value(&name),
|
||||
);
|
||||
|
||||
found_cmds_vec
|
||||
.push(UntaggedValue::Row(Dictionary::from(indexmap)).into_value(&name));
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(found_cmds_vec.into_iter().into_action_stream());
|
||||
}
|
||||
|
||||
if !rest.is_empty() {
|
||||
if rest[0].item == "commands" {
|
||||
let mut sorted_names = scope.get_command_names();
|
||||
@ -226,7 +302,7 @@ pub fn signature_dict(signature: Signature, tag: impl Into<Tag>) -> Value {
|
||||
let tag = tag.into();
|
||||
let mut sig = TaggedListBuilder::new(&tag);
|
||||
|
||||
for arg in signature.positional.iter() {
|
||||
for arg in &signature.positional {
|
||||
let is_required = matches!(arg.0, PositionalType::Mandatory(_, _));
|
||||
|
||||
sig.push_value(for_spec(arg.0.name(), "argument", is_required, &tag));
|
||||
@ -237,7 +313,7 @@ pub fn signature_dict(signature: Signature, tag: impl Into<Tag>) -> Value {
|
||||
sig.push_value(for_spec("rest", "argument", is_required, &tag));
|
||||
}
|
||||
|
||||
for (name, ty) in signature.named.iter() {
|
||||
for (name, ty) in &signature.named {
|
||||
match ty.0 {
|
||||
NamedType::Mandatory(_, _) => sig.push_value(for_spec(name, "flag", true, &tag)),
|
||||
NamedType::Optional(_, _) => sig.push_value(for_spec(name, "flag", false, &tag)),
|
||||
|
@ -100,18 +100,15 @@ fn if_command(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
context.scope.add_vars(&condition.captured.entries);
|
||||
|
||||
//FIXME: should we use the scope that's brought in as well?
|
||||
let condition = evaluate_baseline_expr(cond, &*context);
|
||||
match condition {
|
||||
let condition = evaluate_baseline_expr(cond, &context);
|
||||
let result = match condition {
|
||||
Ok(condition) => match condition.as_bool() {
|
||||
Ok(b) => {
|
||||
let result = if b {
|
||||
run_block(&then_case.block, &*context, input, external_redirection)
|
||||
if b {
|
||||
run_block(&then_case.block, &context, input, external_redirection)
|
||||
} else {
|
||||
run_block(&else_case.block, &*context, input, external_redirection)
|
||||
};
|
||||
context.scope.exit_scope();
|
||||
|
||||
result
|
||||
run_block(&else_case.block, &context, input, external_redirection)
|
||||
}
|
||||
}
|
||||
Err(e) => Ok(OutputStream::from_stream(
|
||||
vec![UntaggedValue::Error(e).into_untagged_value()].into_iter(),
|
||||
@ -120,13 +117,16 @@ fn if_command(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Err(e) => Ok(OutputStream::from_stream(
|
||||
vec![UntaggedValue::Error(e).into_untagged_value()].into_iter(),
|
||||
)),
|
||||
}
|
||||
};
|
||||
context.scope.exit_scope();
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::If;
|
||||
use super::ShellError;
|
||||
use nu_test_support::nu;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
@ -134,4 +134,21 @@ mod tests {
|
||||
|
||||
test_examples(If {})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_doesnt_leak_on_error() {
|
||||
let actual = nu!(
|
||||
".",
|
||||
r#"
|
||||
def test-leak [] {
|
||||
let var = "hello"
|
||||
if 0 == "" {echo ok} {echo not}
|
||||
}
|
||||
test-leak
|
||||
echo $var
|
||||
"#
|
||||
);
|
||||
|
||||
assert!(actual.err.contains("unknown variable"));
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ mod def;
|
||||
mod describe;
|
||||
mod do_;
|
||||
pub(crate) mod echo;
|
||||
mod error;
|
||||
mod find;
|
||||
mod help;
|
||||
mod history;
|
||||
mod if_;
|
||||
@ -13,6 +15,8 @@ mod nu_plugin;
|
||||
mod nu_signature;
|
||||
mod source;
|
||||
mod tags;
|
||||
mod tutor;
|
||||
mod unalias;
|
||||
mod version;
|
||||
|
||||
pub use self::nu_plugin::SubCommand as NuPlugin;
|
||||
@ -25,6 +29,8 @@ pub use def::Def;
|
||||
pub use describe::Describe;
|
||||
pub use do_::Do;
|
||||
pub use echo::Echo;
|
||||
pub use error::*;
|
||||
pub use find::Find;
|
||||
pub use help::Help;
|
||||
pub use history::History;
|
||||
pub use if_::If;
|
||||
@ -32,4 +38,6 @@ pub use ignore::Ignore;
|
||||
pub use let_::Let;
|
||||
pub use source::Source;
|
||||
pub use tags::Tags;
|
||||
pub use tutor::Tutor;
|
||||
pub use unalias::Unalias;
|
||||
pub use version::{version, Version};
|
||||
|
@ -4,7 +4,7 @@ use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_path::canonicalize;
|
||||
use nu_path::canonicalize_with;
|
||||
use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
|
||||
@ -56,7 +56,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
tag,
|
||||
}) = load_path
|
||||
{
|
||||
let path = canonicalize(shell_manager.path(), load_path).map_err(|_| {
|
||||
let path = canonicalize_with(load_path, shell_manager.path()).map_err(|_| {
|
||||
ShellError::labeled_error(
|
||||
"Cannot load plugins from directory",
|
||||
"directory not found",
|
||||
|
@ -41,7 +41,7 @@ impl WholeStreamCommand for Command {
|
||||
"custom configuration source file",
|
||||
None,
|
||||
)
|
||||
.rest(SyntaxShape::String, "source file(s) to run")
|
||||
.rest("rest", SyntaxShape::String, "source file(s) to run")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -2,11 +2,11 @@ use crate::prelude::*;
|
||||
use nu_engine::{script, WholeStreamCommand};
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_path::expand_path;
|
||||
use nu_path::{canonicalize, canonicalize_with};
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
|
||||
use std::{borrow::Cow, path::Path};
|
||||
use std::path::Path;
|
||||
|
||||
pub struct Source;
|
||||
|
||||
@ -32,7 +32,7 @@ impl WholeStreamCommand for Source {
|
||||
"Runs a script file in the current context."
|
||||
}
|
||||
|
||||
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
source(args)
|
||||
}
|
||||
|
||||
@ -41,14 +41,66 @@ impl WholeStreamCommand for Source {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn source(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
pub fn source(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let ctx = &args.context;
|
||||
let filename: Tagged<String> = args.req(0)?;
|
||||
|
||||
let source_file = Path::new(&filename.item);
|
||||
|
||||
// Note: this is a special case for setting the context from a command
|
||||
// In this case, if we don't set it now, we'll lose the scope that this
|
||||
// variable should be set into.
|
||||
let contents = std::fs::read_to_string(&expand_path(Cow::Borrowed(Path::new(&filename.item))));
|
||||
|
||||
let lib_dirs = &ctx
|
||||
.configs()
|
||||
.lock()
|
||||
.global_config
|
||||
.as_ref()
|
||||
.map(|configuration| match configuration.var("lib_dirs") {
|
||||
Some(paths) => paths
|
||||
.table_entries()
|
||||
.cloned()
|
||||
.map(|path| path.as_string())
|
||||
.collect(),
|
||||
None => vec![],
|
||||
});
|
||||
|
||||
if let Some(dir) = lib_dirs {
|
||||
for lib_path in dir {
|
||||
match lib_path {
|
||||
Ok(name) => {
|
||||
let path = if let Ok(p) = canonicalize_with(&source_file, name) {
|
||||
p
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Ok(contents) = std::fs::read_to_string(path) {
|
||||
let result = script::run_script_standalone(contents, true, ctx, false);
|
||||
|
||||
if let Err(err) = result {
|
||||
ctx.error(err);
|
||||
}
|
||||
return Ok(OutputStream::empty());
|
||||
}
|
||||
}
|
||||
Err(reason) => {
|
||||
ctx.error(reason.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let path = canonicalize(source_file).map_err(|e| {
|
||||
ShellError::labeled_error(
|
||||
format!("Can't load source file. Reason: {}", e.to_string()),
|
||||
"Can't load this file",
|
||||
filename.span(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let contents = std::fs::read_to_string(path);
|
||||
|
||||
match contents {
|
||||
Ok(contents) => {
|
||||
let result = script::run_script_standalone(contents, true, ctx, false);
|
||||
@ -56,16 +108,16 @@ pub fn source(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
if let Err(err) = result {
|
||||
ctx.error(err);
|
||||
}
|
||||
Ok(ActionStream::empty())
|
||||
Ok(OutputStream::empty())
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
ctx.error(ShellError::labeled_error(
|
||||
"Can't load file to source",
|
||||
"can't load file",
|
||||
format!("Can't load source file. Reason: {}", e.to_string()),
|
||||
"Can't load this file",
|
||||
filename.span(),
|
||||
));
|
||||
|
||||
Ok(ActionStream::empty())
|
||||
Ok(OutputStream::empty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, TaggedDictBuilder, UntaggedValue};
|
||||
use nu_protocol::{Primitive, Signature, TaggedDictBuilder, UntaggedValue, Value};
|
||||
|
||||
pub struct Tags;
|
||||
|
||||
@ -18,37 +18,64 @@ impl WholeStreamCommand for Tags {
|
||||
"Read the tags (metadata) for values."
|
||||
}
|
||||
|
||||
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(tags(args))
|
||||
}
|
||||
}
|
||||
|
||||
fn tags(args: CommandArgs) -> ActionStream {
|
||||
args.input
|
||||
.map(move |v| {
|
||||
let mut tags = TaggedDictBuilder::new(v.tag());
|
||||
{
|
||||
let anchor = v.anchor();
|
||||
let span = v.tag.span;
|
||||
let mut dict = TaggedDictBuilder::new(v.tag());
|
||||
dict.insert_untagged("start", UntaggedValue::int(span.start() as i64));
|
||||
dict.insert_untagged("end", UntaggedValue::int(span.end() as i64));
|
||||
tags.insert_value("span", dict.into_value());
|
||||
fn build_tag_table(tag: impl Into<Tag>) -> Value {
|
||||
let tag = tag.into();
|
||||
let span = tag.span;
|
||||
|
||||
match anchor {
|
||||
Some(AnchorLocation::File(source)) => {
|
||||
tags.insert_untagged("anchor", UntaggedValue::string(source));
|
||||
}
|
||||
Some(AnchorLocation::Url(source)) => {
|
||||
tags.insert_untagged("anchor", UntaggedValue::string(source));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
TaggedDictBuilder::build(tag.clone(), |tags| {
|
||||
if let Some(anchor) = anchor_as_value(&tag) {
|
||||
tags.insert_value("anchor", anchor);
|
||||
}
|
||||
|
||||
tags.insert_value(
|
||||
"span",
|
||||
TaggedDictBuilder::build(tag.clone(), |span_dict| {
|
||||
span_dict.insert_untagged("start", UntaggedValue::int(span.start() as i64));
|
||||
span_dict.insert_untagged("end", UntaggedValue::int(span.end() as i64));
|
||||
}),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
fn tags(args: CommandArgs) -> OutputStream {
|
||||
if args.input.is_empty() {
|
||||
OutputStream::one(build_tag_table(&args.name_tag()))
|
||||
} else {
|
||||
args.input
|
||||
.map(move |v| build_tag_table(v.tag()))
|
||||
.into_output_stream()
|
||||
}
|
||||
}
|
||||
|
||||
fn anchor_as_value(tag: &Tag) -> Option<Value> {
|
||||
let anchor = tag.anchor.as_ref();
|
||||
|
||||
anchor.as_ref()?;
|
||||
|
||||
Some(TaggedDictBuilder::build(tag, |table| {
|
||||
let value = match anchor {
|
||||
Some(AnchorLocation::File(path)) => {
|
||||
Some(("file", UntaggedValue::from(path.to_string())))
|
||||
}
|
||||
Some(AnchorLocation::Url(destination)) => {
|
||||
Some(("url", UntaggedValue::from(destination.to_string())))
|
||||
}
|
||||
Some(AnchorLocation::Source(text)) => Some((
|
||||
"source",
|
||||
UntaggedValue::Primitive(Primitive::String(text.to_string())),
|
||||
)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
tags.into_value()
|
||||
})
|
||||
.into_action_stream()
|
||||
if let Some((key, value)) = value {
|
||||
table.insert_untagged(key, value);
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
407
crates/nu-command/src/commands/core_commands/tutor.rs
Normal file
407
crates/nu-command/src/commands/core_commands/tutor.rs
Normal file
@ -0,0 +1,407 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
||||
|
||||
pub struct Tutor;
|
||||
|
||||
impl WholeStreamCommand for Tutor {
|
||||
fn name(&self) -> &str {
|
||||
"tutor"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("tutor")
|
||||
.optional(
|
||||
"search",
|
||||
SyntaxShape::String,
|
||||
"item to search for, or 'list' to list available tutorials",
|
||||
)
|
||||
.named(
|
||||
"find",
|
||||
SyntaxShape::String,
|
||||
"Search tutorial for a phrase",
|
||||
Some('f'),
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Run the tutorial. To begin, run: tutor"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
tutor(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Begin the tutorial",
|
||||
example: "tutor begin",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Search a tutorial by phrase",
|
||||
example: "tutor -f \"$in\"",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn tutor(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.name_tag();
|
||||
let scope = args.scope().clone();
|
||||
|
||||
let search: Option<String> = args.opt(0).unwrap_or(None);
|
||||
let find: Option<String> = args.get_flag("find")?;
|
||||
|
||||
let search_space = [
|
||||
(vec!["begin"], begin_tutor()),
|
||||
(
|
||||
vec!["table", "tables", "row", "rows", "column", "columns"],
|
||||
table_tutor(),
|
||||
),
|
||||
(vec!["cell", "cells"], cell_tutor()),
|
||||
(
|
||||
vec![
|
||||
"expr",
|
||||
"exprs",
|
||||
"expressions",
|
||||
"subexpression",
|
||||
"subexpressions",
|
||||
"sub-expression",
|
||||
"sub-expressions",
|
||||
],
|
||||
expression_tutor(),
|
||||
),
|
||||
(vec!["echo"], echo_tutor()),
|
||||
(vec!["each", "iteration", "iter"], each_tutor()),
|
||||
(
|
||||
vec!["var", "vars", "variable", "variables"],
|
||||
variable_tutor(),
|
||||
),
|
||||
(vec!["block", "blocks"], block_tutor()),
|
||||
(vec!["shorthand", "shorthands"], shorthand_tutor()),
|
||||
];
|
||||
|
||||
if let Some(find) = find {
|
||||
let mut results = vec![];
|
||||
for search_group in search_space {
|
||||
if search_group.1.contains(&find) {
|
||||
results.push(search_group.0[0].to_string())
|
||||
}
|
||||
}
|
||||
|
||||
let message = format!("You can find '{}' in the following topics:\n{}\n\nYou can learn about a topic using `tutor` followed by the name of the topic.\nFor example: `tutor table` to open the table topic.\n\n",
|
||||
find,
|
||||
results.into_iter().map(|x| format!("- {}", x)).join("\n")
|
||||
);
|
||||
|
||||
return Ok(display(tag, &scope, &message));
|
||||
} else if let Some(search) = search {
|
||||
for search_group in search_space {
|
||||
if search_group.0.contains(&search.as_str()) {
|
||||
return Ok(display(tag, &scope, search_group.1));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(display(tag, &scope, default_tutor()))
|
||||
}
|
||||
|
||||
fn default_tutor() -> &'static str {
|
||||
r#"
|
||||
Welcome to the Nushell tutorial!
|
||||
|
||||
With the `tutor` command, you'll be able to learn a lot about how Nushell
|
||||
works along with many fun tips and tricks to speed up everyday tasks.
|
||||
|
||||
To get started, you can use `tutor begin`.
|
||||
|
||||
"#
|
||||
}
|
||||
|
||||
fn begin_tutor() -> &'static str {
|
||||
r#"
|
||||
Nushell is a structured shell and programming language. One way to begin
|
||||
using it is to try a few of the commands.
|
||||
|
||||
The first command to try is `ls`. The `ls` command will show you a list
|
||||
of the files in the current directory. Notice that these files are shown
|
||||
as a table. Each column of this table not only tells us what is being
|
||||
shown, but also gives us a way to work with the data.
|
||||
|
||||
You can combine the `ls` command with other commands using the pipeline
|
||||
symbol '|'. This allows data to flow from one command to the next.
|
||||
|
||||
For example, if we only wanted the name column, we could do:
|
||||
```
|
||||
ls | select name
|
||||
```
|
||||
Notice that we still get a table, but this time it only has one column:
|
||||
the name column.
|
||||
|
||||
You can continue to learn more about tables by running:
|
||||
```
|
||||
tutor tables
|
||||
```
|
||||
If at any point, you'd like to restart this tutorial, you can run:
|
||||
```
|
||||
tutor begin
|
||||
```
|
||||
"#
|
||||
}
|
||||
|
||||
fn table_tutor() -> &'static str {
|
||||
r#"
|
||||
The most common form of data in Nushell is the table. Tables contain rows and
|
||||
columns of data. In each cell of the table, there is data that you can access
|
||||
using Nushell commands.
|
||||
|
||||
To get the 3rd row in the table, you can use the `nth` command:
|
||||
```
|
||||
ls | nth 2
|
||||
```
|
||||
This will get the 3rd (note that `nth` is zero-based) row in the table created
|
||||
by the `ls` command. You can use `nth` on any table created by other commands
|
||||
as well.
|
||||
|
||||
You can also access the column of data in one of two ways. If you want
|
||||
to keep the column as part of a new table, you can use `select`.
|
||||
```
|
||||
ls | select name
|
||||
```
|
||||
This runs `ls` and returns only the "name" column of the table.
|
||||
|
||||
If, instead, you'd like to get access to the values inside of the column, you
|
||||
can use the `get` command.
|
||||
```
|
||||
ls | get name
|
||||
```
|
||||
This allows us to get to the list of strings that are the filenames rather
|
||||
than having a full table. In some cases, this can make the names easier to
|
||||
work with.
|
||||
|
||||
You can continue to learn more about working with cells of the table by
|
||||
running:
|
||||
```
|
||||
tutor cells
|
||||
```
|
||||
"#
|
||||
}
|
||||
|
||||
fn cell_tutor() -> &'static str {
|
||||
r#"
|
||||
Working with cells of data in the table is a key part of working with data in
|
||||
Nushell. Because of this, there is a rich list of commands to work with cells
|
||||
as well as handy shorthands for accessing cells.
|
||||
|
||||
Cells can hold simple values like strings and numbers, or more complex values
|
||||
like lists and tables.
|
||||
|
||||
To reach a cell of data from a table, you can combine a row operation and a
|
||||
column operation.
|
||||
```
|
||||
ls | nth 4 | get name
|
||||
```
|
||||
You can combine these operations into one step using a shortcut.
|
||||
```
|
||||
(ls).4.name
|
||||
```
|
||||
Names/strings represent columns names and numbers represent row numbers.
|
||||
|
||||
The `(ls)` is a form of expression. You can continue to learn more about
|
||||
expressions by running:
|
||||
```
|
||||
tutor expressions
|
||||
```
|
||||
You can also learn about these cell shorthands by running:
|
||||
```
|
||||
tutor shorthands
|
||||
```
|
||||
"#
|
||||
}
|
||||
|
||||
fn expression_tutor() -> &'static str {
|
||||
r#"
|
||||
Expressions give you the power to mix calls to commands with math. The
|
||||
simplest expression is a single value like a string or number.
|
||||
```
|
||||
3
|
||||
```
|
||||
Expressions can also include math operations like addition or division.
|
||||
```
|
||||
10 / 2
|
||||
```
|
||||
Normally, an expression is one type of operation: math or commands. You can
|
||||
mix these types by using subexpressions. Subexpressions are just like
|
||||
expressions, but they're wrapped in parentheses `()`.
|
||||
```
|
||||
10 * (3 + 4)
|
||||
```
|
||||
Here we use parentheses to create a higher math precedence in the math
|
||||
expression.
|
||||
```
|
||||
echo (2 + 3)
|
||||
```
|
||||
You can continue to learn more about the `echo` command by running:
|
||||
```
|
||||
tutor echo
|
||||
```
|
||||
"#
|
||||
}
|
||||
|
||||
fn echo_tutor() -> &'static str {
|
||||
r#"
|
||||
The `echo` command in Nushell is a powerful tool for not only seeing values,
|
||||
but also for creating new ones.
|
||||
```
|
||||
echo "Hello"
|
||||
```
|
||||
You can echo output. This output, if it's not redirected using a "|" pipeline
|
||||
will be displayed to the screen.
|
||||
```
|
||||
echo 1..10
|
||||
```
|
||||
You can also use echo to work with individual values of a range. In this
|
||||
example, `echo` will create the values from 1 to 10 as a list.
|
||||
```
|
||||
echo 1 2 3 4 5
|
||||
```
|
||||
You can also create lists of values by passing `echo` multiple arguments.
|
||||
This can be helpful if you want to later processes these values.
|
||||
|
||||
The `echo` command can pair well with the `each` command which can run
|
||||
code on each row, or item, of input.
|
||||
|
||||
You can continue to learn more about the `each` command by running:
|
||||
```
|
||||
tutor each
|
||||
```
|
||||
"#
|
||||
}
|
||||
|
||||
fn each_tutor() -> &'static str {
|
||||
r#"
|
||||
The `each` command gives us a way of working with each individual row or
|
||||
element of a list one at a time. It reads these in from the pipeline and
|
||||
runs a block on each element. A block is a group of pipelines.
|
||||
```
|
||||
echo 1 2 3 | each { $it + 10}
|
||||
```
|
||||
This example iterates over each element sent by `echo`, giving us three new
|
||||
values that are the original value + 10. Here, the `$it` is a variable that
|
||||
is the name given to the block's parameter by default.
|
||||
|
||||
You can learn more about blocks by running:
|
||||
```
|
||||
tutor blocks
|
||||
```
|
||||
You can also learn more about variables by running:
|
||||
```
|
||||
tutor variables
|
||||
```
|
||||
"#
|
||||
}
|
||||
|
||||
fn variable_tutor() -> &'static str {
|
||||
r#"
|
||||
Variables are an important way to store values to be used later. To create a
|
||||
variable, you can use the `let` keyword. The `let` command will create a
|
||||
variable and then assign it a value in one step.
|
||||
```
|
||||
let $x = 3
|
||||
```
|
||||
Once created, we can refer to this variable by name.
|
||||
```
|
||||
$x
|
||||
```
|
||||
Nushell also comes with built-in variables. The `$nu` variable is a reserved
|
||||
variable that contains a lot of information about the currently running
|
||||
instance of Nushell. The `$it` variable is the name given to block parameters
|
||||
if you don't specify one. And `$in` is the variable that allows you to work
|
||||
with all of the data coming in from the pipeline in one place.
|
||||
|
||||
"#
|
||||
}
|
||||
|
||||
fn block_tutor() -> &'static str {
|
||||
r#"
|
||||
Blocks are a special form of expression that hold code to be run at a later
|
||||
time. Often, you'll see blocks as one of the arguments given to commands
|
||||
like `each` and `if`.
|
||||
```
|
||||
ls | each {|x| $x.name}
|
||||
```
|
||||
The above will create a list of the filenames in the directory.
|
||||
```
|
||||
if $true { echo "it's true" } { echo "it's not true" }
|
||||
```
|
||||
This `if` call will run the first block if the expression is true, or the
|
||||
second block if the expression is false.
|
||||
|
||||
"#
|
||||
}
|
||||
|
||||
fn shorthand_tutor() -> &'static str {
|
||||
r#"
|
||||
You can access cells in a table using a shorthand notation sometimes called a
|
||||
"column path" or "cell path". These paths allow you to go from a table to
|
||||
rows, columns, or cells inside of the table.
|
||||
|
||||
Shorthand paths are made from rows numbers, column names, or both. You can use
|
||||
them on any variable or subexpression.
|
||||
```
|
||||
$nu.cwd
|
||||
```
|
||||
The above accesses the built-in `$nu` variable, gets its table, and then uses
|
||||
the shorthand path to retrieve only the cell data inside the "cwd" column.
|
||||
```
|
||||
(ls).name.4
|
||||
```
|
||||
This will retrieve the cell data in the "name" column on the 5th row (note:
|
||||
row numbers are zero-based).
|
||||
|
||||
Rows and columns don't need to come in any specific order. You can get the
|
||||
same value using:
|
||||
```
|
||||
(ls).4.name
|
||||
```
|
||||
"#
|
||||
}
|
||||
|
||||
fn display(tag: Tag, scope: &Scope, help: &str) -> OutputStream {
|
||||
let help = help.split('`');
|
||||
|
||||
let mut build = String::new();
|
||||
let mut code_mode = false;
|
||||
let palette = nu_engine::DefaultPalette {};
|
||||
|
||||
for item in help {
|
||||
if code_mode {
|
||||
code_mode = false;
|
||||
|
||||
//TODO: support no-color mode
|
||||
let colored_example = nu_engine::Painter::paint_string(item, scope, &palette);
|
||||
build.push_str(&colored_example);
|
||||
} else {
|
||||
code_mode = true;
|
||||
build.push_str(item);
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream::one(UntaggedValue::string(build).into_value(tag))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::Tutor;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Tutor {})
|
||||
}
|
||||
}
|
37
crates/nu-command/src/commands/core_commands/unalias.rs
Normal file
37
crates/nu-command/src/commands/core_commands/unalias.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
|
||||
pub struct Unalias;
|
||||
|
||||
impl WholeStreamCommand for Unalias {
|
||||
fn name(&self) -> &str {
|
||||
"unalias"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("unalias").required("name", SyntaxShape::String, "the name of the alias")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Removes an alias"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
unalias(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Remove the 'v' alias",
|
||||
example: "unalias v",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unalias(_: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(OutputStream::empty())
|
||||
}
|
@ -245,7 +245,7 @@ fn perform_groupby_aggregation(
|
||||
None => &col[..],
|
||||
};
|
||||
|
||||
res.rename(col.as_str(), new_col)
|
||||
res.rename(&col, new_col)
|
||||
.expect("Column is always there. Looping with known names");
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let other: Value = args.req_named("other")?;
|
||||
let axis: Tagged<String> = args.req_named("axis")?;
|
||||
|
||||
let axis = Axis::try_from_str(axis.item.as_str(), &axis.tag.span)?;
|
||||
let axis = Axis::try_from_str(&axis.item, &axis.tag.span)?;
|
||||
|
||||
let df_other = match other.value {
|
||||
UntaggedValue::DataFrame(df) => Ok(df),
|
||||
|
@ -53,7 +53,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let res = df
|
||||
.as_ref()
|
||||
.column(column.item.as_ref())
|
||||
.column(&column.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &column.tag.span, None))?;
|
||||
|
||||
let df = NuDataFrame::try_from_series(vec![res.clone()], &tag.span)?;
|
||||
|
232
crates/nu-command/src/commands/dataframe/describe.rs
Normal file
232
crates/nu-command/src/commands/dataframe/describe.rs
Normal file
@ -0,0 +1,232 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, UntaggedValue,
|
||||
};
|
||||
use polars::{
|
||||
chunked_array::ChunkedArray,
|
||||
prelude::{
|
||||
AnyValue, DataFrame as PolarsDF, DataType, Float64Type, IntoSeries, NewChunkedArray,
|
||||
Series, Utf8Type,
|
||||
},
|
||||
};
|
||||
|
||||
use super::utils::parse_polars_error;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe describe"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[DataFrame] Describes dataframes numeric columns"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe describe")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Describes dataframe",
|
||||
example: "[[a b]; [1 1] [1 1]] | dataframe to-df | dataframe describe",
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![
|
||||
Column::new(
|
||||
"descriptor".to_string(),
|
||||
vec![
|
||||
UntaggedValue::string("count").into(),
|
||||
UntaggedValue::string("sum").into(),
|
||||
UntaggedValue::string("mean").into(),
|
||||
UntaggedValue::string("median").into(),
|
||||
UntaggedValue::string("std").into(),
|
||||
UntaggedValue::string("min").into(),
|
||||
UntaggedValue::string("25%").into(),
|
||||
UntaggedValue::string("50%").into(),
|
||||
UntaggedValue::string("75%").into(),
|
||||
UntaggedValue::string("max").into(),
|
||||
],
|
||||
),
|
||||
Column::new(
|
||||
"a (i64)".to_string(),
|
||||
vec![
|
||||
UntaggedValue::decimal_from_float(2.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(2.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(0.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
],
|
||||
),
|
||||
Column::new(
|
||||
"b (i64)".to_string(),
|
||||
vec![
|
||||
UntaggedValue::decimal_from_float(2.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(2.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(0.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
UntaggedValue::decimal_from_float(1.0, Span::default()).into(),
|
||||
],
|
||||
),
|
||||
],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (df, _) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
|
||||
let names = ChunkedArray::<Utf8Type>::new_from_opt_slice(
|
||||
"descriptor",
|
||||
&[
|
||||
Some("count"),
|
||||
Some("sum"),
|
||||
Some("mean"),
|
||||
Some("median"),
|
||||
Some("std"),
|
||||
Some("min"),
|
||||
Some("25%"),
|
||||
Some("50%"),
|
||||
Some("75%"),
|
||||
Some("max"),
|
||||
],
|
||||
)
|
||||
.into_series();
|
||||
|
||||
let head = std::iter::once(names);
|
||||
|
||||
let tail = df.as_ref().get_columns().iter().map(|col| {
|
||||
let count = col.len() as f64;
|
||||
|
||||
let sum = match col.sum_as_series().cast(&DataType::Float64) {
|
||||
Ok(ca) => match ca.get(0) {
|
||||
AnyValue::Float64(v) => Some(v),
|
||||
_ => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let mean = match col.mean_as_series().get(0) {
|
||||
AnyValue::Float64(v) => Some(v),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let median = match col.median_as_series().get(0) {
|
||||
AnyValue::Float64(v) => Some(v),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let std = match col.std_as_series().get(0) {
|
||||
AnyValue::Float64(v) => Some(v),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let min = match col.min_as_series().cast(&DataType::Float64) {
|
||||
Ok(ca) => match ca.get(0) {
|
||||
AnyValue::Float64(v) => Some(v),
|
||||
_ => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let q_25 = match col.quantile_as_series(0.25) {
|
||||
Ok(ca) => match ca.cast(&DataType::Float64) {
|
||||
Ok(ca) => match ca.get(0) {
|
||||
AnyValue::Float64(v) => Some(v),
|
||||
_ => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let q_50 = match col.quantile_as_series(0.50) {
|
||||
Ok(ca) => match ca.cast(&DataType::Float64) {
|
||||
Ok(ca) => match ca.get(0) {
|
||||
AnyValue::Float64(v) => Some(v),
|
||||
_ => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let q_75 = match col.quantile_as_series(0.75) {
|
||||
Ok(ca) => match ca.cast(&DataType::Float64) {
|
||||
Ok(ca) => match ca.get(0) {
|
||||
AnyValue::Float64(v) => Some(v),
|
||||
_ => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let max = match col.max_as_series().cast(&DataType::Float64) {
|
||||
Ok(ca) => match ca.get(0) {
|
||||
AnyValue::Float64(v) => Some(v),
|
||||
_ => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let name = format!("{} ({})", col.name(), col.dtype());
|
||||
ChunkedArray::<Float64Type>::new_from_opt_slice(
|
||||
&name,
|
||||
&[
|
||||
Some(count),
|
||||
sum,
|
||||
mean,
|
||||
median,
|
||||
std,
|
||||
min,
|
||||
q_25,
|
||||
q_50,
|
||||
q_75,
|
||||
max,
|
||||
],
|
||||
)
|
||||
.into_series()
|
||||
});
|
||||
|
||||
let res = head.chain(tail).collect::<Vec<Series>>();
|
||||
let df = PolarsDF::new(res).map_err(|e| parse_polars_error::<&str>(&e, &tag.span, None))?;
|
||||
let df = NuDataFrame::dataframe_to_value(df, tag);
|
||||
Ok(OutputStream::one(df))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
@ -20,7 +20,11 @@ impl WholeStreamCommand for DataFrame {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe drop").rest(SyntaxShape::Any, "column names to be dropped")
|
||||
Signature::build("dataframe drop").rest(
|
||||
"rest",
|
||||
SyntaxShape::Any,
|
||||
"column names to be dropped",
|
||||
)
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -72,7 +72,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
.expect("using name from list of names from dataframe")
|
||||
.dtype();
|
||||
|
||||
let dtype_str = format!("{}", dtype);
|
||||
let dtype_str = dtype.to_string();
|
||||
dtypes.push(Value {
|
||||
value: dtype_str.into(),
|
||||
tag: Tag::default(),
|
||||
|
@ -19,7 +19,11 @@ impl WholeStreamCommand for DataFrame {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get").rest(SyntaxShape::Any, "column names to sort dataframe")
|
||||
Signature::build("dataframe get").rest(
|
||||
"rest",
|
||||
SyntaxShape::Any,
|
||||
"column names to sort dataframe",
|
||||
)
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -20,7 +20,7 @@ impl WholeStreamCommand for DataFrame {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe group-by").rest(SyntaxShape::Any, "groupby columns")
|
||||
Signature::build("dataframe group-by").rest("rest", SyntaxShape::Any, "groupby columns")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -44,6 +44,12 @@ impl WholeStreamCommand for DataFrame {
|
||||
"type of join. Inner by default",
|
||||
Some('t'),
|
||||
)
|
||||
.named(
|
||||
"suffix",
|
||||
SyntaxShape::String,
|
||||
"suffix for the columns of the right dataframe",
|
||||
Some('s'),
|
||||
)
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
@ -104,6 +110,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let r_df: Value = args.req(0)?;
|
||||
let l_col: Vec<Value> = args.req_named("left")?;
|
||||
let r_col: Vec<Value> = args.req_named("right")?;
|
||||
let r_suffix: Option<Tagged<String>> = args.get_flag("suffix")?;
|
||||
let join_type_op: Option<Tagged<String>> = args.get_flag("type")?;
|
||||
|
||||
let join_type = match join_type_op {
|
||||
@ -124,6 +131,8 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
},
|
||||
};
|
||||
|
||||
let suffix = r_suffix.map(|s| s.item);
|
||||
|
||||
let (l_col_string, l_col_span) = convert_columns(&l_col, &tag)?;
|
||||
let (r_col_string, r_col_span) = convert_columns(&r_col, &tag)?;
|
||||
|
||||
@ -142,7 +151,13 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
)?;
|
||||
|
||||
df.as_ref()
|
||||
.join(r_df.as_ref(), &l_col_string, &r_col_string, join_type)
|
||||
.join(
|
||||
r_df.as_ref(),
|
||||
&l_col_string,
|
||||
&r_col_string,
|
||||
join_type,
|
||||
suffix,
|
||||
)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &l_col_span, None))
|
||||
}
|
||||
_ => Err(ShellError::labeled_error(
|
||||
@ -177,7 +192,7 @@ fn check_column_datatypes<T: AsRef<str>>(
|
||||
));
|
||||
}
|
||||
|
||||
for (l, r) in l_cols.iter().zip(r_cols.iter()) {
|
||||
for (l, r) in l_cols.iter().zip(r_cols) {
|
||||
let l_series = df_l
|
||||
.column(l.as_ref())
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, l_col_span, None))?;
|
||||
|
@ -5,6 +5,7 @@ use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::Tagged;
|
||||
|
||||
use super::utils::convert_columns;
|
||||
|
||||
@ -33,6 +34,18 @@ impl WholeStreamCommand for DataFrame {
|
||||
"column names used as value columns",
|
||||
Some('v'),
|
||||
)
|
||||
.named(
|
||||
"variable_name",
|
||||
SyntaxShape::String,
|
||||
"optional name for variable column",
|
||||
Some('r'),
|
||||
)
|
||||
.named(
|
||||
"value_name",
|
||||
SyntaxShape::String,
|
||||
"optional name for value column",
|
||||
Some('l'),
|
||||
)
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
@ -105,6 +118,9 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let id_col: Vec<Value> = args.req_named("columns")?;
|
||||
let val_col: Vec<Value> = args.req_named("values")?;
|
||||
|
||||
let value_name: Option<Tagged<String>> = args.get_flag("value_name")?;
|
||||
let variable_name: Option<Tagged<String>> = args.get_flag("variable_name")?;
|
||||
|
||||
let (id_col_string, id_col_span) = convert_columns(&id_col, &tag)?;
|
||||
let (val_col_string, val_col_span) = convert_columns(&val_col, &tag)?;
|
||||
|
||||
@ -113,11 +129,21 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
check_column_datatypes(df.as_ref(), &id_col_string, &id_col_span)?;
|
||||
check_column_datatypes(df.as_ref(), &val_col_string, &val_col_span)?;
|
||||
|
||||
let res = df
|
||||
let mut res = df
|
||||
.as_ref()
|
||||
.melt(&id_col_string, &val_col_string)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &tag.span, None))?;
|
||||
|
||||
if let Some(name) = &variable_name {
|
||||
res.rename("variable", &name.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &name.tag.span, None))?;
|
||||
}
|
||||
|
||||
if let Some(name) = &value_name {
|
||||
res.rename("value", &name.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &name.tag.span, None))?;
|
||||
}
|
||||
|
||||
Ok(OutputStream::one(NuDataFrame::dataframe_to_value(res, tag)))
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ pub mod aggregate;
|
||||
pub mod append;
|
||||
pub mod column;
|
||||
pub mod command;
|
||||
pub mod describe;
|
||||
pub mod drop;
|
||||
pub mod drop_duplicates;
|
||||
pub mod drop_nulls;
|
||||
@ -17,6 +18,7 @@ pub mod list;
|
||||
pub mod melt;
|
||||
pub mod open;
|
||||
pub mod pivot;
|
||||
pub mod rename;
|
||||
pub mod sample;
|
||||
pub mod select;
|
||||
pub mod shape;
|
||||
@ -35,6 +37,7 @@ pub use aggregate::DataFrame as DataFrameAggregate;
|
||||
pub use append::DataFrame as DataFrameAppend;
|
||||
pub use column::DataFrame as DataFrameColumn;
|
||||
pub use command::Command as DataFrame;
|
||||
pub use describe::DataFrame as DataFrameDescribe;
|
||||
pub use drop::DataFrame as DataFrameDrop;
|
||||
pub use drop_duplicates::DataFrame as DataFrameDropDuplicates;
|
||||
pub use drop_nulls::DataFrame as DataFrameDropNulls;
|
||||
@ -50,6 +53,7 @@ pub use list::DataFrame as DataFrameList;
|
||||
pub use melt::DataFrame as DataFrameMelt;
|
||||
pub use open::DataFrame as DataFrameOpen;
|
||||
pub use pivot::DataFrame as DataFramePivot;
|
||||
pub use rename::DataFrame as DataFrameRename;
|
||||
pub use sample::DataFrame as DataFrameSample;
|
||||
pub use select::DataFrame as DataFrameSelect;
|
||||
pub use shape::DataFrame as DataFrameShape;
|
||||
@ -73,6 +77,17 @@ pub use series::DataFrameArgTrue;
|
||||
pub use series::DataFrameArgUnique;
|
||||
pub use series::DataFrameConcatenate;
|
||||
pub use series::DataFrameContains;
|
||||
pub use series::DataFrameCumulative;
|
||||
pub use series::DataFrameGetDay;
|
||||
pub use series::DataFrameGetHour;
|
||||
pub use series::DataFrameGetMinute;
|
||||
pub use series::DataFrameGetMonth;
|
||||
pub use series::DataFrameGetNanoSecond;
|
||||
pub use series::DataFrameGetOrdinal;
|
||||
pub use series::DataFrameGetSecond;
|
||||
pub use series::DataFrameGetWeek;
|
||||
pub use series::DataFrameGetWeekDay;
|
||||
pub use series::DataFrameGetYear;
|
||||
pub use series::DataFrameIsDuplicated;
|
||||
pub use series::DataFrameIsIn;
|
||||
pub use series::DataFrameIsNotNull;
|
||||
@ -83,10 +98,12 @@ pub use series::DataFrameNUnique;
|
||||
pub use series::DataFrameNot;
|
||||
pub use series::DataFrameReplace;
|
||||
pub use series::DataFrameReplaceAll;
|
||||
pub use series::DataFrameRolling;
|
||||
pub use series::DataFrameSeriesRename;
|
||||
pub use series::DataFrameSet;
|
||||
pub use series::DataFrameSetWithIdx;
|
||||
pub use series::DataFrameShift;
|
||||
pub use series::DataFrameStrFTime;
|
||||
pub use series::DataFrameStringLengths;
|
||||
pub use series::DataFrameStringSlice;
|
||||
pub use series::DataFrameToLowercase;
|
||||
|
@ -8,7 +8,7 @@ use nu_protocol::{
|
||||
};
|
||||
|
||||
use nu_source::Tagged;
|
||||
use polars::prelude::{CsvEncoding, CsvReader, JsonReader, ParquetReader, PolarsError, SerReader};
|
||||
use polars::prelude::{CsvEncoding, CsvReader, JsonReader, ParquetReader, SerReader};
|
||||
use std::fs::File;
|
||||
|
||||
pub struct DataFrame;
|
||||
@ -206,15 +206,6 @@ fn from_csv(args: CommandArgs) -> Result<polars::prelude::DataFrame, ShellError>
|
||||
|
||||
match csv_reader.finish() {
|
||||
Ok(df) => Ok(df),
|
||||
Err(e) => match e {
|
||||
PolarsError::Other(_) => Err(ShellError::labeled_error_with_secondary(
|
||||
"Schema error",
|
||||
"Error with the inferred schema",
|
||||
&file.tag.span,
|
||||
"You can use the argument 'infer_schema' with a number of rows large enough to better infer the schema",
|
||||
&file.tag.span,
|
||||
)),
|
||||
_ => Err(parse_polars_error::<&str>(&e, &file.tag.span, None)),
|
||||
},
|
||||
Err(e) => Err(parse_polars_error::<&str>(&e, &file.tag.span, None)),
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let mut groupby = nu_groupby.to_groupby()?;
|
||||
|
||||
let pivot = groupby.pivot(pivot_col.item.as_ref(), value_col.item.as_ref());
|
||||
let pivot = groupby.pivot(&pivot_col.item, &value_col.item);
|
||||
|
||||
let res = match op {
|
||||
Operation::Mean => pivot.mean(),
|
||||
@ -120,7 +120,7 @@ fn check_pivot_column(
|
||||
col: &Tagged<String>,
|
||||
) -> Result<(), ShellError> {
|
||||
let series = df
|
||||
.column(col.item.as_ref())
|
||||
.column(&col.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &col.tag.span, None))?;
|
||||
|
||||
match series.dtype() {
|
||||
@ -146,7 +146,7 @@ fn check_value_column(
|
||||
col: &Tagged<String>,
|
||||
) -> Result<(), ShellError> {
|
||||
let series = df
|
||||
.column(col.item.as_ref())
|
||||
.column(&col.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &col.tag.span, None))?;
|
||||
|
||||
match series.dtype() {
|
||||
|
81
crates/nu-command/src/commands/dataframe/rename.rs
Normal file
81
crates/nu-command/src/commands/dataframe/rename.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, SyntaxShape, UntaggedValue,
|
||||
};
|
||||
|
||||
use nu_source::Tagged;
|
||||
|
||||
use super::utils::parse_polars_error;
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe rename-col"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[DataFrame] rename a dataframe column"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe rename-col")
|
||||
.required("from", SyntaxShape::String, "column name to be renamed")
|
||||
.required("to", SyntaxShape::String, "new column name")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Renames a dataframe column",
|
||||
example: "[[a b]; [1 2] [3 4]] | dataframe to-df | dataframe rename-col a ab",
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![
|
||||
Column::new(
|
||||
"ab".to_string(),
|
||||
vec![UntaggedValue::int(1).into(), UntaggedValue::int(3).into()],
|
||||
),
|
||||
Column::new(
|
||||
"b".to_string(),
|
||||
vec![UntaggedValue::int(2).into(), UntaggedValue::int(4).into()],
|
||||
),
|
||||
],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let from: Tagged<String> = args.req(0)?;
|
||||
let to: Tagged<String> = args.req(1)?;
|
||||
|
||||
let (mut df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
|
||||
df.as_mut()
|
||||
.rename(&from.item, &to.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
Ok(OutputStream::one(df.into_value(tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
@ -41,7 +41,7 @@ impl WholeStreamCommand for DataFrame {
|
||||
vec![
|
||||
Example {
|
||||
description: "Sample rows from dataframe",
|
||||
example: "[[a b]; [1 2] [3 4]] | dataframe to-df | dataframe sample -r 1",
|
||||
example: "[[a b]; [1 2] [3 4]] | dataframe to-df | dataframe sample -n 1",
|
||||
result: None, // No expected value because sampling is random
|
||||
},
|
||||
Example {
|
||||
|
@ -20,7 +20,7 @@ impl WholeStreamCommand for DataFrame {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe select").rest(SyntaxShape::Any, "selected column names")
|
||||
Signature::build("dataframe select").rest("rest", SyntaxShape::Any, "selected column names")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -16,7 +16,7 @@ impl WholeStreamCommand for DataFrame {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Checks if a patter is contained in a string"
|
||||
"[Series] Checks if a pattern is contained in a string"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
@ -33,7 +33,7 @@ impl WholeStreamCommand for DataFrame {
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns boolean indicating if patter was found",
|
||||
description: "Returns boolean indicating if pattern was found",
|
||||
example: "[abc acb acb] | dataframe to-df | dataframe contains ab",
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
@ -68,7 +68,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
})?;
|
||||
|
||||
let res = chunked
|
||||
.contains(pattern.as_str())
|
||||
.contains(&pattern.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &tag.span, None))?;
|
||||
|
||||
let df = NuDataFrame::try_from_series(vec![res.into_series()], &tag.span)?;
|
||||
|
127
crates/nu-command/src/commands/dataframe/series/cumulative.rs
Normal file
127
crates/nu-command/src/commands/dataframe/series/cumulative.rs
Normal file
@ -0,0 +1,127 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, SyntaxShape, UntaggedValue,
|
||||
};
|
||||
use nu_source::Tagged;
|
||||
use polars::prelude::DataType;
|
||||
|
||||
enum CumType {
|
||||
Min,
|
||||
Max,
|
||||
Sum,
|
||||
}
|
||||
|
||||
impl CumType {
|
||||
fn from_str(roll_type: &str, span: &Span) -> Result<Self, ShellError> {
|
||||
match roll_type {
|
||||
"min" => Ok(Self::Min),
|
||||
"max" => Ok(Self::Max),
|
||||
"sum" => Ok(Self::Sum),
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Wrong operation",
|
||||
"Operation not valid for cumulative",
|
||||
span,
|
||||
"Perhaps you want to use: max, min, sum",
|
||||
span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
CumType::Min => "cum_min",
|
||||
CumType::Max => "cum_max",
|
||||
CumType::Sum => "cum_sum",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe cum"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Cumulative calculation for a series"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe cum")
|
||||
.required("type", SyntaxShape::String, "rolling operation")
|
||||
.switch("reverse", "Reverse cumulative calculation", Some('r'))
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Cumulative sum for a series",
|
||||
example: "[1 2 3 4 5] | dataframe to-df | dataframe cum sum",
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0_cum_sum".to_string(),
|
||||
vec![
|
||||
UntaggedValue::int(1).into(),
|
||||
UntaggedValue::int(3).into(),
|
||||
UntaggedValue::int(6).into(),
|
||||
UntaggedValue::int(10).into(),
|
||||
UntaggedValue::int(15).into(),
|
||||
],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let cum_type: Tagged<String> = args.req(0)?;
|
||||
let reverse = args.has_flag("reverse");
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
if let DataType::Object(_) = series.dtype() {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Found object series",
|
||||
"Series of type object cannot be used for cumulative operation",
|
||||
&df_tag.span,
|
||||
));
|
||||
}
|
||||
|
||||
let cum_type = CumType::from_str(&cum_type.item, &cum_type.tag.span)?;
|
||||
let mut res = match cum_type {
|
||||
CumType::Max => series.cummax(reverse),
|
||||
CumType::Min => series.cummin(reverse),
|
||||
CumType::Sum => series.cumsum(reverse),
|
||||
};
|
||||
|
||||
let name = format!("{}_{}", series.name(), cum_type.to_str());
|
||||
res.rename(&name);
|
||||
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
75
crates/nu-command/src/commands/dataframe/series/get_day.rs
Normal file
75
crates/nu-command/src/commands/dataframe/series/get_day.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, UntaggedValue,
|
||||
};
|
||||
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe get-day"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Gets day from date"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get-day")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns day from a date",
|
||||
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | str to-datetime -z 'UTC');
|
||||
let df = ([$dt $dt] | dataframe to-df);
|
||||
$df | dataframe get-day"#,
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![UntaggedValue::int(4).into(), UntaggedValue::int(4).into()],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
let casted = series
|
||||
.datetime()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.day().into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
75
crates/nu-command/src/commands/dataframe/series/get_hour.rs
Normal file
75
crates/nu-command/src/commands/dataframe/series/get_hour.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, UntaggedValue,
|
||||
};
|
||||
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe get-hour"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Gets hour from date"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get-hour")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns hour from a date",
|
||||
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | str to-datetime -z 'UTC');
|
||||
let df = ([$dt $dt] | dataframe to-df);
|
||||
$df | dataframe get-hour"#,
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![UntaggedValue::int(16).into(), UntaggedValue::int(16).into()],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
let casted = series
|
||||
.datetime()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.hour().into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, UntaggedValue,
|
||||
};
|
||||
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe get-minute"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Gets minute from date"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get-minute")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns minute from a date",
|
||||
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | str to-datetime -z 'UTC');
|
||||
let df = ([$dt $dt] | dataframe to-df);
|
||||
$df | dataframe get-minute"#,
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![UntaggedValue::int(39).into(), UntaggedValue::int(39).into()],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
let casted = series
|
||||
.datetime()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.minute().into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
75
crates/nu-command/src/commands/dataframe/series/get_month.rs
Normal file
75
crates/nu-command/src/commands/dataframe/series/get_month.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, UntaggedValue,
|
||||
};
|
||||
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe get-month"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Gets month from date"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get-month")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns month from a date",
|
||||
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | str to-datetime -z 'UTC');
|
||||
let df = ([$dt $dt] | dataframe to-df);
|
||||
$df | dataframe get-month"#,
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![UntaggedValue::int(8).into(), UntaggedValue::int(8).into()],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
let casted = series
|
||||
.datetime()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.month().into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, UntaggedValue,
|
||||
};
|
||||
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe get-nanosecond"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Gets nanosecond from date"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get-nanosecond")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns nanosecond from a date",
|
||||
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | str to-datetime -z 'UTC');
|
||||
let df = ([$dt $dt] | dataframe to-df);
|
||||
$df | dataframe get-nanosecond"#,
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![UntaggedValue::int(0).into(), UntaggedValue::int(0).into()],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
let casted = series
|
||||
.datetime()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.nanosecond().into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, UntaggedValue,
|
||||
};
|
||||
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe get-ordinal"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Gets ordinal date from date"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get-ordinal")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns ordinal from a date",
|
||||
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | str to-datetime -z 'UTC');
|
||||
let df = ([$dt $dt] | dataframe to-df);
|
||||
$df | dataframe get-ordinal"#,
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![
|
||||
UntaggedValue::int(217).into(),
|
||||
UntaggedValue::int(217).into(),
|
||||
],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
let casted = series
|
||||
.datetime()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.ordinal().into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, UntaggedValue,
|
||||
};
|
||||
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe get-second"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Gets second from date"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get-second")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns second from a date",
|
||||
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | str to-datetime -z 'UTC');
|
||||
let df = ([$dt $dt] | dataframe to-df);
|
||||
$df | dataframe get-second"#,
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![UntaggedValue::int(18).into(), UntaggedValue::int(18).into()],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
let casted = series
|
||||
.datetime()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.second().into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
75
crates/nu-command/src/commands/dataframe/series/get_week.rs
Normal file
75
crates/nu-command/src/commands/dataframe/series/get_week.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, UntaggedValue,
|
||||
};
|
||||
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe get-week"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Gets week from date"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get-week")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns week from a date",
|
||||
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | str to-datetime -z 'UTC');
|
||||
let df = ([$dt $dt] | dataframe to-df);
|
||||
$df | dataframe get-week"#,
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![UntaggedValue::int(32).into(), UntaggedValue::int(32).into()],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
let casted = series
|
||||
.datetime()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.week().into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, UntaggedValue,
|
||||
};
|
||||
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe get-weekday"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Gets weekday from date"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get-weekday")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns weekday from a date",
|
||||
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | str to-datetime -z 'UTC');
|
||||
let df = ([$dt $dt] | dataframe to-df);
|
||||
$df | dataframe get-weekday"#,
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![UntaggedValue::int(1).into(), UntaggedValue::int(1).into()],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
let casted = series
|
||||
.datetime()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.weekday().into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
78
crates/nu-command/src/commands/dataframe/series/get_year.rs
Normal file
78
crates/nu-command/src/commands/dataframe/series/get_year.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, UntaggedValue,
|
||||
};
|
||||
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe get-year"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Gets year from date"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get-year")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns year from a date",
|
||||
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | str to-datetime -z 'UTC');
|
||||
let df = ([$dt $dt] | dataframe to-df);
|
||||
$df | dataframe get-year"#,
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![
|
||||
UntaggedValue::int(2020).into(),
|
||||
UntaggedValue::int(2020).into(),
|
||||
],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
let casted = series
|
||||
.datetime()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.year().into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
@ -7,6 +7,17 @@ pub mod arg_true;
|
||||
pub mod arg_unique;
|
||||
pub mod concatenate;
|
||||
pub mod contains;
|
||||
pub mod cumulative;
|
||||
pub mod get_day;
|
||||
pub mod get_hour;
|
||||
pub mod get_minute;
|
||||
pub mod get_month;
|
||||
pub mod get_nanosecond;
|
||||
pub mod get_ordinal;
|
||||
pub mod get_second;
|
||||
pub mod get_week;
|
||||
pub mod get_weekday;
|
||||
pub mod get_year;
|
||||
pub mod is_duplicated;
|
||||
pub mod is_in;
|
||||
pub mod is_not_null;
|
||||
@ -18,11 +29,13 @@ pub mod not;
|
||||
pub mod rename;
|
||||
pub mod replace;
|
||||
pub mod replace_all;
|
||||
pub mod rolling;
|
||||
pub mod set;
|
||||
pub mod set_with_idx;
|
||||
pub mod shift;
|
||||
pub mod str_lengths;
|
||||
pub mod str_slice;
|
||||
pub mod strftime;
|
||||
pub mod to_lowercase;
|
||||
pub mod to_uppercase;
|
||||
pub mod unique;
|
||||
@ -37,6 +50,17 @@ pub use arg_true::DataFrame as DataFrameArgTrue;
|
||||
pub use arg_unique::DataFrame as DataFrameArgUnique;
|
||||
pub use concatenate::DataFrame as DataFrameConcatenate;
|
||||
pub use contains::DataFrame as DataFrameContains;
|
||||
pub use cumulative::DataFrame as DataFrameCumulative;
|
||||
pub use get_day::DataFrame as DataFrameGetDay;
|
||||
pub use get_hour::DataFrame as DataFrameGetHour;
|
||||
pub use get_minute::DataFrame as DataFrameGetMinute;
|
||||
pub use get_month::DataFrame as DataFrameGetMonth;
|
||||
pub use get_nanosecond::DataFrame as DataFrameGetNanoSecond;
|
||||
pub use get_ordinal::DataFrame as DataFrameGetOrdinal;
|
||||
pub use get_second::DataFrame as DataFrameGetSecond;
|
||||
pub use get_week::DataFrame as DataFrameGetWeek;
|
||||
pub use get_weekday::DataFrame as DataFrameGetWeekDay;
|
||||
pub use get_year::DataFrame as DataFrameGetYear;
|
||||
pub use is_duplicated::DataFrame as DataFrameIsDuplicated;
|
||||
pub use is_in::DataFrame as DataFrameIsIn;
|
||||
pub use is_not_null::DataFrame as DataFrameIsNotNull;
|
||||
@ -48,11 +72,13 @@ pub use not::DataFrame as DataFrameNot;
|
||||
pub use rename::DataFrame as DataFrameSeriesRename;
|
||||
pub use replace::DataFrame as DataFrameReplace;
|
||||
pub use replace_all::DataFrame as DataFrameReplaceAll;
|
||||
pub use rolling::DataFrame as DataFrameRolling;
|
||||
pub use set::DataFrame as DataFrameSet;
|
||||
pub use set_with_idx::DataFrame as DataFrameSetWithIdx;
|
||||
pub use shift::DataFrame as DataFrameShift;
|
||||
pub use str_lengths::DataFrame as DataFrameStringLengths;
|
||||
pub use str_slice::DataFrame as DataFrameStringSlice;
|
||||
pub use strftime::DataFrame as DataFrameStrFTime;
|
||||
pub use to_lowercase::DataFrame as DataFrameToLowercase;
|
||||
pub use to_uppercase::DataFrame as DataFrameToUppercase;
|
||||
pub use unique::DataFrame as DataFrameUnique;
|
||||
|
@ -60,7 +60,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let mut series = df.as_series(&df_tag.span)?;
|
||||
|
||||
series.rename(name.item.as_ref());
|
||||
series.rename(&name.item);
|
||||
|
||||
let df = NuDataFrame::try_from_series(vec![series], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
|
@ -77,7 +77,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
})?;
|
||||
|
||||
let mut res = chunked
|
||||
.replace(pattern.as_str(), replace.as_str())
|
||||
.replace(&pattern.item, &replace.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &tag.span, None))?;
|
||||
|
||||
res.rename(series.name());
|
||||
|
@ -77,7 +77,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
})?;
|
||||
|
||||
let mut res = chunked
|
||||
.replace_all(pattern.as_str(), replace.as_str())
|
||||
.replace_all(&pattern.item, &replace.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &tag.span, None))?;
|
||||
|
||||
res.rename(series.name());
|
||||
|
160
crates/nu-command/src/commands/dataframe/series/rolling.rs
Normal file
160
crates/nu-command/src/commands/dataframe/series/rolling.rs
Normal file
@ -0,0 +1,160 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, SyntaxShape, UntaggedValue,
|
||||
};
|
||||
use nu_source::Tagged;
|
||||
use polars::prelude::{DataType, RollingOptions};
|
||||
|
||||
enum RollType {
|
||||
Min,
|
||||
Max,
|
||||
Sum,
|
||||
Mean,
|
||||
}
|
||||
|
||||
impl RollType {
|
||||
fn from_str(roll_type: &str, span: &Span) -> Result<Self, ShellError> {
|
||||
match roll_type {
|
||||
"min" => Ok(Self::Min),
|
||||
"max" => Ok(Self::Max),
|
||||
"sum" => Ok(Self::Sum),
|
||||
"mean" => Ok(Self::Mean),
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Wrong operation",
|
||||
"Operation not valid for rolling",
|
||||
span,
|
||||
"Perhaps you want to use: max, min, sum, mean",
|
||||
span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
RollType::Min => "rolling_min",
|
||||
RollType::Max => "rolling_max",
|
||||
RollType::Sum => "rolling_sum",
|
||||
RollType::Mean => "rolling_mean",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe rolling"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Rolling calculation for a series"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe rolling")
|
||||
.required("type", SyntaxShape::String, "rolling operation")
|
||||
.required("window", SyntaxShape::Int, "Window size for rolling")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Rolling sum for a series",
|
||||
example:
|
||||
"[1 2 3 4 5] | dataframe to-df | dataframe rolling sum 2 | dataframe drop-nulls",
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0_rolling_sum".to_string(),
|
||||
vec![
|
||||
UntaggedValue::int(3).into(),
|
||||
UntaggedValue::int(5).into(),
|
||||
UntaggedValue::int(7).into(),
|
||||
UntaggedValue::int(9).into(),
|
||||
],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
},
|
||||
Example {
|
||||
description: "Rolling max for a series",
|
||||
example:
|
||||
"[1 2 3 4 5] | dataframe to-df | dataframe rolling max 2 | dataframe drop-nulls",
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0_rolling_max".to_string(),
|
||||
vec![
|
||||
UntaggedValue::int(2).into(),
|
||||
UntaggedValue::int(3).into(),
|
||||
UntaggedValue::int(4).into(),
|
||||
UntaggedValue::int(5).into(),
|
||||
],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let roll_type: Tagged<String> = args.req(0)?;
|
||||
let window_size: Tagged<i64> = args.req(1)?;
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
if let DataType::Object(_) = series.dtype() {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Found object series",
|
||||
"Series of type object cannot be used for rolling operation",
|
||||
&df_tag.span,
|
||||
));
|
||||
}
|
||||
|
||||
let roll_type = RollType::from_str(&roll_type.item, &roll_type.tag.span)?;
|
||||
let rolling_opts = RollingOptions {
|
||||
window_size: window_size.item as usize,
|
||||
min_periods: window_size.item as usize,
|
||||
weights: None,
|
||||
center: false,
|
||||
};
|
||||
let res = match roll_type {
|
||||
RollType::Max => series.rolling_max(rolling_opts),
|
||||
RollType::Min => series.rolling_min(rolling_opts),
|
||||
RollType::Sum => series.rolling_sum(rolling_opts),
|
||||
RollType::Mean => series.rolling_mean(rolling_opts),
|
||||
};
|
||||
|
||||
let mut res = res.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let name = format!("{}_{}", series.name(), roll_type.to_str());
|
||||
res.rename(&name);
|
||||
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
@ -78,7 +78,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let casted = match indices.dtype() {
|
||||
DataType::UInt32 | DataType::UInt64 | DataType::Int32 | DataType::Int64 => indices
|
||||
.as_ref()
|
||||
.cast_with_dtype(&DataType::UInt32)
|
||||
.cast(&DataType::UInt32)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &value.tag.span, None)),
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Incorrect type",
|
||||
|
80
crates/nu-command/src/commands/dataframe/series/strftime.rs
Normal file
80
crates/nu-command/src/commands/dataframe/series/strftime.rs
Normal file
@ -0,0 +1,80 @@
|
||||
use crate::{commands::dataframe::utils::parse_polars_error, prelude::*};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, SyntaxShape, UntaggedValue,
|
||||
};
|
||||
|
||||
use nu_source::Tagged;
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe strftime"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[Series] Formats date based on string rule"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe strftime").required("fmt", SyntaxShape::String, "Format rule")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Formats date",
|
||||
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | str to-datetime -z 'UTC');
|
||||
let df = ([$dt $dt] | dataframe to-df);
|
||||
$df | dataframe strftime "%Y/%m/%d""#,
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![
|
||||
UntaggedValue::string("2020/08/04").into(),
|
||||
UntaggedValue::string("2020/08/04").into(),
|
||||
],
|
||||
)],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let fmt: Tagged<String> = args.req(0)?;
|
||||
|
||||
let (df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let series = df.as_series(&df_tag.span)?;
|
||||
|
||||
let casted = series
|
||||
.datetime()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.strftime(&fmt.item).into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ impl WholeStreamCommand for DataFrame {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe sort")
|
||||
.switch("reverse", "invert sort", Some('r'))
|
||||
.rest(SyntaxShape::Any, "column names to sort dataframe")
|
||||
.rest("rest", SyntaxShape::Any, "column names to sort dataframe")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -92,7 +92,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let casted = match series.dtype() {
|
||||
DataType::UInt32 | DataType::UInt64 | DataType::Int32 | DataType::Int64 => series
|
||||
.as_ref()
|
||||
.cast_with_dtype(&DataType::UInt32)
|
||||
.cast(&DataType::UInt32)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &value.tag.span, None)),
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Incorrect type",
|
||||
@ -111,9 +111,12 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
ShellError::labeled_error("Empty stream", "No value found in the stream", &tag)
|
||||
})?;
|
||||
|
||||
match value.value {
|
||||
match &value.value {
|
||||
UntaggedValue::DataFrame(df) => {
|
||||
let res = df.as_ref().take(indices);
|
||||
let res = df
|
||||
.as_ref()
|
||||
.take(indices)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &value.tag.span, None))?;
|
||||
|
||||
Ok(OutputStream::one(NuDataFrame::dataframe_to_value(res, tag)))
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ impl WholeStreamCommand for DataFrame {
|
||||
vec![
|
||||
Example {
|
||||
description: "Saves dataframe to csv file",
|
||||
example: "[[a b]; [1 2] [3 4]] | dataframe to-df | dataframe to_csv test.csv",
|
||||
example: "[[a b]; [1 2] [3 4]] | dataframe to-df | dataframe to-csv test.csv",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
@ -64,22 +64,18 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let delimiter: Option<Tagged<String>> = args.get_flag("delimiter")?;
|
||||
let no_header: bool = args.has_flag("no_header");
|
||||
|
||||
let (mut df, _) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let (df, _) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
|
||||
let mut file = File::create(&file_name.item).map_err(|e| {
|
||||
ShellError::labeled_error(
|
||||
"Error with file name",
|
||||
format!("{}", e),
|
||||
&file_name.tag.span,
|
||||
)
|
||||
ShellError::labeled_error("Error with file name", e.to_string(), &file_name.tag.span)
|
||||
})?;
|
||||
|
||||
let writer = CsvWriter::new(&mut file);
|
||||
|
||||
let writer = if no_header {
|
||||
writer.has_headers(false)
|
||||
writer.has_header(false)
|
||||
} else {
|
||||
writer.has_headers(true)
|
||||
writer.has_header(true)
|
||||
};
|
||||
|
||||
let writer = match delimiter {
|
||||
@ -103,7 +99,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
};
|
||||
|
||||
writer
|
||||
.finish(df.as_mut())
|
||||
.finish(df.as_ref())
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &file_name.tag.span, None))?;
|
||||
|
||||
let tagged_value = Value {
|
||||
|
@ -48,18 +48,14 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let file_name: Tagged<PathBuf> = args.req(0)?;
|
||||
|
||||
let (mut df, _) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let (df, _) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
|
||||
let file = File::create(&file_name.item).map_err(|e| {
|
||||
ShellError::labeled_error(
|
||||
"Error with file name",
|
||||
format!("{}", e),
|
||||
&file_name.tag.span,
|
||||
)
|
||||
ShellError::labeled_error("Error with file name", e.to_string(), &file_name.tag.span)
|
||||
})?;
|
||||
|
||||
ParquetWriter::new(file)
|
||||
.finish(df.as_mut())
|
||||
.finish(df.as_ref())
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &file_name.tag.span, None))?;
|
||||
|
||||
let tagged_value = Value {
|
||||
|
@ -46,30 +46,31 @@ pub(crate) fn parse_polars_error<T: AsRef<str>>(
|
||||
span: &Span,
|
||||
secondary: Option<T>,
|
||||
) -> ShellError {
|
||||
let (msg, label) = match e {
|
||||
PolarsError::PolarsArrowError(_) => ("PolarsArrow Error", format!("{}", e)),
|
||||
PolarsError::ArrowError(_) => ("Arrow Error", format!("{}", e)),
|
||||
PolarsError::InvalidOperation(_) => ("Invalid Operation", format!("{}", e)),
|
||||
PolarsError::DataTypeMisMatch(_) => ("Data Type Mismatch", format!("{}", e)),
|
||||
PolarsError::NotFound(_) => ("Not Found", format!("{}", e)),
|
||||
PolarsError::ShapeMisMatch(_) => ("Shape Mismatch", format!("{}", e)),
|
||||
PolarsError::Other(_) => ("Other", format!("{}", e)),
|
||||
PolarsError::OutOfBounds(_) => ("Out Of Bounds", format!("{}", e)),
|
||||
PolarsError::NoSlice => ("No Slice", format!("{}", e)),
|
||||
PolarsError::NoData(_) => ("No Data", format!("{}", e)),
|
||||
PolarsError::ValueError(_) => ("Value Error", format!("{}", e)),
|
||||
PolarsError::MemoryNotAligned => ("Memory Not Aligned", format!("{}", e)),
|
||||
PolarsError::ParquetError(_) => ("Parquet Error", format!("{}", e)),
|
||||
PolarsError::RandError(_) => ("Rand Error", format!("{}", e)),
|
||||
PolarsError::HasNullValues(_) => ("Has Null Values", format!("{}", e)),
|
||||
PolarsError::UnknownSchema(_) => ("Unknown Schema", format!("{}", e)),
|
||||
PolarsError::Various(_) => ("Various", format!("{}", e)),
|
||||
PolarsError::Io(_) => ("Io Error", format!("{}", e)),
|
||||
PolarsError::Regex(_) => ("Regex Error", format!("{}", e)),
|
||||
PolarsError::Duplicate(_) => ("Duplicate Error", format!("{}", e)),
|
||||
PolarsError::ImplementationError => ("Implementation Error", format!("{}", e)),
|
||||
let msg = match e {
|
||||
PolarsError::PolarsArrowError(_) => "PolarsArrow Error",
|
||||
PolarsError::ArrowError(_) => "Arrow Error",
|
||||
PolarsError::InvalidOperation(_) => "Invalid Operation",
|
||||
PolarsError::DataTypeMisMatch(_) => "Data Type Mismatch",
|
||||
PolarsError::NotFound(_) => "Not Found",
|
||||
PolarsError::ShapeMisMatch(_) => "Shape Mismatch",
|
||||
PolarsError::ComputeError(_) => "Computer error",
|
||||
PolarsError::OutOfBounds(_) => "Out Of Bounds",
|
||||
PolarsError::NoSlice => "No Slice",
|
||||
PolarsError::NoData(_) => "No Data",
|
||||
PolarsError::ValueError(_) => "Value Error",
|
||||
PolarsError::MemoryNotAligned => "Memory Not Aligned",
|
||||
PolarsError::RandError(_) => "Rand Error",
|
||||
PolarsError::HasNullValues(_) => "Has Null Values",
|
||||
PolarsError::UnknownSchema(_) => "Unknown Schema",
|
||||
PolarsError::Various(_) => "Various",
|
||||
PolarsError::Io(_) => "Io Error",
|
||||
PolarsError::Regex(_) => "Regex Error",
|
||||
PolarsError::Duplicate(_) => "Duplicate Error",
|
||||
PolarsError::ImplementationError => "Implementation Error",
|
||||
};
|
||||
|
||||
let label = e.to_string();
|
||||
|
||||
match secondary {
|
||||
None => ShellError::labeled_error(msg, label, span),
|
||||
Some(s) => ShellError::labeled_error_with_secondary(msg, label, span, s.as_ref(), span),
|
||||
|
@ -82,7 +82,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let mut series = df.as_series(&value.tag.span)?;
|
||||
|
||||
let series = series.rename(name.item.as_ref()).clone();
|
||||
let series = series.rename(&name.item).clone();
|
||||
|
||||
let (mut df, _) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
|
||||
|
@ -31,12 +31,12 @@ impl WholeStreamCommand for AutoenvTrust {
|
||||
value: UntaggedValue::Primitive(Primitive::String(ref path)),
|
||||
tag: _,
|
||||
}) => {
|
||||
let mut dir = fs::canonicalize(path)?;
|
||||
let mut dir = nu_path::canonicalize(path)?;
|
||||
dir.push(".nu-env");
|
||||
dir
|
||||
}
|
||||
_ => {
|
||||
let mut dir = fs::canonicalize(std::env::current_dir()?)?;
|
||||
let mut dir = nu_path::canonicalize(std::env::current_dir()?)?;
|
||||
dir.push(".nu-env");
|
||||
dir
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ impl WholeStreamCommand for AutoenvUntrust {
|
||||
value: UntaggedValue::Primitive(Primitive::String(ref path)),
|
||||
tag: _,
|
||||
}) => {
|
||||
let mut dir = fs::canonicalize(path)?;
|
||||
let mut dir = nu_path::canonicalize(path)?;
|
||||
dir.push(".nu-env");
|
||||
dir
|
||||
}
|
||||
@ -61,7 +61,7 @@ impl WholeStreamCommand for AutoenvUntrust {
|
||||
let mut doc = String::new();
|
||||
file.read_to_string(&mut doc)?;
|
||||
|
||||
let mut allowed: Trusted = toml::from_str(doc.as_str()).unwrap_or_else(|_| Trusted::new());
|
||||
let mut allowed: Trusted = toml::from_str(&doc).unwrap_or_else(|_| Trusted::new());
|
||||
|
||||
let file_to_untrust = file_to_untrust.to_string_lossy().to_string();
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use crate::prelude::*;
|
||||
use nu_engine::{evaluate_baseline_expr, WholeStreamCommand};
|
||||
use nu_engine::{evaluate_baseline_expr, EnvVar, WholeStreamCommand};
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{hir::CapturedBlock, hir::ClassifiedCommand, Signature, SyntaxShape};
|
||||
@ -90,9 +92,7 @@ pub fn set_env(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
|
||||
ctx.scope.exit_scope();
|
||||
|
||||
let value = value?;
|
||||
let value = value.as_string()?;
|
||||
|
||||
let value: EnvVar = value?.try_into()?;
|
||||
let name = name.item;
|
||||
|
||||
// Note: this is a special case for setting the context from a command
|
||||
|
13
crates/nu-command/src/commands/env/load_env.rs
vendored
13
crates/nu-command/src/commands/env/load_env.rs
vendored
@ -1,5 +1,7 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_engine::{EnvVar, WholeStreamCommand};
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape, Value};
|
||||
@ -60,14 +62,17 @@ fn load_env_from_table(
|
||||
|
||||
for (key, value) in value.row_entries() {
|
||||
if key == "name" {
|
||||
var_name = Some(value.as_string()?);
|
||||
var_name = Some(value);
|
||||
} else if key == "value" {
|
||||
var_value = Some(value.as_string()?);
|
||||
var_value = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
match (var_name, var_value) {
|
||||
(Some(name), Some(value)) => ctx.scope.add_env_var(name, value),
|
||||
(Some(name), Some(value)) => {
|
||||
let env_var: EnvVar = value.try_into()?;
|
||||
ctx.scope.add_env_var(name.as_string()?, env_var);
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
r#"Expected each row in the table to have a "name" and "value" field."#,
|
||||
|
11
crates/nu-command/src/commands/env/with_env.rs
vendored
11
crates/nu-command/src/commands/env/with_env.rs
vendored
@ -1,5 +1,8 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use crate::prelude::*;
|
||||
use nu_engine::run_block;
|
||||
use nu_engine::EnvVar;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
@ -73,20 +76,20 @@ fn with_env(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
let variable: Value = args.req(0)?;
|
||||
let block: CapturedBlock = args.req(1)?;
|
||||
|
||||
let mut env = IndexMap::new();
|
||||
let mut env: IndexMap<String, EnvVar> = IndexMap::new();
|
||||
|
||||
match &variable.value {
|
||||
UntaggedValue::Table(table) => {
|
||||
if table.len() == 1 {
|
||||
// single row([[X W]; [Y Z]])
|
||||
for (k, v) in table[0].row_entries() {
|
||||
env.insert(k.clone(), v.convert_to_string());
|
||||
env.insert(k.clone(), v.try_into()?);
|
||||
}
|
||||
} else {
|
||||
// primitive values([X Y W Z])
|
||||
for row in table.chunks(2) {
|
||||
if row.len() == 2 && row[0].is_primitive() && row[1].is_primitive() {
|
||||
env.insert(row[0].convert_to_string(), row[1].convert_to_string());
|
||||
env.insert(row[0].convert_to_string(), (&row[1]).try_into()?);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,7 +97,7 @@ fn with_env(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
// when get object by `open x.json` or `from json`
|
||||
UntaggedValue::Row(row) => {
|
||||
for (k, v) in &row.entries {
|
||||
env.insert(k.clone(), v.convert_to_string());
|
||||
env.insert(k.clone(), v.try_into()?);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -12,6 +12,7 @@ impl WholeStreamCommand for Mkdir {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("mkdir")
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::FilePath,
|
||||
"the name(s) of the path(s) to create",
|
||||
)
|
||||
|
@ -6,6 +6,7 @@ use log::debug;
|
||||
use nu_engine::StringOrBinary;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_path::canonicalize;
|
||||
use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::{AnchorLocation, Span, Tagged};
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -172,9 +173,9 @@ fn open(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
Ok(StringOrBinary::String(s)) => {
|
||||
ReturnSuccess::value(UntaggedValue::string(s).into_value(file_tag))
|
||||
}
|
||||
Ok(StringOrBinary::Binary(b)) => ReturnSuccess::value(
|
||||
UntaggedValue::binary(b.into_iter().collect()).into_value(file_tag),
|
||||
),
|
||||
Ok(StringOrBinary::Binary(b)) => {
|
||||
ReturnSuccess::value(UntaggedValue::binary(b).into_value(file_tag))
|
||||
}
|
||||
Err(se) => Err(se),
|
||||
}
|
||||
});
|
||||
@ -193,7 +194,7 @@ pub fn fetch(
|
||||
// TODO: I don't understand the point of this? Maybe for better error reporting
|
||||
let mut cwd = PathBuf::from(cwd);
|
||||
cwd.push(location);
|
||||
let nice_location = dunce::canonicalize(&cwd).map_err(|e| match e.kind() {
|
||||
let nice_location = canonicalize(&cwd).map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::NotFound => ShellError::labeled_error(
|
||||
format!("Cannot find file {:?}", cwd),
|
||||
"cannot find file",
|
||||
|
@ -26,7 +26,11 @@ impl WholeStreamCommand for Remove {
|
||||
)
|
||||
.switch("recursive", "delete subdirectories recursively", Some('r'))
|
||||
.switch("force", "suppress error when no file", Some('f'))
|
||||
.rest(SyntaxShape::GlobPattern, "the file path(s) to remove")
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::GlobPattern,
|
||||
"the file path(s) to remove",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -142,6 +142,7 @@ impl WholeStreamCommand for Save {
|
||||
"treat values as-is rather than auto-converting based on file extension",
|
||||
Some('r'),
|
||||
)
|
||||
.switch("append", "append values rather than overriding", Some('a'))
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -165,6 +166,7 @@ fn save(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let path: Option<Tagged<PathBuf>> = args.opt(0)?;
|
||||
let save_raw = args.has_flag("raw");
|
||||
let append = args.has_flag("append");
|
||||
|
||||
let input: Vec<Value> = args.input.collect();
|
||||
if path.is_none() {
|
||||
@ -231,7 +233,7 @@ fn save(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
};
|
||||
};
|
||||
|
||||
shell_manager.save(&full_path, &content?, name.span)
|
||||
shell_manager.save(&full_path, &content?, name.span, append)
|
||||
}
|
||||
|
||||
fn string_from(input: &[Value]) -> String {
|
||||
@ -239,7 +241,7 @@ fn string_from(input: &[Value]) -> String {
|
||||
|
||||
if !input.is_empty() {
|
||||
let mut first = true;
|
||||
for i in input.iter() {
|
||||
for i in input {
|
||||
if !first {
|
||||
save_data.push('\n');
|
||||
} else {
|
||||
|
@ -19,7 +19,7 @@ impl WholeStreamCommand for Touch {
|
||||
SyntaxShape::FilePath,
|
||||
"the path of the file you want to create",
|
||||
)
|
||||
.rest(SyntaxShape::FilePath, "additional files to create")
|
||||
.rest("rest", SyntaxShape::FilePath, "additional files to create")
|
||||
}
|
||||
fn usage(&self) -> &str {
|
||||
"Creates one or more files."
|
||||
@ -48,7 +48,7 @@ fn touch(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
let target: Tagged<PathBuf> = args.req(0)?;
|
||||
let rest: Vec<Tagged<PathBuf>> = args.rest(1)?;
|
||||
|
||||
for item in vec![target].into_iter().chain(rest.into_iter()) {
|
||||
for item in vec![target].into_iter().chain(rest) {
|
||||
match OpenOptions::new().write(true).create(true).open(&item) {
|
||||
Ok(_) => continue,
|
||||
Err(err) => {
|
||||
|
@ -45,7 +45,7 @@ impl WholeStreamCommand for Command {
|
||||
|
||||
Ok(prepend
|
||||
.into_iter()
|
||||
.chain(args.input.into_iter().chain(vec![value]))
|
||||
.chain(args.input.into_iter().chain([value]))
|
||||
.into_output_stream())
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user