ronantakizawa/codereview-bench huggingface dataset:
Repository: godotengine/godot
File: editor/gui/editor_quick_open_dialog.cpp (C++)

Code before:
	if (query.is_empty()) {
		_use_default_candidates();
	} else {
		_score_and_sort_candidates();
	}

	_update_result_items(MIN(candidates.size(), max_total_results), 0);
}

void QuickOpenResultContainer::_add_history_candidates() {
	Vector<ResourceUID::ID> *history = _get_history();
	if (history) {
		for (const ResourceUID::ID &uid : *history) {
			bool success;
			QuickOpenResultCandidate candidate = QuickOpenResultCandidate::from_uid(uid, success);
			if (!success) {
				continue;
			}
			_add_candidate(candidate);
		}
	}
}

void QuickOpenResultContainer::_use_default_candidates() {
	HashSet<ResourceUID::ID> existing_uids;
	_add_history_candidates();

	for (const ResourceUID::ID &uid : uids) {
		if (candidates.size() >= max_total_results) {
			break;
		}
		if (candidates_uids.has(uid)) {
			continue;
		}

		bool success;
		QuickOpenResultCandidate candidate = QuickOpenResultCandidate::from_uid(uid, success);
		if (!success) {
			continue;
		}

		_add_candidate(candidate);
	}
}

void QuickOpenResultContainer::_update_fuzzy_search_results() {
	FuzzySearch fuzzy_search;
	fuzzy_search.start_offset = 6; // Don't match against "res://" at the start of each filepath.
	fuzzy_search.set_query(query);
	fuzzy_search.max_results = max_total_results;
	bool fuzzy_matching = EDITOR_GET("filesystem/quick_open_dialog/enable_fuzzy_matching");

Review comment (suggestion):
Any reason why `_add_history_candidates()` is a separate method? It's only called once and requires adding `candidates_uids` field to the class. As a result, `existing_uids` is unused.

Code after:
	Vector<ResourceUID::ID> *history = _get_history();
	if (history) {
		for (const ResourceUID::ID &uid : *history) {
			bool success;
			QuickOpenResultCandidate candidate = QuickOpenResultCandidate::from_uid(uid, success);
			if (!success) {
				continue;
			}
			_add_candidate(candidate);
		}
	}

	for (const ResourceUID::ID &uid : uids) {
		if (candidates.size() >= max_total_results) {
			break;
		}
		if (candidates_uids.has(uid)) {
			continue;
		}

		bool success;
		QuickOpenResultCandidate candidate = QuickOpenResultCandidate::from_uid(uid, success);
		if (!success) {
			continue;
		}

		_add_candidate(candidate);
	}
}

void QuickOpenResultContainer::_update_fuzzy_search_results() {
	FuzzySearch fuzzy_search;
	fuzzy_search.start_offset = 6; // Don't match against "res://" at the start of each filepath.
	fuzzy_search.set_query(query);
	fuzzy_search.max_results = max_total_results;
	bool fuzzy_matching = EDITOR_GET("filesystem/quick_open_dialog/enable_fuzzy_matching");
	int max_misses = EDITOR_GET("filesystem/quick_open_dialog/max_fuzzy_misses");
	fuzzy_search.allow_subsequences = fuzzy_matching;
	fuzzy_search.max_misses = fuzzy_matching ? max_misses : 0;

	PackedStringArray paths;
	paths.reserve_exact(uids.size());

	for (const ResourceUID::ID &uid : uids) {
		paths.push_back(ResourceUID::get_singleton()->get_id_path(uid));
	}

	fuzzy_search.search_all(paths, search_results);
}

void QuickOpenResultContainer::_score_and_sort_candidates() {
Repository: godotengine/godot
File: editor/gui/editor_quick_open_dialog.cpp (C++)

Code before:
			Vector<ResourceUID::ID> cleaned_ids;
			cleaned_ids.resize(history_uids.size());

			{
				String *text_write = cleaned_text_uids.ptrw();
				ResourceUID::ID *id_write = cleaned_ids.ptrw();
				int i = 0;
				for (String uid : history_uids) {
					if (!uid.begins_with("uid://")) {
						// uid might be a path here, if config was written by older editor version
						ResourceUID::ID id = EditorFileSystem::get_singleton()->get_file_uid(uid);
						if (id == ResourceUID::INVALID_ID) {
							continue;
						}
						uid = ResourceUID::get_singleton()->id_to_text(id);
					}

					ResourceUID::ID id = ResourceUID::get_singleton()->text_to_id(uid);
					if (id == ResourceUID::INVALID_ID) {
						continue;
					}

					filetypes.insert(id, type_name);

					bool success;
					QuickOpenResultCandidate candidate = QuickOpenResultCandidate::from_uid(id, success);

					if (!success) {
						continue;
					}

					text_write[i] = uid;
					id_write[i] = id;
					i++;
				}

				cleaned_text_uids.resize(i);
				selected_history.insert(type, cleaned_ids);

				if (i < history_uids.size()) {
					// Some paths removed, need to update history.
					if (i == 0) {
						history_file->erase_section_key("selected_history", type);
					} else {
						history_file->set_value("selected_history", type, cleaned_text_uids);
					}
					history_modified = true;
				}
			}
		}
		if (history_modified) {

Review comment (suggestion):
This should be done after the candidate is created, otherwise the type might be added for invalid UID.

Code after:

			Vector<ResourceUID::ID> cleaned_ids;
			cleaned_ids.resize(history_uids.size());

			{
				String *text_write = cleaned_text_uids.ptrw();
				ResourceUID::ID *id_write = cleaned_ids.ptrw();
				int i = 0;
				for (String uid : history_uids) {
#ifndef DISABLE_DEPRECATED
					if (!uid.begins_with("uid://")) {
						// uid might be a path here, if config was written by older editor version
						ResourceUID::ID id = EditorFileSystem::get_singleton()->get_file_uid(uid);
						if (id == ResourceUID::INVALID_ID) {
							continue;
						}
						uid = ResourceUID::get_singleton()->id_to_text(id);
					}
#endif

					ResourceUID::ID id = ResourceUID::get_singleton()->text_to_id(uid);
					if (id == ResourceUID::INVALID_ID || !ResourceUID::get_singleton()->has_id(id)) {
						continue;
					}

					filetypes.insert(id, type_name);
					text_write[i] = uid;
					id_write[i] = id;
					i++;
				}

				cleaned_text_uids.resize(i);
				selected_history.insert(type, cleaned_ids);

				if (i < history_uids.size()) {
					// Some paths removed, need to update history.
					if (i == 0) {
						history_file->erase_section_key("selected_history", type);
					} else {
						history_file->set_value("selected_history", type, cleaned_text_uids);
					}
					history_modified = true;
				}
			}
		}
	} else if (!first_open && base_types.size() == 1) {
		const StringName &type = base_types[0];
		Vector<ResourceUID::ID> *history = selected_history.getptr(type);

		if (history) {
			Vector<ResourceUID::ID> clean_history;
Repository: godotengine/godot
File: editor/gui/editor_quick_open_dialog.cpp (C++)

Code before:
						continue;
					}

					filetypes.insert(id, type_name);
					text_write[i] = uid;
					id_write[i] = id;
					i++;
				}

				cleaned_text_uids.resize(i);
				selected_history.insert(type, cleaned_ids);

				if (i < history_uids.size()) {
					// Some paths removed, need to update history.
					if (i == 0) {
						history_file->erase_section_key("selected_history", type);
					} else {
						history_file->set_value("selected_history", type, cleaned_text_uids);
					}
					history_modified = true;
				}
			}
		}
	}

	if (!first_open && base_types.size() == 1) {
		StringName type = base_types[0];
		Vector<ResourceUID::ID> *history = selected_history.getptr(type);

		if (history) {
			Vector<ResourceUID::ID> clean_history;

			for (const ResourceUID::ID &uid : *history) {
				if (ResourceUID::get_singleton()->has_id(uid)) {
					clean_history.push_back(uid);
				} else {
					history_modified = true;
				}
			}

			if (clean_history.is_empty()) {
				selected_history.erase(type);
			} else if (history_modified) {
				*history = clean_history;
			}
		}
	}

	if (history_modified) {
		history_file->save(_get_cache_file_path());
	}

Review comment (suggestion):
```suggestion
	} else if (!first_open && base_types.size() == 1) {
```

Code after:
						continue;
					}

					filetypes.insert(id, type_name);
					text_write[i] = uid;
					id_write[i] = id;
					i++;
				}

				cleaned_text_uids.resize(i);
				selected_history.insert(type, cleaned_ids);

				if (i < history_uids.size()) {
					// Some paths removed, need to update history.
					if (i == 0) {
						history_file->erase_section_key("selected_history", type);
					} else {
						history_file->set_value("selected_history", type, cleaned_text_uids);
					}
					history_modified = true;
				}
			}
		}
	} else if (!first_open && base_types.size() == 1) {
		const StringName &type = base_types[0];
		Vector<ResourceUID::ID> *history = selected_history.getptr(type);

		if (history) {
			Vector<ResourceUID::ID> clean_history;

			for (const ResourceUID::ID &uid : *history) {
				if (ResourceUID::get_singleton()->has_id(uid)) {
					clean_history.push_back(uid);
				} else {
					history_modified = true;
				}
			}

			if (clean_history.is_empty()) {
				selected_history.erase(type);
			} else if (history_modified) {
				*history = clean_history;
			}
		}
	}

	if (history_modified) {
		history_file->save(_get_cache_file_path());
	}

	_create_initial_results();
Repository: godotengine/godot
File: editor/gui/editor_quick_open_dialog.cpp (C++)

Code before:
					}

					filetypes.insert(id, type_name);
					text_write[i] = uid;
					id_write[i] = id;
					i++;
				}

				cleaned_text_uids.resize(i);
				selected_history.insert(type, cleaned_ids);

				if (i < history_uids.size()) {
					// Some paths removed, need to update history.
					if (i == 0) {
						history_file->erase_section_key("selected_history", type);
					} else {
						history_file->set_value("selected_history", type, cleaned_text_uids);
					}
					history_modified = true;
				}
			}
		}
	}

	if (!first_open && base_types.size() == 1) {
		StringName type = base_types[0];
		Vector<ResourceUID::ID> *history = selected_history.getptr(type);

		if (history) {
			Vector<ResourceUID::ID> clean_history;

			for (const ResourceUID::ID &uid : *history) {
				if (ResourceUID::get_singleton()->has_id(uid)) {
					clean_history.push_back(uid);
				} else {
					history_modified = true;
				}
			}

			if (clean_history.is_empty()) {
				selected_history.erase(type);
			} else if (history_modified) {
				*history = clean_history;
			}
		}
	}

	if (history_modified) {
		history_file->save(_get_cache_file_path());
	}


Review comment (suggestion):
```suggestion
		const StringName &type = base_types[0];
```

Code after:
					}

					filetypes.insert(id, type_name);
					text_write[i] = uid;
					id_write[i] = id;
					i++;
				}

				cleaned_text_uids.resize(i);
				selected_history.insert(type, cleaned_ids);

				if (i < history_uids.size()) {
					// Some paths removed, need to update history.
					if (i == 0) {
						history_file->erase_section_key("selected_history", type);
					} else {
						history_file->set_value("selected_history", type, cleaned_text_uids);
					}
					history_modified = true;
				}
			}
		}
	} else if (!first_open && base_types.size() == 1) {
		const StringName &type = base_types[0];
		Vector<ResourceUID::ID> *history = selected_history.getptr(type);

		if (history) {
			Vector<ResourceUID::ID> clean_history;

			for (const ResourceUID::ID &uid : *history) {
				if (ResourceUID::get_singleton()->has_id(uid)) {
					clean_history.push_back(uid);
				} else {
					history_modified = true;
				}
			}

			if (clean_history.is_empty()) {
				selected_history.erase(type);
			} else if (history_modified) {
				*history = clean_history;
			}
		}
	}

	if (history_modified) {
		history_file->save(_get_cache_file_path());
	}

	_create_initial_results();
}
Repository: godotengine/godot
File: platform/android/java_godot_lib_jni.cpp (C++)

Code before:
	FileAccessAndroid::terminate();
	DirAccessJAndroid::terminate();
	FileAccessFilesystemJAndroid::terminate();
	NetSocketAndroid::terminate();

	cleanup_android_class_loader();
	godot_cleanup_profiler();

	if (godot_java) {
		godot_java->on_godot_terminating(env);
		if (!restart_on_cleanup) {
			if (p_restart) {
				godot_java->restart(env);
			} else {
				godot_java->force_quit(env);
			}
		}
		delete godot_java;
	}
}

static String rendering_source_to_string(OS::RenderingSource p_source) {
	switch (p_source) {
		case OS::RENDERING_SOURCE_DEFAULT:
			return "Default";
		case OS::RENDERING_SOURCE_PROJECT_SETTINGS:
			return "ProjectSettings";
		case OS::RENDERING_SOURCE_COMMANDLINE:
			return "Commandline";
		case OS::RENDERING_SOURCE_FALLBACK:
			return "Fallback";
		default:
			return "Unknown";
	}
}

extern "C" {

JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jclass clazz, jint p_height) {
	if (godot_io_java) {
		godot_io_java->set_vk_height(p_height);
	}
}

JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject p_godot_instance, jobject p_asset_manager, jobject p_godot_io, jobject p_net_utils, jobject p_directory_access_handler, jobject p_file_access_handler, jboolean p_use_apk_expansion) {
	godot_init_profiler();

	JavaVM *jvm;
	env->GetJavaVM(&jvm);

	init_thread_jandroid(jvm, env);

Review comment (suggestion):
```suggestion
		case OS::RENDERING_SOURCE_PROJECT_SETTING:
```

Code after:
	FileAccessAndroid::terminate();
	DirAccessJAndroid::terminate();
	FileAccessFilesystemJAndroid::terminate();
	NetSocketAndroid::terminate();

	cleanup_android_class_loader();
	godot_cleanup_profiler();

	if (godot_java) {
		godot_java->on_godot_terminating(env);
		if (!restart_on_cleanup) {
			if (p_restart) {
				godot_java->restart(env);
			} else {
				godot_java->force_quit(env);
			}
		}
		delete godot_java;
	}
}

static String rendering_source_to_string(OS::RenderingSource p_source) {
	switch (p_source) {
		case OS::RENDERING_SOURCE_DEFAULT:
			return "Default";
		case OS::RENDERING_SOURCE_PROJECT_SETTING:
			return "ProjectSettings";
		case OS::RENDERING_SOURCE_COMMANDLINE:
			return "Commandline";
		case OS::RENDERING_SOURCE_FALLBACK:
			return "Fallback";
		default:
			return "Unknown";
	}
}

extern "C" {

JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jclass clazz, jint p_height) {
	if (godot_io_java) {
		godot_io_java->set_vk_height(p_height);
	}
}

JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject p_godot_instance, jobject p_asset_manager, jobject p_godot_io, jobject p_net_utils, jobject p_directory_access_handler, jobject p_file_access_handler, jboolean p_use_apk_expansion) {
	godot_init_profiler();

	JavaVM *jvm;
	env->GetJavaVM(&jvm);

	init_thread_jandroid(jvm, env);
Repository: godotengine/godot
File: core/input/input.h (C/C++)

Code before:
enum InputCursorShape : int {
	CURSOR_ARROW,
	CURSOR_IBEAM,
	CURSOR_POINTING_HAND,
	CURSOR_CROSS,
	CURSOR_WAIT,
	CURSOR_BUSY,
	CURSOR_DRAG,
	CURSOR_CAN_DROP,
	CURSOR_FORBIDDEN,
	CURSOR_VSIZE,
	CURSOR_HSIZE,
	CURSOR_BDIAGSIZE,
	CURSOR_FDIAGSIZE,
	CURSOR_MOVE,
	CURSOR_VSPLIT,
	CURSOR_HSPLIT,
	CURSOR_HELP,
	CURSOR_MAX
};

class Input : public Object {
	GDCLASS(Input, Object);
	_THREAD_SAFE_CLASS_

	static inline Input *singleton = nullptr;

	static constexpr uint64_t MAX_EVENT = 32;

public:
	using MouseMode = InputMouseMode;
#undef CursorShape
	using CursorShape = InputCursorShape;

	class JoypadFeatures {
	public:
		virtual ~JoypadFeatures() {}

		virtual bool has_joy_light() const { return false; }
		virtual void set_joy_light(const Color &p_color) {}
	};

	static constexpr int32_t JOYPADS_MAX = 16;

	typedef void (*EventDispatchFunc)(const Ref<InputEvent> &p_event);

private:
	BitField<MouseButtonMask> mouse_button_mask = MouseButtonMask::NONE;

	RBSet<Key> key_label_pressed;
	RBSet<Key> physical_keys_pressed;

Review comment (suggestion):
Could be moved to `input_enums.h` instead, but maybe this scope is fine while it's still constrained to `Input`

Code after:
	MOUSE_MODE_MAX,
};

#undef CursorShape
enum CursorShape : int {
	CURSOR_ARROW,
	CURSOR_IBEAM,
	CURSOR_POINTING_HAND,
	CURSOR_CROSS,
	CURSOR_WAIT,
	CURSOR_BUSY,
	CURSOR_DRAG,
	CURSOR_CAN_DROP,
	CURSOR_FORBIDDEN,
	CURSOR_VSIZE,
	CURSOR_HSIZE,
	CURSOR_BDIAGSIZE,
	CURSOR_FDIAGSIZE,
	CURSOR_MOVE,
	CURSOR_VSPLIT,
	CURSOR_HSPLIT,
	CURSOR_HELP,
	CURSOR_MAX
};
} //namespace InputClassEnums

class Input : public Object {
	GDCLASS(Input, Object);
	_THREAD_SAFE_CLASS_

	static inline Input *singleton = nullptr;

	static constexpr uint64_t MAX_EVENT = 32;

public:
	// TODO: When we migrate to C++20, replace these with "using enum" and skip prefixing MouseMode and CursorShape in other files.
	using MouseMode = InputClassEnums::MouseMode;
	using CursorShape = InputClassEnums::CursorShape;

	class JoypadFeatures {
	public:
		virtual ~JoypadFeatures() {}

		virtual bool has_joy_light() const { return false; }
		virtual void set_joy_light(const Color &p_color) {}

		virtual bool has_joy_motion_sensors() const { return false; }
		virtual void set_joy_motion_sensors_enabled(bool p_enable) {}
	};

	static constexpr int32_t JOYPADS_MAX = 16;
Repository: godotengine/godot
File: core/input/input.h (C/C++)

Code before:
	CURSOR_VSIZE,
	CURSOR_HSIZE,
	CURSOR_BDIAGSIZE,
	CURSOR_FDIAGSIZE,
	CURSOR_MOVE,
	CURSOR_VSPLIT,
	CURSOR_HSPLIT,
	CURSOR_HELP,
	CURSOR_MAX
};
} //namespace InputClassEnums

class Input : public Object {
	GDCLASS(Input, Object);
	_THREAD_SAFE_CLASS_

	static inline Input *singleton = nullptr;

	static constexpr uint64_t MAX_EVENT = 32;

public:
	using MouseMode = InputClassEnums::MouseMode;
	using CursorShape = InputClassEnums::CursorShape;

	class JoypadFeatures {
	public:
		virtual ~JoypadFeatures() {}

		virtual bool has_joy_light() const { return false; }
		virtual void set_joy_light(const Color &p_color) {}
	};

	static constexpr int32_t JOYPADS_MAX = 16;

	typedef void (*EventDispatchFunc)(const Ref<InputEvent> &p_event);

private:
	BitField<MouseButtonMask> mouse_button_mask = MouseButtonMask::NONE;

	RBSet<Key> key_label_pressed;
	RBSet<Key> physical_keys_pressed;
	RBSet<Key> keys_pressed;
	RBSet<JoyButton> joy_buttons_pressed;
	RBMap<JoyAxis, float> _joy_axis;
	//RBMap<StringName,int> custom_action_press;
	bool gravity_enabled = false;
	Vector3 gravity;
	bool accelerometer_enabled = false;
	Vector3 accelerometer;
	bool magnetometer_enabled = false;
	Vector3 magnetometer;

Review comment (suggestion):
When we eventually migrate to C++20 we can replace these with `using enum` and skip prefixing `MouseMode` and `CursorShape`, might be worth a "TODO" comment 

Code after:
	CURSOR_CAN_DROP,
	CURSOR_FORBIDDEN,
	CURSOR_VSIZE,
	CURSOR_HSIZE,
	CURSOR_BDIAGSIZE,
	CURSOR_FDIAGSIZE,
	CURSOR_MOVE,
	CURSOR_VSPLIT,
	CURSOR_HSPLIT,
	CURSOR_HELP,
	CURSOR_MAX
};
} //namespace InputClassEnums

class Input : public Object {
	GDCLASS(Input, Object);
	_THREAD_SAFE_CLASS_

	static inline Input *singleton = nullptr;

	static constexpr uint64_t MAX_EVENT = 32;

public:
	// TODO: When we migrate to C++20, replace these with "using enum" and skip prefixing MouseMode and CursorShape in other files.
	using MouseMode = InputClassEnums::MouseMode;
	using CursorShape = InputClassEnums::CursorShape;

	class JoypadFeatures {
	public:
		virtual ~JoypadFeatures() {}

		virtual bool has_joy_light() const { return false; }
		virtual void set_joy_light(const Color &p_color) {}

		virtual bool has_joy_motion_sensors() const { return false; }
		virtual void set_joy_motion_sensors_enabled(bool p_enable) {}
	};

	static constexpr int32_t JOYPADS_MAX = 16;

	typedef void (*EventDispatchFunc)(const Ref<InputEvent> &p_event);

private:
	BitField<MouseButtonMask> mouse_button_mask = MouseButtonMask::NONE;

	RBSet<Key> key_label_pressed;
	RBSet<Key> physical_keys_pressed;
	RBSet<Key> keys_pressed;
	RBSet<JoyButton> joy_buttons_pressed;
	RBMap<JoyAxis, float> _joy_axis;
	//RBMap<StringName,int> custom_action_press;
Repository: godotengine/godot
File: editor/doc/editor_help.h (C/C++)

Code before:
// Standard tooltips do not allow you to hover over them.
// This class is intended as a temporary workaround.
class EditorHelpBitTooltip : public PopupPanel {
	GDCLASS(EditorHelpBitTooltip, PopupPanel);

	static bool _is_tooltip_visible;

	Timer *timer = nullptr;
	uint64_t _enter_tree_time = 0;
	bool _is_mouse_inside_tooltip = false;
	bool _is_shortcut_pressed = false;

	static Control *_make_invisible_control();

	void _start_timer();
	void _target_gui_input(const Ref<InputEvent> &p_event);
	void _shortcut_pressed(Control *p_target);

protected:
	void _notification(int p_what);

public:
	// The returned control is an orphan node, which is to make the standard tooltip invisible.
	[[nodiscard]] static Control *make_tooltip(Control *p_target, const String &p_symbol, const String &p_prologue = String(), bool p_use_class_prefix = false, bool p_shortcut = false);

	void popup_under_position(const Point2 p_point);

	bool is_shortcut_pressed() { return _is_shortcut_pressed; }

	EditorHelpBitTooltip(Control *p_target, bool p_shortcut = false);
};

class EditorSyntaxHighlighter;

class EditorHelpHighlighter {
public:
	enum Language {
		LANGUAGE_GDSCRIPT,
		LANGUAGE_CSHARP,
		LANGUAGE_MAX,
	};

private:
	using HighlightData = Vector<Pair<int, Color>>;

	static EditorHelpHighlighter *singleton;

	HashMap<String, HighlightData> highlight_data_caches[LANGUAGE_MAX];

	TextEdit *text_edits[LANGUAGE_MAX];
	Ref<Script> scripts[LANGUAGE_MAX];

Review comment (suggestion):
```suggestion
	void popup_under_position(const Point2 &p_point);
```

Code after:
// Standard tooltips do not allow you to hover over them.
// This class is intended as a temporary workaround.
class EditorHelpBitTooltip : public PopupPanel {
	GDCLASS(EditorHelpBitTooltip, PopupPanel);

	static bool _is_tooltip_visible;

	Timer *timer = nullptr;
	uint64_t _enter_tree_time = 0;
	bool _is_mouse_inside_tooltip = false;
	bool _is_shortcut_pressed = false;

	static Control *_make_invisible_control();

	void _start_timer();
	void _target_gui_input(const Ref<InputEvent> &p_event);
	void _shortcut_pressed(Control *p_target);

protected:
	void _notification(int p_what);

public:
	// The returned control is an orphan node, which is to make the standard tooltip invisible.
	[[nodiscard]] static Control *make_tooltip(Control *p_target, const String &p_symbol, const String &p_prologue = String(), bool p_use_class_prefix = false, bool p_shortcut = false);

	void popup_under_position(const Point2 &p_point);

	bool is_shortcut_pressed() const { return _is_shortcut_pressed; }

	EditorHelpBitTooltip(Control *p_target, bool p_shortcut = false);
};

class EditorSyntaxHighlighter;

class EditorHelpHighlighter {
public:
	enum Language {
		LANGUAGE_GDSCRIPT,
		LANGUAGE_CSHARP,
		LANGUAGE_MAX,
	};

private:
	using HighlightData = Vector<Pair<int, Color>>;

	static EditorHelpHighlighter *singleton;

	HashMap<String, HighlightData> highlight_data_caches[LANGUAGE_MAX];

	TextEdit *text_edits[LANGUAGE_MAX];
	Ref<Script> scripts[LANGUAGE_MAX];