@@ -244,18 +244,66 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
244244 int region_end_index = -1 ;
245245 int end_key_length = color_regions[in_region].end_key .length ();
246246 const char32_t *end_key = color_regions[in_region].end_key .get_data ();
247+ int placeholder_end = from;
247248 for (; from < line_length; from++) {
248249 if (line_length - from < end_key_length) {
249- // Don't break if '\' to highlight esc chars.
250- if (str.find_char (' \\ ' , from) < 0 ) {
250+ // Don't break if '\' to highlight escape sequences,
251+ // and '%' and '{' to highlight placeholders.
252+ if (str.find_char (' \\ ' , from) == -1 && str.find_char (' %' , from) == -1 && str.find_char (' {' , from) == -1 ) {
251253 break ;
252254 }
253255 }
254256
255- if (!is_symbol (str[from])) {
257+ if (!is_symbol (str[from]) && str[from] != ' % ' ) {
256258 continue ;
257259 }
258260
261+ if (str[from] == ' %' || str[from] == ' {' ) {
262+ int placeholder_start = from;
263+ bool is_percent = str[from] == ' %' ;
264+
265+ from++;
266+
267+ if (is_percent) {
268+ if (str[from] == ' %' ) {
269+ placeholder_end = from + 1 ;
270+ } else {
271+ const String allowed_chars = " +.-*0123456789" ;
272+ const String placeholder_types = " cdfosvxX" ;
273+ for (int i = 0 ; i < line_length - from; i++) {
274+ if (allowed_chars.contains_char (str[from + i]) &&
275+ !placeholder_types.contains_char (str[from + i]) &&
276+ (str[from + i] != end_key[0 ] || (str[from + i] == end_key[0 ] && str[from + i - 1 ] == ' \\ ' ))) {
277+ continue ;
278+ }
279+ if (placeholder_types.contains_char (str[from + i])) {
280+ placeholder_end = from + i + 1 ;
281+ }
282+ break ;
283+ }
284+ }
285+ } else {
286+ for (int i = 0 ; i < line_length - from; i++) {
287+ if (str[from + i] != ' }' && (str[from + i] != end_key[0 ] || (str[from + i] == end_key[0 ] && str[from + i - 1 ] == ' \\ ' ))) {
288+ continue ;
289+ }
290+ if (str[from + i] == ' }' ) {
291+ placeholder_end = from + i + 1 ;
292+ }
293+ break ;
294+ }
295+ }
296+
297+ if (placeholder_end > placeholder_start) {
298+ Dictionary placeholder_highlighter_info;
299+ placeholder_highlighter_info[" color" ] = placeholder_color;
300+ color_map[placeholder_start] = placeholder_highlighter_info;
301+ Dictionary region_continue_highlighter_info;
302+ region_continue_highlighter_info[" color" ] = region_color;
303+ color_map[placeholder_end] = region_continue_highlighter_info;
304+ }
305+ }
306+
259307 if (str[from] == ' \\ ' ) {
260308 if (!color_regions[in_region].r_prefix ) {
261309 Dictionary escape_char_highlighter_info;
@@ -280,7 +328,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
280328 }
281329
282330 Dictionary region_continue_highlighter_info;
283- region_continue_highlighter_info[" color" ] = region_color;
331+ region_continue_highlighter_info[" color" ] = from < placeholder_end ? placeholder_color : region_color;
284332 color_map[from + 1 ] = region_continue_highlighter_info;
285333 }
286334
@@ -315,6 +363,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
315363 prev_is_binary_op = false ;
316364 continue ;
317365 }
366+ color_map.sort (); // Prevents e.g. escape sequences from being overridden by string placeholders.
318367 }
319368 }
320369
@@ -813,6 +862,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
813862
814863 /* Strings */
815864 string_color = EDITOR_GET (" text_editor/theme/highlighting/string_color" );
865+ placeholder_color = EDITOR_GET (" text_editor/theme/highlighting/string_placeholder_color" );
816866 add_color_region (ColorRegion::TYPE_STRING, " \" " , " \" " , string_color);
817867 add_color_region (ColorRegion::TYPE_STRING, " '" , " '" , string_color);
818868 add_color_region (ColorRegion::TYPE_MULTILINE_STRING, " \"\"\" " , " \"\"\" " , string_color);
0 commit comments