1use std::ops::{Deref, DerefMut};
2
3use anyhow::{Result, anyhow};
4use yazi_core::{Core, mgr::Tabs, tab::{Folder, Tab}, tasks::Tasks};
5use yazi_fs::File;
6use yazi_shared::{Id, Source, event::Cmd, url::UrlBuf};
7
8pub struct Ctx<'a> {
9 pub core: &'a mut Core,
10 pub tab: usize,
11 pub level: usize,
12 pub source: Source,
13 #[cfg(debug_assertions)]
14 pub backtrace: Vec<&'static str>,
15}
16
17impl Deref for Ctx<'_> {
18 type Target = Core;
19
20 fn deref(&self) -> &Self::Target { self.core }
21}
22
23impl DerefMut for Ctx<'_> {
24 fn deref_mut(&mut self) -> &mut Self::Target { self.core }
25}
26
27impl<'a> Ctx<'a> {
28 #[inline]
29 pub fn new(core: &'a mut Core, cmd: &Cmd) -> Result<Self> {
30 let tab = if let Ok(id) = cmd.get::<Id>("tab") {
31 core
32 .mgr
33 .tabs
34 .iter()
35 .position(|t| t.id == id)
36 .ok_or_else(|| anyhow!("Tab with id {id} not found"))?
37 } else {
38 core.mgr.tabs.cursor
39 };
40
41 Ok(Self {
42 core,
43 tab,
44 level: 0,
45 source: cmd.source,
46 #[cfg(debug_assertions)]
47 backtrace: vec![],
48 })
49 }
50
51 #[inline]
52 pub fn renew<'b>(cx: &'a mut Ctx<'b>) -> Self {
53 let tab = cx.core.mgr.tabs.cursor;
54 Self {
55 core: cx.core,
56 tab,
57 level: cx.level,
58 source: cx.source,
59 #[cfg(debug_assertions)]
60 backtrace: vec![],
61 }
62 }
63
64 #[inline]
65 pub fn active(core: &'a mut Core) -> Self {
66 let tab = core.mgr.tabs.cursor;
67 Self {
68 core,
69 tab,
70 level: 0,
71 source: Source::Unknown,
72 #[cfg(debug_assertions)]
73 backtrace: vec![],
74 }
75 }
76}
77
78impl<'a> Ctx<'a> {
79 #[inline]
80 pub fn tabs(&self) -> &Tabs { &self.mgr.tabs }
81
82 #[inline]
83 pub fn tabs_mut(&mut self) -> &mut Tabs { &mut self.mgr.tabs }
84
85 #[inline]
86 pub fn tab(&self) -> &Tab { &self.tabs()[self.tab] }
87
88 #[inline]
89 pub fn tab_mut(&mut self) -> &mut Tab { &mut self.core.mgr.tabs[self.tab] }
90
91 #[inline]
92 pub fn cwd(&self) -> &UrlBuf { self.tab().cwd() }
93
94 #[inline]
95 pub fn parent(&self) -> Option<&Folder> { self.tab().parent.as_ref() }
96
97 #[inline]
98 pub fn parent_mut(&mut self) -> Option<&mut Folder> { self.tab_mut().parent.as_mut() }
99
100 #[inline]
101 pub fn current(&self) -> &Folder { &self.tab().current }
102
103 #[inline]
104 pub fn current_mut(&mut self) -> &mut Folder { &mut self.tab_mut().current }
105
106 #[inline]
107 pub fn hovered(&self) -> Option<&File> { self.tab().hovered() }
108
109 #[inline]
110 pub fn hovered_folder(&self) -> Option<&Folder> { self.tab().hovered_folder() }
111
112 #[inline]
113 pub fn hovered_folder_mut(&mut self) -> Option<&mut Folder> {
114 self.tab_mut().hovered_folder_mut()
115 }
116
117 #[inline]
118 pub fn tasks(&self) -> &Tasks { &self.tasks }
119
120 #[inline]
121 pub fn source(&self) -> Source { if self.level != 1 { Source::Ind } else { self.source } }
122}