1use nvim_oxi::Dictionary;
2use nvim_oxi::api::Buffer;
3use nvim_oxi::api::opts::CreateAutocmdOpts;
4use ytil_noxi::buffer::BufferExt;
5use ytil_noxi::mru_buffers::BufferKind;
6
7pub fn dict() -> Dictionary {
9 dict! {
10 "focus_term": fn_from!(focus_term),
11 "focus_buffer": fn_from!(focus_buffer),
12 "smart_close_buffer": fn_from!(smart_close_buffer),
13 "toggle_alternate_buffer": fn_from!(toggle_alternate_buffer),
14 }
15}
16
17pub fn create_autocmd() {
18 crate::cmds::create_autocmd(
19 ["BufEnter", "WinEnter", "TermOpen"],
20 "TerminalAutoInsertMode",
21 CreateAutocmdOpts::builder()
22 .patterns(["term://*"])
23 .command("startinsert"),
24 );
25}
26
27fn focus_term(width_perc: i32) -> Option<()> {
28 let current_buffer = nvim_oxi::api::get_current_buf();
29
30 if current_buffer.is_terminal() {
32 ytil_noxi::common::exec_vim_script("only", None)?;
33 return Some(());
34 }
35
36 let maybe_terminal_window = ytil_noxi::window::find_with_buffer("terminal");
38
39 if let Some((win, _)) = maybe_terminal_window {
41 ytil_noxi::window::set_current(&win)?;
42 return Some(());
43 }
44
45 let width = compute_width(width_perc)?;
46
47 if let Some(terminal_buffer) = nvim_oxi::api::list_bufs().find(BufferExt::is_terminal) {
49 ytil_noxi::common::exec_vim_script(&format!("leftabove vsplit | vertical resize {width}"), None);
50 ytil_noxi::buffer::set_current(&terminal_buffer)?;
51 return Some(());
52 }
53
54 ytil_noxi::common::exec_vim_script(&format!("leftabove vsplit | vertical resize {width} | term"), None);
56
57 Some(())
58}
59
60fn focus_buffer(width_perc: i32) -> Option<()> {
61 let current_buffer = nvim_oxi::api::get_current_buf();
62
63 if !current_buffer.is_terminal() {
65 ytil_noxi::common::exec_vim_script("only", None)?;
66 return Some(());
67 }
68
69 let maybe_buffer_window = ytil_noxi::window::find_with_buffer("");
71
72 if let Some((win, _)) = maybe_buffer_window {
74 ytil_noxi::window::set_current(&win)?;
75 return Some(());
76 }
77
78 let width = compute_width(width_perc)?;
80
81 ytil_noxi::common::exec_vim_script(&format!("vsplit | vertical resize {width}"), None)?;
83
84 let buffer = if let Some(mru_buffer) = ytil_noxi::mru_buffers::get()?
85 .iter()
86 .find(|b| matches!(b.kind, BufferKind::Path | BufferKind::NoName))
87 {
88 Buffer::from(mru_buffer)
89 } else {
90 ytil_noxi::buffer::create()?
91 };
92
93 ytil_noxi::buffer::set_current(&buffer)?;
94
95 Some(())
96}
97
98fn toggle_alternate_buffer(_: ()) -> Option<()> {
99 let alt_buf_id = nvim_oxi::api::call_function::<_, i32>("bufnr", ("#",))
100 .inspect_err(|err| ytil_noxi::notify::error(format!("error getting alternate buffer | error={err:?}")))
101 .ok()?;
102
103 if alt_buf_id != -1
104 && let alt_buf = Buffer::from(alt_buf_id)
105 && alt_buf.is_loaded()
106 && !alt_buf.is_terminal()
107 {
108 ytil_noxi::buffer::set_current(&alt_buf)?;
109 return Some(());
110 }
111
112 let current_buf = Buffer::current();
113 for buf in nvim_oxi::api::list_bufs().rev() {
114 if buf != current_buf
115 && buf.is_loaded()
116 && !buf.is_terminal()
117 && buf.get_buf_type().is_some_and(|bt| bt.is_empty())
118 && buf
119 .get_name()
120 .inspect_err(|err| {
121 ytil_noxi::notify::error(format!("error getting buffer name | buffer={buf:?} error={err:?}"));
122 })
123 .ok()
124 .is_some_and(|bn| !bn.is_empty())
125 {
126 ytil_noxi::buffer::set_current(&buf)?;
127 return Some(());
128 }
129 }
130
131 Some(())
132}
133
134fn smart_close_buffer(force_close: Option<bool>) -> Option<()> {
135 let mru_buffers = ytil_noxi::mru_buffers::get()?;
136
137 let Some(current_buffer) = mru_buffers.first() else {
138 return Some(());
139 };
140
141 let force = if force_close.is_some_and(std::convert::identity) {
142 "!"
143 } else {
144 ""
145 };
146
147 match current_buffer.kind {
148 BufferKind::Term | BufferKind::NoName => return Some(()),
149 BufferKind::GrugFar => {}
150 BufferKind::Path => {
151 let new_current_buffer = if let Some(mru_buffer) = mru_buffers.get(1)
152 && !matches!(mru_buffer.kind, BufferKind::Term)
153 {
154 Buffer::from(mru_buffer.id)
155 } else {
156 ytil_noxi::buffer::create()?
157 };
158
159 ytil_noxi::buffer::set_current(&new_current_buffer)?;
160 }
161 }
162
163 ytil_noxi::common::exec_vim_script(&format!("bd{force} {}", current_buffer.id), Option::default())?;
164
165 Some(())
166}
167
168pub fn compute_width(perc: i32) -> Option<i32> {
169 let total_width: i32 = crate::vim_opts::get("columns", &crate::vim_opts::global_scope())?;
170 Some((total_width.saturating_mul(perc)) / 100)
171}