aboutsummaryrefslogtreecommitdiff
path: root/src/client/shell/worktrees.rs
diff options
context:
space:
mode:
authorMark Jaquith <mark@jaquith.me>2026-09-14 15:47:53 -0400
committerGitHub <noreply@github.com>2026-09-14 21:47:53 +0200
commitb0f21ed2cb85613050b794bf6c78a7c367a94e0d (patch)
tree25c14e09338f5300bedbc8131aa23fab3d37add9 /src/client/shell/worktrees.rs
parentd8b36691d10c6055293ad45324b22af8b8f570e5 (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.rs108
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,