Skip to content

Commit 14fab80

Browse files
committed
Add multiple selection in diff view
1 parent 5e12608 commit 14fab80

File tree

2 files changed

+98
-27
lines changed

2 files changed

+98
-27
lines changed

src/components/diff.rs

Lines changed: 92 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use super::{CommandBlocking, DrawableComponent, ScrollType};
1+
use super::{
2+
CommandBlocking, DrawableComponent, ExtendType, ScrollType,
3+
};
24
use crate::{
35
components::{CommandInfo, Component},
46
keys,
@@ -27,11 +29,41 @@ struct Current {
2729
hash: u64,
2830
}
2931

32+
///
33+
#[derive(Clone, Copy)]
34+
enum Selection {
35+
Single(usize),
36+
Multiple(usize, usize),
37+
}
38+
39+
impl Selection {
40+
fn get_start(&self) -> usize {
41+
match self {
42+
Self::Single(start) | Self::Multiple(start, _) => *start,
43+
}
44+
}
45+
46+
fn get_end(&self) -> usize {
47+
match self {
48+
Self::Single(end) | Self::Multiple(_, end) => *end,
49+
}
50+
}
51+
52+
fn contains(&self, index: usize) -> bool {
53+
match self {
54+
Self::Single(start) => index == *start,
55+
Self::Multiple(start, end) => {
56+
*start <= index && index <= *end
57+
}
58+
}
59+
}
60+
}
61+
3062
///
3163
pub struct DiffComponent {
3264
diff: Option<FileDiff>,
3365
pending: bool,
34-
selection: usize,
66+
selection: Selection,
3567
selected_hunk: Option<usize>,
3668
current_size: Cell<(u16, u16)>,
3769
focused: bool,
@@ -52,7 +84,7 @@ impl DiffComponent {
5284
selected_hunk: None,
5385
diff: None,
5486
current_size: Cell::new((0, 0)),
55-
selection: 0,
87+
selection: Selection::Single(0),
5688
scroll_top: Cell::new(0),
5789
theme,
5890
}
@@ -73,7 +105,7 @@ impl DiffComponent {
73105
self.current = Current::default();
74106
self.diff = None;
75107
self.scroll_top.set(0);
76-
self.selection = 0;
108+
self.selection = Selection::Single(0);
77109
self.selected_hunk = None;
78110
self.pending = pending;
79111

@@ -97,12 +129,14 @@ impl DiffComponent {
97129
hash,
98130
};
99131

100-
self.selected_hunk =
101-
Self::find_selected_hunk(&diff, self.selection)?;
132+
self.selected_hunk = Self::find_selected_hunk(
133+
&diff,
134+
self.selection.get_start(),
135+
)?;
102136

103137
self.diff = Some(diff);
104138
self.scroll_top.set(0);
105-
self.selection = 0;
139+
self.selection = Selection::Single(0);
106140
}
107141

108142
Ok(())
@@ -113,37 +147,61 @@ impl DiffComponent {
113147
move_type: ScrollType,
114148
) -> Result<()> {
115149
if let Some(diff) = &self.diff {
116-
let old = self.selection;
150+
let old_start = self.selection.get_start();
117151

118152
let max = diff.lines.saturating_sub(1) as usize;
119153

120-
self.selection = match move_type {
121-
ScrollType::Down => old.saturating_add(1),
122-
ScrollType::Up => old.saturating_sub(1),
154+
let new_start = match move_type {
155+
ScrollType::Down => old_start.saturating_add(1),
156+
ScrollType::Up => old_start.saturating_sub(1),
123157
ScrollType::Home => 0,
124158
ScrollType::End => max,
125-
ScrollType::PageDown => {
126-
self.selection.saturating_add(
127-
self.current_size.get().1.saturating_sub(1)
128-
as usize,
129-
)
130-
}
131-
ScrollType::PageUp => self.selection.saturating_sub(
159+
ScrollType::PageDown => old_start.saturating_add(
160+
self.current_size.get().1.saturating_sub(1)
161+
as usize,
162+
),
163+
ScrollType::PageUp => old_start.saturating_sub(
132164
self.current_size.get().1.saturating_sub(1)
133165
as usize,
134166
),
135167
};
136168

137-
self.selection = cmp::min(max, self.selection);
169+
self.selection =
170+
Selection::Single(cmp::min(max, new_start));
138171

139-
if old != self.selection {
172+
if new_start != old_start {
140173
self.selected_hunk =
141-
Self::find_selected_hunk(diff, self.selection)?;
174+
Self::find_selected_hunk(diff, new_start)?;
142175
}
143176
}
144177
Ok(())
145178
}
146179

180+
fn extend_selection(
181+
&mut self,
182+
extend_type: ExtendType,
183+
) -> Result<()> {
184+
if let Some(diff) = &self.diff {
185+
let max = diff.lines.saturating_sub(1) as usize;
186+
let start = self.selection.get_start();
187+
let old_end = self.selection.get_end();
188+
189+
self.selection = match extend_type {
190+
ExtendType::Up => Selection::Multiple(
191+
start,
192+
cmp::max(start, old_end.saturating_sub(1)),
193+
),
194+
195+
ExtendType::Down => Selection::Multiple(
196+
start,
197+
cmp::min(old_end + 1, max),
198+
),
199+
};
200+
}
201+
202+
Ok(())
203+
}
204+
147205
fn find_selected_hunk(
148206
diff: &FileDiff,
149207
line_selected: usize,
@@ -210,8 +268,6 @@ impl DiffComponent {
210268
Text::Raw(Cow::from(")")),
211269
]);
212270
} else {
213-
let selection = self.selection;
214-
215271
let min = self.scroll_top.get();
216272
let max = min + height as usize;
217273

@@ -242,7 +298,8 @@ impl DiffComponent {
242298
&mut res,
243299
width,
244300
line,
245-
selection == line_cursor,
301+
self.selection
302+
.contains(line_cursor),
246303
hunk_selected,
247304
i == hunk_len as usize - 1,
248305
&self.theme,
@@ -432,7 +489,7 @@ impl DrawableComponent for DiffComponent {
432489
self.scroll_top.set(calc_scroll_top(
433490
self.scroll_top.get(),
434491
self.current_size.get().1 as usize,
435-
self.selection,
492+
self.selection.get_start(),
436493
));
437494

438495
let title =
@@ -512,11 +569,19 @@ impl Component for DiffComponent {
512569
self.move_selection(ScrollType::Down)?;
513570
Ok(true)
514571
}
515-
keys::SHIFT_DOWN | keys::END => {
572+
keys::SHIFT_DOWN => {
573+
self.extend_selection(ExtendType::Down)?;
574+
Ok(true)
575+
}
576+
keys::SHIFT_UP => {
577+
self.extend_selection(ExtendType::Up)?;
578+
Ok(true)
579+
}
580+
keys::END => {
516581
self.move_selection(ScrollType::End)?;
517582
Ok(true)
518583
}
519-
keys::HOME | keys::SHIFT_UP => {
584+
keys::HOME => {
520585
self.move_selection(ScrollType::Home)?;
521586
Ok(true)
522587
}

src/components/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ pub enum ScrollType {
105105
PageDown,
106106
}
107107

108+
#[derive(Copy, Clone)]
109+
pub enum ExtendType {
110+
Up,
111+
Down,
112+
}
113+
108114
///
109115
#[derive(PartialEq)]
110116
pub enum CommandBlocking {

0 commit comments

Comments
 (0)