@@ -9,6 +9,31 @@ use graphic_types::{Artboard, Graphic, Vector};
99use raster_types:: { CPU , GPU , Raster } ;
1010use unicode_segmentation:: UnicodeSegmentation ;
1111
12+ /// Processes escape sequences in a string, converting `\n`, `\r`, `\t`, `\0`, and `\\` into their corresponding characters.
13+ /// Unrecognized escape sequences (e.g. `\x`) are preserved as-is.
14+ fn unescape ( input : String ) -> String {
15+ let mut result = String :: with_capacity ( input. len ( ) ) ;
16+ let mut chars = input. chars ( ) ;
17+
18+ while let Some ( c) = chars. next ( ) {
19+ if c == '\\' {
20+ match chars. next ( ) {
21+ Some ( 'n' ) => result. push ( '\n' ) ,
22+ Some ( 'r' ) => result. push ( '\r' ) ,
23+ Some ( 't' ) => result. push ( '\t' ) ,
24+ Some ( '0' ) => result. push ( '\0' ) ,
25+ Some ( '\\' ) => result. push ( '\\' ) ,
26+ Some ( unrecognized) => result. extend ( [ '\\' , unrecognized] ) ,
27+ None => result. push ( '\\' ) ,
28+ }
29+ } else {
30+ result. push ( c) ;
31+ }
32+ }
33+
34+ result
35+ }
36+
1237#[ derive( Debug , Clone , Copy , Default , PartialEq , Eq , Hash , dyn_any:: DynAny , node_macro:: ChoiceType , serde:: Serialize , serde:: Deserialize ) ]
1338#[ widget( Dropdown ) ]
1439pub enum StringCapitalization {
@@ -234,11 +259,7 @@ fn string_repeat(
234259 #[ default( true ) ]
235260 separator_escaping : bool ,
236261) -> String {
237- let separator = if separator_escaping {
238- separator. replace ( "\\ n" , "\n " ) . replace ( "\\ r" , "\r " ) . replace ( "\\ t" , "\t " ) . replace ( "\\ 0" , "\0 " ) . replace ( "\\ \\ " , "\\ " )
239- } else {
240- separator
241- } ;
262+ let separator = if separator_escaping { unescape ( separator) } else { separator } ;
242263
243264 let count = count. max ( 1 ) as usize ;
244265
@@ -399,20 +420,18 @@ fn string_capitalization(
399420 StringCapitalization :: UpperCase => string. to_uppercase ( ) ,
400421 StringCapitalization :: CapitalCase => {
401422 let mut capitalize_next = true ;
402- string
403- . chars ( )
404- . map ( |c| {
405- if c. is_whitespace ( ) || c == '_' || c == '-' {
406- capitalize_next = true ;
407- c
408- } else if capitalize_next {
409- capitalize_next = false ;
410- c. to_uppercase ( ) . next ( ) . unwrap_or ( c)
411- } else {
412- c
413- }
414- } )
415- . collect ( )
423+ string. chars ( ) . fold ( String :: with_capacity ( string. len ( ) ) , |mut result, c| {
424+ if c. is_whitespace ( ) || c == '_' || c == '-' {
425+ capitalize_next = true ;
426+ result. push ( c) ;
427+ } else if capitalize_next {
428+ capitalize_next = false ;
429+ result. extend ( c. to_uppercase ( ) ) ;
430+ } else {
431+ result. push ( c) ;
432+ }
433+ result
434+ } )
416435 }
417436 StringCapitalization :: HeadlineCase => titlecase:: titlecase ( & string) ,
418437 StringCapitalization :: SentenceCase => {
@@ -424,20 +443,18 @@ fn string_capitalization(
424443 }
425444 StringCapitalization :: CamelCase => {
426445 let mut capitalize_next = false ;
427- string
428- . chars ( )
429- . map ( |c| {
430- if c. is_whitespace ( ) || c == '_' || c == '-' {
431- capitalize_next = true ;
432- c
433- } else if capitalize_next {
434- capitalize_next = false ;
435- c. to_uppercase ( ) . next ( ) . unwrap_or ( c)
436- } else {
437- c. to_lowercase ( ) . next ( ) . unwrap_or ( c)
438- }
439- } )
440- . collect ( )
446+ string. chars ( ) . fold ( String :: with_capacity ( string. len ( ) ) , |mut result, c| {
447+ if c. is_whitespace ( ) || c == '_' || c == '-' {
448+ capitalize_next = true ;
449+ result. push ( c) ;
450+ } else if capitalize_next {
451+ capitalize_next = false ;
452+ result. extend ( c. to_uppercase ( ) ) ;
453+ } else {
454+ result. extend ( c. to_lowercase ( ) ) ;
455+ }
456+ result
457+ } )
441458 }
442459 }
443460 }
@@ -466,11 +483,7 @@ fn string_split(
466483 #[ default( true ) ]
467484 delimeter_escaping : bool ,
468485) -> Vec < String > {
469- let delimeter = if delimeter_escaping {
470- delimeter. replace ( "\\ n" , "\n " ) . replace ( "\\ r" , "\r " ) . replace ( "\\ t" , "\t " ) . replace ( "\\ 0" , "\0 " ) . replace ( "\\ \\ " , "\\ " )
471- } else {
472- delimeter
473- } ;
486+ let delimeter = if delimeter_escaping { unescape ( delimeter) } else { delimeter } ;
474487
475488 string. split ( & delimeter) . map ( str:: to_string) . collect ( )
476489}
@@ -490,11 +503,7 @@ fn string_join(
490503 #[ default( true ) ]
491504 separator_escaping : bool ,
492505) -> String {
493- let separator = if separator_escaping {
494- separator. replace ( "\\ n" , "\n " ) . replace ( "\\ r" , "\r " ) . replace ( "\\ t" , "\t " ) . replace ( "\\ 0" , "\0 " ) . replace ( "\\ \\ " , "\\ " )
495- } else {
496- separator
497- } ;
506+ let separator = if separator_escaping { unescape ( separator) } else { separator } ;
498507
499508 strings. join ( & separator)
500509}
0 commit comments