1use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Action {
8 Continue,
10 Quit,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum Pane {
17 Ready,
19 List,
21 Claims,
23 Agenda,
25 Search,
27}
28
29impl Pane {
30 pub const ALL: [Pane; 5] = [
32 Pane::Ready,
33 Pane::List,
34 Pane::Claims,
35 Pane::Agenda,
36 Pane::Search,
37 ];
38
39 pub fn title(self) -> &'static str {
41 match self {
42 Self::Ready => "Ready",
43 Self::List => "List",
44 Self::Claims => "Claims",
45 Self::Agenda => "Agenda",
46 Self::Search => "Search",
47 }
48 }
49
50 pub fn index(self) -> usize {
52 Self::ALL.iter().position(|p| *p == self).unwrap_or(0)
53 }
54
55 pub fn from_index(i: usize) -> Self {
57 Self::ALL[i % Self::ALL.len()]
58 }
59
60 pub fn next(self) -> Self {
62 Self::from_index(self.index() + 1)
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum DetailTab {
69 Show,
71 Excerpt,
73 Tree,
75 Related,
77 Recall,
79}
80
81impl DetailTab {
82 pub const ALL: [DetailTab; 5] = [
84 DetailTab::Show,
85 DetailTab::Excerpt,
86 DetailTab::Tree,
87 DetailTab::Related,
88 DetailTab::Recall,
89 ];
90
91 pub fn title(self) -> &'static str {
93 match self {
94 Self::Show => "show",
95 Self::Excerpt => "excerpt",
96 Self::Tree => "tree",
97 Self::Related => "related",
98 Self::Recall => "recall",
99 }
100 }
101
102 pub fn next(self) -> Self {
104 let i = Self::ALL.iter().position(|t| *t == self).unwrap_or(0);
105 Self::ALL[(i + 1) % Self::ALL.len()]
106 }
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub enum Focus {
112 Rows,
114 Detail,
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub enum PromptKind {
121 Search,
123 Note,
125 Deed,
127 Project,
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
133pub enum ConfirmKind {
134 Done,
136 Cancelled,
138}
139
140impl ConfirmKind {
141 pub fn state(self) -> &'static str {
143 match self {
144 Self::Done => "DONE",
145 Self::Cancelled => "CANCELLED",
146 }
147 }
148}
149
150pub fn is_press(key: KeyEvent) -> bool {
152 key.kind == KeyEventKind::Press || key.kind == KeyEventKind::Repeat
153}
154
155pub fn char_of(key: KeyEvent) -> Option<char> {
157 match key.code {
158 KeyCode::Char(c) if key.modifiers.is_empty() || key.modifiers == KeyModifiers::SHIFT => {
159 Some(c)
160 }
161 _ => None,
162 }
163}
164
165pub const HELP: &str = "\
167vissue tui
168
169j/k, arrows move
170Tab, 1-5 pane (Ready List Claims Agenda Search)
171Enter focus detail / cycle detail tab
172p project filter
173/ search
174c claim
175n note
176s cycle TODO / STARTED / BLOCKED
177D DONE (confirm)
178X CANCELLED (confirm)
179o open (shared selection)
180y copy id
181R reload
182? this help
183q / Esc quit / back
184
185Body edits stay in the file.
186body lives in file; open the range above
187";