@@ -2098,18 +2098,38 @@ fn analyze_magic_line(content: &str) -> usize {
20982098
20992099 // Point to where "technique" should be if missing or incorrect
21002100 if !trimmed. contains ( "technique" ) {
2101- // Find position after % and whitespace
2102- return content
2103- . find ( '%' )
2104- . unwrap_or ( 0 )
2105- + 1 ;
2101+ // Find position after % and skip whitespace to point to first char of wrong keyword
2102+ if let Some ( percent_pos) = content. find ( '%' ) {
2103+ let after_percent = percent_pos + 1 ;
2104+ let remaining = & content[ after_percent..] ;
2105+ for ( i, ch) in remaining. char_indices ( ) {
2106+ if !ch. is_whitespace ( ) {
2107+ return after_percent + i;
2108+ }
2109+ }
2110+ return after_percent;
2111+ }
2112+ return 0 ;
21062113 }
21072114
21082115 // Point to where version should be if missing v1
21092116 if !trimmed. contains ( "v1" ) {
21102117 // Find position after "technique"
21112118 if let Some ( pos) = content. find ( "technique" ) {
2112- return pos + "technique" . len ( ) ;
2119+ let after_technique = pos + "technique" . len ( ) ;
2120+ // Skip whitespace to find the actual version string
2121+ let remaining = & content[ after_technique..] ;
2122+ for ( i, ch) in remaining. char_indices ( ) {
2123+ if !ch. is_whitespace ( ) {
2124+ // If we found a 'v', point to the character after it (the version number)
2125+ if ch == 'v' && i + 1 < remaining. len ( ) {
2126+ return after_technique + i + 1 ;
2127+ }
2128+ // Otherwise point to where we found the non-whitespace character
2129+ return after_technique + i;
2130+ }
2131+ }
2132+ return after_technique;
21132133 }
21142134 }
21152135
@@ -2418,6 +2438,37 @@ mod check {
24182438 assert ! ( result. is_err( ) ) ;
24192439 }
24202440
2441+ #[ test]
2442+ fn magic_line_wrong_keyword_error_position ( ) {
2443+ // Test that error position points to the first character of the wrong keyword
2444+ assert_eq ! ( analyze_magic_line( "% tecnique v1" ) , 2 ) ; // Points to "t" in "tecnique"
2445+ assert_eq ! ( analyze_magic_line( "% tecnique v1" ) , 3 ) ; // Points to "t" in "tecnique" with extra space
2446+ assert_eq ! ( analyze_magic_line( "% \t techniqe v1" ) , 3 ) ; // Points to "t" in "techniqe" with tab
2447+ assert_eq ! ( analyze_magic_line( "% wrong v1" ) , 5 ) ; // Points to "w" in "wrong" with multiple spaces
2448+ assert_eq ! ( analyze_magic_line( "% foo v1" ) , 2 ) ; // Points to "f" in "foo"
2449+ assert_eq ! ( analyze_magic_line( "% TECHNIQUE v1" ) , 2 ) ; // Points to "T" in uppercase "TECHNIQUE"
2450+
2451+ // Test missing keyword entirely - should point to position after %
2452+ assert_eq ! ( analyze_magic_line( "% v1" ) , 2 ) ; // Points to "v" when keyword is missing
2453+ assert_eq ! ( analyze_magic_line( "% v1" ) , 3 ) ; // Points to "v" when keyword is missing with space
2454+ }
2455+
2456+ #[ test]
2457+ fn magic_line_wrong_version_error_position ( ) {
2458+ // Test that error position points to the version number after "v" in wrong version strings
2459+ assert_eq ! ( analyze_magic_line( "% technique v0" ) , 13 ) ; // Points to "0" in "v0"
2460+ assert_eq ! ( analyze_magic_line( "% technique v2" ) , 14 ) ; // Points to "2" in "v2" with extra space
2461+ assert_eq ! ( analyze_magic_line( "% technique\t v0" ) , 13 ) ; // Points to "0" in "v0" with tab
2462+ assert_eq ! ( analyze_magic_line( "% technique vX" ) , 15 ) ; // Points to "X" in "vX" with multiple spaces
2463+ assert_eq ! ( analyze_magic_line( "% technique v99" ) , 13 ) ; // Points to "9" in "v99"
2464+ assert_eq ! ( analyze_magic_line( "% technique v0.5" ) , 15 ) ; // Points to "0" in "v0.5" with multiple spaces
2465+
2466+ // Test edge case where there's no "v" at all - should point to where version should start
2467+ assert_eq ! ( analyze_magic_line( "% technique 1.0" ) , 12 ) ; // Points to "1" when there's no "v"
2468+ assert_eq ! ( analyze_magic_line( "% technique 2" ) , 13 ) ; // Points to "2" when there's no "v" with extra space
2469+ assert_eq ! ( analyze_magic_line( "% technique beta" ) , 12 ) ; // Points to "b" in "beta" when there's no "v"
2470+ }
2471+
24212472 #[ test]
24222473 fn header_spdx ( ) {
24232474 let mut input = Parser :: new ( ) ;
0 commit comments