@@ -3,9 +3,11 @@ use super::{
3
3
DrawableComponent ,
4
4
} ;
5
5
use crate :: {
6
+ components:: ScrollType ,
6
7
keys:: SharedKeyConfig ,
7
8
queue:: { Action , InternalEvent , NeedsUpdate , Queue } ,
8
- strings, ui,
9
+ strings,
10
+ ui:: { self , calc_scroll_top} ,
9
11
} ;
10
12
use asyncgit:: {
11
13
sync:: {
@@ -14,7 +16,7 @@ use asyncgit::{
14
16
CWD ,
15
17
} ;
16
18
use crossterm:: event:: Event ;
17
- use std:: { cmp , convert:: TryFrom } ;
19
+ use std:: { cell :: Cell , convert:: TryInto } ;
18
20
use tui:: {
19
21
backend:: Backend ,
20
22
layout:: { Alignment , Rect } ,
@@ -32,6 +34,7 @@ pub struct SelectBranchComponent {
32
34
branch_names : Vec < BranchForDisplay > ,
33
35
visible : bool ,
34
36
selection : u16 ,
37
+ scroll_top : Cell < usize > ,
35
38
queue : Queue ,
36
39
theme : SharedTheme ,
37
40
key_config : SharedKeyConfig ,
@@ -56,22 +59,28 @@ impl DrawableComponent for SelectBranchComponent {
56
59
ui:: rect_inside ( MIN_SIZE , f. size ( ) . into ( ) , area) ;
57
60
let area = area. intersection ( rect) ;
58
61
59
- let scroll_threshold = area. height / 3 ;
60
- let scroll =
61
- self . selection . saturating_sub ( scroll_threshold) ;
62
+ let height_in_lines =
63
+ ( area. height as usize ) . saturating_sub ( 2 ) ;
64
+
65
+ self . scroll_top . set ( calc_scroll_top (
66
+ self . scroll_top . get ( ) ,
67
+ height_in_lines,
68
+ self . selection as usize ,
69
+ ) ) ;
62
70
63
71
f. render_widget ( Clear , area) ;
64
72
f. render_widget (
65
- Paragraph :: new (
66
- self . get_text ( & self . theme , area. width ) ?,
67
- )
73
+ Paragraph :: new ( self . get_text (
74
+ & self . theme ,
75
+ area. width ,
76
+ height_in_lines,
77
+ ) ?)
68
78
. block (
69
79
Block :: default ( )
70
80
. title ( strings:: SELECT_BRANCH_POPUP_MSG )
71
81
. borders ( Borders :: ALL )
72
82
. border_type ( BorderType :: Thick ) ,
73
83
)
74
- . scroll ( ( scroll, 0 ) )
75
84
. alignment ( Alignment :: Left ) ,
76
85
area,
77
86
) ;
@@ -135,9 +144,9 @@ impl Component for SelectBranchComponent {
135
144
if e == self . key_config . exit_popup {
136
145
self . hide ( )
137
146
} else if e == self . key_config . move_down {
138
- self . move_selection ( true )
147
+ return self . move_selection ( ScrollType :: Up ) ;
139
148
} else if e == self . key_config . move_up {
140
- self . move_selection ( false )
149
+ return self . move_selection ( ScrollType :: Down ) ;
141
150
} else if e == self . key_config . enter {
142
151
if let Err ( e) = self . switch_to_selected_branch ( ) {
143
152
log:: error!( "switch branch error: {}" , e) ;
@@ -211,6 +220,7 @@ impl SelectBranchComponent {
211
220
branch_names : Vec :: new ( ) ,
212
221
visible : false ,
213
222
selection : 0 ,
223
+ scroll_top : Cell :: new ( 0 ) ,
214
224
queue,
215
225
theme,
216
226
key_config,
@@ -248,28 +258,31 @@ impl SelectBranchComponent {
248
258
}
249
259
250
260
///
251
- fn move_selection ( & mut self , inc : bool ) {
252
- let mut new_selection = self . selection ;
253
-
254
- new_selection = if inc {
255
- new_selection. saturating_add ( 1 )
256
- } else {
257
- new_selection. saturating_sub ( 1 )
261
+ fn move_selection ( & mut self , scroll : ScrollType ) -> Result < bool > {
262
+ let num_branches: u16 = self . branch_names . len ( ) . try_into ( ) ?;
263
+ let num_branches = num_branches. saturating_sub ( 1 ) ;
264
+
265
+ let mut new_selection = match scroll {
266
+ ScrollType :: Up => self . selection . saturating_add ( 1 ) ,
267
+ ScrollType :: Down => self . selection . saturating_sub ( 1 ) ,
268
+ _ => self . selection ,
258
269
} ;
259
- new_selection = cmp:: max ( new_selection, 0 ) ;
260
270
261
- if let Ok ( max) =
262
- u16:: try_from ( self . branch_names . len ( ) . saturating_sub ( 1 ) )
263
- {
264
- self . selection = cmp:: min ( new_selection, max) ;
271
+ if new_selection > num_branches {
272
+ new_selection = num_branches;
265
273
}
274
+
275
+ self . selection = new_selection;
276
+
277
+ Ok ( true )
266
278
}
267
279
268
280
/// Get branches to display
269
281
fn get_text (
270
282
& self ,
271
283
theme : & SharedTheme ,
272
284
width_available : u16 ,
285
+ height : usize ,
273
286
) -> Result < Text > {
274
287
const COMMIT_HASH_LENGTH : usize = 8 ;
275
288
const IS_HEAD_STAR_LENGTH : usize = 3 ; // "* "
@@ -286,7 +299,12 @@ impl SelectBranchComponent {
286
299
. saturating_sub ( THREE_DOTS_LENGTH ) ;
287
300
let mut txt = Vec :: new ( ) ;
288
301
289
- for ( i, displaybranch) in self . branch_names . iter ( ) . enumerate ( )
302
+ for ( i, displaybranch) in self
303
+ . branch_names
304
+ . iter ( )
305
+ . skip ( self . scroll_top . get ( ) )
306
+ . take ( height)
307
+ . enumerate ( )
290
308
{
291
309
let mut commit_message =
292
310
displaybranch. top_commit_message . clone ( ) ;
@@ -310,63 +328,67 @@ impl SelectBranchComponent {
310
328
let is_head_str =
311
329
if displaybranch. is_head { "*" } else { " " } ;
312
330
313
- txt. push ( Spans :: from ( if self . selection as usize == i {
314
- vec ! [
315
- Span :: styled(
316
- format!( "{} " , is_head_str) ,
317
- theme. commit_author( true ) ,
318
- ) ,
319
- Span :: styled(
320
- format!(
321
- ">{:w$} " ,
322
- branch_name,
323
- w = branch_name_length
331
+ txt. push ( Spans :: from (
332
+ if self . selection as usize - self . scroll_top . get ( )
333
+ == i
334
+ {
335
+ vec ! [
336
+ Span :: styled(
337
+ format!( "{} " , is_head_str) ,
338
+ theme. commit_author( true ) ,
339
+ ) ,
340
+ Span :: styled(
341
+ format!(
342
+ ">{:w$} " ,
343
+ branch_name,
344
+ w = branch_name_length
345
+ ) ,
346
+ theme. commit_author( true ) ,
347
+ ) ,
348
+ Span :: styled(
349
+ format!(
350
+ "{} " ,
351
+ displaybranch
352
+ . top_commit
353
+ . get_short_string( )
354
+ ) ,
355
+ theme. commit_hash( true ) ,
324
356
) ,
325
- theme. commit_author( true ) ,
326
- ) ,
327
- Span :: styled(
328
- format!(
329
- "{} " ,
330
- displaybranch
331
- . top_commit
332
- . get_short_string( )
357
+ Span :: styled(
358
+ commit_message. to_string( ) ,
359
+ theme. text( true , true ) ,
333
360
) ,
334
- theme. commit_hash( true ) ,
335
- ) ,
336
- Span :: styled(
337
- commit_message. to_string( ) ,
338
- theme. text( true , true ) ,
339
- ) ,
340
- ]
341
- } else {
342
- vec ! [
343
- Span :: styled(
344
- format!( "{} " , is_head_str) ,
345
- theme. commit_author( false ) ,
346
- ) ,
347
- Span :: styled(
348
- format!(
349
- " {:w$} " ,
350
- branch_name,
351
- w = branch_name_length
361
+ ]
362
+ } else {
363
+ vec ! [
364
+ Span :: styled(
365
+ format!( "{} " , is_head_str) ,
366
+ theme. commit_author( false ) ,
352
367
) ,
353
- theme. commit_author( false ) ,
354
- ) ,
355
- Span :: styled(
356
- format!(
357
- "{} " ,
358
- displaybranch
359
- . top_commit
360
- . get_short_string( )
368
+ Span :: styled(
369
+ format!(
370
+ " {:w$} " ,
371
+ branch_name,
372
+ w = branch_name_length
373
+ ) ,
374
+ theme. commit_author( false ) ,
375
+ ) ,
376
+ Span :: styled(
377
+ format!(
378
+ "{} " ,
379
+ displaybranch
380
+ . top_commit
381
+ . get_short_string( )
382
+ ) ,
383
+ theme. commit_hash( false ) ,
361
384
) ,
362
- theme. commit_hash( false ) ,
363
- ) ,
364
- Span :: styled(
365
- commit_message. to_string( ) ,
366
- theme. text( true , false ) ,
367
- ) ,
368
- ]
369
- } ) ) ;
385
+ Span :: styled(
386
+ commit_message. to_string( ) ,
387
+ theme. text( true , false ) ,
388
+ ) ,
389
+ ]
390
+ } ,
391
+ ) ) ;
370
392
}
371
393
372
394
Ok ( Text :: from ( txt) )
0 commit comments