ronantakizawa/codereview-bench huggingface dataset:
Repository: godotengine/godot
File: core/string/ustring.cpp (C++)

Code before:

char32_t String::unicode_at(int p_idx) const {
	ERR_FAIL_INDEX_V(p_idx, length(), 0);
	return operator[](p_idx);
}

bool String::has_extension(const char *p_ext) const {
	const int extlen = strlen(p_ext);
	if (extlen >= length()) {
		return false;
	}

	const char32_t *this_str = get_data() + length() - extlen - 1;
	if (*this_str != '.') {
		return false;
	}

	this_str++;
	while (true) {
		if (*p_ext == 0 && *this_str == 0) {
			return true;
		} else if (*this_str == 0 || *p_ext == 0) {
			return false;
		} else if (_find_upper(*this_str) < _find_upper(*p_ext)) {
			return false;
		} else if (_find_upper(*this_str) > _find_upper(*p_ext)) {
			return false;
		}
		this_str++;
		p_ext++;
	}
	return false;
}

bool String::has_extension(const String &p_ext) const {
	if (p_ext.length() >= length()) {
		return false;
	}

	const char32_t *this_str = get_data() + length() - p_ext.length() - 1;
	if (*this_str != '.') {
		return false;
	}

	this_str++;
	const char32_t *that_str = p_ext.get_data();
	while (true) {
		if (*that_str == 0 && *this_str == 0) {
			return true;
		} else if (*this_str == 0 || that_str == 0) {
			return false;

Review comment (suggestion):
Aren't these two branches the same as `_find_upper(*this_str) != _find_upper(*p_ext)`?

Same in the other overload.

Code after:

char32_t String::unicode_at(int p_idx) const {
	ERR_FAIL_INDEX_V(p_idx, length(), 0);
	return operator[](p_idx);
}

String String::indent(const String &p_prefix) const {
	String new_string;
	int line_start = 0;

	for (int i = 0; i < length(); i++) {
		const char32_t c = operator[](i);
		if (c == '\n') {
			if (i == line_start) {
				new_string += c; // Leave empty lines empty.
			} else {
				new_string += p_prefix + substr(line_start, i - line_start + 1);
			}
			line_start = i + 1;
		}
	}
	if (line_start != length()) {
		new_string += p_prefix + substr(line_start);
	}
	return new_string;
}

String String::dedent() const {
	String new_string;
	String indent;
	bool has_indent = false;
	bool has_text = false;
	int line_start = 0;
	int indent_stop = -1;

	for (int i = 0; i < length(); i++) {
		char32_t c = operator[](i);
		if (c == '\n') {
			if (has_text) {
				new_string += substr(indent_stop, i - indent_stop);
			}
			new_string += "\n";
			has_text = false;
			line_start = i + 1;
			indent_stop = -1;
		} else if (!has_text) {
			if (c > 32) {
				has_text = true;
				if (!has_indent) {
					has_indent = true;
					indent = substr(line_start, i - line_start);
Repository: godotengine/godot
File: editor/inspector/multi_node_edit.cpp (C++)

Code before:
	List<PLData *> data_list;

	for (const NodePath &E : nodes) {
		Node *n = es->get_node_or_null(E);
		if (!n) {
			continue;
		}

		List<PropertyInfo> plist;
		n->get_property_list(&plist, true);

		for (PropertyInfo F : plist) {
			if (F.name == "script") {
				continue; // Added later manually, since this is intercepted before being set (check Variant Object::get()).
			} else if (F.name.begins_with("metadata/")) {
				F.name = F.name.replace_first("metadata/", "Metadata/"); // Trick to not get actual metadata edited from MultiNodeEdit.
			}

			PLData *usage_data = usage.getptr(F.name);
			if (!usage_data) {
				PLData pld;
				pld.uses = 0;
				pld.info = F;
				pld.info.name = F.name;
				usage[F.name] = pld;
				usage_data = usage.getptr(F.name);
				data_list.push_back(usage_data);
			}

			// Make sure only properties with the same exact PropertyInfo data will appear.
			if (usage_data->info == F) {
				usage_data->uses++;
			}
		}

		nc++;
	}

	for (const PLData *E : data_list) {
		if (nc == E->uses) {
			p_list->push_back(E->info);
		}
	}

	p_list->push_back(PropertyInfo(Variant::OBJECT, "scripts", PROPERTY_HINT_RESOURCE_TYPE, "Script"));
}

String MultiNodeEdit::_get_editor_name() const {
	return vformat(TTR("%s (%d Selected)"), get_edited_class_name(), get_node_count());
}


Review comment (suggestion):
You can replace it with
```suggestion
				HashMap<String, MultiNodeEdit::PLData>::Iterator I = usage.insert(F.name, pld);
				usage_data = &I->value;
```
although not sure if getting the pointer is safe here.

Code after:
	List<PLData *> data_list;

	for (const NodePath &E : nodes) {
		Node *n = es->get_node_or_null(E);
		if (!n) {
			continue;
		}

		List<PropertyInfo> plist;
		n->get_property_list(&plist, true);

		for (PropertyInfo F : plist) {
			if (F.name == "script") {
				continue; // Added later manually, since this is intercepted before being set (check Variant Object::get()).
			} else if (F.name.begins_with("metadata/")) {
				F.name = F.name.replace_first("metadata/", "Metadata/"); // Trick to not get actual metadata edited from MultiNodeEdit.
			}

			PLData *usage_data = usage.getptr(F.name);
			if (!usage_data) {
				PLData pld;
				pld.uses = 0;
				pld.info = F;
				pld.info.name = F.name;
				HashMap<String, MultiNodeEdit::PLData>::Iterator I = usage.insert(F.name, pld);
				usage_data = &I->value;
				data_list.push_back(usage_data);
			}

			// Make sure only properties with the same exact PropertyInfo data will appear.
			if (usage_data->info == F) {
				usage_data->uses++;
			}
		}

		nc++;
	}

	for (const PLData *E : data_list) {
		if (nc == E->uses) {
			p_list->push_back(E->info);
		}
	}

	p_list->push_back(PropertyInfo(Variant::OBJECT, "scripts", PROPERTY_HINT_RESOURCE_TYPE, "Script"));
}

String MultiNodeEdit::_get_editor_name() const {
	return vformat(TTR("%s (%d Selected)"), get_edited_class_name(), get_node_count());
}
Repository: godotengine/godot
File: editor/scene/2d/particles_2d_editor_plugin.cpp (C++)

Code before:
	for (Node *node : current_selection) {
		nodes_in_current_selection.insert(node);
		if (!selected_particles.has(node)) {
			_set_show_gizmos(node, true);
			selected_particles.insert(node);
		}
	}

	// Turn gizmos off for nodes that are no longer selected.
	LocalVector<Node *> to_erase;
	for (Node *node : selected_particles) {
		if (!nodes_in_current_selection.has(node)) {
			_set_show_gizmos(node, false);
			to_erase.push_back(node);
		}
	}

	for (Node *node : to_erase) {
		selected_particles.erase(node);
	}
}

void Particles2DEditorPlugin::_node_removed(Node *p_node) {
	if (selected_particles.has(p_node)) {
		_set_show_gizmos(p_node, false);
		selected_particles.erase(p_node);
	}
}

void GPUParticles2DEditorPlugin::_generate_visibility_rect() {
	GPUParticles2D *particles = Object::cast_to<GPUParticles2D>(edited_node);

	double time = generate_seconds->get_value();

	float running = 0.0;

	EditorProgress ep("gen_vrect", TTR("Generating Visibility Rect (Waiting for Particle Simulation)"), int(time));

	bool was_emitting = particles->is_emitting();
	if (!was_emitting) {
		particles->set_emitting(true);
		OS::get_singleton()->delay_usec(1000);
	}

	Rect2 rect;
	while (running < time) {
		uint64_t ticks = OS::get_singleton()->get_ticks_usec();
		ep.step(TTR("Generating..."), int(running), true);
		OS::get_singleton()->delay_usec(1000);

		Rect2 capture = particles->capture_rect();

Review comment (suggestion):
You can do
```suggestion
	if (selected_particles.erase(p_node)) {
		_set_show_gizmos(p_node, false);
```

Code after:
	for (Node *node : current_selection) {
		nodes_in_current_selection.insert(node);
		if (!selected_particles.has(node)) {
			_set_show_gizmos(node, true);
			selected_particles.insert(node);
		}
	}

	// Turn gizmos off for nodes that are no longer selected.
	LocalVector<Node *> to_erase;
	for (Node *node : selected_particles) {
		if (!nodes_in_current_selection.has(node)) {
			_set_show_gizmos(node, false);
			to_erase.push_back(node);
		}
	}

	for (Node *node : to_erase) {
		selected_particles.erase(node);
	}
}

void Particles2DEditorPlugin::_node_removed(Node *p_node) {
	if (selected_particles.erase(p_node)) {
		_set_show_gizmos(p_node, false);
	}
}

void GPUParticles2DEditorPlugin::_generate_visibility_rect() {
	GPUParticles2D *particles = Object::cast_to<GPUParticles2D>(edited_node);

	double time = generate_seconds->get_value();

	float running = 0.0;

	EditorProgress ep("gen_vrect", TTR("Generating Visibility Rect (Waiting for Particle Simulation)"), int(time));

	bool was_emitting = particles->is_emitting();
	if (!was_emitting) {
		particles->set_emitting(true);
		OS::get_singleton()->delay_usec(1000);
	}

	Rect2 rect;
	while (running < time) {
		uint64_t ticks = OS::get_singleton()->get_ticks_usec();
		ep.step(TTR("Generating..."), int(running), true);
		OS::get_singleton()->delay_usec(1000);

		Rect2 capture = particles->capture_rect();
		if (rect == Rect2()) {
Repository: godotengine/godot
File: scene/gui/text_edit.cpp (C++)

Code before:
			_update_caches();
			if (caret_pos_dirty) {
				callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred();
			}
			if (text_changed_dirty) {
				callable_mp(this, &TextEdit::_emit_text_changed).call_deferred();
			}
			_update_wrap_at_column(true);
		} break;

		case NOTIFICATION_RESIZED: {
			_update_scrollbars();
			_update_wrap_at_column();
		} break;

		case NOTIFICATION_VISIBILITY_CHANGED: {
			if (is_visible()) {
				callable_mp(this, &TextEdit::_update_scrollbars).call_deferred();
				callable_mp(this, &TextEdit::_update_wrap_at_column).call_deferred(false);
			}
		} break;

		case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
		case NOTIFICATION_THEME_CHANGED: {
			if (is_inside_tree()) {
				_update_caches();
				_update_wrap_at_column(true);
			}
		} break;
		case NOTIFICATION_TRANSLATION_CHANGED: {
			if (is_inside_tree()) {
				_update_caches(true);
				_update_wrap_at_column(true);
			}
		} break;

		case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
			window_has_focus = true;
			draw_caret = true;
			queue_redraw();
		} break;

		case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
			window_has_focus = false;
			draw_caret = false;
			queue_redraw();
		} break;

		case NOTIFICATION_INTERNAL_PROCESS: {
			if (scrolling && get_v_scroll() != target_v_scroll) {
				double target_y = target_v_scroll - get_v_scroll();

Review comment (performance):
Technically you could do
```suggestion
				_update_caches(p_what = NOTIFICATION_TRANSLATION_CHANGED);
```

Code after:
			if (caret_pos_dirty) {
				callable_mp(this, &TextEdit::_emit_caret_changed).call_deferred();
			}
			if (text_changed_dirty) {
				callable_mp(this, &TextEdit::_emit_text_changed).call_deferred();
			}
			_update_wrap_at_column(true);
		} break;

		case NOTIFICATION_RESIZED: {
			_update_scrollbars();
			_update_wrap_at_column();
		} break;

		case NOTIFICATION_VISIBILITY_CHANGED: {
			if (is_visible()) {
				callable_mp(this, &TextEdit::_update_scrollbars).call_deferred();
				callable_mp(this, &TextEdit::_update_wrap_at_column).call_deferred(false);
			}
		} break;

		case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
		case NOTIFICATION_TRANSLATION_CHANGED:
		case NOTIFICATION_THEME_CHANGED: {
			if (is_inside_tree()) {
				_update_caches(p_what == NOTIFICATION_TRANSLATION_CHANGED);
				_update_wrap_at_column(true);
			}
		} break;

		case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
			window_has_focus = true;
			draw_caret = true;
			queue_redraw();
		} break;

		case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
			window_has_focus = false;
			draw_caret = false;
			queue_redraw();
		} break;

		case NOTIFICATION_INTERNAL_PROCESS: {
			if (scrolling && get_v_scroll() != target_v_scroll) {
				double target_y = target_v_scroll - get_v_scroll();
				double dist = std::abs(target_y);
				// To ensure minimap is responsive override the speed setting.
				double vel = ((target_y / dist) * ((minimap_clicked) ? 3000 : v_scroll_speed)) * get_process_delta_time();

				// Prevent small velocities from blocking scrolling.
				if (Math::abs(vel) < v_scroll->get_step()) {
Repository: godotengine/godot
File: editor/gui/editor_spin_slider.cpp (C++)

Code before:
void EditorSpinSlider::set_control_state(ControlState p_state) {
	control_state = p_state;
	queue_redraw();
}

EditorSpinSlider::ControlState EditorSpinSlider::get_control_state() const {
	return control_state;
}

#ifndef DISABLE_DEPRECATED
void EditorSpinSlider::set_hide_slider(bool p_hide) {
	set_control_state(p_hide ? CONTROL_STATE_HIDE : CONTROL_STATE_DEFAULT);
}

bool EditorSpinSlider::is_hiding_slider() const {
	return control_state == CONTROL_STATE_HIDE;
}
#endif

void EditorSpinSlider::set_editing_integer(bool p_editing_integer) {
	if (p_editing_integer == editing_integer) {
		return;
	}

	editing_integer = p_editing_integer;
	grabbing_spinner_speed = editing_integer ? EDITOR_GET("interface/inspector/integer_drag_speed") : EDITOR_GET("interface/inspector/float_drag_speed");
	queue_redraw();
}

bool EditorSpinSlider::is_editing_integer() const {
	return editing_integer;
}

void EditorSpinSlider::set_label(const String &p_label) {
	label = p_label;
	queue_redraw();
}

String EditorSpinSlider::get_label() const {
	return label;
}

void EditorSpinSlider::set_suffix(const String &p_suffix) {
	suffix = p_suffix;
	queue_redraw();
}

String EditorSpinSlider::get_suffix() const {
	return suffix;
}


Review comment (suggestion):
You could add a check for `is_inside_tree()`, as this will be updated anyway in `NOTIFICATION_ENTER_TREE`.

Code after:
void EditorSpinSlider::set_control_state(ControlState p_state) {
	control_state = p_state;
	queue_redraw();
}

EditorSpinSlider::ControlState EditorSpinSlider::get_control_state() const {
	return control_state;
}

#ifndef DISABLE_DEPRECATED
void EditorSpinSlider::set_hide_slider(bool p_hide) {
	set_control_state(p_hide ? CONTROL_STATE_HIDE : CONTROL_STATE_DEFAULT);
}

bool EditorSpinSlider::is_hiding_slider() const {
	return control_state == CONTROL_STATE_HIDE;
}
#endif

void EditorSpinSlider::set_editing_integer(bool p_editing_integer) {
	if (p_editing_integer == editing_integer) {
		return;
	}

	editing_integer = p_editing_integer;
	if (is_inside_tree()) {
		grabbing_spinner_speed = editing_integer ? EDITOR_GET("interface/inspector/integer_drag_speed") : EDITOR_GET("interface/inspector/float_drag_speed");
		queue_redraw();
	}
}

bool EditorSpinSlider::is_editing_integer() const {
	return editing_integer;
}

void EditorSpinSlider::set_label(const String &p_label) {
	label = p_label;
	queue_redraw();
}

String EditorSpinSlider::get_label() const {
	return label;
}

void EditorSpinSlider::set_suffix(const String &p_suffix) {
	suffix = p_suffix;
	queue_redraw();
}

String EditorSpinSlider::get_suffix() const {
	return suffix;
Repository: godotengine/godot
File: scene/debugger/scene_debugger.cpp (C++)

Code before:
	}

	HashMap<String, HashSet<Node *>>::Iterator E = live_scene_edit_cache.find(live_edit_scene);
	if (!E) {
		return; //scene not editable
	}

	for (Node *F : E->value) {
		Node *n = F;

		if (base && !base->is_ancestor_of(n)) {
			continue;
		}

		if (!n->has_node(np)) {
			continue;
		}
		Node *n2 = n->get_node(np);

		// Do not change transform of edited scene root, unless it's the scene being played.
		// See GH-86659 for additional context.
		bool keep_transform = (n2 == n) && (n2->get_parent() != scene_tree->root);
		Variant orig_tf;

		if (keep_transform) {
			if (n2->is_class("Node3D")) {
				orig_tf = n2->call("get_transform");
			} else if (n2->is_class("CanvasItem")) {
				orig_tf = n2->call("_edit_get_state");
			}
		}

		n2->set(p_prop, p_value);

		if (keep_transform) {
			if (n2->is_class("Node3D")) {
				Variant new_tf = n2->call("get_transform");
				if (new_tf != orig_tf) {
					n2->call("set_transform", orig_tf);
				}
			} else if (n2->is_class("CanvasItem")) {
				Variant new_tf = n2->call("_edit_get_state");
				if (new_tf != orig_tf) {
					n2->call("_edit_set_state", orig_tf);
				}
			}
		}
	}
}

void LiveEditor::_node_set_res_func(int p_id, const StringName &p_prop, const String &p_value) {

Review comment (suggestion):
This, and probably many other cases, breaks 2D only builds, will make a report, but I think we should just roll this back and rework it as it's a serious breakage

Will test enclosing these cases in `_3D_DISABLED` and see that should fix it, but it makes it clear that this kind of change is a bit unstable

Some specific cases might still break in certain configurations if the relevant classes aren't available though

Code after:
	}

	HashMap<String, HashSet<Node *>>::Iterator E = live_scene_edit_cache.find(live_edit_scene);
	if (!E) {
		return; //scene not editable
	}

	for (Node *F : E->value) {
		Node *n = F;

		if (base && !base->is_ancestor_of(n)) {
			continue;
		}

		if (!n->has_node(np)) {
			continue;
		}
		Node *n2 = n->get_node(np);

		// Do not change transform of edited scene root, unless it's the scene being played.
		// See GH-86659 for additional context.
		bool keep_transform = (n2 == n) && (n2->get_parent() != scene_tree->root);
		Variant orig_tf;

		if (keep_transform) {
			if (n2->derives_from<Node3D>()) {
				orig_tf = n2->call("get_transform");
			} else if (n2->derives_from<CanvasItem>()) {
				orig_tf = n2->call("_edit_get_state");
			}
		}

		n2->set(p_prop, p_value);

		if (keep_transform) {
			if (n2->derives_from<Node3D>()) {
				Variant new_tf = n2->call("get_transform");
				if (new_tf != orig_tf) {
					n2->call("set_transform", orig_tf);
				}
			} else if (n2->derives_from<CanvasItem>()) {
				Variant new_tf = n2->call("_edit_get_state");
				if (new_tf != orig_tf) {
					n2->call("_edit_set_state", orig_tf);
				}
			}
		}
	}
}

void LiveEditor::_node_set_res_func(int p_id, const StringName &p_prop, const String &p_value) {
Repository: godotengine/godot
File: scene/gui/tree.cpp (C++)

Code before:
}

void Tree::set_hide_folding(bool p_hide) {
	if (hide_folding == p_hide) {
		return;
	}

	hide_folding = p_hide;
	queue_redraw();
}

bool Tree::is_folding_hidden() const {
	return hide_folding;
}

void Tree::set_enable_recursive_folding(bool p_enable) {
	enable_recursive_folding = p_enable;
}

bool Tree::is_recursive_folding_enabled() const {
	return enable_recursive_folding;
}

void Tree::set_enable_drag_unfolding(bool p_enable) {
	enable_drag_unfolding = p_enable;
	if (!dropping_unfold_timer->is_stopped()) {
		dropping_unfold_timer->stop();
	}
}

bool Tree::is_drag_unfolding_enabled() const {
	return enable_drag_unfolding;
}

void Tree::set_drop_mode_flags(int p_flags) {
	if (drop_mode_flags == p_flags) {
		return;
	}
	drop_mode_flags = p_flags;
	if (drop_mode_flags == 0) {
		_reset_drop_mode_over();
	}

	queue_redraw();
}

int Tree::get_drop_mode_flags() const {
	return drop_mode_flags;
}

void Tree::set_edit_checkbox_cell_only_when_checkbox_is_pressed(bool p_enable) {

Review comment (suggestion):
```suggestion
	if (enable_drag_unfolding == p_enabled) {
		return;
	}
	enable_drag_unfolding = p_enable;
	if (!enable_drag_unfolding  && !dropping_unfold_timer->is_stopped()) {
```

Code after:
void Tree::set_hide_folding(bool p_hide) {
	if (hide_folding == p_hide) {
		return;
	}

	hide_folding = p_hide;
	queue_redraw();
}

bool Tree::is_folding_hidden() const {
	return hide_folding;
}

void Tree::set_enable_recursive_folding(bool p_enable) {
	enable_recursive_folding = p_enable;
}

bool Tree::is_recursive_folding_enabled() const {
	return enable_recursive_folding;
}

void Tree::set_enable_drag_unfolding(bool p_enable) {
	if (enable_drag_unfolding == p_enable) {
		return;
	}

	enable_drag_unfolding = p_enable;
	if (!enable_drag_unfolding && !dropping_unfold_timer->is_stopped()) {
		dropping_unfold_timer->stop();
	}
}

bool Tree::is_drag_unfolding_enabled() const {
	return enable_drag_unfolding;
}

void Tree::set_drop_mode_flags(int p_flags) {
	if (drop_mode_flags == p_flags) {
		return;
	}
	drop_mode_flags = p_flags;
	if (drop_mode_flags == 0) {
		_reset_drop_mode_over();
	}

	queue_redraw();
}

int Tree::get_drop_mode_flags() const {
	return drop_mode_flags;
}
Repository: godotengine/godot
File: editor/editor_log.cpp (C++)

Code before:

		if (collapse) {
			// If collapsing, only log one instance of the message.
			_add_log_line(msg);
		} else {
			// If not collapsing, log each instance on a line.
			for (int i = initial_skip; i < msg.count; i++) {
				initial_skip = 0;
				_add_log_line(msg);
			}
		}
	}
}

bool EditorLog::_check_display_message(LogMessage &p_message) {
	bool filter_active = type_filter_map[p_message.type]->is_active();
	String search_text = search_box->get_text();

	if (search_text.is_empty()) {
		return filter_active;
	}

	bool search_match = p_message.text.containsn(search_text);

	// If not found and message contains BBCode tags, also check the parsed text
	if (!search_match && p_message.text.find_char('[') != -1) {
		// Lazy initialize the BBCode parser
		if (!bbcode_parser) {
			bbcode_parser = memnew(RichTextLabel);
			bbcode_parser->set_use_bbcode(true);
		}

		// Ensure clean state for each message
		bbcode_parser->clear();
		bbcode_parser->parse_bbcode(p_message.text);
		String parsed_text = bbcode_parser->get_parsed_text();
		search_match = parsed_text.containsn(search_text);
	}

	return filter_active && search_match;
}

void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
	if (!is_inside_tree()) {
		// The log will be built all at once when it enters the tree and has its theme items.
		return;
	}

	if (unlikely(log->is_updating())) {
		// The new message arrived during log RTL text processing/redraw (invalid BiDi control characters / font error), ignore it to avoid RTL data corruption.
		return;

Review comment (suggestion):
```suggestion
	if (!search_match && p_message.text.contains_char('[')) {
```

Code after:
			}
		} else {
			// If not collapsing, log each instance on a line.
			for (int i = 0; i < msg.count; i++) {
				if (_check_display_message(msg)) {
					line_count++;
				}
			}
		}
		if (line_count >= line_limit) {
			initial_skip = line_count - line_limit;
			break;
		}
		if (start_message_index == 0) {
			break;
		}
	}

	for (int msg_idx = start_message_index; msg_idx < messages.size(); msg_idx++) {
		LogMessage msg = messages[msg_idx];

		if (collapse) {
			// If collapsing, only log one instance of the message.
			_add_log_line(msg);
		} else {
			// If not collapsing, log each instance on a line.
			for (int i = initial_skip; i < msg.count; i++) {
				initial_skip = 0;
				_add_log_line(msg);
			}
		}
	}
}

bool EditorLog::_check_display_message(LogMessage &p_message) {
	bool filter_active = type_filter_map[p_message.type]->is_active();
	String search_text = search_box->get_text();

	if (search_text.is_empty()) {
		return filter_active;
	}

	bool search_match = p_message.text.containsn(search_text);

	// If not found and message contains BBCode tags, also check the parsed text
	if (!search_match && p_message.text.contains_char('[')) {
		// Lazy initialize the BBCode parser
		if (!bbcode_parser) {
			bbcode_parser = memnew(RichTextLabel);
			bbcode_parser->set_use_bbcode(true);
		}