@@ -14,6 +14,18 @@ impl TextProcessor {
1414 pub fn process_challenge_text_with_comment_mapping (
1515 text : & str ,
1616 comment_ranges : & [ ( usize , usize ) ] ,
17+ ) -> ( String , Vec < ( usize , usize ) > ) {
18+ Self :: process_challenge_text_with_comment_mapping_preserve_empty (
19+ text,
20+ comment_ranges,
21+ false ,
22+ )
23+ }
24+
25+ pub fn process_challenge_text_with_comment_mapping_preserve_empty (
26+ text : & str ,
27+ comment_ranges : & [ ( usize , usize ) ] ,
28+ preserve_empty_lines : bool ,
1729 ) -> ( String , Vec < ( usize , usize ) > ) {
1830 // Create character position mapping from original to processed text
1931 let mut position_mapping = Vec :: new ( ) ;
@@ -26,8 +38,8 @@ impl TextProcessor {
2638 for line in & lines {
2739 let trimmed_line = line. trim_end ( ) ;
2840
29- // Skip empty lines
30- if trimmed_line. trim ( ) . is_empty ( ) {
41+ // Skip empty lines only if preserve_empty_lines is false
42+ if !preserve_empty_lines && trimmed_line. trim ( ) . is_empty ( ) {
3143 // Record that all characters in this line are skipped
3244 for _ in 0 ..line. len ( ) {
3345 position_mapping. push ( None ) ; // None means this character was removed
@@ -190,14 +202,13 @@ impl TextProcessor {
190202 return false ;
191203 }
192204
193- // Don't skip newlines - they need to be typeable
205+ // Skip newlines only in specific cases, but keep them typeable
194206 if chars[ position] == '\n' {
195- // Only skip newlines that are at the end of comment-only lines or at end of text
196- if Self :: is_newline_after_comment_only_line ( text, position, comment_ranges)
197- || Self :: should_skip_final_newline ( text, position)
198- {
207+ // Skip newlines only at the very end of text
208+ if Self :: should_skip_final_newline ( text, position) {
199209 return true ;
200210 }
211+ // Keep newlines typeable by default
201212 return false ;
202213 }
203214
@@ -291,39 +302,42 @@ impl TextProcessor {
291302 false
292303 }
293304
294- fn is_newline_after_comment_only_line (
305+ pub fn is_rest_of_line_comment_only (
295306 text : & str ,
296307 position : usize ,
297308 comment_ranges : & [ ( usize , usize ) ] ,
298309 ) -> bool {
299310 let chars: Vec < char > = text. chars ( ) . collect ( ) ;
300-
301- // Check if current character is newline
302- if position >= chars. len ( ) || chars[ position] != '\n' {
311+ if position >= chars. len ( ) {
303312 return false ;
304313 }
305314
306- // Find the start of current line
307- let mut line_start = position;
308- while line_start > 0 && chars[ line_start - 1 ] != '\n' {
309- line_start = line_start . saturating_sub ( 1 ) ;
315+ // Find the next newline or end of text
316+ let mut end_pos = position;
317+ while end_pos < chars . len ( ) && chars[ end_pos ] != '\n' {
318+ end_pos += 1 ;
310319 }
311320
312- // Check if everything from line_start to position is whitespace or comment
313- for ( i, & ch) in chars. iter ( ) . enumerate ( ) . take ( position) . skip ( line_start) {
314- if !ch. is_whitespace ( ) {
315- // Found non-whitespace, check if it's part of a comment
316- if !comment_ranges
317- . iter ( )
318- . any ( |& ( start, end) | i >= start && i < end)
319- {
320- // Non-whitespace that's not a comment = this is not a comment-only line
321- return false ;
322- }
321+ // Check if everything from current position to end of line is comment or whitespace
322+ for i in position..end_pos {
323+ let ch = chars[ i] ;
324+
325+ // Skip whitespace
326+ if ch. is_whitespace ( ) {
327+ continue ;
328+ }
329+
330+ // Check if this character is part of a comment
331+ let is_in_comment = comment_ranges
332+ . iter ( )
333+ . any ( |& ( start, end) | i >= start && i < end) ;
334+
335+ if !is_in_comment {
336+ return false ; // Found non-comment, non-whitespace content
323337 }
324338 }
325339
326- // This line contains only whitespace and/ or comments
340+ // Everything from current position to end of line is comment or whitespace
327341 true
328342 }
329343}
0 commit comments