@@ -9,9 +9,9 @@ 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.
12+ /// Converts escape sequence representations ( `\n`, `\r`, `\t`, `\0`, `\\`) into their corresponding control characters.
1313/// Unrecognized escape sequences (e.g. `\x`) are preserved as-is.
14- fn unescape ( input : String ) -> String {
14+ fn unescape_string ( input : String ) -> String {
1515 let mut result = String :: with_capacity ( input. len ( ) ) ;
1616 let mut chars = input. chars ( ) ;
1717
@@ -34,6 +34,24 @@ fn unescape(input: String) -> String {
3434 result
3535}
3636
37+ /// Converts control characters (newline, carriage return, tab, null, backslash) back into their escape sequence representations.
38+ fn escape_string ( input : String ) -> String {
39+ let mut result = String :: with_capacity ( input. len ( ) ) ;
40+
41+ for c in input. chars ( ) {
42+ match c {
43+ '\n' => result. push_str ( "\\ n" ) ,
44+ '\r' => result. push_str ( "\\ r" ) ,
45+ '\t' => result. push_str ( "\\ t" ) ,
46+ '\0' => result. push_str ( "\\ 0" ) ,
47+ '\\' => result. push_str ( "\\ \\ " ) ,
48+ other => result. push ( other) ,
49+ }
50+ }
51+
52+ result
53+ }
54+
3755#[ derive( Debug , Clone , Copy , Default , PartialEq , Eq , Hash , dyn_any:: DynAny , node_macro:: ChoiceType , serde:: Serialize , serde:: Deserialize ) ]
3856#[ widget( Dropdown ) ]
3957pub enum StringCapitalization {
@@ -236,6 +254,22 @@ fn string_trim(_: impl Ctx, string: String, #[default(true)] start: bool, #[defa
236254 }
237255}
238256
257+ /// Converts between literal escape sequences and their corresponding control characters within a string.
258+ ///
259+ /// Unescape: `\n` (newline), `\r` (carriage return), `\t` (tab), `\0` (null), and `\\` (backslash) are converted into the actual characters.
260+ /// Escape: the actual special characters are converted back into their escape sequence representations.
261+ #[ node_macro:: node( category( "Text" ) ) ]
262+ fn string_escape (
263+ _: impl Ctx ,
264+ /// The string that contains either literal escape sequences or control characters to be converted to the opposite representation.
265+ string : String ,
266+ /// Convert the control characters back into their escape sequence representations.
267+ #[ default( true ) ]
268+ unescape : bool ,
269+ ) -> String {
270+ if unescape { unescape_string ( string) } else { escape_string ( string) }
271+ }
272+
239273/// Reverses the order of grapheme clusters (visual characters) in the string.
240274#[ node_macro:: node( category( "Text" ) ) ]
241275fn string_reverse ( _: impl Ctx , string : String ) -> String {
@@ -259,7 +293,7 @@ fn string_repeat(
259293 #[ default( true ) ]
260294 separator_escaping : bool ,
261295) -> String {
262- let separator = if separator_escaping { unescape ( separator) } else { separator } ;
296+ let separator = if separator_escaping { unescape_string ( separator) } else { separator } ;
263297
264298 let count = count. max ( 1 ) as usize ;
265299
@@ -483,7 +517,7 @@ fn string_split(
483517 #[ default( true ) ]
484518 delimeter_escaping : bool ,
485519) -> Vec < String > {
486- let delimeter = if delimeter_escaping { unescape ( delimeter) } else { delimeter } ;
520+ let delimeter = if delimeter_escaping { unescape_string ( delimeter) } else { delimeter } ;
487521
488522 string. split ( & delimeter) . map ( str:: to_string) . collect ( )
489523}
@@ -503,7 +537,7 @@ fn string_join(
503537 #[ default( true ) ]
504538 separator_escaping : bool ,
505539) -> String {
506- let separator = if separator_escaping { unescape ( separator) } else { separator } ;
540+ let separator = if separator_escaping { unescape_string ( separator) } else { separator } ;
507541
508542 strings. join ( & separator)
509543}
0 commit comments