mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
Merge branch 'sxyazi:main' into feat/independent-style-on-inner-section-of-status
This commit is contained in:
commit
f5effc8845
139 changed files with 1940 additions and 1237 deletions
27
.github/workflows/cachix.yml
vendored
Normal file
27
.github/workflows/cachix.yml
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
name: Cachix
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish Flake
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v25
|
||||
|
||||
- name: Authenticate with Cachix
|
||||
uses: cachix/cachix-action@v14
|
||||
with:
|
||||
name: yazi
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Build Flake
|
||||
run: nix build -L
|
||||
122
.github/workflows/release.yml
vendored
122
.github/workflows/release.yml
vendored
|
|
@ -6,9 +6,7 @@ on:
|
|||
- "v[0-9]+.[0-9]+.[0-9]+"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
permissions:
|
||||
contents: write
|
||||
build-unix:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
|
|
@ -20,6 +18,27 @@ jobs:
|
|||
target: x86_64-apple-darwin
|
||||
- os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install gcc-aarch64-linux-gnu
|
||||
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
||||
run: sudo apt-get update && sudo apt-get install -yq gcc-aarch64-linux-gnu
|
||||
|
||||
- name: Build
|
||||
run: ./scripts/build.sh ${{ matrix.target }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: yazi-${{ matrix.target }}.zip
|
||||
path: yazi-${{ matrix.target }}.zip
|
||||
|
||||
build-windows:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
- os: windows-latest
|
||||
|
|
@ -31,57 +50,92 @@ jobs:
|
|||
- name: Setup Rust toolchain
|
||||
run: rustup toolchain install stable --profile minimal
|
||||
|
||||
- name: Add aarch64 target
|
||||
if: contains(fromJson('["aarch64-unknown-linux-gnu", "aarch64-apple-darwin", "aarch64-pc-windows-msvc"]'), matrix.target)
|
||||
- name: Add target
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
|
||||
- name: Install gcc-aarch64-linux-gnu
|
||||
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -yq gcc-aarch64-linux-gnu
|
||||
|
||||
- name: Setup Rust cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
YAZI_GEN_COMPLETIONS: true
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: /usr/bin/aarch64-linux-gnu-gcc
|
||||
run: cargo build --release --locked --target ${{ matrix.target }}
|
||||
|
||||
- name: Build snap
|
||||
if: matrix.target == 'x86_64-unknown-linux-gnu'
|
||||
uses: snapcore/action-build@v1
|
||||
|
||||
- name: Pack artifacts [Linux & macOS]
|
||||
if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'
|
||||
env:
|
||||
TARGET_NAME: yazi-${{ matrix.target }}
|
||||
run: |
|
||||
mkdir $TARGET_NAME
|
||||
cp target/${{ matrix.target }}/release/yazi $TARGET_NAME
|
||||
cp -r yazi-config/completions $TARGET_NAME
|
||||
cp README.md LICENSE $TARGET_NAME
|
||||
zip -r $TARGET_NAME.zip $TARGET_NAME
|
||||
|
||||
- name: Pack artifacts [Windows]
|
||||
- name: Pack artifact
|
||||
if: matrix.os == 'windows-latest'
|
||||
env:
|
||||
TARGET_NAME: yazi-${{ matrix.target }}
|
||||
run: |
|
||||
New-Item -ItemType Directory -Path ${env:TARGET_NAME}
|
||||
Copy-Item -Path "target\${{ matrix.target }}\release\yazi.exe" -Destination ${env:TARGET_NAME}
|
||||
Copy-Item -Path "yazi-config\completions" -Destination ${env:TARGET_NAME} -Recurse
|
||||
Copy-Item -Path "yazi-boot\completions" -Destination ${env:TARGET_NAME} -Recurse
|
||||
Copy-Item -Path "README.md", "LICENSE" -Destination ${env:TARGET_NAME}
|
||||
Compress-Archive -Path ${env:TARGET_NAME} -DestinationPath "${env:TARGET_NAME}.zip"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: yazi-${{ matrix.target }}.zip
|
||||
path: yazi-${{ matrix.target }}.zip
|
||||
|
||||
build-musl:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-unknown-linux-musl
|
||||
image: rust-musl-cross:x86_64-musl
|
||||
- target: aarch64-unknown-linux-musl
|
||||
image: rust-musl-cross:aarch64-musl
|
||||
container:
|
||||
image: docker://ghcr.io/rust-cross/${{ matrix.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
run: ./scripts/build.sh ${{ matrix.target }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: yazi-${{ matrix.target }}.zip
|
||||
path: yazi-${{ matrix.target }}.zip
|
||||
|
||||
build-snap:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build snap
|
||||
uses: snapcore/action-build@v1
|
||||
|
||||
- name: Build
|
||||
run: mv yazi_*.snap yazi-${{ matrix.target }}.snap
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: yazi-${{ matrix.target }}.snap
|
||||
path: yazi-${{ matrix.target }}.snap
|
||||
|
||||
release:
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-unix, build-windows, build-musl, build-snap]
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
draft: true
|
||||
files: |
|
||||
yazi-${{ matrix.target }}.zip
|
||||
yazi*.snap
|
||||
yazi-*.zip
|
||||
yazi-*.snap
|
||||
generate_release_notes: true
|
||||
|
|
|
|||
345
Cargo.lock
generated
345
Cargo.lock
generated
|
|
@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.8"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
|
|
@ -72,9 +72,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.12"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540"
|
||||
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
|
|
@ -120,15 +120,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.79"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.6.0"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
|
||||
checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f"
|
||||
|
||||
[[package]]
|
||||
name = "async-priority-channel"
|
||||
|
|
@ -166,6 +166,12 @@ version = "0.21.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
|
||||
|
||||
[[package]]
|
||||
name = "better-panic"
|
||||
version = "0.3.0"
|
||||
|
|
@ -214,9 +220,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.9.0"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc"
|
||||
checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
|
|
@ -224,9 +230,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.15.0"
|
||||
version = "3.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f"
|
||||
checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
|
|
@ -263,12 +269,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
|
@ -285,7 +288,7 @@ dependencies = [
|
|||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -307,7 +310,7 @@ dependencies = [
|
|||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"strsim 0.11.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -348,7 +351,7 @@ dependencies = [
|
|||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.49",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -431,9 +434,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.11"
|
||||
version = "0.5.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
|
||||
checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
|
@ -505,6 +508,41 @@ dependencies = [
|
|||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.10.0",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
|
|
@ -565,9 +603,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
|||
|
||||
[[package]]
|
||||
name = "erased-serde"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55d05712b2d8d88102bc9868020c9e5c7a1f5527c452b9b97450a1d006140ba7"
|
||||
checksum = "388979d208a049ffdfb22fa33b9c81942215b940910bccfe258caeb25d125cb3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
|
@ -749,7 +787,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.49",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -805,9 +843,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.12.0"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045"
|
||||
checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
|
|
@ -827,9 +865,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
|||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.3.1"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872"
|
||||
checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
|
|
@ -853,9 +891,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.6"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
|
|
@ -890,14 +928,10 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
|
|
@ -909,17 +943,11 @@ dependencies = [
|
|||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "if_chain"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.24.8"
|
||||
version = "0.24.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "034bbe799d1909622a74d1193aa50147769440040ff36cb2baa947609b0a4e23"
|
||||
checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder",
|
||||
|
|
@ -941,9 +969,9 @@ checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.3"
|
||||
version = "2.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
|
||||
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
|
|
@ -1001,9 +1029,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.68"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
|
||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
|
@ -1093,15 +1121,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db2c024b41519440580066ba82aab04092b333e09066a5eb86c7c4890df31f22"
|
||||
checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
|
@ -1168,9 +1196,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.10"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
||||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
|
|
@ -1180,9 +1208,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mlua"
|
||||
version = "0.9.5"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d3561f79659ff3afad7b25e2bf2ec21507fe601ebecb7f81088669ec4bfd51e"
|
||||
checksum = "868d02cb5eb97761bbf6bd6922c1c7a88b8ea252bbf43bd8350a0bf8497a1fc0"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"erased-serde",
|
||||
|
|
@ -1221,7 +1249,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn 2.0.49",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1434,7 +1462,7 @@ version = "1.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
"indexmap",
|
||||
"line-wrap",
|
||||
"quick-xml",
|
||||
|
|
@ -1444,9 +1472,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.12"
|
||||
version = "0.17.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c2378060fb13acff3ba0325b83442c1d2c44fbb76df481160ddc1687cce160"
|
||||
checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"crc32fast",
|
||||
|
|
@ -1543,9 +1571,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.8.1"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051"
|
||||
checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
|
|
@ -1595,9 +1623,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
|
@ -1643,9 +1671,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
|||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.16"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||
|
||||
[[package]]
|
||||
name = "safemem"
|
||||
|
|
@ -1670,9 +1698,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.196"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
|
||||
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
|
@ -1689,20 +1717,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.196"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
|
||||
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.49",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.113"
|
||||
version = "1.0.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
|
||||
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
|
@ -1804,12 +1832,12 @@ checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
|||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
|
||||
checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1843,6 +1871,12 @@ version = "1.0.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.0"
|
||||
|
|
@ -1868,7 +1902,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.49",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1884,9 +1918,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.49"
|
||||
version = "2.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496"
|
||||
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1931,14 +1965,14 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.49",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.7"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
|
||||
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
|
|
@ -2050,7 +2084,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.49",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2143,7 +2177,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.49",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2217,9 +2251,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
|
@ -2243,7 +2277,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna 0.5.0",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
|
|
@ -2265,12 +2299,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "validator"
|
||||
version = "0.16.1"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b92f40481c04ff1f4f61f304d61793c7b56ff76ac1469f1beb199b1445b253bd"
|
||||
checksum = "da339118f018cc70ebf01fafc103360528aad53717e4bf311db929cb01cb9345"
|
||||
dependencies = [
|
||||
"idna 0.4.0",
|
||||
"lazy_static",
|
||||
"idna",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
|
|
@ -2281,28 +2315,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "validator_derive"
|
||||
version = "0.16.0"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc44ca3088bb3ba384d9aecf40c6a23a676ce23e09bdaca2073d99c207f864af"
|
||||
checksum = "76e88ea23b8f5e59230bff8a2f03c0ee0054a61d5b8343a38946bcd406fe624c"
|
||||
dependencies = [
|
||||
"if_chain",
|
||||
"lazy_static",
|
||||
"darling",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn 1.0.109",
|
||||
"validator_types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "validator_types"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "111abfe30072511849c5910134e8baf8dc05de4c0e5903d681cbd5c9c4d611e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2331,9 +2353,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
|
|
@ -2347,9 +2369,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
|
||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
|
|
@ -2357,24 +2379,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
|
||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.49",
|
||||
"syn 2.0.52",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
|
||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
|
@ -2382,22 +2404,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
|
||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.49",
|
||||
"syn 2.0.52",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
|
|
@ -2464,7 +2486,7 @@ version = "0.52.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2482,7 +2504,7 @@ version = "0.52.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2517,17 +2539,17 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
"windows_aarch64_gnullvm 0.52.4",
|
||||
"windows_aarch64_msvc 0.52.4",
|
||||
"windows_i686_gnu 0.52.4",
|
||||
"windows_i686_msvc 0.52.4",
|
||||
"windows_x86_64_gnu 0.52.4",
|
||||
"windows_x86_64_gnullvm 0.52.4",
|
||||
"windows_x86_64_msvc 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2544,9 +2566,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
|||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
|
|
@ -2562,9 +2584,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
|||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
|
|
@ -2580,9 +2602,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
|||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
|
|
@ -2598,9 +2620,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
|||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
|
|
@ -2616,9 +2638,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
|||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
|
|
@ -2634,9 +2656,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
|||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
|
|
@ -2652,15 +2674,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.1"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d90f4e0f530c4c69f62b80d839e9ef3855edc9cba471a160c4d692deed62b401"
|
||||
checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
|
@ -2671,7 +2693,7 @@ version = "0.2.3"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
"base64",
|
||||
"base64 0.22.0",
|
||||
"color_quant",
|
||||
"crossterm",
|
||||
"image",
|
||||
|
|
@ -2722,7 +2744,7 @@ name = "yazi-core"
|
|||
version = "0.2.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"base64 0.22.0",
|
||||
"bitflags 2.4.2",
|
||||
"clipboard-win",
|
||||
"crossterm",
|
||||
|
|
@ -2743,6 +2765,7 @@ dependencies = [
|
|||
"yazi-boot",
|
||||
"yazi-config",
|
||||
"yazi-plugin",
|
||||
"yazi-proxy",
|
||||
"yazi-scheduler",
|
||||
"yazi-shared",
|
||||
]
|
||||
|
|
@ -2773,6 +2796,7 @@ dependencies = [
|
|||
"yazi-config",
|
||||
"yazi-core",
|
||||
"yazi-plugin",
|
||||
"yazi-proxy",
|
||||
"yazi-scheduler",
|
||||
"yazi-shared",
|
||||
]
|
||||
|
|
@ -2804,6 +2828,7 @@ dependencies = [
|
|||
"yazi-boot",
|
||||
"yazi-config",
|
||||
"yazi-prebuild",
|
||||
"yazi-proxy",
|
||||
"yazi-shared",
|
||||
]
|
||||
|
||||
|
|
@ -2813,13 +2838,24 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4b6c8e12e39ac0f79fa96f36e5b88e0da8d230691abd729eec709b43c74f632"
|
||||
|
||||
[[package]]
|
||||
name = "yazi-proxy"
|
||||
version = "0.2.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"mlua",
|
||||
"tokio",
|
||||
"yazi-config",
|
||||
"yazi-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yazi-scheduler"
|
||||
version = "0.2.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-priority-channel",
|
||||
"base64",
|
||||
"base64 0.22.0",
|
||||
"crossterm",
|
||||
"futures",
|
||||
"parking_lot",
|
||||
|
|
@ -2831,6 +2867,7 @@ dependencies = [
|
|||
"yazi-adaptor",
|
||||
"yazi-config",
|
||||
"yazi-plugin",
|
||||
"yazi-proxy",
|
||||
"yazi-shared",
|
||||
]
|
||||
|
||||
|
|
@ -2869,7 +2906,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.49",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
11
README.md
11
README.md
|
|
@ -12,10 +12,10 @@ Yazi (means "duck") is a terminal file manager written in Rust, based on non-blo
|
|||
- 💪 **Powerful Async Task Scheduling and Management**: Provides real-time progress updates, task cancellation, and internal task priority assignment.
|
||||
- 🖼️ **Built-in Support for Multiple Image Protocols**: Also integrated with Überzug++, covering almost all terminals.
|
||||
- 🌟 **Built-in Code Highlighting and Image Decoding**: Combined with the pre-loading mechanism, greatly accelerates image and normal file loading.
|
||||
- 🔌 **Concurrent Plugin System**: UI plugins (rewriting most of the UI), functional plugins (coming soon), custom previewer, and custom preloader; Just some pieces of Lua.
|
||||
- 🔌 **Concurrent Plugin System**: UI plugins (rewriting most of the UI), functional plugins, custom previewer, and custom preloader; Just some pieces of Lua.
|
||||
- 🧰 Integration with fd, rg, fzf, zoxide
|
||||
- 💫 Vim-like input/select component, auto-completion for cd paths
|
||||
- 🏷️ Multi-Tab Support, Scrollable Preview (for videos, PDFs, archives, directories, code, etc.)
|
||||
- 💫 Vim-like input/select/notify component, auto-completion for cd paths
|
||||
- 🏷️ Multi-Tab Support, Cross-directory selection, Scrollable Preview (for videos, PDFs, archives, directories, code, etc.)
|
||||
- 🔄 Bulk Renaming, Visual Mode, File Chooser
|
||||
- 🎨 Theme System, Custom Layouts, Trash Bin, CSI u
|
||||
- ... and more!
|
||||
|
|
@ -46,8 +46,9 @@ https://github.com/sxyazi/yazi/assets/17523360/92ff23fa-0cd5-4f04-b387-894c12265
|
|||
| foot | [Sixel graphics format](https://www.vt100.net/docs/vt3xx-gp/chapter14.html) | ✅ Built-in |
|
||||
| Ghostty | [Kitty old protocol](https://github.com/sxyazi/yazi/blob/main/yazi-adaptor/src/kitty_old.rs) | ✅ Built-in |
|
||||
| Black Box | [Sixel graphics format](https://www.vt100.net/docs/vt3xx-gp/chapter14.html) | ✅ Built-in |
|
||||
| Tabby | [Sixel graphics format](https://www.vt100.net/docs/vt3xx-gp/chapter14.html) | ✅ Built-in |
|
||||
| Hyper | [Sixel graphics format](https://www.vt100.net/docs/vt3xx-gp/chapter14.html) | ✅ Built-in |
|
||||
| VSCode | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||
| Tabby | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||
| Hyper | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||
| X11 / Wayland | Window system protocol | ☑️ Überzug++ required |
|
||||
| Fallback | [Chafa](https://hpjansson.org/chafa/) | ☑️ Überzug++ required |
|
||||
|
||||
|
|
|
|||
|
|
@ -60,9 +60,9 @@
|
|||
wrapProgram $out/bin/yazi \
|
||||
--prefix PATH : "${makeBinPath runtimePaths}"
|
||||
installShellCompletion --cmd yazi \
|
||||
--bash ./yazi-config/completions/yazi.bash \
|
||||
--fish ./yazi-config/completions/yazi.fish \
|
||||
--zsh ./yazi-config/completions/_yazi
|
||||
--bash ./yazi-boot/completions/yazi.bash \
|
||||
--fish ./yazi-boot/completions/yazi.fish \
|
||||
--zsh ./yazi-boot/completions/_yazi
|
||||
|
||||
# Resize logo
|
||||
for RES in 16 24 32 48 64 128 256; do
|
||||
|
|
|
|||
|
|
@ -1,20 +1,26 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
cd $SCRIPT_DIR/..
|
||||
export ARTIFACT_NAME="yazi-$1"
|
||||
export YAZI_GEN_COMPLETIONS=1
|
||||
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=/usr/bin/aarch64-linux-gnu-gcc
|
||||
|
||||
cargo +stable build --release --target aarch64-apple-darwin
|
||||
cargo +stable build --release --target x86_64-apple-darwin
|
||||
cargo +stable build --release --target x86_64-unknown-linux-gnu
|
||||
cargo +stable build --release --target x86_64-pc-windows-gnu
|
||||
# Setup Rust toolchain
|
||||
rustup toolchain install stable --profile minimal
|
||||
rustup target add "$1"
|
||||
|
||||
mv target/aarch64-apple-darwin/release/yazi yazi-aarch64-apple-darwin
|
||||
mv target/x86_64-apple-darwin/release/yazi yazi-x86_64-apple-darwin
|
||||
mv target/x86_64-unknown-linux-gnu/release/yazi yazi-x86_64-unknown-linux-gnu
|
||||
mv target/x86_64-pc-windows-gnu/release/yazi.exe yazi-x86_64-pc-windows-gnu.exe
|
||||
# Build for the target
|
||||
cargo build --release --locked --target "$1"
|
||||
|
||||
zip -j yazi-aarch64-apple-darwin.zip yazi-aarch64-apple-darwin
|
||||
zip -j yazi-x86_64-apple-darwin.zip yazi-x86_64-apple-darwin
|
||||
zip -j yazi-x86_64-unknown-linux-gnu.zip yazi-x86_64-unknown-linux-gnu
|
||||
zip -j yazi-x86_64-pc-windows-gnu.zip yazi-x86_64-pc-windows-gnu.exe
|
||||
# Create the artifact
|
||||
mkdir "$ARTIFACT_NAME"
|
||||
cp "target/$1/release/yazi" "$ARTIFACT_NAME"
|
||||
cp -r yazi-boot/completions "$ARTIFACT_NAME"
|
||||
cp README.md LICENSE "$ARTIFACT_NAME"
|
||||
|
||||
# Zip the artifact
|
||||
if ! command -v zip &> /dev/null
|
||||
then
|
||||
sudo apt-get update && sudo apt-get install -yq zip
|
||||
fi
|
||||
zip -r "$ARTIFACT_NAME.zip" "$ARTIFACT_NAME"
|
||||
|
|
|
|||
|
|
@ -92,9 +92,9 @@ impl Adaptor {
|
|||
Emulator::Foot => vec![Self::Sixel],
|
||||
Emulator::Ghostty => vec![Self::KittyOld],
|
||||
Emulator::BlackBox => vec![Self::Sixel],
|
||||
Emulator::VSCode => vec![Self::Sixel],
|
||||
Emulator::Tabby => vec![Self::Sixel],
|
||||
Emulator::Hyper => vec![Self::Sixel],
|
||||
Emulator::VSCode => vec![Self::Iterm2, Self::Sixel],
|
||||
Emulator::Tabby => vec![Self::Iterm2, Self::Sixel],
|
||||
Emulator::Hyper => vec![Self::Iterm2, Self::Sixel],
|
||||
Emulator::Mintty => vec![Self::Iterm2],
|
||||
Emulator::Neovim => vec![],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#[path = "src/args.rs"]
|
||||
mod args;
|
||||
|
||||
use std::{env, error::Error, fs};
|
||||
use std::{env, error::Error};
|
||||
|
||||
use clap::CommandFactory;
|
||||
use clap_complete::{generate_to, Shell};
|
||||
|
|
@ -18,7 +18,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
let bin = "yazi";
|
||||
let out = "completions";
|
||||
|
||||
fs::create_dir_all(out)?;
|
||||
std::fs::create_dir_all(out)?;
|
||||
generate_to(Shell::Bash, cmd, bin, out)?;
|
||||
generate_to(Shell::Fish, cmd, bin, out)?;
|
||||
generate_to(Shell::Zsh, cmd, bin, out)?;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{ffi::OsString, fs, path::{Path, PathBuf}, process};
|
||||
use std::{ffi::OsString, path::{Path, PathBuf}, process};
|
||||
|
||||
use clap::Parser;
|
||||
use serde::Serialize;
|
||||
|
|
@ -14,8 +14,8 @@ pub struct Boot {
|
|||
pub file: Option<OsString>,
|
||||
|
||||
pub config_dir: PathBuf,
|
||||
pub flavor_dir: PathBuf,
|
||||
pub plugin_dir: PathBuf,
|
||||
pub state_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl Boot {
|
||||
|
|
@ -36,20 +36,20 @@ impl Boot {
|
|||
|
||||
impl Default for Boot {
|
||||
fn default() -> Self {
|
||||
let config_dir = Xdg::config_dir();
|
||||
let (cwd, file) = Self::parse_entry(ARGS.entry.as_deref());
|
||||
|
||||
let boot = Self {
|
||||
cwd,
|
||||
file,
|
||||
|
||||
config_dir: Xdg::config_dir().unwrap(),
|
||||
plugin_dir: Xdg::plugin_dir().unwrap(),
|
||||
state_dir: Xdg::state_dir().unwrap(),
|
||||
flavor_dir: config_dir.join("flavors"),
|
||||
plugin_dir: config_dir.join("plugins"),
|
||||
config_dir,
|
||||
};
|
||||
|
||||
if !boot.state_dir.is_dir() {
|
||||
fs::create_dir_all(&boot.state_dir).unwrap();
|
||||
}
|
||||
|
||||
std::fs::create_dir_all(&boot.flavor_dir).expect("Failed to create flavor directory");
|
||||
std::fs::create_dir_all(&boot.plugin_dir).expect("Failed to create plugin directory");
|
||||
boot
|
||||
}
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ impl Default for Args {
|
|||
if args.clear_cache {
|
||||
if PREVIEW.cache_dir == Xdg::cache_dir() {
|
||||
println!("Clearing cache directory: \n{:?}", PREVIEW.cache_dir);
|
||||
fs::remove_dir_all(&PREVIEW.cache_dir).unwrap();
|
||||
std::fs::remove_dir_all(&PREVIEW.cache_dir).unwrap();
|
||||
} else {
|
||||
println!(
|
||||
"You've changed the default cache directory, for your data's safety, please clear it manually: \n{:?}",
|
||||
|
|
|
|||
|
|
@ -5,296 +5,301 @@
|
|||
[manager]
|
||||
|
||||
keymap = [
|
||||
{ on = [ "<Esc>" ], exec = "escape", desc = "Exit visual mode, clear selected, or cancel search" },
|
||||
{ on = [ "q" ], exec = "quit", desc = "Exit the process" },
|
||||
{ on = [ "Q" ], exec = "quit --no-cwd-file", desc = "Exit the process without writing cwd-file" },
|
||||
{ on = [ "<C-q>" ], exec = "close", desc = "Close the current tab, or quit if it is last tab" },
|
||||
{ on = [ "<C-z>" ], exec = "suspend", desc = "Suspend the process" },
|
||||
{ on = [ "<Esc>" ], run = "escape", desc = "Exit visual mode, clear selected, or cancel search" },
|
||||
{ on = [ "<C-[>" ], run = "escape", desc = "Exit visual mode, clear selected, or cancel search" },
|
||||
{ on = [ "q" ], run = "quit", desc = "Exit the process" },
|
||||
{ on = [ "Q" ], run = "quit --no-cwd-file", desc = "Exit the process without writing cwd-file" },
|
||||
{ on = [ "<C-q>" ], run = "close", desc = "Close the current tab, or quit if it is last tab" },
|
||||
{ on = [ "<C-z>" ], run = "suspend", desc = "Suspend the process" },
|
||||
|
||||
# Navigation
|
||||
{ on = [ "k" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "j" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||
{ on = [ "k" ], run = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "j" ], run = "arrow 1", desc = "Move cursor down" },
|
||||
|
||||
{ on = [ "K" ], exec = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "J" ], exec = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
{ on = [ "K" ], run = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "J" ], run = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
|
||||
{ on = [ "<S-Up>" ], exec = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "<S-Down>" ], exec = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
{ on = [ "<S-Up>" ], run = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "<S-Down>" ], run = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
|
||||
{ on = [ "<C-u>" ], exec = "arrow -50%", desc = "Move cursor up half page" },
|
||||
{ on = [ "<C-d>" ], exec = "arrow 50%", desc = "Move cursor down half page" },
|
||||
{ on = [ "<C-b>" ], exec = "arrow -100%", desc = "Move cursor up one page" },
|
||||
{ on = [ "<C-f>" ], exec = "arrow 100%", desc = "Move cursor down one page" },
|
||||
{ on = [ "<C-u>" ], run = "arrow -50%", desc = "Move cursor up half page" },
|
||||
{ on = [ "<C-d>" ], run = "arrow 50%", desc = "Move cursor down half page" },
|
||||
{ on = [ "<C-b>" ], run = "arrow -100%", desc = "Move cursor up one page" },
|
||||
{ on = [ "<C-f>" ], run = "arrow 100%", desc = "Move cursor down one page" },
|
||||
|
||||
{ on = [ "<C-PageUp>" ], exec = "arrow -50%", desc = "Move cursor up half page" },
|
||||
{ on = [ "<C-PageDown>" ], exec = "arrow 50%", desc = "Move cursor down half page" },
|
||||
{ on = [ "<PageUp>" ], exec = "arrow -100%", desc = "Move cursor up one page" },
|
||||
{ on = [ "<PageDown>" ], exec = "arrow 100%", desc = "Move cursor down one page" },
|
||||
{ on = [ "<C-PageUp>" ], run = "arrow -50%", desc = "Move cursor up half page" },
|
||||
{ on = [ "<C-PageDown>" ], run = "arrow 50%", desc = "Move cursor down half page" },
|
||||
{ on = [ "<PageUp>" ], run = "arrow -100%", desc = "Move cursor up one page" },
|
||||
{ on = [ "<PageDown>" ], run = "arrow 100%", desc = "Move cursor down one page" },
|
||||
|
||||
{ on = [ "h" ], exec = "leave", desc = "Go back to the parent directory" },
|
||||
{ on = [ "l" ], exec = "enter", desc = "Enter the child directory" },
|
||||
{ on = [ "h" ], run = "leave", desc = "Go back to the parent directory" },
|
||||
{ on = [ "l" ], run = "enter", desc = "Enter the child directory" },
|
||||
|
||||
{ on = [ "H" ], exec = "back", desc = "Go back to the previous directory" },
|
||||
{ on = [ "L" ], exec = "forward", desc = "Go forward to the next directory" },
|
||||
{ on = [ "H" ], run = "back", desc = "Go back to the previous directory" },
|
||||
{ on = [ "L" ], run = "forward", desc = "Go forward to the next directory" },
|
||||
|
||||
{ on = [ "<A-k>" ], exec = "seek -5", desc = "Seek up 5 units in the preview" },
|
||||
{ on = [ "<A-j>" ], exec = "seek 5", desc = "Seek down 5 units in the preview" },
|
||||
{ on = [ "<A-PageUp>" ], exec = "seek -5", desc = "Seek up 5 units in the preview" },
|
||||
{ on = [ "<A-PageDown>" ], exec = "seek 5", desc = "Seek down 5 units in the preview" },
|
||||
{ on = [ "<A-k>" ], run = "seek -5", desc = "Seek up 5 units in the preview" },
|
||||
{ on = [ "<A-j>" ], run = "seek 5", desc = "Seek down 5 units in the preview" },
|
||||
{ on = [ "<A-PageUp>" ], run = "seek -5", desc = "Seek up 5 units in the preview" },
|
||||
{ on = [ "<A-PageDown>" ], run = "seek 5", desc = "Seek down 5 units in the preview" },
|
||||
|
||||
{ on = [ "<Up>" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<Down>" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||
{ on = [ "<Left>" ], exec = "leave", desc = "Go back to the parent directory" },
|
||||
{ on = [ "<Right>" ], exec = "enter", desc = "Enter the child directory" },
|
||||
{ on = [ "<Up>" ], run = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<Down>" ], run = "arrow 1", desc = "Move cursor down" },
|
||||
{ on = [ "<Left>" ], run = "leave", desc = "Go back to the parent directory" },
|
||||
{ on = [ "<Right>" ], run = "enter", desc = "Enter the child directory" },
|
||||
|
||||
{ on = [ "g", "g" ], exec = "arrow -99999999", desc = "Move cursor to the top" },
|
||||
{ on = [ "G" ], exec = "arrow 99999999", desc = "Move cursor to the bottom" },
|
||||
{ on = [ "g", "g" ], run = "arrow -99999999", desc = "Move cursor to the top" },
|
||||
{ on = [ "G" ], run = "arrow 99999999", desc = "Move cursor to the bottom" },
|
||||
|
||||
# Selection
|
||||
{ on = [ "<Space>" ], exec = [ "select --state=none", "arrow 1" ], desc = "Toggle the current selection state" },
|
||||
{ on = [ "v" ], exec = "visual_mode", desc = "Enter visual mode (selection mode)" },
|
||||
{ on = [ "V" ], exec = "visual_mode --unset", desc = "Enter visual mode (unset mode)" },
|
||||
{ on = [ "<C-a>" ], exec = "select_all --state=true", desc = "Select all files" },
|
||||
{ on = [ "<C-r>" ], exec = "select_all --state=none", desc = "Inverse selection of all files" },
|
||||
{ on = [ "<Space>" ], run = [ "select --state=none", "arrow 1" ], desc = "Toggle the current selection state" },
|
||||
{ on = [ "v" ], run = "visual_mode", desc = "Enter visual mode (selection mode)" },
|
||||
{ on = [ "V" ], run = "visual_mode --unset", desc = "Enter visual mode (unset mode)" },
|
||||
{ on = [ "<C-a>" ], run = "select_all --state=true", desc = "Select all files" },
|
||||
{ on = [ "<C-r>" ], run = "select_all --state=none", desc = "Inverse selection of all files" },
|
||||
|
||||
# Operation
|
||||
{ on = [ "o" ], exec = "open", desc = "Open the selected files" },
|
||||
{ on = [ "O" ], exec = "open --interactive", desc = "Open the selected files interactively" },
|
||||
{ on = [ "<Enter>" ], exec = "open", desc = "Open the selected files" },
|
||||
{ on = [ "<C-Enter>" ], exec = "open --interactive", desc = "Open the selected files interactively" },
|
||||
{ on = [ "y" ], exec = "yank", desc = "Copy the selected files" },
|
||||
{ on = [ "Y" ], exec = "unyank", desc = "Cancel the yank status of files" },
|
||||
{ on = [ "x" ], exec = "yank --cut", desc = "Cut the selected files" },
|
||||
{ on = [ "p" ], exec = "paste", desc = "Paste the files" },
|
||||
{ on = [ "P" ], exec = "paste --force", desc = "Paste the files (overwrite if the destination exists)" },
|
||||
{ on = [ "-" ], exec = "link", desc = "Symlink the absolute path of files" },
|
||||
{ on = [ "_" ], exec = "link --relative", desc = "Symlink the relative path of files" },
|
||||
{ on = [ "d" ], exec = "remove", desc = "Move the files to the trash" },
|
||||
{ on = [ "D" ], exec = "remove --permanently", desc = "Permanently delete the files" },
|
||||
{ on = [ "a" ], exec = "create", desc = "Create a file or directory (ends with / for directories)" },
|
||||
{ on = [ "r" ], exec = "rename --cursor=before_ext", desc = "Rename a file or directory" },
|
||||
{ on = [ ";" ], exec = "shell", desc = "Run a shell command" },
|
||||
{ on = [ ":" ], exec = "shell --block", desc = "Run a shell command (block the UI until the command finishes)" },
|
||||
{ on = [ "." ], exec = "hidden toggle", desc = "Toggle the visibility of hidden files" },
|
||||
{ on = [ "s" ], exec = "search fd", desc = "Search files by name using fd" },
|
||||
{ on = [ "S" ], exec = "search rg", desc = "Search files by content using ripgrep" },
|
||||
{ on = [ "<C-s>" ], exec = "search none", desc = "Cancel the ongoing search" },
|
||||
{ on = [ "z" ], exec = "jump zoxide", desc = "Jump to a directory using zoxide" },
|
||||
{ on = [ "Z" ], exec = "jump fzf", desc = "Jump to a directory, or reveal a file using fzf" },
|
||||
{ on = [ "o" ], run = "open", desc = "Open the selected files" },
|
||||
{ on = [ "O" ], run = "open --interactive", desc = "Open the selected files interactively" },
|
||||
{ on = [ "<Enter>" ], run = "open", desc = "Open the selected files" },
|
||||
{ on = [ "<C-Enter>" ], run = "open --interactive", desc = "Open the selected files interactively" },
|
||||
{ on = [ "y" ], run = "yank", desc = "Copy the selected files" },
|
||||
{ on = [ "Y" ], run = "unyank", desc = "Cancel the yank status of files" },
|
||||
{ on = [ "x" ], run = "yank --cut", desc = "Cut the selected files" },
|
||||
{ on = [ "p" ], run = "paste", desc = "Paste the files" },
|
||||
{ on = [ "P" ], run = "paste --force", desc = "Paste the files (overwrite if the destination exists)" },
|
||||
{ on = [ "-" ], run = "link", desc = "Symlink the absolute path of files" },
|
||||
{ on = [ "_" ], run = "link --relative", desc = "Symlink the relative path of files" },
|
||||
{ on = [ "d" ], run = "remove", desc = "Move the files to the trash" },
|
||||
{ on = [ "D" ], run = "remove --permanently", desc = "Permanently delete the files" },
|
||||
{ on = [ "a" ], run = "create", desc = "Create a file or directory (ends with / for directories)" },
|
||||
{ on = [ "r" ], run = "rename --cursor=before_ext", desc = "Rename a file or directory" },
|
||||
{ on = [ ";" ], run = "shell", desc = "Run a shell command" },
|
||||
{ on = [ ":" ], run = "shell --block", desc = "Run a shell command (block the UI until the command finishes)" },
|
||||
{ on = [ "." ], run = "hidden toggle", desc = "Toggle the visibility of hidden files" },
|
||||
{ on = [ "s" ], run = "search fd", desc = "Search files by name using fd" },
|
||||
{ on = [ "S" ], run = "search rg", desc = "Search files by content using ripgrep" },
|
||||
{ on = [ "<C-s>" ], run = "search none", desc = "Cancel the ongoing search" },
|
||||
{ on = [ "z" ], run = "jump zoxide", desc = "Jump to a directory using zoxide" },
|
||||
{ on = [ "Z" ], run = "jump fzf", desc = "Jump to a directory, or reveal a file using fzf" },
|
||||
|
||||
# Linemode
|
||||
{ on = [ "m", "s" ], exec = "linemode size", desc = "Set linemode to size" },
|
||||
{ on = [ "m", "p" ], exec = "linemode permissions", desc = "Set linemode to permissions" },
|
||||
{ on = [ "m", "m" ], exec = "linemode mtime", desc = "Set linemode to mtime" },
|
||||
{ on = [ "m", "n" ], exec = "linemode none", desc = "Set linemode to none" },
|
||||
{ on = [ "m", "s" ], run = "linemode size", desc = "Set linemode to size" },
|
||||
{ on = [ "m", "p" ], run = "linemode permissions", desc = "Set linemode to permissions" },
|
||||
{ on = [ "m", "m" ], run = "linemode mtime", desc = "Set linemode to mtime" },
|
||||
{ on = [ "m", "n" ], run = "linemode none", desc = "Set linemode to none" },
|
||||
|
||||
# Copy
|
||||
{ on = [ "c", "c" ], exec = "copy path", desc = "Copy the absolute path" },
|
||||
{ on = [ "c", "d" ], exec = "copy dirname", desc = "Copy the path of the parent directory" },
|
||||
{ on = [ "c", "f" ], exec = "copy filename", desc = "Copy the name of the file" },
|
||||
{ on = [ "c", "n" ], exec = "copy name_without_ext", desc = "Copy the name of the file without the extension" },
|
||||
{ on = [ "c", "c" ], run = "copy path", desc = "Copy the absolute path" },
|
||||
{ on = [ "c", "d" ], run = "copy dirname", desc = "Copy the path of the parent directory" },
|
||||
{ on = [ "c", "f" ], run = "copy filename", desc = "Copy the name of the file" },
|
||||
{ on = [ "c", "n" ], run = "copy name_without_ext", desc = "Copy the name of the file without the extension" },
|
||||
|
||||
# Filter
|
||||
{ on = [ "f" ], exec = "filter --smart", desc = "Filter the files" },
|
||||
{ on = [ "f" ], run = "filter --smart", desc = "Filter the files" },
|
||||
|
||||
# Find
|
||||
{ on = [ "/" ], exec = "find --smart", desc = "Find next file" },
|
||||
{ on = [ "?" ], exec = "find --previous --smart", desc = "Find previous file" },
|
||||
{ on = [ "n" ], exec = "find_arrow", desc = "Go to next found file" },
|
||||
{ on = [ "N" ], exec = "find_arrow --previous", desc = "Go to previous found file" },
|
||||
{ on = [ "/" ], run = "find --smart", desc = "Find next file" },
|
||||
{ on = [ "?" ], run = "find --previous --smart", desc = "Find previous file" },
|
||||
{ on = [ "n" ], run = "find_arrow", desc = "Go to next found file" },
|
||||
{ on = [ "N" ], run = "find_arrow --previous", desc = "Go to previous found file" },
|
||||
|
||||
# Sorting
|
||||
{ on = [ ",", "m" ], exec = "sort modified --dir-first", desc = "Sort by modified time" },
|
||||
{ on = [ ",", "M" ], exec = "sort modified --reverse --dir-first", desc = "Sort by modified time (reverse)" },
|
||||
{ on = [ ",", "c" ], exec = "sort created --dir-first", desc = "Sort by created time" },
|
||||
{ on = [ ",", "C" ], exec = "sort created --reverse --dir-first", desc = "Sort by created time (reverse)" },
|
||||
{ on = [ ",", "e" ], exec = "sort extension --dir-first", desc = "Sort by extension" },
|
||||
{ on = [ ",", "E" ], exec = "sort extension --reverse --dir-first", desc = "Sort by extension (reverse)" },
|
||||
{ on = [ ",", "a" ], exec = "sort alphabetical --dir-first", desc = "Sort alphabetically" },
|
||||
{ on = [ ",", "A" ], exec = "sort alphabetical --reverse --dir-first", desc = "Sort alphabetically (reverse)" },
|
||||
{ on = [ ",", "n" ], exec = "sort natural --dir-first", desc = "Sort naturally" },
|
||||
{ on = [ ",", "N" ], exec = "sort natural --reverse --dir-first", desc = "Sort naturally (reverse)" },
|
||||
{ on = [ ",", "s" ], exec = "sort size --dir-first", desc = "Sort by size" },
|
||||
{ on = [ ",", "S" ], exec = "sort size --reverse --dir-first", desc = "Sort by size (reverse)" },
|
||||
{ on = [ ",", "m" ], run = "sort modified --dir-first", desc = "Sort by modified time" },
|
||||
{ on = [ ",", "M" ], run = "sort modified --reverse --dir-first", desc = "Sort by modified time (reverse)" },
|
||||
{ on = [ ",", "c" ], run = "sort created --dir-first", desc = "Sort by created time" },
|
||||
{ on = [ ",", "C" ], run = "sort created --reverse --dir-first", desc = "Sort by created time (reverse)" },
|
||||
{ on = [ ",", "e" ], run = "sort extension --dir-first", desc = "Sort by extension" },
|
||||
{ on = [ ",", "E" ], run = "sort extension --reverse --dir-first", desc = "Sort by extension (reverse)" },
|
||||
{ on = [ ",", "a" ], run = "sort alphabetical --dir-first", desc = "Sort alphabetically" },
|
||||
{ on = [ ",", "A" ], run = "sort alphabetical --reverse --dir-first", desc = "Sort alphabetically (reverse)" },
|
||||
{ on = [ ",", "n" ], run = "sort natural --dir-first", desc = "Sort naturally" },
|
||||
{ on = [ ",", "N" ], run = "sort natural --reverse --dir-first", desc = "Sort naturally (reverse)" },
|
||||
{ on = [ ",", "s" ], run = "sort size --dir-first", desc = "Sort by size" },
|
||||
{ on = [ ",", "S" ], run = "sort size --reverse --dir-first", desc = "Sort by size (reverse)" },
|
||||
|
||||
# Tabs
|
||||
{ on = [ "t" ], exec = "tab_create --current", desc = "Create a new tab using the current path" },
|
||||
{ on = [ "t" ], run = "tab_create --current", desc = "Create a new tab using the current path" },
|
||||
|
||||
{ on = [ "1" ], exec = "tab_switch 0", desc = "Switch to the first tab" },
|
||||
{ on = [ "2" ], exec = "tab_switch 1", desc = "Switch to the second tab" },
|
||||
{ on = [ "3" ], exec = "tab_switch 2", desc = "Switch to the third tab" },
|
||||
{ on = [ "4" ], exec = "tab_switch 3", desc = "Switch to the fourth tab" },
|
||||
{ on = [ "5" ], exec = "tab_switch 4", desc = "Switch to the fifth tab" },
|
||||
{ on = [ "6" ], exec = "tab_switch 5", desc = "Switch to the sixth tab" },
|
||||
{ on = [ "7" ], exec = "tab_switch 6", desc = "Switch to the seventh tab" },
|
||||
{ on = [ "8" ], exec = "tab_switch 7", desc = "Switch to the eighth tab" },
|
||||
{ on = [ "9" ], exec = "tab_switch 8", desc = "Switch to the ninth tab" },
|
||||
{ on = [ "1" ], run = "tab_switch 0", desc = "Switch to the first tab" },
|
||||
{ on = [ "2" ], run = "tab_switch 1", desc = "Switch to the second tab" },
|
||||
{ on = [ "3" ], run = "tab_switch 2", desc = "Switch to the third tab" },
|
||||
{ on = [ "4" ], run = "tab_switch 3", desc = "Switch to the fourth tab" },
|
||||
{ on = [ "5" ], run = "tab_switch 4", desc = "Switch to the fifth tab" },
|
||||
{ on = [ "6" ], run = "tab_switch 5", desc = "Switch to the sixth tab" },
|
||||
{ on = [ "7" ], run = "tab_switch 6", desc = "Switch to the seventh tab" },
|
||||
{ on = [ "8" ], run = "tab_switch 7", desc = "Switch to the eighth tab" },
|
||||
{ on = [ "9" ], run = "tab_switch 8", desc = "Switch to the ninth tab" },
|
||||
|
||||
{ on = [ "[" ], exec = "tab_switch -1 --relative", desc = "Switch to the previous tab" },
|
||||
{ on = [ "]" ], exec = "tab_switch 1 --relative", desc = "Switch to the next tab" },
|
||||
{ on = [ "[" ], run = "tab_switch -1 --relative", desc = "Switch to the previous tab" },
|
||||
{ on = [ "]" ], run = "tab_switch 1 --relative", desc = "Switch to the next tab" },
|
||||
|
||||
{ on = [ "{" ], exec = "tab_swap -1", desc = "Swap the current tab with the previous tab" },
|
||||
{ on = [ "}" ], exec = "tab_swap 1", desc = "Swap the current tab with the next tab" },
|
||||
{ on = [ "{" ], run = "tab_swap -1", desc = "Swap the current tab with the previous tab" },
|
||||
{ on = [ "}" ], run = "tab_swap 1", desc = "Swap the current tab with the next tab" },
|
||||
|
||||
# Tasks
|
||||
{ on = [ "w" ], exec = "tasks_show", desc = "Show the tasks manager" },
|
||||
{ on = [ "w" ], run = "tasks_show", desc = "Show the tasks manager" },
|
||||
|
||||
# Goto
|
||||
{ on = [ "g", "h" ], exec = "cd ~", desc = "Go to the home directory" },
|
||||
{ on = [ "g", "c" ], exec = "cd ~/.config", desc = "Go to the config directory" },
|
||||
{ on = [ "g", "d" ], exec = "cd ~/Downloads", desc = "Go to the downloads directory" },
|
||||
{ on = [ "g", "t" ], exec = "cd /tmp", desc = "Go to the temporary directory" },
|
||||
{ on = [ "g", "<Space>" ], exec = "cd --interactive", desc = "Go to a directory interactively" },
|
||||
{ on = [ "g", "h" ], run = "cd ~", desc = "Go to the home directory" },
|
||||
{ on = [ "g", "c" ], run = "cd ~/.config", desc = "Go to the config directory" },
|
||||
{ on = [ "g", "d" ], run = "cd ~/Downloads", desc = "Go to the downloads directory" },
|
||||
{ on = [ "g", "t" ], run = "cd /tmp", desc = "Go to the temporary directory" },
|
||||
{ on = [ "g", "<Space>" ], run = "cd --interactive", desc = "Go to a directory interactively" },
|
||||
|
||||
# Help
|
||||
{ on = [ "~" ], exec = "help", desc = "Open help" },
|
||||
{ on = [ "~" ], run = "help", desc = "Open help" },
|
||||
]
|
||||
|
||||
[tasks]
|
||||
|
||||
keymap = [
|
||||
{ on = [ "<Esc>" ], exec = "close", desc = "Hide the task manager" },
|
||||
{ on = [ "<C-q>" ], exec = "close", desc = "Hide the task manager" },
|
||||
{ on = [ "w" ], exec = "close", desc = "Hide the task manager" },
|
||||
{ on = [ "<Esc>" ], run = "close", desc = "Hide the task manager" },
|
||||
{ on = [ "<C-[>" ], run = "close", desc = "Hide the task manager" },
|
||||
{ on = [ "<C-q>" ], run = "close", desc = "Hide the task manager" },
|
||||
{ on = [ "w" ], run = "close", desc = "Hide the task manager" },
|
||||
|
||||
{ on = [ "k" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "j" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||
{ on = [ "k" ], run = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "j" ], run = "arrow 1", desc = "Move cursor down" },
|
||||
|
||||
{ on = [ "<Up>" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<Down>" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||
{ on = [ "<Up>" ], run = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<Down>" ], run = "arrow 1", desc = "Move cursor down" },
|
||||
|
||||
{ on = [ "<Enter>" ], exec = "inspect", desc = "Inspect the task" },
|
||||
{ on = [ "x" ], exec = "cancel", desc = "Cancel the task" },
|
||||
{ on = [ "<Enter>" ], run = "inspect", desc = "Inspect the task" },
|
||||
{ on = [ "x" ], run = "cancel", desc = "Cancel the task" },
|
||||
|
||||
{ on = [ "~" ], exec = "help", desc = "Open help" }
|
||||
{ on = [ "~" ], run = "help", desc = "Open help" }
|
||||
]
|
||||
|
||||
[select]
|
||||
|
||||
keymap = [
|
||||
{ on = [ "<C-q>" ], exec = "close", desc = "Cancel selection" },
|
||||
{ on = [ "<Esc>" ], exec = "close", desc = "Cancel selection" },
|
||||
{ on = [ "<Enter>" ], exec = "close --submit", desc = "Submit the selection" },
|
||||
{ on = [ "<Esc>" ], run = "close", desc = "Cancel selection" },
|
||||
{ on = [ "<C-[>" ], run = "close", desc = "Cancel selection" },
|
||||
{ on = [ "<C-q>" ], run = "close", desc = "Cancel selection" },
|
||||
{ on = [ "<Enter>" ], run = "close --submit", desc = "Submit the selection" },
|
||||
|
||||
{ on = [ "k" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "j" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||
{ on = [ "k" ], run = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "j" ], run = "arrow 1", desc = "Move cursor down" },
|
||||
|
||||
{ on = [ "K" ], exec = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "J" ], exec = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
{ on = [ "K" ], run = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "J" ], run = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
|
||||
{ on = [ "<Up>" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<Down>" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||
{ on = [ "<Up>" ], run = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<Down>" ], run = "arrow 1", desc = "Move cursor down" },
|
||||
|
||||
{ on = [ "<S-Up>" ], exec = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "<S-Down>" ], exec = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
{ on = [ "<S-Up>" ], run = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "<S-Down>" ], run = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
|
||||
{ on = [ "~" ], exec = "help", desc = "Open help" }
|
||||
{ on = [ "~" ], run = "help", desc = "Open help" }
|
||||
]
|
||||
|
||||
[input]
|
||||
|
||||
keymap = [
|
||||
{ on = [ "<C-q>" ], exec = "close", desc = "Cancel input" },
|
||||
{ on = [ "<Enter>" ], exec = "close --submit", desc = "Submit the input" },
|
||||
{ on = [ "<Esc>" ], exec = "escape", desc = "Go back the normal mode, or cancel input" },
|
||||
{ on = [ "<C-q>" ], run = "close", desc = "Cancel input" },
|
||||
{ on = [ "<Enter>" ], run = "close --submit", desc = "Submit the input" },
|
||||
{ on = [ "<Esc>" ], run = "escape", desc = "Go back the normal mode, or cancel input" },
|
||||
{ on = [ "<C-[>" ], run = "escape", desc = "Go back the normal mode, or cancel input" },
|
||||
|
||||
# Mode
|
||||
{ on = [ "i" ], exec = "insert", desc = "Enter insert mode" },
|
||||
{ on = [ "a" ], exec = "insert --append", desc = "Enter append mode" },
|
||||
{ on = [ "I" ], exec = [ "move -999", "insert" ], desc = "Move to the BOL, and enter insert mode" },
|
||||
{ on = [ "A" ], exec = [ "move 999", "insert --append" ], desc = "Move to the EOL, and enter append mode" },
|
||||
{ on = [ "v" ], exec = "visual", desc = "Enter visual mode" },
|
||||
{ on = [ "V" ], exec = [ "move -999", "visual", "move 999" ], desc = "Enter visual mode and select all" },
|
||||
{ on = [ "i" ], run = "insert", desc = "Enter insert mode" },
|
||||
{ on = [ "a" ], run = "insert --append", desc = "Enter append mode" },
|
||||
{ on = [ "I" ], run = [ "move -999", "insert" ], desc = "Move to the BOL, and enter insert mode" },
|
||||
{ on = [ "A" ], run = [ "move 999", "insert --append" ], desc = "Move to the EOL, and enter append mode" },
|
||||
{ on = [ "v" ], run = "visual", desc = "Enter visual mode" },
|
||||
{ on = [ "V" ], run = [ "move -999", "visual", "move 999" ], desc = "Enter visual mode and select all" },
|
||||
|
||||
# Character-wise movement
|
||||
{ on = [ "h" ], exec = "move -1", desc = "Move back a character" },
|
||||
{ on = [ "l" ], exec = "move 1", desc = "Move forward a character" },
|
||||
{ on = [ "<Left>" ], exec = "move -1", desc = "Move back a character" },
|
||||
{ on = [ "<Right>" ], exec = "move 1", desc = "Move forward a character" },
|
||||
{ on = [ "<C-b>" ], exec = "move -1", desc = "Move back a character" },
|
||||
{ on = [ "<C-f>" ], exec = "move 1", desc = "Move forward a character" },
|
||||
{ on = [ "h" ], run = "move -1", desc = "Move back a character" },
|
||||
{ on = [ "l" ], run = "move 1", desc = "Move forward a character" },
|
||||
{ on = [ "<Left>" ], run = "move -1", desc = "Move back a character" },
|
||||
{ on = [ "<Right>" ], run = "move 1", desc = "Move forward a character" },
|
||||
{ on = [ "<C-b>" ], run = "move -1", desc = "Move back a character" },
|
||||
{ on = [ "<C-f>" ], run = "move 1", desc = "Move forward a character" },
|
||||
|
||||
# Word-wise movement
|
||||
{ on = [ "b" ], exec = "backward", desc = "Move back to the start of the current or previous word" },
|
||||
{ on = [ "w" ], exec = "forward", desc = "Move forward to the start of the next word" },
|
||||
{ on = [ "e" ], exec = "forward --end-of-word", desc = "Move forward to the end of the current or next word" },
|
||||
{ on = [ "<A-b>" ], exec = "backward", desc = "Move back to the start of the current or previous word" },
|
||||
{ on = [ "<A-f>" ], exec = "forward --end-of-word", desc = "Move forward to the end of the current or next word" },
|
||||
{ on = [ "b" ], run = "backward", desc = "Move back to the start of the current or previous word" },
|
||||
{ on = [ "w" ], run = "forward", desc = "Move forward to the start of the next word" },
|
||||
{ on = [ "e" ], run = "forward --end-of-word", desc = "Move forward to the end of the current or next word" },
|
||||
{ on = [ "<A-b>" ], run = "backward", desc = "Move back to the start of the current or previous word" },
|
||||
{ on = [ "<A-f>" ], run = "forward --end-of-word", desc = "Move forward to the end of the current or next word" },
|
||||
|
||||
# Line-wise movement
|
||||
{ on = [ "0" ], exec = "move -999", desc = "Move to the BOL" },
|
||||
{ on = [ "$" ], exec = "move 999", desc = "Move to the EOL" },
|
||||
{ on = [ "<C-a>" ], exec = "move -999", desc = "Move to the BOL" },
|
||||
{ on = [ "<C-e>" ], exec = "move 999", desc = "Move to the EOL" },
|
||||
{ on = [ "<Home>" ], exec = "move -999", desc = "Move to the BOL" },
|
||||
{ on = [ "<End>" ], exec = "move 999", desc = "Move to the EOL" },
|
||||
{ on = [ "0" ], run = "move -999", desc = "Move to the BOL" },
|
||||
{ on = [ "$" ], run = "move 999", desc = "Move to the EOL" },
|
||||
{ on = [ "<C-a>" ], run = "move -999", desc = "Move to the BOL" },
|
||||
{ on = [ "<C-e>" ], run = "move 999", desc = "Move to the EOL" },
|
||||
{ on = [ "<Home>" ], run = "move -999", desc = "Move to the BOL" },
|
||||
{ on = [ "<End>" ], run = "move 999", desc = "Move to the EOL" },
|
||||
|
||||
# Delete
|
||||
{ on = [ "<Backspace>" ], exec = "backspace", desc = "Delete the character before the cursor" },
|
||||
{ on = [ "<Delete>" ], exec = "backspace --under", desc = "Delete the character under the cursor" },
|
||||
{ on = [ "<C-h>" ], exec = "backspace", desc = "Delete the character before the cursor" },
|
||||
{ on = [ "<C-d>" ], exec = "backspace --under", desc = "Delete the character under the cursor" },
|
||||
{ on = [ "<Backspace>" ], run = "backspace", desc = "Delete the character before the cursor" },
|
||||
{ on = [ "<Delete>" ], run = "backspace --under", desc = "Delete the character under the cursor" },
|
||||
{ on = [ "<C-h>" ], run = "backspace", desc = "Delete the character before the cursor" },
|
||||
{ on = [ "<C-d>" ], run = "backspace --under", desc = "Delete the character under the cursor" },
|
||||
|
||||
# Kill
|
||||
{ on = [ "<C-u>" ], exec = "kill bol", desc = "Kill backwards to the BOL" },
|
||||
{ on = [ "<C-k>" ], exec = "kill eol", desc = "Kill forwards to the EOL" },
|
||||
{ on = [ "<C-w>" ], exec = "kill backward", desc = "Kill backwards to the start of the current word" },
|
||||
{ on = [ "<A-d>" ], exec = "kill forward", desc = "Kill forwards to the end of the current word" },
|
||||
{ on = [ "<C-u>" ], run = "kill bol", desc = "Kill backwards to the BOL" },
|
||||
{ on = [ "<C-k>" ], run = "kill eol", desc = "Kill forwards to the EOL" },
|
||||
{ on = [ "<C-w>" ], run = "kill backward", desc = "Kill backwards to the start of the current word" },
|
||||
{ on = [ "<A-d>" ], run = "kill forward", desc = "Kill forwards to the end of the current word" },
|
||||
|
||||
# Cut/Yank/Paste
|
||||
{ on = [ "d" ], exec = "delete --cut", desc = "Cut the selected characters" },
|
||||
{ on = [ "D" ], exec = [ "delete --cut", "move 999" ], desc = "Cut until the EOL" },
|
||||
{ on = [ "c" ], exec = "delete --cut --insert", desc = "Cut the selected characters, and enter insert mode" },
|
||||
{ on = [ "C" ], exec = [ "delete --cut --insert", "move 999" ], desc = "Cut until the EOL, and enter insert mode" },
|
||||
{ on = [ "x" ], exec = [ "delete --cut", "move 1 --in-operating" ], desc = "Cut the current character" },
|
||||
{ on = [ "y" ], exec = "yank", desc = "Copy the selected characters" },
|
||||
{ on = [ "p" ], exec = "paste", desc = "Paste the copied characters after the cursor" },
|
||||
{ on = [ "P" ], exec = "paste --before", desc = "Paste the copied characters before the cursor" },
|
||||
{ on = [ "d" ], run = "delete --cut", desc = "Cut the selected characters" },
|
||||
{ on = [ "D" ], run = [ "delete --cut", "move 999" ], desc = "Cut until the EOL" },
|
||||
{ on = [ "c" ], run = "delete --cut --insert", desc = "Cut the selected characters, and enter insert mode" },
|
||||
{ on = [ "C" ], run = [ "delete --cut --insert", "move 999" ], desc = "Cut until the EOL, and enter insert mode" },
|
||||
{ on = [ "x" ], run = [ "delete --cut", "move 1 --in-operating" ], desc = "Cut the current character" },
|
||||
{ on = [ "y" ], run = "yank", desc = "Copy the selected characters" },
|
||||
{ on = [ "p" ], run = "paste", desc = "Paste the copied characters after the cursor" },
|
||||
{ on = [ "P" ], run = "paste --before", desc = "Paste the copied characters before the cursor" },
|
||||
|
||||
# Undo/Redo
|
||||
{ on = [ "u" ], exec = "undo", desc = "Undo the last operation" },
|
||||
{ on = [ "<C-r>" ], exec = "redo", desc = "Redo the last operation" },
|
||||
{ on = [ "u" ], run = "undo", desc = "Undo the last operation" },
|
||||
{ on = [ "<C-r>" ], run = "redo", desc = "Redo the last operation" },
|
||||
|
||||
# Help
|
||||
{ on = [ "~" ], exec = "help", desc = "Open help" }
|
||||
{ on = [ "~" ], run = "help", desc = "Open help" }
|
||||
]
|
||||
|
||||
[completion]
|
||||
|
||||
keymap = [
|
||||
{ on = [ "<C-q>" ], exec = "close", desc = "Cancel completion" },
|
||||
{ on = [ "<Tab>" ], exec = "close --submit", desc = "Submit the completion" },
|
||||
{ on = [ "<Enter>" ], exec = [ "close --submit", "close_input --submit" ], desc = "Submit the completion and input" },
|
||||
{ on = [ "<C-q>" ], run = "close", desc = "Cancel completion" },
|
||||
{ on = [ "<Tab>" ], run = "close --submit", desc = "Submit the completion" },
|
||||
{ on = [ "<Enter>" ], run = [ "close --submit", "close_input --submit" ], desc = "Submit the completion and input" },
|
||||
|
||||
{ on = [ "<A-k>" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<A-j>" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||
{ on = [ "<A-k>" ], run = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<A-j>" ], run = "arrow 1", desc = "Move cursor down" },
|
||||
|
||||
{ on = [ "<Up>" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<Down>" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||
{ on = [ "<Up>" ], run = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<Down>" ], run = "arrow 1", desc = "Move cursor down" },
|
||||
|
||||
{ on = [ "~" ], exec = "help", desc = "Open help" }
|
||||
{ on = [ "~" ], run = "help", desc = "Open help" }
|
||||
]
|
||||
|
||||
[help]
|
||||
|
||||
keymap = [
|
||||
{ on = [ "<Esc>" ], exec = "escape", desc = "Clear the filter, or hide the help" },
|
||||
{ on = [ "q" ], exec = "close", desc = "Exit the process" },
|
||||
{ on = [ "<C-q>" ], exec = "close", desc = "Hide the help" },
|
||||
{ on = [ "<Esc>" ], run = "escape", desc = "Clear the filter, or hide the help" },
|
||||
{ on = [ "<C-[>" ], run = "escape", desc = "Clear the filter, or hide the help" },
|
||||
{ on = [ "q" ], run = "close", desc = "Exit the process" },
|
||||
{ on = [ "<C-q>" ], run = "close", desc = "Hide the help" },
|
||||
|
||||
# Navigation
|
||||
{ on = [ "k" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "j" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||
{ on = [ "k" ], run = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "j" ], run = "arrow 1", desc = "Move cursor down" },
|
||||
|
||||
{ on = [ "K" ], exec = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "J" ], exec = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
{ on = [ "K" ], run = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "J" ], run = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
|
||||
{ on = [ "<Up>" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<Down>" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||
{ on = [ "<Up>" ], run = "arrow -1", desc = "Move cursor up" },
|
||||
{ on = [ "<Down>" ], run = "arrow 1", desc = "Move cursor down" },
|
||||
|
||||
{ on = [ "<S-Up>" ], exec = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "<S-Down>" ], exec = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
{ on = [ "<S-Up>" ], run = "arrow -5", desc = "Move cursor up 5 lines" },
|
||||
{ on = [ "<S-Down>" ], run = "arrow 5", desc = "Move cursor down 5 lines" },
|
||||
|
||||
# Filtering
|
||||
{ on = [ "/" ], exec = "filter", desc = "Apply a filter for the help items" },
|
||||
{ on = [ "/" ], run = "filter", desc = "Apply a filter for the help items" },
|
||||
]
|
||||
|
|
|
|||
|
|
@ -4,6 +4,13 @@
|
|||
|
||||
# vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
# : Flavor {{{
|
||||
|
||||
[flavor]
|
||||
use = ""
|
||||
|
||||
# : }}}
|
||||
|
||||
# : Manager {{{
|
||||
|
||||
[manager]
|
||||
|
|
@ -137,7 +144,7 @@ separator_style = { fg = "darkgray" }
|
|||
|
||||
[help]
|
||||
on = { fg = "magenta" }
|
||||
exec = { fg = "cyan" }
|
||||
run = { fg = "cyan" }
|
||||
desc = { fg = "gray" }
|
||||
hovered = { bg = "darkgray", bold = true }
|
||||
footer = { fg = "black", bg = "white" }
|
||||
|
|
@ -145,6 +152,21 @@ footer = { fg = "black", bg = "white" }
|
|||
# : }}}
|
||||
|
||||
|
||||
# : Notify {{{
|
||||
|
||||
[notify]
|
||||
title_info = { fg = "green" }
|
||||
title_warn = { fg = "yellow" }
|
||||
title_error = { fg = "red" }
|
||||
|
||||
# Icons
|
||||
icon_info = ""
|
||||
icon_warn = ""
|
||||
icon_error = ""
|
||||
|
||||
# : }}}
|
||||
|
||||
|
||||
# : File-specific styles {{{
|
||||
|
||||
[filetype]
|
||||
|
|
|
|||
|
|
@ -26,27 +26,28 @@ ueberzug_offset = [ 0, 0, 0, 0 ]
|
|||
|
||||
[opener]
|
||||
edit = [
|
||||
{ exec = '${EDITOR:=vi} "$@"', desc = "$EDITOR", block = true, for = "unix" },
|
||||
{ exec = 'code "%*"', orphan = true, for = "windows" },
|
||||
{ run = '${EDITOR:=vi} "$@"', desc = "$EDITOR", block = true, for = "unix" },
|
||||
{ run = 'code "%*"', orphan = true, desc = "code", for = "windows" },
|
||||
{ run = 'code -w "%*"', block = true, desc = "code (block)", for = "windows" },
|
||||
]
|
||||
open = [
|
||||
{ exec = 'xdg-open "$@"', desc = "Open", for = "linux" },
|
||||
{ exec = 'open "$@"', desc = "Open", for = "macos" },
|
||||
{ exec = 'start "" "%1"', orphan = true, desc = "Open", for = "windows" }
|
||||
{ run = 'xdg-open "$@"', desc = "Open", for = "linux" },
|
||||
{ run = 'open "$@"', desc = "Open", for = "macos" },
|
||||
{ run = 'start "" "%1"', orphan = true, desc = "Open", for = "windows" },
|
||||
]
|
||||
reveal = [
|
||||
{ exec = 'open -R "$1"', desc = "Reveal", for = "macos" },
|
||||
{ exec = 'explorer /select, "%1"', orphan = true, desc = "Reveal", for = "windows" },
|
||||
{ exec = '''exiftool "$1"; echo "Press enter to exit"; read''', block = true, desc = "Show EXIF", for = "unix" },
|
||||
{ run = 'open -R "$1"', desc = "Reveal", for = "macos" },
|
||||
{ run = 'explorer /select, "%1"', orphan = true, desc = "Reveal", for = "windows" },
|
||||
{ run = '''exiftool "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show EXIF", for = "unix" },
|
||||
]
|
||||
extract = [
|
||||
{ exec = 'unar "$1"', desc = "Extract here", for = "unix" },
|
||||
{ exec = 'unar "%1"', desc = "Extract here", for = "windows" },
|
||||
{ run = 'unar "$1"', desc = "Extract here", for = "unix" },
|
||||
{ run = 'unar "%1"', desc = "Extract here", for = "windows" },
|
||||
]
|
||||
play = [
|
||||
{ exec = 'mpv "$@"', orphan = true, for = "unix" },
|
||||
{ exec = 'mpv "%1"', orphan = true, for = "windows" },
|
||||
{ exec = '''mediainfo "$1"; echo "Press enter to exit"; read''', block = true, desc = "Show media info", for = "unix" },
|
||||
{ run = 'mpv "$@"', orphan = true, for = "unix" },
|
||||
{ run = 'mpv "%1"', orphan = true, for = "windows" },
|
||||
{ run = '''mediainfo "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show media info", for = "unix" },
|
||||
]
|
||||
|
||||
[open]
|
||||
|
|
@ -85,42 +86,42 @@ suppress_preload = false
|
|||
[plugin]
|
||||
|
||||
preloaders = [
|
||||
{ name = "*", cond = "!mime", exec = "mime", multi = true, prio = "high" },
|
||||
{ name = "*", cond = "!mime", run = "mime", multi = true, prio = "high" },
|
||||
# Image
|
||||
{ mime = "image/vnd.djvu", exec = "noop" },
|
||||
{ mime = "image/*", exec = "image" },
|
||||
{ mime = "image/vnd.djvu", run = "noop" },
|
||||
{ mime = "image/*", run = "image" },
|
||||
# Video
|
||||
{ mime = "video/*", exec = "video" },
|
||||
{ mime = "video/*", run = "video" },
|
||||
# PDF
|
||||
{ mime = "application/pdf", exec = "pdf" },
|
||||
{ mime = "application/pdf", run = "pdf" },
|
||||
]
|
||||
previewers = [
|
||||
{ name = "*/", exec = "folder", sync = true },
|
||||
{ name = "*/", run = "folder", sync = true },
|
||||
# Code
|
||||
{ mime = "text/*", exec = "code" },
|
||||
{ mime = "*/xml", exec = "code" },
|
||||
{ mime = "*/javascript", exec = "code" },
|
||||
{ mime = "*/x-wine-extension-ini", exec = "code" },
|
||||
{ mime = "text/*", run = "code" },
|
||||
{ mime = "*/xml", run = "code" },
|
||||
{ mime = "*/javascript", run = "code" },
|
||||
{ mime = "*/x-wine-extension-ini", run = "code" },
|
||||
# JSON
|
||||
{ mime = "application/json", exec = "json" },
|
||||
{ mime = "application/json", run = "json" },
|
||||
# Image
|
||||
{ mime = "image/vnd.djvu", exec = "noop" },
|
||||
{ mime = "image/*", exec = "image" },
|
||||
{ mime = "image/vnd.djvu", run = "noop" },
|
||||
{ mime = "image/*", run = "image" },
|
||||
# Video
|
||||
{ mime = "video/*", exec = "video" },
|
||||
{ mime = "video/*", run = "video" },
|
||||
# PDF
|
||||
{ mime = "application/pdf", exec = "pdf" },
|
||||
{ mime = "application/pdf", run = "pdf" },
|
||||
# Archive
|
||||
{ mime = "application/zip", exec = "archive" },
|
||||
{ mime = "application/gzip", exec = "archive" },
|
||||
{ mime = "application/x-tar", exec = "archive" },
|
||||
{ mime = "application/x-bzip", exec = "archive" },
|
||||
{ mime = "application/x-bzip2", exec = "archive" },
|
||||
{ mime = "application/x-7z-compressed", exec = "archive" },
|
||||
{ mime = "application/x-rar", exec = "archive" },
|
||||
{ mime = "application/xz", exec = "archive" },
|
||||
{ mime = "application/zip", run = "archive" },
|
||||
{ mime = "application/gzip", run = "archive" },
|
||||
{ mime = "application/x-tar", run = "archive" },
|
||||
{ mime = "application/x-bzip", run = "archive" },
|
||||
{ mime = "application/x-bzip2", run = "archive" },
|
||||
{ mime = "application/x-7z-compressed", run = "archive" },
|
||||
{ mime = "application/x-rar", run = "archive" },
|
||||
{ mime = "application/xz", run = "archive" },
|
||||
# Fallback
|
||||
{ name = "*", exec = "file" },
|
||||
{ name = "*", run = "file" },
|
||||
]
|
||||
|
||||
[input]
|
||||
|
|
|
|||
|
|
@ -1,22 +1,21 @@
|
|||
use std::{borrow::Cow, collections::VecDeque, ops::Deref};
|
||||
use std::{borrow::Cow, collections::VecDeque};
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
use super::Key;
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Control {
|
||||
pub on: Vec<Key>,
|
||||
#[serde(deserialize_with = "super::exec_deserialize")]
|
||||
pub exec: Vec<Cmd>,
|
||||
pub run: Vec<Cmd>,
|
||||
pub desc: Option<String>,
|
||||
}
|
||||
|
||||
impl Control {
|
||||
#[inline]
|
||||
pub fn to_seq(&self) -> VecDeque<Cmd> {
|
||||
self.exec.iter().map(|e| e.clone_without_data()).collect()
|
||||
self.run.iter().map(|e| e.clone_without_data()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -25,58 +24,47 @@ impl Control {
|
|||
pub fn on(&self) -> String { self.on.iter().map(ToString::to_string).collect() }
|
||||
|
||||
#[inline]
|
||||
pub fn exec(&self) -> String {
|
||||
self.exec.iter().map(|e| e.to_string()).collect::<Vec<_>>().join("; ")
|
||||
pub fn run(&self) -> String {
|
||||
self.run.iter().map(|e| e.to_string()).collect::<Vec<_>>().join("; ")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn desc_or_exec(&self) -> Cow<str> {
|
||||
if let Some(ref s) = self.desc { Cow::Borrowed(s) } else { self.exec().into() }
|
||||
pub fn desc_or_run(&self) -> Cow<str> {
|
||||
if let Some(ref s) = self.desc { Cow::Borrowed(s) } else { self.run().into() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains(&self, s: &str) -> bool {
|
||||
let s = s.to_lowercase();
|
||||
self.desc.as_ref().map(|d| d.to_lowercase().contains(&s)) == Some(true)
|
||||
|| self.exec().to_lowercase().contains(&s)
|
||||
|| self.run().to_lowercase().contains(&s)
|
||||
|| self.on().to_lowercase().contains(&s)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ControlCow {
|
||||
Owned(Control),
|
||||
Borrowed(&'static Control),
|
||||
}
|
||||
|
||||
impl From<&'static Control> for ControlCow {
|
||||
fn from(c: &'static Control) -> Self { Self::Borrowed(c) }
|
||||
}
|
||||
|
||||
impl From<Control> for ControlCow {
|
||||
fn from(c: Control) -> Self { Self::Owned(c) }
|
||||
}
|
||||
|
||||
impl Deref for ControlCow {
|
||||
type Target = Control;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Self::Owned(c) => c,
|
||||
Self::Borrowed(c) => c,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ControlCow {
|
||||
fn default() -> Self { Self::Owned(Control::default()) }
|
||||
}
|
||||
|
||||
impl ControlCow {
|
||||
pub fn into_seq(self) -> VecDeque<Cmd> {
|
||||
match self {
|
||||
Self::Owned(c) => c.exec.into(),
|
||||
Self::Borrowed(c) => c.to_seq(),
|
||||
// TODO: remove this once Yazi 0.3 is released
|
||||
impl<'de> Deserialize<'de> for Control {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
pub struct Shadow {
|
||||
pub on: Vec<Key>,
|
||||
pub run: Option<VecCmd>,
|
||||
pub exec: Option<VecCmd>,
|
||||
pub desc: Option<String>,
|
||||
}
|
||||
|
||||
let shadow = Shadow::deserialize(deserializer)?;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct VecCmd(#[serde(deserialize_with = "super::run_deserialize")] Vec<Cmd>);
|
||||
|
||||
let Some(run) = shadow.run.or(shadow.exec) else {
|
||||
return Err(serde::de::Error::custom("missing field `run` within `[keymap]`"));
|
||||
};
|
||||
|
||||
Ok(Self { on: shadow.on, run: run.0, desc: shadow.desc })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
43
yazi-config/src/keymap/cow.rs
Normal file
43
yazi-config/src/keymap/cow.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use std::{collections::VecDeque, ops::Deref};
|
||||
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
use super::Control;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ControlCow {
|
||||
Owned(Control),
|
||||
Borrowed(&'static Control),
|
||||
}
|
||||
|
||||
impl From<&'static Control> for ControlCow {
|
||||
fn from(c: &'static Control) -> Self { Self::Borrowed(c) }
|
||||
}
|
||||
|
||||
impl From<Control> for ControlCow {
|
||||
fn from(c: Control) -> Self { Self::Owned(c) }
|
||||
}
|
||||
|
||||
impl Deref for ControlCow {
|
||||
type Target = Control;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Self::Owned(c) => c,
|
||||
Self::Borrowed(c) => c,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ControlCow {
|
||||
fn default() -> Self { Self::Owned(Control::default()) }
|
||||
}
|
||||
|
||||
impl ControlCow {
|
||||
pub fn into_seq(self) -> VecDeque<Cmd> {
|
||||
match self {
|
||||
Self::Owned(c) => c.run.into(),
|
||||
Self::Borrowed(c) => c.to_seq(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use std::str::FromStr;
|
||||
use std::{fmt::{Display, Write}, str::FromStr};
|
||||
|
||||
use anyhow::bail;
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||
|
|
@ -132,22 +132,22 @@ impl TryFrom<String> for Key {
|
|||
fn try_from(s: String) -> Result<Self, Self::Error> { Self::from_str(&s) }
|
||||
}
|
||||
|
||||
impl ToString for Key {
|
||||
fn to_string(&self) -> String {
|
||||
impl Display for Key {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(c) = self.plain() {
|
||||
let c = if self.shift { c.to_ascii_uppercase() } else { c };
|
||||
return if c == ' ' { "<Space>".to_string() } else { c.to_string() };
|
||||
return if c == ' ' { write!(f, "<Space>") } else { f.write_char(c) };
|
||||
}
|
||||
|
||||
let mut s = "<".to_string();
|
||||
write!(f, "<")?;
|
||||
if self.ctrl {
|
||||
s += "C-";
|
||||
write!(f, "C-")?;
|
||||
}
|
||||
if self.alt {
|
||||
s += "A-";
|
||||
write!(f, "A-")?;
|
||||
}
|
||||
if self.shift && !matches!(self.code, KeyCode::Char(_)) {
|
||||
s += "S-";
|
||||
write!(f, "S-")?;
|
||||
}
|
||||
|
||||
let code = match self.code {
|
||||
|
|
@ -181,12 +181,12 @@ impl ToString for Key {
|
|||
|
||||
KeyCode::Char(' ') => "Space",
|
||||
KeyCode::Char(c) => {
|
||||
s.push(if self.shift { c.to_ascii_uppercase() } else { c });
|
||||
f.write_char(if self.shift { c.to_ascii_uppercase() } else { c })?;
|
||||
""
|
||||
}
|
||||
_ => "Unknown",
|
||||
};
|
||||
|
||||
s + code + ">"
|
||||
write!(f, "{}>", code)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
mod control;
|
||||
mod exec;
|
||||
mod cow;
|
||||
mod key;
|
||||
mod keymap;
|
||||
mod run;
|
||||
|
||||
pub use control::*;
|
||||
#[allow(unused_imports)]
|
||||
pub use exec::*;
|
||||
pub use cow::*;
|
||||
pub use key::*;
|
||||
pub use keymap::*;
|
||||
#[allow(unused_imports)]
|
||||
pub use run::*;
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@ use anyhow::{bail, Result};
|
|||
use serde::{de::{self, Visitor}, Deserializer};
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
pub(super) fn exec_deserialize<'de, D>(deserializer: D) -> Result<Vec<Cmd>, D::Error>
|
||||
pub(super) fn run_deserialize<'de, D>(deserializer: D) -> Result<Vec<Cmd>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct ExecVisitor;
|
||||
struct RunVisitor;
|
||||
|
||||
fn parse(s: &str) -> Result<Cmd> {
|
||||
let s = shell_words::split(s)?;
|
||||
if s.is_empty() {
|
||||
bail!("`exec` cannot be empty");
|
||||
bail!("`run` cannot be empty");
|
||||
}
|
||||
|
||||
let mut cmd = Cmd { name: s[0].clone(), ..Default::default() };
|
||||
|
|
@ -30,11 +30,11 @@ where
|
|||
Ok(cmd)
|
||||
}
|
||||
|
||||
impl<'de> Visitor<'de> for ExecVisitor {
|
||||
impl<'de> Visitor<'de> for RunVisitor {
|
||||
type Value = Vec<Cmd>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a `exec` string or array of strings within [keymap]")
|
||||
formatter.write_str("a `run` string or array of strings within keymap.toml")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
|
|
@ -46,7 +46,7 @@ where
|
|||
cmds.push(parse(value).map_err(de::Error::custom)?);
|
||||
}
|
||||
if cmds.is_empty() {
|
||||
return Err(de::Error::custom("`exec` within [keymap] cannot be empty"));
|
||||
return Err(de::Error::custom("`run` within keymap.toml cannot be empty"));
|
||||
}
|
||||
Ok(cmds)
|
||||
}
|
||||
|
|
@ -59,5 +59,5 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(ExecVisitor)
|
||||
deserializer.deserialize_any(RunVisitor)
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(clippy::module_inception)]
|
||||
|
||||
use yazi_shared::RoCell;
|
||||
use yazi_shared::{RoCell, Xdg};
|
||||
|
||||
pub mod keymap;
|
||||
mod layout;
|
||||
|
|
@ -23,11 +23,11 @@ pub(crate) use pattern::*;
|
|||
pub(crate) use preset::*;
|
||||
pub use priority::*;
|
||||
|
||||
pub static LAYOUT: RoCell<arc_swap::ArcSwap<Layout>> = RoCell::new();
|
||||
|
||||
static MERGED_YAZI: RoCell<String> = RoCell::new();
|
||||
static MERGED_KEYMAP: RoCell<String> = RoCell::new();
|
||||
static MERGED_THEME: RoCell<String> = RoCell::new();
|
||||
static MERGED_YAZI: RoCell<String> = RoCell::new();
|
||||
|
||||
pub static LAYOUT: RoCell<arc_swap::ArcSwap<Layout>> = RoCell::new();
|
||||
|
||||
pub static KEYMAP: RoCell<keymap::Keymap> = RoCell::new();
|
||||
pub static LOG: RoCell<log::Log> = RoCell::new();
|
||||
|
|
@ -42,12 +42,12 @@ pub static SELECT: RoCell<popup::Select> = RoCell::new();
|
|||
pub static WHICH: RoCell<which::Which> = RoCell::new();
|
||||
|
||||
pub fn init() {
|
||||
LAYOUT.with(Default::default);
|
||||
|
||||
let config_dir = yazi_shared::Xdg::config_dir().unwrap();
|
||||
let config_dir = Xdg::config_dir();
|
||||
MERGED_YAZI.init(Preset::yazi(&config_dir));
|
||||
MERGED_KEYMAP.init(Preset::keymap(&config_dir));
|
||||
MERGED_THEME.init(Preset::theme(&config_dir));
|
||||
MERGED_YAZI.init(Preset::yazi(&config_dir));
|
||||
|
||||
LAYOUT.with(Default::default);
|
||||
|
||||
KEYMAP.with(Default::default);
|
||||
LOG.with(Default::default);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::str::FromStr;
|
||||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
use anyhow::bail;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -39,9 +39,9 @@ impl TryFrom<String> for SortBy {
|
|||
fn try_from(s: String) -> Result<Self, Self::Error> { Self::from_str(&s) }
|
||||
}
|
||||
|
||||
impl ToString for SortBy {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
impl Display for SortBy {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
Self::None => "none",
|
||||
Self::Modified => "modified",
|
||||
Self::Created => "created",
|
||||
|
|
@ -49,7 +49,6 @@ impl ToString for SortBy {
|
|||
Self::Alphabetical => "alphabetical",
|
||||
Self::Natural => "natural",
|
||||
Self::Size => "size",
|
||||
}
|
||||
.to_string()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use serde::{Deserialize, Deserializer};
|
|||
use yazi_shared::MIME_DIR;
|
||||
|
||||
use super::Opener;
|
||||
use crate::{open::OpenRule, MERGED_YAZI};
|
||||
use crate::{open::OpenRule, Preset, MERGED_YAZI};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Open {
|
||||
|
|
@ -70,15 +70,22 @@ impl<'de> Deserialize<'de> for Open {
|
|||
}
|
||||
#[derive(Deserialize)]
|
||||
struct OuterOpen {
|
||||
rules: Vec<OpenRule>,
|
||||
rules: Vec<OpenRule>,
|
||||
#[serde(default)]
|
||||
prepend_rules: Vec<OpenRule>,
|
||||
#[serde(default)]
|
||||
append_rules: Vec<OpenRule>,
|
||||
}
|
||||
|
||||
let outer = Outer::deserialize(deserializer)?;
|
||||
let mut outer = Outer::deserialize(deserializer)?;
|
||||
Preset::mix(&mut outer.open.rules, outer.open.prepend_rules, outer.open.append_rules);
|
||||
|
||||
let openers = outer
|
||||
.opener
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, v.into_iter().filter_map(|o| o.take()).collect::<IndexSet<_>>()))
|
||||
.collect();
|
||||
|
||||
Ok(Self { rules: outer.open.rules, openers })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use serde::{Deserialize, Deserializer};
|
|||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Opener {
|
||||
pub exec: String,
|
||||
pub run: String,
|
||||
pub block: bool,
|
||||
pub orphan: bool,
|
||||
pub desc: String,
|
||||
|
|
@ -32,7 +32,9 @@ impl<'de> Deserialize<'de> for Opener {
|
|||
{
|
||||
#[derive(Deserialize)]
|
||||
pub struct Shadow {
|
||||
exec: String,
|
||||
run: Option<String>,
|
||||
// TODO: remove this once Yazi 0.3 is released --
|
||||
exec: Option<String>,
|
||||
#[serde(default)]
|
||||
block: bool,
|
||||
#[serde(default)]
|
||||
|
|
@ -43,22 +45,18 @@ impl<'de> Deserialize<'de> for Opener {
|
|||
}
|
||||
|
||||
let shadow = Shadow::deserialize(deserializer)?;
|
||||
if shadow.exec.is_empty() {
|
||||
return Err(serde::de::Error::custom("`exec` cannot be empty"));
|
||||
|
||||
// TODO: remove this once Yazi 0.3 is released --
|
||||
let run = shadow.run.or(shadow.exec).unwrap_or_default();
|
||||
// TODO: -- remove this once Yazi 0.3 is released
|
||||
|
||||
if run.is_empty() {
|
||||
return Err(serde::de::Error::custom("`run` cannot be empty"));
|
||||
}
|
||||
|
||||
let desc =
|
||||
shadow.desc.unwrap_or_else(|| shadow.exec.split_whitespace().next().unwrap().to_string());
|
||||
let desc = shadow.desc.unwrap_or_else(|| run.split_whitespace().next().unwrap().to_string());
|
||||
|
||||
let spread =
|
||||
shadow.exec.contains("$@") || shadow.exec.contains("%*") || shadow.exec.contains("$*");
|
||||
Ok(Self {
|
||||
exec: shadow.exec,
|
||||
block: shadow.block,
|
||||
orphan: shadow.orphan,
|
||||
desc,
|
||||
for_: shadow.for_,
|
||||
spread,
|
||||
})
|
||||
let spread = run.contains("$@") || run.contains("%*") || run.contains("$*");
|
||||
Ok(Self { run, block: shadow.block, orphan: shadow.orphan, desc, for_: shadow.for_, spread })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
mod exec;
|
||||
mod plugin;
|
||||
mod props;
|
||||
mod rule;
|
||||
mod run;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub use exec::*;
|
||||
pub use plugin::*;
|
||||
pub use props::*;
|
||||
pub use rule::*;
|
||||
#[allow(unused_imports)]
|
||||
pub use run::*;
|
||||
|
||||
pub const MAX_PRELOADERS: u8 = 32;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use std::path::Path;
|
||||
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::{event::Cmd, Condition, MIME_DIR};
|
||||
use yazi_shared::MIME_DIR;
|
||||
|
||||
use crate::{pattern::Pattern, plugin::MAX_PRELOADERS, Preset, Priority, MERGED_YAZI};
|
||||
use super::PluginRule;
|
||||
use crate::{plugin::MAX_PRELOADERS, Preset, MERGED_YAZI};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Plugin {
|
||||
|
|
@ -86,29 +87,3 @@ impl Plugin {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct PluginRule {
|
||||
#[serde(default)]
|
||||
pub id: u8,
|
||||
pub cond: Option<Condition>,
|
||||
pub name: Option<Pattern>,
|
||||
pub mime: Option<Pattern>,
|
||||
#[serde(rename = "exec")]
|
||||
#[serde(deserialize_with = "super::exec_deserialize")]
|
||||
pub cmd: Cmd,
|
||||
#[serde(default)]
|
||||
pub sync: bool,
|
||||
#[serde(default)]
|
||||
pub multi: bool,
|
||||
#[serde(default)]
|
||||
pub prio: Priority,
|
||||
}
|
||||
|
||||
impl PluginRule {
|
||||
#[inline]
|
||||
fn any_file(&self) -> bool { self.name.as_ref().is_some_and(|p| p.any_file()) }
|
||||
|
||||
#[inline]
|
||||
fn any_dir(&self) -> bool { self.name.as_ref().is_some_and(|p| p.any_dir()) }
|
||||
}
|
||||
|
|
|
|||
68
yazi-config/src/plugin/rule.rs
Normal file
68
yazi-config/src/plugin/rule.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
use serde::{Deserialize, Deserializer};
|
||||
use yazi_shared::{event::Cmd, Condition};
|
||||
|
||||
use crate::{Pattern, Priority};
|
||||
|
||||
pub struct PluginRule {
|
||||
pub id: u8,
|
||||
pub cond: Option<Condition>,
|
||||
pub name: Option<Pattern>,
|
||||
pub mime: Option<Pattern>,
|
||||
pub cmd: Cmd,
|
||||
pub sync: bool,
|
||||
pub multi: bool,
|
||||
pub prio: Priority,
|
||||
}
|
||||
|
||||
impl PluginRule {
|
||||
#[inline]
|
||||
pub fn any_file(&self) -> bool { self.name.as_ref().is_some_and(|p| p.any_file()) }
|
||||
|
||||
#[inline]
|
||||
pub fn any_dir(&self) -> bool { self.name.as_ref().is_some_and(|p| p.any_dir()) }
|
||||
}
|
||||
|
||||
// TODO: remove this once Yazi 0.3 is released
|
||||
impl<'de> Deserialize<'de> for PluginRule {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
pub struct Shadow {
|
||||
#[serde(default)]
|
||||
pub id: u8,
|
||||
pub cond: Option<Condition>,
|
||||
pub name: Option<Pattern>,
|
||||
pub mime: Option<Pattern>,
|
||||
pub run: Option<WrappedCmd>,
|
||||
pub exec: Option<WrappedCmd>,
|
||||
#[serde(default)]
|
||||
pub sync: bool,
|
||||
#[serde(default)]
|
||||
pub multi: bool,
|
||||
#[serde(default)]
|
||||
pub prio: Priority,
|
||||
}
|
||||
|
||||
let shadow = Shadow::deserialize(deserializer)?;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct WrappedCmd(#[serde(deserialize_with = "super::run_deserialize")] Cmd);
|
||||
|
||||
let Some(run) = shadow.run.or(shadow.exec) else {
|
||||
return Err(serde::de::Error::custom("missing field `run` within `[plugin]`"));
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
id: shadow.id,
|
||||
cond: shadow.cond,
|
||||
name: shadow.name,
|
||||
mime: shadow.mime,
|
||||
cmd: run.0,
|
||||
sync: shadow.sync,
|
||||
multi: shadow.multi,
|
||||
prio: shadow.prio,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -4,24 +4,24 @@ use anyhow::Result;
|
|||
use serde::{de::{self, Visitor}, Deserializer};
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
pub(super) fn exec_deserialize<'de, D>(deserializer: D) -> Result<Cmd, D::Error>
|
||||
pub(super) fn run_deserialize<'de, D>(deserializer: D) -> Result<Cmd, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct ExecVisitor;
|
||||
struct RunVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ExecVisitor {
|
||||
impl<'de> Visitor<'de> for RunVisitor {
|
||||
type Value = Cmd;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a `exec` string or array of strings")
|
||||
formatter.write_str("a `run` string or array of strings")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, _: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::SeqAccess<'de>,
|
||||
{
|
||||
Err(de::Error::custom("`exec` within [plugin] must be a string"))
|
||||
Err(de::Error::custom("`run` within [plugin] must be a string"))
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
|
|
@ -29,11 +29,11 @@ where
|
|||
E: de::Error,
|
||||
{
|
||||
if value.is_empty() {
|
||||
return Err(de::Error::custom("`exec` within [plugin] cannot be empty"));
|
||||
return Err(de::Error::custom("`run` within [plugin] cannot be empty"));
|
||||
}
|
||||
Ok(Cmd { name: value.to_owned(), ..Default::default() })
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(ExecVisitor)
|
||||
deserializer.deserialize_any(RunVisitor)
|
||||
}
|
||||
|
|
@ -1,24 +1,63 @@
|
|||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
use anyhow::bail;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Copy, Default, Deserialize, PartialEq, Eq)]
|
||||
#[serde(try_from = "String")]
|
||||
pub enum Origin {
|
||||
#[default]
|
||||
#[serde(rename = "top-left")]
|
||||
TopLeft,
|
||||
#[serde(rename = "top-center")]
|
||||
TopCenter,
|
||||
#[serde(rename = "top-right")]
|
||||
TopRight,
|
||||
|
||||
#[serde(rename = "bottom-left")]
|
||||
BottomLeft,
|
||||
#[serde(rename = "bottom-center")]
|
||||
BottomCenter,
|
||||
#[serde(rename = "bottom-right")]
|
||||
BottomRight,
|
||||
|
||||
#[serde(rename = "center")]
|
||||
Center,
|
||||
#[serde(rename = "hovered")]
|
||||
Hovered,
|
||||
}
|
||||
|
||||
impl FromStr for Origin {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(match s {
|
||||
"top-left" => Self::TopLeft,
|
||||
"top-center" => Self::TopCenter,
|
||||
"top-right" => Self::TopRight,
|
||||
|
||||
"bottom-left" => Self::BottomLeft,
|
||||
"bottom-center" => Self::BottomCenter,
|
||||
"bottom-right" => Self::BottomRight,
|
||||
|
||||
"center" => Self::Center,
|
||||
"hovered" => Self::Hovered,
|
||||
_ => bail!("Invalid `origin` value: {s}"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for Origin {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> { Self::from_str(&value) }
|
||||
}
|
||||
|
||||
impl Display for Origin {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
Self::TopLeft => "top-left",
|
||||
Self::TopCenter => "top-center",
|
||||
Self::TopRight => "top-right",
|
||||
|
||||
Self::BottomLeft => "bottom-left",
|
||||
Self::BottomCenter => "bottom-center",
|
||||
Self::BottomRight => "bottom-right",
|
||||
|
||||
Self::Center => "center",
|
||||
Self::Hovered => "hovered",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,35 @@
|
|||
use std::{mem, path::{Path, PathBuf}};
|
||||
|
||||
use anyhow::Context;
|
||||
use toml::{Table, Value};
|
||||
|
||||
use crate::theme::Flavor;
|
||||
|
||||
pub(crate) struct Preset;
|
||||
|
||||
impl Preset {
|
||||
#[inline]
|
||||
pub(crate) fn keymap(dir: &Path) -> String {
|
||||
Self::merge_str(dir.join("keymap.toml"), include_str!("../preset/keymap.toml"))
|
||||
pub(crate) fn yazi(p: &Path) -> String {
|
||||
Self::merge_path(p.join("yazi.toml"), include_str!("../preset/yazi.toml"))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn theme(dir: &Path) -> String {
|
||||
Self::merge_str(dir.join("theme.toml"), include_str!("../preset/theme.toml"))
|
||||
pub(crate) fn keymap(p: &Path) -> String {
|
||||
Self::merge_path(p.join("keymap.toml"), include_str!("../preset/keymap.toml"))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn yazi(dir: &Path) -> String {
|
||||
Self::merge_str(dir.join("yazi.toml"), include_str!("../preset/yazi.toml"))
|
||||
pub(crate) fn theme(p: &Path) -> String {
|
||||
let Ok(user) = std::fs::read_to_string(p.join("theme.toml")) else {
|
||||
return include_str!("../preset/theme.toml").to_owned();
|
||||
};
|
||||
let Some(use_) = Flavor::parse_use(&user) else {
|
||||
return Self::merge_str(&user, include_str!("../preset/theme.toml"));
|
||||
};
|
||||
|
||||
let p = p.join(format!("flavors/{}.yazi/flavor.toml", use_));
|
||||
let flavor = std::fs::read_to_string(&p)
|
||||
.with_context(|| format!("Failed to load flavor {:?}", p))
|
||||
.unwrap();
|
||||
|
||||
Self::merge_str(&user, &Self::merge_str(&flavor, include_str!("../preset/theme.toml")))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -25,6 +37,24 @@ impl Preset {
|
|||
*a = b.into_iter().chain(mem::take(a)).chain(c).collect();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn merge_str(user: &str, base: &str) -> String {
|
||||
let mut t = user.parse().unwrap();
|
||||
Self::merge(&mut t, base.parse().unwrap(), 2);
|
||||
|
||||
t.to_string()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn merge_path(user: PathBuf, base: &str) -> String {
|
||||
let s = std::fs::read_to_string(user).unwrap_or_default();
|
||||
if s.is_empty() {
|
||||
return base.to_string();
|
||||
}
|
||||
|
||||
Self::merge_str(&s, base)
|
||||
}
|
||||
|
||||
fn merge(a: &mut Table, b: Table, max: u8) {
|
||||
for (k, v) in b {
|
||||
let Some(a) = a.get_mut(&k) else {
|
||||
|
|
@ -45,12 +75,4 @@ impl Preset {
|
|||
*a = v;
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_str(user: PathBuf, base: &str) -> String {
|
||||
let mut user = std::fs::read_to_string(user).unwrap_or_default().parse::<Table>().unwrap();
|
||||
let base = base.parse::<Table>().unwrap();
|
||||
|
||||
Self::merge(&mut user, base, 2);
|
||||
user.to_string()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ use std::{fs, path::PathBuf, time::{self, SystemTime}};
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
use yazi_shared::{fs::expand_path, Xdg};
|
||||
use yazi_shared::fs::expand_path;
|
||||
|
||||
use crate::{validation::check_validation, MERGED_YAZI};
|
||||
use crate::{validation::check_validation, Xdg, MERGED_YAZI};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Preview {
|
||||
|
|
|
|||
23
yazi-config/src/theme/flavor.rs
Normal file
23
yazi-config/src/theme/flavor.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Flavor {
|
||||
#[serde(rename = "use")]
|
||||
pub use_: String,
|
||||
}
|
||||
|
||||
impl Flavor {
|
||||
pub fn parse_use(s: &str) -> Option<String> {
|
||||
#[derive(Deserialize)]
|
||||
struct Outer {
|
||||
flavor: Inner,
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
struct Inner {
|
||||
#[serde(rename = "use")]
|
||||
pub use_: String,
|
||||
}
|
||||
|
||||
toml::from_str::<Outer>(s).ok().map(|o| o.flavor.use_).filter(|s| !s.is_empty())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
mod color;
|
||||
mod filetype;
|
||||
mod flavor;
|
||||
mod icon;
|
||||
mod is;
|
||||
mod style;
|
||||
|
|
@ -7,6 +8,7 @@ mod theme;
|
|||
|
||||
pub use color::*;
|
||||
pub use filetype::*;
|
||||
pub use flavor::*;
|
||||
pub use icon::*;
|
||||
pub use is::*;
|
||||
pub use style::*;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,49 @@ use std::path::PathBuf;
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
use yazi_shared::fs::expand_path;
|
||||
use yazi_shared::{fs::expand_path, Xdg};
|
||||
|
||||
use super::{Filetype, Icon, Style};
|
||||
use super::{Filetype, Flavor, Icon, Style};
|
||||
use crate::{validation::check_validation, MERGED_THEME};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Theme {
|
||||
pub flavor: Flavor,
|
||||
pub manager: Manager,
|
||||
status: Status,
|
||||
pub input: Input,
|
||||
pub select: Select,
|
||||
pub completion: Completion,
|
||||
pub tasks: Tasks,
|
||||
pub which: Which,
|
||||
pub help: Help,
|
||||
pub notify: Notify,
|
||||
|
||||
// File-specific styles
|
||||
#[serde(rename = "filetype", deserialize_with = "Filetype::deserialize", skip_serializing)]
|
||||
pub filetypes: Vec<Filetype>,
|
||||
#[serde(rename = "icon", deserialize_with = "Icon::deserialize", skip_serializing)]
|
||||
pub icons: Vec<Icon>,
|
||||
}
|
||||
|
||||
impl Default for Theme {
|
||||
fn default() -> Self {
|
||||
let mut theme: Self = toml::from_str(&MERGED_THEME).unwrap();
|
||||
|
||||
check_validation(theme.manager.validate());
|
||||
check_validation(theme.which.validate());
|
||||
|
||||
if theme.flavor.use_.is_empty() {
|
||||
theme.manager.syntect_theme = expand_path(&theme.manager.syntect_theme);
|
||||
} else {
|
||||
theme.manager.syntect_theme =
|
||||
Xdg::config_dir().join(format!("flavors/{}.yazi/tmtheme.xml", theme.flavor.use_));
|
||||
}
|
||||
|
||||
theme
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Validate)]
|
||||
pub struct Manager {
|
||||
cwd: Style,
|
||||
|
|
@ -118,7 +156,7 @@ pub struct Which {
|
|||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Help {
|
||||
pub on: Style,
|
||||
pub exec: Style,
|
||||
pub run: Style,
|
||||
pub desc: Style,
|
||||
|
||||
pub hovered: Style,
|
||||
|
|
@ -126,32 +164,12 @@ pub struct Help {
|
|||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Theme {
|
||||
pub manager: Manager,
|
||||
status: Status,
|
||||
pub input: Input,
|
||||
pub select: Select,
|
||||
pub completion: Completion,
|
||||
pub tasks: Tasks,
|
||||
pub which: Which,
|
||||
pub help: Help,
|
||||
pub struct Notify {
|
||||
pub title_info: Style,
|
||||
pub title_warn: Style,
|
||||
pub title_error: Style,
|
||||
|
||||
// File-specific styles
|
||||
#[serde(rename = "filetype", deserialize_with = "Filetype::deserialize", skip_serializing)]
|
||||
pub filetypes: Vec<Filetype>,
|
||||
#[serde(rename = "icon", deserialize_with = "Icon::deserialize", skip_serializing)]
|
||||
pub icons: Vec<Icon>,
|
||||
}
|
||||
|
||||
impl Default for Theme {
|
||||
fn default() -> Self {
|
||||
let mut theme: Self = toml::from_str(&MERGED_THEME).unwrap();
|
||||
|
||||
check_validation(theme.manager.validate());
|
||||
check_validation(theme.which.validate());
|
||||
|
||||
theme.manager.syntect_theme = expand_path(&theme.manager.syntect_theme);
|
||||
|
||||
theme
|
||||
}
|
||||
pub icon_info: String,
|
||||
pub icon_warn: String,
|
||||
pub icon_error: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ impl FromStr for SortBy {
|
|||
"none" => Self::None,
|
||||
"key" => Self::Key,
|
||||
"desc" => Self::Desc,
|
||||
_ => bail!("Invalid sort option: {s}"),
|
||||
_ => bail!("Invalid `sort_by` value: {s}"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ yazi-adaptor = { path = "../yazi-adaptor", version = "0.2.3" }
|
|||
yazi-boot = { path = "../yazi-boot", version = "0.2.3" }
|
||||
yazi-config = { path = "../yazi-config", version = "0.2.3" }
|
||||
yazi-plugin = { path = "../yazi-plugin", version = "0.2.3" }
|
||||
yazi-proxy = { path = "../yazi-proxy", version = "0.2.3" }
|
||||
yazi-scheduler = { path = "../yazi-scheduler", version = "0.2.3" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "0.2.3" }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use yazi_shared::{emit, event::Cmd, render, Layer};
|
||||
use yazi_proxy::InputProxy;
|
||||
use yazi_shared::{event::Cmd, render};
|
||||
|
||||
use crate::{completion::Completion, input::Input};
|
||||
use crate::completion::Completion;
|
||||
|
||||
pub struct Opt {
|
||||
submit: bool,
|
||||
|
|
@ -11,16 +12,11 @@ impl From<Cmd> for Opt {
|
|||
}
|
||||
|
||||
impl Completion {
|
||||
#[inline]
|
||||
pub fn _close() {
|
||||
emit!(Call(Cmd::new("close"), Layer::Completion));
|
||||
}
|
||||
|
||||
pub fn close(&mut self, opt: impl Into<Opt>) {
|
||||
let opt = opt.into() as Opt;
|
||||
|
||||
if let Some(s) = self.selected().filter(|_| opt.submit) {
|
||||
Input::_complete(s, self.ticket);
|
||||
InputProxy::complete(s, self.ticket);
|
||||
}
|
||||
|
||||
self.caches.clear();
|
||||
|
|
|
|||
|
|
@ -20,14 +20,6 @@ impl From<Cmd> for Opt {
|
|||
}
|
||||
|
||||
impl Completion {
|
||||
#[inline]
|
||||
pub fn _trigger(word: &str, ticket: usize) {
|
||||
emit!(Call(
|
||||
Cmd::args("trigger", vec![word.to_owned()]).with("ticket", ticket),
|
||||
Layer::Completion
|
||||
));
|
||||
}
|
||||
|
||||
pub fn trigger(&mut self, opt: impl Into<Opt>) {
|
||||
let opt = opt.into() as Opt;
|
||||
if opt.ticket < self.ticket {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ use std::{mem, time::SystemTime};
|
|||
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_config::{LAYOUT, MANAGER};
|
||||
use yazi_proxy::ManagerProxy;
|
||||
use yazi_shared::fs::{File, FilesOp, Url};
|
||||
|
||||
use super::FolderStage;
|
||||
use crate::{folder::Files, manager::Manager, Step};
|
||||
use crate::{folder::Files, Step};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Folder {
|
||||
|
|
@ -99,7 +100,7 @@ impl Folder {
|
|||
|
||||
let new = self.cursor / limit;
|
||||
if mem::replace(&mut self.page, new) != new || force {
|
||||
Manager::_update_paged_by(new, &self.cwd);
|
||||
ManagerProxy::update_paged_by(new, &self.cwd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use yazi_proxy::CompletionProxy;
|
||||
use yazi_shared::{event::Cmd, render, InputError};
|
||||
|
||||
use crate::{completion::Completion, input::Input};
|
||||
use crate::input::Input;
|
||||
|
||||
pub struct Opt {
|
||||
submit: bool,
|
||||
|
|
@ -18,7 +19,7 @@ impl Input {
|
|||
let opt = opt.into() as Opt;
|
||||
|
||||
if self.completion {
|
||||
Completion::_close();
|
||||
CompletionProxy::close();
|
||||
}
|
||||
|
||||
if let Some(cb) = self.callback.take() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::path::MAIN_SEPARATOR;
|
||||
|
||||
use yazi_shared::{emit, event::Cmd, render, Layer};
|
||||
use yazi_shared::{event::Cmd, render};
|
||||
|
||||
use crate::input::Input;
|
||||
|
||||
|
|
@ -19,11 +19,6 @@ impl From<Cmd> for Opt {
|
|||
}
|
||||
|
||||
impl Input {
|
||||
#[inline]
|
||||
pub fn _complete(word: &str, ticket: usize) {
|
||||
emit!(Call(Cmd::args("complete", vec![word.to_owned()]).with("ticket", ticket), Layer::Input));
|
||||
}
|
||||
|
||||
pub fn complete(&mut self, opt: impl Into<Opt>) {
|
||||
let opt = opt.into() as Opt;
|
||||
if self.ticket != opt.ticket {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use yazi_proxy::CompletionProxy;
|
||||
use yazi_shared::{event::Cmd, render};
|
||||
|
||||
use crate::{completion::Completion, input::{op::InputOp, Input, InputMode}};
|
||||
use crate::input::{op::InputOp, Input, InputMode};
|
||||
|
||||
pub struct Opt;
|
||||
|
||||
|
|
@ -26,7 +27,7 @@ impl Input {
|
|||
self.move_(-1);
|
||||
|
||||
if self.completion {
|
||||
Completion::_close();
|
||||
CompletionProxy::close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,10 @@
|
|||
use tokio::sync::mpsc;
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_shared::{emit, event::Cmd, render, InputError, Layer};
|
||||
use yazi_proxy::options::InputOpt;
|
||||
use yazi_shared::render;
|
||||
|
||||
use crate::input::Input;
|
||||
|
||||
pub struct Opt {
|
||||
cfg: InputCfg,
|
||||
tx: mpsc::UnboundedSender<Result<String, InputError>>,
|
||||
}
|
||||
|
||||
impl TryFrom<Cmd> for Opt {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
|
||||
}
|
||||
|
||||
impl Input {
|
||||
pub fn _show(cfg: InputCfg) -> mpsc::UnboundedReceiver<Result<String, InputError>> {
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
emit!(Call(Cmd::new("show").with_data(Opt { cfg, tx }), Layer::Input));
|
||||
rx
|
||||
}
|
||||
|
||||
pub fn show(&mut self, opt: impl TryInto<Opt>) {
|
||||
pub fn show(&mut self, opt: impl TryInto<InputOpt>) {
|
||||
let Ok(opt) = opt.try_into() else {
|
||||
return;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,8 +22,4 @@ pub mod which;
|
|||
pub use clipboard::*;
|
||||
pub use step::*;
|
||||
|
||||
pub fn init() {
|
||||
CLIPBOARD.with(Default::default);
|
||||
|
||||
yazi_scheduler::init();
|
||||
}
|
||||
pub fn init() { CLIPBOARD.with(Default::default); }
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use std::path::{PathBuf, MAIN_SEPARATOR};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use tokio::fs;
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_proxy::{InputProxy, ManagerProxy};
|
||||
use yazi_shared::{event::Cmd, fs::{File, FilesOp, Url}};
|
||||
|
||||
use crate::{input::Input, manager::Manager};
|
||||
use crate::manager::Manager;
|
||||
|
||||
pub struct Opt {
|
||||
force: bool,
|
||||
|
|
@ -19,20 +20,20 @@ impl Manager {
|
|||
let opt = opt.into() as Opt;
|
||||
let cwd = self.cwd().to_owned();
|
||||
tokio::spawn(async move {
|
||||
let mut result = Input::_show(InputCfg::create());
|
||||
let mut result = InputProxy::show(InputCfg::create());
|
||||
let Some(Ok(name)) = result.recv().await else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let path = cwd.join(&name);
|
||||
if !opt.force && fs::symlink_metadata(&path).await.is_ok() {
|
||||
match Input::_show(InputCfg::overwrite()).recv().await {
|
||||
match InputProxy::show(InputCfg::overwrite()).recv().await {
|
||||
Some(Ok(c)) if c == "y" || c == "Y" => (),
|
||||
_ => return Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
if name.ends_with(MAIN_SEPARATOR) {
|
||||
if name.ends_with('/') || name.ends_with('\\') {
|
||||
fs::create_dir_all(&path).await?;
|
||||
} else {
|
||||
fs::create_dir_all(&path.parent().unwrap()).await.ok();
|
||||
|
|
@ -43,7 +44,7 @@ impl Manager {
|
|||
Url::from(path.components().take(cwd.components().count() + 1).collect::<PathBuf>());
|
||||
if let Ok(f) = File::from(child.clone()).await {
|
||||
FilesOp::Creating(cwd, vec![f]).emit();
|
||||
Manager::_hover(Some(child));
|
||||
ManagerProxy::hover(Some(child));
|
||||
}
|
||||
Ok::<(), anyhow::Error>(())
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use yazi_shared::{emit, event::Cmd, fs::Url, render, Layer};
|
||||
use yazi_shared::{event::Cmd, fs::Url, render};
|
||||
|
||||
use crate::manager::Manager;
|
||||
|
||||
|
|
@ -16,14 +16,6 @@ impl From<Option<Url>> for Opt {
|
|||
}
|
||||
|
||||
impl Manager {
|
||||
#[inline]
|
||||
pub fn _hover(url: Option<Url>) {
|
||||
emit!(Call(
|
||||
Cmd::args("hover", url.map_or_else(Vec::new, |u| vec![u.to_string()])),
|
||||
Layer::Manager
|
||||
));
|
||||
}
|
||||
|
||||
pub fn hover(&mut self, opt: impl Into<Opt>) {
|
||||
let opt = opt.into() as Opt;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,20 +4,19 @@ use tracing::error;
|
|||
use yazi_boot::ARGS;
|
||||
use yazi_config::{popup::SelectCfg, OPEN};
|
||||
use yazi_plugin::isolate;
|
||||
use yazi_shared::{emit, event::{Cmd, EventQuit}, fs::{File, Url}, Layer, MIME_DIR};
|
||||
use yazi_proxy::{options::OpenDoOpt, ManagerProxy, TasksProxy};
|
||||
use yazi_shared::{emit, event::{Cmd, EventQuit}, fs::{File, Url}, MIME_DIR};
|
||||
|
||||
use crate::{folder::Folder, manager::Manager, select::Select, tasks::Tasks};
|
||||
use crate::{folder::Folder, manager::Manager, tasks::Tasks};
|
||||
|
||||
pub struct Opt {
|
||||
targets: Vec<(Url, String)>,
|
||||
interactive: bool,
|
||||
hovered: bool,
|
||||
}
|
||||
|
||||
impl From<Cmd> for Opt {
|
||||
fn from(mut c: Cmd) -> Self {
|
||||
fn from(c: Cmd) -> Self {
|
||||
Self {
|
||||
targets: c.take_data().unwrap_or_default(),
|
||||
interactive: c.named.contains_key("interactive"),
|
||||
hovered: c.named.contains_key("hovered"),
|
||||
}
|
||||
|
|
@ -29,23 +28,19 @@ impl Manager {
|
|||
if !self.active_mut().try_escape_visual() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut opt = opt.into() as Opt;
|
||||
let selected = if opt.hovered {
|
||||
self.hovered().map(|h| vec![&h.url]).unwrap_or_default()
|
||||
} else {
|
||||
self.selected_or_hovered()
|
||||
let Some(hovered) = self.hovered().map(|h| h.url()) else {
|
||||
return;
|
||||
};
|
||||
|
||||
if selected.is_empty() {
|
||||
return;
|
||||
} else if Self::quit_with_selected(&selected) {
|
||||
let opt = opt.into() as Opt;
|
||||
let selected = if opt.hovered { vec![&hovered] } else { self.selected_or_hovered() };
|
||||
if Self::quit_with_selected(&selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
let (mut done, mut todo) = (Vec::with_capacity(selected.len()), vec![]);
|
||||
for u in selected {
|
||||
if self.mimetype.get(u).is_some() {
|
||||
if self.mimetype.contains_key(u) {
|
||||
done.push((u.clone(), String::new()));
|
||||
} else if self.guess_folder(u) {
|
||||
done.push((u.clone(), MIME_DIR.to_owned()));
|
||||
|
|
@ -55,8 +50,8 @@ impl Manager {
|
|||
}
|
||||
|
||||
if todo.is_empty() {
|
||||
opt.targets = done;
|
||||
return self.open_do(opt, tasks);
|
||||
return self
|
||||
.open_do(OpenDoOpt { hovered, targets: done, interactive: opt.interactive }, tasks);
|
||||
}
|
||||
|
||||
tokio::spawn(async move {
|
||||
|
|
@ -69,27 +64,15 @@ impl Manager {
|
|||
|
||||
done.extend(files.iter().map(|f| (f.url(), String::new())));
|
||||
if let Err(e) = isolate::preload("mime", files, true).await {
|
||||
error!("preload in watcher failed: {e}");
|
||||
error!("preload in open failed: {e}");
|
||||
}
|
||||
|
||||
Self::_open_do(done, opt.interactive);
|
||||
ManagerProxy::open_do(OpenDoOpt { hovered, targets: done, interactive: opt.interactive });
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn _open_do(targets: Vec<(Url, String)>, interactive: bool) {
|
||||
emit!(Call(
|
||||
Cmd::new("open_do").with_bool("interactive", interactive).with_data(targets),
|
||||
Layer::Manager
|
||||
));
|
||||
}
|
||||
|
||||
pub fn open_do(&mut self, opt: impl Into<Opt>, tasks: &Tasks) {
|
||||
let opt = opt.into() as Opt;
|
||||
if opt.targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
pub fn open_do(&mut self, opt: impl Into<OpenDoOpt>, tasks: &Tasks) {
|
||||
let opt = opt.into() as OpenDoOpt;
|
||||
let targets: Vec<_> = opt
|
||||
.targets
|
||||
.into_iter()
|
||||
|
|
@ -101,8 +84,7 @@ impl Manager {
|
|||
if targets.is_empty() {
|
||||
return;
|
||||
} else if !opt.interactive {
|
||||
tasks.file_open(&targets);
|
||||
return;
|
||||
return tasks.file_open(&opt.hovered, &targets);
|
||||
}
|
||||
|
||||
let openers: Vec<_> = OPEN.common_openers(&targets).into_iter().cloned().collect();
|
||||
|
|
@ -110,11 +92,13 @@ impl Manager {
|
|||
return;
|
||||
}
|
||||
|
||||
let urls = targets.into_iter().map(|(u, _)| u).collect();
|
||||
let urls = [opt.hovered].into_iter().chain(targets.into_iter().map(|(u, _)| u)).collect();
|
||||
tokio::spawn(async move {
|
||||
let result = Select::_show(SelectCfg::open(openers.iter().map(|o| o.desc.clone()).collect()));
|
||||
let result = yazi_proxy::SelectProxy::show(SelectCfg::open(
|
||||
openers.iter().map(|o| o.desc.clone()).collect(),
|
||||
));
|
||||
if let Ok(choice) = result.await {
|
||||
Tasks::_open(urls, openers[choice].clone());
|
||||
TasksProxy::open_with(urls, openers[choice].clone());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use yazi_shared::{emit, event::Cmd, fs::Url, render, Layer};
|
||||
use yazi_shared::{event::Cmd, fs::Url, render};
|
||||
|
||||
use crate::manager::Manager;
|
||||
|
||||
|
|
@ -25,11 +25,6 @@ impl From<bool> for Opt {
|
|||
}
|
||||
|
||||
impl Manager {
|
||||
#[inline]
|
||||
pub fn _peek(force: bool) {
|
||||
emit!(Call(Cmd::new("peek").with_bool("force", force), Layer::Manager));
|
||||
}
|
||||
|
||||
pub fn peek(&mut self, opt: impl Into<Opt>) {
|
||||
let Some(hovered) = self.hovered().cloned() else {
|
||||
return render!(self.active_mut().preview.reset());
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use yazi_config::popup::InputCfg;
|
||||
use yazi_proxy::InputProxy;
|
||||
use yazi_shared::{emit, event::{Cmd, EventQuit}};
|
||||
|
||||
use crate::{input::Input, manager::Manager, tasks::Tasks};
|
||||
use crate::{manager::Manager, tasks::Tasks};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Opt {
|
||||
|
|
@ -25,7 +26,7 @@ impl Manager {
|
|||
}
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut result = Input::_show(InputCfg::quit(tasks));
|
||||
let mut result = InputProxy::show(InputCfg::quit(tasks));
|
||||
if let Some(Ok(choice)) = result.recv().await {
|
||||
if choice == "y" || choice == "Y" {
|
||||
emit!(Quit(opt));
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
use std::env;
|
||||
|
||||
use yazi_shared::{emit, event::Cmd, Layer};
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
use crate::{manager::Manager, tasks::Tasks};
|
||||
|
||||
impl Manager {
|
||||
#[inline]
|
||||
pub fn _refresh() {
|
||||
emit!(Call(Cmd::new("refresh"), Layer::Manager));
|
||||
}
|
||||
|
||||
pub fn refresh(&mut self, _: Cmd, tasks: &Tasks) {
|
||||
env::set_current_dir(self.cwd()).ok();
|
||||
env::set_var("PWD", self.cwd());
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use yazi_config::popup::InputCfg;
|
||||
use yazi_shared::{emit, event::Cmd, fs::Url, Layer};
|
||||
use yazi_proxy::{InputProxy, ManagerProxy};
|
||||
use yazi_shared::{event::Cmd, fs::Url};
|
||||
|
||||
use crate::{input::Input, manager::Manager, tasks::Tasks};
|
||||
use crate::{manager::Manager, tasks::Tasks};
|
||||
|
||||
pub struct Opt {
|
||||
force: bool,
|
||||
|
|
@ -33,7 +34,7 @@ impl Manager {
|
|||
}
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut result = Input::_show(if opt.permanently {
|
||||
let mut result = InputProxy::show(if opt.permanently {
|
||||
InputCfg::delete(opt.targets.len())
|
||||
} else {
|
||||
InputCfg::trash(opt.targets.len())
|
||||
|
|
@ -44,19 +45,11 @@ impl Manager {
|
|||
return;
|
||||
}
|
||||
|
||||
Self::_remove_do(opt.targets, opt.permanently);
|
||||
ManagerProxy::remove_do(opt.targets, opt.permanently);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn _remove_do(targets: Vec<Url>, permanently: bool) {
|
||||
emit!(Call(
|
||||
Cmd::new("remove_do").with_bool("permanently", permanently).with_data(targets),
|
||||
Layer::Manager
|
||||
));
|
||||
}
|
||||
|
||||
pub fn remove_do(&mut self, opt: impl Into<Opt>, tasks: &Tasks) {
|
||||
let opt = opt.into() as Opt;
|
||||
for u in &opt.targets {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
use std::{collections::BTreeMap, ffi::OsStr, io::{stdout, BufWriter, Write}, path::PathBuf};
|
||||
use std::{collections::BTreeMap, ffi::{OsStr, OsString}, io::{stdout, BufWriter, Write}, path::PathBuf};
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}};
|
||||
use yazi_config::{popup::InputCfg, OPEN, PREVIEW};
|
||||
use yazi_plugin::external::{self, ShellOpt};
|
||||
use yazi_scheduler::{Scheduler, BLOCKER};
|
||||
use yazi_proxy::{AppProxy, InputProxy, ManagerProxy};
|
||||
use yazi_scheduler::BLOCKER;
|
||||
use yazi_shared::{event::Cmd, fs::{max_common_root, File, FilesOp, Url}, term::Term, Defer};
|
||||
|
||||
use crate::{input::Input, manager::Manager};
|
||||
use crate::manager::Manager;
|
||||
|
||||
pub struct Opt {
|
||||
force: bool,
|
||||
|
|
@ -49,7 +50,7 @@ impl Manager {
|
|||
let file = File::from(new.clone()).await?;
|
||||
FilesOp::Deleting(file.parent().unwrap(), vec![new.clone()]).emit();
|
||||
FilesOp::Upserting(file.parent().unwrap(), BTreeMap::from_iter([(old, file)])).emit();
|
||||
Ok(Self::_hover(Some(new)))
|
||||
Ok(ManagerProxy::hover(Some(new)))
|
||||
}
|
||||
|
||||
pub fn rename(&mut self, opt: impl Into<Opt>) {
|
||||
|
|
@ -77,7 +78,7 @@ impl Manager {
|
|||
};
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut result = Input::_show(InputCfg::rename().with_value(name).with_cursor(cursor));
|
||||
let mut result = InputProxy::show(InputCfg::rename().with_value(name).with_cursor(cursor));
|
||||
let Some(Ok(name)) = result.recv().await else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -88,7 +89,7 @@ impl Manager {
|
|||
return;
|
||||
}
|
||||
|
||||
let mut result = Input::_show(InputCfg::overwrite());
|
||||
let mut result = InputProxy::show(InputCfg::overwrite());
|
||||
if let Some(Ok(choice)) = result.recv().await {
|
||||
if choice == "y" || choice == "Y" {
|
||||
Self::rename_and_hover(hovered, Url::from(new)).await.ok();
|
||||
|
|
@ -122,14 +123,14 @@ impl Manager {
|
|||
|
||||
let _guard = BLOCKER.acquire().await.unwrap();
|
||||
let _defer = Defer::new(|| {
|
||||
Scheduler::app_resume();
|
||||
AppProxy::resume();
|
||||
tokio::spawn(fs::remove_file(tmp.clone()))
|
||||
});
|
||||
Scheduler::app_stop().await;
|
||||
AppProxy::stop().await;
|
||||
|
||||
let mut child = external::shell(ShellOpt {
|
||||
cmd: (*opener.exec).into(),
|
||||
args: vec![tmp.to_owned().into()],
|
||||
cmd: (*opener.run).into(),
|
||||
args: vec![OsString::new(), tmp.to_owned().into()],
|
||||
piped: false,
|
||||
orphan: false,
|
||||
})?;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use yazi_scheduler::Scheduler;
|
||||
use yazi_proxy::AppProxy;
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
use crate::manager::Manager;
|
||||
|
|
@ -7,7 +7,7 @@ impl Manager {
|
|||
pub fn suspend(&mut self, _: Cmd) {
|
||||
#[cfg(unix)]
|
||||
tokio::spawn(async move {
|
||||
Scheduler::app_stop().await;
|
||||
AppProxy::stop().await;
|
||||
unsafe { libc::raise(libc::SIGTSTP) };
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use yazi_proxy::ManagerProxy;
|
||||
use yazi_shared::{event::Cmd, fs::FilesOp, render};
|
||||
|
||||
use crate::{folder::Folder, manager::Manager, tab::Tab, tasks::Tasks};
|
||||
|
|
@ -56,8 +57,8 @@ impl Manager {
|
|||
return;
|
||||
}
|
||||
|
||||
Self::_hover(None); // Re-hover in next loop
|
||||
Self::_update_paged(); // Update for paged files in next loop
|
||||
ManagerProxy::hover(None); // Re-hover in next loop
|
||||
ManagerProxy::update_paged(); // Update for paged files in next loop
|
||||
if calc {
|
||||
tasks.preload_sorted(&tab.current.files);
|
||||
}
|
||||
|
|
@ -73,7 +74,7 @@ impl Manager {
|
|||
}
|
||||
|
||||
if !foreign {
|
||||
Self::_peek(true);
|
||||
ManagerProxy::peek(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use yazi_shared::{emit, event::Cmd, fs::Url, Layer};
|
||||
use yazi_shared::{event::Cmd, fs::Url};
|
||||
|
||||
use crate::{manager::Manager, tasks::Tasks};
|
||||
|
||||
|
|
@ -22,19 +22,6 @@ impl From<()> for Opt {
|
|||
}
|
||||
|
||||
impl Manager {
|
||||
#[inline]
|
||||
pub fn _update_paged() {
|
||||
emit!(Call(Cmd::new("update_paged"), Layer::Manager));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn _update_paged_by(page: usize, only_if: &Url) {
|
||||
emit!(Call(
|
||||
Cmd::args("update_paged", vec![page.to_string()]).with("only-if", only_if.to_string()),
|
||||
Layer::Manager
|
||||
));
|
||||
}
|
||||
|
||||
pub fn update_paged(&mut self, opt: impl TryInto<Opt>, tasks: &Tasks) {
|
||||
let Ok(opt) = opt.try_into() else {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -52,4 +52,7 @@ impl Manager {
|
|||
|
||||
#[inline]
|
||||
pub fn selected_or_hovered(&self) -> Vec<&Url> { self.tabs.active().selected_or_hovered() }
|
||||
|
||||
#[inline]
|
||||
pub fn hovered_and_selected(&self) -> Vec<&Url> { self.tabs.active().hovered_and_selected() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use yazi_boot::BOOT;
|
||||
use yazi_proxy::ManagerProxy;
|
||||
use yazi_shared::fs::Url;
|
||||
|
||||
use crate::{manager::Manager, tab::Tab};
|
||||
use crate::tab::Tab;
|
||||
|
||||
pub struct Tabs {
|
||||
pub idx: usize,
|
||||
|
|
@ -17,7 +18,7 @@ impl Tabs {
|
|||
tabs.items[0].reveal(Url::from(BOOT.cwd.join(file)));
|
||||
}
|
||||
|
||||
Manager::_refresh();
|
||||
ManagerProxy::refresh();
|
||||
tabs
|
||||
}
|
||||
|
||||
|
|
@ -42,8 +43,8 @@ impl Tabs {
|
|||
}
|
||||
|
||||
self.idx = idx;
|
||||
Manager::_refresh();
|
||||
Manager::_peek(true);
|
||||
ManagerProxy::refresh();
|
||||
ManagerProxy::peek(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,22 +5,8 @@ use yazi_shared::{emit, event::Cmd, Layer};
|
|||
use crate::notify::{Message, Notify};
|
||||
|
||||
impl Notify {
|
||||
#[inline]
|
||||
pub fn _push_warn(title: &str, content: &str) {
|
||||
emit!(Call(
|
||||
Cmd::new("notify")
|
||||
.with("title", title)
|
||||
.with("content", content)
|
||||
.with("level", "warn")
|
||||
.with("timeout", 5),
|
||||
Layer::App
|
||||
));
|
||||
}
|
||||
|
||||
pub fn push(&mut self, msg: impl TryInto<Message>) {
|
||||
let Ok(mut msg) = msg.try_into() else {
|
||||
return;
|
||||
};
|
||||
pub fn push(&mut self, msg: impl Into<Message>) {
|
||||
let mut msg = msg.into() as Message;
|
||||
|
||||
let instant = Instant::now();
|
||||
msg.timeout += instant - self.messages.first().map_or(instant, |m| m.instant);
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
pub enum Level {
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl FromStr for Level {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(match s {
|
||||
"info" => Self::Info,
|
||||
"warn" => Self::Warn,
|
||||
"error" => Self::Error,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +1,31 @@
|
|||
use std::time::{Duration, Instant};
|
||||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use yazi_shared::event::Cmd;
|
||||
use yazi_proxy::options::{NotifyLevel, NotifyOpt};
|
||||
|
||||
use super::{Level, NOTIFY_BORDER};
|
||||
use super::NOTIFY_BORDER;
|
||||
|
||||
pub struct Message {
|
||||
pub title: String,
|
||||
pub content: String,
|
||||
pub level: Level,
|
||||
|
||||
pub instant: Instant,
|
||||
pub level: NotifyLevel,
|
||||
pub timeout: Duration,
|
||||
|
||||
pub instant: Instant,
|
||||
pub percent: u8,
|
||||
}
|
||||
|
||||
impl TryFrom<Cmd> for Message {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||
let timeout = c.take_name("timeout").and_then(|s| s.parse::<f64>().ok()).ok_or(())?;
|
||||
if timeout < 0.0 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let content = c.take_name("content").ok_or(())?;
|
||||
Ok(Self {
|
||||
title: c.take_name("title").ok_or(())?,
|
||||
content,
|
||||
level: c.take_name("level").ok_or(())?.parse()?,
|
||||
impl From<NotifyOpt> for Message {
|
||||
fn from(opt: NotifyOpt) -> Self {
|
||||
Self {
|
||||
title: opt.title,
|
||||
content: opt.content,
|
||||
level: opt.level,
|
||||
timeout: opt.timeout,
|
||||
|
||||
instant: Instant::now(),
|
||||
timeout: Duration::from_secs_f64(timeout),
|
||||
|
||||
percent: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
mod commands;
|
||||
mod level;
|
||||
mod message;
|
||||
mod notify;
|
||||
|
||||
pub use level::*;
|
||||
pub use message::*;
|
||||
pub use notify::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,29 +1,10 @@
|
|||
use anyhow::Result;
|
||||
use tokio::sync::oneshot;
|
||||
use yazi_config::popup::SelectCfg;
|
||||
use yazi_shared::{emit, event::Cmd, render, term::Term, Layer};
|
||||
use yazi_proxy::options::SelectOpt;
|
||||
use yazi_shared::render;
|
||||
|
||||
use crate::select::Select;
|
||||
|
||||
pub struct Opt {
|
||||
cfg: SelectCfg,
|
||||
tx: oneshot::Sender<Result<usize>>,
|
||||
}
|
||||
|
||||
impl TryFrom<Cmd> for Opt {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
|
||||
}
|
||||
|
||||
impl Select {
|
||||
pub async fn _show(cfg: SelectCfg) -> Result<usize> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
emit!(Call(Cmd::new("show").with_data(Opt { cfg, tx }), Layer::Select));
|
||||
rx.await.unwrap_or_else(|_| Term::goodbye(|| false))
|
||||
}
|
||||
|
||||
pub fn show(&mut self, opt: impl TryInto<Opt>) {
|
||||
pub fn show(&mut self, opt: impl TryInto<SelectOpt>) {
|
||||
let Ok(opt) = opt.try_into() else {
|
||||
return;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use yazi_proxy::ManagerProxy;
|
||||
use yazi_shared::{event::Cmd, render};
|
||||
|
||||
use crate::{manager::Manager, tab::Tab, Step};
|
||||
use crate::{tab::Tab, Step};
|
||||
|
||||
pub struct Opt {
|
||||
step: Step,
|
||||
|
|
@ -36,7 +37,7 @@ impl Tab {
|
|||
}
|
||||
}
|
||||
|
||||
Manager::_hover(None);
|
||||
ManagerProxy::hover(None);
|
||||
render!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ use std::{mem, time::Duration};
|
|||
use tokio::{fs, pin};
|
||||
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_shared::{emit, event::Cmd, fs::{expand_path, Url}, render, Debounce, InputError, Layer};
|
||||
use yazi_proxy::{CompletionProxy, InputProxy, ManagerProxy, TabProxy};
|
||||
use yazi_shared::{event::Cmd, fs::{expand_path, Url}, render, Debounce, InputError};
|
||||
|
||||
use crate::{completion::Completion, input::Input, manager::Manager, tab::Tab};
|
||||
use crate::tab::Tab;
|
||||
|
||||
pub struct Opt {
|
||||
target: Url,
|
||||
|
|
@ -27,11 +28,6 @@ impl From<Url> for Opt {
|
|||
}
|
||||
|
||||
impl Tab {
|
||||
#[inline]
|
||||
pub fn _cd(target: &Url) {
|
||||
emit!(Call(Cmd::args("cd", vec![target.to_string()]), Layer::Manager));
|
||||
}
|
||||
|
||||
pub fn cd(&mut self, opt: impl Into<Opt>) {
|
||||
if !self.try_escape_visual() {
|
||||
return;
|
||||
|
|
@ -68,13 +64,13 @@ impl Tab {
|
|||
self.backstack.push(opt.target.clone());
|
||||
}
|
||||
|
||||
Manager::_refresh();
|
||||
ManagerProxy::refresh();
|
||||
render!();
|
||||
}
|
||||
|
||||
fn cd_interactive(&mut self) {
|
||||
tokio::spawn(async move {
|
||||
let rx = Input::_show(InputCfg::cd());
|
||||
let rx = InputProxy::show(InputCfg::cd());
|
||||
|
||||
let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50));
|
||||
pin!(rx);
|
||||
|
|
@ -88,13 +84,13 @@ impl Tab {
|
|||
};
|
||||
|
||||
if meta.is_dir() {
|
||||
Tab::_cd(&u);
|
||||
TabProxy::cd(&u);
|
||||
} else {
|
||||
Tab::_reveal(&u);
|
||||
TabProxy::reveal(&u);
|
||||
}
|
||||
}
|
||||
Err(InputError::Completed(before, ticket)) => {
|
||||
Completion::_trigger(&before, ticket);
|
||||
CompletionProxy::trigger(&before, ticket);
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use bitflags::bitflags;
|
||||
use yazi_proxy::{AppProxy, ManagerProxy};
|
||||
use yazi_shared::{event::Cmd, render, render_and};
|
||||
|
||||
use crate::{manager::Manager, notify::Notify, tab::Tab};
|
||||
use crate::tab::Tab;
|
||||
|
||||
bitflags! {
|
||||
pub struct Opt: u8 {
|
||||
|
|
@ -74,7 +75,7 @@ impl Tab {
|
|||
|
||||
self.selected.clear();
|
||||
if self.current.hovered().is_some_and(|h| h.is_dir()) {
|
||||
Manager::_peek(true);
|
||||
ManagerProxy::peek(true);
|
||||
}
|
||||
render_and!(true)
|
||||
}
|
||||
|
|
@ -98,28 +99,26 @@ impl Tab {
|
|||
}
|
||||
|
||||
pub fn try_escape_visual(&mut self) -> bool {
|
||||
let state = self.mode.is_select();
|
||||
let select = self.mode.is_select();
|
||||
let Some((_, indices)) = self.mode.take_visual() else {
|
||||
return true;
|
||||
};
|
||||
|
||||
let mut success = true;
|
||||
for f in indices.iter().filter_map(|i| self.current.files.get(*i)) {
|
||||
if state {
|
||||
success &= self.selected.add(&f.url);
|
||||
} else {
|
||||
self.selected.remove(&f.url);
|
||||
}
|
||||
}
|
||||
render!();
|
||||
let urls: Vec<_> =
|
||||
indices.into_iter().filter_map(|i| self.current.files.get(i)).map(|f| &f.url).collect();
|
||||
|
||||
if !success {
|
||||
Notify::_push_warn(
|
||||
let same = !self.current.cwd.is_search();
|
||||
if !select {
|
||||
self.selected.remove_many(&urls, same);
|
||||
} else if self.selected.add_many(&urls, same) != urls.len() {
|
||||
AppProxy::notify_warn(
|
||||
"Escape visual mode",
|
||||
"Some files cannot be selected, due to path nesting conflict.",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
render!();
|
||||
success
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ use std::time::Duration;
|
|||
use tokio::pin;
|
||||
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_proxy::{InputProxy, ManagerProxy};
|
||||
use yazi_shared::{emit, event::Cmd, render, Debounce, InputError, Layer};
|
||||
|
||||
use crate::{folder::{Filter, FilterCase}, input::Input, manager::Manager, tab::Tab};
|
||||
use crate::{folder::{Filter, FilterCase}, tab::Tab};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Opt {
|
||||
|
|
@ -28,7 +29,7 @@ impl Tab {
|
|||
pub fn filter(&mut self, opt: impl Into<Opt>) {
|
||||
let opt = opt.into() as Opt;
|
||||
tokio::spawn(async move {
|
||||
let rx = Input::_show(InputCfg::filter());
|
||||
let rx = InputProxy::show(InputCfg::filter());
|
||||
|
||||
let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50));
|
||||
pin!(rx);
|
||||
|
|
@ -62,7 +63,7 @@ impl Tab {
|
|||
};
|
||||
|
||||
if opt.done {
|
||||
Manager::_update_paged(); // Update for paged files in next loop
|
||||
ManagerProxy::update_paged(); // Update for paged files in next loop
|
||||
}
|
||||
|
||||
let hovered = self.current.hovered().map(|f| f.url());
|
||||
|
|
@ -71,7 +72,7 @@ impl Tab {
|
|||
}
|
||||
|
||||
if self.current.repos(hovered) {
|
||||
Manager::_hover(None);
|
||||
ManagerProxy::hover(None);
|
||||
}
|
||||
render!();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ use std::time::Duration;
|
|||
use tokio::pin;
|
||||
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_proxy::InputProxy;
|
||||
use yazi_shared::{emit, event::Cmd, render, Debounce, InputError, Layer};
|
||||
|
||||
use crate::{folder::FilterCase, input::Input, tab::{Finder, Tab}};
|
||||
use crate::{folder::FilterCase, tab::{Finder, Tab}};
|
||||
|
||||
pub struct Opt {
|
||||
query: Option<String>,
|
||||
|
|
@ -35,7 +36,7 @@ impl Tab {
|
|||
pub fn find(&mut self, opt: impl Into<Opt>) {
|
||||
let opt = opt.into() as Opt;
|
||||
tokio::spawn(async move {
|
||||
let rx = Input::_show(InputCfg::find(opt.prev));
|
||||
let rx = InputProxy::show(InputCfg::find(opt.prev));
|
||||
|
||||
let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50));
|
||||
pin!(rx);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use yazi_proxy::ManagerProxy;
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
use crate::{manager::Manager, tab::Tab};
|
||||
use crate::tab::Tab;
|
||||
|
||||
impl Tab {
|
||||
pub fn hidden(&mut self, c: Cmd) {
|
||||
|
|
@ -14,10 +15,10 @@ impl Tab {
|
|||
self.apply_files_attrs();
|
||||
|
||||
if hovered.as_ref() != self.current.hovered().map(|f| &f.url) {
|
||||
Manager::_hover(hovered);
|
||||
ManagerProxy::hover(hovered);
|
||||
} else if self.current.hovered().is_some_and(|f| f.is_dir()) {
|
||||
Manager::_peek(true);
|
||||
ManagerProxy::peek(true);
|
||||
}
|
||||
Manager::_update_paged();
|
||||
ManagerProxy::update_paged();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use yazi_plugin::external::{self, FzfOpt, ZoxideOpt};
|
||||
use yazi_scheduler::{Scheduler, BLOCKER};
|
||||
use yazi_proxy::{AppProxy, TabProxy};
|
||||
use yazi_scheduler::BLOCKER;
|
||||
use yazi_shared::{event::Cmd, fs::ends_with_slash, Defer};
|
||||
|
||||
use crate::tab::Tab;
|
||||
|
|
@ -37,8 +38,8 @@ impl Tab {
|
|||
let cwd = self.current.cwd.clone();
|
||||
tokio::spawn(async move {
|
||||
let _guard = BLOCKER.acquire().await.unwrap();
|
||||
let _defer = Defer::new(Scheduler::app_resume);
|
||||
Scheduler::app_stop().await;
|
||||
let _defer = Defer::new(AppProxy::resume);
|
||||
AppProxy::stop().await;
|
||||
|
||||
let result = if opt.type_ == OptType::Fzf {
|
||||
external::fzf(FzfOpt { cwd }).await
|
||||
|
|
@ -51,9 +52,9 @@ impl Tab {
|
|||
};
|
||||
|
||||
if opt.type_ == OptType::Fzf && !ends_with_slash(&url) {
|
||||
Tab::_reveal(&url)
|
||||
TabProxy::reveal(&url)
|
||||
} else {
|
||||
Tab::_cd(&url)
|
||||
TabProxy::cd(&url)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use yazi_shared::{emit, event::Cmd, fs::{expand_path, File, FilesOp, Url}, Layer};
|
||||
use yazi_proxy::ManagerProxy;
|
||||
use yazi_shared::{event::Cmd, fs::{expand_path, File, FilesOp, Url}};
|
||||
|
||||
use crate::{manager::Manager, tab::Tab};
|
||||
use crate::tab::Tab;
|
||||
|
||||
pub struct Opt {
|
||||
target: Url,
|
||||
|
|
@ -21,11 +22,6 @@ impl From<Url> for Opt {
|
|||
}
|
||||
|
||||
impl Tab {
|
||||
#[inline]
|
||||
pub fn _reveal(target: &Url) {
|
||||
emit!(Call(Cmd::args("reveal", vec![target.to_string()]), Layer::Manager));
|
||||
}
|
||||
|
||||
pub fn reveal(&mut self, opt: impl Into<Opt>) {
|
||||
let opt = opt.into() as Opt;
|
||||
|
||||
|
|
@ -35,6 +31,6 @@ impl Tab {
|
|||
|
||||
self.cd(parent.clone());
|
||||
FilesOp::Creating(parent, vec![File::from_dummy(&opt.target)]).emit();
|
||||
Manager::_hover(Some(opt.target));
|
||||
ManagerProxy::hover(Some(opt.target));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
use std::{mem, time::Duration};
|
||||
use std::{fmt::Display, mem, time::Duration};
|
||||
|
||||
use anyhow::bail;
|
||||
use tokio::pin;
|
||||
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_plugin::external;
|
||||
use yazi_proxy::{InputProxy, ManagerProxy, TabProxy};
|
||||
use yazi_shared::{event::Cmd, fs::FilesOp, render};
|
||||
|
||||
use crate::{input::Input, manager::Manager, tab::Tab};
|
||||
use crate::tab::Tab;
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum OptType {
|
||||
|
|
@ -26,14 +27,13 @@ impl From<String> for OptType {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToString for OptType {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
impl Display for OptType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
Self::Rg => "rg",
|
||||
Self::Fd => "fd",
|
||||
Self::None => "none",
|
||||
}
|
||||
.to_owned()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ impl Tab {
|
|||
let hidden = self.conf.show_hidden;
|
||||
|
||||
self.search = Some(tokio::spawn(async move {
|
||||
let mut input = Input::_show(InputCfg::search(&opt.type_.to_string()));
|
||||
let mut input = InputProxy::show(InputCfg::search(&opt.type_.to_string()));
|
||||
let Some(Ok(subject)) = input.recv().await else { bail!("") };
|
||||
|
||||
cwd = cwd.into_search(subject.clone());
|
||||
|
|
@ -73,7 +73,7 @@ impl Tab {
|
|||
let rx = UnboundedReceiverStream::new(rx).chunks_timeout(1000, Duration::from_millis(300));
|
||||
pin!(rx);
|
||||
|
||||
let ((), ticket) = (Tab::_cd(&cwd), FilesOp::prepare(&cwd));
|
||||
let ((), ticket) = (TabProxy::cd(&cwd), FilesOp::prepare(&cwd));
|
||||
while let Some(chunk) = rx.next().await {
|
||||
FilesOp::Part(cwd.clone(), chunk, ticket).emit();
|
||||
}
|
||||
|
|
@ -91,7 +91,7 @@ impl Tab {
|
|||
if self.current.cwd.is_search() {
|
||||
let rep = self.history_new(&self.current.cwd.to_regular());
|
||||
drop(mem::replace(&mut self.current, rep));
|
||||
Manager::_refresh();
|
||||
ManagerProxy::refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use yazi_shared::{event::Cmd, fs::Url, render};
|
||||
use yazi_proxy::AppProxy;
|
||||
use yazi_shared::{event::Cmd, fs::Url, render, render_and};
|
||||
|
||||
use crate::tab::Tab;
|
||||
|
||||
|
|
@ -30,10 +31,17 @@ impl<'a> Tab {
|
|||
return;
|
||||
};
|
||||
|
||||
render!(match opt.state {
|
||||
Some(true) => self.selected.add(&url),
|
||||
Some(false) => self.selected.remove(&url),
|
||||
None => self.selected.remove(&url) || self.selected.add(&url),
|
||||
});
|
||||
let b = match opt.state {
|
||||
Some(true) => render_and!(self.selected.add(&url)),
|
||||
Some(false) => render_and!(self.selected.remove(&url)) | true,
|
||||
None => render_and!(self.selected.remove(&url) || self.selected.add(&url)),
|
||||
};
|
||||
|
||||
if !b {
|
||||
AppProxy::notify_warn(
|
||||
"Select one",
|
||||
"This file cannot be selected, due to path nesting conflict.",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use yazi_proxy::AppProxy;
|
||||
use yazi_shared::{event::Cmd, render};
|
||||
|
||||
use crate::tab::Tab;
|
||||
|
|
@ -23,24 +24,24 @@ impl From<Option<bool>> for Opt {
|
|||
|
||||
impl Tab {
|
||||
pub fn select_all(&mut self, opt: impl Into<Opt>) {
|
||||
let mut b = false;
|
||||
match opt.into().state {
|
||||
Some(true) => {
|
||||
for f in self.current.files.iter() {
|
||||
b |= self.selected.add(&f.url);
|
||||
}
|
||||
}
|
||||
Some(false) => {
|
||||
for f in self.current.files.iter() {
|
||||
b |= self.selected.remove(&f.url);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
for f in self.current.files.iter() {
|
||||
b |= self.selected.remove(&f.url) || self.selected.add(&f.url);
|
||||
}
|
||||
}
|
||||
let iter = self.current.files.iter().map(|f| &f.url);
|
||||
let (removal, addition): (Vec<_>, Vec<_>) = match opt.into().state {
|
||||
Some(true) => (vec![], iter.collect()),
|
||||
Some(false) => (iter.collect(), vec![]),
|
||||
None => iter.partition(|&u| self.selected.contains(u)),
|
||||
};
|
||||
|
||||
let same = !self.current.cwd.is_search();
|
||||
render!(self.selected.remove_many(&removal, same) > 0);
|
||||
|
||||
let added = self.selected.add_many(&addition, same);
|
||||
render!(added > 0);
|
||||
|
||||
if added != addition.len() {
|
||||
AppProxy::notify_warn(
|
||||
"Select all",
|
||||
"Some files cannot be selected, due to path nesting conflict.",
|
||||
);
|
||||
}
|
||||
render!(b);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use yazi_config::{open::Opener, popup::InputCfg};
|
||||
use yazi_proxy::{InputProxy, TasksProxy};
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
use crate::{input::Input, tab::Tab, tasks::Tasks};
|
||||
use crate::tab::Tab;
|
||||
|
||||
pub struct Opt {
|
||||
exec: String,
|
||||
run: String,
|
||||
block: bool,
|
||||
confirm: bool,
|
||||
}
|
||||
|
|
@ -12,7 +13,7 @@ pub struct Opt {
|
|||
impl From<Cmd> for Opt {
|
||||
fn from(mut c: Cmd) -> Self {
|
||||
Self {
|
||||
exec: c.take_first().unwrap_or_default(),
|
||||
run: c.take_first().unwrap_or_default(),
|
||||
block: c.named.contains_key("block"),
|
||||
confirm: c.named.contains_key("confirm"),
|
||||
}
|
||||
|
|
@ -26,19 +27,19 @@ impl Tab {
|
|||
}
|
||||
|
||||
let mut opt = opt.into() as Opt;
|
||||
let selected: Vec<_> = self.selected_or_hovered().into_iter().cloned().collect();
|
||||
let selected = self.hovered_and_selected().into_iter().cloned().collect();
|
||||
|
||||
tokio::spawn(async move {
|
||||
if !opt.confirm || opt.exec.is_empty() {
|
||||
let mut result = Input::_show(InputCfg::shell(opt.block).with_value(opt.exec));
|
||||
if !opt.confirm || opt.run.is_empty() {
|
||||
let mut result = InputProxy::show(InputCfg::shell(opt.block).with_value(opt.run));
|
||||
match result.recv().await {
|
||||
Some(Ok(e)) => opt.exec = e,
|
||||
Some(Ok(e)) => opt.run = e,
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
|
||||
Tasks::_open(selected, Opener {
|
||||
exec: opt.exec,
|
||||
TasksProxy::open_with(selected, Opener {
|
||||
run: opt.run,
|
||||
block: opt.block,
|
||||
orphan: false,
|
||||
desc: Default::default(),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use yazi_config::manager::SortBy;
|
||||
use yazi_proxy::ManagerProxy;
|
||||
use yazi_shared::event::Cmd;
|
||||
|
||||
use crate::{manager::Manager, tab::Tab, tasks::Tasks};
|
||||
use crate::{tab::Tab, tasks::Tasks};
|
||||
|
||||
impl Tab {
|
||||
pub fn sort(&mut self, c: Cmd, tasks: &Tasks) {
|
||||
|
|
@ -15,7 +16,7 @@ impl Tab {
|
|||
self.conf.sort_dir_first = c.named.contains_key("dir-first");
|
||||
|
||||
self.apply_files_attrs();
|
||||
Manager::_update_paged();
|
||||
ManagerProxy::update_paged();
|
||||
|
||||
tasks.preload_sorted(&self.current.files);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{collections::BTreeSet, mem};
|
||||
use std::{collections::BTreeSet, fmt::Display, mem};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub enum Mode {
|
||||
|
|
@ -37,13 +37,12 @@ impl Mode {
|
|||
pub fn is_visual(&self) -> bool { matches!(self, Mode::Select(..) | Mode::Unset(..)) }
|
||||
}
|
||||
|
||||
impl ToString for Mode {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
impl Display for Mode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
Mode::Normal => "normal",
|
||||
Mode::Select(..) => "select",
|
||||
Mode::Unset(..) => "unset",
|
||||
}
|
||||
.to_string()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,90 +15,86 @@ impl Deref for Selected {
|
|||
}
|
||||
|
||||
impl Selected {
|
||||
pub fn add(&mut self, url: &Url) -> bool { self.add_many(&[url]) }
|
||||
#[inline]
|
||||
pub fn add(&mut self, url: &Url) -> bool { self.add_same(&[url]) == 1 }
|
||||
|
||||
/// Adds a list of URLs to the user structure.
|
||||
///
|
||||
/// This method attempts to add a slice of `Url` references to the internal
|
||||
/// structure, ensuring that all URLs have the same parent directory. For
|
||||
/// example, URLs such as `/a/b/c`, `/a/b/d`, `/a/b/e`, and `/a/b/f` are
|
||||
/// acceptable, while `/a/b/c` and `/a/e/f` would not be, due to differing
|
||||
/// parent directories.
|
||||
///
|
||||
/// The addition will fail under the following conditions:
|
||||
/// - Any of the URLs already exists within the `inner` collection.
|
||||
/// - The parent directory of the URLs already exists as a key in the
|
||||
/// `parents` map.
|
||||
///
|
||||
/// When the provided list of URLs is empty, the method will return `true` as
|
||||
/// there are no URLs to process, which is considered a successful operation.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `urls` - A slice of references to `Url` objects that are to be added.
|
||||
/// All URLs should have the same parent path.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns `true` if all URLs were successfully added, or if the input list
|
||||
/// is empty. Returns `false` if any URL could not be added due to the
|
||||
/// existence of its parent directory in the structure, or if the URL itself
|
||||
/// is already present.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use yazi_core::tab::Selected;
|
||||
/// # use yazi_shared::fs::Url;
|
||||
/// let mut s = Selected::default();
|
||||
///
|
||||
/// let url1 = Url::from("/a/b/c");
|
||||
/// let url2 = Url::from("/a/b/d");
|
||||
/// assert!(s.add_many(&[&url1, &url2]));
|
||||
/// ```
|
||||
pub fn add_many(&mut self, urls: &[&Url]) -> bool {
|
||||
if urls.is_empty() {
|
||||
return true;
|
||||
} else if self.parents.contains_key(urls[0]) {
|
||||
return false;
|
||||
pub fn add_many(&mut self, urls: &[&Url], same: bool) -> usize {
|
||||
if same {
|
||||
return self.add_same(urls);
|
||||
}
|
||||
|
||||
let mut grouped: HashMap<_, Vec<_>> = Default::default();
|
||||
for &u in urls {
|
||||
if let Some(p) = u.parent_url() {
|
||||
grouped.entry(p).or_default().push(u);
|
||||
}
|
||||
}
|
||||
grouped.into_values().map(|v| self.add_same(&v)).sum()
|
||||
}
|
||||
|
||||
fn add_same(&mut self, urls: &[&Url]) -> usize {
|
||||
// If it has appeared as a parent
|
||||
let urls: Vec<_> = urls.iter().filter(|&&u| !self.parents.contains_key(u)).collect();
|
||||
if urls.is_empty() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If it has appeared as a child
|
||||
let mut parent = urls[0].parent_url();
|
||||
let mut parents = vec![];
|
||||
while let Some(u) = parent {
|
||||
if self.inner.contains(&u) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
parent = u.parent_url();
|
||||
parents.push(u);
|
||||
}
|
||||
|
||||
for u in parents {
|
||||
*self.parents.entry(u).or_insert(0) += urls.len();
|
||||
}
|
||||
let len = self.inner.len();
|
||||
self.inner.extend(urls.iter().map(|&&u| u.clone()));
|
||||
|
||||
self.inner.extend(urls.iter().map(|&u| u.clone()));
|
||||
true
|
||||
for u in parents {
|
||||
*self.parents.entry(u).or_insert(0) += self.inner.len() - len;
|
||||
}
|
||||
urls.len()
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, url: &Url) -> bool {
|
||||
if !self.inner.remove(url) {
|
||||
return false;
|
||||
#[inline]
|
||||
pub fn remove(&mut self, url: &Url) -> bool { self.remove_same(&[url]) == 1 }
|
||||
|
||||
pub fn remove_many(&mut self, urls: &[&Url], same: bool) -> usize {
|
||||
if same {
|
||||
return self.remove_same(urls);
|
||||
}
|
||||
|
||||
let mut parent = url.parent_url();
|
||||
let mut grouped: HashMap<_, Vec<_>> = Default::default();
|
||||
for &u in urls {
|
||||
if let Some(p) = u.parent_url() {
|
||||
grouped.entry(p).or_default().push(u);
|
||||
}
|
||||
}
|
||||
grouped.into_values().map(|v| self.remove_same(&v)).sum()
|
||||
}
|
||||
|
||||
fn remove_same(&mut self, urls: &[&Url]) -> usize {
|
||||
let count = urls.iter().map(|&u| self.inner.remove(u)).filter(|&b| b).count();
|
||||
if count == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut parent = urls[0].parent_url();
|
||||
while let Some(u) = parent {
|
||||
let n = self.parents.get_mut(&u).unwrap();
|
||||
if *n == 1 {
|
||||
|
||||
*n -= count;
|
||||
if *n == 0 {
|
||||
self.parents.remove(&u);
|
||||
} else {
|
||||
*n -= 1;
|
||||
}
|
||||
|
||||
parent = u.parent_url();
|
||||
}
|
||||
true
|
||||
count
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
|
|
@ -153,11 +149,14 @@ mod tests {
|
|||
fn insert_many_success() {
|
||||
let mut s = Selected::default();
|
||||
|
||||
assert!(s.add_many(&[
|
||||
&Url::from("/parent/child1"),
|
||||
&Url::from("/parent/child2"),
|
||||
&Url::from("/parent/child3")
|
||||
]));
|
||||
assert_eq!(
|
||||
3,
|
||||
s.add_same(&[
|
||||
&Url::from("/parent/child1"),
|
||||
&Url::from("/parent/child2"),
|
||||
&Url::from("/parent/child3")
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -165,7 +164,7 @@ mod tests {
|
|||
let mut s = Selected::default();
|
||||
|
||||
s.add(&Url::from("/parent"));
|
||||
assert!(!s.add_many(&[&Url::from("/parent/child1"), &Url::from("/parent/child2"),]));
|
||||
assert_eq!(0, s.add_same(&[&Url::from("/parent/child1"), &Url::from("/parent/child2")]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -173,14 +172,14 @@ mod tests {
|
|||
let mut s = Selected::default();
|
||||
|
||||
s.add(&Url::from("/parent/child1"));
|
||||
assert!(s.add_many(&[&Url::from("/parent/child1"), &Url::from("/parent/child2")]));
|
||||
assert_eq!(2, s.add_same(&[&Url::from("/parent/child1"), &Url::from("/parent/child2")]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_many_empty_urls_list() {
|
||||
let mut s = Selected::default();
|
||||
|
||||
assert!(s.add_many(&[]));
|
||||
assert_eq!(0, s.add_same(&[]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -188,14 +187,17 @@ mod tests {
|
|||
let mut s = Selected::default();
|
||||
|
||||
s.add(&Url::from("/parent/child"));
|
||||
assert!(!s.add_many(&[&Url::from("/parent/child/child1"), &Url::from("/parent/child/child2")]));
|
||||
assert_eq!(
|
||||
0,
|
||||
s.add_same(&[&Url::from("/parent/child/child1"), &Url::from("/parent/child/child2")])
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn insert_many_with_direct_parent_fails() {
|
||||
let mut s = Selected::default();
|
||||
|
||||
s.add(&Url::from("/a"));
|
||||
assert!(!s.add_many(&[&Url::from("/a/b")]));
|
||||
assert_eq!(0, s.add_same(&[&Url::from("/a/b")]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -203,14 +205,15 @@ mod tests {
|
|||
let mut s = Selected::default();
|
||||
|
||||
s.add(&Url::from("/a/b"));
|
||||
assert!(!s.add_many(&[&Url::from("/a")]));
|
||||
assert_eq!(0, s.add_same(&[&Url::from("/a")]));
|
||||
assert_eq!(1, s.add_same(&[&Url::from("/b"), &Url::from("/a")]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_many_sibling_directories_success() {
|
||||
let mut s = Selected::default();
|
||||
|
||||
assert!(s.add_many(&[&Url::from("/a/b"), &Url::from("/a/c")]));
|
||||
assert_eq!(2, s.add_same(&[&Url::from("/a/b"), &Url::from("/a/c")]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -218,7 +221,7 @@ mod tests {
|
|||
let mut s = Selected::default();
|
||||
|
||||
s.add(&Url::from("/a/b"));
|
||||
assert!(!s.add_many(&[&Url::from("/a/b/c")]));
|
||||
assert_eq!(0, s.add_same(&[&Url::from("/a/b/c")]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -228,7 +231,7 @@ mod tests {
|
|||
let child1 = Url::from("/parent/child1");
|
||||
let child2 = Url::from("/parent/child2");
|
||||
let child3 = Url::from("/parent/child3");
|
||||
assert!(s.add_many(&[&child1, &child2, &child3]));
|
||||
assert_eq!(3, s.add_same(&[&child1, &child2, &child3]));
|
||||
|
||||
assert!(s.remove(&child1));
|
||||
assert_eq!(s.inner.len(), 2);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,18 @@ impl Tab {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn hovered_and_selected(&self) -> Vec<&Url> {
|
||||
let Some(h) = self.current.hovered() else {
|
||||
return vec![];
|
||||
};
|
||||
|
||||
if self.selected.is_empty() {
|
||||
vec![&h.url, &h.url]
|
||||
} else {
|
||||
[&h.url].into_iter().chain(self.selected.iter()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
// --- History
|
||||
#[inline]
|
||||
pub fn history_new(&mut self, url: &Url) -> Folder {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ use std::io::{stdout, Write};
|
|||
|
||||
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
|
||||
use tokio::{io::{stdin, AsyncReadExt}, select, sync::mpsc, time};
|
||||
use yazi_scheduler::{Scheduler, BLOCKER};
|
||||
use yazi_proxy::AppProxy;
|
||||
use yazi_scheduler::BLOCKER;
|
||||
use yazi_shared::{event::Cmd, term::Term, Defer};
|
||||
|
||||
use crate::tasks::Tasks;
|
||||
|
|
@ -26,10 +27,10 @@ impl Tasks {
|
|||
task.logs.clone()
|
||||
};
|
||||
|
||||
Scheduler::app_stop().await;
|
||||
AppProxy::stop().await;
|
||||
let _defer = Defer::new(|| {
|
||||
disable_raw_mode().ok();
|
||||
Scheduler::app_resume();
|
||||
AppProxy::resume();
|
||||
});
|
||||
|
||||
Term::clear(&mut stdout()).ok();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
mod arrow;
|
||||
mod cancel;
|
||||
mod inspect;
|
||||
mod open;
|
||||
mod open_with;
|
||||
mod toggle;
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
use yazi_config::open::Opener;
|
||||
use yazi_shared::{emit, event::Cmd, fs::Url, Layer};
|
||||
|
||||
use crate::tasks::Tasks;
|
||||
|
||||
pub struct Opt {
|
||||
targets: Vec<Url>,
|
||||
opener: Opener,
|
||||
}
|
||||
|
||||
impl TryFrom<Cmd> for Opt {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
|
||||
}
|
||||
|
||||
impl Tasks {
|
||||
pub fn _open(targets: Vec<Url>, opener: Opener) {
|
||||
emit!(Call(Cmd::new("open").with_data(Opt { targets, opener }), Layer::Tasks));
|
||||
}
|
||||
|
||||
pub fn open(&mut self, opt: impl TryInto<Opt>) {
|
||||
if let Ok(opt) = opt.try_into() {
|
||||
self.file_open_with(&opt.opener, &opt.targets);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
yazi-core/src/tasks/commands/open_with.rs
Normal file
11
yazi-core/src/tasks/commands/open_with.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
use yazi_proxy::options::OpenWithOpt;
|
||||
|
||||
use crate::tasks::Tasks;
|
||||
|
||||
impl Tasks {
|
||||
pub fn open_with(&mut self, opt: impl TryInto<OpenWithOpt>) {
|
||||
if let Ok(opt) = opt.try_into() {
|
||||
self.file_open_with(&opt.opener, &opt.targets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{collections::{BTreeMap, HashMap, HashSet}, ffi::OsStr, mem, path::Path, sync::Arc, time::Duration};
|
||||
use std::{collections::{BTreeMap, HashMap, HashSet}, ffi::OsStr, mem, sync::Arc, time::Duration};
|
||||
|
||||
use tokio::time::sleep;
|
||||
use tracing::debug;
|
||||
|
|
@ -56,28 +56,26 @@ impl Tasks {
|
|||
running.values().take(Self::limit()).map(Into::into).collect()
|
||||
}
|
||||
|
||||
pub fn file_open(&self, targets: &[(impl AsRef<Path>, impl AsRef<str>)]) -> bool {
|
||||
pub fn file_open(&self, hovered: &Url, targets: &[(Url, String)]) {
|
||||
let mut openers = BTreeMap::new();
|
||||
for (path, mime) in targets {
|
||||
if let Some(opener) = OPEN.openers(path, mime).and_then(|o| o.first().copied()) {
|
||||
openers.entry(opener).or_insert_with(Vec::new).push(path.as_ref().as_os_str());
|
||||
for (url, mime) in targets {
|
||||
if let Some(opener) = OPEN.openers(url, mime).and_then(|o| o.first().copied()) {
|
||||
openers.entry(opener).or_insert_with(|| vec![hovered]).push(url);
|
||||
}
|
||||
}
|
||||
for (opener, args) in openers {
|
||||
self.file_open_with(opener, &args);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn file_open_with(&self, opener: &Opener, args: &[impl AsRef<OsStr>]) -> bool {
|
||||
pub fn file_open_with(&self, opener: &Opener, args: &[impl AsRef<OsStr>]) {
|
||||
if opener.spread {
|
||||
self.scheduler.process_open(opener, args);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
for target in args {
|
||||
self.scheduler.process_open(opener, &[target]);
|
||||
for target in args.iter().skip(1) {
|
||||
self.scheduler.process_open(opener, &[&args[0], target]);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn file_cut(&self, src: &HashSet<Url>, dest: &Url, force: bool) {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ impl WhichSorter {
|
|||
entities.push(match self.by {
|
||||
SortBy::None => unreachable!(),
|
||||
SortBy::Key => Cow::Owned(ctrl.on()),
|
||||
SortBy::Desc => ctrl.desc_or_exec(),
|
||||
SortBy::Desc => ctrl.desc_or_run(),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ yazi-boot = { path = "../yazi-boot", version = "0.2.3" }
|
|||
yazi-config = { path = "../yazi-config", version = "0.2.3" }
|
||||
yazi-core = { path = "../yazi-core", version = "0.2.3" }
|
||||
yazi-plugin = { path = "../yazi-plugin", version = "0.2.3" }
|
||||
yazi-proxy = { path = "../yazi-proxy", version = "0.2.3" }
|
||||
yazi-scheduler = { path = "../yazi-scheduler", version = "0.2.3" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "0.2.3" }
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ pub(crate) struct App {
|
|||
}
|
||||
|
||||
impl App {
|
||||
pub(crate) async fn run() -> Result<()> {
|
||||
pub(crate) async fn serve() -> Result<()> {
|
||||
let term = Term::start()?;
|
||||
let signals = Signals::start()?;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
use yazi_core::notify::Message;
|
||||
use yazi_proxy::options::NotifyOpt;
|
||||
|
||||
use crate::app::App;
|
||||
|
||||
impl App {
|
||||
pub(crate) fn notify(&mut self, msg: impl TryInto<Message>) { self.cx.notify.push(msg); }
|
||||
pub(crate) fn notify(&mut self, opt: impl TryInto<NotifyOpt>) {
|
||||
let Ok(opt) = opt.try_into() else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.cx.notify.push(opt);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,11 +151,11 @@ impl<'a> Executor<'a> {
|
|||
};
|
||||
}
|
||||
|
||||
on!(open);
|
||||
on!(toggle, "close");
|
||||
on!(arrow);
|
||||
on!(inspect);
|
||||
on!(cancel);
|
||||
on!(open_with);
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match cmd.name.as_str() {
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ impl Widget for Bindings<'_> {
|
|||
let col1: Vec<_> =
|
||||
bindings.iter().map(|c| ListItem::new(c.on()).style(THEME.help.on)).collect();
|
||||
|
||||
// Exec
|
||||
// Run
|
||||
let col2: Vec<_> =
|
||||
bindings.iter().map(|c| ListItem::new(c.exec()).style(THEME.help.exec)).collect();
|
||||
bindings.iter().map(|c| ListItem::new(c.run()).style(THEME.help.run)).collect();
|
||||
|
||||
// Desc
|
||||
let col3: Vec<_> = bindings
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ impl<'a> Widget for Layout<'a> {
|
|||
|
||||
let chunks = layout::Layout::vertical([Constraint::Fill(1), Constraint::Length(1)]).split(area);
|
||||
Line::styled(
|
||||
help.keyword().unwrap_or_else(|| format!("{}.help", help.layer.to_string())),
|
||||
help.keyword().unwrap_or_else(|| format!("{}.help", help.layer)),
|
||||
THEME.help.footer,
|
||||
)
|
||||
.render(chunks[1], buf);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use mlua::{Scope, Table};
|
|||
use tracing::error;
|
||||
use yazi_config::LAYOUT;
|
||||
use yazi_plugin::{elements::RectRef, LUA};
|
||||
use yazi_shared::RoCell;
|
||||
use yazi_shared::{Defer, RoCell};
|
||||
|
||||
use crate::Ctx;
|
||||
|
||||
|
|
@ -34,6 +34,7 @@ impl Lives {
|
|||
f: impl FnOnce(&Scope<'a, 'a>) -> mlua::Result<T>,
|
||||
) -> mlua::Result<T> {
|
||||
let result = LUA.scope(|scope| {
|
||||
let _defer = Defer::new(|| SCOPE.drop());
|
||||
SCOPE.init(unsafe { mem::transmute(scope) });
|
||||
LUA.set_named_registry_value("cx", scope.create_any_userdata_ref(cx)?)?;
|
||||
|
||||
|
|
@ -58,7 +59,6 @@ impl Lives {
|
|||
status: *globals.raw_get::<_, Table>("Status")?.raw_get::<_, RectRef>("area")?,
|
||||
}));
|
||||
|
||||
SCOPE.drop();
|
||||
Ok(ret)
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ pub(super) struct Logs;
|
|||
|
||||
impl Logs {
|
||||
pub(super) fn start() {
|
||||
let appender = tracing_appender::rolling::never(Xdg::state_dir().unwrap(), "yazi.log");
|
||||
let state_dir = Xdg::state_dir();
|
||||
std::fs::create_dir_all(&state_dir).expect("Failed to create state directory");
|
||||
|
||||
let appender = tracing_appender::rolling::never(state_dir, "yazi.log");
|
||||
let (handle, guard) = tracing_appender::non_blocking(appender);
|
||||
|
||||
// let filter = EnvFilter::from_default_env();
|
||||
|
|
|
|||
|
|
@ -52,5 +52,5 @@ async fn main() -> anyhow::Result<()> {
|
|||
|
||||
yazi_core::init();
|
||||
|
||||
app::App::run().await
|
||||
app::App::serve().await
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use ratatui::{buffer::Buffer, layout::{self, Constraint, Offset, Rect}, style::{Style, Stylize}, widgets::{Block, BorderType, Paragraph, Widget, Wrap}};
|
||||
use yazi_core::notify::{Level, Message};
|
||||
use ratatui::{buffer::Buffer, layout::{self, Constraint, Offset, Rect}, widgets::{Block, BorderType, Paragraph, Widget, Wrap}};
|
||||
use yazi_config::THEME;
|
||||
use yazi_core::notify::Message;
|
||||
use yazi_proxy::options::NotifyLevel;
|
||||
|
||||
use crate::{widgets::Clear, Ctx};
|
||||
|
||||
|
|
@ -42,9 +44,9 @@ impl<'a> Widget for Layout<'a> {
|
|||
|
||||
for (i, m) in notify.messages.iter().enumerate().take(limit) {
|
||||
let (icon, style) = match m.level {
|
||||
Level::Info => ("", Style::default().green()),
|
||||
Level::Warn => ("", Style::default().yellow()),
|
||||
Level::Error => ("", Style::default().red()),
|
||||
NotifyLevel::Info => (&THEME.notify.icon_info, THEME.notify.title_info),
|
||||
NotifyLevel::Warn => (&THEME.notify.icon_warn, THEME.notify.title_warn),
|
||||
NotifyLevel::Error => (&THEME.notify.icon_error, THEME.notify.title_error),
|
||||
};
|
||||
|
||||
let mut rect =
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@ impl Signals {
|
|||
#[cfg(unix)]
|
||||
fn spawn_system_task(&self) -> Result<JoinHandle<()>> {
|
||||
use libc::{SIGCONT, SIGHUP, SIGINT, SIGQUIT, SIGTERM};
|
||||
use yazi_scheduler::{Scheduler, BLOCKER};
|
||||
use yazi_proxy::AppProxy;
|
||||
use yazi_scheduler::BLOCKER;
|
||||
|
||||
let mut signals = signal_hook_tokio::Signals::new([
|
||||
// Terminating signals
|
||||
|
|
@ -65,7 +66,7 @@ impl Signals {
|
|||
break;
|
||||
}
|
||||
}
|
||||
SIGCONT => Scheduler::app_resume(),
|
||||
SIGCONT => AppProxy::resume(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ impl Widget for Cand<'_> {
|
|||
spans.push(Span::styled(&THEME.which.separator, THEME.which.separator_style));
|
||||
|
||||
// Description
|
||||
spans.push(Span::styled(self.cand.desc_or_exec(), THEME.which.desc));
|
||||
spans.push(Span::styled(self.cand.desc_or_run(), THEME.which.desc));
|
||||
|
||||
Line::from(spans).render(area, buf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ repository = "https://github.com/sxyazi/yazi"
|
|||
yazi-adaptor = { path = "../yazi-adaptor", version = "0.2.3" }
|
||||
yazi-boot = { path = "../yazi-boot", version = "0.2.3" }
|
||||
yazi-config = { path = "../yazi-config", version = "0.2.3" }
|
||||
yazi-proxy = { path = "../yazi-proxy", version = "0.2.3" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "0.2.3" }
|
||||
|
||||
# External dependencies
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ local M = {}
|
|||
function M:peek()
|
||||
local _, bound = ya.preview_archive(self)
|
||||
if bound then
|
||||
ya.manager_emit("peek", { tostring(bound), only_if = tostring(self.file.url), upper_bound = "" })
|
||||
ya.manager_emit("peek", { bound, only_if = tostring(self.file.url), upper_bound = true })
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ function M:seek(units)
|
|||
if h and h.url == self.file.url then
|
||||
local step = math.floor(units * self.area.h / 10)
|
||||
ya.manager_emit("peek", {
|
||||
tostring(math.max(0, cx.active.preview.skip + step)),
|
||||
math.max(0, cx.active.preview.skip + step),
|
||||
only_if = tostring(self.file.url),
|
||||
})
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ local M = {}
|
|||
function M:peek()
|
||||
local _, bound = ya.preview_code(self)
|
||||
if bound then
|
||||
ya.manager_emit("peek", { tostring(bound), only_if = tostring(self.file.url), upper_bound = "" })
|
||||
ya.manager_emit("peek", { bound, only_if = tostring(self.file.url), upper_bound = true })
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ function M:seek(units)
|
|||
if h and h.url == self.file.url then
|
||||
local step = math.floor(units * self.area.h / 10)
|
||||
ya.manager_emit("peek", {
|
||||
tostring(math.max(0, cx.active.preview.skip + step)),
|
||||
math.max(0, cx.active.preview.skip + step),
|
||||
only_if = tostring(self.file.url),
|
||||
})
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ function M:peek()
|
|||
|
||||
local bound = math.max(0, #folder.files - self.area.h)
|
||||
if self.skip > bound then
|
||||
ya.manager_emit("peek", { tostring(bound), only_if = tostring(self.file.url), upper_bound = "" })
|
||||
ya.manager_emit("peek", { bound, only_if = tostring(self.file.url), upper_bound = true })
|
||||
end
|
||||
|
||||
local items, markers = {}, {}
|
||||
|
|
@ -37,7 +37,7 @@ function M:seek(units)
|
|||
local step = math.floor(units * self.area.h / 10)
|
||||
local bound = math.max(0, #folder.files - self.area.h)
|
||||
ya.manager_emit("peek", {
|
||||
tostring(ya.clamp(0, cx.active.preview.skip + step, bound)),
|
||||
ya.clamp(0, cx.active.preview.skip + step, bound),
|
||||
only_if = tostring(self.file.url),
|
||||
})
|
||||
end
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ function M:peek()
|
|||
|
||||
child:start_kill()
|
||||
if self.skip > 0 and i < self.skip + limit then
|
||||
ya.manager_emit("peek", { tostring(math.max(0, i - limit)), only_if = tostring(self.file.url), upper_bound = "" })
|
||||
ya.manager_emit("peek", { math.max(0, i - limit), only_if = tostring(self.file.url), upper_bound = true })
|
||||
else
|
||||
lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size))
|
||||
ya.preview_widgets(self, { ui.Paragraph.parse(self.area, lines) })
|
||||
|
|
@ -46,7 +46,7 @@ function M:seek(units)
|
|||
if h and h.url == self.file.url then
|
||||
local step = math.floor(units * self.area.h / 10)
|
||||
ya.manager_emit("peek", {
|
||||
tostring(math.max(0, cx.active.preview.skip + step)),
|
||||
math.max(0, cx.active.preview.skip + step),
|
||||
only_if = tostring(self.file.url),
|
||||
})
|
||||
end
|
||||
|
|
@ -55,7 +55,7 @@ end
|
|||
function M:fallback_to_builtin()
|
||||
local _, bound = ya.preview_code(self)
|
||||
if bound then
|
||||
ya.manager_emit("peek", { tostring(bound), only_if = tostring(self.file.url), upper_bound = "" })
|
||||
ya.manager_emit("peek", { bound, only_if = tostring(self.file.url), upper_bound = true })
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,10 @@ function M:preload()
|
|||
urls[#urls + 1] = tostring(file.url)
|
||||
end
|
||||
|
||||
local child, code = Command("file"):args({ "-bL", "--mime-type" }):args(urls):stdout(Command.PIPED):spawn()
|
||||
local cmd = os.getenv("YAZI_FILE_ONE") or "file"
|
||||
local child, code = Command(cmd):args({ "-bL", "--mime-type" }):args(urls):stdout(Command.PIPED):spawn()
|
||||
if not child then
|
||||
ya.err("spawn `file` command returns " .. tostring(code))
|
||||
ya.err(string.format("spawn `%s` command returns %s", cmd, code))
|
||||
return 0
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ function M:seek(units)
|
|||
local h = cx.active.current.hovered
|
||||
if h and h.url == self.file.url then
|
||||
local step = ya.clamp(-1, units, 1)
|
||||
ya.manager_emit("peek", { tostring(math.max(0, cx.active.preview.skip + step)), only_if = tostring(self.file.url) })
|
||||
ya.manager_emit("peek", { math.max(0, cx.active.preview.skip + step), only_if = tostring(self.file.url) })
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ function M:preload()
|
|||
elseif not output.status:success() then
|
||||
local pages = tonumber(output.stderr:match("the last page %((%d+)%)")) or 0
|
||||
if self.skip > 0 and pages > 0 then
|
||||
ya.manager_emit("peek", { tostring(math.max(0, pages - 1)), only_if = tostring(self.file.url), upper_bound = "" })
|
||||
ya.manager_emit("peek", { math.max(0, pages - 1), only_if = tostring(self.file.url), upper_bound = true })
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue