Merge pull request #39076 from rileylyman/editor_tab_names
Implement filename disambiguation for scene tabs and script names
This commit is contained in:
commit
8a484756de
3 changed files with 131 additions and 1 deletions
|
@ -178,6 +178,111 @@
|
|||
|
||||
EditorNode *EditorNode::singleton = nullptr;
|
||||
|
||||
void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames) {
|
||||
// Keep track of a list of "index sets," i.e. sets of indices
|
||||
// within disambiguated_scene_names which contain the same name.
|
||||
Vector<Set<int>> index_sets;
|
||||
Map<String, int> scene_name_to_set_index;
|
||||
for (int i = 0; i < r_filenames.size(); i++) {
|
||||
String scene_name = r_filenames[i];
|
||||
if (!scene_name_to_set_index.has(scene_name)) {
|
||||
index_sets.append(Set<int>());
|
||||
scene_name_to_set_index.insert(r_filenames[i], index_sets.size() - 1);
|
||||
}
|
||||
index_sets.write[scene_name_to_set_index[scene_name]].insert(i);
|
||||
}
|
||||
|
||||
// For each index set with a size > 1, we need to disambiguate
|
||||
for (int i = 0; i < index_sets.size(); i++) {
|
||||
Set<int> iset = index_sets[i];
|
||||
while (iset.size() > 1) {
|
||||
// Append the parent folder to each scene name
|
||||
for (Set<int>::Element *E = iset.front(); E; E = E->next()) {
|
||||
int set_idx = E->get();
|
||||
String scene_name = r_filenames[set_idx];
|
||||
String full_path = p_full_paths[set_idx];
|
||||
|
||||
// Get rid of file extensions and res:// prefixes
|
||||
if (scene_name.rfind(".") >= 0) {
|
||||
scene_name = scene_name.substr(0, scene_name.rfind("."));
|
||||
}
|
||||
if (full_path.begins_with("res://")) {
|
||||
full_path = full_path.substr(6);
|
||||
}
|
||||
if (full_path.rfind(".") >= 0) {
|
||||
full_path = full_path.substr(0, full_path.rfind("."));
|
||||
}
|
||||
|
||||
int scene_name_size = scene_name.size();
|
||||
int full_path_size = full_path.size();
|
||||
int difference = full_path_size - scene_name_size;
|
||||
|
||||
// Find just the parent folder of the current path and append it.
|
||||
// If the current name is foo.tscn, and the full path is /some/folder/foo.tscn
|
||||
// then slash_idx is the second '/', so that we select just "folder", and
|
||||
// append that to yield "folder/foo.tscn".
|
||||
if (difference > 0) {
|
||||
String parent = full_path.substr(0, difference);
|
||||
int slash_idx = parent.rfind("/");
|
||||
slash_idx = parent.rfind("/", slash_idx - 1);
|
||||
parent = slash_idx >= 0 ? parent.substr(slash_idx + 1) : parent;
|
||||
r_filenames.write[set_idx] = parent + r_filenames[set_idx];
|
||||
}
|
||||
}
|
||||
|
||||
// Loop back through scene names and remove non-ambiguous names
|
||||
bool can_proceed = false;
|
||||
Set<int>::Element *E = iset.front();
|
||||
while (E) {
|
||||
String scene_name = r_filenames[E->get()];
|
||||
bool duplicate_found = false;
|
||||
for (Set<int>::Element *F = iset.front(); F; F = F->next()) {
|
||||
if (E->get() == F->get()) {
|
||||
continue;
|
||||
}
|
||||
String other_scene_name = r_filenames[F->get()];
|
||||
if (other_scene_name == scene_name) {
|
||||
duplicate_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Set<int>::Element *to_erase = duplicate_found ? nullptr : E;
|
||||
|
||||
// We need to check that we could actually append anymore names
|
||||
// if we wanted to for disambiguation. If we can't, then we have
|
||||
// to abort even with ambiguous names. We clean the full path
|
||||
// and the scene name first to remove extensions so that this
|
||||
// comparison actually works.
|
||||
String path = p_full_paths[E->get()];
|
||||
if (path.begins_with("res://")) {
|
||||
path = path.substr(6);
|
||||
}
|
||||
if (path.rfind(".") >= 0) {
|
||||
path = path.substr(0, path.rfind("."));
|
||||
}
|
||||
if (scene_name.rfind(".") >= 0) {
|
||||
scene_name = scene_name.substr(0, scene_name.rfind("."));
|
||||
}
|
||||
|
||||
// We can proceed iff the full path is longer than the scene name,
|
||||
// meaning that there is at least one more parent folder we can
|
||||
// tack onto the name.
|
||||
can_proceed = can_proceed || (path.size() - scene_name.size()) >= 1;
|
||||
|
||||
E = E->next();
|
||||
if (to_erase) {
|
||||
iset.erase(to_erase);
|
||||
}
|
||||
}
|
||||
|
||||
if (!can_proceed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorNode::_update_scene_tabs() {
|
||||
bool show_rb = EditorSettings::get_singleton()->get("interface/scene_tabs/show_script_button");
|
||||
|
||||
|
@ -185,6 +290,16 @@ void EditorNode::_update_scene_tabs() {
|
|||
DisplayServer::get_singleton()->global_menu_clear("_dock");
|
||||
}
|
||||
|
||||
// Get all scene names, which may be ambiguous
|
||||
Vector<String> disambiguated_scene_names;
|
||||
Vector<String> full_path_names;
|
||||
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
|
||||
disambiguated_scene_names.append(editor_data.get_scene_title(i));
|
||||
full_path_names.append(editor_data.get_scene_path(i));
|
||||
}
|
||||
|
||||
disambiguate_filenames(full_path_names, disambiguated_scene_names);
|
||||
|
||||
scene_tabs->clear_tabs();
|
||||
Ref<Texture2D> script_icon = gui_base->get_theme_icon("Script", "EditorIcons");
|
||||
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
|
||||
|
@ -196,7 +311,7 @@ void EditorNode::_update_scene_tabs() {
|
|||
|
||||
int current = editor_data.get_edited_scene();
|
||||
bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0;
|
||||
scene_tabs->add_tab(editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), icon);
|
||||
scene_tabs->add_tab(disambiguated_scene_names[i] + (unsaved ? "(*)" : ""), icon);
|
||||
|
||||
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
|
||||
DisplayServer::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), callable_mp(this, &EditorNode::_global_menu_scene), i);
|
||||
|
|
|
@ -687,6 +687,8 @@ public:
|
|||
static void add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed = false);
|
||||
static void remove_editor_plugin(EditorPlugin *p_editor, bool p_config_changed = false);
|
||||
|
||||
static void disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames);
|
||||
|
||||
void new_inherited_scene() { _menu_option_confirm(FILE_NEW_INHERITED_SCENE, false); }
|
||||
|
||||
void set_docks_visible(bool p_show);
|
||||
|
|
|
@ -1731,6 +1731,19 @@ void ScriptEditor::_update_script_names() {
|
|||
sedata.push_back(sd);
|
||||
}
|
||||
|
||||
Vector<String> disambiguated_script_names;
|
||||
Vector<String> full_script_paths;
|
||||
for (int j = 0; j < sedata.size(); j++) {
|
||||
disambiguated_script_names.append(sedata[j].name);
|
||||
full_script_paths.append(sedata[j].tooltip);
|
||||
}
|
||||
|
||||
EditorNode::disambiguate_filenames(full_script_paths, disambiguated_script_names);
|
||||
|
||||
for (int j = 0; j < sedata.size(); j++) {
|
||||
sedata.write[j].name = disambiguated_script_names[j];
|
||||
}
|
||||
|
||||
EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
|
||||
if (eh) {
|
||||
String name = eh->get_class();
|
||||
|
|
Loading…
Reference in a new issue