Skip to content

Commit 9f077f9

Browse files
committed
refactor: switch to actor model (#2986)
1 parent 6366e46 commit 9f077f9

File tree

336 files changed

+4120
-3007
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

336 files changed

+4120
-3007
lines changed

Cargo.lock

Lines changed: 34 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

yazi-actor/Cargo.toml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[package]
2+
name = "yazi-actor"
3+
version = "25.6.11"
4+
edition = "2024"
5+
license = "MIT"
6+
authors = [ "sxyazi <[email protected]>" ]
7+
description = "Yazi actor model"
8+
homepage = "https://yazi-rs.github.io"
9+
repository = "https://github.com/sxyazi/yazi"
10+
11+
[dependencies]
12+
yazi-boot = { path = "../yazi-boot", version = "25.6.11" }
13+
yazi-config = { path = "../yazi-config", version = "25.6.11" }
14+
yazi-core = { path = "../yazi-core", version = "25.6.11" }
15+
yazi-dds = { path = "../yazi-dds", version = "25.6.11" }
16+
yazi-fs = { path = "../yazi-fs", version = "25.6.11" }
17+
yazi-macro = { path = "../yazi-macro", version = "25.6.11" }
18+
yazi-parser = { path = "../yazi-parser", version = "25.6.11" }
19+
yazi-plugin = { path = "../yazi-plugin", version = "25.6.11" }
20+
yazi-proxy = { path = "../yazi-proxy", version = "25.6.11" }
21+
yazi-shared = { path = "../yazi-shared", version = "25.6.11" }
22+
yazi-term = { path = "../yazi-term", version = "25.6.11" }
23+
yazi-widgets = { path = "../yazi-widgets", version = "25.6.11" }
24+
25+
# External dependencies
26+
anyhow = { workspace = true }
27+
crossterm = { workspace = true }
28+
futures = { workspace = true }
29+
paste = { workspace = true }
30+
scopeguard = { workspace = true }
31+
tokio = { workspace = true }
32+
tokio-stream = { workspace = true }
33+
tracing = { workspace = true }
34+
35+
[target."cfg(unix)".dependencies]
36+
libc = { workspace = true }
37+
38+
[target.'cfg(target_os = "macos")'.dependencies]
39+
crossterm = { workspace = true, features = [ "use-dev-tty", "libc" ] }

yazi-actor/src/actor.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use anyhow::Result;
2+
use yazi_shared::event::Data;
3+
4+
use crate::Ctx;
5+
6+
pub trait Actor {
7+
type Options;
8+
9+
const NAME: &'static str;
10+
11+
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data>;
12+
}

yazi-actor/src/cmp/arrow.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use anyhow::Result;
2+
use yazi_macro::{render, succ};
3+
use yazi_parser::ArrowOpt;
4+
use yazi_shared::event::Data;
5+
use yazi_widgets::Scrollable;
6+
7+
use crate::{Actor, Ctx};
8+
9+
pub struct Arrow;
10+
11+
impl Actor for Arrow {
12+
type Options = ArrowOpt;
13+
14+
const NAME: &'static str = "arrow";
15+
16+
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
17+
succ!(render!(cx.cmp.scroll(opt.step)));
18+
}
19+
}

yazi-actor/src/cmp/close.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use std::mem;
2+
3+
use anyhow::Result;
4+
use yazi_macro::{act, render, succ};
5+
use yazi_parser::{cmp::CloseOpt, input::CompleteOpt};
6+
use yazi_shared::event::Data;
7+
8+
use crate::{Actor, Ctx};
9+
10+
pub struct Close;
11+
12+
impl Actor for Close {
13+
type Options = CloseOpt;
14+
15+
const NAME: &'static str = "close";
16+
17+
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
18+
let cmp = &mut cx.core.cmp;
19+
if let Some(item) = cmp.selected().filter(|_| opt.submit).cloned() {
20+
return act!(complete, cx.core.input, CompleteOpt { item, _ticket: cmp.ticket });
21+
}
22+
23+
cmp.caches.clear();
24+
succ!(render!(mem::replace(&mut cmp.visible, false)));
25+
}
26+
}
File renamed without changes.

yazi-core/src/cmp/commands/show.rs renamed to yazi-actor/src/cmp/show.rs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,49 @@
11
use std::{mem, ops::ControlFlow};
22

3-
use yazi_macro::render;
3+
use anyhow::Result;
4+
use yazi_macro::{render, succ};
45
use yazi_parser::cmp::ShowOpt;
56
use yazi_proxy::options::CmpItem;
6-
use yazi_shared::{osstr_contains, osstr_starts_with};
7+
use yazi_shared::{event::Data, osstr_contains, osstr_starts_with};
78

8-
use crate::cmp::Cmp;
9+
use crate::{Actor, Ctx};
910

1011
const LIMIT: usize = 30;
1112

12-
impl Cmp {
13-
#[yazi_codegen::command]
14-
pub fn show(&mut self, opt: ShowOpt) {
15-
if self.ticket != opt.ticket {
16-
return;
13+
pub struct Show;
14+
15+
impl Actor for Show {
16+
type Options = ShowOpt;
17+
18+
const NAME: &'static str = "show";
19+
20+
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
21+
let cmp = &mut cx.cmp;
22+
if cmp.ticket != opt.ticket {
23+
succ!();
1724
}
1825

1926
if !opt.cache.is_empty() {
20-
self.caches.insert(opt.cache_name.clone(), opt.cache);
27+
cmp.caches.insert(opt.cache_name.clone(), opt.cache);
2128
}
22-
let Some(cache) = self.caches.get(&opt.cache_name) else {
23-
return;
29+
let Some(cache) = cmp.caches.get(&opt.cache_name) else {
30+
succ!();
2431
};
2532

26-
self.ticket = opt.ticket;
27-
self.cands = Self::match_candidates(&opt.word, cache);
28-
if self.cands.is_empty() {
29-
return render!(mem::replace(&mut self.visible, false));
33+
cmp.ticket = opt.ticket;
34+
cmp.cands = Self::match_candidates(&opt.word, cache);
35+
if cmp.cands.is_empty() {
36+
succ!(render!(mem::replace(&mut cmp.visible, false)));
3037
}
3138

32-
self.offset = 0;
33-
self.cursor = 0;
34-
self.visible = true;
35-
render!();
39+
cmp.offset = 0;
40+
cmp.cursor = 0;
41+
cmp.visible = true;
42+
succ!(render!());
3643
}
44+
}
3745

46+
impl Show {
3847
fn match_candidates(word: &str, cache: &[CmpItem]) -> Vec<CmpItem> {
3948
let smart = !word.bytes().any(|c| c.is_ascii_uppercase());
4049

yazi-core/src/cmp/commands/trigger.rs renamed to yazi-actor/src/cmp/trigger.rs

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,41 @@
11
use std::{ffi::OsString, mem, path::{MAIN_SEPARATOR_STR, Path, PathBuf}};
22

3+
use anyhow::Result;
34
use tokio::fs;
45
use yazi_fs::{CWD, expand_path};
5-
use yazi_macro::{emit, render};
6-
use yazi_parser::cmp::TriggerOpt;
6+
use yazi_macro::{act, emit, render, succ};
7+
use yazi_parser::cmp::{ShowOpt, TriggerOpt};
78
use yazi_proxy::options::CmpItem;
8-
use yazi_shared::{event::Cmd, natsort};
9+
use yazi_shared::{event::{Cmd, Data}, natsort};
910

10-
use crate::cmp::Cmp;
11+
use crate::{Actor, Ctx};
1112

12-
impl Cmp {
13-
#[yazi_codegen::command]
14-
pub fn trigger(&mut self, opt: TriggerOpt) {
13+
pub struct Trigger;
14+
15+
impl Actor for Trigger {
16+
type Options = TriggerOpt;
17+
18+
const NAME: &'static str = "trigger";
19+
20+
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
21+
let cmp = &mut cx.cmp;
1522
if let Some(t) = opt.ticket {
16-
if t < self.ticket {
17-
return;
23+
if t < cmp.ticket {
24+
succ!();
1825
}
19-
self.ticket = t;
26+
cmp.ticket = t;
2027
}
2128

2229
let Some((parent, word)) = Self::split_path(&opt.word) else {
23-
return self.close(false);
30+
return act!(cmp:close, cx, false);
2431
};
2532

26-
if self.caches.contains_key(&parent) {
27-
return self.show(
28-
Cmd::default()
29-
.with_any("cache-name", parent)
30-
.with("word", word)
31-
.with("ticket", self.ticket),
32-
);
33+
if cmp.caches.contains_key(&parent) {
34+
let ticket = cmp.ticket;
35+
return act!(cmp:show, cx, ShowOpt { cache_name: parent, word: word.into(), ticket, ..Default::default() });
3336
}
3437

35-
let ticket = self.ticket;
38+
let ticket = cmp.ticket;
3639
tokio::spawn(async move {
3740
let mut dir = fs::read_dir(&parent).await?;
3841
let mut cache = vec![];
@@ -65,9 +68,11 @@ impl Cmp {
6568
Ok::<_, anyhow::Error>(())
6669
});
6770

68-
render!(mem::replace(&mut self.visible, false));
71+
succ!(render!(mem::replace(&mut cmp.visible, false)));
6972
}
73+
}
7074

75+
impl Trigger {
7176
fn split_path(s: &str) -> Option<(PathBuf, String)> {
7277
if s == "~" {
7378
return None; // We don't autocomplete a `~`, but `~/`
@@ -93,7 +98,7 @@ mod tests {
9398
use super::*;
9499

95100
fn compare(s: &str, parent: &str, child: &str) {
96-
let (p, c) = Cmp::split_path(s).unwrap();
101+
let (p, c) = Trigger::split_path(s).unwrap();
97102
let p = p.strip_prefix(yazi_fs::CWD.load().as_ref()).unwrap_or(&p);
98103
assert_eq!((p, c.as_str()), (Path::new(parent), child));
99104
}

0 commit comments

Comments
 (0)