Repository: godotengine/godot
File: editor/scene/scene_tree_editor.cpp (C++)

Code before:
	if (is_root) {
		tree->set_hide_root(hide_filtered_out_parents && !selectable);
		if (tree->is_root_hidden()) {
			p_parent->set_collapsed(false);
		}
	}

	if (editor_selection) {
		Node *n = get_node(p_parent->get_metadata(0));
		if (selectable) {
			if (p_scroll_to_selected && n && editor_selection->is_selected(n)) {
				// Needs to be deferred to account for possible root visibility change.
				callable_mp(tree, &Tree::scroll_to_item).call_deferred(p_parent, false);
			}
		} else if (n) {
			editor_selection->remove_node(n);
			p_parent->deselect(0);
		}
	}

	return p_parent->is_visible();
}

bool SceneTreeEditor::_node_matches_class_term(const Node *p_item_node, const String &p_term) {
	if (p_term.is_empty()) {
		// Defend against https://github.com/godotengine/godot/issues/82473
		return true;
	}
	Ref<Script> item_script = p_item_node->get_script();
	while (item_script.is_valid()) {
		String global_name = item_script->get_global_name();
		if (global_name.to_lower().contains(p_term)) {
			return true;
		}
		item_script = item_script->get_base_script();
	}

	String type = p_item_node->get_class();
	// Every Node is a Node, duh!
	while (type != "Node") {
		if (type.to_lower().contains(p_term)) {
			return true;
		}

		type = ClassDB::get_parent_class(type);
	}

	return false;
}

bool SceneTreeEditor::_item_matches_all_terms(TreeItem *p_item, const PackedStringArray &p_terms) {

Review comment (bug):
Looks like this (or the one above) is called for every selected item, so the Tree will needlessly scroll to each item, eventually settling on the last one. This can be queued with something like
```C++
void _queue_scroll_to_item(TreeItem *p_item) {
	if (!queued_item) {
		callable_mp(this, &SceneTreeEditor::_scroll_to_item).call_deferred();
	}
	queued_item = p_item;
}

void _scroll_to_item() {
	tree->scroll_to_item(queued_item );
	queued_item  = nullptr;
}
```

Code after:
						I->value.has_moved_children = true;
					}
				}

				return false;
			}
		} else {
			p_parent->set_custom_color(0, get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));
			p_parent->set_selectable(0, false);
			p_parent->deselect(0);
		}
	}
	if (is_root) {
		tree->set_hide_root(hide_filtered_out_parents && !selectable);
		if (tree->is_root_hidden()) {
			p_parent->set_collapsed(false);
		}
	}

	if (editor_selection) {
		Node *n = get_node(p_parent->get_metadata(0));
		if (selectable) {
			if (n && editor_selection->is_selected(n)) {
				if (p_scroll_to_selected) {
					// Needs to be deferred to account for possible root visibility change.
					callable_mp(tree, &Tree::scroll_to_item).call_deferred(p_parent, false);
				} else {
					r_last_selected = p_parent;
				}
			}
		} else if (n) {
			editor_selection->remove_node(n);
			p_parent->deselect(0);
		}
	}

	return p_parent->is_visible();
}

bool SceneTreeEditor::_node_matches_class_term(const Node *p_item_node, const String &p_term) {
	if (p_term.is_empty()) {
		// Defend against https://github.com/godotengine/godot/issues/82473
		return true;
	}
	Ref<Script> item_script = p_item_node->get_script();
	while (item_script.is_valid()) {
		String global_name = item_script->get_global_name();
		if (global_name.to_lower().contains(p_term)) {
			return true;
		}
		item_script = item_script->get_base_script();