diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 47584dea959d..ef0cdc8bee1e 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -1596,6 +1596,11 @@
The GDScript syntax highlighter text color for annotations (e.g. [code]@export[/code]).
+
+ The list of colors to use for bracket pair colorization.
+ The color for a bracket pair is determined by its nesting level. The first color in the array is used for the outermost level, the second for the first nested level, and so on. If the nesting level exceeds the number of colors in the array, the colors will cycle through from the beginning.
+ An empty array disables this feature.
+
The GDScript syntax highlighter text color for function definitions (e.g. the [code]_ready[/code] in [code]func _ready():[/code]).
diff --git a/editor/settings/editor_settings.cpp b/editor/settings/editor_settings.cpp
index 3f78ac9c520e..25c563e967cb 100644
--- a/editor/settings/editor_settings.cpp
+++ b/editor/settings/editor_settings.cpp
@@ -748,6 +748,14 @@ void EditorSettings::_load_defaults(Ref p_extra_config) {
_initial_set("text_editor/theme/highlighting/comment_markers/warning_list", "BUG,DEPRECATED,FIXME,HACK,TASK,TBD,TODO,WARNING");
_initial_set("text_editor/theme/highlighting/comment_markers/notice_list", "INFO,NOTE,NOTICE,TEST,TESTING");
+ PackedColorArray bracket_pair_colors_defaults;
+ bracket_pair_colors_defaults.push_back(Color(0.627, 0.741, 0.937));
+ bracket_pair_colors_defaults.push_back(Color(0.396, 0.549, 0.953));
+ bracket_pair_colors_defaults.push_back(Color(0.788, 0.835, 0));
+ bracket_pair_colors_defaults.push_back(Color(0.729, 0.518, 0.898));
+
+ EDITOR_SETTING_BASIC(Variant::PACKED_COLOR_ARRAY, PROPERTY_HINT_NONE, "text_editor/theme/highlighting/gdscript/bracket_pair_colors", bracket_pair_colors_defaults, "")
+
// Appearance
EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "text_editor/appearance/enable_inline_color_picker", true, "");
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index ec5a23033399..a1f862c6a5ad 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -76,6 +76,10 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
int in_declaration_param_dicts = 0; // The number of opened `{` inside func params.
int in_type_params = 0; // The number of opened `[` after type name.
+ int square_bracket_level = 0; // for ()
+ int curly_brace_level = 0; // for {}
+ int paren_level = 0; // for []
+
Color keyword_color;
Color color;
@@ -93,6 +97,24 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
get_line_syntax_highlighting(p_line - 1);
}
in_region = color_region_cache[p_line - 1];
+
+ if (bracket_pair_colors.size() > 0) {
+ if (!bracket_level_cache.has(p_line - 1)) {
+ int prev_line = p_line - 1;
+ while (prev_line > 0 && !bracket_level_cache.has(prev_line)) {
+ prev_line--;
+ }
+
+ for (int i = prev_line; i < p_line; i++) {
+ get_line_syntax_highlighting(i);
+ }
+ }
+
+ Vector prev_levels = bracket_level_cache[p_line - 1];
+ paren_level = prev_levels[0];
+ square_bracket_level = prev_levels[1];
+ curly_brace_level = prev_levels[2];
+ }
}
const String &str = text_edit->get_line_with_ime(p_line);
@@ -655,6 +677,51 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
next_type = IDENTIFIER;
}
+ // Bracket pair colorization
+ if (bracket_pair_colors.size() > 0) {
+ bool is_bracket = false;
+ Color bracket_color;
+
+ switch (str[j]) {
+ case '(': {
+ bracket_color = bracket_pair_colors[paren_level % bracket_pair_colors.size()];
+ paren_level++;
+ is_bracket = true;
+ } break;
+ case ')': {
+ paren_level = MAX(0, paren_level - 1);
+ bracket_color = bracket_pair_colors[paren_level % bracket_pair_colors.size()];
+ is_bracket = true;
+ } break;
+
+ case '[': {
+ bracket_color = bracket_pair_colors[square_bracket_level % bracket_pair_colors.size()];
+ square_bracket_level++;
+ is_bracket = true;
+ } break;
+ case ']': {
+ square_bracket_level = MAX(0, square_bracket_level - 1);
+ bracket_color = bracket_pair_colors[square_bracket_level % bracket_pair_colors.size()];
+ is_bracket = true;
+ } break;
+
+ case '{': {
+ bracket_color = bracket_pair_colors[curly_brace_level % bracket_pair_colors.size()];
+ curly_brace_level++;
+ is_bracket = true;
+ } break;
+ case '}': {
+ curly_brace_level = MAX(0, curly_brace_level - 1);
+ bracket_color = bracket_pair_colors[curly_brace_level % bracket_pair_colors.size()];
+ is_bracket = true;
+ } break;
+ }
+
+ if (is_bracket) {
+ color = bracket_color;
+ }
+ }
+
if (next_type != current_type) {
if (current_type == NONE) {
current_type = next_type;
@@ -688,6 +755,13 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
color_map[j] = highlighter_info;
}
}
+
+ Vector final_levels;
+ final_levels.push_back(paren_level);
+ final_levels.push_back(square_bracket_level);
+ final_levels.push_back(curly_brace_level);
+ bracket_level_cache[p_line] = final_levels;
+
return color_map;
}
@@ -910,6 +984,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
annotation_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/annotation_color");
string_name_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/string_name_color");
type_color = EDITOR_GET("text_editor/theme/highlighting/base_type_color");
+ bracket_pair_colors = EDITOR_GET("text_editor/theme/highlighting/gdscript/bracket_pair_colors");
comment_marker_colors[COMMENT_MARKER_CRITICAL] = EDITOR_GET("text_editor/theme/highlighting/comment_markers/critical_color");
comment_marker_colors[COMMENT_MARKER_WARNING] = EDITOR_GET("text_editor/theme/highlighting/comment_markers/warning_color");
comment_marker_colors[COMMENT_MARKER_NOTICE] = EDITOR_GET("text_editor/theme/highlighting/comment_markers/notice_color");
@@ -960,6 +1035,10 @@ void GDScriptSyntaxHighlighter::add_color_region(ColorRegion::Type p_type, const
clear_highlighting_cache();
}
+void GDScriptSyntaxHighlighter::_clear_highlighting_cache() {
+ bracket_level_cache.clear();
+}
+
Ref GDScriptSyntaxHighlighter::_create() const {
Ref syntax_highlighter;
syntax_highlighter.instantiate();
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index 263c2a023777..389772715b38 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -95,6 +95,8 @@ class GDScriptSyntaxHighlighter : public EditorSyntaxHighlighter {
Color string_name_color;
Color type_color;
+ PackedColorArray bracket_pair_colors;
+
enum CommentMarkerLevel {
COMMENT_MARKER_CRITICAL,
COMMENT_MARKER_WARNING,
@@ -104,8 +106,14 @@ class GDScriptSyntaxHighlighter : public EditorSyntaxHighlighter {
Color comment_marker_colors[COMMENT_MARKER_MAX];
HashMap comment_markers;
+ // Index 0: paren_level, Index 1: square_bracket_level, Index 2: curly_brace_level
+ HashMap> bracket_level_cache;
+
void add_color_region(ColorRegion::Type p_type, const String &p_start_key, const String &p_end_key, const Color &p_color, bool p_line_only = false, bool p_r_prefix = false);
+protected:
+ virtual void _clear_highlighting_cache() override;
+
public:
virtual void _update_cache() override;
virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override;