Skip to content

Commit 7c6f86b

Browse files
committed
add BranchSortPopup
1 parent b7b7705 commit 7c6f86b

File tree

9 files changed

+457
-13
lines changed

9 files changed

+457
-13
lines changed

asyncgit/src/sync/branch/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ use super::{
1111
};
1212
use crate::{
1313
error::{Error, Result},
14-
sync::{repository::repo, utils::get_head_repo, CommitId},
14+
sync::{
15+
repository::repo, utils::get_head_repo, CommitId,
16+
CommitSignature,
17+
},
1518
};
1619
use git2::{Branch, BranchType, Repository};
1720
use scopetime::scope_time;
@@ -92,6 +95,10 @@ pub struct BranchInfo {
9295
///
9396
pub top_commit: CommitId,
9497
///
98+
pub top_commit_time: i64,
99+
///
100+
pub top_commit_author: String,
101+
///
95102
pub details: BranchDetails,
96103
}
97104

@@ -181,13 +188,17 @@ pub fn get_branches_info(
181188
})
182189
};
183190

191+
let author = CommitSignature::from(&top_commit.author());
192+
184193
Ok(BranchInfo {
185194
name: bytes2string(name_bytes)?,
186195
reference,
187196
top_commit_message: bytes2string(
188197
top_commit.summary_bytes().unwrap_or_default(),
189198
)?,
190199
top_commit: top_commit.id().into(),
200+
top_commit_time: top_commit.time().seconds(),
201+
top_commit_author: author.name,
191202
details,
192203
})
193204
})

src/app.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ use crate::{
1010
options::{Options, SharedOptions},
1111
popup_stack::PopupStack,
1212
popups::{
13-
AppOption, BlameFilePopup, BranchListPopup, CommitPopup,
14-
CompareCommitsPopup, ConfirmPopup, CreateBranchPopup,
15-
ExternalEditorPopup, FetchPopup, FileRevlogPopup,
16-
FuzzyFindPopup, HelpPopup, InspectCommitPopup,
17-
LogSearchPopupPopup, MsgPopup, OptionsPopup, PullPopup,
18-
PushPopup, PushTagsPopup, RenameBranchPopup, ResetPopup,
19-
RevisionFilesPopup, StashMsgPopup, SubmodulesListPopup,
20-
TagCommitPopup, TagListPopup,
13+
AppOption, BlameFilePopup, BranchListPopup, BranchSortPopup,
14+
CommitPopup, CompareCommitsPopup, ConfirmPopup,
15+
CreateBranchPopup, ExternalEditorPopup, FetchPopup,
16+
FileRevlogPopup, FuzzyFindPopup, HelpPopup,
17+
InspectCommitPopup, LogSearchPopupPopup, MsgPopup,
18+
OptionsPopup, PullPopup, PushPopup, PushTagsPopup,
19+
RenameBranchPopup, ResetPopup, RevisionFilesPopup,
20+
StashMsgPopup, SubmodulesListPopup, TagCommitPopup,
21+
TagListPopup,
2122
},
2223
queue::{
2324
Action, AppTabs, InternalEvent, NeedsUpdate, Queue,
@@ -88,6 +89,7 @@ pub struct App {
8889
create_branch_popup: CreateBranchPopup,
8990
rename_branch_popup: RenameBranchPopup,
9091
select_branch_popup: BranchListPopup,
92+
sort_branch_popup: BranchSortPopup,
9193
options_popup: OptionsPopup,
9294
submodule_popup: SubmodulesListPopup,
9395
tags_popup: TagListPopup,
@@ -196,6 +198,7 @@ impl App {
196198
submodule_popup: SubmodulesListPopup::new(&env),
197199
log_search_popup: LogSearchPopupPopup::new(&env),
198200
fuzzy_find_popup: FuzzyFindPopup::new(&env),
201+
sort_branch_popup: BranchSortPopup::new(&env),
199202
do_quit: QuitState::None,
200203
cmdbar: RefCell::new(CommandBar::new(
201204
env.theme.clone(),
@@ -468,6 +471,7 @@ impl App {
468471
[
469472
log_search_popup,
470473
fuzzy_find_popup,
474+
sort_branch_popup,
471475
msg_popup,
472476
confirm_popup,
473477
commit_popup,
@@ -517,6 +521,7 @@ impl App {
517521
reset_popup,
518522
create_branch_popup,
519523
rename_branch_popup,
524+
sort_branch_popup,
520525
revision_files_popup,
521526
fuzzy_find_popup,
522527
log_search_popup,
@@ -803,6 +808,16 @@ impl App {
803808
flags
804809
.insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS);
805810
}
811+
InternalEvent::OpenBranchSortPopup(sort_by) => {
812+
self.sort_branch_popup.open(sort_by)?;
813+
flags
814+
.insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS);
815+
}
816+
InternalEvent::BranchListSort(sort_by) => {
817+
self.select_branch_popup.sort(sort_by)?;
818+
flags
819+
.insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS);
820+
}
806821
InternalEvent::OptionSwitched(o) => {
807822
match o {
808823
AppOption::StatusShowUntracked => {

src/components/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,16 @@ pub enum FuzzyFinderTarget {
191191
Files,
192192
}
193193

194+
#[derive(Copy, Clone)]
195+
pub enum BranchListSortBy {
196+
LastCommitTimeAsc,
197+
LastCommitTimeDesc,
198+
BranchNameAsc,
199+
BranchNameDesc,
200+
LastCommitAuthorAsc,
201+
LastCommitAuthorDesc,
202+
}
203+
194204
impl EventState {
195205
pub fn is_consumed(&self) -> bool {
196206
*self == Self::Consumed

src/keys/key_list.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ pub struct KeysList {
107107
pub open_file_tree: GituiKeyEvent,
108108
pub file_find: GituiKeyEvent,
109109
pub branch_find: GituiKeyEvent,
110+
pub branch_sort: GituiKeyEvent,
111+
pub branch_sort_by_name: GituiKeyEvent,
112+
pub branch_sort_by_name_rev: GituiKeyEvent,
113+
pub branch_sort_by_time: GituiKeyEvent,
114+
pub branch_sort_by_time_rev: GituiKeyEvent,
115+
pub branch_sort_by_author: GituiKeyEvent,
116+
pub branch_sort_by_author_rev: GituiKeyEvent,
110117
pub force_push: GituiKeyEvent,
111118
pub fetch: GituiKeyEvent,
112119
pub pull: GituiKeyEvent,
@@ -203,6 +210,13 @@ impl Default for KeysList {
203210
open_file_tree: GituiKeyEvent::new(KeyCode::Char('F'), KeyModifiers::SHIFT),
204211
file_find: GituiKeyEvent::new(KeyCode::Char('f'), KeyModifiers::empty()),
205212
branch_find: GituiKeyEvent::new(KeyCode::Char('f'), KeyModifiers::empty()),
213+
branch_sort: GituiKeyEvent::new(KeyCode::Char('s'), KeyModifiers::empty()),
214+
branch_sort_by_name: GituiKeyEvent::new(KeyCode::Char('n'), KeyModifiers::empty()),
215+
branch_sort_by_name_rev: GituiKeyEvent::new(KeyCode::Char('N'), KeyModifiers::SHIFT),
216+
branch_sort_by_time: GituiKeyEvent::new(KeyCode::Char('t'), KeyModifiers::empty()),
217+
branch_sort_by_time_rev: GituiKeyEvent::new(KeyCode::Char('T'), KeyModifiers::SHIFT),
218+
branch_sort_by_author: GituiKeyEvent::new(KeyCode::Char('a'), KeyModifiers::empty()),
219+
branch_sort_by_author_rev: GituiKeyEvent::new(KeyCode::Char('A'), KeyModifiers::SHIFT),
206220
diff_hunk_next: GituiKeyEvent::new(KeyCode::Char('n'), KeyModifiers::empty()),
207221
diff_hunk_prev: GituiKeyEvent::new(KeyCode::Char('p'), KeyModifiers::empty()),
208222
stage_unstage_item: GituiKeyEvent::new(KeyCode::Enter, KeyModifiers::empty()),

src/popups/branch_sort.rs

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
use anyhow::Result;
2+
use crossterm::event::Event;
3+
use ratatui::{
4+
layout::{Alignment, Margin, Rect},
5+
text::{Line, Span},
6+
widgets::{Block, Borders, Clear, Paragraph},
7+
Frame,
8+
};
9+
10+
use crate::{
11+
app::Environment,
12+
components::{
13+
visibility_blocking, BranchListSortBy, CommandBlocking,
14+
CommandInfo, Component, DrawableComponent, EventState,
15+
},
16+
keys::{key_match, SharedKeyConfig},
17+
queue::{InternalEvent, Queue},
18+
strings,
19+
ui::{self, style::SharedTheme},
20+
};
21+
22+
pub struct BranchSortPopup {
23+
queue: Queue,
24+
visible: bool,
25+
key_config: SharedKeyConfig,
26+
theme: SharedTheme,
27+
}
28+
29+
impl BranchSortPopup {
30+
///
31+
pub fn new(env: &Environment) -> Self {
32+
Self {
33+
queue: env.queue.clone(),
34+
visible: false,
35+
key_config: env.key_config.clone(),
36+
theme: env.theme.clone(),
37+
}
38+
}
39+
40+
pub fn open(&mut self, sort_by: BranchListSortBy) -> Result<()> {
41+
self.show()?;
42+
self.update_sort_key(sort_by);
43+
44+
Ok(())
45+
}
46+
47+
fn is_visible(&self) -> bool {
48+
self.visible
49+
}
50+
51+
fn hide(&mut self) {
52+
self.visible = false;
53+
}
54+
55+
fn show(&mut self) -> Result<()> {
56+
self.visible = true;
57+
Ok(())
58+
}
59+
60+
fn update_sort_key(&mut self, sort_by: BranchListSortBy) {
61+
self.queue.push(InternalEvent::BranchListSort(sort_by));
62+
}
63+
64+
fn get_sort_key_lines(&self) -> Vec<Line> {
65+
let texts = vec![
66+
strings::sort_branch_by_name_msg(&self.key_config),
67+
strings::sort_branch_by_name_rev_msg(&self.key_config),
68+
strings::sort_branch_by_time_msg(&self.key_config),
69+
strings::sort_branch_by_time_rev_msg(&self.key_config),
70+
strings::sort_branch_by_author_msg(&self.key_config),
71+
strings::sort_branch_by_author_rev_msg(&self.key_config),
72+
];
73+
texts
74+
.iter()
75+
.map(|t| {
76+
Line::from(vec![Span::styled(
77+
t.clone(),
78+
self.theme.text(true, false),
79+
)])
80+
})
81+
.collect()
82+
}
83+
}
84+
85+
impl DrawableComponent for BranchSortPopup {
86+
fn draw(&self, f: &mut Frame, area: Rect) -> Result<()> {
87+
if self.is_visible() {
88+
const MAX_SIZE: (u16, u16) = (50, 20);
89+
90+
let mut area = ui::centered_rect_absolute(
91+
MAX_SIZE.0, MAX_SIZE.1, area,
92+
);
93+
94+
f.render_widget(Clear, area);
95+
f.render_widget(
96+
Block::default()
97+
.borders(Borders::all())
98+
.style(self.theme.title(true))
99+
.title(Span::styled(
100+
strings::POPUP_TITLE_BRANCH_SORT,
101+
self.theme.title(true),
102+
)),
103+
area,
104+
);
105+
106+
area = area.inner(&Margin {
107+
horizontal: 1,
108+
vertical: 1,
109+
});
110+
f.render_widget(
111+
Paragraph::new(self.get_sort_key_lines())
112+
.block(
113+
Block::default()
114+
.borders(Borders::NONE)
115+
.border_style(self.theme.block(true)),
116+
)
117+
.alignment(Alignment::Left),
118+
area,
119+
);
120+
}
121+
Ok(())
122+
}
123+
}
124+
125+
impl Component for BranchSortPopup {
126+
fn commands(
127+
&self,
128+
out: &mut Vec<CommandInfo>,
129+
force_all: bool,
130+
) -> CommandBlocking {
131+
if self.is_visible() || force_all {
132+
out.push(CommandInfo::new(
133+
strings::commands::close_popup(&self.key_config),
134+
true,
135+
true,
136+
));
137+
}
138+
139+
visibility_blocking(self)
140+
}
141+
142+
fn event(
143+
&mut self,
144+
event: &crossterm::event::Event,
145+
) -> Result<EventState> {
146+
if self.is_visible() {
147+
if let Event::Key(key) = event {
148+
if key_match(key, self.key_config.keys.exit_popup) {
149+
self.hide();
150+
} else if key_match(
151+
key,
152+
self.key_config.keys.branch_sort_by_name,
153+
) {
154+
self.update_sort_key(
155+
BranchListSortBy::BranchNameAsc,
156+
);
157+
self.hide();
158+
} else if key_match(
159+
key,
160+
self.key_config.keys.branch_sort_by_name_rev,
161+
) {
162+
self.update_sort_key(
163+
BranchListSortBy::BranchNameDesc,
164+
);
165+
self.hide();
166+
} else if key_match(
167+
key,
168+
self.key_config.keys.branch_sort_by_time,
169+
) {
170+
self.update_sort_key(
171+
BranchListSortBy::LastCommitTimeDesc,
172+
);
173+
self.hide();
174+
} else if key_match(
175+
key,
176+
self.key_config.keys.branch_sort_by_time_rev,
177+
) {
178+
self.update_sort_key(
179+
BranchListSortBy::LastCommitTimeAsc,
180+
);
181+
self.hide();
182+
} else if key_match(
183+
key,
184+
self.key_config.keys.branch_sort_by_author,
185+
) {
186+
self.update_sort_key(
187+
BranchListSortBy::LastCommitAuthorAsc,
188+
);
189+
self.hide();
190+
} else if key_match(
191+
key,
192+
self.key_config.keys.branch_sort_by_author_rev,
193+
) {
194+
self.update_sort_key(
195+
BranchListSortBy::LastCommitAuthorDesc,
196+
);
197+
self.hide();
198+
}
199+
}
200+
return Ok(EventState::Consumed);
201+
}
202+
203+
Ok(EventState::NotConsumed)
204+
}
205+
206+
fn is_visible(&self) -> bool {
207+
self.visible
208+
}
209+
210+
fn hide(&mut self) {
211+
self.visible = false;
212+
}
213+
214+
fn show(&mut self) -> Result<()> {
215+
self.visible = true;
216+
Ok(())
217+
}
218+
}

0 commit comments

Comments
 (0)