use crate::tui::{AddConnectionForm, AppMode, AppState, ConfirmAction, Overlay};
pub fn cmd_exit(state: &mut AppState) {
state.should_quit = true;
}
pub fn cmd_quit(state: &mut AppState, args: &[&str]) {
let pane_count = state.active_tab().map(|tab| tab.tree.pane_count());
match pane_count {
Some(count) if count > 1 => super::pane::cmd_close(state, args),
Some(_) if state.tabs.len() > 1 => super::tab::cmd_tab_delete(state),
Some(_) | None => {
state.should_quit = true;
}
}
}
pub fn cmd_help(state: &mut AppState) {
let overlay = if state.mode == AppMode::Dashboard {
Overlay::DashboardHelp
} else {
Overlay::Help
};
state.overlay = Some(overlay);
}
pub fn cmd_add(state: &mut AppState) {
state.overlay = Some(Overlay::AddConnection);
state.form = Some(AddConnectionForm::new());
}
pub fn cmd_connect(state: &mut AppState) {
state.overlay = Some(Overlay::ConnectionPicker);
}
pub fn cmd_disconnect(state: &mut AppState) {
if state.tabs.is_empty() {
state.cmdline.set_error("not connected");
return;
}
state.tabs = vec![];
state.active_tab = 0;
state.mode = AppMode::Home;
state.cmdline.reset();
}
pub fn cmd_delete(state: &mut AppState, args: &[&str]) {
let name_input = args.join(" ").trim().to_string();
if name_input.is_empty() {
state.cmdline.set_error("usage: :delete <connection name>");
return;
}
let target = state
.connections
.iter()
.find(|db| db.name == name_input)
.or_else(|| {
state
.connections
.iter()
.find(|db| db.name.eq_ignore_ascii_case(&name_input))
})
.map(|db| db.name.clone());
if let Some(name) = target {
state
.cmdline
.open_confirm(ConfirmAction::DeleteConnection(name));
} else {
state
.cmdline
.set_error(format!("connection `{name_input}` not found"));
}
}
pub fn cmd_back(state: &mut AppState) {
let result = state.active_tab_mut().and_then(|tab| {
tab.tree.active_mut().map(|pane| {
let went_back = pane.go_back();
let needs_load = if went_back && pane.kind == crate::tui::state::PaneType::TableView {
pane.bound_table.clone()
} else {
None
};
(went_back, needs_load)
})
});
let Some((went_back, table_name)) = result else {
state.cmdline.set_error("not in dashboard");
return;
};
if went_back {
if let Some(name) = table_name {
let cache_has = state.table_cache.contains_key(&name);
let Some(tab) = state.active_tab_mut() else {
return;
};
if !cache_has {
tab.pending_load = Some(crate::tui::state::tab::PendingQuery {
table: name,
filter: None,
sort_col: None,
sort_desc: false,
selected_cols: None,
});
tab.loading = true;
tab.error = None;
}
}
} else {
state.cmdline.set_error("no previous view");
}
}
pub fn cmd_forward(state: &mut AppState) {
let result = state.active_tab_mut().and_then(|tab| {
tab.tree.active_mut().map(|pane| {
let went_forward = pane.go_forward();
let needs_load = if went_forward && pane.kind == crate::tui::state::PaneType::TableView
{
pane.bound_table.clone()
} else {
None
};
(went_forward, needs_load)
})
});
let Some((went_forward, table_name)) = result else {
state.cmdline.set_error("not in dashboard");
return;
};
if went_forward {
if let Some(name) = table_name {
let cache_has = state.table_cache.contains_key(&name);
let Some(tab) = state.active_tab_mut() else {
return;
};
if !cache_has {
tab.pending_load = Some(crate::tui::state::tab::PendingQuery {
table: name,
filter: None,
sort_col: None,
sort_desc: false,
selected_cols: None,
});
tab.loading = true;
tab.error = None;
}
}
} else {
state.cmdline.set_error("no next view");
}
}
pub fn cmd_resize(state: &mut AppState, args: &[&str]) {
let Some(tab) = state.active_tab_mut() else {
state.cmdline.set_error("not in dashboard");
return;
};
if args.is_empty() {
state.cmdline.set_error(":resize requires +N or -N");
return;
}
let arg = args.join(" ");
let delta = match arg.parse::<i32>() {
Ok(v) if (-100..=100).contains(&v) => v,
Ok(_) => {
state
.cmdline
.set_error("resize value must be between -100 and 100");
return;
}
Err(_) => {
state
.cmdline
.set_error(format!("invalid resize value `{arg}`"));
return;
}
};
match tab.tree.resize_active(delta) {
Ok(_) => {}
Err(e) => state.cmdline.set_error(e),
}
}
pub fn cmd_fullscreen(state: &mut AppState) {
let Some(tab) = state.active_tab_mut() else {
state.cmdline.set_error("not in dashboard");
return;
};
if tab.tree.pane_count() <= 1 {
state
.cmdline
.set_error("only one pane — nothing to fullscreen");
return;
}
tab.tree.toggle_fullscreen();
}
pub fn cmd_bang(state: &mut AppState, args: &[&str]) {
let sql = args.join(" ").trim().to_string();
if sql.is_empty() {
state.cmdline.set_error("! requires an SQL query");
return;
}
let Some(tab) = state.active_tab_mut() else {
state.cmdline.set_error("not in dashboard");
return;
};
tab.pending_query_exec = Some(sql);
tab.loading = true;
tab.error = None;
let active_id = tab.tree.active_pane;
if let Some(pane) = tab.tree.panes.get_mut(&active_id) {
pane.set_query_results(0);
pane.query_result_count = 1;
}
}