mirror of
https://github.com/sxyazi/yazi.git
synced 2024-09-11 18:38:19 +03:00
Merge branch 'main' into preview-word-wrap
This commit is contained in:
commit
c078fb8513
85
Cargo.lock
generated
85
Cargo.lock
generated
@ -218,6 +218,15 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block2"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
|
||||
dependencies = [
|
||||
"objc2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.9.1"
|
||||
@ -970,9 +979,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "imagesize"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284"
|
||||
checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
@ -1150,15 +1159,6 @@ dependencies = [
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.10.6"
|
||||
@ -1205,9 +1205,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mlua"
|
||||
version = "0.9.8"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e340c022072f3208a4105458286f4985ba5355bfe243c3073afe45cbe9ecf491"
|
||||
checksum = "d111deb18a9c9bd33e1541309f4742523bfab01d276bfa9a27519f6de9c11dc7"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"erased-serde",
|
||||
@ -1223,9 +1223,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mlua-sys"
|
||||
version = "0.6.0"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5552e7e4e22ada0463dfdeee6caf6dc057a189fdc83136408a8f950a5e5c5540"
|
||||
checksum = "a088ed0723df7567f569ba018c5d48c23c501f3878b190b04144dfa5ebfa8abc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
@ -1328,12 +1328,37 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.7"
|
||||
name = "objc-sys"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||
checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
|
||||
|
||||
[[package]]
|
||||
name = "objc2"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
|
||||
dependencies = [
|
||||
"malloc_buf",
|
||||
"objc-sys",
|
||||
"objc2-encode",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-encode"
|
||||
version = "4.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8"
|
||||
|
||||
[[package]]
|
||||
name = "objc2-foundation"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"block2",
|
||||
"libc",
|
||||
"objc2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1652,9 +1677,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
@ -2210,17 +2235,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "trash"
|
||||
version = "4.1.1"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c254b119cf49bdde3dfef21b1dc492dc8026b75566ca24aa77993eccd7cbc1b5"
|
||||
checksum = "8d8fbfb70b1fad5c0b788f9b2e1bf4d04e5ac6efa828f1ed9ee462c50ff9cf05"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"libc",
|
||||
"log",
|
||||
"objc",
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
"once_cell",
|
||||
"scopeguard",
|
||||
"url",
|
||||
"urlencoding",
|
||||
"windows",
|
||||
]
|
||||
|
||||
@ -2284,6 +2310,12 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urlencoding"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
@ -2758,7 +2790,6 @@ dependencies = [
|
||||
"indexmap",
|
||||
"ratatui",
|
||||
"serde",
|
||||
"shell-words",
|
||||
"toml",
|
||||
"validator",
|
||||
"yazi-shared",
|
||||
@ -2924,7 +2955,6 @@ dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"crossterm",
|
||||
"dirs",
|
||||
"filetime",
|
||||
"futures",
|
||||
"libc",
|
||||
"parking_lot",
|
||||
@ -2934,7 +2964,6 @@ dependencies = [
|
||||
"serde",
|
||||
"shell-words",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -13,15 +13,15 @@ yazi-config = { path = "../yazi-config", version = "0.2.5" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "0.2.5" }
|
||||
|
||||
# External dependencies
|
||||
ansi-to-tui = "3.1.0"
|
||||
ansi-to-tui = "=3.1.0"
|
||||
anyhow = "1.0.86"
|
||||
arc-swap = "1.7.1"
|
||||
base64 = "0.22.1"
|
||||
color_quant = "1.1.0"
|
||||
crossterm = "0.27.0"
|
||||
futures = "0.3.30"
|
||||
image = "0.24.9"
|
||||
imagesize = "0.12.0"
|
||||
image = "=0.24.9"
|
||||
imagesize = "0.13.0"
|
||||
kamadak-exif = "0.5.5"
|
||||
ratatui = "0.26.3"
|
||||
scopeguard = "1.2.0"
|
||||
|
@ -37,6 +37,10 @@ impl Display for Adapter {
|
||||
|
||||
impl Adapter {
|
||||
pub async fn image_show(self, path: &Path, max: Rect) -> Result<Rect> {
|
||||
if max.is_empty() {
|
||||
return Ok(Rect::default());
|
||||
}
|
||||
|
||||
match self {
|
||||
Self::Kitty => Kitty::image_show(path, max).await,
|
||||
Self::KittyOld => KittyOld::image_show(path, max).await,
|
||||
|
@ -22,6 +22,8 @@ pub(super) enum Command {
|
||||
PubStatic(CommandPubStatic),
|
||||
/// Manage packages.
|
||||
Pack(CommandPack),
|
||||
/// Subscribe to messages from all remote instances.
|
||||
Sub(CommandSub),
|
||||
}
|
||||
|
||||
#[derive(clap::Args)]
|
||||
@ -109,3 +111,10 @@ pub(super) struct CommandPack {
|
||||
#[arg(short = 'u', long)]
|
||||
pub(super) upgrade: bool,
|
||||
}
|
||||
|
||||
#[derive(clap::Args)]
|
||||
pub(super) struct CommandSub {
|
||||
/// The kind of messages to subscribe to, separated by commas if multiple.
|
||||
#[arg(index = 1)]
|
||||
pub(super) kinds: String,
|
||||
}
|
||||
|
@ -46,6 +46,13 @@ async fn main() -> anyhow::Result<()> {
|
||||
package::Package::add_to_config(repo).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Command::Sub(cmd) => {
|
||||
yazi_dds::init();
|
||||
yazi_dds::Client::draw(cmd.kinds.split(',').collect()).await?;
|
||||
|
||||
tokio::signal::ctrl_c().await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -20,6 +20,5 @@ globset = "0.4.14"
|
||||
indexmap = "2.2.6"
|
||||
ratatui = "0.26.3"
|
||||
serde = { version = "1.0.203", features = [ "derive" ] }
|
||||
shell-words = "1.1.0"
|
||||
toml = { version = "0.8.14", features = [ "preserve_order" ] }
|
||||
validator = { version = "0.18.1", features = [ "derive" ] }
|
||||
|
@ -30,8 +30,8 @@ ueberzug_offset = [ 0, 0, 0, 0 ]
|
||||
[opener]
|
||||
edit = [
|
||||
{ run = '${EDITOR:=vi} "$@"', desc = "$EDITOR", block = true, for = "unix" },
|
||||
{ run = 'code "%*"', orphan = true, desc = "code", for = "windows" },
|
||||
{ run = 'code -w "%*"', block = true, desc = "code (block)", for = "windows" },
|
||||
{ run = 'code %*', orphan = true, desc = "code", for = "windows" },
|
||||
{ run = 'code -w %*', block = true, desc = "code (block)", for = "windows" },
|
||||
]
|
||||
open = [
|
||||
{ run = 'xdg-open "$1"', desc = "Open", for = "linux" },
|
||||
|
@ -1,8 +1,10 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use yazi_shared::Layer;
|
||||
|
||||
use super::Control;
|
||||
use crate::{Preset, MERGED_KEYMAP};
|
||||
use crate::Preset;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Keymap {
|
||||
@ -14,6 +16,28 @@ pub struct Keymap {
|
||||
pub completion: Vec<Control>,
|
||||
}
|
||||
|
||||
impl Keymap {
|
||||
#[inline]
|
||||
pub fn get(&self, layer: Layer) -> &Vec<Control> {
|
||||
match layer {
|
||||
Layer::App => unreachable!(),
|
||||
Layer::Manager => &self.manager,
|
||||
Layer::Tasks => &self.tasks,
|
||||
Layer::Select => &self.select,
|
||||
Layer::Input => &self.input,
|
||||
Layer::Help => &self.help,
|
||||
Layer::Completion => &self.completion,
|
||||
Layer::Which => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Keymap {
|
||||
type Err = toml::de::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> { toml::from_str(s) }
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Keymap {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
@ -62,23 +86,3 @@ impl<'de> Deserialize<'de> for Keymap {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Keymap {
|
||||
fn default() -> Self { toml::from_str(&MERGED_KEYMAP).unwrap() }
|
||||
}
|
||||
|
||||
impl Keymap {
|
||||
#[inline]
|
||||
pub fn get(&self, layer: Layer) -> &Vec<Control> {
|
||||
match layer {
|
||||
Layer::App => unreachable!(),
|
||||
Layer::Manager => &self.manager,
|
||||
Layer::Tasks => &self.tasks,
|
||||
Layer::Select => &self.select,
|
||||
Layer::Input => &self.input,
|
||||
Layer::Help => &self.help,
|
||||
Layer::Completion => &self.completion,
|
||||
Layer::Which => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use yazi_shared::{RoCell, Xdg};
|
||||
|
||||
pub mod keymap;
|
||||
@ -15,7 +17,6 @@ pub mod preview;
|
||||
mod priority;
|
||||
mod tasks;
|
||||
pub mod theme;
|
||||
mod validation;
|
||||
pub mod which;
|
||||
|
||||
pub use layout::*;
|
||||
@ -23,10 +24,6 @@ pub(crate) use pattern::*;
|
||||
pub(crate) use preset::*;
|
||||
pub use priority::*;
|
||||
|
||||
static MERGED_YAZI: RoCell<String> = RoCell::new();
|
||||
static MERGED_KEYMAP: RoCell<String> = RoCell::new();
|
||||
static MERGED_THEME: RoCell<String> = RoCell::new();
|
||||
|
||||
pub static LAYOUT: RoCell<arc_swap::ArcSwap<Layout>> = RoCell::new();
|
||||
|
||||
pub static KEYMAP: RoCell<keymap::Keymap> = RoCell::new();
|
||||
@ -43,23 +40,23 @@ pub static WHICH: RoCell<which::Which> = RoCell::new();
|
||||
|
||||
pub fn init() -> anyhow::Result<()> {
|
||||
let config_dir = Xdg::config_dir();
|
||||
MERGED_YAZI.init(Preset::yazi(&config_dir)?);
|
||||
MERGED_KEYMAP.init(Preset::keymap(&config_dir)?);
|
||||
MERGED_THEME.init(Preset::theme(&config_dir)?);
|
||||
let yazi_toml = &Preset::yazi(&config_dir)?;
|
||||
let keymap_toml = &Preset::keymap(&config_dir)?;
|
||||
let theme_toml = &Preset::theme(&config_dir)?;
|
||||
|
||||
LAYOUT.with(Default::default);
|
||||
|
||||
KEYMAP.with(Default::default);
|
||||
LOG.with(Default::default);
|
||||
MANAGER.with(Default::default);
|
||||
OPEN.with(Default::default);
|
||||
PLUGIN.with(Default::default);
|
||||
PREVIEW.with(Default::default);
|
||||
TASKS.with(Default::default);
|
||||
THEME.with(Default::default);
|
||||
INPUT.with(Default::default);
|
||||
SELECT.with(Default::default);
|
||||
WHICH.with(Default::default);
|
||||
KEYMAP.init(<_>::from_str(keymap_toml)?);
|
||||
LOG.init(<_>::from_str(yazi_toml)?);
|
||||
MANAGER.init(<_>::from_str(yazi_toml)?);
|
||||
OPEN.init(<_>::from_str(yazi_toml)?);
|
||||
PLUGIN.init(<_>::from_str(yazi_toml)?);
|
||||
PREVIEW.init(<_>::from_str(yazi_toml)?);
|
||||
TASKS.init(<_>::from_str(yazi_toml)?);
|
||||
THEME.init(<_>::from_str(theme_toml)?);
|
||||
INPUT.init(<_>::from_str(yazi_toml)?);
|
||||
SELECT.init(<_>::from_str(yazi_toml)?);
|
||||
WHICH.init(<_>::from_str(yazi_toml)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::MERGED_YAZI;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Log {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for Log {
|
||||
fn default() -> Self { toml::from_str(&MERGED_YAZI).unwrap() }
|
||||
impl FromStr for Log {
|
||||
type Err = toml::de::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> { toml::from_str(s) }
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Log {
|
||||
|
@ -1,8 +1,9 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
use super::{ManagerRatio, MouseEvents, SortBy};
|
||||
use crate::{validation::check_validation, MERGED_YAZI};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Validate)]
|
||||
pub struct Manager {
|
||||
@ -24,16 +25,18 @@ pub struct Manager {
|
||||
pub mouse_events: MouseEvents,
|
||||
}
|
||||
|
||||
impl Default for Manager {
|
||||
fn default() -> Self {
|
||||
impl FromStr for Manager {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
#[derive(Deserialize)]
|
||||
struct Outer {
|
||||
manager: Manager,
|
||||
}
|
||||
|
||||
let manager = toml::from_str::<Outer>(&MERGED_YAZI).unwrap().manager;
|
||||
let manager = toml::from_str::<Outer>(s)?.manager;
|
||||
manager.validate()?;
|
||||
|
||||
check_validation(manager.validate());
|
||||
manager
|
||||
Ok(manager)
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ bitflags! {
|
||||
}
|
||||
|
||||
impl MouseEvents {
|
||||
#[inline]
|
||||
pub const fn draggable(self) -> bool { self.contains(Self::DRAG) }
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
use std::{collections::HashMap, path::Path};
|
||||
use std::{collections::HashMap, path::Path, str::FromStr};
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use yazi_shared::MIME_DIR;
|
||||
|
||||
use super::Opener;
|
||||
use crate::{open::OpenRule, Preset, MERGED_YAZI};
|
||||
use crate::{open::OpenRule, Preset};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Open {
|
||||
@ -13,10 +13,6 @@ pub struct Open {
|
||||
openers: HashMap<String, IndexSet<Opener>>,
|
||||
}
|
||||
|
||||
impl Default for Open {
|
||||
fn default() -> Self { toml::from_str(&MERGED_YAZI).unwrap() }
|
||||
}
|
||||
|
||||
impl Open {
|
||||
pub fn openers<P, M>(&self, path: P, mime: M) -> Option<IndexSet<&Opener>>
|
||||
where
|
||||
@ -58,6 +54,12 @@ impl Open {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Open {
|
||||
type Err = toml::de::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> { toml::from_str(s) }
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Open {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
|
@ -6,7 +6,9 @@ use crate::{Pattern, Priority};
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Fetcher {
|
||||
#[serde(skip)]
|
||||
pub id: u8,
|
||||
pub idx: u8,
|
||||
|
||||
pub id: String,
|
||||
pub cond: Option<Condition>,
|
||||
pub name: Option<Pattern>,
|
||||
pub mime: Option<Pattern>,
|
||||
@ -24,6 +26,6 @@ pub struct FetcherProps {
|
||||
|
||||
impl From<&Fetcher> for FetcherProps {
|
||||
fn from(fetcher: &Fetcher) -> Self {
|
||||
Self { id: fetcher.id, name: fetcher.run.name.to_owned(), prio: fetcher.prio }
|
||||
Self { id: fetcher.idx, name: fetcher.run.name.to_owned(), prio: fetcher.prio }
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
use std::path::Path;
|
||||
use std::{path::Path, str::FromStr};
|
||||
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::MIME_DIR;
|
||||
|
||||
use super::{Fetcher, Preloader, Previewer};
|
||||
use crate::{plugin::MAX_PREWORKERS, Preset, MERGED_YAZI};
|
||||
use crate::{plugin::MAX_PREWORKERS, Preset};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Plugin {
|
||||
@ -13,65 +13,6 @@ pub struct Plugin {
|
||||
pub previewers: Vec<Previewer>,
|
||||
}
|
||||
|
||||
impl Default for Plugin {
|
||||
fn default() -> Self {
|
||||
#[derive(Deserialize)]
|
||||
struct Outer {
|
||||
plugin: Shadow,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Shadow {
|
||||
fetchers: Vec<Fetcher>,
|
||||
#[serde(default)]
|
||||
prepend_fetchers: Vec<Fetcher>,
|
||||
#[serde(default)]
|
||||
append_fetchers: Vec<Fetcher>,
|
||||
|
||||
preloaders: Vec<Preloader>,
|
||||
#[serde(default)]
|
||||
prepend_preloaders: Vec<Preloader>,
|
||||
#[serde(default)]
|
||||
append_preloaders: Vec<Preloader>,
|
||||
|
||||
previewers: Vec<Previewer>,
|
||||
#[serde(default)]
|
||||
prepend_previewers: Vec<Previewer>,
|
||||
#[serde(default)]
|
||||
append_previewers: Vec<Previewer>,
|
||||
}
|
||||
|
||||
let mut shadow = toml::from_str::<Outer>(&MERGED_YAZI).unwrap().plugin;
|
||||
if shadow.append_previewers.iter().any(|r| r.any_file()) {
|
||||
shadow.previewers.retain(|r| !r.any_file());
|
||||
}
|
||||
if shadow.append_previewers.iter().any(|r| r.any_dir()) {
|
||||
shadow.previewers.retain(|r| !r.any_dir());
|
||||
}
|
||||
|
||||
Preset::mix(&mut shadow.fetchers, shadow.prepend_fetchers, shadow.append_fetchers);
|
||||
Preset::mix(&mut shadow.preloaders, shadow.prepend_preloaders, shadow.append_preloaders);
|
||||
Preset::mix(&mut shadow.previewers, shadow.prepend_previewers, shadow.append_previewers);
|
||||
|
||||
if shadow.fetchers.len() + shadow.preloaders.len() > MAX_PREWORKERS as usize {
|
||||
panic!("Fetchers and preloaders exceed the limit of {MAX_PREWORKERS}");
|
||||
}
|
||||
|
||||
for (i, p) in shadow.fetchers.iter_mut().enumerate() {
|
||||
p.id = i as u8;
|
||||
}
|
||||
for (i, p) in shadow.preloaders.iter_mut().enumerate() {
|
||||
p.id = shadow.fetchers.len() as u8 + i as u8;
|
||||
}
|
||||
|
||||
Self {
|
||||
fetchers: shadow.fetchers,
|
||||
preloaders: shadow.preloaders,
|
||||
previewers: shadow.previewers,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin {
|
||||
pub fn fetchers(
|
||||
&self,
|
||||
@ -118,3 +59,63 @@ impl Plugin {
|
||||
})
|
||||
}
|
||||
}
|
||||
impl FromStr for Plugin {
|
||||
type Err = toml::de::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
#[derive(Deserialize)]
|
||||
struct Outer {
|
||||
plugin: Shadow,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Shadow {
|
||||
fetchers: Vec<Fetcher>,
|
||||
#[serde(default)]
|
||||
prepend_fetchers: Vec<Fetcher>,
|
||||
#[serde(default)]
|
||||
append_fetchers: Vec<Fetcher>,
|
||||
|
||||
preloaders: Vec<Preloader>,
|
||||
#[serde(default)]
|
||||
prepend_preloaders: Vec<Preloader>,
|
||||
#[serde(default)]
|
||||
append_preloaders: Vec<Preloader>,
|
||||
|
||||
previewers: Vec<Previewer>,
|
||||
#[serde(default)]
|
||||
prepend_previewers: Vec<Previewer>,
|
||||
#[serde(default)]
|
||||
append_previewers: Vec<Previewer>,
|
||||
}
|
||||
|
||||
let mut shadow = toml::from_str::<Outer>(s)?.plugin;
|
||||
if shadow.append_previewers.iter().any(|r| r.any_file()) {
|
||||
shadow.previewers.retain(|r| !r.any_file());
|
||||
}
|
||||
if shadow.append_previewers.iter().any(|r| r.any_dir()) {
|
||||
shadow.previewers.retain(|r| !r.any_dir());
|
||||
}
|
||||
|
||||
Preset::mix(&mut shadow.fetchers, shadow.prepend_fetchers, shadow.append_fetchers);
|
||||
Preset::mix(&mut shadow.preloaders, shadow.prepend_preloaders, shadow.append_preloaders);
|
||||
Preset::mix(&mut shadow.previewers, shadow.prepend_previewers, shadow.append_previewers);
|
||||
|
||||
if shadow.fetchers.len() + shadow.preloaders.len() > MAX_PREWORKERS as usize {
|
||||
panic!("Fetchers and preloaders exceed the limit of {MAX_PREWORKERS}");
|
||||
}
|
||||
|
||||
for (i, p) in shadow.fetchers.iter_mut().enumerate() {
|
||||
p.idx = i as u8;
|
||||
}
|
||||
for (i, p) in shadow.preloaders.iter_mut().enumerate() {
|
||||
p.idx = shadow.fetchers.len() as u8 + i as u8;
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
fetchers: shadow.fetchers,
|
||||
preloaders: shadow.preloaders,
|
||||
previewers: shadow.previewers,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ use crate::{Pattern, Priority};
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Preloader {
|
||||
#[serde(skip)]
|
||||
pub id: u8,
|
||||
pub idx: u8,
|
||||
|
||||
pub name: Option<Pattern>,
|
||||
pub mime: Option<Pattern>,
|
||||
pub run: Cmd,
|
||||
@ -25,6 +26,6 @@ pub struct PreloaderProps {
|
||||
|
||||
impl From<&Preloader> for PreloaderProps {
|
||||
fn from(preloader: &Preloader) -> Self {
|
||||
Self { id: preloader.id, name: preloader.run.name.to_owned(), prio: preloader.prio }
|
||||
Self { id: preloader.idx, name: preloader.run.name.to_owned(), prio: preloader.prio }
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::{Offset, Origin};
|
||||
use crate::MERGED_YAZI;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Input {
|
||||
@ -63,18 +64,19 @@ pub struct Input {
|
||||
pub quit_offset: Offset,
|
||||
}
|
||||
|
||||
impl Default for Input {
|
||||
fn default() -> Self {
|
||||
impl Input {
|
||||
pub const fn border(&self) -> u16 { 2 }
|
||||
}
|
||||
|
||||
impl FromStr for Input {
|
||||
type Err = toml::de::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
#[derive(Deserialize)]
|
||||
struct Outer {
|
||||
input: Input,
|
||||
}
|
||||
|
||||
toml::from_str::<Outer>(&MERGED_YAZI).unwrap().input
|
||||
Ok(toml::from_str::<Outer>(s)?.input)
|
||||
}
|
||||
}
|
||||
|
||||
impl Input {
|
||||
#[inline]
|
||||
pub const fn border(&self) -> u16 { 2 }
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::{Offset, Origin};
|
||||
use crate::MERGED_YAZI;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Select {
|
||||
@ -11,18 +12,19 @@ pub struct Select {
|
||||
pub open_offset: Offset,
|
||||
}
|
||||
|
||||
impl Default for Select {
|
||||
fn default() -> Self {
|
||||
impl Select {
|
||||
pub const fn border(&self) -> u16 { 2 }
|
||||
}
|
||||
|
||||
impl FromStr for Select {
|
||||
type Err = toml::de::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
#[derive(Deserialize)]
|
||||
struct Outer {
|
||||
select: Select,
|
||||
}
|
||||
|
||||
toml::from_str::<Outer>(&MERGED_YAZI).unwrap().select
|
||||
Ok(toml::from_str::<Outer>(s)?.select)
|
||||
}
|
||||
}
|
||||
|
||||
impl Select {
|
||||
#[inline]
|
||||
pub const fn border(&self) -> u16 { 2 }
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{mem, path::{Path, PathBuf}};
|
||||
use std::{borrow::Cow, mem, path::{Path, PathBuf}};
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use toml::{Table, Value};
|
||||
@ -8,17 +8,17 @@ use crate::theme::Flavor;
|
||||
pub(crate) struct Preset;
|
||||
|
||||
impl Preset {
|
||||
pub(crate) fn yazi(p: &Path) -> Result<String> {
|
||||
pub(crate) fn yazi(p: &Path) -> Result<Cow<str>> {
|
||||
Self::merge_path(p.join("yazi.toml"), include_str!("../preset/yazi.toml"))
|
||||
}
|
||||
|
||||
pub(crate) fn keymap(p: &Path) -> Result<String> {
|
||||
pub(crate) fn keymap(p: &Path) -> Result<Cow<str>> {
|
||||
Self::merge_path(p.join("keymap.toml"), include_str!("../preset/keymap.toml"))
|
||||
}
|
||||
|
||||
pub(crate) fn theme(p: &Path) -> Result<String> {
|
||||
pub(crate) fn theme(p: &Path) -> Result<Cow<str>> {
|
||||
let Ok(user) = std::fs::read_to_string(p.join("theme.toml")) else {
|
||||
return Ok(include_str!("../preset/theme.toml").to_owned());
|
||||
return Ok(include_str!("../preset/theme.toml").into());
|
||||
};
|
||||
let Some(use_) = Flavor::parse_use(&user) else {
|
||||
return Self::merge_str(&user, include_str!("../preset/theme.toml"));
|
||||
@ -37,18 +37,18 @@ impl Preset {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn merge_str(user: &str, base: &str) -> Result<String> {
|
||||
pub(crate) fn merge_str(user: &str, base: &str) -> Result<Cow<'static, str>> {
|
||||
let mut t = user.parse()?;
|
||||
Self::merge(&mut t, base.parse()?, 2);
|
||||
|
||||
Ok(t.to_string())
|
||||
Ok(t.to_string().into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn merge_path(user: PathBuf, base: &str) -> Result<String> {
|
||||
fn merge_path(user: PathBuf, base: &str) -> Result<Cow<str>> {
|
||||
let s = std::fs::read_to_string(&user).unwrap_or_default();
|
||||
if s.is_empty() {
|
||||
return Ok(base.to_string());
|
||||
return Ok(base.into());
|
||||
}
|
||||
|
||||
Self::merge_str(&s, base).with_context(|| anyhow!("Loading {user:?}"))
|
||||
|
@ -1,10 +1,11 @@
|
||||
use std::{path::PathBuf, time::{self, SystemTime}};
|
||||
use std::{path::PathBuf, str::FromStr, time::{self, SystemTime}};
|
||||
|
||||
use anyhow::Context;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
use yazi_shared::fs::expand_path;
|
||||
|
||||
use crate::{validation::check_validation, Xdg, MERGED_YAZI};
|
||||
use crate::Xdg;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Preview {
|
||||
@ -23,8 +24,18 @@ pub struct Preview {
|
||||
pub ueberzug_offset: (f32, f32, f32, f32),
|
||||
}
|
||||
|
||||
impl Default for Preview {
|
||||
fn default() -> Self {
|
||||
impl Preview {
|
||||
#[inline]
|
||||
pub fn tmpfile(&self, prefix: &str) -> PathBuf {
|
||||
let nanos = SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos();
|
||||
self.cache_dir.join(format!("{prefix}-{}", nanos / 1000))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Preview {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
#[derive(Deserialize)]
|
||||
struct Outer {
|
||||
preview: Shadow,
|
||||
@ -48,14 +59,14 @@ impl Default for Preview {
|
||||
ueberzug_offset: (f32, f32, f32, f32),
|
||||
}
|
||||
|
||||
let preview = toml::from_str::<Outer>(&MERGED_YAZI).unwrap().preview;
|
||||
check_validation(preview.validate());
|
||||
let preview = toml::from_str::<Outer>(s)?.preview;
|
||||
preview.validate()?;
|
||||
|
||||
let cache_dir =
|
||||
preview.cache_dir.filter(|p| !p.is_empty()).map_or_else(Xdg::cache_dir, expand_path);
|
||||
std::fs::create_dir_all(&cache_dir).expect("Failed to create cache directory");
|
||||
std::fs::create_dir_all(&cache_dir).context("Failed to create cache directory")?;
|
||||
|
||||
Preview {
|
||||
Ok(Preview {
|
||||
tab_size: preview.tab_size,
|
||||
word_wrap: preview.word_wrap,
|
||||
max_width: preview.max_width,
|
||||
@ -69,14 +80,6 @@ impl Default for Preview {
|
||||
|
||||
ueberzug_scale: preview.ueberzug_scale,
|
||||
ueberzug_offset: preview.ueberzug_offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Preview {
|
||||
#[inline]
|
||||
pub fn tmpfile(&self, prefix: &str) -> PathBuf {
|
||||
let nanos = SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos();
|
||||
self.cache_dir.join(format!("{prefix}-{}", nanos / 1000))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::Deserialize;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::{validation::check_validation, MERGED_YAZI};
|
||||
|
||||
#[derive(Debug, Deserialize, Validate)]
|
||||
pub struct Tasks {
|
||||
#[validate(range(min = 1, message = "Cannot be less than 1"))]
|
||||
@ -18,16 +18,18 @@ pub struct Tasks {
|
||||
pub suppress_preload: bool,
|
||||
}
|
||||
|
||||
impl Default for Tasks {
|
||||
fn default() -> Self {
|
||||
impl FromStr for Tasks {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
#[derive(Deserialize)]
|
||||
struct Outer {
|
||||
tasks: Tasks,
|
||||
}
|
||||
|
||||
let tasks = toml::from_str::<Outer>(&MERGED_YAZI).unwrap().tasks;
|
||||
check_validation(tasks.validate());
|
||||
let tasks = toml::from_str::<Outer>(s)?.tasks;
|
||||
tasks.validate()?;
|
||||
|
||||
tasks
|
||||
Ok(tasks)
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
use std::path::PathBuf;
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
use yazi_shared::{fs::expand_path, theme::Style, Xdg};
|
||||
|
||||
use super::{Filetype, Flavor, Icons};
|
||||
use crate::{validation::check_validation, MERGED_THEME};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Theme {
|
||||
@ -27,12 +26,13 @@ pub struct Theme {
|
||||
pub icons: Icons,
|
||||
}
|
||||
|
||||
impl Default for Theme {
|
||||
fn default() -> Self {
|
||||
let mut theme: Self = toml::from_str(&MERGED_THEME).unwrap();
|
||||
impl FromStr for Theme {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
check_validation(theme.manager.validate());
|
||||
check_validation(theme.which.validate());
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut theme: Self = toml::from_str(s)?;
|
||||
theme.manager.validate()?;
|
||||
theme.which.validate()?;
|
||||
|
||||
if theme.flavor.use_.is_empty() {
|
||||
theme.manager.syntect_theme = expand_path(&theme.manager.syntect_theme);
|
||||
@ -41,7 +41,7 @@ impl Default for Theme {
|
||||
Xdg::config_dir().join(format!("flavors/{}.yazi/tmtheme.xml", theme.flavor.use_));
|
||||
}
|
||||
|
||||
theme
|
||||
Ok(theme)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,29 +0,0 @@
|
||||
use std::{borrow::Cow, process};
|
||||
|
||||
use validator::{ValidationErrors, ValidationErrorsKind};
|
||||
|
||||
pub fn check_validation(res: Result<(), ValidationErrors>) {
|
||||
let Err(errors) = res else { return };
|
||||
|
||||
for (field, kind) in errors.into_errors() {
|
||||
match kind {
|
||||
ValidationErrorsKind::Struct(errors) => check_validation(Err(*errors)),
|
||||
ValidationErrorsKind::List(errors) => {
|
||||
for (i, errors) in errors {
|
||||
eprint!("Config `{field}[{i}]` format error: ");
|
||||
check_validation(Err(*errors));
|
||||
eprintln!();
|
||||
}
|
||||
}
|
||||
ValidationErrorsKind::Field(error) => {
|
||||
for e in error {
|
||||
eprintln!(
|
||||
"Config `{field}` format error: {}\n",
|
||||
e.message.unwrap_or(Cow::Borrowed("unknown error"))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
process::exit(1);
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
use super::SortBy;
|
||||
use crate::MERGED_YAZI;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Validate)]
|
||||
pub struct Which {
|
||||
@ -13,13 +14,15 @@ pub struct Which {
|
||||
pub sort_translit: bool,
|
||||
}
|
||||
|
||||
impl Default for Which {
|
||||
fn default() -> Self {
|
||||
impl FromStr for Which {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
#[derive(Deserialize)]
|
||||
struct Outer {
|
||||
which: Which,
|
||||
}
|
||||
|
||||
toml::from_str::<Outer>(&MERGED_YAZI).unwrap().which
|
||||
Ok(toml::from_str::<Outer>(s)?.which)
|
||||
}
|
||||
}
|
||||
|
@ -19,11 +19,11 @@ impl Tasks {
|
||||
|
||||
for p in PLUGIN.fetchers(&f.url, mime, factors) {
|
||||
match loaded.get_mut(&f.url) {
|
||||
Some(n) if *n & (1 << p.id) != 0 => continue,
|
||||
Some(n) => *n |= 1 << p.id,
|
||||
None => _ = loaded.insert(f.url.clone(), 1 << p.id),
|
||||
Some(n) if *n & (1 << p.idx) != 0 => continue,
|
||||
Some(n) => *n |= 1 << p.idx,
|
||||
None => _ = loaded.insert(f.url.clone(), 1 << p.idx),
|
||||
}
|
||||
tasks[p.id as usize].push(f.clone());
|
||||
tasks[p.idx as usize].push(f.clone());
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,9 +41,9 @@ impl Tasks {
|
||||
let mime = if f.is_dir() { Some(MIME_DIR) } else { mimetype.get(&f.url).map(|s| &**s) };
|
||||
for p in PLUGIN.preloaders(&f.url, mime) {
|
||||
match loaded.get_mut(&f.url) {
|
||||
Some(n) if *n & (1 << p.id) != 0 => continue,
|
||||
Some(n) => *n |= 1 << p.id,
|
||||
None => _ = loaded.insert(f.url.clone(), 1 << p.id),
|
||||
Some(n) if *n & (1 << p.idx) != 0 => continue,
|
||||
Some(n) => *n |= 1 << p.idx,
|
||||
None => _ = loaded.insert(f.url.clone(), 1 << p.idx),
|
||||
}
|
||||
self.scheduler.preload_paged(p, f);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ yazi-shared = { path = "../yazi-shared", version = "0.2.5" }
|
||||
|
||||
# External dependencies
|
||||
anyhow = "1.0.86"
|
||||
mlua = { version = "0.9.8", features = [ "lua54" ] }
|
||||
mlua = { version = "0.9.9", features = [ "lua54" ] }
|
||||
parking_lot = "0.12.3"
|
||||
serde = { version = "1.0.203", features = [ "derive" ] }
|
||||
serde_json = "1.0.117"
|
||||
|
@ -5,15 +5,17 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::Body;
|
||||
|
||||
/// The client handshake
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct BodyHi<'a> {
|
||||
pub abilities: HashSet<Cow<'a, String>>,
|
||||
/// Specifies the kinds of events that the client can handle
|
||||
pub abilities: HashSet<Cow<'a, str>>,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
impl<'a> BodyHi<'a> {
|
||||
#[inline]
|
||||
pub fn borrowed(abilities: HashSet<&'a String>) -> Body<'a> {
|
||||
pub fn borrowed(abilities: HashSet<&'a str>) -> Body<'a> {
|
||||
Self {
|
||||
abilities: abilities.into_iter().map(Cow::Borrowed).collect(),
|
||||
version: Self::version(),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::{collections::{HashMap, HashSet}, mem, str::FromStr};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use parking_lot::RwLock;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::{io::AsyncWriteExt, select, sync::mpsc, task::JoinHandle, time};
|
||||
@ -27,6 +27,7 @@ pub struct Peer {
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// Connect to an existing server or start a new one.
|
||||
pub(super) fn serve() {
|
||||
let mut rx = QUEUE_RX.drop();
|
||||
while rx.try_recv().is_ok() {}
|
||||
@ -52,7 +53,7 @@ impl Client {
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
} else if line.starts_with("hey,") {
|
||||
Self::handle_hey(line);
|
||||
Self::handle_hey(&line);
|
||||
} else {
|
||||
Payload::from_str(&line).map(|p| p.emit()).ok();
|
||||
}
|
||||
@ -62,6 +63,7 @@ impl Client {
|
||||
});
|
||||
}
|
||||
|
||||
/// Connect to an existing server to send a single message.
|
||||
pub async fn shot(kind: &str, receiver: u64, severity: Option<u16>, body: &str) -> Result<()> {
|
||||
Body::validate(kind)?;
|
||||
|
||||
@ -100,6 +102,40 @@ impl Client {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Connect to an existing server and listen in on the messages that are being
|
||||
/// sent by other yazi instances:
|
||||
/// - If no server is running, fail right away;
|
||||
/// - If a server is closed, attempt to reconnect forever.
|
||||
pub async fn draw(kinds: HashSet<&str>) -> Result<()> {
|
||||
async fn make(kinds: &HashSet<&str>) -> Result<ClientReader> {
|
||||
let (lines, mut writer) = Stream::connect().await?;
|
||||
let hi = Payload::new(BodyHi::borrowed(kinds.clone()));
|
||||
writer.write_all(format!("{hi}\n").as_bytes()).await?;
|
||||
writer.flush().await?;
|
||||
Ok(lines)
|
||||
}
|
||||
|
||||
let mut lines = make(&kinds).await.context("No running Yazi instance found")?;
|
||||
loop {
|
||||
match lines.next_line().await? {
|
||||
Some(s) => {
|
||||
let kind = s.split(',').next();
|
||||
if matches!(kind, Some(kind) if kinds.contains(kind)) {
|
||||
println!("{s}");
|
||||
}
|
||||
}
|
||||
None => loop {
|
||||
if let Ok(new) = make(&kinds).await {
|
||||
lines = new;
|
||||
break;
|
||||
} else {
|
||||
time::sleep(time::Duration::from_secs(1)).await;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn push<'a>(payload: impl Into<Payload<'a>>) {
|
||||
QUEUE_TX.send(format!("{}\n", payload.into())).ok();
|
||||
@ -136,8 +172,8 @@ impl Client {
|
||||
Self::connect(server).await
|
||||
}
|
||||
|
||||
fn handle_hey(s: String) {
|
||||
if let Ok(Body::Hey(mut hey)) = Payload::from_str(&s).map(|p| p.body) {
|
||||
fn handle_hey(s: &str) {
|
||||
if let Ok(Body::Hey(mut hey)) = Payload::from_str(s).map(|p| p.body) {
|
||||
hey.peers.retain(|&id, _| id != *ID);
|
||||
*PEERS.write() = hey.peers;
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ impl Pubsub {
|
||||
|
||||
pub fn pub_from_hi() -> bool {
|
||||
let abilities = REMOTE.read().keys().cloned().collect();
|
||||
let abilities = BOOT.remote_events.union(&abilities).collect();
|
||||
let abilities = BOOT.remote_events.union(&abilities).map(|s| s.as_str()).collect();
|
||||
|
||||
Client::push(BodyHi::borrowed(abilities));
|
||||
true
|
||||
|
@ -28,7 +28,7 @@ better-panic = "0.3.0"
|
||||
crossterm = { version = "0.27.0", features = [ "event-stream" ] }
|
||||
fdlimit = "0.3.0"
|
||||
futures = "0.3.30"
|
||||
mlua = { version = "0.9.8", features = [ "lua54" ] }
|
||||
mlua = { version = "0.9.9", features = [ "lua54" ] }
|
||||
ratatui = "0.26.3"
|
||||
scopeguard = "1.2.0"
|
||||
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||
|
@ -21,8 +21,6 @@ impl Filter {
|
||||
}
|
||||
|
||||
pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
|
||||
lua.register_userdata_type::<Self>(|_| {})?;
|
||||
|
||||
Ok(())
|
||||
lua.register_userdata_type::<Self>(|_| {})
|
||||
}
|
||||
}
|
||||
|
26
yazi-fm/src/lives/finder.rs
Normal file
26
yazi-fm/src/lives/finder.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, Lua};
|
||||
|
||||
use super::SCOPE;
|
||||
|
||||
pub(super) struct Finder {
|
||||
inner: *const yazi_core::tab::Finder,
|
||||
}
|
||||
|
||||
impl Deref for Finder {
|
||||
type Target = yazi_core::tab::Finder;
|
||||
|
||||
fn deref(&self) -> &Self::Target { unsafe { &*self.inner } }
|
||||
}
|
||||
|
||||
impl Finder {
|
||||
#[inline]
|
||||
pub(super) fn make(inner: &yazi_core::tab::Finder) -> mlua::Result<AnyUserData<'static>> {
|
||||
SCOPE.create_any_userdata(Self { inner })
|
||||
}
|
||||
|
||||
pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
|
||||
lua.register_userdata_type::<Self>(|_| {})
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ impl Lives {
|
||||
super::File::register(&LUA)?;
|
||||
super::Files::register(&LUA)?;
|
||||
super::Filter::register(&LUA)?;
|
||||
super::Finder::register(&LUA)?;
|
||||
super::Folder::register(&LUA)?;
|
||||
super::Mode::register(&LUA)?;
|
||||
super::Preview::register(&LUA)?;
|
||||
|
@ -4,6 +4,7 @@ mod config;
|
||||
mod file;
|
||||
mod files;
|
||||
mod filter;
|
||||
mod finder;
|
||||
mod folder;
|
||||
mod iter;
|
||||
mod lives;
|
||||
@ -19,6 +20,7 @@ use config::*;
|
||||
use file::*;
|
||||
use files::*;
|
||||
use filter::*;
|
||||
use finder::*;
|
||||
use folder::*;
|
||||
use iter::*;
|
||||
pub(super) use lives::*;
|
||||
|
@ -2,7 +2,7 @@ use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, Lua, UserDataFields, UserDataMethods};
|
||||
|
||||
use super::{Config, Folder, Mode, Preview, Selected, SCOPE};
|
||||
use super::{Config, Finder, Folder, Mode, Preview, Selected, SCOPE};
|
||||
|
||||
pub(super) struct Tab {
|
||||
inner: *const yazi_core::tab::Tab,
|
||||
@ -44,6 +44,7 @@ impl Tab {
|
||||
reg.add_field_method_get("selected", |_, me| Selected::make(&me.selected));
|
||||
|
||||
reg.add_field_method_get("preview", |_, me| Preview::make(me));
|
||||
reg.add_field_method_get("finder", |_, me| me.finder.as_ref().map(Finder::make).transpose());
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
|
@ -21,13 +21,13 @@ yazi-proxy = { path = "../yazi-proxy", version = "0.2.5" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "0.2.5" }
|
||||
|
||||
# External dependencies
|
||||
ansi-to-tui = "3.1.0"
|
||||
ansi-to-tui = "=3.1.0"
|
||||
anyhow = "1.0.86"
|
||||
base64 = "0.22.1"
|
||||
crossterm = "0.27.0"
|
||||
futures = "0.3.30"
|
||||
md-5 = "0.10.6"
|
||||
mlua = { version = "0.9.8", features = [ "lua54", "serialize", "macros", "async" ] }
|
||||
mlua = { version = "0.9.9", features = [ "lua54", "serialize", "macros", "async" ] }
|
||||
parking_lot = "0.12.3"
|
||||
ratatui = "0.26.3"
|
||||
serde = "1.0.203"
|
||||
|
@ -10,11 +10,12 @@ impl Utils {
|
||||
pub(super) fn text(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set(
|
||||
"quote",
|
||||
lua.create_function(|_, s: mlua::String| {
|
||||
#[cfg(unix)]
|
||||
let s = shell_escape::unix::escape(s.to_str()?.into());
|
||||
#[cfg(windows)]
|
||||
let s = shell_escape::windows::escape(s.to_str()?.into());
|
||||
lua.create_function(|_, (s, unix): (mlua::String, Option<bool>)| {
|
||||
let s = match unix {
|
||||
Some(true) => shell_escape::unix::escape(s.to_str()?.into()),
|
||||
Some(false) => shell_escape::windows::escape(s.to_str()?.into()),
|
||||
None => shell_escape::escape(s.to_str()?.into()),
|
||||
};
|
||||
Ok(s.into_owned())
|
||||
})?,
|
||||
)?;
|
||||
|
@ -18,5 +18,5 @@ yazi-shared = { path = "../yazi-shared", version = "0.2.5" }
|
||||
|
||||
# External dependencies
|
||||
anyhow = "1.0.86"
|
||||
mlua = { version = "0.9.8", features = [ "lua54" ] }
|
||||
mlua = { version = "0.9.9", features = [ "lua54" ] }
|
||||
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||
|
@ -30,4 +30,4 @@ tracing = { version = "0.1.40", features = [ "max_level_debug", "release_max_lev
|
||||
libc = "0.2.155"
|
||||
|
||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||
trash = "4.1.1"
|
||||
trash = "5.0.0"
|
||||
|
@ -14,7 +14,6 @@ anyhow = "1.0.86"
|
||||
bitflags = "2.5.0"
|
||||
crossterm = "0.27.0"
|
||||
dirs = "5.0.1"
|
||||
filetime = "0.2.23"
|
||||
futures = "0.3.30"
|
||||
parking_lot = "0.12.3"
|
||||
percent-encoding = "2.3.1"
|
||||
@ -24,8 +23,5 @@ serde = { version = "1.0.203", features = [ "derive" ] }
|
||||
shell-words = "1.1.0"
|
||||
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||
|
||||
# Logging
|
||||
tracing = { version = "0.1.40", features = [ "max_level_debug", "release_max_level_warn" ] }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
libc = "0.2.155"
|
||||
|
@ -1,7 +1,6 @@
|
||||
use std::{borrow::Cow, collections::{HashMap, VecDeque}, fs::Metadata, path::{Path, PathBuf}};
|
||||
|
||||
use anyhow::Result;
|
||||
use filetime::{set_file_mtime, FileTime};
|
||||
use tokio::{fs, io, select, sync::{mpsc, oneshot}, time};
|
||||
|
||||
#[inline]
|
||||
@ -104,12 +103,23 @@ pub fn copy_with_progress(
|
||||
|
||||
tokio::spawn({
|
||||
let (from, to) = (from.to_owned(), to.to_owned());
|
||||
let mtime = FileTime::from_last_modification_time(meta);
|
||||
|
||||
let mut ft = std::fs::FileTimes::new();
|
||||
meta.accessed().map(|t| ft = ft.set_accessed(t)).ok();
|
||||
meta.modified().map(|t| ft = ft.set_modified(t)).ok();
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use std::os::macos::fs::FileTimesExt;
|
||||
meta.created().map(|t| ft = ft.set_created(t)).ok();
|
||||
}
|
||||
|
||||
async move {
|
||||
_ = match fs::copy(&from, &to).await {
|
||||
Ok(len) => {
|
||||
set_file_mtime(to, mtime).ok();
|
||||
_ = tokio::task::spawn_blocking(move || {
|
||||
std::fs::File::options().write(true).open(to).and_then(|f| f.set_times(ft)).ok();
|
||||
})
|
||||
.await;
|
||||
tick_tx.send(Ok(len))
|
||||
}
|
||||
Err(e) => tick_tx.send(Err(e)),
|
||||
|
@ -13,7 +13,7 @@ impl<T> RoCell<T> {
|
||||
|
||||
#[inline]
|
||||
pub fn init(&self, value: T) {
|
||||
debug_assert!(!self.is_initialized());
|
||||
debug_assert!(!self.initialized());
|
||||
unsafe {
|
||||
*self.0.get() = Some(value);
|
||||
}
|
||||
@ -29,25 +29,25 @@ impl<T> RoCell<T> {
|
||||
|
||||
#[inline]
|
||||
pub fn replace(&self, value: T) -> T {
|
||||
debug_assert!(self.is_initialized());
|
||||
debug_assert!(self.initialized());
|
||||
unsafe { mem::replace(&mut *self.0.get(), Some(value)).unwrap_unchecked() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn drop(&self) -> T {
|
||||
debug_assert!(self.is_initialized());
|
||||
debug_assert!(self.initialized());
|
||||
unsafe { mem::take(&mut *self.0.get()).unwrap_unchecked() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_initialized(&self) -> bool { unsafe { (*self.0.get()).is_some() } }
|
||||
fn initialized(&self) -> bool { unsafe { (*self.0.get()).is_some() } }
|
||||
}
|
||||
|
||||
impl<T> Deref for RoCell<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
debug_assert!(self.is_initialized());
|
||||
debug_assert!(self.initialized());
|
||||
unsafe { (*self.0.get()).as_ref().unwrap_unchecked() }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user