@@ -3,9 +3,11 @@ use super::{
33 DrawableComponent ,
44} ;
55use crate :: {
6+ components:: ScrollType ,
67 keys:: SharedKeyConfig ,
78 queue:: { Action , InternalEvent , NeedsUpdate , Queue } ,
8- strings, ui,
9+ strings,
10+ ui:: { self , calc_scroll_top} ,
911} ;
1012use asyncgit:: {
1113 sync:: {
@@ -14,7 +16,7 @@ use asyncgit::{
1416 CWD ,
1517} ;
1618use crossterm:: event:: Event ;
17- use std:: { cmp , convert:: TryFrom } ;
19+ use std:: { cell :: Cell , convert:: TryInto } ;
1820use tui:: {
1921 backend:: Backend ,
2022 layout:: { Alignment , Rect } ,
@@ -32,6 +34,7 @@ pub struct SelectBranchComponent {
3234 branch_names : Vec < BranchForDisplay > ,
3335 visible : bool ,
3436 selection : u16 ,
37+ scroll_top : Cell < usize > ,
3538 queue : Queue ,
3639 theme : SharedTheme ,
3740 key_config : SharedKeyConfig ,
@@ -56,22 +59,28 @@ impl DrawableComponent for SelectBranchComponent {
5659 ui:: rect_inside ( MIN_SIZE , f. size ( ) . into ( ) , area) ;
5760 let area = area. intersection ( rect) ;
5861
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+ ) ) ;
6270
6371 f. render_widget ( Clear , area) ;
6472 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+ ) ?)
6878 . block (
6979 Block :: default ( )
7080 . title ( strings:: SELECT_BRANCH_POPUP_MSG )
7181 . borders ( Borders :: ALL )
7282 . border_type ( BorderType :: Thick ) ,
7383 )
74- . scroll ( ( scroll, 0 ) )
7584 . alignment ( Alignment :: Left ) ,
7685 area,
7786 ) ;
@@ -135,9 +144,9 @@ impl Component for SelectBranchComponent {
135144 if e == self . key_config . exit_popup {
136145 self . hide ( )
137146 } else if e == self . key_config . move_down {
138- self . move_selection ( true )
147+ return self . move_selection ( ScrollType :: Up ) ;
139148 } else if e == self . key_config . move_up {
140- self . move_selection ( false )
149+ return self . move_selection ( ScrollType :: Down ) ;
141150 } else if e == self . key_config . enter {
142151 if let Err ( e) = self . switch_to_selected_branch ( ) {
143152 log:: error!( "switch branch error: {}" , e) ;
@@ -211,6 +220,7 @@ impl SelectBranchComponent {
211220 branch_names : Vec :: new ( ) ,
212221 visible : false ,
213222 selection : 0 ,
223+ scroll_top : Cell :: new ( 0 ) ,
214224 queue,
215225 theme,
216226 key_config,
@@ -248,28 +258,31 @@ impl SelectBranchComponent {
248258 }
249259
250260 ///
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 ,
258269 } ;
259- new_selection = cmp:: max ( new_selection, 0 ) ;
260270
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;
265273 }
274+
275+ self . selection = new_selection;
276+
277+ Ok ( true )
266278 }
267279
268280 /// Get branches to display
269281 fn get_text (
270282 & self ,
271283 theme : & SharedTheme ,
272284 width_available : u16 ,
285+ height : usize ,
273286 ) -> Result < Text > {
274287 const COMMIT_HASH_LENGTH : usize = 8 ;
275288 const IS_HEAD_STAR_LENGTH : usize = 3 ; // "* "
@@ -286,7 +299,12 @@ impl SelectBranchComponent {
286299 . saturating_sub ( THREE_DOTS_LENGTH ) ;
287300 let mut txt = Vec :: new ( ) ;
288301
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 ( )
290308 {
291309 let mut commit_message =
292310 displaybranch. top_commit_message . clone ( ) ;
@@ -310,63 +328,67 @@ impl SelectBranchComponent {
310328 let is_head_str =
311329 if displaybranch. is_head { "*" } else { " " } ;
312330
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 ) ,
324356 ) ,
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 ) ,
333360 ) ,
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 ) ,
352367 ) ,
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 ) ,
361384 ) ,
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+ ) ) ;
370392 }
371393
372394 Ok ( Text :: from ( txt) )
0 commit comments