From 63381ee804b565d88d823c044ad7d9784906e603 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Thu, 9 Apr 2026 11:57:44 +0200 Subject: [PATCH 1/3] Feat: add Escape key to return to profile selection from normal mode --- src/tui/keys.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tui/keys.rs b/src/tui/keys.rs index 63ea160..d551f25 100644 --- a/src/tui/keys.rs +++ b/src/tui/keys.rs @@ -119,6 +119,11 @@ impl super::app::App { self.switch_to = true; self.quit = true; } + KeyCode::Esc => { + self.phone.hangup_all(); + self.switch_to = true; + self.quit = true; + } KeyCode::Char('d') if !ctrl => { self.dial.mode = InputMode::Dial; self.command.error = None; From 1a993c2b2582c98b7da9003e46c509a922f803e4 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Thu, 9 Apr 2026 11:59:13 +0200 Subject: [PATCH 2/3] Feat: accept Enter to confirm quit in addition to y --- src/tui/keys.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tui/keys.rs b/src/tui/keys.rs index d551f25..d09245b 100644 --- a/src/tui/keys.rs +++ b/src/tui/keys.rs @@ -16,7 +16,7 @@ impl super::app::App { // Quit confirmation captures all input if self.quit_confirm { match key.code { - KeyCode::Char('y') => { + KeyCode::Char('y') | KeyCode::Enter => { self.phone.hangup_all(); self.quit = true; } From e0330421e7ddc036fe0e6f05a29d2537e8a00321 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Thu, 9 Apr 2026 13:34:42 +0200 Subject: [PATCH 3/3] Feat: preserve profile selection when returning to picker via Escape --- src/app.rs | 13 ++++++++----- src/tui/mod.rs | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/app.rs b/src/app.rs index 375e1ef..0dcfbee 100644 --- a/src/app.rs +++ b/src/app.rs @@ -11,7 +11,7 @@ use crate::profile; pub fn run(name: Option, notify: bool) -> Result<()> { let mut current = match name { Some(n) => n, - None => pick_profile()?, + None => pick_profile(None)?, }; loop { @@ -64,14 +64,14 @@ fn run_one(name: &str, notify: bool) -> Result> { /// Open the interactive profile picker; loops until a profile is selected to start. /// Manages the terminal lifecycle; stays in alternate screen on success so the /// TUI can take over seamlessly. -pub fn pick_profile() -> Result { +pub fn pick_profile(focus: Option<&str>) -> Result { enable_raw_mode()?; let mut stdout = io::stdout(); execute!(stdout, EnterAlternateScreen)?; let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend)?; - let result = pick_profile_loop(&mut terminal); + let result = pick_profile_loop(&mut terminal, focus); if result.is_err() { let _ = disable_raw_mode(); @@ -81,9 +81,12 @@ pub fn pick_profile() -> Result { result } -fn pick_profile_loop(terminal: &mut Terminal>) -> Result { +fn pick_profile_loop( + terminal: &mut Terminal>, + initial_focus: Option<&str>, +) -> Result { use crate::picker::{PickerAction, PickerItem}; - let mut focus: Option = None; + let mut focus: Option = initial_focus.map(|s| s.to_string()); loop { let config = crate::config::load(); let theme = &config.theme; diff --git a/src/tui/mod.rs b/src/tui/mod.rs index ab984c6..9ca288e 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -168,7 +168,7 @@ pub fn run( } if app.switch_to { - match crate::app::pick_profile() { + match crate::app::pick_profile(Some(&app.profile_name)) { Ok(name) => return Ok(Some(name)), Err(_) => {} }