mirror of
https://github.com/sayanarijit/xplr.git
synced 2024-09-11 11:05:39 +03:00
v0.21.3 (#661)
This commit is contained in:
commit
8af1647c09
@ -1,4 +1,14 @@
|
||||
# Why dynamic linking?
|
||||
# See https://github.com/sayanarijit/xplr/issues/309
|
||||
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
rustflags = ["-C", "linker=aarch64-linux-gnu-gcc", "-C", "link-args=-rdynamic"]
|
||||
|
||||
[target.aarch64-linux-android]
|
||||
rustflags = ["-C", "linker=aarch64-linux-android-clang", "-C", "link-args=-rdynamic", "-C", "default-linker-libraries"]
|
||||
|
||||
[target.arm-unknown-linux-gnueabihf]
|
||||
rustflags = ["-C", "linker=arm-linux-gnueabihf-gcc", "-C", "link-args=-rdynamic"]
|
||||
|
97
.github/workflows/cd.yml
vendored
97
.github/workflows/cd.yml
vendored
@ -12,71 +12,74 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- macos-latest
|
||||
- ubuntu-latest
|
||||
- ubuntu-20.04
|
||||
build:
|
||||
- macos
|
||||
- macos-aarch64
|
||||
- linux
|
||||
- linux-musl
|
||||
- linux-aarch64
|
||||
- linux-arm
|
||||
rust: [stable]
|
||||
include:
|
||||
# See the list: https://github.com/cross-rs/cross
|
||||
|
||||
- os: macos-latest
|
||||
artifact_prefix: macos
|
||||
- build: macos
|
||||
os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
binary_postfix: ""
|
||||
|
||||
- os: ubuntu-latest
|
||||
artifact_prefix: linux
|
||||
- build: macos-aarch64
|
||||
os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
|
||||
- build: linux
|
||||
os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
binary_postfix: ""
|
||||
|
||||
- os: ubuntu-20.04
|
||||
artifact_prefix: linux-musl
|
||||
- build: linux-musl
|
||||
os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-musl
|
||||
binary_postfix: ""
|
||||
|
||||
# Will see later
|
||||
- build: linux-aarch64
|
||||
os: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
|
||||
# - os: ubuntu-latest
|
||||
# artifact_prefix: x86_64-android
|
||||
# target: x86_64-linux-android
|
||||
# binary_postfix: ''
|
||||
#
|
||||
# - os: ubuntu-latest
|
||||
# artifact_prefix: aarch64-android
|
||||
# target: aarch64-linux-android
|
||||
# binary_postfix: ''
|
||||
- build: linux-arm
|
||||
os: ubuntu-latest
|
||||
target: arm-unknown-linux-gnueabihf
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Installing Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
|
||||
- name: Installing needed macOS dependencies
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: brew install openssl@1.1
|
||||
|
||||
- name: Installing needed Ubuntu dependencies
|
||||
if: matrix.os == 'ubuntu-latest' || matrix.os == 'ubuntu-20.04'
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt-get install -y -qq pkg-config libssl-dev libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
|
||||
sudo apt-get install -y --no-install-recommends liblua5.1-0-dev libluajit-5.1-dev gcc pkg-config curl git make ca-certificates
|
||||
|
||||
- name: Checking out sources
|
||||
uses: actions/checkout@v1
|
||||
- if: matrix.build == 'linux-musl'
|
||||
run: sudo apt-get install -y musl-tools
|
||||
|
||||
- if: matrix.build == 'linux-aarch64'
|
||||
run: sudo apt-get install -y gcc-aarch64-linux-gnu
|
||||
|
||||
- if: matrix.build == 'linux-arm'
|
||||
run: |
|
||||
sudo apt-get install -y gcc-multilib
|
||||
sudo apt-get install -y gcc-arm-linux-gnueabihf
|
||||
sudo ln -s /usr/include/asm-generic/ /usr/include/asm
|
||||
|
||||
- name: Running cargo build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: true
|
||||
command: build
|
||||
toolchain: ${{ matrix.rust }}
|
||||
args: --locked --release --target ${{ matrix.target }}
|
||||
run: cargo build --locked --release --target ${{ matrix.target }}
|
||||
|
||||
- name: Install gpg secret key
|
||||
run: |
|
||||
@ -87,9 +90,9 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
cd target/${{ matrix.target }}/release
|
||||
BINARY_NAME=xplr${{ matrix.binary_postfix }}
|
||||
BINARY_NAME=xplr
|
||||
strip $BINARY_NAME
|
||||
RELEASE_NAME=xplr-${{ matrix.artifact_prefix }}
|
||||
RELEASE_NAME=xplr-${{ matrix.build }}
|
||||
tar czvf $RELEASE_NAME.tar.gz $BINARY_NAME
|
||||
shasum -a 256 $RELEASE_NAME.tar.gz > $RELEASE_NAME.sha256
|
||||
cat <(echo "${{ secrets.GPG_PASS }}") | gpg --pinentry-mode loopback --passphrase-fd 0 --detach-sign --armor $RELEASE_NAME.tar.gz
|
||||
@ -98,9 +101,9 @@ jobs:
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
target/${{ matrix.target }}/release/xplr-${{ matrix.artifact_prefix }}.tar.gz
|
||||
target/${{ matrix.target }}/release/xplr-${{ matrix.artifact_prefix }}.sha256
|
||||
target/${{ matrix.target }}/release/xplr-${{ matrix.artifact_prefix }}.tar.gz.asc
|
||||
target/${{ matrix.target }}/release/xplr-${{ matrix.build }}.tar.gz
|
||||
target/${{ matrix.target }}/release/xplr-${{ matrix.build }}.sha256
|
||||
target/${{ matrix.target }}/release/xplr-${{ matrix.build }}.tar.gz.asc
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@ -108,7 +111,7 @@ jobs:
|
||||
name: Publishing GPG signature
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install gpg secret key
|
||||
run: |
|
||||
cat <(echo -e "${{ secrets.GPG_SECRET }}") | gpg --batch --import
|
||||
@ -133,20 +136,16 @@ jobs:
|
||||
name: Publishing to Cargo
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
|
||||
- run: |
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt-get install -y -qq pkg-config libssl-dev libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: publish
|
||||
args: --allow-dirty
|
||||
- run: cargo publish --allow-dirty
|
||||
env:
|
||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_KEY }}
|
||||
|
172
.github/workflows/ci.yml
vendored
172
.github/workflows/ci.yml
vendored
@ -11,130 +11,134 @@ jobs:
|
||||
name: Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
override: true
|
||||
- uses: actions-rs/cargo@v1
|
||||
- run: cargo check
|
||||
|
||||
fmt:
|
||||
name: Rustfmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
command: check
|
||||
toolchain: stable
|
||||
components: rustfmt
|
||||
- run: cargo fmt --all -- --check
|
||||
|
||||
clippy:
|
||||
name: Clippy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
components: clippy
|
||||
- run: cargo clippy -- -D warnings
|
||||
|
||||
spellcheck:
|
||||
name: Spellcheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: codespell-project/actions-codespell@v1
|
||||
with:
|
||||
ignore_words_file: .codespellignore
|
||||
|
||||
test:
|
||||
name: Test Suite
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs:
|
||||
- check
|
||||
- fmt
|
||||
- clippy
|
||||
- spellcheck
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- macos-latest
|
||||
- ubuntu-latest
|
||||
- ubuntu-20.04
|
||||
build:
|
||||
- macos
|
||||
- macos-aarch64
|
||||
- linux
|
||||
- linux-musl
|
||||
- linux-aarch64
|
||||
- linux-arm
|
||||
rust: [stable]
|
||||
include:
|
||||
- os: macos-latest
|
||||
artifact_prefix: macos
|
||||
# See the list: https://github.com/cross-rs/cross
|
||||
|
||||
- build: macos
|
||||
os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
binary_postfix: ""
|
||||
- os: ubuntu-latest
|
||||
artifact_prefix: linux
|
||||
|
||||
- build: macos-aarch64
|
||||
os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
|
||||
- build: linux
|
||||
os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
binary_postfix: ""
|
||||
- os: ubuntu-20.04
|
||||
artifact_prefix: linux-musl
|
||||
|
||||
- build: linux-musl
|
||||
os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-musl
|
||||
binary_postfix: ""
|
||||
|
||||
- build: linux-aarch64
|
||||
os: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
|
||||
- build: linux-arm
|
||||
os: ubuntu-latest
|
||||
target: arm-unknown-linux-gnueabihf
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: full
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Installing Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
|
||||
- name: Installing needed macOS dependencies
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: brew install openssl@1.1
|
||||
|
||||
- name: Installing needed Ubuntu dependencies
|
||||
if: matrix.os == 'ubuntu-latest' || matrix.os == 'ubuntu-20.04'
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt-get install -y -qq pkg-config libssl-dev libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
|
||||
sudo apt-get install -y --no-install-recommends liblua5.1-0-dev libluajit-5.1-dev gcc pkg-config curl git make ca-certificates
|
||||
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
toolchain: ${{ matrix.rust }}
|
||||
args: --target ${{ matrix.target }}
|
||||
- if: matrix.build == 'linux-musl'
|
||||
run: sudo apt-get install -y musl-tools
|
||||
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
toolchain: ${{ matrix.rust }}
|
||||
args: --target ${{ matrix.target }}
|
||||
- if: matrix.build == 'linux-aarch64'
|
||||
run: sudo apt-get install -y gcc-aarch64-linux-gnu
|
||||
|
||||
- if: matrix.build == 'linux-arm'
|
||||
run: |
|
||||
sudo apt-get install -y gcc-multilib
|
||||
sudo apt-get install -y gcc-arm-linux-gnueabihf
|
||||
sudo ln -s /usr/include/asm-generic/ /usr/include/asm
|
||||
|
||||
- run: cargo build --target ${{ matrix.target }}
|
||||
|
||||
- if: matrix.build == 'macos' || matrix.build == 'linux'
|
||||
run: cargo test --target ${{ matrix.target }}
|
||||
|
||||
# bench:
|
||||
# name: Benchmarks
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
# - uses: actions-rs/toolchain@v1
|
||||
# - uses: actions/checkout@v3
|
||||
# - uses: dtolnay/rust-toolchain@stable
|
||||
# with:
|
||||
# toolchain: stable
|
||||
# profile: minimal
|
||||
# override: true
|
||||
# # These dependencies are required for `clipboard`
|
||||
# - run: sudo apt-get install -y -qq libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
|
||||
# - uses: actions-rs/cargo@v1
|
||||
# with:
|
||||
# command: bench
|
||||
|
||||
fmt:
|
||||
name: Rustfmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
override: true
|
||||
components: rustfmt
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
clippy:
|
||||
name: Clippy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
override: true
|
||||
components: clippy
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: -- -D warnings
|
||||
|
||||
spellcheck:
|
||||
name: Spellcheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: codespell-project/actions-codespell@v1
|
||||
with:
|
||||
ignore_words_file: .codespellignore
|
||||
# - run: cargo bench
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -17,3 +17,6 @@ book/
|
||||
|
||||
# direnv
|
||||
.direnv/
|
||||
|
||||
# nix
|
||||
result
|
||||
|
665
Cargo.lock
generated
665
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
39
Cargo.toml
39
Cargo.toml
@ -8,7 +8,7 @@ path = './benches/criterion.rs'
|
||||
|
||||
[package]
|
||||
name = 'xplr'
|
||||
version = '0.21.2'
|
||||
version = '0.21.3'
|
||||
authors = ['Arijit Basu <hi@arijitbasu.in>']
|
||||
edition = '2021'
|
||||
description = 'A hackable, minimal, fast TUI file explorer'
|
||||
@ -22,29 +22,29 @@ categories = ['command-line-interface', 'command-line-utilities']
|
||||
include = ['src/**/*', 'docs/en/src/**/*', 'LICENSE', 'README.md']
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.144"
|
||||
libc = "0.2.147"
|
||||
humansize = "2.1.3"
|
||||
natord = "1.0.9"
|
||||
anyhow = "1.0.71"
|
||||
serde_yaml = "0.9.21"
|
||||
crossterm = { version = "0.26.1", features = [], default-features = false }
|
||||
ansi-to-tui = "3.0.0"
|
||||
regex = "1.8.1"
|
||||
anyhow = "1.0.72"
|
||||
serde_yaml = "0.9.25"
|
||||
crossterm = { version = "0.27.0", features = [], default-features = false }
|
||||
ansi-to-tui = "3.1.0"
|
||||
regex = "1.9.3"
|
||||
gethostname = "0.4.3"
|
||||
serde_json = "1.0.96"
|
||||
serde_json = "1.0.104"
|
||||
path-absolutize = "3.1.0"
|
||||
which = "4.4.0"
|
||||
nu-ansi-term = "0.47.0"
|
||||
nu-ansi-term = "0.49.0"
|
||||
textwrap = "0.16"
|
||||
snailquote = "0.3.1"
|
||||
skim = { version = "0.10.4", default-features = false }
|
||||
time = { version = "0.3.21", features = ["serde", "local-offset", "formatting", "macros"] }
|
||||
jf = "0.3.1"
|
||||
xdg = "2.5.0"
|
||||
time = { version = "0.3.25", features = ["serde", "local-offset", "formatting", "macros"] }
|
||||
jf = "0.6.2"
|
||||
xdg = "2.5.2"
|
||||
home = "0.5.5"
|
||||
|
||||
[dependencies.lscolors]
|
||||
version = "0.14.0"
|
||||
version = "0.15.0"
|
||||
default-features = false
|
||||
features = ["nu-ansi-term"]
|
||||
|
||||
@ -57,18 +57,18 @@ version = "2.0.4"
|
||||
default-features = false
|
||||
|
||||
[dependencies.tui]
|
||||
version = "0.20.1"
|
||||
version = "0.22.0"
|
||||
default-features = false
|
||||
features = ['crossterm', 'serde']
|
||||
package = 'ratatui'
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.163"
|
||||
version = "1.0.183"
|
||||
features = []
|
||||
default-features = false
|
||||
|
||||
[dependencies.indexmap]
|
||||
version = "1.9.3"
|
||||
version = "2.0.0"
|
||||
features = ['serde']
|
||||
|
||||
[dependencies.mlua]
|
||||
@ -76,16 +76,17 @@ version = "0.8.9"
|
||||
features = ['luajit', 'vendored', 'serialize', 'send']
|
||||
|
||||
[dependencies.tui-input]
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
features = ['serde']
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.4.0"
|
||||
assert_cmd = "2.0.11"
|
||||
criterion = "0.5.1"
|
||||
assert_cmd = "2.0.12"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
panic = 'abort'
|
||||
strip = true
|
||||
|
||||
[features]
|
||||
|
@ -60,6 +60,8 @@ integration][15], enabling you to achieve insane terminal productivity.
|
||||
|
||||
- [[Article] What is a TUI file explorer & why would you need one? ~ xplr.stck.me](https://xplr.stck.me/post/25252/What-is-a-TUI-file-explorer-why-would-you-need-one)
|
||||
|
||||
- [[Article] FOSSPicks - Linux Magazine](https://www.linux-magazine.com/Issues/2022/258/FOSSPicks/(offset)/6)
|
||||
|
||||
## Packaging
|
||||
|
||||
Package maintainers please refer to the [RELEASE.md](./RELEASE.md).
|
||||
|
@ -131,6 +131,14 @@ return {
|
||||
{ LogSuccess = "Switched layout" },
|
||||
{ CallLuaSilently = "custom.some_plugin_with_hooks.on_layout_switch" },
|
||||
}
|
||||
|
||||
-- Add messages to send when the selection changes
|
||||
--
|
||||
-- Type: list of [Message](https://xplr.dev/en/message#message)s
|
||||
on_selection_change = {
|
||||
{ LogSuccess = "Selection changed" },
|
||||
{ CallLuaSilently = "custom.some_plugin_with_hooks.on_selection_change" },
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -587,12 +587,16 @@ Type: nullable list of [Node Sorter](https://xplr.dev/en/sorting#node-sorter-app
|
||||
#### xplr.config.general.initial_mode
|
||||
|
||||
The name of one of the modes to use when xplr loads.
|
||||
This isn't the default mode. To modify the default mode, overwrite
|
||||
[xplr.config.modes.builtin.default](https://xplr.dev/en/modes#xplrconfigmodesbuiltindefault).
|
||||
|
||||
Type: nullable string
|
||||
|
||||
#### xplr.config.general.initial_layout
|
||||
|
||||
The name of one of the layouts to use when xplr loads.
|
||||
This isn't the default layout. To modify the default layout, overwrite
|
||||
[xplr.config.layouts.builtin.default](https://xplr.dev/en/layouts#xplrconfiglayoutsbuiltindefault).
|
||||
|
||||
Type: nullable string
|
||||
|
||||
|
@ -198,44 +198,20 @@ sudo cp target/release/xplr /usr/local/bin/
|
||||
|
||||
## Android
|
||||
|
||||
### [Termux][23]
|
||||
### [Termux][24]
|
||||
|
||||
[![xplr-termuxfd3c398d3cf4bcbc.md.jpg][24]][25]
|
||||
```bash
|
||||
pkg install rust make binutils
|
||||
cargo install --locked xplr
|
||||
|
||||
> Please note that xplr isn't heavily tested on Termux, hence things might
|
||||
> need a little tweaking and fixing for a smooth usage experience.
|
||||
# Run
|
||||
~/.cargo/bin/xplr
|
||||
```
|
||||
|
||||
- Install build dependencies
|
||||
> Please note that xplr isn't heavily tested on Termux, hence things might need
|
||||
> a little tweaking and fixing for a smooth user experience.
|
||||
|
||||
```bash
|
||||
pkg install rustc cargo make
|
||||
```
|
||||
|
||||
- Install `xplr`
|
||||
|
||||
```bash
|
||||
cargo install --locked --force xplr
|
||||
```
|
||||
|
||||
- Setup storage
|
||||
|
||||
```bash
|
||||
termux-setup-storage
|
||||
```
|
||||
|
||||
- Setup config and runtime dir
|
||||
|
||||
```bash
|
||||
export XDG_CONFIG_HOME="$PWD/storage/.config"
|
||||
export XDG_RUNTIME_DIR="$PWD/storage/run"
|
||||
|
||||
mkdir -p "$XDG_CONFIG_HOME" "$XDG_RUNTIME_DIR"
|
||||
```
|
||||
|
||||
- Run
|
||||
```bash
|
||||
~/.cargo/bin/xplr
|
||||
```
|
||||
![termux demo][23]
|
||||
|
||||
[1]: #direct-download
|
||||
[2]: #from-cratesio
|
||||
@ -259,8 +235,8 @@ sudo cp target/release/xplr /usr/local/bin/
|
||||
[20]: https://gcc.gnu.org/
|
||||
[21]: https://www.gnu.org/software/make/
|
||||
[22]: https://git-scm.com/
|
||||
[23]: https://termux.com/
|
||||
[24]: https://s3.gifyu.com/images/xplr-termuxfd3c398d3cf4bcbc.md.jpg
|
||||
[23]: https://github.com/sayanarijit/xplr/assets/11632726/3b61e8c8-76f0-48e8-8734-50e9e7e495b7
|
||||
[24]: https://termux.dev/
|
||||
[25]: https://gifyu.com/image/tF2D
|
||||
[26]: https://github.com/sayanarijit/xplr/releases/latest/download/xplr-linux-musl.tar.gz
|
||||
[27]: https://pkgs.alpinelinux.org/packages?name=xplr
|
||||
|
@ -2,15 +2,13 @@
|
||||
|
||||
#### Example: Defining Custom Layout
|
||||
|
||||
[![layout.png][23]][24]
|
||||
|
||||
```lua
|
||||
xplr.config.layouts.builtin.default = {
|
||||
Horizontal = {
|
||||
config = {
|
||||
margin = 1,
|
||||
horizontal_margin = 2,
|
||||
vertical_margin = 3,
|
||||
horizontal_margin = 1,
|
||||
vertical_margin = 1,
|
||||
constraints = {
|
||||
{ Percentage = 50 },
|
||||
{ Percentage = 50 },
|
||||
@ -24,6 +22,21 @@ xplr.config.layouts.builtin.default = {
|
||||
}
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```
|
||||
╭ /home ─────────────╮╭ Help [default] ────╮
|
||||
│ ╭─── path ││. show hidden │
|
||||
│ ├▸[ð Desktop/] ││/ search │
|
||||
│ ├ ð Documents/ ││: action │
|
||||
│ ├ ð Downloads/ ││? global help │
|
||||
│ ├ ð GitHub/ ││G go to bottom │
|
||||
│ ├ ð Music/ ││V select/unselect│
|
||||
│ ├ ð Pictures/ ││ctrl duplicate as │
|
||||
│ ├ ð Public/ ││ctrl next visit │
|
||||
╰────────────────────╯╰────────────────────╯
|
||||
```
|
||||
|
||||
A layout is a [sum type][56] can be one of the following:
|
||||
|
||||
- [Nothing][8]
|
||||
@ -86,7 +99,7 @@ Type: { Static = [Custom Panel][27] }
|
||||
This is a custom layout to render dynamic content using a function defined in
|
||||
[xplr.fn][28] that takes [Content Renderer Argument][36] and returns [Custom Panel][27].
|
||||
|
||||
Type: { Dynamic = [Content Renderer][35] }
|
||||
Type: { Dynamic = "[Content Renderer][35]" }
|
||||
|
||||
### Horizontal
|
||||
|
||||
@ -97,7 +110,7 @@ It contains the following information:
|
||||
- [config][15]
|
||||
- [splits][17]
|
||||
|
||||
Type: { Horizontal = { config = [config][15], splits = [splits][17] }
|
||||
Type: { Vertical = { config = [Layout Config][15], splits = { [Layout][17], ... } }
|
||||
|
||||
### Vertical
|
||||
|
||||
@ -108,7 +121,7 @@ It contains the following information:
|
||||
- [config][15]
|
||||
- [splits][17]
|
||||
|
||||
Type: { Vertical = { config = [config][15], splits = [splits][17] }
|
||||
Type: { Vertical = { config = [Layout Config][15], splits = { [Layout][17], ... } }
|
||||
|
||||
## Layout Config
|
||||
|
||||
@ -200,6 +213,16 @@ xplr.config.layouts.builtin.default = {
|
||||
}
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```
|
||||
╭ custom title ────────╮
|
||||
│custom body │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────╯
|
||||
```
|
||||
|
||||
#### Example: Render a custom dynamic paragraph
|
||||
|
||||
```lua
|
||||
@ -215,6 +238,23 @@ xplr.fn.custom.render_layout = function(ctx)
|
||||
end
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```
|
||||
╭/home/sayanarijit───────────────────────────╮
|
||||
│mime_essence: inode/directory │
|
||||
│relative_path: Desktop │
|
||||
│is_symlink: false │
|
||||
│is_readonly: false │
|
||||
│parent: /home/sayanarijit │
|
||||
│absolute_path: /home/sayanarijit/Desktop │
|
||||
│is_broken: false │
|
||||
│created: 1668087850396758714 │
|
||||
│size: 4096 │
|
||||
│gid: 100 │
|
||||
╰────────────────────────────────────────────╯
|
||||
```
|
||||
|
||||
### CustomList
|
||||
|
||||
A list to render. It contains the following fields:
|
||||
@ -235,6 +275,17 @@ xplr.config.layouts.builtin.default = {
|
||||
}
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```
|
||||
╭ custom title ─────────────╮
|
||||
│1 │
|
||||
│2 │
|
||||
│3 │
|
||||
│ │
|
||||
╰───────────────────────────╯
|
||||
```
|
||||
|
||||
#### Example: Render a custom dynamic list
|
||||
|
||||
```lua
|
||||
@ -254,6 +305,18 @@ xplr.fn.custom.render_layout = function(ctx)
|
||||
end
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```
|
||||
╭/home/sayanarijit──────────╮
|
||||
│Desktop │
|
||||
│0.21.2 │
|
||||
│17336 │
|
||||
│ │
|
||||
│ │
|
||||
╰───────────────────────────╯
|
||||
```
|
||||
|
||||
## CustomTable
|
||||
|
||||
A custom table to render. It contains the following fields:
|
||||
@ -283,6 +346,18 @@ xplr.config.layouts.builtin.default = {
|
||||
}
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```
|
||||
╭ custom title ────────────────────╮
|
||||
│a b │
|
||||
│c d │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────╯
|
||||
```
|
||||
|
||||
#### Example: Render a custom dynamic table
|
||||
|
||||
```lua
|
||||
@ -309,6 +384,23 @@ xplr.fn.custom.render_layout = function(ctx)
|
||||
end
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```
|
||||
╭/home/sayanarijit───────────────────────────╮
|
||||
│ │
|
||||
│Layout height 12 │
|
||||
│Layout width 46 │
|
||||
│ │
|
||||
│Screen height 12 │
|
||||
│Screen width 46 │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰────────────────────────────────────────────╯
|
||||
```
|
||||
|
||||
### CustomLayout
|
||||
|
||||
A whole custom layout to render. It doesn't make sense to use it as a
|
||||
@ -347,6 +439,40 @@ xplr.fn.custom.render_layout = function(ctx)
|
||||
end
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```
|
||||
╭─────────────────────╮╭─────────────────────╮
|
||||
│Try your luck... ││Press ctrl-r │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
╰─────────────────────╯╰─────────────────────╯
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```
|
||||
╭────────────────────────────────────────────╮
|
||||
│Try your luck... │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰────────────────────────────────────────────╯
|
||||
╭────────────────────────────────────────────╮
|
||||
│Press ctrl-r │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰────────────────────────────────────────────╯
|
||||
```
|
||||
|
||||
## Panel UI Config
|
||||
|
||||
It contains the following optional fields:
|
||||
@ -429,8 +555,6 @@ Hence, only the following fields are available.
|
||||
[20]: #vertical_margin
|
||||
[21]: #constraints
|
||||
[22]: #constraint
|
||||
[23]: https://s6.gifyu.com/images/layout.png
|
||||
[24]: https://gifyu.com/image/1X38
|
||||
[25]: #static
|
||||
[26]: #dynamic
|
||||
[27]: #custom-panel
|
||||
|
@ -12,15 +12,13 @@ You can add new panels in `xplr.config.layouts.custom`.
|
||||
|
||||
##### Example: Defining Custom Layout
|
||||
|
||||
![demo](https://s6.gifyu.com/images/layout.png)
|
||||
|
||||
```lua
|
||||
xplr.config.layouts.builtin.default = {
|
||||
Horizontal = {
|
||||
config = {
|
||||
margin = 1,
|
||||
horizontal_margin = 2,
|
||||
vertical_margin = 3,
|
||||
horizontal_margin = 1,
|
||||
vertical_margin = 1,
|
||||
constraints = {
|
||||
{ Percentage = 50 },
|
||||
{ Percentage = 50 },
|
||||
@ -34,6 +32,21 @@ xplr.config.layouts.builtin.default = {
|
||||
}
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```
|
||||
╭ /home ─────────────╮╭ Help [default] ────╮
|
||||
│ ╭─── path ││. show hidden │
|
||||
│ ├▸[ð Desktop/] ││/ search │
|
||||
│ ├ ð Documents/ ││: action │
|
||||
│ ├ ð Downloads/ ││? global help │
|
||||
│ ├ ð GitHub/ ││G go to bottom │
|
||||
│ ├ ð Music/ ││V select/unselect│
|
||||
│ ├ ð Pictures/ ││ctrl duplicate as │
|
||||
│ ├ ð Public/ ││ctrl next visit │
|
||||
╰────────────────────╯╰────────────────────╯
|
||||
```
|
||||
|
||||
#### xplr.config.layouts.builtin.default
|
||||
|
||||
The default layout
|
||||
|
@ -29,23 +29,23 @@ them, but only a few modern programming languages allow nesting other types
|
||||
into a sum type.
|
||||
|
||||
```rust
|
||||
enum Result {
|
||||
Ok,
|
||||
Err,
|
||||
enum Color {
|
||||
Red,
|
||||
Green,
|
||||
}
|
||||
```
|
||||
|
||||
Here, `Result` can be one of two possible set of values: `Ok` and `Err`, just
|
||||
like `boolean`, but unlike `boolean`, being tagged allows `Result` to have more
|
||||
Here, `Color` can be one of two possible set of values: `Red` and `Green`, just
|
||||
like `boolean`, but unlike `boolean`, being tagged allows `Color` to have more
|
||||
than two variants if required, by changing the definition.
|
||||
|
||||
e.g.
|
||||
|
||||
```rust
|
||||
enum Result {
|
||||
Ok,
|
||||
Err,
|
||||
Pending,
|
||||
enum Color {
|
||||
Red,
|
||||
Green,
|
||||
Blue,
|
||||
}
|
||||
```
|
||||
|
||||
@ -53,35 +53,39 @@ We'd document it here as:
|
||||
|
||||
> Result is a sum type that can be one of the following:
|
||||
>
|
||||
> - "Ok"
|
||||
> - "Err"
|
||||
> - "Pending"
|
||||
> - "Red"
|
||||
> - "Green"
|
||||
> - "Blue"
|
||||
|
||||
But some languages (like Rust, Haskell, Elm etc.) go even further, allowing us
|
||||
to associate each branch of the enum with further nested types like:
|
||||
|
||||
```rust
|
||||
enum Result {
|
||||
Ok(bool),
|
||||
Err(Error),
|
||||
Pending,
|
||||
enum Layout {
|
||||
Table,
|
||||
HelpMenu,
|
||||
Horizontal {
|
||||
config: LayoutConfig, // A product type (similar to class/struct)
|
||||
splits: Vec<Layout> // A list of "Layout"s (i.e. list of sum types)
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Here, as we can see, unlike the first example, some of `Result`'s possible
|
||||
variants can have further nested types associated with them. Note that `Error`
|
||||
here can be either a sum type (e.g. enum), or a product type (e.g.
|
||||
class/struct), but whatever it is, it will only exist when `Result` is `Err`.
|
||||
Here, as we can see, unlike the first example, some of `Layout`'s possible
|
||||
variants can have further nested types associated with them. Note that
|
||||
`Horizontal` here can have a sum type (e.g. enum), or a product type (e.g.
|
||||
class/struct), or both (any number of them actually) nested in it. But the
|
||||
nested values will only exist when `Layout` is `Horizontal`.
|
||||
|
||||
We'd document it here as:
|
||||
|
||||
> Result is a sum type that can be one of the following:
|
||||
> Layout is a sum type that can be one of the following:
|
||||
>
|
||||
> - { Ok = bool }
|
||||
> - { Err = Error }
|
||||
> - "Pending"
|
||||
> - "Table"
|
||||
> - "HelpMenu"
|
||||
> - { Horizontal = { config = Layout Config, splits = { Layout, ... } }
|
||||
|
||||
And then we'd go on documenting whatever `Error` is.
|
||||
And then we'd go on documenting whatever `Layout Config` is.
|
||||
|
||||
So, there you go. This is exactly what sum types are - glorified enums that can
|
||||
have nested types in each branch.
|
||||
@ -89,7 +93,7 @@ have nested types in each branch.
|
||||
---
|
||||
|
||||
If you're still confused about something, or if you found an error in this
|
||||
explaination, feel free to [discuss together][5].
|
||||
explanation, feel free to [discuss together][5].
|
||||
|
||||
[1]: https://en.wikipedia.org/wiki/Tagged_union
|
||||
[2]: layout.md
|
||||
|
@ -45,7 +45,7 @@ compatibility.
|
||||
|
||||
### Instructions
|
||||
|
||||
#### [v0.20.2][48] -> [v0.21.2][49]
|
||||
#### [v0.20.2][48] -> [v0.21.3][49]
|
||||
|
||||
- Some plugins might stop rendering colors. Wait for them to update.
|
||||
- Rename `xplr.config.general.sort_and_filter_ui.search_identifier` to
|
||||
@ -81,7 +81,7 @@ compatibility.
|
||||
- `:ss` to create softlink of the selected items.
|
||||
- `:sh` to create hardlink of the selected items.
|
||||
- `:se` to edit selection list in your $EDITOR.
|
||||
- Better conflict handling: add suffix rather than overriding/skipping.
|
||||
- Better conflict handling: prompt for action.
|
||||
- Navigate between the selected paths using the following messages:
|
||||
- FocusPreviousSelection (`ctrl-p`)
|
||||
- FocusNextSelection (`ctrl-n`)
|
||||
@ -118,6 +118,7 @@ compatibility.
|
||||
- xplr.util.shell_escape
|
||||
- Executables will me marked with the mime type: `application/x-executable`.
|
||||
- macOS legacy coreutils will be generally supported, but please update it.
|
||||
- Since v0.21.2 you can use the on_selection_change hook.
|
||||
|
||||
Thanks to @noahmayr for contributing to a major part of this release.
|
||||
|
||||
@ -516,5 +517,5 @@ Else do the following:
|
||||
[46]: https://github.com/sayanarijit/xplr/releases/tag/v0.18.0
|
||||
[47]: https://github.com/sayanarijit/xplr/releases/tag/v0.19.4
|
||||
[48]: https://github.com/sayanarijit/xplr/releases/tag/v0.20.2
|
||||
[49]: https://github.com/sayanarijit/xplr/releases/tag/v0.21.2
|
||||
[49]: https://github.com/sayanarijit/xplr/releases/tag/v0.21.3
|
||||
[50]: https://github.com/lotabout/skim#search-syntax
|
||||
|
@ -151,7 +151,7 @@
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link page-scroll"
|
||||
href="https://xplr.stck.me"
|
||||
href="https://blog.xplr.dev"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
|
95
flake.lock
95
flake.lock
@ -1,97 +1,12 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1673956053,
|
||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"lowdown-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1633514407,
|
||||
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix": {
|
||||
"inputs": {
|
||||
"lowdown-src": "lowdown-src",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-regression": "nixpkgs-regression"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1676545802,
|
||||
"narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "relaxed-flakes",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1657693803,
|
||||
"narHash": "sha256-G++2CJ9u0E7NNTAi9n5G8TdDmGJXcIjkJ3NF8cetQB8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "365e1b3a859281cf11b94f87231adeabbdd878a2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-22.05-small",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-regression": {
|
||||
"locked": {
|
||||
"lastModified": 1643052045,
|
||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1684472219,
|
||||
"narHash": "sha256-cBTmj5Ad5pkU41GkyW/id7/A+s5FUlvj9jr3A35+lIE=",
|
||||
"lastModified": 1689422397,
|
||||
"narHash": "sha256-fnopownlSBGTBYxGdTdUPM215yG/UEEj3wgheBLIbHs=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9c82602247a58de900df71fdcc0cfdae2bf29189",
|
||||
"rev": "45ae0efbbce2aada6d5e8de6ace0c803b08ac9c7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -102,9 +17,7 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nix": "nix",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
37
flake.nix
37
flake.nix
@ -3,30 +3,26 @@
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs";
|
||||
nix.url = "github:domenkozar/nix/relaxed-flakes";
|
||||
flake-compat = {
|
||||
url = "github:edolstra/flake-compat";
|
||||
flake = false;
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, nix, ... }:
|
||||
outputs = inputs@{ self, nixpkgs, ... }:
|
||||
let
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"i686-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-linux"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
forAllSystems = f: builtins.listToAttrs (map (name: { inherit name; value = f name; }) systems);
|
||||
lib = nixpkgs.lib;
|
||||
|
||||
darwin = [ "x86_64-darwin" "aarch64-darwin" ];
|
||||
linux = [ "x86_64-linux" "x86_64-linux-musl" "aarch64-linux" "aarch64-linux-android" "i86_64-linux" ];
|
||||
allSystems = darwin ++ linux;
|
||||
|
||||
forEachSystem = systems: f: lib.genAttrs systems (system: f system);
|
||||
forAllSystems = forEachSystem allSystems;
|
||||
in
|
||||
{
|
||||
packages = forAllSystems (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
in
|
||||
{
|
||||
rec {
|
||||
# e.g. nix build .#xplr
|
||||
xplr = pkgs.rustPlatform.buildRustPackage rec {
|
||||
name = "xplr";
|
||||
src = ./.;
|
||||
@ -34,6 +30,14 @@
|
||||
lockFile = ./Cargo.lock;
|
||||
};
|
||||
};
|
||||
|
||||
# e.g. nix build .#cross.x86_64-linux-musl.xplr --impure
|
||||
cross = forEachSystem (lib.filter (sys: sys != system) allSystems) (targetSystem:
|
||||
let
|
||||
crossPkgs = import nixpkgs { localSystem = system; crossSystem = targetSystem; };
|
||||
in
|
||||
{ inherit (crossPkgs) xplr; }
|
||||
);
|
||||
}
|
||||
);
|
||||
defaultPackage = forAllSystems (system: self.packages.${system}.xplr);
|
||||
@ -54,6 +58,9 @@
|
||||
default = pkgs.mkShell {
|
||||
RUST_BACKTRACE = 1;
|
||||
|
||||
# For cross compilation
|
||||
NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM = 1;
|
||||
|
||||
buildInputs = devRequirements;
|
||||
packages = devRequirements;
|
||||
};
|
||||
|
26
src/app.rs
26
src/app.rs
@ -1034,19 +1034,23 @@ impl App {
|
||||
}
|
||||
|
||||
fn enter(self) -> Result<Self> {
|
||||
if let Some(path) = self.focused_node().map(|n| n.absolute_path.clone()) {
|
||||
self.change_directory(&path, true)
|
||||
if let Some(node) = self.focused_node() {
|
||||
if node.is_dir || node.symlink.as_ref().map(|s| s.is_dir).unwrap_or(false) {
|
||||
let path = node.absolute_path.clone();
|
||||
self.change_directory(&path, true)
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn back(self) -> Result<Self> {
|
||||
if let Some(p) = PathBuf::from(self.pwd.clone())
|
||||
.parent()
|
||||
.and_then(|p| p.to_str())
|
||||
{
|
||||
self.change_directory(p, true)
|
||||
let pwd = self.pwd.clone();
|
||||
if let Some(p) = PathBuf::from(&pwd).parent().and_then(|p| p.to_str()) {
|
||||
self.change_directory(p, false)
|
||||
.and_then(|a| a.focus_path(&pwd, true))
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
@ -1486,7 +1490,7 @@ impl App {
|
||||
|
||||
if dir.parent == self.pwd {
|
||||
self.directory_buffer = Some(dir);
|
||||
// Migh as well refresh the selection
|
||||
// Might as well refresh the selection
|
||||
self = self.refresh_selection()?;
|
||||
};
|
||||
|
||||
@ -2035,8 +2039,10 @@ impl App {
|
||||
let read_only = self.config.general.read_only;
|
||||
let global_kb = &self.config.general.global_key_bindings;
|
||||
|
||||
builtin.into_iter()
|
||||
.chain(custom.into_iter())
|
||||
let modes = builtin.into_iter().chain(custom.into_iter());
|
||||
|
||||
std::iter::once((self.mode.name.clone(), self.mode.clone()))
|
||||
.chain(modes)
|
||||
.map(|(name, mode)| {
|
||||
(name, mode.sanitized(read_only, global_kb.clone()))
|
||||
})
|
||||
|
@ -206,12 +206,10 @@ pub fn print_msg_in(args: Vec<String>) -> Result<()> {
|
||||
fn fmt_msg_in(args: Vec<String>) -> Result<String> {
|
||||
let msg = match jf::format(args.into_iter().map(Into::into)) {
|
||||
Ok(msg) => msg,
|
||||
Err(jf::Error::Usage) => {
|
||||
bail!("usage: xplr -m TEMPLATE [VALUE]... [NAME=VALUE]...")
|
||||
}
|
||||
Err(jf::Error::Jf(e)) => bail!("xplr -m: {e}"),
|
||||
Err(jf::Error::Json(e)) => bail!("xplr -m: json: {e}"),
|
||||
Err(jf::Error::Yaml(e)) => bail!("xplr -m: yaml: {e}"),
|
||||
Err(jf::Error::Io(e)) => bail!("xplr -m: io: {e}"),
|
||||
};
|
||||
|
||||
// validate
|
||||
|
68
src/init.lua
68
src/init.lua
@ -680,11 +680,15 @@ xplr.config.general.initial_sorting = {
|
||||
}
|
||||
|
||||
-- The name of one of the modes to use when xplr loads.
|
||||
-- This isn't the default mode. To modify the default mode, overwrite
|
||||
-- [xplr.config.modes.builtin.default](https://xplr.dev/en/modes#xplrconfigmodesbuiltindefault).
|
||||
--
|
||||
-- Type: nullable string
|
||||
xplr.config.general.initial_mode = "default"
|
||||
|
||||
-- The name of one of the layouts to use when xplr loads.
|
||||
-- This isn't the default layout. To modify the default layout, overwrite
|
||||
-- [xplr.config.layouts.builtin.default](https://xplr.dev/en/layouts#xplrconfiglayoutsbuiltindefault).
|
||||
--
|
||||
-- Type: nullable string
|
||||
xplr.config.general.initial_layout = "default"
|
||||
@ -701,6 +705,17 @@ xplr.config.general.start_fifo = nil
|
||||
-- Type: [Key Bindings](https://xplr.dev/en/configure-key-bindings#key-bindings)
|
||||
xplr.config.general.global_key_bindings = {
|
||||
on_key = {
|
||||
["f1"] = {
|
||||
help = "global help menu",
|
||||
messages = {
|
||||
{
|
||||
BashExec = [===[
|
||||
[ -z "$PAGER" ] && PAGER="less -+F"
|
||||
cat -- "${XPLR_PIPE_GLOBAL_HELP_MENU_OUT}" | ${PAGER:?}
|
||||
]===],
|
||||
},
|
||||
},
|
||||
},
|
||||
["esc"] = {
|
||||
messages = {
|
||||
"PopMode",
|
||||
@ -852,15 +867,13 @@ xplr.config.node_types.special = {}
|
||||
--
|
||||
-- ##### Example: Defining Custom Layout
|
||||
--
|
||||
-- ![demo](https://s6.gifyu.com/images/layout.png)
|
||||
--
|
||||
-- ```lua
|
||||
-- xplr.config.layouts.builtin.default = {
|
||||
-- Horizontal = {
|
||||
-- config = {
|
||||
-- margin = 1,
|
||||
-- horizontal_margin = 2,
|
||||
-- vertical_margin = 3,
|
||||
-- horizontal_margin = 1,
|
||||
-- vertical_margin = 1,
|
||||
-- constraints = {
|
||||
-- { Percentage = 50 },
|
||||
-- { Percentage = 50 },
|
||||
@ -873,6 +886,21 @@ xplr.config.node_types.special = {}
|
||||
-- }
|
||||
-- }
|
||||
-- ```
|
||||
--
|
||||
-- Result:
|
||||
--
|
||||
-- ```
|
||||
-- ╭ /home ─────────────╮╭ Help [default] ────╮
|
||||
-- │ ╭─── path ││. show hidden │
|
||||
-- │ ├▸[ð Desktop/] ││/ search │
|
||||
-- │ ├ ð Documents/ ││: action │
|
||||
-- │ ├ ð Downloads/ ││? global help │
|
||||
-- │ ├ ð GitHub/ ││G go to bottom │
|
||||
-- │ ├ ð Music/ ││V select/unselect│
|
||||
-- │ ├ ð Pictures/ ││ctrl duplicate as │
|
||||
-- │ ├ ð Public/ ││ctrl next visit │
|
||||
-- ╰────────────────────╯╰────────────────────╯
|
||||
-- ```
|
||||
|
||||
-- The default layout
|
||||
--
|
||||
@ -1062,17 +1090,6 @@ xplr.config.modes.builtin.default = {
|
||||
{ SwitchModeBuiltin = "action" },
|
||||
},
|
||||
},
|
||||
["?"] = {
|
||||
help = "global help menu",
|
||||
messages = {
|
||||
{
|
||||
BashExec = [===[
|
||||
[ -z "$PAGER" ] && PAGER="less -+F"
|
||||
cat -- "${XPLR_PIPE_GLOBAL_HELP_MENU_OUT}" | ${PAGER:?}
|
||||
]===],
|
||||
},
|
||||
},
|
||||
},
|
||||
["G"] = {
|
||||
help = "go to bottom",
|
||||
messages = {
|
||||
@ -1295,6 +1312,8 @@ xplr.config.modes.builtin.default.key_bindings.on_key["l"] =
|
||||
xplr.config.modes.builtin.default.key_bindings.on_key["right"]
|
||||
xplr.config.modes.builtin.default.key_bindings.on_key["tab"] =
|
||||
xplr.config.modes.builtin.default.key_bindings.on_key["ctrl-i"] -- compatibility workaround
|
||||
xplr.config.modes.builtin.default.key_bindings.on_key["?"] =
|
||||
xplr.config.general.global_key_bindings.on_key["f1"]
|
||||
|
||||
-- The builtin debug error mode.
|
||||
--
|
||||
@ -1978,7 +1997,9 @@ xplr.config.modes.builtin.delete = {
|
||||
messages = {
|
||||
{
|
||||
BashExec0 = [===[
|
||||
cat "${XPLR_PIPE_RESULT_OUT:?}" | xargs -0 printf '%q\n'
|
||||
while IFS= read -r -d '' PTH; do
|
||||
printf '%q\n' "$PTH"
|
||||
done < "${XPLR_PIPE_RESULT_OUT:?}"
|
||||
echo
|
||||
read -p "Permanently delete these files? [Y/n]: " ANS
|
||||
[ "${ANS:-Y}" = "Y" ] || [ "$ANS" = "y" ] || exit 0
|
||||
@ -2006,7 +2027,9 @@ xplr.config.modes.builtin.delete = {
|
||||
messages = {
|
||||
{
|
||||
BashExec0 = [===[
|
||||
cat "${XPLR_PIPE_RESULT_OUT:?}" | xargs -0 printf '%q\n'
|
||||
while IFS= read -r -d '' PTH; do
|
||||
printf '%q\n' "$PTH"
|
||||
done < "${XPLR_PIPE_RESULT_OUT:?}"
|
||||
echo
|
||||
read -p "Permanently delete these files? [Y/n]: " ANS
|
||||
[ "${ANS:-Y}" = "Y" ] || [ "$ANS" = "y" ] || exit 0
|
||||
@ -2967,7 +2990,8 @@ xplr.fn.builtin.fmt_general_table_row_cols_1 = function(m)
|
||||
if m.is_broken then
|
||||
r = r .. "×"
|
||||
else
|
||||
local symlink_path = xplr.util.shorten(m.symlink.absolute_path)
|
||||
local symlink_path =
|
||||
xplr.util.shorten(m.symlink.absolute_path, { base = m.parent })
|
||||
if m.symlink.is_dir then
|
||||
symlink_path = symlink_path .. "/"
|
||||
end
|
||||
@ -3076,6 +3100,14 @@ xplr.fn.custom = {}
|
||||
-- { LogSuccess = "Switched layout" },
|
||||
-- { CallLuaSilently = "custom.some_plugin_with_hooks.on_layout_switch" },
|
||||
-- }
|
||||
--
|
||||
-- -- Add messages to send when the selection changes
|
||||
-- --
|
||||
-- -- Type: list of [Message](https://xplr.dev/en/message#message)s
|
||||
-- on_selection_change = {
|
||||
-- { LogSuccess = "Selection changed" },
|
||||
-- { CallLuaSilently = "custom.some_plugin_with_hooks.on_selection_change" },
|
||||
-- }
|
||||
-- }
|
||||
-- ```
|
||||
|
||||
|
@ -160,24 +160,24 @@ mod tests {
|
||||
assert!(check_version(VERSION, "foo path").is_ok());
|
||||
|
||||
// Current release if OK
|
||||
assert!(check_version("0.21.2", "foo path").is_ok());
|
||||
assert!(check_version("0.21.3", "foo path").is_ok());
|
||||
|
||||
// Prev major release is ERR
|
||||
// - Not yet
|
||||
|
||||
// Prev minor release is ERR (Change when we get to v1)
|
||||
assert!(check_version("0.20.2", "foo path").is_err());
|
||||
assert!(check_version("0.20.3", "foo path").is_err());
|
||||
|
||||
// Prev bugfix release is OK
|
||||
assert!(check_version("0.21.1", "foo path").is_ok());
|
||||
assert!(check_version("0.21.2", "foo path").is_ok());
|
||||
|
||||
// Next major release is ERR
|
||||
assert!(check_version("1.20.2", "foo path").is_err());
|
||||
assert!(check_version("1.20.3", "foo path").is_err());
|
||||
|
||||
// Next minor release is ERR
|
||||
assert!(check_version("0.22.2", "foo path").is_err());
|
||||
assert!(check_version("0.22.3", "foo path").is_err());
|
||||
|
||||
// Next bugfix release is ERR (Change when we get to v1)
|
||||
assert!(check_version("0.21.3", "foo path").is_err());
|
||||
assert!(check_version("0.21.4", "foo path").is_err());
|
||||
}
|
||||
}
|
||||
|
17
src/path.rs
17
src/path.rs
@ -216,17 +216,20 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_relative_to_parent() {
|
||||
let path = std::env::current_dir().unwrap();
|
||||
let path = std::env::current_dir().unwrap().join("docs");
|
||||
let parent = path.parent().unwrap();
|
||||
|
||||
let relative = relative_to(parent, NONE).unwrap();
|
||||
assert_eq!(relative, PathBuf::from(".."));
|
||||
let base = default().with_base(path.to_str().unwrap());
|
||||
|
||||
let relative = relative_to(parent, Some(&default().with_prefix_dots())).unwrap();
|
||||
let relative = relative_to(parent, Some(&base)).unwrap();
|
||||
assert_eq!(relative, PathBuf::from(".."));
|
||||
|
||||
let relative =
|
||||
relative_to(parent, Some(&default().without_suffix_dots())).unwrap();
|
||||
relative_to(parent, Some(&base.clone().with_prefix_dots())).unwrap();
|
||||
assert_eq!(relative, PathBuf::from(".."));
|
||||
|
||||
let relative =
|
||||
relative_to(parent, Some(&base.clone().without_suffix_dots())).unwrap();
|
||||
assert_eq!(
|
||||
relative,
|
||||
PathBuf::from("../..").join(parent.file_name().unwrap())
|
||||
@ -234,12 +237,12 @@ mod tests {
|
||||
|
||||
let relative = relative_to(
|
||||
parent,
|
||||
Some(&default().with_prefix_dots().without_suffix_dots()),
|
||||
Some(&base.clone().with_prefix_dots().without_suffix_dots()),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
relative,
|
||||
PathBuf::from("../..").join(parent.file_name().unwrap())
|
||||
PathBuf::from("../..").join(parent.clone().file_name().unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -40,15 +40,14 @@ pub fn get_tty() -> Result<fs::File> {
|
||||
// returns physical path. As a workaround, this function tries to use `PWD`
|
||||
// environment variable that is configured by shell.
|
||||
fn get_current_dir() -> Result<PathBuf, std::io::Error> {
|
||||
let cur = std::env::current_dir();
|
||||
if let Ok(pwd) = std::env::var("PWD") {
|
||||
if pwd.is_empty() {
|
||||
cur
|
||||
std::env::current_dir()
|
||||
} else {
|
||||
Ok(PathBuf::from(pwd))
|
||||
}
|
||||
} else {
|
||||
cur
|
||||
std::env::current_dir()
|
||||
}
|
||||
}
|
||||
|
||||
|
60
src/ui.rs
60
src/ui.rs
@ -20,7 +20,7 @@ use tui::backend::Backend;
|
||||
use tui::layout::Rect as TuiRect;
|
||||
use tui::layout::{Constraint as TuiConstraint, Direction, Layout as TuiLayout};
|
||||
use tui::style::{Color, Modifier as TuiModifier, Style as TuiStyle};
|
||||
use tui::text::{Span, Spans, Text};
|
||||
use tui::text::{Line, Span, Text};
|
||||
use tui::widgets::{
|
||||
Block, BorderType as TuiBorderType, Borders as TuiBorders, Cell, List, ListItem,
|
||||
Paragraph, Row, Table,
|
||||
@ -329,6 +329,7 @@ impl Into<TuiStyle> for Style {
|
||||
TuiStyle {
|
||||
fg: self.fg,
|
||||
bg: self.bg,
|
||||
underline_color: None,
|
||||
add_modifier: TuiModifier::from_bits_truncate(xor(self.add_modifiers)),
|
||||
sub_modifier: TuiModifier::from_bits_truncate(xor(self.sub_modifiers)),
|
||||
}
|
||||
@ -401,22 +402,22 @@ impl Into<nu_ansi_term::Style> for Style {
|
||||
style.add_modifiers.as_ref().map_or(false, f)
|
||||
}
|
||||
|
||||
nu_ansi_term::Style {
|
||||
foreground: self.fg.and_then(convert_color),
|
||||
background: self.bg.and_then(convert_color),
|
||||
is_bold: match_modifiers(&self, |m| m.contains(&Modifier::Bold)),
|
||||
is_dimmed: match_modifiers(&self, |m| m.contains(&Modifier::Dim)),
|
||||
is_italic: match_modifiers(&self, |m| m.contains(&Modifier::Italic)),
|
||||
is_underline: match_modifiers(&self, |m| m.contains(&Modifier::Underlined)),
|
||||
is_blink: match_modifiers(&self, |m| {
|
||||
m.contains(&Modifier::SlowBlink) || m.contains(&Modifier::RapidBlink)
|
||||
}),
|
||||
is_reverse: match_modifiers(&self, |m| m.contains(&Modifier::Reversed)),
|
||||
is_hidden: match_modifiers(&self, |m| m.contains(&Modifier::Hidden)),
|
||||
is_strikethrough: match_modifiers(&self, |m| {
|
||||
m.contains(&Modifier::CrossedOut)
|
||||
}),
|
||||
}
|
||||
let mut style = nu_ansi_term::Style::new();
|
||||
style.foreground = self.fg.and_then(convert_color);
|
||||
style.background = self.bg.and_then(convert_color);
|
||||
style.is_bold = match_modifiers(&self, |m| m.contains(&Modifier::Bold));
|
||||
style.is_dimmed = match_modifiers(&self, |m| m.contains(&Modifier::Dim));
|
||||
style.is_italic = match_modifiers(&self, |m| m.contains(&Modifier::Italic));
|
||||
style.is_underline =
|
||||
match_modifiers(&self, |m| m.contains(&Modifier::Underlined));
|
||||
style.is_blink = match_modifiers(&self, |m| {
|
||||
m.contains(&Modifier::SlowBlink) || m.contains(&Modifier::RapidBlink)
|
||||
});
|
||||
style.is_reverse = match_modifiers(&self, |m| m.contains(&Modifier::Reversed));
|
||||
style.is_hidden = match_modifiers(&self, |m| m.contains(&Modifier::Hidden));
|
||||
style.is_strikethrough =
|
||||
match_modifiers(&self, |m| m.contains(&Modifier::CrossedOut));
|
||||
style
|
||||
}
|
||||
}
|
||||
|
||||
@ -669,6 +670,7 @@ fn draw_table<B: Backend>(
|
||||
let header_height = app_config.general.table.header.height.unwrap_or(1);
|
||||
let height: usize =
|
||||
(layout_size.height.max(header_height + 2) - (header_height + 2)).into();
|
||||
let row_style = app_config.general.table.row.style.to_owned();
|
||||
|
||||
let rows = app
|
||||
.directory_buffer
|
||||
@ -767,17 +769,17 @@ fn draw_table<B: Backend>(
|
||||
c.format.as_ref().map(|f| {
|
||||
let out = lua::call(lua, f, v.clone())
|
||||
.unwrap_or_else(|e| format!("{e:?}"));
|
||||
string_to_text(out)
|
||||
(string_to_text(out), c.style.to_owned())
|
||||
})
|
||||
})
|
||||
.collect::<Vec<Text>>()
|
||||
.collect::<Vec<(Text, Style)>>()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.map(|x| Cell::from(x.to_owned()))
|
||||
.into_iter()
|
||||
.map(|(text, style)| Cell::from(text).style(style.into()))
|
||||
.collect::<Vec<Cell>>();
|
||||
|
||||
Row::new(cols)
|
||||
Row::new(cols).style(row_style.to_owned().into())
|
||||
})
|
||||
.collect::<Vec<Row>>()
|
||||
})
|
||||
@ -831,7 +833,10 @@ fn draw_table<B: Backend>(
|
||||
.to_owned()
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.map(|c| Cell::from(c.format.to_owned().unwrap_or_default()))
|
||||
.map(|c| {
|
||||
Cell::from(c.format.to_owned().unwrap_or_default())
|
||||
.style(c.style.to_owned().into())
|
||||
})
|
||||
.collect::<Vec<Cell>>(),
|
||||
)
|
||||
.height(header_height)
|
||||
@ -878,7 +883,10 @@ fn draw_selection<B: Backend>(
|
||||
.unwrap_or_else(|| n.absolute_path.clone());
|
||||
string_to_text(out)
|
||||
})
|
||||
.map(ListItem::new)
|
||||
.map(|i| {
|
||||
ListItem::new(i)
|
||||
.style(app.config.general.selection.item.style.to_owned().into())
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Selected items
|
||||
@ -973,7 +981,7 @@ fn draw_input_buffer<B: Backend>(
|
||||
let width = layout_size.width.max(offset_width) - offset_width;
|
||||
let scroll = input.visual_scroll(width.into()) as u16;
|
||||
|
||||
let input_buf = Paragraph::new(Spans::from(vec![
|
||||
let input_buf = Paragraph::new(Line::from(vec![
|
||||
Span::styled(
|
||||
app.input.prompt.to_owned(),
|
||||
app.config.general.prompt.style.to_owned().into(),
|
||||
@ -1114,7 +1122,7 @@ fn draw_sort_n_filter<B: Backend>(
|
||||
format!("({item_count}) ")
|
||||
};
|
||||
|
||||
let p = Paragraph::new(Spans::from(spans))
|
||||
let p = Paragraph::new(Line::from(spans))
|
||||
.block(block(config, format!(" Sort & filter {item_count}")));
|
||||
|
||||
f.render_widget(p, layout_size);
|
||||
|
Loading…
Reference in New Issue
Block a user