@@ -1502,27 +1502,27 @@ fn split_on_top_level(input: &str, split_on_newline: bool) -> Vec<&str> {
15021502 }
15031503 _ if !in_single_quote && !in_double_quote && paren_depth == 0
15041504 // Check for keyword at word boundary
1505- && ( ch. is_alphabetic ( ) || ch == '_' ) => {
1506- let word_start = i;
1507- while i < bytes. len ( ) && ( bytes[ i] . is_ascii_alphanumeric ( ) || bytes[ i] == b'_' )
1508- {
1509- i += 1 ;
1510- }
1511- let word = & input[ word_start..i] ;
1512- // Keywords only count at word boundaries (followed by space, ;, newline, or EOF)
1513- let at_boundary = i >= bytes. len ( )
1514- || bytes[ i] == b' '
1515- || bytes[ i] == b'\t'
1516- || bytes[ i] == b';'
1517- || bytes[ i] == b'\n' ;
1518- if at_boundary {
1519- if is_block_open_keyword ( word) {
1520- block_depth += 1 ;
1521- } else if is_block_close_keyword ( word) {
1522- block_depth = ( block_depth - 1 ) . max ( 0 ) ;
1523- }
1505+ && ( ch. is_alphabetic ( ) || ch == '_' ) =>
1506+ {
1507+ let word_start = i;
1508+ while i < bytes. len ( ) && ( bytes[ i] . is_ascii_alphanumeric ( ) || bytes[ i] == b'_' ) {
1509+ i += 1 ;
1510+ }
1511+ let word = & input[ word_start..i] ;
1512+ // Keywords only count at word boundaries (followed by space, ;, newline, or EOF)
1513+ let at_boundary = i >= bytes. len ( )
1514+ || bytes[ i] == b' '
1515+ || bytes[ i] == b'\t'
1516+ || bytes[ i] == b';'
1517+ || bytes[ i] == b'\n' ;
1518+ if at_boundary {
1519+ if is_block_open_keyword ( word) {
1520+ block_depth += 1 ;
1521+ } else if is_block_close_keyword ( word) {
1522+ block_depth = ( block_depth - 1 ) . max ( 0 ) ;
15241523 }
15251524 }
1525+ }
15261526 _ => {
15271527 i += 1 ;
15281528 }
@@ -2794,45 +2794,42 @@ fn split_control_keywords<'a>(input: &'a str, keywords: &[&str]) -> Vec<(&'a str
27942794 in_double_quote = !in_double_quote;
27952795 i += 1 ;
27962796 }
2797- _ if !in_single_quote && !in_double_quote
2798- && ( ch. is_alphabetic ( ) || ch == '_' ) => {
2799- let word_start = i;
2800- while i < bytes. len ( ) && ( bytes[ i] . is_ascii_alphanumeric ( ) || bytes[ i] == b'_' )
2801- {
2802- i += 1 ;
2803- }
2804- let word = & input[ word_start..i] ;
2805-
2806- let at_boundary = word_start == 0
2807- || bytes[ word_start - 1 ] == b' '
2808- || bytes[ word_start - 1 ] == b'\t'
2809- || bytes[ word_start - 1 ] == b';'
2810- || bytes[ word_start - 1 ] == b'\n' ;
2811-
2812- let ends_boundary = i >= bytes. len ( )
2813- || bytes[ i] == b' '
2814- || bytes[ i] == b'\t'
2815- || bytes[ i] == b';'
2816- || bytes[ i] == b'\n' ;
2817-
2818- if at_boundary && ends_boundary {
2819- if nested_depth == 0 && keywords. contains ( & word) {
2820- // Top-level keyword split point
2821- if !last_keyword. is_empty ( ) || !result. is_empty ( ) {
2822- result
2823- . push ( ( last_keyword, input[ content_start..word_start] . trim ( ) ) ) ;
2824- }
2825- last_keyword = word;
2826- content_start = i;
2827- // Do NOT change nested_depth — this is OUR keyword, not a nested one
2828- } else if is_block_open_keyword ( word) {
2829- // Nested control structure — track depth so we skip inner keywords
2830- nested_depth += 1 ;
2831- } else if is_block_close_keyword ( word) && nested_depth > 0 {
2832- nested_depth -= 1 ;
2797+ _ if !in_single_quote && !in_double_quote && ( ch. is_alphabetic ( ) || ch == '_' ) => {
2798+ let word_start = i;
2799+ while i < bytes. len ( ) && ( bytes[ i] . is_ascii_alphanumeric ( ) || bytes[ i] == b'_' ) {
2800+ i += 1 ;
2801+ }
2802+ let word = & input[ word_start..i] ;
2803+
2804+ let at_boundary = word_start == 0
2805+ || bytes[ word_start - 1 ] == b' '
2806+ || bytes[ word_start - 1 ] == b'\t'
2807+ || bytes[ word_start - 1 ] == b';'
2808+ || bytes[ word_start - 1 ] == b'\n' ;
2809+
2810+ let ends_boundary = i >= bytes. len ( )
2811+ || bytes[ i] == b' '
2812+ || bytes[ i] == b'\t'
2813+ || bytes[ i] == b';'
2814+ || bytes[ i] == b'\n' ;
2815+
2816+ if at_boundary && ends_boundary {
2817+ if nested_depth == 0 && keywords. contains ( & word) {
2818+ // Top-level keyword split point
2819+ if !last_keyword. is_empty ( ) || !result. is_empty ( ) {
2820+ result. push ( ( last_keyword, input[ content_start..word_start] . trim ( ) ) ) ;
28332821 }
2822+ last_keyword = word;
2823+ content_start = i;
2824+ // Do NOT change nested_depth — this is OUR keyword, not a nested one
2825+ } else if is_block_open_keyword ( word) {
2826+ // Nested control structure — track depth so we skip inner keywords
2827+ nested_depth += 1 ;
2828+ } else if is_block_close_keyword ( word) && nested_depth > 0 {
2829+ nested_depth -= 1 ;
28342830 }
28352831 }
2832+ }
28362833 _ => {
28372834 i += 1 ;
28382835 }
@@ -3215,32 +3212,30 @@ pub fn is_incomplete_control_structure(input: &str) -> bool {
32153212 in_double_quote = !in_double_quote;
32163213 i += 1 ;
32173214 }
3218- _ if !in_single_quote && !in_double_quote
3219- && ( ch. is_alphabetic ( ) || ch == '_' ) => {
3220- let word_start = i;
3221- while i < bytes. len ( ) && ( bytes[ i] . is_ascii_alphanumeric ( ) || bytes[ i] == b'_' )
3222- {
3223- i += 1 ;
3224- }
3225- let word = & trimmed[ word_start..i] ;
3226- let at_boundary = word_start == 0
3227- || bytes[ word_start - 1 ] == b' '
3228- || bytes[ word_start - 1 ] == b'\t'
3229- || bytes[ word_start - 1 ] == b';'
3230- || bytes[ word_start - 1 ] == b'\n' ;
3231- let ends_boundary = i >= bytes. len ( )
3232- || bytes[ i] == b' '
3233- || bytes[ i] == b'\t'
3234- || bytes[ i] == b';'
3235- || bytes[ i] == b'\n' ;
3236- if at_boundary && ends_boundary {
3237- if is_block_open_keyword ( word) {
3238- block_depth += 1 ;
3239- } else if is_block_close_keyword ( word) {
3240- block_depth -= 1 ;
3241- }
3215+ _ if !in_single_quote && !in_double_quote && ( ch. is_alphabetic ( ) || ch == '_' ) => {
3216+ let word_start = i;
3217+ while i < bytes. len ( ) && ( bytes[ i] . is_ascii_alphanumeric ( ) || bytes[ i] == b'_' ) {
3218+ i += 1 ;
3219+ }
3220+ let word = & trimmed[ word_start..i] ;
3221+ let at_boundary = word_start == 0
3222+ || bytes[ word_start - 1 ] == b' '
3223+ || bytes[ word_start - 1 ] == b'\t'
3224+ || bytes[ word_start - 1 ] == b';'
3225+ || bytes[ word_start - 1 ] == b'\n' ;
3226+ let ends_boundary = i >= bytes. len ( )
3227+ || bytes[ i] == b' '
3228+ || bytes[ i] == b'\t'
3229+ || bytes[ i] == b';'
3230+ || bytes[ i] == b'\n' ;
3231+ if at_boundary && ends_boundary {
3232+ if is_block_open_keyword ( word) {
3233+ block_depth += 1 ;
3234+ } else if is_block_close_keyword ( word) {
3235+ block_depth -= 1 ;
32423236 }
32433237 }
3238+ }
32443239 _ => {
32453240 i += 1 ;
32463241 }
@@ -4907,15 +4902,14 @@ pub fn extract_heredoc_delimiters(input: &str) -> Result<Vec<String>> {
49074902 let tokens = tokenize ( input) ?;
49084903
49094904 for i in 0 ..tokens. len ( ) {
4910- if matches ! ( tokens[ i] , Token :: HereDoc | Token :: HereDocDash )
4911- && i + 1 < tokens. len ( ) {
4912- if let Token :: Word ( ref word) = tokens[ i + 1 ] {
4913- let delimiter = quoted_word_to_string ( word) ;
4914- // Remove quotes if present
4915- let clean = delimiter. trim_matches ( |c| c == '\'' || c == '"' ) ;
4916- delimiters. push ( clean. to_string ( ) ) ;
4917- }
4905+ if matches ! ( tokens[ i] , Token :: HereDoc | Token :: HereDocDash ) && i + 1 < tokens. len ( ) {
4906+ if let Token :: Word ( ref word) = tokens[ i + 1 ] {
4907+ let delimiter = quoted_word_to_string ( word) ;
4908+ // Remove quotes if present
4909+ let clean = delimiter. trim_matches ( |c| c == '\'' || c == '"' ) ;
4910+ delimiters. push ( clean. to_string ( ) ) ;
49184911 }
4912+ }
49194913 }
49204914
49214915 Ok ( delimiters)
0 commit comments