diff options
| author | Mark Jaquith <mark@jaquith.me> | 2026-09-14 15:47:53 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-14 21:47:53 +0200 |
| commit | b0f21ed2cb85613050b794bf6c78a7c367a94e0d (patch) | |
| tree | 25c14e09338f5300bedbc8131aa23fab3d37add9 /src/client/shell/worktrees.rs | |
| parent | d8b36691d10c6055293ad45324b22af8b8f570e5 (diff) | |
feat: add cursor-based editing to text inputs (#3698)
* feat: add cursor-based editing to text inputs
refs #1803
* fix: preserve dialog actions with associated text
refs #1803
* refactor: simplify text editor outcomes and tests
refs #1803
---------
Co-authored-by: JJ Liebig <jonathan.liebig@gmail.com>
Diffstat (limited to 'src/client/shell/worktrees.rs')
| -rw-r--r-- | src/client/shell/worktrees.rs | 108 |
1 files changed, 44 insertions, 64 deletions
diff --git a/src/client/shell/worktrees.rs b/src/client/shell/worktrees.rs index d4253672..56c554c8 100644 --- a/src/client/shell/worktrees.rs +++ b/src/client/shell/worktrees.rs @@ -24,20 +24,18 @@ impl ClientShellState { pub(super) fn insert_worktree_overlay_text(&mut self, text: &str) -> bool { match self.overlay.as_mut() { Some(ClientShellOverlay::WorktreeCreate(create)) if !create.creating => { - if create.replace_on_type { - create.branch.clear(); - create.replace_on_type = false; + if create.branch.insert(text) { + self.sync_worktree_create_path(); } - create.branch.push_str(text); - self.sync_worktree_create_path(); true } Some(ClientShellOverlay::WorktreeOpen(open)) if open.search_focused && !open.opening => { - open.query.push_str(text); - if let Some(first) = open.filtered_indices().first().copied() { - open.selected = first; + if open.query.insert(text) { + if let Some(first) = open.filtered_indices().first().copied() { + open.selected = first; + } } true } @@ -59,39 +57,24 @@ impl ClientShellState { ClientWorktreeCreateOverlay { creating: true, .. } )) ); + if !creating { + if let Some(ClientShellOverlay::WorktreeCreate(create)) = self.overlay.as_mut() + { + if let Some(content_changed) = create.branch.handle_key(key) { + if content_changed { + self.sync_worktree_create_path(); + } + outcome.repaint = true; + return true; + } + } + } match code { KeyCode::Esc if !creating => { self.overlay = None; outcome.repaint = true; } KeyCode::Enter => self.submit_worktree_create(outcome), - KeyCode::Backspace if !creating => { - if let Some(ClientShellOverlay::WorktreeCreate(create)) = - self.overlay.as_mut() - { - if create.replace_on_type { - create.branch.clear(); - create.replace_on_type = false; - } else { - create.branch.pop(); - } - } - self.sync_worktree_create_path(); - outcome.repaint = true; - } - KeyCode::Char(character) - if !creating - && modifiers - .difference(crossterm::event::KeyModifiers::SHIFT) - .is_empty() => - { - let text = key - .generated_text - .clone() - .unwrap_or_else(|| character.to_string()); - self.insert_worktree_overlay_text(&text); - outcome.repaint = true; - } _ => {} } true @@ -112,6 +95,19 @@ impl ClientShellState { } )) ); + if !opening && search_focused { + if let Some(ClientShellOverlay::WorktreeOpen(open)) = self.overlay.as_mut() { + if let Some(content_changed) = open.query.handle_key(key) { + if content_changed { + if let Some(first) = open.filtered_indices().first().copied() { + open.selected = first; + } + } + outcome.repaint = true; + return true; + } + } + } match code { KeyCode::Esc if !opening => { self.overlay = None; @@ -126,37 +122,23 @@ impl ClientShellState { self.move_worktree_open_selection(1); outcome.repaint = true; } - KeyCode::Char('/') if !opening && !search_focused => { - if let Some(ClientShellOverlay::WorktreeOpen(open)) = self.overlay.as_mut() - { - open.search_focused = true; - } + KeyCode::Char('n' | 'p') + if !opening && modifiers == crossterm::event::KeyModifiers::CONTROL => + { + self.move_worktree_open_selection(if code == KeyCode::Char('n') { + 1 + } else { + -1 + }); outcome.repaint = true; } - KeyCode::Backspace if !opening && search_focused => { + KeyCode::Char('/') if !opening && !search_focused => { if let Some(ClientShellOverlay::WorktreeOpen(open)) = self.overlay.as_mut() { - open.query.pop(); - if let Some(first) = open.filtered_indices().first().copied() { - open.selected = first; - } + open.search_focused = true; } outcome.repaint = true; } - KeyCode::Char(character) - if !opening - && search_focused - && modifiers - .difference(crossterm::event::KeyModifiers::SHIFT) - .is_empty() => - { - let text = key - .generated_text - .clone() - .unwrap_or_else(|| character.to_string()); - self.insert_worktree_overlay_text(&text); - outcome.repaint = true; - } _ => {} } true @@ -274,8 +256,7 @@ impl ClientShellState { outcome.repaint = true; return; } - create.branch = branch.clone(); - create.replace_on_type = false; + create.branch.trim_and_accept(); create.checkout_path = checkout_path_preview(&worktree_directory, &create.repo_name, &branch); create.creating = true; @@ -411,9 +392,8 @@ impl ClientShellState { ClientWorktreeCreateOverlay { source_workspace_id: workspace_id, repo_name: source.repo_name, - branch, + branch: TextEditor::new(&branch, true), checkout_path, - replace_on_type: true, error: None, creating: false, }, @@ -447,7 +427,7 @@ impl ClientShellState { source_workspace_id: workspace_id, entries, selected: 0, - query: String::new(), + query: TextEditor::default(), search_focused: false, error: None, opening: false, |
