tmx/ui/
worktree_picker.rs1use anyhow::Result;
2use ratatui::style::Style;
3use ratatui::text::{Line, Span};
4
5use crate::ui::picker::{PickerConfig, PickerItem, run_picker};
6use crate::ui::theme;
7use crate::worktree::{WorktreeEntry, short_branch};
8
9impl PickerItem for WorktreeEntry {
10 fn fuzzy_key(&self) -> &str {
11 if let Some(b) = self.branch.as_deref() {
13 short_branch(b)
14 } else {
15 self.path.to_str().unwrap_or("(detached)")
20 }
21 }
22
23 fn render(&self, is_cursor: bool) -> Line<'static> {
24 let (cursor_marker, name_style) = if is_cursor {
25 (
26 Span::styled("▸ ", Style::default().fg(theme::VIOLET)),
27 theme::selected_style(),
28 )
29 } else {
30 (Span::raw(" "), theme::normal_style())
31 };
32
33 let label = match self.branch.as_deref() {
34 Some(b) => short_branch(b).to_string(),
35 None => "(detached)".to_string(),
36 };
37
38 let mut spans = vec![
39 cursor_marker,
40 Span::styled(label, name_style),
41 Span::styled(format!(" {}", self.path.display()), theme::muted_style()),
42 ];
43 if self.locked {
44 spans.push(Span::styled(
45 " [locked]",
46 Style::default().fg(theme::VIOLET),
47 ));
48 }
49 if self.prunable {
50 spans.push(Span::styled(" [prunable]", theme::muted_style()));
51 }
52 Line::from(spans)
53 }
54}
55
56pub fn run_worktree_picker(entries: Vec<WorktreeEntry>) -> Result<Option<WorktreeEntry>> {
57 run_picker(
58 entries,
59 PickerConfig {
60 title: "git worktrees",
61 search_placeholder: "Search worktrees...",
62 empty_message: "No worktrees",
63 item_noun: "worktrees",
64 },
65 )
66}