@@ -19,6 +19,7 @@ use tui::{
19
19
Frame ,
20
20
} ;
21
21
22
+ #[ derive( Default ) ]
22
23
struct LogEntry {
23
24
time : String ,
24
25
author : String ,
@@ -62,14 +63,49 @@ const STYLE_MSG_SELECTED: Style =
62
63
Style :: new ( ) . fg ( Color :: Reset ) . bg ( COLOR_SELECTION_BG ) ;
63
64
64
65
static ELEMENTS_PER_LINE : usize = 10 ;
65
- static SLICE_SIZE : usize = 1000 ;
66
+ static SLICE_SIZE : usize = 1200 ;
66
67
static SLICE_OFFSET_RELOAD_THRESHOLD : usize = 100 ;
67
68
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
+
68
104
///
69
105
pub struct Revlog {
70
106
selection : usize ,
71
107
selection_max : usize ,
72
- items : Vec < LogEntry > ,
108
+ items : ItemBatch ,
73
109
git_log : AsyncLog ,
74
110
visible : bool ,
75
111
first_open_done : bool ,
@@ -81,7 +117,7 @@ impl Revlog {
81
117
///
82
118
pub fn new ( sender : & Sender < AsyncNotification > ) -> Self {
83
119
Self {
84
- items : Vec :: new ( ) ,
120
+ items : ItemBatch :: default ( ) ,
85
121
git_log : AsyncLog :: new ( sender. clone ( ) ) ,
86
122
selection : 0 ,
87
123
selection_max : 0 ,
@@ -95,12 +131,13 @@ impl Revlog {
95
131
///
96
132
pub fn draw < B : Backend > ( & self , f : & mut Frame < B > , area : Rect ) {
97
133
let height = area. height as usize ;
98
- let selection = self . selection ;
134
+ let selection =
135
+ self . selection . saturating_sub ( self . items . index_offset ) ;
99
136
let height_d2 = height as usize / 2 ;
100
137
let min = selection. saturating_sub ( height_d2) ;
101
138
102
139
let mut txt = Vec :: new ( ) ;
103
- for ( idx, e) in self . items . iter ( ) . enumerate ( ) {
140
+ for ( idx, e) in self . items . items . iter ( ) . enumerate ( ) {
104
141
let tag = if let Some ( tag_name) = self . tags . get ( & e. hash ) {
105
142
tag_name. as_str ( )
106
143
} else {
@@ -109,8 +146,10 @@ impl Revlog {
109
146
Self :: add_entry ( e, idx == selection, & mut txt, tag) ;
110
147
}
111
148
112
- let title =
113
- format ! ( "commit {}/{}" , selection, self . selection_max) ;
149
+ let title = format ! (
150
+ "commit {}/{}" ,
151
+ self . selection, self . selection_max
152
+ ) ;
114
153
115
154
f. render_widget (
116
155
Paragraph :: new (
@@ -135,31 +174,30 @@ impl Revlog {
135
174
136
175
///
137
176
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
-
144
177
self . selection_max = self . git_log . count ( ) . saturating_sub ( 1 ) ;
145
178
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 ( ) ;
156
181
}
157
182
158
183
if self . tags . is_empty ( ) {
159
184
self . tags = sync:: get_tags ( CWD ) . unwrap ( ) ;
160
185
}
161
186
}
162
187
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
+
163
201
fn move_selection ( & mut self , scroll : ScrollType ) {
164
202
self . update_scroll_speed ( ) ;
165
203
@@ -176,7 +214,7 @@ impl Revlog {
176
214
self . selection . saturating_add ( speed_int)
177
215
}
178
216
ScrollType :: Home => 0 ,
179
- _ => self . selection ,
217
+ ScrollType :: End => self . selection_max ,
180
218
} ;
181
219
182
220
self . selection = cmp:: min ( self . selection , self . selection_max ) ;
@@ -296,6 +334,10 @@ impl Component for Revlog {
296
334
self . move_selection ( ScrollType :: Home ) ;
297
335
true
298
336
}
337
+ keys:: SHIFT_DOWN | keys:: END => {
338
+ self . move_selection ( ScrollType :: End ) ;
339
+ true
340
+ }
299
341
_ => false ,
300
342
} ;
301
343
}
0 commit comments