1use std::path::Path;
8
9use nvim_oxi::Dictionary;
10use serde::Deserialize;
11use ytil_noxi::buffer::BufferExt;
12
13pub fn dict() -> Dictionary {
15 dict! {
16 "run_test": fn_from!(run_test),
17 }
18}
19
20#[derive(Clone, Copy, Deserialize)]
21enum TargetTerminal {
22 WezTerm,
23 Nvim,
24}
25
26ytil_noxi::impl_nvim_deserializable!(TargetTerminal);
27
28fn run_test(target_terminal: TargetTerminal) -> Option<()> {
29 let file_path = ytil_noxi::buffer::get_absolute_path(Some(&nvim_oxi::api::get_current_buf()))?;
30
31 let test_name = ytil_noxi::tree_sitter::get_enclosing_fn_name_of_position(&file_path)?;
32
33 let test_runner = get_test_runner_for_path(&file_path)
34 .inspect_err(|err| {
35 ytil_noxi::notify::error(format!(
36 "error getting test runner | path={} error={err:#?}",
37 file_path.display()
38 ));
39 })
40 .ok()?;
41
42 match target_terminal {
43 TargetTerminal::WezTerm => run_test_in_wezterm(test_runner, &test_name),
44 TargetTerminal::Nvim => run_test_in_nvim_term(test_runner, &test_name),
45 }
46}
47
48fn run_test_in_wezterm(test_runner: &str, test_name: &str) -> Option<()> {
49 let cur_pane_id = ytil_wezterm::get_current_pane_id()
50 .inspect_err(|err| ytil_noxi::notify::error(format!("error getting current WezTerm pane id | error={err:#?}")))
51 .ok()?;
52
53 let wez_panes = ytil_wezterm::get_all_panes(&[])
54 .inspect_err(|err| {
55 ytil_noxi::notify::error(format!("error getting WezTerm panes | error={err:#?}"));
56 })
57 .ok()?;
58
59 let Some(cur_pane) = wez_panes.iter().find(|p| p.pane_id == cur_pane_id) else {
60 ytil_noxi::notify::error(format!(
61 "error WezTerm pane not found | pane_id={cur_pane_id:#?} panes={wez_panes:#?}"
62 ));
63 return None;
64 };
65
66 let Some(test_runner_pane) = wez_panes.iter().find(|p| p.is_sibling_terminal_pane_of(cur_pane)) else {
67 ytil_noxi::notify::error(format!(
68 "error finding sibling pane to run test | current_pane={cur_pane:#?} panes={wez_panes:#?} test={test_name}"
69 ));
70 return None;
71 };
72
73 let test_run_cmd = format!("'{test_runner} {test_name}'");
74
75 let send_text_to_pane_cmd = ytil_wezterm::send_text_to_pane_cmd(&test_run_cmd, test_runner_pane.pane_id);
76 let submit_pane_cmd = ytil_wezterm::submit_pane_cmd(test_runner_pane.pane_id);
77
78 ytil_cmd::silent_cmd("sh")
79 .args(["-c", &format!("{send_text_to_pane_cmd} && {submit_pane_cmd}")])
80 .spawn()
81 .inspect_err(|err| {
82 ytil_noxi::notify::error(format!(
83 "error executing test run cmd | cmd={test_run_cmd:#?} pane={test_runner_pane:#?} error={err:#?}"
84 ));
85 })
86 .ok()?;
87
88 Some(())
89}
90
91fn run_test_in_nvim_term(test_runner: &str, test_name: &str) -> Option<()> {
92 let Some(terminal_buffer) = nvim_oxi::api::list_bufs().find(BufferExt::is_terminal) else {
93 ytil_noxi::notify::error(format!(
94 "error no terminal buffer found | test_runner={test_runner:?} test_name={test_name:?}",
95 ));
96 return None;
97 };
98
99 terminal_buffer.send_command(&format!("{test_runner} {test_name}\n"));
100
101 Some(())
102}
103
104fn get_test_runner_for_path(path: &Path) -> rootcause::Result<&'static str> {
118 let git_repo_root = ytil_git::repo::get_root(&ytil_git::repo::discover(path)?);
119
120 if git_repo_root.join("Makefile.toml").exists() {
121 return Ok("cargo make test");
122 }
123
124 Ok("cargo test")
125}