aboutsummaryrefslogtreecommitdiff
path: root/src/app
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-20 22:03:49 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-20 22:08:26 +0300
commitdf357b250c0fcf4edf2681d4f114e199afb51899 (patch)
treeeba744d9238057e8758e2098670e0561d920d998 /src/app
parentc584037c77c63f6a08f8837f357c89432b8043e7 (diff)
fix: clarify keybinding conflict warnings
refs #154
Diffstat (limited to 'src/app')
-rw-r--r--src/app/input/modal.rs38
-rw-r--r--src/app/input/navigate.rs12
-rw-r--r--src/app/input/sidebar.rs8
-rw-r--r--src/app/mod.rs28
-rw-r--r--src/app/state.rs6
5 files changed, 52 insertions, 40 deletions
diff --git a/src/app/input/modal.rs b/src/app/input/modal.rs
index 5b585221..084f44a9 100644
--- a/src/app/input/modal.rs
+++ b/src/app/input/modal.rs
@@ -67,7 +67,7 @@ pub(super) fn modal_action_from_buttons<A: Copy>(
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum GlobalMenuAction {
- Quit,
+ Detach,
WhatsNew,
Keybinds,
ReloadConfig,
@@ -83,7 +83,7 @@ pub(super) fn global_menu_actions(state: &AppState) -> Vec<GlobalMenuAction> {
if state.update_available.is_some() || state.latest_release_notes_available {
actions.push(GlobalMenuAction::WhatsNew);
}
- actions.push(GlobalMenuAction::Quit);
+ actions.push(GlobalMenuAction::Detach);
actions
}
@@ -111,19 +111,19 @@ fn open_update_release_notes(state: &mut AppState) {
state.mode = Mode::ReleaseNotes;
}
-pub(super) fn request_quit_or_detach(state: &mut AppState) {
- if state.quit_detaches {
- state.detach_requested = true;
- } else {
+pub(super) fn request_detach(state: &mut AppState) {
+ if state.detach_exits {
state.should_quit = true;
+ } else {
+ state.detach_requested = true;
}
}
pub(super) fn apply_global_menu_action(state: &mut AppState, action: GlobalMenuAction) {
match action {
- GlobalMenuAction::Quit => {
+ GlobalMenuAction::Detach => {
leave_modal(state);
- request_quit_or_detach(state);
+ request_detach(state);
}
GlobalMenuAction::WhatsNew => open_update_release_notes(state),
GlobalMenuAction::Keybinds => open_keybind_help(state),
@@ -690,6 +690,28 @@ mod tests {
}
#[test]
+ fn detach_requests_client_detach_in_persistence_mode() {
+ let mut state = state_with_workspaces(&["test"]);
+ state.detach_exits = false;
+
+ request_detach(&mut state);
+
+ assert!(state.detach_requested);
+ assert!(!state.should_quit);
+ }
+
+ #[test]
+ fn detach_exits_in_no_session_mode() {
+ let mut state = state_with_workspaces(&["test"]);
+ state.detach_exits = true;
+
+ request_detach(&mut state);
+
+ assert!(state.should_quit);
+ assert!(!state.detach_requested);
+ }
+
+ #[test]
fn global_menu_whats_new_opens_saved_release_notes() {
let _guard = config_env_lock().lock().unwrap();
let path = temp_config_path("whats-new-saved-release-notes");
diff --git a/src/app/input/navigate.rs b/src/app/input/navigate.rs
index 8bf10832..17180fed 100644
--- a/src/app/input/navigate.rs
+++ b/src/app/input/navigate.rs
@@ -479,7 +479,6 @@ pub(crate) enum NavigateAction {
CyclePanePrevious,
Help,
Settings,
- Quit,
ReloadConfig,
OpenNotificationTarget,
Detach,
@@ -545,7 +544,6 @@ fn action_for_key(
for (bindings, action) in [
(&kb.help, NavigateAction::Help),
(&kb.settings, NavigateAction::Settings),
- (&kb.quit, NavigateAction::Quit),
(&kb.workspace_picker, NavigateAction::WorkspacePicker),
(&kb.new_workspace, NavigateAction::NewWorkspace),
(&kb.rename_workspace, NavigateAction::RenameWorkspace),
@@ -727,10 +725,6 @@ pub(super) fn execute_navigate_action_in_context(
}
NavigateAction::Help => super::modal::open_keybind_help(state),
NavigateAction::Settings => super::settings::open_settings(state),
- NavigateAction::Quit => {
- super::modal::request_quit_or_detach(state);
- leave_navigate_mode(state);
- }
NavigateAction::ReloadConfig => {
state.request_reload_config = true;
leave_navigate_mode(state);
@@ -742,7 +736,7 @@ pub(super) fn execute_navigate_action_in_context(
}
}
NavigateAction::Detach => {
- state.detach_requested = true;
+ super::modal::request_detach(state);
leave_navigate_mode(state);
}
}
@@ -1449,9 +1443,9 @@ mod tests {
}
#[test]
- fn persistence_mode_navigate_q_detaches_instead_of_quitting_server() {
+ fn navigate_q_detaches_in_persistence_mode() {
let mut state = crate::app::state::AppState::test_new();
- state.quit_detaches = true;
+ state.detach_exits = false;
handle_navigate_key(
&mut state,
diff --git a/src/app/input/sidebar.rs b/src/app/input/sidebar.rs
index 7491c9c1..dc192e50 100644
--- a/src/app/input/sidebar.rs
+++ b/src/app/input/sidebar.rs
@@ -192,7 +192,7 @@ impl AppState {
} else if self.latest_release_notes_available {
labels.push("what's new");
}
- labels.push(if self.quit_detaches { "detach" } else { "quit" });
+ labels.push("detach");
labels
}
@@ -578,7 +578,7 @@ mod tests {
"keybinds",
"reload config",
"update ready",
- "quit"
+ "detach"
]
);
assert!(!app.state.should_quit);
@@ -587,7 +587,7 @@ mod tests {
#[test]
fn persistence_mode_menu_surfaces_detach_action() {
let mut app = app_for_mouse_test();
- app.state.quit_detaches = true;
+ app.state.detach_exits = false;
let launcher = app.state.global_launcher_rect();
app.handle_mouse(mouse(
@@ -625,7 +625,7 @@ mod tests {
"keybinds",
"reload config",
"what's new",
- "quit"
+ "detach"
]
);
}
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 63bf690d..b87eec66 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -338,7 +338,7 @@ impl App {
selected,
mode,
should_quit: false,
- quit_detaches: !no_session,
+ detach_exits: no_session,
detach_requested: false,
request_new_workspace: false,
request_new_tab: false,
@@ -466,10 +466,7 @@ impl App {
});
Self {
- config_diagnostic_deadline: state
- .config_diagnostic
- .as_ref()
- .map(|_| Instant::now() + Duration::from_secs(8)),
+ config_diagnostic_deadline: None,
toast_deadline: None,
state,
event_tx,
@@ -797,7 +794,7 @@ impl App {
self.state.toast = None;
self.state.config_diagnostic =
crate::config::config_diagnostic_summary(&diagnostics);
- self.config_diagnostic_deadline = Some(Instant::now() + Duration::from_secs(8));
+ self.config_diagnostic_deadline = None;
crate::config::ConfigReloadReport {
status: crate::config::ConfigReloadStatus::Failed,
diagnostics,
@@ -827,11 +824,11 @@ impl App {
self.state.keybinds = live.keybinds;
}
Err(keybind_diagnostics) => {
- let mut message = keybind_diagnostics.join("; ");
- if !message.contains("keeping current keybinds") {
- message.push_str("; keeping current keybinds");
- }
- diagnostics.push(message);
+ diagnostics.extend(
+ keybind_diagnostics
+ .into_iter()
+ .map(|diagnostic| format!("{diagnostic}; kept current keybinds")),
+ );
}
}
}
@@ -928,7 +925,7 @@ impl App {
}
} else {
self.state.config_diagnostic = crate::config::config_diagnostic_summary(&diagnostics);
- self.config_diagnostic_deadline = Some(Instant::now() + Duration::from_secs(8));
+ self.config_diagnostic_deadline = None;
if notify_success {
self.state.toast = Some(crate::app::state::ToastNotification {
kind: crate::app::state::ToastKind::UpdateInstalled,
@@ -1545,8 +1542,7 @@ mod tests {
.config_diagnostic
.as_deref()
.is_some_and(|message| {
- message.contains("keys.new_workspace")
- && message.contains("keeping current keybinds")
+ message.contains("keys.new_workspace") && message.contains("kept current keybinds")
}));
std::env::remove_var(crate::config::CONFIG_PATH_ENV_VAR);
@@ -2514,7 +2510,7 @@ mod tests {
app.state.workspaces = vec![Workspace::test_new("test")];
app.state.active = Some(0);
app.state.selected = 0;
- app.state.quit_detaches = true;
+ app.state.detach_exits = false;
// Start in navigate mode.
app.state.mode = Mode::Navigate;
@@ -2540,7 +2536,7 @@ mod tests {
app.state.workspaces = vec![Workspace::test_new("test")];
app.state.active = Some(0);
app.state.selected = 0;
- app.state.quit_detaches = true;
+ app.state.detach_exits = false;
// Start in terminal mode (default after workspace creation).
app.state.mode = Mode::Terminal;
diff --git a/src/app/state.rs b/src/app/state.rs
index 921a82c9..7ee79c4a 100644
--- a/src/app/state.rs
+++ b/src/app/state.rs
@@ -900,8 +900,8 @@ pub struct AppState {
pub selected: usize,
pub mode: Mode,
pub should_quit: bool,
- /// In persistence mode, client quit actions detach instead of stopping the server.
- pub quit_detaches: bool,
+ /// In monolithic --no-session mode, detach exits the app because there is no server to detach from.
+ pub detach_exits: bool,
/// Set when the current client should detach from the persistent session.
/// The server's event loop checks this and handles client detach.
pub detach_requested: bool,
@@ -1159,7 +1159,7 @@ impl AppState {
selected: 0,
mode: Mode::Navigate,
should_quit: false,
- quit_detaches: false,
+ detach_exits: false,
detach_requested: false,
request_new_workspace: false,
request_new_tab: false,