yazi_core/manager/commands/
update_files.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::borrow::Cow;

use yazi_fs::FilesOp;
use yazi_macro::render;
use yazi_proxy::ManagerProxy;
use yazi_shared::event::CmdCow;

use crate::{manager::{LINKED, Manager}, tab::{Folder, Tab}, tasks::Tasks};

pub struct Opt {
	op: FilesOp,
}

impl TryFrom<CmdCow> for Opt {
	type Error = ();

	fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
		Ok(Self { op: c.take_any("op").ok_or(())? })
	}
}

impl Manager {
	pub fn update_files(&mut self, opt: impl TryInto<Opt>, tasks: &Tasks) {
		let Ok(opt) = opt.try_into() else {
			return;
		};

		let linked: Vec<_> = LINKED.read().from_dir(opt.op.cwd()).map(|u| opt.op.rebase(u)).collect();
		for op in [opt.op].into_iter().chain(linked) {
			let idx = self.tabs.cursor;
			self.yanked.apply_op(&op);

			for (_, tab) in self.tabs.iter_mut().enumerate().filter(|(i, _)| *i != idx) {
				Self::update_tab(tab, Cow::Borrowed(&op), tasks);
			}
			Self::update_tab(self.active_mut(), Cow::Owned(op), tasks);
		}

		render!(self.yanked.catchup_revision(false));
		self.active_mut().apply_files_attrs();
	}

	fn update_tab(tab: &mut Tab, op: Cow<FilesOp>, tasks: &Tasks) {
		let url = op.cwd();
		tab.selected.apply_op(&op);

		if url == tab.cwd() {
			Self::update_current(tab, op, tasks);
		} else if matches!(&tab.parent, Some(p) if *url == p.url) {
			Self::update_parent(tab, op);
		} else if matches!(tab.hovered(), Some(h) if *url == h.url) {
			Self::update_hovered(tab, op);
		} else {
			Self::update_history(tab, op);
		}
	}

	fn update_parent(tab: &mut Tab, op: Cow<FilesOp>) {
		let urn = tab.cwd().urn_owned();
		let leave = matches!(*op, FilesOp::Deleting(_, ref urns) if urns.contains(&urn));

		if let Some(f) = tab.parent.as_mut() {
			render!(f.update_pub(tab.id, op.into_owned()));
			render!(f.hover(urn.as_urn()));
		}

		if leave {
			tab.leave(());
		}
	}

	fn update_current(tab: &mut Tab, op: Cow<FilesOp>, tasks: &Tasks) {
		let calc = !matches!(*op, FilesOp::Size(..) | FilesOp::Deleting(..));
		let foreign = matches!(op, Cow::Borrowed(_));

		if !tab.current.update_pub(tab.id, op.into_owned()) {
			return;
		} else if foreign {
			return;
		}

		ManagerProxy::hover(None, tab.id); // Re-hover in next loop
		ManagerProxy::update_paged(); // Update for paged files in next loop
		if calc {
			tasks.prework_sorted(&tab.current.files);
		}
	}

	fn update_hovered(tab: &mut Tab, op: Cow<FilesOp>) {
		let url = op.cwd();
		let folder = tab.history.entry(url.clone()).or_insert_with(|| Folder::from(url));

		let foreign = matches!(op, Cow::Borrowed(_));
		if !folder.update_pub(tab.id, op.into_owned()) {
			return;
		}

		if !foreign {
			ManagerProxy::peek(true);
		}
	}

	fn update_history(tab: &mut Tab, op: Cow<FilesOp>) {
		let leave = tab.parent.as_ref().and_then(|f| f.url.parent_url().map(|p| (p, f.url.urn()))).is_some_and(
			|(p, n)| matches!(*op, FilesOp::Deleting(ref parent, ref urns) if *parent == p && urns.contains(n)),
		);

		tab
			.history
			.entry(op.cwd().clone())
			.or_insert_with(|| Folder::from(op.cwd()))
			.update_pub(tab.id, op.into_owned());

		if leave {
			tab.leave(());
		}
	}
}