@@ -19,6 +19,7 @@ use tui::{
1919 Frame ,
2020} ;
2121
22+ #[ derive( Default ) ]
2223struct LogEntry {
2324 time : String ,
2425 author : String ,
@@ -62,14 +63,49 @@ const STYLE_MSG_SELECTED: Style =
6263 Style :: new ( ) . fg ( Color :: Reset ) . bg ( COLOR_SELECTION_BG ) ;
6364
6465static ELEMENTS_PER_LINE : usize = 10 ;
65- static SLICE_SIZE : usize = 1000 ;
66+ static SLICE_SIZE : usize = 1200 ;
6667static SLICE_OFFSET_RELOAD_THRESHOLD : usize = 100 ;
6768
69+ ///
70+ #[ derive( Default ) ]
71+ struct ItemBatch {
72+ index_offset : usize ,
73+ items : Vec < LogEntry > ,
74+ }
75+
76+ impl ItemBatch {
77+ fn last_idx ( & self ) -> usize {
78+ self . index_offset + self . items . len ( )
79+ }
80+
81+ fn set_items (
82+ & mut self ,
83+ start_index : usize ,
84+ commits : Vec < CommitInfo > ,
85+ ) {
86+ self . items . clear ( ) ;
87+ self . items . extend ( commits. into_iter ( ) . map ( LogEntry :: from) ) ;
88+ self . index_offset = start_index;
89+ }
90+
91+ fn needs_data ( & self , idx : usize , idx_max : usize ) -> bool {
92+ let want_min =
93+ idx. saturating_sub ( SLICE_OFFSET_RELOAD_THRESHOLD ) ;
94+ let want_max = idx
95+ . saturating_add ( SLICE_OFFSET_RELOAD_THRESHOLD )
96+ . min ( idx_max) ;
97+
98+ let needs_data_top = want_min < self . index_offset ;
99+ let needs_data_bottom = want_max > self . last_idx ( ) ;
100+ needs_data_bottom || needs_data_top
101+ }
102+ }
103+
68104///
69105pub struct Revlog {
70106 selection : usize ,
71107 selection_max : usize ,
72- items : Vec < LogEntry > ,
108+ items : ItemBatch ,
73109 git_log : AsyncLog ,
74110 visible : bool ,
75111 first_open_done : bool ,
@@ -81,7 +117,7 @@ impl Revlog {
81117 ///
82118 pub fn new ( sender : & Sender < AsyncNotification > ) -> Self {
83119 Self {
84- items : Vec :: new ( ) ,
120+ items : ItemBatch :: default ( ) ,
85121 git_log : AsyncLog :: new ( sender. clone ( ) ) ,
86122 selection : 0 ,
87123 selection_max : 0 ,
@@ -95,12 +131,13 @@ impl Revlog {
95131 ///
96132 pub fn draw < B : Backend > ( & self , f : & mut Frame < B > , area : Rect ) {
97133 let height = area. height as usize ;
98- let selection = self . selection ;
134+ let selection =
135+ self . selection . saturating_sub ( self . items . index_offset ) ;
99136 let height_d2 = height as usize / 2 ;
100137 let min = selection. saturating_sub ( height_d2) ;
101138
102139 let mut txt = Vec :: new ( ) ;
103- for ( idx, e) in self . items . iter ( ) . enumerate ( ) {
140+ for ( idx, e) in self . items . items . iter ( ) . enumerate ( ) {
104141 let tag = if let Some ( tag_name) = self . tags . get ( & e. hash ) {
105142 tag_name. as_str ( )
106143 } else {
@@ -109,8 +146,10 @@ impl Revlog {
109146 Self :: add_entry ( e, idx == selection, & mut txt, tag) ;
110147 }
111148
112- let title =
113- format ! ( "commit {}/{}" , selection, self . selection_max) ;
149+ let title = format ! (
150+ "commit {}/{}" ,
151+ self . selection, self . selection_max
152+ ) ;
114153
115154 f. render_widget (
116155 Paragraph :: new (
@@ -135,31 +174,30 @@ impl Revlog {
135174
136175 ///
137176 pub fn update ( & mut self ) {
138- let next_idx = self . items . len ( ) ;
139-
140- let requires_more_data = next_idx
141- . saturating_sub ( self . selection )
142- < SLICE_OFFSET_RELOAD_THRESHOLD ;
143-
144177 self . selection_max = self . git_log . count ( ) . saturating_sub ( 1 ) ;
145178
146- if requires_more_data {
147- let commits = sync:: get_commits_info (
148- CWD ,
149- & self . git_log . get_slice ( next_idx, SLICE_SIZE ) ,
150- ) ;
151-
152- if let Ok ( commits) = commits {
153- self . items
154- . extend ( commits. into_iter ( ) . map ( LogEntry :: from) ) ;
155- }
179+ if self . items . needs_data ( self . selection , self . selection_max ) {
180+ self . fetch_commits ( ) ;
156181 }
157182
158183 if self . tags . is_empty ( ) {
159184 self . tags = sync:: get_tags ( CWD ) . unwrap ( ) ;
160185 }
161186 }
162187
188+ fn fetch_commits ( & mut self ) {
189+ let want_min = self . selection . saturating_sub ( SLICE_SIZE / 2 ) ;
190+
191+ let commits = sync:: get_commits_info (
192+ CWD ,
193+ & self . git_log . get_slice ( want_min, SLICE_SIZE ) ,
194+ ) ;
195+
196+ if let Ok ( commits) = commits {
197+ self . items . set_items ( want_min, commits) ;
198+ }
199+ }
200+
163201 fn move_selection ( & mut self , scroll : ScrollType ) {
164202 self . update_scroll_speed ( ) ;
165203
@@ -176,7 +214,7 @@ impl Revlog {
176214 self . selection . saturating_add ( speed_int)
177215 }
178216 ScrollType :: Home => 0 ,
179- _ => self . selection ,
217+ ScrollType :: End => self . selection_max ,
180218 } ;
181219
182220 self . selection = cmp:: min ( self . selection , self . selection_max ) ;
@@ -296,6 +334,10 @@ impl Component for Revlog {
296334 self . move_selection ( ScrollType :: Home ) ;
297335 true
298336 }
337+ keys:: SHIFT_DOWN | keys:: END => {
338+ self . move_selection ( ScrollType :: End ) ;
339+ true
340+ }
299341 _ => false ,
300342 } ;
301343 }
0 commit comments