mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-23 15:51:03 +00:00
Merge remote-tracking branch 'upstream/main' into improve-rg-search
This commit is contained in:
commit
963b277dbd
623 changed files with 8017 additions and 6527 deletions
6
.github/DISCUSSION_TEMPLATE/1-q-a.yml
vendored
6
.github/DISCUSSION_TEMPLATE/1-q-a.yml
vendored
|
|
@ -22,10 +22,10 @@ body:
|
|||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: debug
|
||||
id: env
|
||||
attributes:
|
||||
label: "`yazi --debug` output"
|
||||
description: Please run `yazi --debug` and paste the debug information here.
|
||||
label: "`ya env` output"
|
||||
description: Run `ya env` and paste the environment information here.
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
|
|
|
|||
8
.github/ISSUE_TEMPLATE/bug.yml
vendored
8
.github/ISSUE_TEMPLATE/bug.yml
vendored
|
|
@ -26,10 +26,10 @@ body:
|
|||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: debug
|
||||
id: env
|
||||
attributes:
|
||||
label: "`yazi --debug` output"
|
||||
description: Please run `yazi --debug` and paste the debug information here.
|
||||
label: "`ya env` output"
|
||||
description: Run `ya env` and paste the environment information here.
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
|
|
@ -65,6 +65,6 @@ body:
|
|||
options:
|
||||
- label: I tried the [latest nightly build](https://yazi-rs.github.io/docs/installation#binaries), and the issue is still reproducible
|
||||
required: true
|
||||
- label: I updated the debug information (`yazi --debug`) input box to the nightly that I tried
|
||||
- label: I updated the environment information (`ya env`) field to the nightly that I tried
|
||||
required: true
|
||||
- label: I can reproduce it after disabling all custom configs/plugins (`mv ~/.config/yazi ~/.config/yazi-backup`)
|
||||
|
|
|
|||
6
.github/ISSUE_TEMPLATE/feature.yml
vendored
6
.github/ISSUE_TEMPLATE/feature.yml
vendored
|
|
@ -4,10 +4,10 @@ labels: [feature]
|
|||
assignees: []
|
||||
body:
|
||||
- type: textarea
|
||||
id: debug
|
||||
id: env
|
||||
attributes:
|
||||
label: "`yazi --debug` output"
|
||||
description: Please run `yazi --debug` and paste the debug information here.
|
||||
label: "`ya env` output"
|
||||
description: Run `ya env` and paste the environment information here.
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
|
|
|
|||
4
.github/pull_request_template.md
vendored
4
.github/pull_request_template.md
vendored
|
|
@ -15,3 +15,7 @@ A clear and concise description of the rationale of the changes, to help our rev
|
|||
|
||||
If it has already been detailed in the associated issue, please skip this section.
|
||||
-->
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] I have read [CONTRIBUTING.md](https://github.com/sxyazi/yazi/blob/main/CONTRIBUTING.md)
|
||||
|
|
|
|||
28
CHANGELOG.md
28
CHANGELOG.md
|
|
@ -14,14 +14,33 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
|
|||
|
||||
### Added
|
||||
|
||||
- Drag and drop ([#4005])
|
||||
- Bulk create ([#3793])
|
||||
- Dynamic keymap Lua API ([#4031])
|
||||
- New `ui.Input` element ([#4040])
|
||||
- Image preview with Überzug++ on Niri ([#3990])
|
||||
- New gait for input `backward` and `forward` actions ([#4012])
|
||||
|
||||
### Changed
|
||||
|
||||
- Rename `<BackTab>` to `<S-Tab>` ([#3989])
|
||||
- Remove Legacy Console Mode on Windows ([#3989])
|
||||
|
||||
### Deprecated
|
||||
|
||||
- Deprecate `backward --far` and `forward --far` in favor of `backward wide` and `forward wide`, respectively ([#4012])
|
||||
|
||||
### Fixed
|
||||
|
||||
- Normalize `\\?\`-prefixed Verbatim paths when creating relative symlinks on Windows ([#4067])
|
||||
- Keep package hashes indifferent to line endings when `ya pkg` pulls packages ([#4064])
|
||||
- Use WebP as `magick` preset preloader cache format to keep image transparency ([#4065])
|
||||
- Use cleaned and normalized `$PWD` as startup CWD to avoid MSYS2/git-bash path quirks ([#4068])
|
||||
|
||||
### Improved
|
||||
|
||||
- Eliminate hacks in image and UI conflict resolution ([#4022])
|
||||
|
||||
## [v26.5.6]
|
||||
|
||||
### Added
|
||||
|
|
@ -1729,3 +1748,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
|
|||
[#3943]: https://github.com/sxyazi/yazi/pull/3943
|
||||
[#3989]: https://github.com/sxyazi/yazi/pull/3989
|
||||
[#3990]: https://github.com/sxyazi/yazi/pull/3990
|
||||
[#4005]: https://github.com/sxyazi/yazi/pull/4005
|
||||
[#4012]: https://github.com/sxyazi/yazi/pull/4012
|
||||
[#4022]: https://github.com/sxyazi/yazi/pull/4022
|
||||
[#4031]: https://github.com/sxyazi/yazi/pull/4031
|
||||
[#4040]: https://github.com/sxyazi/yazi/pull/4040
|
||||
[#4064]: https://github.com/sxyazi/yazi/pull/4064
|
||||
[#4065]: https://github.com/sxyazi/yazi/pull/4065
|
||||
[#4067]: https://github.com/sxyazi/yazi/pull/4067
|
||||
[#4068]: https://github.com/sxyazi/yazi/pull/4068
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ This guide will help you understand how to contribute to the project.
|
|||
3. [Development Setup](#development-setup)
|
||||
4. [How to Contribute](#how-to-contribute)
|
||||
5. [Pull Requests](#pull-requests)
|
||||
6. [AI Policy](#ai-policy)
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
|
@ -164,3 +165,10 @@ We want you to succeed, and it can be discouraging to find that a lot of re-work
|
|||
- Your code passes all tests and lints.
|
||||
- Your pull request description clearly explains the changes and why they are needed.
|
||||
4. Address any review comments. Make sure to push updates to the same branch on your fork.
|
||||
|
||||
## AI Policy
|
||||
|
||||
1. All issue, PR, and discussion descriptions must be written by humans, not AI.
|
||||
2. Any use of AI must be disclosed. You must declare which model you used and the extent of AI assistance.
|
||||
3. Any AI-generated code must be reviewed, tested, and simplified by a human before publishing. This requires you to fully understand how it interacts with the greater system without AI assistance.
|
||||
4. Any AI tools used must explicitly state they do not assert copyright over the work.
|
||||
|
|
|
|||
1763
Cargo.lock
generated
1763
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
15
Cargo.toml
15
Cargo.toml
|
|
@ -39,8 +39,8 @@ ansi-to-tui = "8.0.1"
|
|||
anyhow = "1.0.102"
|
||||
arc-swap = { version = "1.9.1", features = [ "serde" ] }
|
||||
base64 = "0.22.1"
|
||||
bitflags = { version = "2.11.1", features = [ "serde" ] }
|
||||
chrono = "0.4.44"
|
||||
bitflags = { version = "2.13.0", features = [ "serde" ] }
|
||||
chrono = "0.4.45"
|
||||
clap = { version = "4.6.1", features = [ "derive" ] }
|
||||
core-foundation-sys = "0.8.7"
|
||||
dirs = "6.0.0"
|
||||
|
|
@ -50,7 +50,9 @@ foldhash = "0.2.0"
|
|||
futures = "0.3.32"
|
||||
globset = "0.4.18"
|
||||
hashbrown = { version = "0.17.1", features = [ "serde" ] }
|
||||
image = { version = "0.25.10", default-features = false, features = [ "avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp" ] }
|
||||
indexmap = { version = "2.14.0", features = [ "serde" ] }
|
||||
inventory = "0.3.24"
|
||||
libc = "0.2.186"
|
||||
lru = "0.18.0"
|
||||
mlua = { version = "0.11.6", features = [ "anyhow", "async", "error-send", "lua55", "macros", "serde" ] }
|
||||
|
|
@ -60,13 +62,14 @@ parking_lot = "0.12.5"
|
|||
paste = "1.0.15"
|
||||
percent-encoding = "2.3.2"
|
||||
rand = { version = "0.10.1", default-features = false, features = [ "std", "sys_rng" ] }
|
||||
ratatui = { version = "0.30.0", default-features = false, features = [ "layout-cache", "serde", "underline-color", "unstable-rendered-line-info", "unstable-widget-ref" ] }
|
||||
regex = "1.12.3"
|
||||
russh = { version = "0.61.0", default-features = false, features = [ "ring", "rsa" ] }
|
||||
ratatui-core = { version = "0.1.2", default-features = false, features = [ "std", "layout-cache", "serde", "underline-color" ] }
|
||||
ratatui-widgets = { version = "0.3.2", default-features = false, features = [ "std", "unstable-rendered-line-info" ] }
|
||||
regex = "1.12.4"
|
||||
russh = { version = "0.61.2", default-features = false, features = [ "ring", "rsa" ] }
|
||||
scopeguard = "1.2.0"
|
||||
serde = { version = "1.0.228", features = [ "derive" ] }
|
||||
serde_json = "1.0.150"
|
||||
serde_with = "3.20.0"
|
||||
serde_with = "3.21.0"
|
||||
strum = { version = "0.28.0", features = [ "derive" ] }
|
||||
syntect = { version = "5.3.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||
thiserror = "2.0.18"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ Yazi (means "duck") is a terminal file manager written in Rust, based on non-blo
|
|||
- 💫 Vim-like input/pick/confirm/which/notify component, auto-completion for cd paths
|
||||
- 🏷️ Multi-Tab Support, Cross-directory selection, Scrollable Preview (for videos, PDFs, archives, code, directories, etc.)
|
||||
- 🔄 Bulk Rename/Create, Archive Extraction, Visual Mode, File Chooser, [Git Integration](https://github.com/yazi-rs/plugins/tree/main/git.yazi), [Mount Manager](https://github.com/yazi-rs/plugins/tree/main/mount.yazi)
|
||||
- 🎨 Theme System, Mouse Support, Trash Bin, Custom Layouts, CSI u, OSC 52
|
||||
- 🎨 Theme System, Mouse Support, Drag and Drop, Trash Bin, Custom Layouts, CSI u, OSC 52
|
||||
- ... and more!
|
||||
|
||||
https://github.com/sxyazi/yazi/assets/17523360/92ff23fa-0cd5-4f04-b387-894c12265cc7
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","peekable","ratatui","syntect","pbpaste","pbcopy","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","Konsole","Überzug","pkgs","pdftoppm","poppler","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","ffprobe","vframes","luma","obase","outln","errln","tmtheme","twox","cfgs","fstype","objc","rdev","runloop","exfat","rclone","DECRQSS","DECSCUSR","libvterm","Uninit","lockin","rposition","resvg","foldhash","tilded","futs","chdir","hashbrown","JEMALLOC","RUSTFLAGS","RDONLY","GETPATH","fcntl","casefold","inodes","Splatable","casefied","thiserror","memchr","memmem","russh","deadpool","keepalive","nodelay","publickey","deadpool","initing","treelize","TOCTOU","fellback","watchee","Textlike","sstr","pointee","writef","wakeup","nonblocking","sigwinch","timespec","termios","tcgetattr","tcsetattr","tcgetwinsize","rustix","codepoint","codepoints","Raterm"],"version":"0.2","flagWords":[]}
|
||||
{"flagWords":[],"version":"0.2","language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","peekable","ratatui","syntect","pbpaste","pbcopy","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","Konsole","Überzug","pkgs","pdftoppm","poppler","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","ffprobe","vframes","luma","obase","outln","errln","tmtheme","twox","cfgs","fstype","objc","rdev","runloop","exfat","rclone","DECRQSS","DECSCUSR","libvterm","Uninit","lockin","rposition","resvg","foldhash","tilded","futs","chdir","hashbrown","JEMALLOC","RUSTFLAGS","RDONLY","GETPATH","fcntl","casefold","inodes","Splatable","casefied","thiserror","memchr","memmem","russh","deadpool","keepalive","nodelay","publickey","deadpool","initing","treelize","TOCTOU","fellback","watchee","Textlike","sstr","pointee","writef","wakeup","nonblocking","sigwinch","timespec","termios","tcgetattr","tcsetattr","tcgetwinsize","rustix","codepoint","codepoints","Raterm","mimetypes","Mimelist","renderables","redrawer","Padable"]}
|
||||
12
flake.lock
generated
12
flake.lock
generated
|
|
@ -20,11 +20,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1776329215,
|
||||
"narHash": "sha256-a8BYi3mzoJ/AcJP8UldOx8emoPRLeWqALZWu4ZvjPXw=",
|
||||
"lastModified": 1779877693,
|
||||
"narHash": "sha256-NOF9NAREhxr50bbBfVcVOq+ArCMSoe8dP79Pk2uyARk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b86751bc4085f48661017fa226dee99fab6c651b",
|
||||
"rev": "4100e830e085863741bc69b156ec4ccd53ab5be0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -48,11 +48,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1776741231,
|
||||
"narHash": "sha256-k9G98qzn+7npROUaks8VqCFm7cFtEG8ulQLBBo5lItg=",
|
||||
"lastModified": 1779851998,
|
||||
"narHash": "sha256-UkkMh3bX9QW4Luqkm98nUaOqKWrU6i65mUnph3WeSSw=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "02061303f7c4c964f7b4584dabd9e985b4cd442b",
|
||||
"rev": "6cddd512fa2bf7231f098d3a2f92f6e4cff71e0a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
|||
|
||||
cargoLock = {
|
||||
lockFile = "${src}/Cargo.lock";
|
||||
#outputHashes = {
|
||||
# "mlua-0.10.0" = "sha256-Xg6/jc+UP8tbJJ6x1sbAgt8ZHt051xEBBcjmikQqYlw=";
|
||||
#};
|
||||
};
|
||||
|
||||
env = {
|
||||
|
|
@ -54,6 +51,11 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
|||
--fish ./yazi-boot/completions/yazi.fish \
|
||||
--zsh ./yazi-boot/completions/_yazi
|
||||
|
||||
installShellCompletion --cmd ya \
|
||||
--bash ./yazi-cli/completions/ya.bash \
|
||||
--fish ./yazi-cli/completions/ya.fish \
|
||||
--zsh ./yazi-cli/completions/_ya
|
||||
|
||||
# Resize logo
|
||||
for RES in 16 24 32 48 64 128 256; do
|
||||
mkdir -p $out/share/icons/hicolor/"$RES"x"$RES"/apps
|
||||
|
|
@ -75,7 +77,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
|||
hash = "sha256-kEVXejDg4ChFoMNBvKlwdFEyUuTcY2VuK9j0PdafKus=";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
meta = {
|
||||
description = "Blazing fast terminal file manager written in Rust, based on async I/O";
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ function bugReportBody(creator, content, hash) {
|
|||
I noticed that you did not correctly follow the issue template. Please ensure that:
|
||||
|
||||
- The bug can still be reproduced on the [newest nightly build](https://yazi-rs.github.io/docs/installation/#binaries).
|
||||
- The debug information (\`yazi --debug\`) is updated for the newest nightly.
|
||||
- The environment info (\`ya env\`) is updated for the newest nightly.
|
||||
- The non-optional items in the checklist are checked.
|
||||
|
||||
Issues with \`${LABEL_NAME}\` will be marked ready once edited with the proper content, or closed after 2 days of inactivity.
|
||||
|
|
@ -32,7 +32,7 @@ function featureRequestBody(creator, content) {
|
|||
I noticed that you did not correctly follow the issue template. Please ensure that:
|
||||
|
||||
- The requested feature does not exist in the [newest nightly build](https://yazi-rs.github.io/docs/installation/#binaries).
|
||||
- The debug information (\`yazi --debug\`) is updated for the newest nightly.
|
||||
- The environment info (\`ya env\`) is updated for the newest nightly.
|
||||
- The non-optional items in the checklist are checked.
|
||||
|
||||
Issues with \`${LABEL_NAME}\` will be marked ready once edited with the proper content, or closed after 2 days of inactivity.
|
||||
|
|
|
|||
6
scripts/validate-form/package-lock.json
generated
6
scripts/validate-form/package-lock.json
generated
|
|
@ -238,9 +238,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.25.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.25.0.tgz",
|
||||
"integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==",
|
||||
"version": "6.27.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz",
|
||||
"integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.17"
|
||||
|
|
|
|||
|
|
@ -133,9 +133,16 @@ parts:
|
|||
- --prefix=/usr
|
||||
build-attributes:
|
||||
- enable-patchelf
|
||||
organize:
|
||||
# `libgomp1` installs libgomp into the multiarch directory, but the
|
||||
# `magick` binary's RPATH only searches `$ORIGIN/../lib` (i.e. usr/lib).
|
||||
# Move it alongside the Magick libraries so the bundled binary can load
|
||||
# it at runtime; otherwise magick fails with:
|
||||
# "libgomp.so.1: cannot open shared object file: No such file or directory"
|
||||
usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libgomp.so*: usr/lib/
|
||||
prime:
|
||||
- usr/bin/magick
|
||||
- usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libgomp.so.1
|
||||
- usr/lib/libgomp.so*
|
||||
- usr/lib/libMagickCore-7.Q16HDRI.so*
|
||||
- usr/lib/libMagickWand-7.Q16HDRI.so*
|
||||
|
||||
|
|
|
|||
|
|
@ -40,18 +40,18 @@ yazi-watcher = { path = "../yazi-watcher", version = "26.5.6" }
|
|||
yazi-widgets = { path = "../yazi-widgets", version = "26.5.6" }
|
||||
|
||||
# External dependencies
|
||||
anyhow = { workspace = true }
|
||||
either = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
paste = { workspace = true }
|
||||
ratatui = { workspace = true }
|
||||
scopeguard = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
either = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
paste = { workspace = true }
|
||||
ratatui-core = { workspace = true }
|
||||
scopeguard = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
libc = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ impl Actor for AcceptPayload {
|
|||
drop(lock);
|
||||
|
||||
let kind = kind.to_owned();
|
||||
succ!(Lives::scope(cx.core, || {
|
||||
succ!(Lives::scope(cx.core, |_| {
|
||||
let body = payload.body.into_lua(&LUA)?;
|
||||
for (id, cb) in handlers {
|
||||
if let Err(e) = runtime_scope!(LUA, &id, cb.call::<()>(body.clone())) {
|
||||
|
|
|
|||
43
yazi-actor/src/app/dnd.rs
Normal file
43
yazi-actor/src/app/dnd.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use anyhow::Result;
|
||||
use mlua::{ObjectLike, Table};
|
||||
use tracing::error;
|
||||
use yazi_actor::lives::Lives;
|
||||
use yazi_binding::runtime_scope;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::app::DndForm;
|
||||
use yazi_plugin::LUA;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Dnd;
|
||||
|
||||
impl Actor for Dnd {
|
||||
type Form = DndForm;
|
||||
|
||||
const NAME: &str = "dnd";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let Some(size) = cx.term.as_ref().and_then(|t| t.size().ok()) else { succ!() };
|
||||
let area = yazi_binding::elements::Rect::from(size);
|
||||
|
||||
let result = Lives::scope(cx.core, move |_| {
|
||||
runtime_scope!(LUA, "root", {
|
||||
let root = LUA.globals().raw_get::<Table>("Root")?.call_method::<Table>("new", area)?;
|
||||
|
||||
if form.event.is_drag() {
|
||||
root.call_method::<()>("drag", form.event)?;
|
||||
} else {
|
||||
root.call_method::<()>("drop", form.event)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
|
||||
if let Err(ref e) = result {
|
||||
error!("{e}");
|
||||
}
|
||||
succ!(result?);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
use anyhow::Result;
|
||||
use yazi_binding::runtime_scope;
|
||||
use yazi_dds::Sendable;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::app::LuaForm;
|
||||
use yazi_plugin::LUA;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_shared::data::{Data, Sendable};
|
||||
|
||||
use crate::{Actor, Ctx, lives::Lives};
|
||||
|
||||
|
|
@ -17,7 +16,7 @@ impl Actor for Lua {
|
|||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let chunk = LUA.load(&*form.code).set_name("anonymous");
|
||||
let result = Lives::scope(cx.core, || {
|
||||
let result = Lives::scope(cx.core, |_| {
|
||||
runtime_scope!(LUA, "inline", Sendable::value_to_data(&LUA, chunk.eval()?))
|
||||
});
|
||||
succ!(result?);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ yazi_macro::mod_flat!(
|
|||
accept_payload
|
||||
bootstrap
|
||||
deprecate
|
||||
dnd
|
||||
focus
|
||||
lua
|
||||
mouse
|
||||
|
|
|
|||
|
|
@ -19,31 +19,29 @@ impl Actor for Mouse {
|
|||
const NAME: &str = "mouse";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let event = yazi_binding::MouseEvent::from(form.event);
|
||||
|
||||
let Some(size) = cx.term.as_ref().and_then(|t| t.size().ok()) else { succ!() };
|
||||
let area = yazi_binding::elements::Rect::from(size);
|
||||
|
||||
let result = Lives::scope(cx.core, move || {
|
||||
let root = runtime_scope!(LUA, "root", {
|
||||
LUA.globals().raw_get::<Table>("Root")?.call_method::<Table>("new", area)
|
||||
})?;
|
||||
let result = Lives::scope(cx.core, move |_| {
|
||||
runtime_scope!(LUA, "root", {
|
||||
let root = LUA.globals().raw_get::<Table>("Root")?.call_method::<Table>("new", area)?;
|
||||
|
||||
match event.kind {
|
||||
MouseEventKind::Down(_) => root.call_method("click", (event, false))?,
|
||||
MouseEventKind::Up(_) => root.call_method("click", (event, true))?,
|
||||
match form.event.kind {
|
||||
MouseEventKind::Down(_) => root.call_method("click", (form.event, false))?,
|
||||
MouseEventKind::Up(_) => root.call_method("click", (form.event, true))?,
|
||||
|
||||
MouseEventKind::ScrollDown => root.call_method("scroll", (event, 1))?,
|
||||
MouseEventKind::ScrollUp => root.call_method("scroll", (event, -1))?,
|
||||
MouseEventKind::ScrollDown => root.call_method("scroll", (form.event, 1))?,
|
||||
MouseEventKind::ScrollUp => root.call_method("scroll", (form.event, -1))?,
|
||||
|
||||
MouseEventKind::ScrollRight => root.call_method("touch", (event, 1))?,
|
||||
MouseEventKind::ScrollLeft => root.call_method("touch", (event, -1))?,
|
||||
MouseEventKind::ScrollRight => root.call_method("touch", (form.event, 1))?,
|
||||
MouseEventKind::ScrollLeft => root.call_method("touch", (form.event, -1))?,
|
||||
|
||||
MouseEventKind::Moved => root.call_method("move", event)?,
|
||||
MouseEventKind::Drag(_) => root.call_method("drag", event)?,
|
||||
}
|
||||
MouseEventKind::Moved => root.call_method("move", form.event)?,
|
||||
MouseEventKind::Drag(_) => root.call_method("drag", form.event)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
|
||||
if let Err(ref e) = result {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ impl Actor for PluginDo {
|
|||
};
|
||||
drop(loader);
|
||||
|
||||
let result = Lives::scope(cx.core, || {
|
||||
let result = Lives::scope(cx.core, |_| {
|
||||
if let Some(cb) = opt.callback {
|
||||
cb(&LUA, plugin)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use mlua::Value;
|
||||
use ratatui::layout::Position;
|
||||
use ratatui_core::layout::Position;
|
||||
use tracing::error;
|
||||
use yazi_actor::lives::Lives;
|
||||
use yazi_config::LAYOUT;
|
||||
|
|
@ -21,7 +21,7 @@ impl Actor for Reflow {
|
|||
let Some(size) = cx.term.as_ref().and_then(|t| t.size().ok()) else { succ!() };
|
||||
let mut layout = LAYOUT.get();
|
||||
|
||||
let result = Lives::scope(cx.core, || {
|
||||
let result = Lives::scope(cx.core, |_| {
|
||||
let comps = (form.reflow)((Position::ORIGIN, size).into())?;
|
||||
|
||||
for v in comps.sequence_values::<Value>() {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ use yazi_actor::Ctx;
|
|||
use yazi_macro::{succ, writef};
|
||||
use yazi_parser::{app::TitleForm, spark::SparkKind};
|
||||
use yazi_shared::{Source, data::Data};
|
||||
use yazi_term::sequence::SetTitle;
|
||||
use yazi_tty::TTY;
|
||||
use yazi_tty::{TTY, sequence::SetTitle};
|
||||
use yazi_tui::RatermState;
|
||||
|
||||
use crate::Actor;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ impl Actor for Trigger {
|
|||
if form.ticket.is_some_and(|t| t != cx.cmp.ticket) {
|
||||
succ!();
|
||||
} else if form.ticket.is_none() {
|
||||
cx.cmp.ticket = cx.input.ticket.current();
|
||||
cx.cmp.ticket = cx.input.lock().map(|g| g.ticket.current()).unwrap_or_default();
|
||||
}
|
||||
|
||||
cx.cmp.handle.take().map(|h| h.abort());
|
||||
|
|
@ -53,7 +53,7 @@ impl Actor for Trigger {
|
|||
|
||||
if !cache.is_empty() {
|
||||
cache
|
||||
.sort_unstable_by(|a, b| natsort(a.name.encoded_bytes(), b.name.encoded_bytes(), false));
|
||||
.sort_unstable_by(|a, b| natsort(a.name.encoded_bytes(), b.name.encoded_bytes(), true));
|
||||
CmpProxy::show(CmpOpt { cache, cache_name: parent, word, ticket });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use std::ops::{Deref, DerefMut};
|
|||
|
||||
use anyhow::{Result, anyhow};
|
||||
use yazi_core::{Core, mgr::Tabs, tab::{Folder, Tab}};
|
||||
use yazi_fs::File;
|
||||
use yazi_shared::{Id, Source, event::Action, url::UrlBuf};
|
||||
use yazi_fs::file::File;
|
||||
use yazi_shared::{Source, event::Action, id::Id, url::UrlBuf};
|
||||
use yazi_tui::Raterm;
|
||||
|
||||
pub struct Ctx<'a> {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ impl Preflight {
|
|||
return Ok(opt.1);
|
||||
};
|
||||
|
||||
Ok(Lives::scope(cx.core, || {
|
||||
Ok(Lives::scope(cx.core, |_| {
|
||||
let mut body = opt.1.into_lua(&LUA)?;
|
||||
for (id, cb) in handlers {
|
||||
match runtime_scope!(LUA, &id, cb.call::<Value>(&body)) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::input::CloseForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_parser::{input::CloseForm, spark::SparkKind};
|
||||
use yazi_shared::{Source, data::Data};
|
||||
use yazi_widgets::input::InputEvent;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
|
@ -14,16 +14,28 @@ impl Actor for Close {
|
|||
const NAME: &str = "close";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let input = &mut cx.input;
|
||||
input.visible = false;
|
||||
input.ticket.next();
|
||||
let Some(mut guard) = cx.input.lock_mut() else {
|
||||
succ!();
|
||||
};
|
||||
|
||||
if let Some(tx) = input.tx.take() {
|
||||
let value = input.snap().value.clone();
|
||||
_ = tx.send(if form.submit { InputEvent::Submit(value) } else { InputEvent::Cancel(value) });
|
||||
guard.ticket.next();
|
||||
if let Some(cb) = guard.cb.take() {
|
||||
let value = guard.snap().value.clone();
|
||||
cb(if form.submit { InputEvent::Submit(value) } else { InputEvent::Cancel(value) });
|
||||
}
|
||||
|
||||
drop(guard);
|
||||
cx.input.main.visible = false;
|
||||
|
||||
act!(cmp:close, cx)?;
|
||||
succ!(render!());
|
||||
}
|
||||
|
||||
fn hook(cx: &Ctx, _form: &Self::Form) -> Option<SparkKind> {
|
||||
match cx.source() {
|
||||
Source::Key => Some(SparkKind::KeyInputClose),
|
||||
Source::Ind => Some(SparkKind::IndInputClose),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,14 @@ impl Actor for Complete {
|
|||
const NAME: &str = "complete";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let input = &mut cx.input;
|
||||
if !input.visible || input.ticket.current() != form.ticket {
|
||||
let Some(mut guard) = cx.input.lock_mut() else {
|
||||
succ!();
|
||||
};
|
||||
|
||||
if guard.ticket.current() != form.ticket {
|
||||
succ!();
|
||||
}
|
||||
|
||||
act!(complete, input, form)
|
||||
act!(complete, guard, form)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,16 +15,20 @@ impl Actor for Escape {
|
|||
|
||||
fn act(cx: &mut Ctx, _: Self::Form) -> Result<Data> {
|
||||
use yazi_widgets::input::InputMode as M;
|
||||
let input = &mut cx.input;
|
||||
let Some(mut guard) = cx.input.lock_mut() else {
|
||||
succ!();
|
||||
};
|
||||
|
||||
let mode = input.snap().mode;
|
||||
let (mode, op) = (guard.snap().mode, guard.snap().op);
|
||||
act!(escape, guard)?;
|
||||
|
||||
drop(guard);
|
||||
match mode {
|
||||
M::Normal if input.snap_mut().op == InputOp::None => act!(input:close, cx),
|
||||
M::Normal if op == InputOp::None => act!(input:close, cx),
|
||||
M::Insert => act!(cmp:close, cx),
|
||||
M::Normal | M::Replace => Ok(().into()),
|
||||
}?;
|
||||
|
||||
act!(escape, cx.input)?;
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,34 @@
|
|||
use std::ops::DerefMut;
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_config::{THEME, YAZI};
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::input::ShowForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_widgets::input::InputOpt;
|
||||
use yazi_shim::ratatui::Padable;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Show;
|
||||
|
||||
impl Actor for Show {
|
||||
type Form = InputOpt;
|
||||
type Form = ShowForm;
|
||||
|
||||
const NAME: &str = "show";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
fn act(cx: &mut Ctx, Self::Form { mut opt }: Self::Form) -> Result<Data> {
|
||||
act!(input:close, cx)?;
|
||||
|
||||
let area = cx.mgr.area(opt.position).padding(cx.input.padding());
|
||||
let input = &mut cx.input;
|
||||
input.visible = true;
|
||||
input.title = form.cfg.title.clone();
|
||||
input.position = form.cfg.position;
|
||||
*input.deref_mut() = yazi_widgets::input::Input::new(form)?;
|
||||
input.main.visible = true;
|
||||
input.main.title = opt.title.clone();
|
||||
input.main.position = opt.position;
|
||||
|
||||
opt.styles = (&THEME.input).into();
|
||||
opt.blinking = YAZI.input.cursor_blink;
|
||||
*input.main.deref_mut() = yazi_widgets::input::Input::new(opt)?;
|
||||
input.main.repos(area);
|
||||
|
||||
succ!(render!());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,3 +3,5 @@ extern crate self as yazi_actor;
|
|||
yazi_macro::mod_pub!(app cmp confirm core help input lives mgr notify pick spot tasks which);
|
||||
|
||||
yazi_macro::mod_flat!(actor context);
|
||||
|
||||
pub fn init() { lives::init(); }
|
||||
|
|
|
|||
29
yazi-actor/src/lives/behavior.rs
Normal file
29
yazi-actor/src/lives/behavior.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataMethods};
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) struct Behavior {
|
||||
inner: PtrCell<yazi_scheduler::Behavior>,
|
||||
}
|
||||
|
||||
impl Deref for Behavior {
|
||||
type Target = yazi_scheduler::Behavior;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Behavior {
|
||||
pub(super) fn make(inner: &yazi_scheduler::Behavior) -> mlua::Result<AnyUserData> {
|
||||
let inner = PtrCell::from(inner);
|
||||
|
||||
Lives::scoped_userdata(Self { inner })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Behavior {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("reset", |_, me, ()| Ok(me.reset()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, IntoLua, MetaMethod, UserData, UserDataMethods, Value};
|
||||
use mlua::{AnyUserData, IntoLua, MetaMethod, UserData, UserDataMethods, UserDataRef, Value};
|
||||
use paste::paste;
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) type CoreRef = UserDataRef<Core>;
|
||||
|
||||
pub(super) struct Core {
|
||||
inner: PtrCell<yazi_core::Core>,
|
||||
|
||||
|
|
@ -12,8 +14,9 @@ pub(super) struct Core {
|
|||
c_tabs: Option<Value>,
|
||||
c_tasks: Option<Value>,
|
||||
c_yanked: Option<Value>,
|
||||
c_layer: Option<Value>,
|
||||
c_input: Option<Value>,
|
||||
c_which: Option<Value>,
|
||||
c_layer: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Core {
|
||||
|
|
@ -31,8 +34,9 @@ impl Core {
|
|||
c_tabs: None,
|
||||
c_tasks: None,
|
||||
c_yanked: None,
|
||||
c_layer: None,
|
||||
c_input: None,
|
||||
c_which: None,
|
||||
c_layer: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -57,10 +61,9 @@ impl UserData for Core {
|
|||
b"tabs" => reuse!(tabs, super::Tabs::make(&me.mgr.tabs)),
|
||||
b"tasks" => reuse!(tasks, super::Tasks::make(&me.tasks)),
|
||||
b"yanked" => reuse!(yanked, super::Yanked::make(&me.mgr.yanked)),
|
||||
b"layer" => {
|
||||
reuse!(layer, Ok::<_, mlua::Error>(yazi_binding::Layer::from(me.layer())))
|
||||
}
|
||||
b"input" => reuse!(input, super::Input::make(&me.input)),
|
||||
b"which" => reuse!(which, super::Which::make(&me.which)),
|
||||
b"layer" => reuse!(layer, Ok::<_, mlua::Error>(me.layer())),
|
||||
_ => Value::Nil,
|
||||
})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,37 +1,27 @@
|
|||
use std::{ops::Deref, ptr};
|
||||
|
||||
use mlua::{AnyUserData, IntoLua, UserData, UserDataFields, UserDataMethods, Value};
|
||||
use yazi_binding::{Range, Style, cached_field};
|
||||
use mlua::{AnyUserData, IntoLua, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_binding::{Range, style::Style};
|
||||
use yazi_config::THEME;
|
||||
use yazi_shared::{path::AsPath, url::UrlLike};
|
||||
|
||||
use super::Lives;
|
||||
use crate::lives::PtrCell;
|
||||
use super::{FILE_CACHE, Lives};
|
||||
use crate::lives::{CoreRef, PtrCell};
|
||||
|
||||
pub(super) struct File {
|
||||
idx: usize,
|
||||
folder: PtrCell<yazi_core::tab::Folder>,
|
||||
tab: PtrCell<yazi_core::tab::Tab>,
|
||||
|
||||
v_cha: Option<Value>,
|
||||
v_url: Option<Value>,
|
||||
v_link_to: Option<Value>,
|
||||
|
||||
v_name: Option<Value>,
|
||||
v_path: Option<Value>,
|
||||
v_cache: Option<Value>,
|
||||
|
||||
v_bare: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for File {
|
||||
type Target = yazi_fs::File;
|
||||
type Target = yazi_fs::file::File;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.folder.files[self.idx] }
|
||||
}
|
||||
|
||||
impl AsRef<yazi_fs::File> for File {
|
||||
fn as_ref(&self) -> &yazi_fs::File { self }
|
||||
impl AsRef<yazi_fs::file::File> for File {
|
||||
fn as_ref(&self) -> &yazi_fs::file::File { self }
|
||||
}
|
||||
|
||||
impl File {
|
||||
|
|
@ -42,24 +32,10 @@ impl File {
|
|||
) -> mlua::Result<AnyUserData> {
|
||||
use hashbrown::hash_map::Entry;
|
||||
|
||||
Ok(match super::FILE_CACHE.borrow_mut().entry(PtrCell(&folder.files[idx])) {
|
||||
Ok(match unsafe { (*FILE_CACHE.get()).assume_init_mut() }.entry(PtrCell(&folder.files[idx])) {
|
||||
Entry::Occupied(oe) => oe.into_mut().clone(),
|
||||
Entry::Vacant(ve) => {
|
||||
let ud = Lives::scoped_userdata(Self {
|
||||
idx,
|
||||
folder: folder.into(),
|
||||
tab: tab.into(),
|
||||
|
||||
v_cha: None,
|
||||
v_url: None,
|
||||
v_link_to: None,
|
||||
|
||||
v_name: None,
|
||||
v_path: None,
|
||||
v_cache: None,
|
||||
|
||||
v_bare: None,
|
||||
})?;
|
||||
let ud = Lives::scoped_userdata(Self { idx, folder: folder.into(), tab: tab.into() })?;
|
||||
ve.insert(ud.clone());
|
||||
ud
|
||||
}
|
||||
|
|
@ -73,7 +49,7 @@ impl File {
|
|||
impl UserData for File {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
yazi_binding::impl_file_fields!(fields);
|
||||
cached_field!(fields, bare, |_, me| Ok(yazi_binding::File::new(&**me)));
|
||||
fields.add_cached_field("bare", |_, me| Ok(yazi_fs::file::File::from(&**me)));
|
||||
|
||||
fields.add_field_method_get("idx", |_, me| Ok(me.idx + 1));
|
||||
fields.add_field_method_get("is_hovered", |_, me| Ok(me.is_hovered()));
|
||||
|
|
@ -87,17 +63,15 @@ impl UserData for File {
|
|||
yazi_binding::impl_file_methods!(methods);
|
||||
|
||||
methods.add_method("icon", |_, me, ()| {
|
||||
use yazi_binding::Icon;
|
||||
// TODO: use a cache
|
||||
Ok(yazi_config::THEME.icon.matches(me, me.is_hovered()).map(Icon::from))
|
||||
Ok(yazi_config::THEME.icon.matches(me, me.is_hovered()))
|
||||
});
|
||||
methods.add_method("size", |_, me, ()| {
|
||||
Ok(if me.is_dir() { me.folder.files.sizes.get(&me.urn()).copied() } else { Some(me.len) })
|
||||
});
|
||||
methods.add_method("mime", |lua, me, ()| {
|
||||
lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|core: &yazi_core::Core| {
|
||||
core.mgr.mimetype.get(&me.url).map(|s| lua.create_string(s)).transpose()
|
||||
})?
|
||||
let core: CoreRef = lua.named_registry_value("cx")?;
|
||||
core.mgr.mimetype.get(&me.url).map(|s| lua.create_string(s)).transpose()
|
||||
});
|
||||
methods.add_method("prefix", |lua, me, ()| {
|
||||
if !me.url.has_trail() {
|
||||
|
|
@ -109,20 +83,18 @@ impl UserData for File {
|
|||
Some(lua.create_string(comp.as_path().encoded_bytes())).transpose()
|
||||
});
|
||||
methods.add_method("style", |lua, me, ()| {
|
||||
lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|core: &yazi_core::Core| {
|
||||
let mime = core.mgr.mimetype.get(&me.url).unwrap_or_default();
|
||||
THEME.filetype.match_style(me, mime).map(Style::from)
|
||||
})
|
||||
let core: CoreRef = lua.named_registry_value("cx")?;
|
||||
let mime = core.mgr.mimetype.get(&me.url).unwrap_or_default();
|
||||
Ok(THEME.filetype.match_style(me, mime).map(Style::from))
|
||||
});
|
||||
methods.add_method("is_yanked", |lua, me, ()| {
|
||||
lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|core: &yazi_core::Core| {
|
||||
if !core.mgr.yanked.contains(&me.url) {
|
||||
0u8
|
||||
} else if core.mgr.yanked.cut {
|
||||
2u8
|
||||
} else {
|
||||
1u8
|
||||
}
|
||||
let core: CoreRef = lua.named_registry_value("cx")?;
|
||||
Ok(if !core.mgr.yanked.contains(&me.url) {
|
||||
0u8
|
||||
} else if core.mgr.yanked.cut {
|
||||
2u8
|
||||
} else {
|
||||
1u8
|
||||
})
|
||||
});
|
||||
methods.add_method("is_marked", |_, me, ()| {
|
||||
|
|
@ -139,31 +111,30 @@ impl UserData for File {
|
|||
});
|
||||
methods.add_method("is_selected", |_, me, ()| Ok(me.tab.selected.contains(&me.url)));
|
||||
methods.add_method("found", |lua, me, ()| {
|
||||
lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|core: &yazi_core::Core| {
|
||||
let Some(finder) = &core.active().finder else {
|
||||
return Ok(None);
|
||||
};
|
||||
let core: CoreRef = lua.named_registry_value("cx")?;
|
||||
let Some(finder) = &core.active().finder else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let Some(idx) = finder.matched_idx(&me.folder, me.urn()) else {
|
||||
return Ok(None);
|
||||
};
|
||||
let Some(idx) = finder.matched_idx(&me.folder, me.urn()) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
Some(lua.create_sequence_from([idx.into_lua(lua)?, finder.matched.len().into_lua(lua)?]))
|
||||
.transpose()
|
||||
})
|
||||
lua.create_sequence_from([idx.into_lua(lua)?, finder.matched.len().into_lua(lua)?]).map(Some)
|
||||
});
|
||||
methods.add_method("highlights", |lua, me, ()| {
|
||||
lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|core: &yazi_core::Core| {
|
||||
let Some(finder) = &core.active().finder else {
|
||||
return None;
|
||||
};
|
||||
if me.folder.url != me.tab.current.url {
|
||||
return None;
|
||||
}
|
||||
let core: CoreRef = lua.named_registry_value("cx")?;
|
||||
let Some(finder) = &core.active().finder else {
|
||||
return Ok(None);
|
||||
};
|
||||
if me.folder.url != me.tab.current.url {
|
||||
return Ok(None);
|
||||
}
|
||||
let Some(Some(h)) = me.url.name().map(|s| finder.filter.highlighted(s)) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let h = finder.filter.highlighted(me.url.name()?)?;
|
||||
Some(h.into_iter().map(Range::from).collect::<Vec<_>>())
|
||||
})
|
||||
lua.create_sequence_from(h.into_iter().map(Range::from)).map(Some)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::ops::{Deref, Range};
|
||||
|
||||
use mlua::{AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods, Value};
|
||||
use yazi_binding::cached_field;
|
||||
use mlua::{AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{File, Filter, Lives, PtrCell};
|
||||
|
||||
|
|
@ -9,8 +9,6 @@ pub(super) struct Files {
|
|||
window: Range<usize>,
|
||||
folder: PtrCell<yazi_core::tab::Folder>,
|
||||
tab: PtrCell<yazi_core::tab::Tab>,
|
||||
|
||||
v_filter: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Files {
|
||||
|
|
@ -25,13 +23,13 @@ impl Files {
|
|||
folder: &yazi_core::tab::Folder,
|
||||
tab: &yazi_core::tab::Tab,
|
||||
) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { window, folder: folder.into(), tab: tab.into(), v_filter: None })
|
||||
Lives::scoped_userdata(Self { window, folder: folder.into(), tab: tab.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Files {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
cached_field!(fields, filter, |_, me| me.filter().map(Filter::make).transpose());
|
||||
fields.add_static_field("filter", |_, me| me.filter().map(Filter::make).transpose());
|
||||
}
|
||||
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use std::ops::{Deref, Range};
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields, Value};
|
||||
use yazi_binding::{FolderStage, Url, cached_field};
|
||||
use mlua::{AnyUserData, UserData, UserDataFields};
|
||||
use yazi_config::LAYOUT;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{File, Files, Lives, PtrCell};
|
||||
|
||||
|
|
@ -10,12 +10,6 @@ pub(super) struct Folder {
|
|||
window: Range<usize>,
|
||||
inner: PtrCell<yazi_core::tab::Folder>,
|
||||
tab: PtrCell<yazi_core::tab::Tab>,
|
||||
|
||||
v_cwd: Option<Value>,
|
||||
v_files: Option<Value>,
|
||||
v_stage: Option<Value>,
|
||||
v_window: Option<Value>,
|
||||
v_hovered: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Folder {
|
||||
|
|
@ -38,30 +32,20 @@ impl Folder {
|
|||
}
|
||||
};
|
||||
|
||||
Lives::scoped_userdata(Self {
|
||||
window,
|
||||
inner: inner.into(),
|
||||
tab: tab.into(),
|
||||
|
||||
v_cwd: None,
|
||||
v_files: None,
|
||||
v_stage: None,
|
||||
v_window: None,
|
||||
v_hovered: None,
|
||||
})
|
||||
Lives::scoped_userdata(Self { window, inner: inner.into(), tab: tab.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Folder {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
cached_field!(fields, cwd, |_, me| Ok(Url::new(&me.url)));
|
||||
cached_field!(fields, files, |_, me| Files::make(0..me.files.len(), me, &me.tab));
|
||||
cached_field!(fields, stage, |_, me| Ok(FolderStage::new(me.stage.clone())));
|
||||
cached_field!(fields, window, |_, me| Files::make(me.window.clone(), me, &me.tab));
|
||||
fields.add_cached_field("cwd", |_, me| Ok(me.url.clone()));
|
||||
fields.add_static_field("files", |_, me| Files::make(0..me.files.len(), me, &me.tab));
|
||||
fields.add_cached_field("stage", |_, me| Ok(me.stage.clone()));
|
||||
fields.add_static_field("window", |_, me| Files::make(me.window.clone(), me, &me.tab));
|
||||
|
||||
fields.add_field_method_get("offset", |_, me| Ok(me.offset));
|
||||
fields.add_field_method_get("cursor", |_, me| Ok(me.cursor));
|
||||
cached_field!(fields, hovered, |_, me| {
|
||||
fields.add_static_field("hovered", |_, me| {
|
||||
me.hovered().map(|_| File::make(me.cursor, me, &me.tab)).transpose()
|
||||
});
|
||||
}
|
||||
|
|
|
|||
29
yazi-actor/src/lives/input.rs
Normal file
29
yazi-actor/src/lives/input.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields};
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
use crate::lives::InputAlt;
|
||||
|
||||
pub(super) struct Input {
|
||||
inner: PtrCell<yazi_core::input::Input>,
|
||||
}
|
||||
|
||||
impl Deref for Input {
|
||||
type Target = yazi_core::input::Input;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Input {
|
||||
pub(super) fn make(inner: &yazi_core::input::Input) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Input {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_cached_field("alt", |_, me| me.alt.as_ref().map(InputAlt::make).transpose());
|
||||
}
|
||||
}
|
||||
26
yazi-actor/src/lives/input_alt.rs
Normal file
26
yazi-actor/src/lives/input_alt.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields};
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) struct InputAlt(PtrCell<yazi_core::input::InputAlt>);
|
||||
|
||||
impl Deref for InputAlt {
|
||||
type Target = yazi_core::input::InputAlt;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl InputAlt {
|
||||
pub(super) fn make(inner: &yazi_core::input::InputAlt) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self(inner.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for InputAlt {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_cached_field("value", |lua, me| lua.create_string(me.lock().value()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +1,38 @@
|
|||
use std::cell::RefCell;
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use mlua::{AnyUserData, UserData};
|
||||
use scopeguard::defer;
|
||||
use tracing::error;
|
||||
use yazi_plugin::LUA;
|
||||
use yazi_shim::cell::RoCell;
|
||||
|
||||
use super::{Core, PtrCell};
|
||||
use crate::lives::MutCell;
|
||||
|
||||
static TO_DESTROY: RoCell<RefCell<Vec<AnyUserData>>> = RoCell::new_const(RefCell::new(Vec::new()));
|
||||
pub(super) static FILE_CACHE: RoCell<RefCell<HashMap<PtrCell<yazi_fs::File>, AnyUserData>>> =
|
||||
RoCell::new();
|
||||
pub(super) static TO_DESTROY: MutCell<Vec<AnyUserData>> = MutCell::new(Vec::new());
|
||||
pub(super) static FILE_CACHE: MutCell<
|
||||
MaybeUninit<HashMap<PtrCell<yazi_fs::file::File>, AnyUserData>>,
|
||||
> = MutCell::new(MaybeUninit::uninit());
|
||||
|
||||
pub struct Lives;
|
||||
|
||||
impl Lives {
|
||||
pub fn scope<T, F>(core: &yazi_core::Core, f: F) -> mlua::Result<T>
|
||||
pub fn scope<T, F>(core: &mut yazi_core::Core, f: F) -> mlua::Result<T>
|
||||
where
|
||||
F: FnOnce() -> mlua::Result<T>,
|
||||
F: FnOnce(&mut yazi_core::Core) -> mlua::Result<T>,
|
||||
{
|
||||
FILE_CACHE.init(Default::default());
|
||||
defer! { FILE_CACHE.drop(); }
|
||||
|
||||
let result = LUA.scope(|scope| {
|
||||
scope.add_destructor(|| {
|
||||
for ud in TO_DESTROY.borrow_mut().drain(..) {
|
||||
defer! {
|
||||
unsafe {
|
||||
(*FILE_CACHE.get()).assume_init_mut().clear();
|
||||
for ud in (*TO_DESTROY.get()).drain(..) {
|
||||
ud.destroy().expect("failed to destruct scoped userdata");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
LUA.set_named_registry_value("cx", scope.create_any_userdata_ref(core)?)?;
|
||||
LUA.globals().raw_set("cx", Core::make(core)?)?;
|
||||
f()
|
||||
});
|
||||
LUA.set_named_registry_value("cx", Core::make(core)?)?;
|
||||
LUA.globals().raw_set("cx", Core::make(core)?)?;
|
||||
let result = f(core);
|
||||
|
||||
if let Err(ref e) = result {
|
||||
error!("{e}");
|
||||
|
|
@ -46,7 +45,7 @@ impl Lives {
|
|||
T: UserData + 'static,
|
||||
{
|
||||
let ud = LUA.create_userdata(data)?;
|
||||
TO_DESTROY.borrow_mut().push(ud.clone());
|
||||
unsafe { &mut *TO_DESTROY.get() }.push(ud.clone());
|
||||
Ok(ud)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,5 @@
|
|||
yazi_macro::mod_flat!(core file files filter finder folder lives mode preference preview ptr selected tab tabs task tasks which yanked);
|
||||
yazi_macro::mod_flat!(behavior core file files filter finder folder input input_alt lives mode mut_cell preference preview ptr selected tab tabs task tasks which yanked);
|
||||
|
||||
pub(super) fn init() {
|
||||
unsafe { FILE_CACHE.get().write(std::mem::MaybeUninit::new(<_>::default())) };
|
||||
}
|
||||
|
|
|
|||
11
yazi-actor/src/lives/mut_cell.rs
Normal file
11
yazi-actor/src/lives/mut_cell.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
use std::cell::UnsafeCell;
|
||||
|
||||
pub(super) struct MutCell<T>(UnsafeCell<T>);
|
||||
|
||||
unsafe impl<T> Sync for MutCell<T> {}
|
||||
|
||||
impl<T> MutCell<T> {
|
||||
pub(super) const fn new(value: T) -> Self { Self(UnsafeCell::new(value)) }
|
||||
|
||||
pub(super) fn get(&self) -> *mut T { self.0.get() }
|
||||
}
|
||||
|
|
@ -1,18 +1,12 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields, Value};
|
||||
use yazi_binding::cached_field;
|
||||
use yazi_shim::strum::IntoStr;
|
||||
use mlua::{AnyUserData, UserData, UserDataFields};
|
||||
use yazi_shim::{mlua::UserDataFieldsExt, strum::IntoStr};
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) struct Preference {
|
||||
inner: PtrCell<yazi_core::tab::Preference>,
|
||||
|
||||
v_name: Option<Value>,
|
||||
v_linemode: Option<Value>,
|
||||
|
||||
v_sort_by: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Preference {
|
||||
|
|
@ -23,26 +17,19 @@ impl Deref for Preference {
|
|||
|
||||
impl Preference {
|
||||
pub(super) fn make(inner: &yazi_core::tab::Preference) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self {
|
||||
inner: inner.into(),
|
||||
|
||||
v_name: None,
|
||||
v_linemode: None,
|
||||
|
||||
v_sort_by: None,
|
||||
})
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Preference {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
// Display
|
||||
cached_field!(fields, name, |lua, me| lua.create_string(&me.name));
|
||||
cached_field!(fields, linemode, |lua, me| lua.create_string(&*me.linemode));
|
||||
fields.add_cached_field("name", |lua, me| lua.create_string(&me.name));
|
||||
fields.add_cached_field("linemode", |lua, me| lua.create_string(&*me.linemode));
|
||||
fields.add_field_method_get("show_hidden", |_, me| Ok(me.show_hidden));
|
||||
|
||||
// Sorting
|
||||
cached_field!(fields, sort_by, |_, me| Ok(me.sort_by.into_str()));
|
||||
fields.add_cached_field("sort_by", |_, me| Ok(me.sort_by.into_str()));
|
||||
fields.add_field_method_get("sort_sensitive", |_, me| Ok(me.sort_sensitive));
|
||||
fields.add_field_method_get("sort_reverse", |_, me| Ok(me.sort_reverse));
|
||||
fields.add_field_method_get("sort_dir_first", |_, me| Ok(me.sort_dir_first));
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields, Value};
|
||||
use yazi_binding::cached_field;
|
||||
use mlua::{AnyUserData, UserData, UserDataFields};
|
||||
use yazi_config::LAYOUT;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{Folder, Lives, PtrCell};
|
||||
|
||||
pub(super) struct Preview {
|
||||
tab: PtrCell<yazi_core::tab::Tab>,
|
||||
|
||||
v_folder: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Preview {
|
||||
|
|
@ -22,17 +20,16 @@ impl Deref for Preview {
|
|||
|
||||
impl Preview {
|
||||
pub(super) fn make(tab: &yazi_core::tab::Tab) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { tab: tab.into(), v_folder: None })
|
||||
Lives::scoped_userdata(Self { tab: tab.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Preview {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("skip", |_, me| Ok(me.skip));
|
||||
// TODO: Make sure we need this ?
|
||||
fields.add_field_method_get("search_idx", |_, me| Ok(me.search_idx));
|
||||
|
||||
cached_field!(fields, folder, |_, me| {
|
||||
fields.add_static_field("folder", |_, me| {
|
||||
me.tab
|
||||
.hovered_folder()
|
||||
.map(|f| {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use mlua::AnyUserData;
|
||||
use yazi_shared::url::UrlBuf;
|
||||
|
||||
use super::Lives;
|
||||
use crate::lives::PtrCell;
|
||||
|
|
@ -11,7 +12,7 @@ impl Selected {
|
|||
let inner = PtrCell::from(inner);
|
||||
|
||||
Lives::scoped_userdata(yazi_binding::Iter::new(
|
||||
inner.as_static().values().map(yazi_binding::Url::new),
|
||||
inner.as_static().values().map(UrlBuf::from),
|
||||
Some(inner.len()),
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,13 @@
|
|||
use std::{borrow::Cow, ops::Deref};
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields, UserDataMethods, Value};
|
||||
use yazi_binding::{Id, UrlRef, cached_field};
|
||||
use mlua::{AnyUserData, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_shared::url::UrlRef;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{Finder, Folder, Lives, Mode, Preference, Preview, PtrCell, Selected};
|
||||
|
||||
pub(super) struct Tab {
|
||||
inner: PtrCell<yazi_core::tab::Tab>,
|
||||
|
||||
v_name: Option<Value>,
|
||||
v_mode: Option<Value>,
|
||||
v_pref: Option<Value>,
|
||||
v_current: Option<Value>,
|
||||
v_parent: Option<Value>,
|
||||
v_selected: Option<Value>,
|
||||
v_preview: Option<Value>,
|
||||
v_finder: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Tab {
|
||||
|
|
@ -26,42 +18,29 @@ impl Deref for Tab {
|
|||
|
||||
impl Tab {
|
||||
pub(super) fn make(inner: &yazi_core::tab::Tab) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self {
|
||||
inner: inner.into(),
|
||||
|
||||
v_name: None,
|
||||
v_mode: None,
|
||||
v_pref: None,
|
||||
v_current: None,
|
||||
v_parent: None,
|
||||
v_selected: None,
|
||||
v_preview: None,
|
||||
v_finder: None,
|
||||
})
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Tab {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
cached_field!(fields, name, |lua, me| {
|
||||
match me.name() {
|
||||
Cow::Borrowed(s) => lua.create_string(s),
|
||||
Cow::Owned(s) => lua.create_external_string(s),
|
||||
}
|
||||
fields.add_field_method_get("id", |_, me| Ok(me.id));
|
||||
fields.add_cached_field("name", |lua, me| match me.name() {
|
||||
Cow::Borrowed(s) => lua.create_string(s),
|
||||
Cow::Owned(s) => lua.create_external_string(s),
|
||||
});
|
||||
|
||||
cached_field!(fields, mode, |_, me| Mode::make(&me.mode));
|
||||
cached_field!(fields, pref, |_, me| Preference::make(&me.pref));
|
||||
cached_field!(fields, current, |_, me| Folder::make(None, &me.current, me));
|
||||
cached_field!(fields, parent, |_, me| {
|
||||
fields.add_static_field("mode", |_, me| Mode::make(&me.mode));
|
||||
fields.add_static_field("pref", |_, me| Preference::make(&me.pref));
|
||||
fields.add_static_field("current", |_, me| Folder::make(None, &me.current, me));
|
||||
fields.add_static_field("parent", |_, me| {
|
||||
me.parent.as_ref().map(|f| Folder::make(None, f, me)).transpose()
|
||||
});
|
||||
|
||||
cached_field!(fields, selected, |_, me| Selected::make(&me.selected));
|
||||
fields.add_static_field("selected", |_, me| Selected::make(&me.selected));
|
||||
|
||||
cached_field!(fields, preview, |_, me| Preview::make(me));
|
||||
cached_field!(fields, finder, |_, me| me.finder.as_ref().map(Finder::make).transpose());
|
||||
fields.add_static_field("preview", |_, me| Preview::make(me));
|
||||
fields.add_static_field("finder", |_, me| me.finder.as_ref().map(Finder::make).transpose());
|
||||
}
|
||||
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields, Value};
|
||||
use yazi_binding::{SER_OPT, cached_field};
|
||||
use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields};
|
||||
use yazi_scheduler::Progress;
|
||||
use yazi_shim::mlua::{SER_OPT, UserDataFieldsExt};
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) struct TaskSnap {
|
||||
inner: PtrCell<yazi_scheduler::TaskSnap>,
|
||||
|
||||
v_title: Option<Value>,
|
||||
v_prog: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for TaskSnap {
|
||||
|
|
@ -21,14 +18,14 @@ impl Deref for TaskSnap {
|
|||
|
||||
impl TaskSnap {
|
||||
pub(super) fn make(inner: &yazi_scheduler::TaskSnap) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into(), v_title: None, v_prog: None })
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for TaskSnap {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
cached_field!(fields, title, |lua, me| lua.create_string(&me.title));
|
||||
cached_field!(fields, prog, |lua, me| lua.to_value_with(&me.prog, SER_OPT));
|
||||
fields.add_cached_field("title", |lua, me| lua.create_string(&me.title));
|
||||
fields.add_cached_field("prog", |lua, me| lua.to_value_with(&me.prog, SER_OPT));
|
||||
|
||||
fields.add_field_method_get("running", |_, me| Ok(me.prog.running()));
|
||||
fields.add_field_method_get("cooked", |_, me| Ok(me.prog.cooked()));
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields, Value};
|
||||
use yazi_binding::{SER_OPT, cached_field};
|
||||
use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields};
|
||||
use yazi_shim::mlua::{SER_OPT, UserDataFieldsExt};
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
use crate::lives::TaskSnap;
|
||||
use crate::lives::{Behavior, TaskSnap};
|
||||
|
||||
pub(super) struct Tasks {
|
||||
inner: PtrCell<yazi_core::tasks::Tasks>,
|
||||
|
||||
v_snaps: Option<Value>,
|
||||
v_summary: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Tasks {
|
||||
|
|
@ -21,12 +18,7 @@ impl Deref for Tasks {
|
|||
|
||||
impl Tasks {
|
||||
pub(super) fn make(inner: &yazi_core::tasks::Tasks) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self {
|
||||
inner: inner.into(),
|
||||
|
||||
v_snaps: None,
|
||||
v_summary: None,
|
||||
})
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +26,9 @@ impl UserData for Tasks {
|
|||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("cursor", |_, me| Ok(me.cursor));
|
||||
|
||||
cached_field!(fields, snaps, |lua, me| {
|
||||
fields.add_static_field("behavior", |_, me| Behavior::make(&me.scheduler.behavior));
|
||||
|
||||
fields.add_static_field("snaps", |lua, me| {
|
||||
let tbl = lua.create_table_with_capacity(me.snaps.len(), 0)?;
|
||||
for snap in &me.snaps {
|
||||
tbl.raw_push(TaskSnap::make(snap)?)?;
|
||||
|
|
@ -42,6 +36,6 @@ impl UserData for Tasks {
|
|||
Ok(tbl)
|
||||
});
|
||||
|
||||
cached_field!(fields, summary, |lua, me| lua.to_value_with(&me.summary, SER_OPT));
|
||||
fields.add_cached_field("summary", |lua, me| lua.to_value_with(&me.summary, SER_OPT));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields, Value};
|
||||
use yazi_binding::cached_field;
|
||||
use mlua::{AnyUserData, UserData, UserDataFields};
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) struct Which {
|
||||
inner: PtrCell<yazi_core::which::Which>,
|
||||
|
||||
v_tx: Option<Value>,
|
||||
v_cands: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Which {
|
||||
|
|
@ -20,16 +17,16 @@ impl Deref for Which {
|
|||
|
||||
impl Which {
|
||||
pub(super) fn make(inner: &yazi_core::which::Which) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into(), v_tx: None, v_cands: None })
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Which {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
cached_field!(fields, tx, |_, me| Ok(me.tx.clone().map(yazi_binding::MpscUnboundedTx)));
|
||||
fields.add_cached_field("tx", |_, me| Ok(me.tx.clone().map(yazi_binding::MpscUnboundedTx)));
|
||||
fields.add_field_method_get("times", |_, me| Ok(me.inner.times));
|
||||
cached_field!(fields, cands, |lua, me| {
|
||||
lua.create_sequence_from(me.inner.cands.iter().cloned().map(yazi_binding::ChordCow))
|
||||
fields.add_cached_field("cands", |lua, me| {
|
||||
lua.create_sequence_from(me.inner.cands.iter().cloned())
|
||||
});
|
||||
|
||||
fields.add_field_method_get("active", |_, me| Ok(me.inner.active));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, MetaMethod, MultiValue, ObjectLike, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_binding::{Iter, get_metatable};
|
||||
use yazi_binding::Iter;
|
||||
use yazi_shared::url::UrlBuf;
|
||||
use yazi_shim::mlua::get_metatable;
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
|
|
@ -23,7 +25,7 @@ impl Yanked {
|
|||
Lives::scoped_userdata(Self {
|
||||
inner,
|
||||
iter: Lives::scoped_userdata(Iter::new(
|
||||
inner.as_static().iter().map(yazi_binding::Url::new),
|
||||
inner.as_static().iter().map(UrlBuf::from),
|
||||
Some(inner.len()),
|
||||
))?,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
use std::{fmt::{self, Display}, io::{self, Read, Write}, path::{MAIN_SEPARATOR, Path}, sync::Arc};
|
||||
use std::{fmt::{self, Display}, io::{self, Read, Write}, path::{MAIN_SEPARATOR, Path}};
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use scopeguard::defer;
|
||||
use yazi_binding::Permit;
|
||||
use yazi_config::{YAZI, opener::OpenerRule};
|
||||
use yazi_fs::{File, FilesOp, Splatter, provider::{Provider, local::Local}};
|
||||
use yazi_config::{YAZI, opener::OpenerRuleArc};
|
||||
use yazi_fs::{FilesOp, Splatter, file::File, provider::{Provider, local::Local}};
|
||||
use yazi_macro::{succ, writef};
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_proxy::TasksProxy;
|
||||
use yazi_scheduler::{AppProxy, NotifyProxy};
|
||||
use yazi_shared::{data::Data, strand::Strand, url::{AsUrl, UrlBuf, UrlCow, UrlLike}};
|
||||
use yazi_shim::path::CROSS_SEPARATOR;
|
||||
use yazi_term::{YIELD_TO_SUBPROCESS, sequence::EraseScreen};
|
||||
use yazi_tty::TTY;
|
||||
use yazi_term::YIELD_TO_SUBPROCESS;
|
||||
use yazi_tty::{TTY, sequence::EraseScreen};
|
||||
use yazi_vfs::{VfsFile, provider};
|
||||
use yazi_watcher::WATCHER;
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ impl BulkCreate {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn opener() -> Option<Arc<OpenerRule>> {
|
||||
fn opener() -> Option<OpenerRuleArc> {
|
||||
YAZI
|
||||
.open
|
||||
.match_dummy(Path::new("bulk-create.txt"), "text/plain")
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
use std::{hash::Hash, io::{Read, Write}, ops::Deref, path::Path, sync::Arc};
|
||||
use std::{hash::Hash, io::{Read, Write}, ops::Deref, path::Path};
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use hashbrown::HashMap;
|
||||
use scopeguard::defer;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use yazi_binding::Permit;
|
||||
use yazi_config::{YAZI, opener::OpenerRule};
|
||||
use yazi_config::{YAZI, opener::OpenerRuleArc};
|
||||
use yazi_dds::Pubsub;
|
||||
use yazi_fs::{File, FilesOp, Splatter, max_common_root, path::skip_url, provider::{FileBuilder, Provider, local::{Gate, Local}}};
|
||||
use yazi_fs::{FilesOp, Splatter, file::File, max_common_root, path::skip_url, provider::{FileBuilder, Provider, local::{Gate, Local}}};
|
||||
use yazi_macro::{err, succ, writef};
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_proxy::TasksProxy;
|
||||
use yazi_scheduler::{AppProxy, NotifyProxy};
|
||||
use yazi_shared::{data::Data, path::PathDyn, strand::{AsStrand, AsStrandJoin, Strand, StrandBuf, StrandLike}, url::{AsUrl, UrlBuf, UrlCow, UrlLike}};
|
||||
use yazi_term::{YIELD_TO_SUBPROCESS, sequence::EraseScreen};
|
||||
use yazi_tty::TTY;
|
||||
use yazi_term::YIELD_TO_SUBPROCESS;
|
||||
use yazi_tty::{TTY, sequence::EraseScreen};
|
||||
use yazi_vfs::{VfsFile, maybe_exists, provider};
|
||||
use yazi_watcher::WATCHER;
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ impl BulkRename {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn opener() -> Option<Arc<OpenerRule>> {
|
||||
fn opener() -> Option<OpenerRuleArc> {
|
||||
YAZI
|
||||
.open
|
||||
.match_dummy(Path::new("bulk-rename.txt"), "text/plain")
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ use std::{mem, time::Duration};
|
|||
use anyhow::Result;
|
||||
use tokio::pin;
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_core::mgr::CdSource;
|
||||
use yazi_dds::Pubsub;
|
||||
use yazi_fs::{File, FilesOp, path::{clean_url, expand_url}};
|
||||
use yazi_fs::{FilesOp, file::File, path::{clean_url, expand_url}};
|
||||
use yazi_macro::{act, err, input, render, succ};
|
||||
use yazi_parser::mgr::CdForm;
|
||||
use yazi_proxy::{CmpProxy, MgrProxy};
|
||||
|
|
@ -63,7 +63,7 @@ impl Actor for Cd {
|
|||
|
||||
impl Cd {
|
||||
fn cd_interactive(cx: &mut Ctx) -> Result<Data> {
|
||||
let input = input!(cx, InputCfg::cd(cx.cwd().as_url()))?;
|
||||
let input = input!(cx, YAZI.input.cd(cx.cwd().as_url()))?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let rx = Debounce::new(UnboundedReceiverStream::new(input), Duration::from_millis(50));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::{Result, bail};
|
||||
use yazi_config::popup::{ConfirmCfg, InputCfg};
|
||||
use yazi_fs::{File, FilesOp};
|
||||
use yazi_config::{YAZI, popup::ConfirmCfg};
|
||||
use yazi_fs::{FilesOp, file::File};
|
||||
use yazi_macro::{input, ok_or_not_found, succ};
|
||||
use yazi_parser::mgr::CreateForm;
|
||||
use yazi_proxy::{ConfirmProxy, MgrProxy};
|
||||
|
|
@ -20,7 +20,7 @@ impl Actor for Create {
|
|||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let cwd = cx.cwd().to_owned();
|
||||
let mut input = input!(cx, InputCfg::create(form.dir))?;
|
||||
let mut input = input!(cx, YAZI.input.create(form.dir))?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let Some(InputEvent::Submit(name)) = input.recv().await else { return };
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use anyhow::Result;
|
|||
use futures::{StreamExt, stream::FuturesUnordered};
|
||||
use hashbrown::HashSet;
|
||||
use yazi_core::mgr::OpenOpt;
|
||||
use yazi_fs::{File, FsScheme, provider::{Provider, local::Local}};
|
||||
use yazi_fs::{FsScheme, file::File, provider::{Provider, local::Local}};
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::mgr::DownloadForm;
|
||||
use yazi_proxy::MgrProxy;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::time::Duration;
|
|||
use anyhow::Result;
|
||||
use tokio::pin;
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_core::mgr::FilterOpt;
|
||||
use yazi_macro::{input, succ};
|
||||
use yazi_parser::mgr::FilterForm;
|
||||
|
|
@ -21,7 +21,7 @@ impl Actor for Filter {
|
|||
const NAME: &str = "filter";
|
||||
|
||||
fn act(cx: &mut Ctx, Self::Form { opt }: Self::Form) -> Result<Data> {
|
||||
let input = input!(cx, InputCfg::filter())?;
|
||||
let input = input!(cx, YAZI.input.filter())?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let rx = Debounce::new(UnboundedReceiverStream::new(input), Duration::from_millis(50));
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::time::Duration;
|
|||
use anyhow::Result;
|
||||
use tokio::pin;
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_core::mgr::FindDoOpt;
|
||||
use yazi_macro::{input, succ};
|
||||
use yazi_parser::mgr::FindForm;
|
||||
|
|
@ -21,7 +21,7 @@ impl Actor for Find {
|
|||
const NAME: &str = "find";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let input = input!(cx, InputCfg::find(form.prev))?;
|
||||
let input = input!(cx, YAZI.input.find(form.prev))?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let rx = Debounce::new(UnboundedReceiverStream::new(input), Duration::from_millis(50));
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use futures::StreamExt;
|
|||
use hashbrown::HashSet;
|
||||
use yazi_boot::ARGS;
|
||||
use yazi_core::mgr::OpenDoOpt;
|
||||
use yazi_fs::File;
|
||||
use yazi_fs::file::File;
|
||||
use yazi_macro::{act, succ};
|
||||
use yazi_parser::mgr::OpenForm;
|
||||
use yazi_proxy::MgrProxy;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use anyhow::Result;
|
||||
use hashbrown::HashMap;
|
||||
use indexmap::IndexSet;
|
||||
use yazi_config::{YAZI, popup::PickCfg};
|
||||
use yazi_config::YAZI;
|
||||
use yazi_fs::file::File;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::mgr::OpenDoForm;
|
||||
use yazi_proxy::{PickProxy, TasksProxy};
|
||||
|
|
@ -40,7 +41,7 @@ impl Actor for OpenDo {
|
|||
succ!();
|
||||
}
|
||||
|
||||
let pick = PickProxy::show(PickCfg::open(openers.iter().map(|o| o.desc()).collect()));
|
||||
let pick = PickProxy::show(YAZI.pick.open(openers.iter().map(|o| o.desc()).collect()));
|
||||
let urls: Vec<_> = [UrlCow::default()]
|
||||
.into_iter()
|
||||
.chain(targets.into_iter().map(|(file, _)| file.url.into()))
|
||||
|
|
@ -63,7 +64,7 @@ impl Actor for OpenDo {
|
|||
|
||||
impl OpenDo {
|
||||
// TODO: remove
|
||||
fn match_and_open(cx: &Ctx, cwd: UrlBuf, targets: Vec<(yazi_fs::File, &str)>) {
|
||||
fn match_and_open(cx: &Ctx, cwd: UrlBuf, targets: Vec<(File, &str)>) {
|
||||
let mut openers = HashMap::new();
|
||||
for (file, mime) in targets {
|
||||
if let Some(open) = YAZI.open.matches(&file, mime)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use anyhow::Result;
|
||||
use yazi_config::popup::{ConfirmCfg, InputCfg};
|
||||
use yazi_config::{YAZI, popup::ConfirmCfg};
|
||||
use yazi_dds::Pubsub;
|
||||
use yazi_fs::{File, FilesOp};
|
||||
use yazi_fs::{FilesOp, file::File};
|
||||
use yazi_macro::{act, err, input, ok_or_not_found, succ};
|
||||
use yazi_parser::mgr::RenameForm;
|
||||
use yazi_proxy::{ConfirmProxy, MgrProxy};
|
||||
use yazi_shared::{Id, data::Data, url::{UrlBuf, UrlLike}};
|
||||
use yazi_shared::{data::Data, id::Id, url::{UrlBuf, UrlLike}};
|
||||
use yazi_vfs::{VfsFile, maybe_exists, provider};
|
||||
use yazi_watcher::WATCHER;
|
||||
use yazi_widgets::input::InputEvent;
|
||||
|
|
@ -42,7 +42,7 @@ impl Actor for Rename {
|
|||
};
|
||||
|
||||
let (tab, old) = (cx.tab().id, hovered.url_owned());
|
||||
let mut input = input!(cx, InputCfg::rename().with_value(name).with_cursor(cursor))?;
|
||||
let mut input = input!(cx, YAZI.input.rename().with_value(name).with_cursor(cursor))?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let Some(InputEvent::Submit(name)) = input.recv().await else { return };
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use yazi_fs::{File, FilesOp};
|
||||
use yazi_fs::{FilesOp, file::File};
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::mgr::RevealForm;
|
||||
use yazi_shared::{data::Data, url::UrlLike};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{borrow::Cow, time::Duration};
|
|||
use anyhow::Result;
|
||||
use tokio::pin;
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_core::mgr::{CdSource, SearchVia};
|
||||
use yazi_fs::{FilesOp, cha::Cha};
|
||||
use yazi_macro::{act, input, succ};
|
||||
|
|
@ -28,7 +28,7 @@ impl Actor for Search {
|
|||
handle.abort();
|
||||
}
|
||||
|
||||
let mut input = input!(cx, InputCfg::search(opt.via.into()).with_value(&*opt.subject))?;
|
||||
let mut input = input!(cx, YAZI.input.search(opt.via.into()).with_value(&*opt.subject))?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Some(InputEvent::Submit(subject)) = input.recv().await {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_macro::{act, input, succ};
|
||||
use yazi_parser::mgr::ShellForm;
|
||||
use yazi_proxy::TasksProxy;
|
||||
|
|
@ -25,7 +25,10 @@ impl Actor for Shell {
|
|||
let selected: Vec<_> = cx.tab().hovered_and_selected().cloned().map(Into::into).collect();
|
||||
|
||||
let input = if form.interactive {
|
||||
Some(input!(cx, InputCfg::shell(form.block).with_value(&*form.run).with_cursor(form.cursor))?)
|
||||
Some(input!(
|
||||
cx,
|
||||
YAZI.input.shell(form.block).with_value(&*form.run).with_cursor(form.cursor)
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_macro::{act, input, render, succ};
|
||||
use yazi_parser::mgr::TabRenameForm;
|
||||
use yazi_proxy::MgrProxy;
|
||||
|
|
@ -29,7 +29,7 @@ impl Actor for TabRename {
|
|||
|
||||
let mut input = input!(
|
||||
cx,
|
||||
InputCfg::tab_rename().with_value(form.name.unwrap_or(Cow::Borrowed(&pref.name)))
|
||||
YAZI.input.tab_rename().with_value(form.name.unwrap_or(Cow::Borrowed(&pref.name)))
|
||||
)?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui_core::layout::Rect;
|
||||
use yazi_core::notify::Notify;
|
||||
use yazi_macro::{render, render_partial, succ};
|
||||
use yazi_parser::notify::TickForm;
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@ use anyhow::Result;
|
|||
use scopeguard::defer;
|
||||
use tokio::{io::{AsyncReadExt, stdin}, select, sync::mpsc, time};
|
||||
use yazi_binding::Permit;
|
||||
use yazi_term::TERM;
|
||||
use yazi_macro::{succ, writef};
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_scheduler::AppProxy;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_term::{YIELD_TO_SUBPROCESS, sequence::EraseScreen};
|
||||
use yazi_tty::TTY;
|
||||
use yazi_term::{TERM, YIELD_TO_SUBPROCESS};
|
||||
use yazi_tty::{TTY, sequence::EraseScreen};
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ impl Actor for Spawn {
|
|||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
succ!(match form.opt {
|
||||
TaskOpt::Cut(r#in) => cx.tasks.scheduler.file_cut(r#in),
|
||||
|
||||
TaskOpt::Plugin(r#in) => cx.tasks.scheduler.plugin_entry(r#in),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,18 +19,19 @@ yazi-fs = { path = "../yazi-fs", version = "26.5.6" }
|
|||
yazi-macro = { path = "../yazi-macro", version = "26.5.6" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "26.5.6" }
|
||||
yazi-shim = { path = "../yazi-shim", version = "26.5.6" }
|
||||
yazi-term = { path = "../yazi-term", version = "26.5.6" }
|
||||
yazi-tty = { path = "../yazi-tty", version = "26.5.9" }
|
||||
yazi-widgets = { path = "../yazi-widgets", version = "26.5.6" }
|
||||
|
||||
# External dependencies
|
||||
ansi-to-tui = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
image = { version = "0.25.10", default-features = false, features = [ "avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp" ] }
|
||||
moxcms = "0.8.1"
|
||||
palette = { version = "0.7.6", default-features = false }
|
||||
quantette = { version = "0.6.0", default-features = false }
|
||||
ratatui = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
ansi-to-tui = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
image = { workspace = true }
|
||||
inventory = { workspace = true }
|
||||
moxcms = "0.8.1"
|
||||
palette = { version = "0.7.6", default-features = false }
|
||||
quantette = { version = "0.6.0", default-features = false }
|
||||
ratatui-core = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,105 +1,56 @@
|
|||
use std::{env, path::PathBuf};
|
||||
use std::{fmt::{self, Debug}, ops::Deref};
|
||||
|
||||
use anyhow::Result;
|
||||
use ratatui::layout::Rect;
|
||||
use strum::{Display, IntoStaticStr};
|
||||
use tracing::warn;
|
||||
use yazi_emulator::{Emulator, TMUX};
|
||||
use yazi_shared::env_exists;
|
||||
use ratatui_core::layout::Rect;
|
||||
use yazi_emulator::EMULATOR;
|
||||
use yazi_shim::cell::SyncCell;
|
||||
use yazi_widgets::clear::ClearInventory;
|
||||
|
||||
use crate::{Adapters, SHOWN, drivers};
|
||||
use crate::{ADAPTOR, drivers::{Driver, Drivers}};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Display, Eq, IntoStaticStr, PartialEq)]
|
||||
#[strum(serialize_all = "kebab-case")]
|
||||
pub enum Adapter {
|
||||
Kgp,
|
||||
KgpOld,
|
||||
Iip,
|
||||
Sixel,
|
||||
pub struct Adapter {
|
||||
driver: Driver,
|
||||
shown: SyncCell<Option<Rect>>,
|
||||
pub collision: SyncCell<bool>,
|
||||
}
|
||||
|
||||
// Supported by Überzug++
|
||||
X11,
|
||||
Wayland,
|
||||
Chafa,
|
||||
impl Deref for Adapter {
|
||||
type Target = Driver;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.driver }
|
||||
}
|
||||
|
||||
impl Debug for Adapter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.driver.fmt(f) }
|
||||
}
|
||||
|
||||
impl Adapter {
|
||||
pub async fn image_show<P>(self, path: P, max: Rect) -> Result<Rect>
|
||||
where
|
||||
P: Into<PathBuf>,
|
||||
{
|
||||
if max.is_empty() {
|
||||
return Ok(Rect::default());
|
||||
}
|
||||
|
||||
let path = path.into();
|
||||
match self {
|
||||
Self::Kgp => drivers::Kgp::image_show(path, max).await,
|
||||
Self::KgpOld => drivers::KgpOld::image_show(path, max).await,
|
||||
Self::Iip => drivers::Iip::image_show(path, max).await,
|
||||
Self::Sixel => drivers::Sixel::image_show(path, max).await,
|
||||
Self::X11 | Self::Wayland => drivers::Ueberzug::image_show(path, max).await,
|
||||
Self::Chafa => drivers::Chafa::image_show(path, max).await,
|
||||
pub(super) fn new() -> Self {
|
||||
Self {
|
||||
driver: Drivers::matches(&EMULATOR),
|
||||
shown: SyncCell::new(None),
|
||||
collision: SyncCell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_hide(self) -> Result<()> {
|
||||
if let Some(area) = SHOWN.replace(None) { self.image_erase(area) } else { Ok(()) }
|
||||
pub fn image_hide(&self) -> Result<()> {
|
||||
if let Some(area) = self.shown.replace(None) { self.driver.image_erase(area) } else { Ok(()) }
|
||||
}
|
||||
|
||||
pub fn image_erase(self, area: Rect) -> Result<()> {
|
||||
match self {
|
||||
Self::Kgp => drivers::Kgp::image_erase(area),
|
||||
Self::KgpOld => drivers::KgpOld::image_erase(area),
|
||||
Self::Iip => drivers::Iip::image_erase(area),
|
||||
Self::Sixel => drivers::Sixel::image_erase(area),
|
||||
Self::X11 | Self::Wayland => drivers::Ueberzug::image_erase(area),
|
||||
Self::Chafa => drivers::Chafa::image_erase(area),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn shown_load(self) -> Option<Rect> { SHOWN.get() }
|
||||
|
||||
#[inline]
|
||||
pub(super) fn shown_store(area: Rect) { SHOWN.set(Some(area)); }
|
||||
|
||||
pub(super) fn start(self) { drivers::Ueberzug::start(self); }
|
||||
|
||||
#[inline]
|
||||
pub(super) fn needs_ueberzug(self) -> bool {
|
||||
!matches!(self, Self::Kgp | Self::KgpOld | Self::Iip | Self::Sixel)
|
||||
}
|
||||
pub(super) fn shown_store(&self, area: Rect) { self.shown.set(Some(area)); }
|
||||
}
|
||||
|
||||
impl Adapter {
|
||||
pub fn matches(emulator: &Emulator) -> Self {
|
||||
let mut adapters: Adapters = emulator.into();
|
||||
if env_exists("ZELLIJ_SESSION_NAME") {
|
||||
adapters.retain(|p| *p == Self::Sixel);
|
||||
} else if TMUX.get() {
|
||||
adapters.retain(|p| *p != Self::KgpOld);
|
||||
}
|
||||
if let Some(p) = adapters.first() {
|
||||
return *p;
|
||||
}
|
||||
inventory::submit! {
|
||||
ClearInventory {
|
||||
clear: |area| {
|
||||
let overlap = area.intersection(ADAPTOR.shown.get()?);
|
||||
if overlap.area() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let supported_compositor = drivers::Ueberzug::supported_compositor();
|
||||
match env::var("XDG_SESSION_TYPE").unwrap_or_default().as_str() {
|
||||
"x11" => return Self::X11,
|
||||
"wayland" if supported_compositor => return Self::Wayland,
|
||||
"wayland" if !supported_compositor => return Self::Chafa,
|
||||
_ => warn!("[Adapter] Could not identify XDG_SESSION_TYPE"),
|
||||
}
|
||||
if env_exists("WAYLAND_DISPLAY") {
|
||||
return if supported_compositor { Self::Wayland } else { Self::Chafa };
|
||||
}
|
||||
match env::var("DISPLAY").unwrap_or_default().as_str() {
|
||||
s if !s.is_empty() && !s.contains("/org.xquartz") => return Self::X11,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
warn!("[Adapter] Falling back to chafa");
|
||||
Self::Chafa
|
||||
ADAPTOR.driver.image_erase(overlap).ok();
|
||||
ADAPTOR.collision.set(true);
|
||||
Some(overlap)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::Adapter;
|
||||
|
||||
pub(super) struct Adapters(Vec<Adapter>);
|
||||
|
||||
impl Deref for Adapters {
|
||||
type Target = Vec<Adapter>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl DerefMut for Adapters {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
|
||||
}
|
||||
|
||||
impl From<&yazi_emulator::Emulator> for Adapters {
|
||||
fn from(value: &yazi_emulator::Emulator) -> Self { value.kind.either_into() }
|
||||
}
|
||||
|
||||
impl From<yazi_emulator::Brand> for Adapters {
|
||||
fn from(value: yazi_emulator::Brand) -> Self {
|
||||
use yazi_emulator::Brand as B;
|
||||
|
||||
use crate::Adapter as A;
|
||||
|
||||
Self(match value {
|
||||
B::Kitty => vec![A::Kgp],
|
||||
B::Konsole => vec![A::KgpOld],
|
||||
B::Iterm2 => vec![A::Iip, A::Sixel],
|
||||
B::WezTerm => vec![A::Iip, A::Sixel],
|
||||
B::Foot => vec![A::Sixel],
|
||||
B::Ghostty => vec![A::Kgp],
|
||||
B::Microsoft => vec![A::Sixel],
|
||||
B::Warp => vec![A::Iip, A::KgpOld],
|
||||
B::Rio => vec![A::Kgp],
|
||||
B::BlackBox => vec![A::Sixel],
|
||||
B::VSCode => vec![A::Iip, A::Sixel],
|
||||
B::Tabby => vec![A::Iip, A::Sixel],
|
||||
B::Hyper => vec![A::Iip, A::Sixel],
|
||||
B::Mintty => vec![A::Iip],
|
||||
B::Tmux => vec![],
|
||||
B::VTerm => vec![],
|
||||
B::Apple => vec![],
|
||||
B::Urxvt => vec![],
|
||||
B::Bobcat => vec![A::Iip, A::Sixel],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<yazi_emulator::Unknown> for Adapters {
|
||||
fn from(value: yazi_emulator::Unknown) -> Self {
|
||||
use Adapter as A;
|
||||
|
||||
Self(match (value.kgp, value.sixel) {
|
||||
(true, true) => vec![A::Sixel, A::KgpOld],
|
||||
(true, false) => vec![A::KgpOld],
|
||||
(false, true) => vec![A::Sixel],
|
||||
(false, false) => vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -2,17 +2,18 @@ use std::{io::Write, path::PathBuf, process::Stdio};
|
|||
|
||||
use ansi_to_tui::IntoText;
|
||||
use anyhow::{Result, anyhow, bail};
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui_core::layout::Rect;
|
||||
use tokio::process::Command;
|
||||
use yazi_config::THEME;
|
||||
use yazi_emulator::Emulator;
|
||||
use yazi_term::sequence::MoveTo;
|
||||
use yazi_tty::sequence::{MoveTo, ResetAttrs, SetBg};
|
||||
|
||||
use crate::Adapter;
|
||||
use crate::ADAPTOR;
|
||||
|
||||
pub(crate) struct Chafa;
|
||||
pub(super) struct Chafa;
|
||||
|
||||
impl Chafa {
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let child = Command::new("chafa")
|
||||
.args([
|
||||
"-f",
|
||||
|
|
@ -57,8 +58,8 @@ impl Chafa {
|
|||
height: lines.len() as u16,
|
||||
};
|
||||
|
||||
Adapter::Chafa.image_hide()?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.image_hide()?;
|
||||
ADAPTOR.shown_store(area);
|
||||
Emulator::move_lock((max.x, max.y), |w| {
|
||||
for (i, line) in lines.into_iter().enumerate() {
|
||||
w.write_all(line)?;
|
||||
|
|
@ -68,14 +69,17 @@ impl Chafa {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(area: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |w| {
|
||||
if let Some(c) = THEME.app.overall.get().bg {
|
||||
write!(w, "{}", SetBg(c))?;
|
||||
}
|
||||
for y in area.top()..area.bottom() {
|
||||
write!(w, "{}", MoveTo(area.x, y))?;
|
||||
write!(w, "{s}")?;
|
||||
}
|
||||
Ok(())
|
||||
Ok(write!(w, "{ResetAttrs}")?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
59
yazi-adapter/src/drivers/driver.rs
Normal file
59
yazi-adapter/src/drivers/driver.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use ratatui_core::layout::Rect;
|
||||
use strum::{Display, IntoStaticStr};
|
||||
|
||||
use crate::drivers::{Chafa, Iip, Kgp, KgpOld, Sixel, Ueberzug};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Display, Eq, IntoStaticStr, PartialEq)]
|
||||
#[strum(serialize_all = "kebab-case")]
|
||||
pub enum Driver {
|
||||
Kgp,
|
||||
KgpOld,
|
||||
Iip,
|
||||
Sixel,
|
||||
|
||||
// Supported by Überzug++
|
||||
X11,
|
||||
Wayland,
|
||||
Chafa,
|
||||
}
|
||||
|
||||
impl Driver {
|
||||
pub async fn image_show<P>(self, path: P, max: Rect) -> Result<Rect>
|
||||
where
|
||||
P: Into<PathBuf>,
|
||||
{
|
||||
if max.is_empty() {
|
||||
return Ok(Rect::default());
|
||||
}
|
||||
|
||||
let path = path.into();
|
||||
match self {
|
||||
Self::Kgp => Kgp::image_show(path, max).await,
|
||||
Self::KgpOld => KgpOld::image_show(path, max).await,
|
||||
Self::Iip => Iip::image_show(path, max).await,
|
||||
Self::Sixel => Sixel::image_show(path, max).await,
|
||||
Self::X11 | Self::Wayland => Ueberzug::image_show(path, max).await,
|
||||
Self::Chafa => Chafa::image_show(path, max).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_erase(self, area: Rect) -> Result<()> {
|
||||
match self {
|
||||
Self::Kgp => Kgp::image_erase(area),
|
||||
Self::KgpOld => KgpOld::image_erase(area),
|
||||
Self::Iip => Iip::image_erase(area),
|
||||
Self::Sixel => Sixel::image_erase(area),
|
||||
Self::X11 | Self::Wayland => Ueberzug::image_erase(area),
|
||||
Self::Chafa => Chafa::image_erase(area),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn start(self) { Ueberzug::start(self); }
|
||||
|
||||
pub(crate) fn needs_ueberzug(self) -> bool {
|
||||
!matches!(self, Self::Kgp | Self::KgpOld | Self::Iip | Self::Sixel)
|
||||
}
|
||||
}
|
||||
94
yazi-adapter/src/drivers/drivers.rs
Normal file
94
yazi-adapter/src/drivers/drivers.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
use std::{env, ops::{Deref, DerefMut}};
|
||||
|
||||
use tracing::warn;
|
||||
use yazi_emulator::{Emulator, TMUX};
|
||||
use yazi_shared::env_exists;
|
||||
|
||||
use crate::drivers::{Driver as D, Ueberzug};
|
||||
|
||||
pub(crate) struct Drivers(Vec<D>);
|
||||
|
||||
impl Deref for Drivers {
|
||||
type Target = Vec<D>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl DerefMut for Drivers {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
|
||||
}
|
||||
|
||||
impl From<&yazi_emulator::Emulator> for Drivers {
|
||||
fn from(value: &yazi_emulator::Emulator) -> Self { value.kind.either_into() }
|
||||
}
|
||||
|
||||
impl From<yazi_emulator::Brand> for Drivers {
|
||||
fn from(value: yazi_emulator::Brand) -> Self {
|
||||
use yazi_emulator::Brand as B;
|
||||
|
||||
Self(match value {
|
||||
B::Kitty => vec![D::Kgp],
|
||||
B::Konsole => vec![D::KgpOld],
|
||||
B::Iterm2 => vec![D::Iip, D::Sixel],
|
||||
B::WezTerm => vec![D::Iip, D::Sixel],
|
||||
B::Foot => vec![D::Sixel],
|
||||
B::Ghostty => vec![D::Kgp],
|
||||
B::Microsoft => vec![D::Sixel],
|
||||
B::Warp => vec![D::Iip, D::KgpOld],
|
||||
B::Rio => vec![D::Kgp],
|
||||
B::BlackBox => vec![D::Sixel],
|
||||
B::VSCode => vec![D::Iip, D::Sixel],
|
||||
B::Tabby => vec![D::Iip, D::Sixel],
|
||||
B::Hyper => vec![D::Iip, D::Sixel],
|
||||
B::Mintty => vec![D::Iip],
|
||||
B::Tmux => vec![],
|
||||
B::VTerm => vec![],
|
||||
B::Apple => vec![],
|
||||
B::Urxvt => vec![],
|
||||
B::Bobcat => vec![D::Iip, D::Sixel],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<yazi_emulator::Unknown> for Drivers {
|
||||
fn from(value: yazi_emulator::Unknown) -> Self {
|
||||
Self(match (value.kgp, value.sixel) {
|
||||
(true, true) => vec![D::Sixel, D::KgpOld],
|
||||
(true, false) => vec![D::KgpOld],
|
||||
(false, true) => vec![D::Sixel],
|
||||
(false, false) => vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drivers {
|
||||
pub fn matches(emulator: &Emulator) -> D {
|
||||
let mut adapters: Self = emulator.into();
|
||||
if env_exists("ZELLIJ_SESSION_NAME") {
|
||||
adapters.retain(|p| *p == D::Sixel);
|
||||
} else if TMUX.get() {
|
||||
adapters.retain(|p| *p != D::KgpOld);
|
||||
}
|
||||
if let Some(p) = adapters.first() {
|
||||
return *p;
|
||||
}
|
||||
|
||||
let supported_compositor = Ueberzug::supported_compositor();
|
||||
match env::var("XDG_SESSION_TYPE").unwrap_or_default().as_str() {
|
||||
"x11" => return D::X11,
|
||||
"wayland" if supported_compositor => return D::Wayland,
|
||||
"wayland" if !supported_compositor => return D::Chafa,
|
||||
_ => warn!("[Adapter] Could not identify XDG_SESSION_TYPE"),
|
||||
}
|
||||
if env_exists("WAYLAND_DISPLAY") {
|
||||
return if supported_compositor { D::Wayland } else { D::Chafa };
|
||||
}
|
||||
match env::var("DISPLAY").unwrap_or_default().as_str() {
|
||||
s if !s.is_empty() && !s.contains("/org.xquartz") => return D::X11,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
warn!("[Adapter] Falling back to chafa");
|
||||
D::Chafa
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +1,42 @@
|
|||
use std::{fmt::Write, io::Write as ioWrite, path::PathBuf};
|
||||
use std::{fmt::Write as _, io::Write as _, path::PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
use base64::{Engine, engine::{Config, general_purpose::STANDARD}};
|
||||
use image::{DynamicImage, ExtendedColorType, ImageEncoder, codecs::{jpeg::JpegEncoder, png::PngEncoder}};
|
||||
use ratatui::layout::Rect;
|
||||
use yazi_config::YAZI;
|
||||
use ratatui_core::layout::Rect;
|
||||
use yazi_config::{THEME, YAZI};
|
||||
use yazi_emulator::{CLOSE, Emulator, START};
|
||||
use yazi_term::sequence::MoveTo;
|
||||
use yazi_tty::sequence::{MoveTo, ResetAttrs, SetBg};
|
||||
|
||||
use crate::{Image, adapter::Adapter};
|
||||
use crate::{ADAPTOR, Image};
|
||||
|
||||
pub(crate) struct Iip;
|
||||
pub(super) struct Iip;
|
||||
|
||||
impl Iip {
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
let b = Self::encode(img).await?;
|
||||
|
||||
Adapter::Iip.image_hide()?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.image_hide()?;
|
||||
ADAPTOR.shown_store(area);
|
||||
Emulator::move_lock((max.x, max.y), |w| {
|
||||
w.write_all(&b)?;
|
||||
Ok(area)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(area: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |w| {
|
||||
if let Some(c) = THEME.app.overall.get().bg {
|
||||
write!(w, "{}", SetBg(c))?;
|
||||
}
|
||||
for y in area.top()..area.bottom() {
|
||||
write!(w, "{}", MoveTo(area.x, y))?;
|
||||
write!(w, "{s}")?;
|
||||
}
|
||||
Ok(())
|
||||
Ok(write!(w, "{ResetAttrs}")?)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@ use std::{io::Write, path::PathBuf};
|
|||
use anyhow::Result;
|
||||
use base64::{Engine, engine::general_purpose};
|
||||
use image::DynamicImage;
|
||||
use ratatui::{layout::Rect, style::Color};
|
||||
use ratatui_core::{layout::Rect, style::Color};
|
||||
use yazi_config::THEME;
|
||||
use yazi_emulator::{CLOSE, ESCAPE, Emulator, START};
|
||||
use yazi_shim::cell::SyncCell;
|
||||
use yazi_term::sequence::{MoveTo, SetFg};
|
||||
use yazi_tty::sequence::{MoveTo, ResetAttrs, SetBg, SetFg};
|
||||
|
||||
use crate::{adapter::Adapter, image::Image};
|
||||
use crate::{ADAPTOR, image::Image};
|
||||
|
||||
static DIACRITICS: [char; 297] = [
|
||||
'\u{0305}',
|
||||
|
|
@ -311,18 +312,18 @@ static DIACRITICS: [char; 297] = [
|
|||
'\u{1D244}',
|
||||
];
|
||||
|
||||
pub(crate) struct Kgp;
|
||||
pub(super) struct Kgp;
|
||||
|
||||
impl Kgp {
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
|
||||
let b1 = Self::encode(img).await?;
|
||||
let b2 = Self::place(&area)?;
|
||||
|
||||
Adapter::Kgp.image_hide()?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.image_hide()?;
|
||||
ADAPTOR.shown_store(area);
|
||||
Emulator::move_lock((area.x, area.y), |w| {
|
||||
w.write_all(&b1)?;
|
||||
w.write_all(&b2)?;
|
||||
|
|
@ -330,15 +331,19 @@ impl Kgp {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(area: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |w| {
|
||||
if let Some(c) = THEME.app.overall.get().bg {
|
||||
write!(w, "{}", SetBg(c))?;
|
||||
}
|
||||
|
||||
for y in area.top()..area.bottom() {
|
||||
write!(w, "{}", MoveTo(area.x, y))?;
|
||||
write!(w, "{s}")?;
|
||||
}
|
||||
|
||||
write!(w, "{START}_Gq=2,a=d,d=A{ESCAPE}\\{CLOSE}")?;
|
||||
write!(w, "{ResetAttrs}{START}_Gq=2,a=d,d=A{ESCAPE}\\{CLOSE}")?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -381,12 +386,16 @@ impl Kgp {
|
|||
}
|
||||
|
||||
fn place(area: &Rect) -> Result<Vec<u8>> {
|
||||
let mut buf = Vec::with_capacity(area.width as usize * area.height as usize * 3 + 50);
|
||||
let mut buf = Vec::with_capacity(area.width as usize * area.height as usize * 3 + 500);
|
||||
|
||||
let id = Self::image_id();
|
||||
let (r, g, b) = ((id >> 16) & 0xff, (id >> 8) & 0xff, id & 0xff);
|
||||
write!(buf, "{}", SetFg(Color::Rgb(r as u8, g as u8, b as u8)))?;
|
||||
|
||||
if let Some(c) = THEME.app.overall.get().bg {
|
||||
write!(buf, "{}", SetBg(c))?;
|
||||
}
|
||||
|
||||
for y in 0..area.height {
|
||||
write!(buf, "{}", MoveTo(area.x, area.y + y))?;
|
||||
for x in 0..area.width {
|
||||
|
|
@ -395,6 +404,8 @@ impl Kgp {
|
|||
write!(buf, "{}", *DIACRITICS.get(x as usize).unwrap_or(&DIACRITICS[0]))?;
|
||||
}
|
||||
}
|
||||
|
||||
write!(buf, "{ResetAttrs}")?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,29 +4,29 @@ use std::{io::Write, path::PathBuf};
|
|||
use anyhow::Result;
|
||||
use base64::{Engine, engine::general_purpose};
|
||||
use image::DynamicImage;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui_core::layout::Rect;
|
||||
use yazi_emulator::{CLOSE, ESCAPE, Emulator, START};
|
||||
use yazi_tty::TTY;
|
||||
|
||||
use crate::{Image, adapter::Adapter};
|
||||
use crate::{ADAPTOR, Image};
|
||||
|
||||
pub(crate) struct KgpOld;
|
||||
pub(super) struct KgpOld;
|
||||
|
||||
impl KgpOld {
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
let b = Self::encode(img).await?;
|
||||
|
||||
Adapter::KgpOld.image_hide()?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.image_hide()?;
|
||||
ADAPTOR.shown_store(area);
|
||||
Emulator::move_lock((area.x, area.y), |w| {
|
||||
w.write_all(&b)?;
|
||||
Ok(area)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(_: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(_: Rect) -> Result<()> {
|
||||
let mut w = TTY.lockout();
|
||||
write!(w, "{START}_Gq=2,a=d,d=A{ESCAPE}\\{CLOSE}")?;
|
||||
w.flush()?;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(chafa iip kgp kgp_old sixel ueberzug);
|
||||
yazi_macro::mod_flat!(chafa driver drivers iip kgp kgp_old sixel ueberzug);
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@ use anyhow::{Result, bail};
|
|||
use image::{DynamicImage, GenericImageView, RgbImage};
|
||||
use palette::{Srgb, cast::ComponentsAs};
|
||||
use quantette::{PaletteSize, color_map::IndexedColorMap, wu::{BinnerU8x3, WuU8x3}};
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui_core::layout::Rect;
|
||||
use yazi_config::THEME;
|
||||
use yazi_emulator::{CLOSE, ESCAPE, Emulator, START};
|
||||
use yazi_term::sequence::MoveTo;
|
||||
use yazi_tty::sequence::{MoveTo, ResetAttrs, SetBg};
|
||||
|
||||
use crate::{Image, adapter::Adapter};
|
||||
use crate::{ADAPTOR, Image};
|
||||
|
||||
pub(crate) struct Sixel;
|
||||
pub(super) struct Sixel;
|
||||
|
||||
struct QuantizeOutput<T> {
|
||||
indices: Vec<u8>,
|
||||
|
|
@ -18,27 +19,30 @@ struct QuantizeOutput<T> {
|
|||
}
|
||||
|
||||
impl Sixel {
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
let b = Self::encode(img).await?;
|
||||
|
||||
Adapter::Sixel.image_hide()?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.image_hide()?;
|
||||
ADAPTOR.shown_store(area);
|
||||
Emulator::move_lock((area.x, area.y), |w| {
|
||||
w.write_all(&b)?;
|
||||
Ok(area)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(area: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |w| {
|
||||
if let Some(c) = THEME.app.overall.get().bg {
|
||||
write!(w, "{}", SetBg(c))?;
|
||||
}
|
||||
for y in area.top()..area.bottom() {
|
||||
write!(w, "{}", MoveTo(area.x, y))?;
|
||||
write!(w, "{s}")?;
|
||||
}
|
||||
Ok(())
|
||||
Ok(write!(w, "{ResetAttrs}")?)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{path::PathBuf, process::Stdio};
|
|||
|
||||
use anyhow::{Result, bail};
|
||||
use image::ImageReader;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui_core::layout::Rect;
|
||||
use tokio::{io::AsyncWriteExt, process::{Child, Command}, sync::mpsc::{self, UnboundedSender}};
|
||||
use tracing::{debug, warn};
|
||||
use yazi_config::YAZI;
|
||||
|
|
@ -10,21 +10,21 @@ use yazi_emulator::Dimension;
|
|||
use yazi_shared::{LOG_LEVEL, env_exists};
|
||||
use yazi_shim::{cell::RoCell, strum::IntoStr};
|
||||
|
||||
use crate::Adapter;
|
||||
use crate::{ADAPTOR, drivers::Driver};
|
||||
|
||||
type Cmd = Option<(PathBuf, Rect)>;
|
||||
|
||||
static DEMON: RoCell<Option<UnboundedSender<Cmd>>> = RoCell::new();
|
||||
|
||||
pub(crate) struct Ueberzug;
|
||||
pub(super) struct Ueberzug;
|
||||
|
||||
impl Ueberzug {
|
||||
pub(crate) fn start(adapter: Adapter) {
|
||||
if !adapter.needs_ueberzug() {
|
||||
pub(super) fn start(driver: Driver) {
|
||||
if !driver.needs_ueberzug() {
|
||||
return DEMON.init(None);
|
||||
}
|
||||
|
||||
let mut child = Self::create_demon(adapter).ok();
|
||||
let mut child = Self::create_demon(driver).ok();
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
|
||||
tokio::spawn(async move {
|
||||
|
|
@ -34,17 +34,17 @@ impl Ueberzug {
|
|||
child = None;
|
||||
}
|
||||
if child.is_none() {
|
||||
child = Self::create_demon(adapter).ok();
|
||||
child = Self::create_demon(driver).ok();
|
||||
}
|
||||
if let Some(c) = &mut child {
|
||||
Self::send_command(adapter, c, cmd).await.ok();
|
||||
Self::send_command(driver, c, cmd).await.ok();
|
||||
}
|
||||
}
|
||||
});
|
||||
DEMON.init(Some(tx))
|
||||
}
|
||||
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let Some(tx) = &*DEMON else {
|
||||
bail!("uninitialized ueberzugpp");
|
||||
};
|
||||
|
|
@ -64,11 +64,11 @@ impl Ueberzug {
|
|||
.unwrap_or(max);
|
||||
|
||||
tx.send(Some((path, area)))?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.shown_store(area);
|
||||
Ok(area)
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(_: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(_: Rect) -> Result<()> {
|
||||
if let Some(tx) = &*DEMON {
|
||||
Ok(tx.send(None)?)
|
||||
} else {
|
||||
|
|
@ -79,16 +79,16 @@ impl Ueberzug {
|
|||
// Currently Überzug++'s Wayland output only supports Niri, Sway, Hyprland and
|
||||
// Wayfire as it requires information from specific compositor socket directly.
|
||||
// These environment variables are from ueberzugpp src/canvas/wayland/config.cpp
|
||||
pub(crate) fn supported_compositor() -> bool {
|
||||
pub(super) fn supported_compositor() -> bool {
|
||||
env_exists("NIRI_SOCKET")
|
||||
|| env_exists("SWAYSOCK")
|
||||
|| env_exists("HYPRLAND_INSTANCE_SIGNATURE")
|
||||
|| env_exists("WAYFIRE_SOCKET")
|
||||
}
|
||||
|
||||
fn create_demon(adapter: Adapter) -> Result<Child> {
|
||||
fn create_demon(driver: Driver) -> Result<Child> {
|
||||
let result = Command::new("ueberzugpp")
|
||||
.args(["layer", "-so", adapter.into_str()])
|
||||
.args(["layer", "-so", driver.into_str()])
|
||||
.env("SPDLOG_LEVEL", if LOG_LEVEL.get().is_none() { "" } else { "debug" })
|
||||
.kill_on_drop(true)
|
||||
.stdin(Stdio::piped())
|
||||
|
|
@ -113,7 +113,7 @@ impl Ueberzug {
|
|||
rect
|
||||
}
|
||||
|
||||
async fn send_command(adapter: Adapter, child: &mut Child, cmd: Cmd) -> Result<()> {
|
||||
async fn send_command(driver: Driver, child: &mut Child, cmd: Cmd) -> Result<()> {
|
||||
let s = if let Some((path, rect)) = cmd {
|
||||
debug!("ueberzugpp rect before adjustment: {:?}", rect);
|
||||
let rect = Self::adjust_rect(rect);
|
||||
|
|
@ -132,7 +132,7 @@ impl Ueberzug {
|
|||
format!(r#"{{"action":"remove","identifier":"yazi"}}{}"#, '\n')
|
||||
};
|
||||
|
||||
debug!("`ueberzugpp layer -so {adapter}` command: {s}");
|
||||
debug!("`ueberzugpp layer -so {driver}` command: {s}");
|
||||
child.stdin.as_mut().unwrap().write_all(s.as_bytes()).await?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use image::{ColorType, DynamicImage, GrayAlphaImage, GrayImage, ImageDecoder, Rg
|
|||
use moxcms::{CicpColorPrimaries, ColorProfile, DataColorSpace, Layout, TransferCharacteristics, TransformOptions};
|
||||
|
||||
pub(super) struct Icc;
|
||||
|
||||
impl Icc {
|
||||
pub(super) fn transform(mut decoder: impl ImageDecoder) -> anyhow::Result<DynamicImage> {
|
||||
if let Some(layout) = Self::color_type_to_layout(decoder.color_type())
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use anyhow::Result;
|
||||
use image::{DynamicImage, ImageDecoder, ImageError, ImageReader, Limits, codecs::{jpeg::JpegEncoder, png::PngEncoder}, imageops::FilterType, metadata::Orientation};
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui_core::layout::Rect;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_emulator::Dimension;
|
||||
use yazi_fs::provider::{Provider, local::Local};
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use image::{ImageDecoder, ImageError};
|
||||
|
||||
pub type ImageFormat = image::ImageFormat;
|
||||
pub type ImageColor = image::ColorType;
|
||||
pub type ImageOrientation = image::metadata::Orientation;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ImageInfo {
|
||||
pub format: ImageFormat,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub color: ImageColor,
|
||||
pub orientation: Option<ImageOrientation>,
|
||||
}
|
||||
|
||||
impl ImageInfo {
|
||||
pub async fn new(path: PathBuf) -> image::ImageResult<Self> {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let reader = image::ImageReader::open(path)?.with_guessed_format()?;
|
||||
|
||||
let Some(format) = reader.format() else {
|
||||
return Err(ImageError::IoError(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"unknown image format",
|
||||
)));
|
||||
};
|
||||
|
||||
let mut decoder = reader.into_decoder()?;
|
||||
let (width, height) = decoder.dimensions();
|
||||
Ok(Self {
|
||||
format,
|
||||
width,
|
||||
height,
|
||||
color: decoder.color_type(),
|
||||
orientation: decoder.orientation().ok(),
|
||||
})
|
||||
})
|
||||
.await
|
||||
.map_err(|e| ImageError::IoError(e.into()))?
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,12 @@
|
|||
yazi_macro::mod_pub!(drivers);
|
||||
|
||||
yazi_macro::mod_flat!(adapter adapters icc image info);
|
||||
yazi_macro::mod_flat!(adapter icc image);
|
||||
|
||||
use yazi_emulator::{Brand, CLOSE, EMULATOR, ESCAPE, Emulator, Mux, START, TMUX};
|
||||
use yazi_shared::in_wsl;
|
||||
use yazi_shim::cell::SyncCell;
|
||||
use yazi_shim::cell::{RoCell, SyncCell};
|
||||
|
||||
pub static ADAPTOR: SyncCell<Adapter> = SyncCell::new(Adapter::Chafa);
|
||||
|
||||
// Image state
|
||||
static SHOWN: SyncCell<Option<ratatui::layout::Rect>> = SyncCell::new(None);
|
||||
pub static ADAPTOR: RoCell<Adapter> = RoCell::new();
|
||||
|
||||
// WSL support
|
||||
pub static WSL: SyncCell<bool> = SyncCell::new(false);
|
||||
|
|
@ -34,7 +31,7 @@ pub fn init() -> anyhow::Result<()> {
|
|||
EMULATOR.init(emulator);
|
||||
yazi_config::init_flavor(EMULATOR.light)?;
|
||||
|
||||
ADAPTOR.set(Adapter::matches(&EMULATOR));
|
||||
ADAPTOR.get().start();
|
||||
ADAPTOR.init(Adapter::new());
|
||||
ADAPTOR.start();
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,30 +17,24 @@ default = [ "vendored-lua" ]
|
|||
vendored-lua = [ "mlua/vendored" ]
|
||||
|
||||
[dependencies]
|
||||
yazi-adapter = { path = "../yazi-adapter", version = "26.5.6" }
|
||||
yazi-codegen = { path = "../yazi-codegen", version = "26.5.6" }
|
||||
yazi-config = { path = "../yazi-config", version = "26.5.6" }
|
||||
yazi-fs = { path = "../yazi-fs", version = "26.5.6" }
|
||||
yazi-macro = { path = "../yazi-macro", version = "26.5.6" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "26.5.6" }
|
||||
yazi-shim = { path = "../yazi-shim", version = "26.5.6" }
|
||||
yazi-term = { path = "../yazi-term", version = "26.5.6" }
|
||||
yazi-vfs = { path = "../yazi-vfs", version = "26.5.6" }
|
||||
yazi-widgets = { path = "../yazi-widgets", version = "26.5.6" }
|
||||
|
||||
# External dependencies
|
||||
ansi-to-tui = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
paste = { workspace = true }
|
||||
ratatui = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
ansi-to-tui = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
image = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
ratatui-core = { workspace = true }
|
||||
ratatui-widgets = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
use mlua::{AnyUserData, IntoLuaMulti, UserData, UserDataMethods, Value};
|
||||
use yazi_fs::provider::FileBuilder;
|
||||
|
||||
use crate::{Error, Fd, UrlRef};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Access(yazi_vfs::provider::Gate);
|
||||
|
||||
impl UserData for Access {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_function("append", |_, (ud, append): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.append(append);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("create", |_, (ud, create): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.create(create);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("create_new", |_, (ud, create_new): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.create_new(create_new);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_async_method("open", |lua, me, url: UrlRef| async move {
|
||||
match me.0.open(&*url).await {
|
||||
Ok(fd) => Fd(fd).into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
});
|
||||
methods.add_function("read", |_, (ud, read): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.read(read);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("truncate", |_, (ud, truncate): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.truncate(truncate);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("write", |_, (ud, write): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.write(write);
|
||||
Ok(ud)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
use mlua::UserData;
|
||||
use yazi_codegen::FromLuaOwned;
|
||||
|
||||
#[derive(Clone, FromLuaOwned)]
|
||||
pub struct ChordCow(pub yazi_config::keymap::ChordCow);
|
||||
|
||||
impl From<yazi_config::keymap::ChordCow> for ChordCow {
|
||||
fn from(value: yazi_config::keymap::ChordCow) -> Self { Self(value) }
|
||||
}
|
||||
|
||||
impl From<ChordCow> for yazi_config::keymap::ChordCow {
|
||||
fn from(value: ChordCow) -> Self { value.0 }
|
||||
}
|
||||
|
||||
impl UserData for ChordCow {}
|
||||
|
|
@ -5,10 +5,9 @@ pub type ComposerGet = fn(&Lua, &[u8]) -> mlua::Result<Value>;
|
|||
pub type ComposerSet = fn(&Lua, &[u8], Value) -> mlua::Result<Value>;
|
||||
|
||||
pub struct Composer<G, S> {
|
||||
get: G,
|
||||
set: S,
|
||||
parent: Option<(G, S)>,
|
||||
cache: HashMap<Vec<u8>, Value>,
|
||||
get: G,
|
||||
set: S,
|
||||
cache: HashMap<Vec<u8>, Value>,
|
||||
}
|
||||
|
||||
impl<G, S> Composer<G, S>
|
||||
|
|
@ -16,13 +15,7 @@ where
|
|||
G: Fn(&Lua, &[u8]) -> mlua::Result<Value> + 'static,
|
||||
S: Fn(&Lua, &[u8], Value) -> mlua::Result<Value> + 'static,
|
||||
{
|
||||
#[inline]
|
||||
pub fn new(get: G, set: S) -> Self { Self { get, set, parent: None, cache: Default::default() } }
|
||||
|
||||
#[inline]
|
||||
pub fn with_parent(get: G, set: S, p_get: G, p_set: S) -> Self {
|
||||
Self { get, set, parent: Some((p_get, p_set)), cache: Default::default() }
|
||||
}
|
||||
pub fn new(get: G, set: S) -> Self { Self { get, set, cache: Default::default() } }
|
||||
}
|
||||
|
||||
impl<G, S> UserData for Composer<G, S>
|
||||
|
|
@ -37,14 +30,9 @@ where
|
|||
return Ok(v.clone());
|
||||
}
|
||||
|
||||
let mut value = (me.get)(lua, &key)?;
|
||||
if value.is_nil()
|
||||
&& let Some((p_get, _)) = &me.parent
|
||||
{
|
||||
value = p_get(lua, &key)?;
|
||||
}
|
||||
|
||||
let value = (me.get)(lua, &key)?;
|
||||
me.cache.insert(key.to_owned(), value.clone());
|
||||
|
||||
Ok(value)
|
||||
});
|
||||
|
||||
|
|
@ -56,11 +44,6 @@ where
|
|||
|
||||
if value.is_nil() {
|
||||
me.cache.remove(key.as_ref());
|
||||
} else if let Some((_, p_set)) = &me.parent {
|
||||
match p_set(lua, key.as_ref(), value)? {
|
||||
Value::Nil => me.cache.remove(key.as_ref()),
|
||||
v => me.cache.insert(key.to_owned(), v),
|
||||
};
|
||||
} else {
|
||||
me.cache.insert(key.to_owned(), value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields, Value};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::{FileRef, Id, Iter, cached_field};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Fetcher {
|
||||
inner: Arc<yazi_config::plugin::Fetcher>,
|
||||
|
||||
v_name: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Fetcher {
|
||||
type Target = yazi_config::plugin::Fetcher;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Fetcher {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::plugin::Fetcher>>) -> Self {
|
||||
Self { inner: inner.into(), v_name: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Fetcher {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
|
||||
cached_field!(fields, name, |lua, me| lua.create_string(&*me.name));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct FetcherMatcher(yazi_config::plugin::FetcherMatcher<'static>);
|
||||
|
||||
impl FetcherMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::plugin::FetcherMatcher<'static>>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for FetcherMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = value.raw_get("id").unwrap_or_default();
|
||||
let file: Option<FileRef> = value.raw_get("file")?;
|
||||
let mime: Option<String> = value.raw_get("mime")?;
|
||||
|
||||
Ok(Self(yazi_config::plugin::FetcherMatcher {
|
||||
fetchers: YAZI.plugin.fetchers.load_full(),
|
||||
id: id.0,
|
||||
file: file.map(|f| f.inner.clone().into()),
|
||||
mime: mime.map(Into::into),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for FetcherMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of FetcherMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for FetcherMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(Fetcher::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
use mlua::{IntoLua, MetaMethod, UserData, UserDataMethods};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::config::FetcherMatcher;
|
||||
|
||||
pub struct Fetchers;
|
||||
|
||||
impl UserData for Fetchers {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |lua, _, matcher: Option<FetcherMatcher>| match matcher {
|
||||
Some(matcher) => matcher.into_lua(lua),
|
||||
None => FetcherMatcher::new(&YAZI.plugin.fetchers).into_lua(lua),
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, _, ()| Ok(YAZI.plugin.fetchers.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
yazi_macro::mod_flat!(fetcher fetchers open_rule open_rules opener opener_rule opener_rules preloader preloaders previewer previewers spotter spotters);
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, LuaSerdeExt, Table, UserData, UserDataFields, Value};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::{FileRef, Id, Iter, cached_field};
|
||||
|
||||
pub struct OpenRule {
|
||||
inner: Arc<yazi_config::open::OpenRule>,
|
||||
|
||||
v_use: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for OpenRule {
|
||||
type Target = Arc<yazi_config::open::OpenRule>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl From<OpenRule> for Arc<yazi_config::open::OpenRule> {
|
||||
fn from(value: OpenRule) -> Self { value.inner }
|
||||
}
|
||||
|
||||
impl OpenRule {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::open::OpenRule>>) -> Self {
|
||||
Self { inner: inner.into(), v_use: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for OpenRule {
|
||||
fn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {
|
||||
Ok(Self::new(lua.from_value::<yazi_config::open::OpenRule>(value)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for OpenRule {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
cached_field!(fields, use, |lua, me| {
|
||||
lua.create_sequence_from(me.r#use.iter().map(|s| s.as_str()))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct OpenRuleMatcher(pub(super) yazi_config::open::OpenRuleMatcher<'static>);
|
||||
|
||||
impl OpenRuleMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::open::OpenRuleMatcher<'static>>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for OpenRuleMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = value.raw_get("id").unwrap_or_default();
|
||||
let file: Option<FileRef> = value.raw_get("file")?;
|
||||
let mime: Option<String> = value.raw_get("mime")?;
|
||||
|
||||
Ok(Self(yazi_config::open::OpenRuleMatcher {
|
||||
rules: YAZI.open.load_full(),
|
||||
id: id.0,
|
||||
file: file.map(|f| f.inner.clone().into()),
|
||||
mime: mime.map(Into::into),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for OpenRuleMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of OpenRuleMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for OpenRuleMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(OpenRule::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
use mlua::{ExternalError, ExternalResult, IntoLua, MetaMethod, Table, UserData, UserDataMethods};
|
||||
use yazi_config::YAZI;
|
||||
use yazi_shim::mlua::DeserializeOverLua;
|
||||
|
||||
use crate::config::{OpenRule, OpenRuleMatcher};
|
||||
|
||||
pub struct OpenRules;
|
||||
|
||||
impl UserData for OpenRules {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |lua, _, matcher: Option<OpenRuleMatcher>| match matcher {
|
||||
Some(matcher) => matcher.into_lua(lua),
|
||||
None => OpenRuleMatcher::new(&*YAZI.open).into_lua(lua),
|
||||
});
|
||||
|
||||
methods.add_method("insert", |_, _, (index, rule): (isize, OpenRule)| {
|
||||
let index = match index {
|
||||
1.. => index - 1,
|
||||
0 => return Err("index must be 1-based or negative".into_lua_err()),
|
||||
_ => index,
|
||||
};
|
||||
|
||||
YAZI.open.insert(index, rule.clone()).into_lua_err()?;
|
||||
Ok(rule)
|
||||
});
|
||||
|
||||
methods.add_method("remove", |_, _, matcher: OpenRuleMatcher| {
|
||||
YAZI.open.remove(matcher.0);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method("update", |_, _, (matcher, table): (OpenRuleMatcher, Table)| {
|
||||
YAZI.open.update(matcher.0, |rule| rule.deserialize_over_lua(&table))?;
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, _, ()| Ok(YAZI.open.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
use mlua::{ExternalError, FromLua, IntoLua, IntoLuaMulti, MetaMethod, UserData, UserDataMethods, Value};
|
||||
use yazi_config::{YAZI, opener::OpenerRulesMatcher};
|
||||
|
||||
use crate::config::OpenerRules;
|
||||
|
||||
pub struct Opener;
|
||||
|
||||
impl UserData for Opener {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(MetaMethod::Index, |lua, _, key: mlua::String| {
|
||||
let key = key.to_str()?;
|
||||
match YAZI.opener.load().get(&*key) {
|
||||
Some(rules) => OpenerRules::new(rules.clone()).into_lua(lua),
|
||||
None => Ok(Value::Nil),
|
||||
}
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::NewIndex, |lua, _, (key, value): (mlua::String, Value)| {
|
||||
let key = key.to_str()?;
|
||||
match value {
|
||||
t @ Value::Table(_) => {
|
||||
YAZI.opener.insert(&key, &*OpenerRules::from_lua(t, lua)?);
|
||||
}
|
||||
Value::Nil => {
|
||||
YAZI.opener.remove(&key);
|
||||
}
|
||||
_ => return Err("expected a table or nil".into_lua_err()),
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Pairs, |lua, _, ()| {
|
||||
let mut matcher = OpenerRulesMatcher::from(&YAZI.opener);
|
||||
let iter = lua.create_function_mut(move |lua, ()| {
|
||||
if let Some((name, rules)) = matcher.next() {
|
||||
(name, OpenerRules::new(rules)).into_lua_multi(lua)
|
||||
} else {
|
||||
().into_lua_multi(lua)
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(iter)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, LuaSerdeExt, Table, UserData, UserDataFields, Value};
|
||||
|
||||
use crate::{Id, Iter, cached_field};
|
||||
|
||||
pub struct OpenerRule {
|
||||
inner: Arc<yazi_config::opener::OpenerRule>,
|
||||
|
||||
v_run: Option<Value>,
|
||||
v_desc: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for OpenerRule {
|
||||
type Target = Arc<yazi_config::opener::OpenerRule>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl From<OpenerRule> for Arc<yazi_config::opener::OpenerRule> {
|
||||
fn from(value: OpenerRule) -> Self { value.inner }
|
||||
}
|
||||
|
||||
impl OpenerRule {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::opener::OpenerRule>>) -> Self {
|
||||
Self { inner: inner.into(), v_run: None, v_desc: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for OpenerRule {
|
||||
fn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {
|
||||
let mut inner: yazi_config::opener::OpenerRule = lua.from_value(value)?;
|
||||
inner.fill();
|
||||
|
||||
Ok(Self::new(inner))
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for OpenerRule {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
cached_field!(fields, run, |lua, me| lua.create_string(&*me.run));
|
||||
fields.add_field_method_get("block", |_, me| Ok(me.block));
|
||||
fields.add_field_method_get("orphan", |_, me| Ok(me.orphan));
|
||||
cached_field!(fields, desc, |lua, me| lua.create_string(&*me.desc));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct OpenerRuleMatcher(pub(super) yazi_config::opener::OpenerRuleMatcher);
|
||||
|
||||
impl OpenerRuleMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::opener::OpenerRuleMatcher>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for OpenerRuleMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(t: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = t.raw_get("id").unwrap_or_default();
|
||||
|
||||
Ok(Self(yazi_config::opener::OpenerRuleMatcher { id: id.0, ..Default::default() }))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for OpenerRuleMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of OpenerRuleMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for OpenerRuleMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(OpenerRule::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, ExternalResult, FromLua, IntoLua, Lua, LuaSerdeExt, MetaMethod, UserData, UserDataMethods, Value};
|
||||
use yazi_shim::toml::DeserializeOverHook;
|
||||
|
||||
use crate::config::{OpenerRule, OpenerRuleMatcher};
|
||||
|
||||
pub struct OpenerRules {
|
||||
inner: Arc<yazi_config::opener::OpenerRules>,
|
||||
}
|
||||
|
||||
impl Deref for OpenerRules {
|
||||
type Target = Arc<yazi_config::opener::OpenerRules>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl OpenerRules {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::opener::OpenerRules>>) -> Self {
|
||||
Self { inner: inner.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for OpenerRules {
|
||||
fn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {
|
||||
let inner: yazi_config::opener::OpenerRules = lua.from_value(value)?;
|
||||
|
||||
Ok(Self::new(inner.deserialize_over_hook().into_lua_err()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for OpenerRules {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |lua, me, matcher: Option<OpenerRuleMatcher>| match matcher {
|
||||
Some(matcher) => matcher.into_lua(lua),
|
||||
None => OpenerRuleMatcher::new(&*me.inner).into_lua(lua),
|
||||
});
|
||||
|
||||
methods.add_method("insert", |_, me, (index, rule): (isize, OpenerRule)| {
|
||||
let index = match index {
|
||||
1.. => index - 1,
|
||||
0 => return Err("index must be 1-based or negative".into_lua_err()),
|
||||
_ => index,
|
||||
};
|
||||
|
||||
me.inner.insert(index, rule.clone()).into_lua_err()?;
|
||||
Ok(rule)
|
||||
});
|
||||
|
||||
methods.add_method("remove", |_, me, matcher: OpenerRuleMatcher| {
|
||||
me.inner.remove(matcher.0);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.inner.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields, Value};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::{FileRef, Id, Iter, cached_field};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Preloader {
|
||||
inner: Arc<yazi_config::plugin::Preloader>,
|
||||
|
||||
v_name: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Preloader {
|
||||
type Target = yazi_config::plugin::Preloader;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Preloader {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::plugin::Preloader>>) -> Self {
|
||||
Self { inner: inner.into(), v_name: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Preloader {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
|
||||
cached_field!(fields, name, |lua, me| lua.create_string(&*me.name));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct PreloaderMatcher(pub(super) yazi_config::plugin::PreloaderMatcher<'static>);
|
||||
|
||||
impl PreloaderMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::plugin::PreloaderMatcher<'static>>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for PreloaderMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = value.raw_get("id").unwrap_or_default();
|
||||
let file: Option<FileRef> = value.raw_get("file")?;
|
||||
let mime: Option<String> = value.raw_get("mime")?;
|
||||
|
||||
Ok(Self(yazi_config::plugin::PreloaderMatcher {
|
||||
preloaders: YAZI.plugin.preloaders.load_full(),
|
||||
id: id.0,
|
||||
file: file.map(|f| f.inner.clone().into()),
|
||||
mime: mime.map(Into::into),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for PreloaderMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of PreloaderMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for PreloaderMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(Preloader::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
use mlua::{IntoLua, MetaMethod, UserData, UserDataMethods};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::config::PreloaderMatcher;
|
||||
|
||||
pub struct Preloaders;
|
||||
|
||||
impl UserData for Preloaders {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |lua, _, matcher: Option<PreloaderMatcher>| match matcher {
|
||||
Some(matcher) => matcher.into_lua(lua),
|
||||
None => PreloaderMatcher::new(&YAZI.plugin.preloaders).into_lua(lua),
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, _, ()| Ok(YAZI.plugin.preloaders.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, LuaSerdeExt, Table, UserData, UserDataFields, Value};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::{FileRef, Id, Iter, cached_field};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Previewer {
|
||||
inner: Arc<yazi_config::plugin::Previewer>,
|
||||
|
||||
v_name: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Previewer {
|
||||
type Target = yazi_config::plugin::Previewer;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl From<Previewer> for Arc<yazi_config::plugin::Previewer> {
|
||||
fn from(value: Previewer) -> Self { value.inner }
|
||||
}
|
||||
|
||||
impl Previewer {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::plugin::Previewer>>) -> Self {
|
||||
Self { inner: inner.into(), v_name: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for Previewer {
|
||||
fn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {
|
||||
Ok(Self::new(lua.from_value::<yazi_config::plugin::Previewer>(value)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Previewer {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
|
||||
cached_field!(fields, name, |lua, me| lua.create_string(&*me.name));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct PreviewerMatcher(pub(super) yazi_config::plugin::PreviewerMatcher<'static>);
|
||||
|
||||
impl PreviewerMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::plugin::PreviewerMatcher<'static>>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for PreviewerMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = value.raw_get("id").unwrap_or_default();
|
||||
let file: Option<FileRef> = value.raw_get("file")?;
|
||||
let mime: Option<String> = value.raw_get("mime")?;
|
||||
|
||||
Ok(Self(yazi_config::plugin::PreviewerMatcher {
|
||||
previewers: YAZI.plugin.previewers.load_full(),
|
||||
id: id.0,
|
||||
file: file.map(|f| f.inner.clone().into()),
|
||||
mime: mime.map(Into::into),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for PreviewerMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of PreviewerMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for PreviewerMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(Previewer::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
use mlua::{ExternalError, ExternalResult, IntoLua, MetaMethod, UserData, UserDataMethods};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::config::{Previewer, PreviewerMatcher};
|
||||
|
||||
pub struct Previewers;
|
||||
|
||||
impl UserData for Previewers {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |lua, _, matcher: Option<PreviewerMatcher>| match matcher {
|
||||
Some(matcher) => matcher.into_lua(lua),
|
||||
None => PreviewerMatcher::new(&YAZI.plugin.previewers).into_lua(lua),
|
||||
});
|
||||
|
||||
methods.add_method("insert", |_, _, (index, previewer): (isize, Previewer)| {
|
||||
let index = match index {
|
||||
1.. => index - 1,
|
||||
0 => return Err("index must be 1-based or negative".into_lua_err()),
|
||||
_ => index,
|
||||
};
|
||||
|
||||
YAZI.plugin.previewers.insert(index, previewer.clone().into()).into_lua_err()?;
|
||||
Ok(previewer)
|
||||
});
|
||||
|
||||
methods.add_method("remove", |_, _, matcher: PreviewerMatcher| {
|
||||
YAZI.plugin.previewers.remove(matcher.0);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, _, ()| Ok(YAZI.plugin.previewers.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields, Value};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::{FileRef, Id, Iter, cached_field};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Spotter {
|
||||
inner: Arc<yazi_config::plugin::Spotter>,
|
||||
|
||||
v_name: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Spotter {
|
||||
type Target = yazi_config::plugin::Spotter;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Spotter {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::plugin::Spotter>>) -> Self {
|
||||
Self { inner: inner.into(), v_name: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Spotter {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
|
||||
cached_field!(fields, name, |lua, me| lua.create_string(&*me.name));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct SpotterMatcher(pub(super) yazi_config::plugin::SpotterMatcher<'static>);
|
||||
|
||||
impl SpotterMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::plugin::SpotterMatcher<'static>>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for SpotterMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = value.raw_get("id").unwrap_or_default();
|
||||
let file: Option<FileRef> = value.raw_get("file")?;
|
||||
let mime: Option<String> = value.raw_get("mime")?;
|
||||
|
||||
Ok(Self(yazi_config::plugin::SpotterMatcher {
|
||||
spotters: YAZI.plugin.spotters.load_full(),
|
||||
id: id.0,
|
||||
file: file.map(|f| f.inner.clone().into()),
|
||||
mime: mime.map(Into::into),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for SpotterMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of SpotterMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for SpotterMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(Spotter::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue