@@ -3,7 +3,7 @@ use std::fmt::{self, Display, Formatter};
3
3
use std:: fs:: { self , remove_file, File } ;
4
4
use std:: io:: { self , BufRead , BufReader } ;
5
5
use std:: path:: PathBuf ;
6
- use std:: process:: { self , Command } ;
6
+ use std:: process:: { self , exit , Command } ;
7
7
use std:: { array, env, mem} ;
8
8
use winnow:: ascii:: { space0, Caseless } ;
9
9
use winnow:: combinator:: opt;
@@ -15,7 +15,8 @@ const RUSTC_NO_DEBUG_ARGS: &[&str] = &["-C", "strip=debuginfo"];
15
15
const CONTEXT : usize = 2 ;
16
16
const CLIPPY_CARGO_TOML_PATH : & str = "./exercises/22_clippy/Cargo.toml" ;
17
17
18
- fn not_done ( input : & str ) -> bool {
18
+ // Checks if the line contains the "I AM NOT DONE" comment.
19
+ fn contains_not_done_comment ( input : & str ) -> bool {
19
20
(
20
21
space0 :: < _ , ( ) > ,
21
22
"//" ,
@@ -219,12 +220,15 @@ path = "{}.rs""#,
219
220
220
221
pub fn state ( & self ) -> State {
221
222
let source_file = File :: open ( & self . path ) . unwrap_or_else ( |e| {
222
- panic ! (
223
- "We were unable to open the exercise file {}! {e}" ,
224
- self . path. display( )
225
- )
223
+ println ! (
224
+ "Failed to open the exercise file {}: {e}" ,
225
+ self . path. display( ) ,
226
+ ) ;
227
+ exit ( 1 ) ;
226
228
} ) ;
227
229
let mut source_reader = BufReader :: new ( source_file) ;
230
+
231
+ // Read the next line into `buf` without the newline at the end.
228
232
let mut read_line = |buf : & mut String | -> io:: Result < _ > {
229
233
let n = source_reader. read_line ( buf) ?;
230
234
if buf. ends_with ( '\n' ) {
@@ -236,70 +240,72 @@ path = "{}.rs""#,
236
240
Ok ( n)
237
241
} ;
238
242
239
- let mut matched_line_ind : usize = 0 ;
243
+ let mut current_line_number : usize = 1 ;
240
244
let mut prev_lines: [ _ ; CONTEXT ] = array:: from_fn ( |_| String :: with_capacity ( 256 ) ) ;
241
245
let mut line = String :: with_capacity ( 256 ) ;
242
246
243
247
loop {
244
- match read_line ( & mut line) {
245
- Ok ( 0 ) => break ,
246
- Ok ( _) => {
247
- if not_done ( & line) {
248
- let mut context = Vec :: with_capacity ( 2 * CONTEXT + 1 ) ;
249
- for ( ind, prev_line) in prev_lines
250
- . into_iter ( )
251
- . rev ( )
252
- . take ( matched_line_ind)
253
- . enumerate ( )
254
- {
255
- context. push ( ContextLine {
256
- line : prev_line,
257
- // TODO
258
- number : matched_line_ind - CONTEXT + ind + 1 ,
259
- important : false ,
260
- } ) ;
261
- }
262
-
263
- context. push ( ContextLine {
264
- line,
265
- number : matched_line_ind + 1 ,
266
- important : true ,
267
- } ) ;
268
-
269
- for ind in 0 ..CONTEXT {
270
- let mut next_line = String :: with_capacity ( 256 ) ;
271
- let Ok ( n) = read_line ( & mut next_line) else {
272
- break ;
273
- } ;
274
-
275
- if n == 0 {
276
- break ;
277
- }
278
-
279
- context. push ( ContextLine {
280
- line : next_line,
281
- number : matched_line_ind + ind + 2 ,
282
- important : false ,
283
- } ) ;
284
- }
285
-
286
- return State :: Pending ( context) ;
287
- }
248
+ let n = read_line ( & mut line) . unwrap_or_else ( |e| {
249
+ println ! (
250
+ "Failed to read the exercise file {}: {e}" ,
251
+ self . path. display( ) ,
252
+ ) ;
253
+ exit ( 1 ) ;
254
+ } ) ;
255
+
256
+ // Reached the end of the file and didn't find the comment.
257
+ if n == 0 {
258
+ return State :: Done ;
259
+ }
260
+
261
+ if contains_not_done_comment ( & line) {
262
+ let mut context = Vec :: with_capacity ( 2 * CONTEXT + 1 ) ;
263
+ for ( ind, prev_line) in prev_lines
264
+ . into_iter ( )
265
+ . take ( current_line_number - 1 )
266
+ . enumerate ( )
267
+ . rev ( )
268
+ {
269
+ context. push ( ContextLine {
270
+ line : prev_line,
271
+ number : current_line_number - 1 - ind,
272
+ important : false ,
273
+ } ) ;
274
+ }
288
275
289
- matched_line_ind += 1 ;
290
- for prev_line in & mut prev_lines {
291
- mem:: swap ( & mut line, prev_line) ;
276
+ context. push ( ContextLine {
277
+ line,
278
+ number : current_line_number,
279
+ important : true ,
280
+ } ) ;
281
+
282
+ for ind in 0 ..CONTEXT {
283
+ let mut next_line = String :: with_capacity ( 256 ) ;
284
+ let Ok ( n) = read_line ( & mut next_line) else {
285
+ break ;
286
+ } ;
287
+
288
+ if n == 0 {
289
+ break ;
292
290
}
293
- line. clear ( ) ;
291
+
292
+ context. push ( ContextLine {
293
+ line : next_line,
294
+ number : current_line_number + 1 + ind,
295
+ important : false ,
296
+ } ) ;
294
297
}
295
- Err ( e) => panic ! (
296
- "We were unable to read the exercise file {}! {e}" ,
297
- self . path. display( )
298
- ) ,
298
+
299
+ return State :: Pending ( context) ;
299
300
}
300
- }
301
301
302
- State :: Done
302
+ current_line_number += 1 ;
303
+ // Recycle the buffers.
304
+ for prev_line in & mut prev_lines {
305
+ mem:: swap ( & mut line, prev_line) ;
306
+ }
307
+ line. clear ( ) ;
308
+ }
303
309
}
304
310
305
311
// Check that the exercise looks to be solved using self.state()
@@ -428,17 +434,17 @@ mod test {
428
434
429
435
#[ test]
430
436
fn test_not_done ( ) {
431
- assert ! ( not_done ( "// I AM NOT DONE" ) ) ;
432
- assert ! ( not_done ( "/// I AM NOT DONE" ) ) ;
433
- assert ! ( not_done ( "// I AM NOT DONE" ) ) ;
434
- assert ! ( not_done ( "/// I AM NOT DONE" ) ) ;
435
- assert ! ( not_done ( "// I AM NOT DONE " ) ) ;
436
- assert ! ( not_done ( "// I AM NOT DONE!" ) ) ;
437
- assert ! ( not_done ( "// I am not done" ) ) ;
438
- assert ! ( not_done ( "// i am NOT done" ) ) ;
439
-
440
- assert ! ( !not_done ( "I AM NOT DONE" ) ) ;
441
- assert ! ( !not_done ( "// NOT DONE" ) ) ;
442
- assert ! ( !not_done ( "DONE" ) ) ;
437
+ assert ! ( contains_not_done_comment ( "// I AM NOT DONE" ) ) ;
438
+ assert ! ( contains_not_done_comment ( "/// I AM NOT DONE" ) ) ;
439
+ assert ! ( contains_not_done_comment ( "// I AM NOT DONE" ) ) ;
440
+ assert ! ( contains_not_done_comment ( "/// I AM NOT DONE" ) ) ;
441
+ assert ! ( contains_not_done_comment ( "// I AM NOT DONE " ) ) ;
442
+ assert ! ( contains_not_done_comment ( "// I AM NOT DONE!" ) ) ;
443
+ assert ! ( contains_not_done_comment ( "// I am not done" ) ) ;
444
+ assert ! ( contains_not_done_comment ( "// i am NOT done" ) ) ;
445
+
446
+ assert ! ( !contains_not_done_comment ( "I AM NOT DONE" ) ) ;
447
+ assert ! ( !contains_not_done_comment ( "// NOT DONE" ) ) ;
448
+ assert ! ( !contains_not_done_comment ( "DONE" ) ) ;
443
449
}
444
450
}
0 commit comments