Skip to content

Commit 4804e2e

Browse files
committed
feat: allow moving item to index
1 parent 81abc6a commit 4804e2e

File tree

2 files changed

+53
-26
lines changed

2 files changed

+53
-26
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
justfile
33
todo.md
44
*.rs.tmp*
5+
test.txt

src/main.rs

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ use std::io::Write;
1414
use std::time::Duration;
1515

1616
const TITLE_FG_COLOR: Color = Color::from_u32(0x282828);
17-
const TITLE_BG_COLOR: Color = Color::from_u32(0xd3869b);
18-
const SELECTED_ITEM_TEXT_FG_COLOR: Color = Color::from_u32(0xfb4934);
17+
const PRIMARY_COLOR: Color = Color::from_u32(0xd3869b);
1918
const TITLE: &str = " shfl ";
2019

2120
#[derive(Parser, Debug)]
@@ -97,7 +96,7 @@ impl From<&Item> for ListItem<'_> {
9796
fn from(value: &Item) -> Self {
9897
let line = match value.status {
9998
Selected::No => Line::from(value.line.clone()),
100-
Selected::Yes => Line::styled(value.line.clone(), SELECTED_ITEM_TEXT_FG_COLOR),
99+
Selected::Yes => Line::styled(value.line.clone(), PRIMARY_COLOR),
101100
};
102101
ListItem::new(line)
103102
}
@@ -118,19 +117,36 @@ enum RunningState {
118117

119118
#[derive(PartialEq)]
120119
enum Message {
121-
GoToNext,
122-
GoToPrevious,
123-
GoToFirst,
124-
GoToLast,
125-
SwitchWithNext,
126-
SwitchWithPrevious,
127-
SwitchWithFirst,
120+
MoveToIndex(usize),
121+
GoToNextItem,
122+
GoToPreviousPreview,
123+
GoToFirstItem,
124+
GoToLastItem,
125+
SwitchWithNextItem,
126+
SwitchWithPreviousItem,
127+
SwitchWithFirstItem,
128128
ToggleSelection,
129129
SaveSelection,
130130
Quit,
131131
}
132132

133133
impl Model {
134+
fn move_to_index(&mut self, index: usize) {
135+
if index > self.todo_list.items.len() - 1 {
136+
self.message = Some(UserMessage::Error("index is out of range".to_string()));
137+
return;
138+
}
139+
140+
let current = self.todo_list.state.selected();
141+
if let Some(i) = current {
142+
if i == index {
143+
return;
144+
}
145+
let removed = self.todo_list.items.remove(i);
146+
self.todo_list.items.insert(index, removed);
147+
self.todo_list.state.select(Some(index));
148+
}
149+
}
134150
fn select_next(&mut self) {
135151
self.todo_list.state.select_next();
136152
}
@@ -215,13 +231,14 @@ impl Model {
215231
fn update(model: &mut Model, msg: Message) -> Option<Message> {
216232
model.message = None;
217233
match msg {
218-
Message::GoToNext => model.select_next(),
219-
Message::GoToPrevious => model.select_previous(),
220-
Message::GoToLast => model.select_last(),
221-
Message::GoToFirst => model.select_first(),
222-
Message::SwitchWithNext => model.switch_with_next(),
223-
Message::SwitchWithPrevious => model.switch_with_previous(),
224-
Message::SwitchWithFirst => model.switch_with_first(),
234+
Message::MoveToIndex(i) => model.move_to_index(i),
235+
Message::GoToNextItem => model.select_next(),
236+
Message::GoToPreviousPreview => model.select_previous(),
237+
Message::GoToLastItem => model.select_last(),
238+
Message::GoToFirstItem => model.select_first(),
239+
Message::SwitchWithNextItem => model.switch_with_next(),
240+
Message::SwitchWithPreviousItem => model.switch_with_previous(),
241+
Message::SwitchWithFirstItem => model.switch_with_first(),
225242
Message::ToggleSelection => model.toggle_current(),
226243
Message::SaveSelection => model.save_selection(),
227244
Message::Quit => model.go_back_or_quit(),
@@ -241,7 +258,7 @@ fn view(model: &mut Model, frame: &mut Frame) {
241258
let base_title_style = Style::new().bold();
242259
let title_style = match model.message {
243260
Some(_) => base_title_style,
244-
None => base_title_style.bg(TITLE_BG_COLOR).fg(TITLE_FG_COLOR),
261+
None => base_title_style.bg(PRIMARY_COLOR).fg(TITLE_FG_COLOR),
245262
};
246263
let list = List::new(items)
247264
.block(
@@ -253,7 +270,7 @@ fn view(model: &mut Model, frame: &mut Frame) {
253270
.style(Style::new().white())
254271
.repeat_highlight_symbol(true)
255272
.highlight_symbol(">> ")
256-
.highlight_style(Style::new().fg(SELECTED_ITEM_TEXT_FG_COLOR))
273+
.highlight_style(Style::new().fg(PRIMARY_COLOR))
257274
.direction(ListDirection::TopToBottom);
258275

259276
frame.render_stateful_widget(list, frame.area(), &mut model.todo_list.state)
@@ -272,13 +289,22 @@ fn handle_event(_: &Model) -> anyhow::Result<Option<Message>> {
272289

273290
fn handle_key(key: event::KeyEvent) -> Option<Message> {
274291
match key.code {
275-
KeyCode::Char('j') => Some(Message::GoToNext),
276-
KeyCode::Char('k') => Some(Message::GoToPrevious),
277-
KeyCode::Char('g') => Some(Message::GoToFirst),
278-
KeyCode::Char('G') => Some(Message::GoToLast),
279-
KeyCode::Char('J') => Some(Message::SwitchWithNext),
280-
KeyCode::Char('K') => Some(Message::SwitchWithPrevious),
281-
KeyCode::Enter => Some(Message::SwitchWithFirst),
292+
KeyCode::Char('1') => Some(Message::MoveToIndex(0)),
293+
KeyCode::Char('2') => Some(Message::MoveToIndex(1)),
294+
KeyCode::Char('3') => Some(Message::MoveToIndex(2)),
295+
KeyCode::Char('4') => Some(Message::MoveToIndex(3)),
296+
KeyCode::Char('5') => Some(Message::MoveToIndex(4)),
297+
KeyCode::Char('6') => Some(Message::MoveToIndex(5)),
298+
KeyCode::Char('7') => Some(Message::MoveToIndex(6)),
299+
KeyCode::Char('8') => Some(Message::MoveToIndex(7)),
300+
KeyCode::Char('9') => Some(Message::MoveToIndex(8)),
301+
KeyCode::Char('j') => Some(Message::GoToNextItem),
302+
KeyCode::Char('k') => Some(Message::GoToPreviousPreview),
303+
KeyCode::Char('g') => Some(Message::GoToFirstItem),
304+
KeyCode::Char('G') => Some(Message::GoToLastItem),
305+
KeyCode::Char('J') => Some(Message::SwitchWithNextItem),
306+
KeyCode::Char('K') => Some(Message::SwitchWithPreviousItem),
307+
KeyCode::Enter => Some(Message::SwitchWithFirstItem),
282308
KeyCode::Char('s') | KeyCode::Char(' ') => Some(Message::ToggleSelection),
283309
KeyCode::Esc | KeyCode::Char('q') => Some(Message::Quit),
284310
KeyCode::Char('w') => Some(Message::SaveSelection),

0 commit comments

Comments
 (0)