@@ -310,18 +310,19 @@ impl TypingCore {
310310 let lines: Vec < & str > = original. lines ( ) . collect ( ) ;
311311 let mut processed_lines = Vec :: new ( ) ;
312312 let mut position_mapping = Vec :: new ( ) ;
313- let mut original_pos = 0 ;
313+ let mut original_char_pos = 0 ;
314314 let mut _processed_pos = 0 ;
315315
316316 for ( line_idx, line) in lines. iter ( ) . enumerate ( ) {
317- let line_start_pos = original_pos ;
317+ let line_start_char_pos = original_char_pos ;
318318
319319 // Process this line, removing comments
320320 let mut line_result = String :: new ( ) ;
321321 let mut line_mapping = Vec :: new ( ) ;
322322
323- for ( char_idx, ch) in line. char_indices ( ) {
324- let char_pos = line_start_pos + char_idx;
323+ // Use enumerate() to get character position, not byte position
324+ for ( char_idx_in_line, ch) in line. chars ( ) . enumerate ( ) {
325+ let char_pos = line_start_char_pos + char_idx_in_line;
325326
326327 // Check if this character is in a comment
327328 let in_comment = comment_ranges
@@ -335,14 +336,16 @@ impl TypingCore {
335336 let is_leading = line_result. chars ( ) . all ( |c| c. is_whitespace ( ) ) ;
336337
337338 // Check if this is trailing whitespace or followed by comment
338- let remaining_line = & line[ char_idx..] ;
339- let is_trailing = remaining_line. chars ( ) . all ( |c| {
340- c. is_whitespace ( )
341- || comment_ranges. iter ( ) . any ( |& ( start, end) | {
342- let pos =
343- line_start_pos + char_idx + remaining_line. find ( c) . unwrap_or ( 0 ) ;
344- pos >= start && pos < end
345- } )
339+ let remaining_chars: Vec < char > = line. chars ( ) . skip ( char_idx_in_line) . collect ( ) ;
340+ let is_trailing = remaining_chars. iter ( ) . all ( |& c| {
341+ c. is_whitespace ( ) || {
342+ // Calculate the absolute char position of this character
343+ let check_pos = char_pos
344+ + remaining_chars. iter ( ) . position ( |& rc| rc == c) . unwrap_or ( 0 ) ;
345+ comment_ranges
346+ . iter ( )
347+ . any ( |& ( start, end) | check_pos >= start && check_pos < end)
348+ }
346349 } ) ;
347350
348351 // Skip leading and trailing whitespace, preserve internal spaces
@@ -366,15 +369,15 @@ impl TypingCore {
366369
367370 // Add line mappings to main mapping
368371 position_mapping. extend ( line_mapping) ;
369- original_pos += line. len ( ) ;
372+ original_char_pos += line. chars ( ) . count ( ) ;
370373
371374 // Handle newline character if not the last line
372375 if line_idx < lines. len ( ) - 1 {
373376 if !is_empty_line {
374- position_mapping. push ( line_start_pos + line. len ( ) ) ;
377+ position_mapping. push ( line_start_char_pos + line. chars ( ) . count ( ) ) ;
375378 _processed_pos += 1 ;
376379 }
377- original_pos += 1 ; // Account for \n
380+ original_char_pos += 1 ; // Account for \n
378381 }
379382 }
380383
@@ -391,19 +394,19 @@ impl TypingCore {
391394 let mut position_mapping = Vec :: new ( ) ;
392395
393396 let lines: Vec < & str > = original_text. lines ( ) . collect ( ) ;
394- let mut original_pos = 0 ;
397+ let mut original_char_pos = 0 ;
395398
396399 for ( line_idx, line) in lines. iter ( ) . enumerate ( ) {
397- let line_start = original_pos ;
400+ let line_start_char_pos = original_char_pos ;
398401
399402 // Check if this line has any content that needs typing (not just comments)
400403 let line_has_typeable_content = {
401404 let mut has_content = false ;
402- for ( char_idx , line_ch) in line. char_indices ( ) {
403- let absolute_pos = line_start + char_idx ;
405+ for ( char_idx_in_line , line_ch) in line. chars ( ) . enumerate ( ) {
406+ let absolute_char_pos = line_start_char_pos + char_idx_in_line ;
404407 let in_comment = comment_ranges
405408 . iter ( )
406- . any ( |& ( start, end) | absolute_pos >= start && absolute_pos < end) ;
409+ . any ( |& ( start, end) | absolute_char_pos >= start && absolute_char_pos < end) ;
407410
408411 if !in_comment && !line_ch. is_whitespace ( ) {
409412 has_content = true ;
@@ -414,16 +417,16 @@ impl TypingCore {
414417 } ;
415418
416419 // Find the position of the last typeable character in this line
417- let last_typeable_pos = if line_has_typeable_content {
420+ let last_typeable_char_idx = if line_has_typeable_content {
418421 let mut last_pos = None ;
419- for ( char_idx , line_ch) in line. char_indices ( ) {
420- let absolute_pos = line_start + char_idx ;
422+ for ( char_idx_in_line , line_ch) in line. chars ( ) . enumerate ( ) {
423+ let absolute_char_pos = line_start_char_pos + char_idx_in_line ;
421424 let in_comment = comment_ranges
422425 . iter ( )
423- . any ( |& ( start, end) | absolute_pos >= start && absolute_pos < end) ;
426+ . any ( |& ( start, end) | absolute_char_pos >= start && absolute_char_pos < end) ;
424427
425428 if !in_comment && !line_ch. is_whitespace ( ) {
426- last_pos = Some ( char_idx ) ;
429+ last_pos = Some ( char_idx_in_line ) ;
427430 }
428431 }
429432 last_pos
@@ -432,8 +435,8 @@ impl TypingCore {
432435 } ;
433436
434437 // Process each character in the line
435- for ( char_idx , ch) in line. char_indices ( ) {
436- let char_original_pos = line_start + char_idx ;
438+ for ( char_idx_in_line , ch) in line. chars ( ) . enumerate ( ) {
439+ let char_original_pos = line_start_char_pos + char_idx_in_line ;
437440 position_mapping. push ( char_original_pos) ;
438441
439442 if options. highlight_special_chars && ch == '\t' {
@@ -447,20 +450,20 @@ impl TypingCore {
447450 }
448451
449452 // Insert ↵ right after the last typeable character
450- if options. add_newline_symbols && Some ( char_idx ) == last_typeable_pos {
451- position_mapping. push ( line_start + line. len ( ) ) ; // Position for ↵
453+ if options. add_newline_symbols && Some ( char_idx_in_line ) == last_typeable_char_idx {
454+ position_mapping. push ( line_start_char_pos + line. chars ( ) . count ( ) ) ; // Position for ↵
452455 display_text. push ( '↵' ) ;
453456 }
454457 }
455458
456459 // Handle newline
457460 if line_idx < lines. len ( ) - 1 {
458- position_mapping. push ( line_start + line. len ( ) ) ; // Position of \n
461+ position_mapping. push ( line_start_char_pos + line. chars ( ) . count ( ) ) ; // Position of \n
459462 display_text. push ( '\n' ) ;
460463
461- original_pos += line. len ( ) + 1 ; // +1 for \n
464+ original_char_pos += line. chars ( ) . count ( ) + 1 ; // +1 for \n
462465 } else {
463- original_pos += line. len ( ) ;
466+ original_char_pos += line. chars ( ) . count ( ) ;
464467 }
465468 }
466469
@@ -489,12 +492,13 @@ impl TypingCore {
489492
490493 // Helper methods for typing logic
491494 pub fn is_position_at_line_end ( & self , type_pos : usize ) -> bool {
492- if type_pos >= self . text_to_type . len ( ) {
495+ let chars: Vec < char > = self . text_to_type . chars ( ) . collect ( ) ;
496+
497+ if type_pos >= chars. len ( ) {
493498 return true ;
494499 }
495500
496501 // Check if current position is newline or if all following chars on line are whitespace
497- let chars: Vec < char > = self . text_to_type . chars ( ) . collect ( ) ;
498502 if chars. get ( type_pos) == Some ( & '\n' ) {
499503 return true ;
500504 }
@@ -519,11 +523,11 @@ impl TypingCore {
519523
520524 // Helper methods for typing logic
521525 pub fn is_completed ( & self ) -> bool {
522- self . current_position_to_type >= self . text_to_type . len ( )
526+ self . current_position_to_type >= self . text_to_type . chars ( ) . count ( )
523527 }
524528
525529 pub fn can_accept_input ( & self ) -> bool {
526- self . current_position_to_type < self . text_to_type . len ( )
530+ self . current_position_to_type < self . text_to_type . chars ( ) . count ( )
527531 }
528532
529533 pub fn check_character_match ( & self , input_char : char ) -> bool {
0 commit comments