@@ -13,7 +13,7 @@ use std::{
13
13
use crate :: {
14
14
app_state:: AppState ,
15
15
exercise:: Exercise ,
16
- term:: { progress_bar, terminal_file_link} ,
16
+ term:: { progress_bar, terminal_file_link, CountedWrite , MaxLenWriter } ,
17
17
MAX_EXERCISE_NAME_LEN ,
18
18
} ;
19
19
@@ -28,14 +28,6 @@ fn next_ln(stdout: &mut StdoutLock) -> io::Result<()> {
28
28
Ok ( ( ) )
29
29
}
30
30
31
- // Avoids having the last written char as the last displayed one when the
32
- // written width is higher than the terminal width.
33
- // Happens on the Gnome terminal for example.
34
- fn next_ln_overwrite ( stdout : & mut StdoutLock ) -> io:: Result < ( ) > {
35
- stdout. write_all ( b" " ) ?;
36
- next_ln ( stdout)
37
- }
38
-
39
31
#[ derive( Copy , Clone , PartialEq , Eq ) ]
40
32
pub enum Filter {
41
33
Done ,
@@ -164,40 +156,44 @@ impl<'a> ListState<'a> {
164
156
. skip ( self . row_offset )
165
157
. take ( self . max_n_rows_to_display )
166
158
{
159
+ let mut writer = MaxLenWriter :: new ( stdout, self . term_width as usize ) ;
160
+
167
161
if self . selected_row == Some ( self . row_offset + n_displayed_rows) {
168
- stdout. queue ( SetBackgroundColor ( Color :: Rgb {
162
+ writer . stdout . queue ( SetBackgroundColor ( Color :: Rgb {
169
163
r : 40 ,
170
164
g : 40 ,
171
165
b : 40 ,
172
166
} ) ) ?;
173
- stdout. write_all ( "🦀" . as_bytes ( ) ) ?;
167
+ // The crab emoji has the width of two ascii chars.
168
+ writer. add_to_len ( 2 ) ;
169
+ writer. stdout . write_all ( "🦀" . as_bytes ( ) ) ?;
174
170
} else {
175
- stdout . write_all ( b" " ) ?;
171
+ writer . write_ascii ( b" " ) ?;
176
172
}
177
173
178
174
if exercise_ind == current_exercise_ind {
179
- stdout. queue ( SetForegroundColor ( Color :: Red ) ) ?;
180
- stdout . write_all ( b">>>>>>> " ) ?;
175
+ writer . stdout . queue ( SetForegroundColor ( Color :: Red ) ) ?;
176
+ writer . write_ascii ( b">>>>>>> " ) ?;
181
177
} else {
182
- stdout . write_all ( b" " ) ?;
178
+ writer . write_ascii ( b" " ) ?;
183
179
}
184
180
185
181
if exercise. done {
186
- stdout. queue ( SetForegroundColor ( Color :: Green ) ) ?;
187
- stdout . write_all ( b"DONE " ) ?;
182
+ writer . stdout . queue ( SetForegroundColor ( Color :: Green ) ) ?;
183
+ writer . write_ascii ( b"DONE " ) ?;
188
184
} else {
189
- stdout. queue ( SetForegroundColor ( Color :: Yellow ) ) ?;
190
- stdout . write_all ( b"PENDING " ) ?;
185
+ writer . stdout . queue ( SetForegroundColor ( Color :: Yellow ) ) ?;
186
+ writer . write_ascii ( b"PENDING " ) ?;
191
187
}
192
188
193
- stdout. queue ( SetForegroundColor ( Color :: Reset ) ) ?;
189
+ writer . stdout . queue ( SetForegroundColor ( Color :: Reset ) ) ?;
194
190
195
- stdout . write_all ( exercise. name . as_bytes ( ) ) ?;
196
- stdout . write_all ( & SPACE [ ..self . name_col_width + 2 - exercise. name . len ( ) ] ) ?;
191
+ writer . write_str ( exercise. name ) ?;
192
+ writer . write_ascii ( & SPACE [ ..self . name_col_width + 2 - exercise. name . len ( ) ] ) ?;
197
193
198
- terminal_file_link ( stdout , exercise. path , Color :: Blue ) ?;
194
+ terminal_file_link ( & mut writer , exercise. path , Color :: Blue ) ?;
199
195
200
- next_ln_overwrite ( stdout) ?;
196
+ next_ln ( stdout) ?;
201
197
stdout. queue ( ResetColor ) ?;
202
198
n_displayed_rows += 1 ;
203
199
}
@@ -213,10 +209,11 @@ impl<'a> ListState<'a> {
213
209
stdout. queue ( BeginSynchronizedUpdate ) ?. queue ( MoveTo ( 0 , 0 ) ) ?;
214
210
215
211
// Header
216
- stdout. write_all ( b" Current State Name" ) ?;
217
- stdout. write_all ( & SPACE [ ..self . name_col_width - 2 ] ) ?;
218
- stdout. write_all ( b"Path" ) ?;
219
- next_ln_overwrite ( stdout) ?;
212
+ let mut writer = MaxLenWriter :: new ( stdout, self . term_width as usize ) ;
213
+ writer. write_ascii ( b" Current State Name" ) ?;
214
+ writer. write_ascii ( & SPACE [ ..self . name_col_width - 2 ] ) ?;
215
+ writer. write_ascii ( b"Path" ) ?;
216
+ next_ln ( stdout) ?;
220
217
221
218
// Rows
222
219
let iter = self . app_state . exercises ( ) . iter ( ) . enumerate ( ) ;
@@ -237,7 +234,7 @@ impl<'a> ListState<'a> {
237
234
next_ln ( stdout) ?;
238
235
239
236
progress_bar (
240
- stdout,
237
+ & mut MaxLenWriter :: new ( stdout, self . term_width as usize ) ,
241
238
self . app_state . n_done ( ) ,
242
239
self . app_state . exercises ( ) . len ( ) as u16 ,
243
240
self . term_width ,
@@ -247,59 +244,55 @@ impl<'a> ListState<'a> {
247
244
stdout. write_all ( & self . separator_line ) ?;
248
245
next_ln ( stdout) ?;
249
246
247
+ let mut writer = MaxLenWriter :: new ( stdout, self . term_width as usize ) ;
250
248
if self . message . is_empty ( ) {
251
249
// Help footer message
252
250
if self . selected_row . is_some ( ) {
253
- stdout. write_all (
254
- "↓/j ↑/k home/g end/G | <c>ontinue at | <r>eset exercise" . as_bytes ( ) ,
255
- ) ?;
251
+ writer. write_str ( "↓/j ↑/k home/g end/G | <c>ontinue at | <r>eset exercise" ) ?;
256
252
if self . narrow_term {
257
- next_ln_overwrite ( stdout) ?;
258
- stdout. write_all ( b"filter " ) ?;
253
+ next_ln ( stdout) ?;
254
+ writer = MaxLenWriter :: new ( stdout, self . term_width as usize ) ;
255
+
256
+ writer. write_ascii ( b"filter " ) ?;
259
257
} else {
260
- stdout . write_all ( b" | filter " ) ?;
258
+ writer . write_ascii ( b" | filter " ) ?;
261
259
}
262
260
} else {
263
261
// Nothing selected (and nothing shown), so only display filter and quit.
264
- stdout . write_all ( b"filter " ) ?;
262
+ writer . write_ascii ( b"filter " ) ?;
265
263
}
266
264
267
265
match self . filter {
268
266
Filter :: Done => {
269
- stdout
267
+ writer
268
+ . stdout
270
269
. queue ( SetForegroundColor ( Color :: Magenta ) ) ?
271
270
. queue ( SetAttribute ( Attribute :: Underlined ) ) ?;
272
- stdout . write_all ( b"<d>one" ) ?;
273
- stdout. queue ( ResetColor ) ?;
274
- stdout . write_all ( b"/<p>ending" ) ?;
271
+ writer . write_ascii ( b"<d>one" ) ?;
272
+ writer . stdout . queue ( ResetColor ) ?;
273
+ writer . write_ascii ( b"/<p>ending" ) ?;
275
274
}
276
275
Filter :: Pending => {
277
- stdout. write_all ( b"<d>one/" ) ?;
278
- stdout
276
+ writer. write_ascii ( b"<d>one/" ) ?;
277
+ writer
278
+ . stdout
279
279
. queue ( SetForegroundColor ( Color :: Magenta ) ) ?
280
280
. queue ( SetAttribute ( Attribute :: Underlined ) ) ?;
281
- stdout . write_all ( b"<p>ending" ) ?;
282
- stdout. queue ( ResetColor ) ?;
281
+ writer . write_ascii ( b"<p>ending" ) ?;
282
+ writer . stdout . queue ( ResetColor ) ?;
283
283
}
284
- Filter :: None => stdout . write_all ( b"<d>one/<p>ending" ) ?,
284
+ Filter :: None => writer . write_ascii ( b"<d>one/<p>ending" ) ?,
285
285
}
286
286
287
- stdout. write_all ( b" | <q>uit list" ) ?;
288
-
289
- if self . narrow_term {
290
- next_ln_overwrite ( stdout) ?;
291
- } else {
292
- next_ln ( stdout) ?;
293
- }
287
+ writer. write_ascii ( b" | <q>uit list" ) ?;
294
288
} else {
295
- stdout. queue ( SetForegroundColor ( Color :: Magenta ) ) ?;
296
- stdout . write_all ( self . message . as_bytes ( ) ) ?;
289
+ writer . stdout . queue ( SetForegroundColor ( Color :: Magenta ) ) ?;
290
+ writer . write_str ( & self . message ) ?;
297
291
stdout. queue ( ResetColor ) ?;
298
- next_ln_overwrite ( stdout) ?;
299
- if self . narrow_term {
300
- next_ln ( stdout) ?;
301
- }
292
+ next_ln ( stdout) ?;
302
293
}
294
+
295
+ next_ln ( stdout) ?;
303
296
}
304
297
305
298
stdout. queue ( EndSynchronizedUpdate ) ?. flush ( )
0 commit comments