@@ -3,7 +3,7 @@ use std::fmt::{self, Display, Formatter};
33use std:: fs:: { self , remove_file, File } ;
44use std:: io:: { self , BufRead , BufReader } ;
55use std:: path:: PathBuf ;
6- use std:: process:: { self , Command } ;
6+ use std:: process:: { self , exit , Command } ;
77use std:: { array, env, mem} ;
88use winnow:: ascii:: { space0, Caseless } ;
99use winnow:: combinator:: opt;
@@ -15,7 +15,8 @@ const RUSTC_NO_DEBUG_ARGS: &[&str] = &["-C", "strip=debuginfo"];
1515const CONTEXT : usize = 2 ;
1616const CLIPPY_CARGO_TOML_PATH : & str = "./exercises/22_clippy/Cargo.toml" ;
1717
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 {
1920 (
2021 space0 :: < _ , ( ) > ,
2122 "//" ,
@@ -219,12 +220,15 @@ path = "{}.rs""#,
219220
220221 pub fn state ( & self ) -> State {
221222 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 ) ;
226228 } ) ;
227229 let mut source_reader = BufReader :: new ( source_file) ;
230+
231+ // Read the next line into `buf` without the newline at the end.
228232 let mut read_line = |buf : & mut String | -> io:: Result < _ > {
229233 let n = source_reader. read_line ( buf) ?;
230234 if buf. ends_with ( '\n' ) {
@@ -236,70 +240,72 @@ path = "{}.rs""#,
236240 Ok ( n)
237241 } ;
238242
239- let mut matched_line_ind : usize = 0 ;
243+ let mut current_line_number : usize = 1 ;
240244 let mut prev_lines: [ _ ; CONTEXT ] = array:: from_fn ( |_| String :: with_capacity ( 256 ) ) ;
241245 let mut line = String :: with_capacity ( 256 ) ;
242246
243247 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+ }
288275
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 ;
292290 }
293- line. clear ( ) ;
291+
292+ context. push ( ContextLine {
293+ line : next_line,
294+ number : current_line_number + 1 + ind,
295+ important : false ,
296+ } ) ;
294297 }
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) ;
299300 }
300- }
301301
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+ }
303309 }
304310
305311 // Check that the exercise looks to be solved using self.state()
@@ -428,17 +434,17 @@ mod test {
428434
429435 #[ test]
430436 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" ) ) ;
443449 }
444450}
0 commit comments