1
1
use super :: {
2
- CommandBlocking , DrawableComponent , ExtendType , ScrollType ,
2
+ CommandBlocking , Direction , DrawableComponent , ScrollType ,
3
3
} ;
4
4
use crate :: {
5
5
components:: { CommandInfo , Component } ,
@@ -10,6 +10,7 @@ use crate::{
10
10
} ;
11
11
use asyncgit:: { hash, sync, DiffLine , DiffLineType , FileDiff , CWD } ;
12
12
use bytesize:: ByteSize ;
13
+ use clipboard:: { ClipboardContext , ClipboardProvider } ;
13
14
use crossterm:: event:: Event ;
14
15
use std:: { borrow:: Cow , cell:: Cell , cmp, path:: Path } ;
15
16
use tui:: {
@@ -49,11 +50,44 @@ impl Selection {
49
50
}
50
51
}
51
52
53
+ fn get_top ( & self ) -> usize {
54
+ match self {
55
+ Self :: Single ( start) => * start,
56
+ Self :: Multiple ( start, end) => cmp:: min ( * start, * end) ,
57
+ }
58
+ }
59
+
60
+ fn get_bottom ( & self ) -> usize {
61
+ match self {
62
+ Self :: Single ( start) => * start,
63
+ Self :: Multiple ( start, end) => cmp:: max ( * start, * end) ,
64
+ }
65
+ }
66
+
67
+ fn modify ( & mut self , direction : Direction , max : usize ) {
68
+ let start = self . get_start ( ) ;
69
+ let old_end = self . get_end ( ) ;
70
+
71
+ * self = match direction {
72
+ Direction :: Up => {
73
+ Self :: Multiple ( start, old_end. saturating_sub ( 1 ) )
74
+ }
75
+
76
+ Direction :: Down => {
77
+ Self :: Multiple ( start, cmp:: min ( old_end + 1 , max) )
78
+ }
79
+ } ;
80
+ }
81
+
52
82
fn contains ( & self , index : usize ) -> bool {
53
83
match self {
54
84
Self :: Single ( start) => index == * start,
55
85
Self :: Multiple ( start, end) => {
56
- * start <= index && index <= * end
86
+ if start <= end {
87
+ * start <= index && index <= * end
88
+ } else {
89
+ * end <= index && index <= * start
90
+ }
57
91
}
58
92
}
59
93
}
@@ -147,56 +181,79 @@ impl DiffComponent {
147
181
move_type : ScrollType ,
148
182
) -> Result < ( ) > {
149
183
if let Some ( diff) = & self . diff {
150
- let old_start = self . selection . get_start ( ) ;
151
-
152
184
let max = diff. lines . saturating_sub ( 1 ) as usize ;
153
185
154
186
let new_start = match move_type {
155
- ScrollType :: Down => old_start. saturating_add ( 1 ) ,
156
- ScrollType :: Up => old_start. saturating_sub ( 1 ) ,
187
+ ScrollType :: Down => {
188
+ self . selection . get_bottom ( ) . saturating_add ( 1 )
189
+ }
190
+ ScrollType :: Up => {
191
+ self . selection . get_top ( ) . saturating_sub ( 1 )
192
+ }
157
193
ScrollType :: Home => 0 ,
158
194
ScrollType :: End => max,
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 (
164
- self . current_size . get ( ) . 1 . saturating_sub ( 1 )
165
- as usize ,
166
- ) ,
195
+ ScrollType :: PageDown => {
196
+ self . selection . get_bottom ( ) . saturating_add (
197
+ self . current_size . get ( ) . 1 . saturating_sub ( 1 )
198
+ as usize ,
199
+ )
200
+ }
201
+ ScrollType :: PageUp => {
202
+ self . selection . get_top ( ) . saturating_sub (
203
+ self . current_size . get ( ) . 1 . saturating_sub ( 1 )
204
+ as usize ,
205
+ )
206
+ }
167
207
} ;
168
208
169
209
self . selection =
170
210
Selection :: Single ( cmp:: min ( max, new_start) ) ;
171
211
172
- if new_start != old_start {
173
- self . selected_hunk =
174
- Self :: find_selected_hunk ( diff, new_start) ?;
175
- }
212
+ self . selected_hunk =
213
+ Self :: find_selected_hunk ( diff, new_start) ?;
176
214
}
177
215
Ok ( ( ) )
178
216
}
179
217
180
- fn extend_selection (
218
+ fn modify_selection (
181
219
& mut self ,
182
- extend_type : ExtendType ,
220
+ direction : Direction ,
183
221
) -> Result < ( ) > {
184
222
if let Some ( diff) = & self . diff {
185
223
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
- } ;
224
+
225
+ self . selection . modify ( direction, max) ;
226
+ }
227
+
228
+ Ok ( ( ) )
229
+ }
230
+
231
+ fn copy_selection ( & self ) -> Result < ( ) > {
232
+ if let Some ( diff) = & self . diff {
233
+ let lines_to_copy: Vec < & str > = diff
234
+ . hunks
235
+ . iter ( )
236
+ . flat_map ( |hunk| hunk. lines . iter ( ) )
237
+ . enumerate ( )
238
+ . filter_map ( |( i, line) | {
239
+ if self . selection . contains ( i) {
240
+ Some (
241
+ line. content
242
+ . trim_matches ( |c| {
243
+ c == '\n' || c == '\r'
244
+ } )
245
+ . as_ref ( ) ,
246
+ )
247
+ } else {
248
+ None
249
+ }
250
+ } )
251
+ . collect ( ) ;
252
+
253
+ let mut ctx: ClipboardContext = ClipboardProvider :: new ( )
254
+ . expect ( "failed to get access to clipboard" ) ;
255
+ ctx. set_contents ( lines_to_copy. join ( "\n " ) )
256
+ . expect ( "failed to set clipboard contents" ) ;
200
257
}
201
258
202
259
Ok ( ( ) )
@@ -489,7 +546,7 @@ impl DrawableComponent for DiffComponent {
489
546
self . scroll_top . set ( calc_scroll_top (
490
547
self . scroll_top . get ( ) ,
491
548
self . current_size . get ( ) . 1 as usize ,
492
- self . selection . get_start ( ) ,
549
+ self . selection . get_end ( ) ,
493
550
) ) ;
494
551
495
552
let title =
@@ -531,6 +588,12 @@ impl Component for DiffComponent {
531
588
self . focused ,
532
589
) ) ;
533
590
591
+ out. push ( CommandInfo :: new (
592
+ commands:: COPY ,
593
+ true ,
594
+ self . focused ,
595
+ ) ) ;
596
+
534
597
out. push (
535
598
CommandInfo :: new (
536
599
commands:: DIFF_HOME_END ,
@@ -570,11 +633,11 @@ impl Component for DiffComponent {
570
633
Ok ( true )
571
634
}
572
635
keys:: SHIFT_DOWN => {
573
- self . extend_selection ( ExtendType :: Down ) ?;
636
+ self . modify_selection ( Direction :: Down ) ?;
574
637
Ok ( true )
575
638
}
576
639
keys:: SHIFT_UP => {
577
- self . extend_selection ( ExtendType :: Up ) ?;
640
+ self . modify_selection ( Direction :: Up ) ?;
578
641
Ok ( true )
579
642
}
580
643
keys:: END => {
@@ -618,6 +681,10 @@ impl Component for DiffComponent {
618
681
}
619
682
Ok ( true )
620
683
}
684
+ keys:: COPY => {
685
+ self . copy_selection ( ) ?;
686
+ Ok ( true )
687
+ }
621
688
_ => Ok ( false ) ,
622
689
} ;
623
690
}
0 commit comments