- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 23.5k
 
[GDScript] Add refactor rename symbol functionality #102380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
779da28
              dc724eb
              4f390c7
              26f1a98
              ba44159
              53cb6ef
              3a3409e
              3124368
              0ccb157
              11a11d3
              f337dd8
              c6d39d7
              c85e33d
              8e478df
              641b06e
              d8ba8f5
              df377d0
              ed26808
              f7e03d6
              2f7a99b
              ac18385
              09b0adf
              c394870
              bb5d86e
              7451662
              1f1c1d9
              1e0f4e4
              96c5dc2
              92a8ba0
              a87afcf
              5c90e3c
              493b656
              db54dc4
              ab3af2b
              09e0e1e
              2357e6f
              a55b15b
              a01a493
              5ac0596
              e55fc62
              7a1280b
              38a61e8
              25e7124
              72c8aa6
              358886f
              7cd933d
              be4a9d7
              48b1223
              6690896
              d42de79
              0d72e1e
              6527af5
              05edbd1
              964fe6a
              a5a79fe
              17b89ac
              f71676c
              e37a56d
              fde6c6c
              e21bc08
              53f04af
              9118d38
              704218f
              d5bd8cb
              2dc08fa
              10342dc
              a7814b8
              9b41a61
              2447098
              854bf25
              eb7f997
              2367c47
              f0b4542
              45494c2
              d81cdcc
              3cbf0b5
              9d300cb
              67f3ced
              0d3bda9
              8a2ca7b
              3af2627
              fc65c5e
              baeee33
              ccd0213
              f87ba92
              2daa0e4
              6f82bce
              1ff2802
              15eb740
              2d42099
              89713c1
              3a942ea
              14b74d2
              b7bc5fd
              258d080
              84118d6
              a3bd51a
              849c783
              827efbf
              da7b71d
              36883e6
              9d704cf
              1819e71
              8b0f4bb
              520c923
              533d479
              f19479f
              e5cbea9
              734272a
              7255e7e
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 
          
            
          
           | 
    @@ -283,6 +283,7 @@ class ScriptLanguage : public Object { | |||||||||||||||||||||||
| virtual bool overrides_external_editor() { return false; } | ||||||||||||||||||||||||
| virtual ScriptNameCasing preferred_file_name_casing() const { return SCRIPT_NAME_CASING_SNAKE_CASE; } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| // Code completion. | ||||||||||||||||||||||||
| // Keep enums in sync with: | ||||||||||||||||||||||||
| // scene/gui/code_edit.h - CodeEdit::CodeCompletionKind | ||||||||||||||||||||||||
| enum CodeCompletionKind { | ||||||||||||||||||||||||
| 
          
            
          
           | 
    @@ -339,6 +340,242 @@ class ScriptLanguage : public Object { | |||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<CodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| // Refactoring. | ||||||||||||||||||||||||
| // Keep enums in sync with: | ||||||||||||||||||||||||
| // scene/gui/code_edit.h - CodeEdit::RefactorKind | ||||||||||||||||||||||||
| enum RefactorKind { | ||||||||||||||||||||||||
| REFACTOR_KIND_RENAME_SYMBOL, | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| enum RefactorRenameSymbolResultType { | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_NONE, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_CONTROL_FLOW, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_LITERAL, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_KEYWORD, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_SYMBOL, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_NATIVE, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_NOT_EXPOSED, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_SCRIPT, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_GLOBAL_CLASS_NAME, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_CLASS_NAME, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_CLASS_CONSTANT, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_CLASS_PROPERTY, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_CLASS_METHOD, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_CLASS_SIGNAL, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_CLASS_ENUM, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_CLASS_ENUM_VALUE, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_CLASS_ANNOTATION, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_LOCAL_CONSTANT, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_LOCAL_VARIABLE, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_LOCAL_FOR_VARIABLE, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_LOCAL_PATTERN_BIND, | ||||||||||||||||||||||||
| REFACTOR_RENAME_SYMBOL_RESULT_MAX, | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| struct RefactorRenameSymbolResult { | ||||||||||||||||||||||||
| struct Match { | ||||||||||||||||||||||||
| int start_line = -1; | ||||||||||||||||||||||||
| int start_column = -1; | ||||||||||||||||||||||||
| int end_line = -1; | ||||||||||||||||||||||||
| int end_column = -1; | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| Match() {} | ||||||||||||||||||||||||
| Match(int p_start_line, int p_start_column, int p_end_line, int p_end_column) { | ||||||||||||||||||||||||
| start_line = p_start_line; | ||||||||||||||||||||||||
| start_column = p_start_column; | ||||||||||||||||||||||||
| end_line = p_end_line; | ||||||||||||||||||||||||
| end_column = p_end_column; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| _FORCE_INLINE_ bool operator==(const Match &r) const { | ||||||||||||||||||||||||
| return start_line == r.start_line && | ||||||||||||||||||||||||
| start_column == r.start_column && | ||||||||||||||||||||||||
| end_line == r.end_line && | ||||||||||||||||||||||||
| end_column == r.end_column; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| _FORCE_INLINE_ bool operator!=(const Match &r) const { | ||||||||||||||||||||||||
| return !(operator==(r)); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| String to_string() const { | ||||||||||||||||||||||||
| return vformat("Match{(%s,%s)=>(%s,%s)}", start_line, start_column, end_line, end_column); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| struct Compare { | ||||||||||||||||||||||||
| _FORCE_INLINE_ bool operator()(const Match &l, const Match &r) const { | ||||||||||||||||||||||||
| if (l.start_line != r.start_line) { | ||||||||||||||||||||||||
| return l.start_line < r.start_line; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| if (l.start_column != r.start_column) { | ||||||||||||||||||||||||
| return l.start_column < r.start_column; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| String symbol; | ||||||||||||||||||||||||
| String new_symbol; | ||||||||||||||||||||||||
| String code; | ||||||||||||||||||||||||
| Vector2i start; | ||||||||||||||||||||||||
| Vector2i sentinel; | ||||||||||||||||||||||||
| Vector2i end; | ||||||||||||||||||||||||
| Error error = FAILED; | ||||||||||||||||||||||||
| bool outside_refactor = false; | ||||||||||||||||||||||||
| RefactorRenameSymbolResultType type = RefactorRenameSymbolResultType::REFACTOR_RENAME_SYMBOL_RESULT_NONE; | ||||||||||||||||||||||||
| HashMap<String, LocalVector<Match>> matches; | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| private: | ||||||||||||||||||||||||
| void _deep_copy(const RefactorRenameSymbolResult &p_result) { | ||||||||||||||||||||||||
| symbol = p_result.symbol; | ||||||||||||||||||||||||
| new_symbol = p_result.new_symbol; | ||||||||||||||||||||||||
| code = p_result.code; | ||||||||||||||||||||||||
| outside_refactor = p_result.outside_refactor; | ||||||||||||||||||||||||
| error = p_result.error; | ||||||||||||||||||||||||
| type = p_result.type; | ||||||||||||||||||||||||
| matches.clear(); | ||||||||||||||||||||||||
| for (const KeyValue<String, LocalVector<Match>> &KV : p_result.matches) { | ||||||||||||||||||||||||
| for (const Match &match : KV.value) { | ||||||||||||||||||||||||
| matches[KV.key].push_back(match); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| public: | ||||||||||||||||||||||||
| String to_string() const { | ||||||||||||||||||||||||
| String matches_string; | ||||||||||||||||||||||||
| for (const KeyValue<String, LocalVector<Match>> &KV : matches) { | ||||||||||||||||||||||||
| LocalVector<String> match_entries; | ||||||||||||||||||||||||
| for (const Match &match : KV.value) { | ||||||||||||||||||||||||
| match_entries.push_back(match.to_string()); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| matches_string += vformat("\t\t%s: %s,\n", KV.key, String(", ").join(PackedStringArray(match_entries))); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| matches_string = matches_string.trim_suffix("\n"); | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| return vformat("(RefactorRenameSymbolResult{\n\"%s\" -> \"%s\",\n\t(\n%s\n\t)\n})", | ||||||||||||||||||||||||
| symbol, new_symbol, matches_string); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| void add_match(const String &p_path, Match p_match) { | ||||||||||||||||||||||||
| matches[p_path].push_back(p_match); | ||||||||||||||||||||||||
| matches[p_path].sort_custom<RefactorRenameSymbolResult::Match::Compare>(); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| void add_match(const String &p_path, int p_start_line, int p_start_column, int p_end_line, int p_end_column) { | ||||||||||||||||||||||||
| add_match(p_path, { p_start_line, p_start_column, p_end_line, p_end_column }); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| Dictionary to_dictionary() { | ||||||||||||||||||||||||
| Dictionary result; | ||||||||||||||||||||||||
| result["symbol"] = symbol; | ||||||||||||||||||||||||
| result["new_symbol"] = new_symbol; | ||||||||||||||||||||||||
| result["code"] = code; | ||||||||||||||||||||||||
| result["outside_refactor"] = outside_refactor; | ||||||||||||||||||||||||
| result["error"] = error; | ||||||||||||||||||||||||
| result["type"] = type; | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| Dictionary dictionary_matches; | ||||||||||||||||||||||||
| for (KeyValue<String, LocalVector<Match>> &KV : matches) { | ||||||||||||||||||||||||
| TypedArray<Dictionary> dictionary_matches_entries; | ||||||||||||||||||||||||
| for (Match &match : KV.value) { | ||||||||||||||||||||||||
| Dictionary dictionary_match; | ||||||||||||||||||||||||
| dictionary_match["start_line"] = match.start_line; | ||||||||||||||||||||||||
| dictionary_match["start_column"] = match.start_column; | ||||||||||||||||||||||||
| dictionary_match["end_line"] = match.end_line; | ||||||||||||||||||||||||
| dictionary_match["end_column"] = match.end_column; | ||||||||||||||||||||||||
| dictionary_matches_entries.push_back(dictionary_match); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| dictionary_matches[KV.key] = dictionary_matches_entries; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| result["matches"] = dictionary_matches; | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| return result; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| RefactorRenameSymbolResult get_undo() { | ||||||||||||||||||||||||
| RefactorRenameSymbolResult undo_result; | ||||||||||||||||||||||||
| undo_result.symbol = new_symbol; | ||||||||||||||||||||||||
| undo_result.new_symbol = symbol; | ||||||||||||||||||||||||
| undo_result.code = code; | ||||||||||||||||||||||||
| undo_result.outside_refactor = outside_refactor; | ||||||||||||||||||||||||
| undo_result.error = error; | ||||||||||||||||||||||||
| undo_result.type = type; | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| for (const KeyValue<String, LocalVector<Match>> &KV : matches) { | ||||||||||||||||||||||||
| int last_line = 0; | ||||||||||||||||||||||||
| int offset = 0; | ||||||||||||||||||||||||
| for (const Match &match : KV.value) { | ||||||||||||||||||||||||
| if (last_line < match.start_line) { | ||||||||||||||||||||||||
| offset = 0; | ||||||||||||||||||||||||
| last_line = match.start_line; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| Match new_match = { | ||||||||||||||||||||||||
| match.start_line, | ||||||||||||||||||||||||
| match.start_column + offset, | ||||||||||||||||||||||||
| match.end_line, | ||||||||||||||||||||||||
| match.end_column, | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
| offset += new_symbol.length() - symbol.length(); | ||||||||||||||||||||||||
| undo_result.matches[KV.key].push_back(new_match); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| return undo_result; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| bool has_failed() const { | ||||||||||||||||||||||||
| return error != OK || outside_refactor; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| void reset(bool p_keep_context = false) { | ||||||||||||||||||||||||
| matches.clear(); | ||||||||||||||||||||||||
| outside_refactor = false; | ||||||||||||||||||||||||
| error = FAILED; | ||||||||||||||||||||||||
| type = REFACTOR_RENAME_SYMBOL_RESULT_NONE; | ||||||||||||||||||||||||
| if (!p_keep_context) { | ||||||||||||||||||||||||
| symbol = ""; | ||||||||||||||||||||||||
| new_symbol = ""; | ||||||||||||||||||||||||
| code = ""; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| void operator=(const RefactorRenameSymbolResult &p_result) { | ||||||||||||||||||||||||
| _deep_copy(p_result); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| RefactorRenameSymbolResult(const RefactorRenameSymbolResult &p_result) { | ||||||||||||||||||||||||
| _deep_copy(p_result); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| RefactorRenameSymbolResult(const Dictionary &p_result) { | ||||||||||||||||||||||||
| ERR_FAIL_COND(!p_result.has("symbol") || !p_result.has("new_symbol") || !p_result.has("code") || !p_result.has("error") || !p_result.has("outside_refactor") || !p_result.has("type") || !p_result.has("matches")); | ||||||||||||||||||||||||
| symbol = p_result["symbol"]; | ||||||||||||||||||||||||
| new_symbol = p_result["new_symbol"]; | ||||||||||||||||||||||||
| code = p_result["code"]; | ||||||||||||||||||||||||
| outside_refactor = p_result["outside_refactor"]; | ||||||||||||||||||||||||
| error = (Error)(int)p_result["error"]; | ||||||||||||||||||||||||
| type = (RefactorRenameSymbolResultType)(int)p_result["type"]; | ||||||||||||||||||||||||
| matches.clear(); | ||||||||||||||||||||||||
| Dictionary dictionary_matches = p_result["matches"]; | ||||||||||||||||||||||||
| for (const String key : dictionary_matches.keys()) { | ||||||||||||||||||||||||
| TypedArray<Dictionary> dictionary_match_entries = dictionary_matches[key]; | ||||||||||||||||||||||||
| for (int i = 0; i < dictionary_match_entries.size(); i++) { | ||||||||||||||||||||||||
| Dictionary dictionar_match_entry = dictionary_match_entries[i]; | ||||||||||||||||||||||||
| matches[key].push_back({ dictionar_match_entry["start_line"], | ||||||||||||||||||||||||
| dictionar_match_entry["start_column"], | ||||||||||||||||||||||||
| dictionar_match_entry["end_line"], | ||||||||||||||||||||||||
| dictionar_match_entry["end_column"] }); | ||||||||||||||||||||||||
| 
         
      Comment on lines
    
      +563
     to 
      +568
    
   
  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
        Suggested change
       
    
  | 
||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| RefactorRenameSymbolResult() = default; | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| virtual Error refactor_rename_symbol_code(const String &p_code, const String &p_path, Object *p_owner, const HashMap<String, String> &p_unsaved_scripts_source_code, RefactorRenameSymbolResult &r_result) { return ERR_UNAVAILABLE; } | ||||||||||||||||||||||||
| 
     | 
||||||||||||||||||||||||
| // Lookup. | ||||||||||||||||||||||||
| enum LookupResultType { | ||||||||||||||||||||||||
| LOOKUP_RESULT_SCRIPT_LOCATION, // Use if none of the options below apply. | ||||||||||||||||||||||||
| LOOKUP_RESULT_CLASS, | ||||||||||||||||||||||||
| 
          
            
          
           | 
    ||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| 
          
            
          
           | 
    @@ -604,6 +604,12 @@ | |||||
| Emitted when the user requests code completion. This signal will not be sent if [method _request_code_completion] is overridden or [member code_completion_enabled] is [code]false[/code]. | ||||||
| </description> | ||||||
| </signal> | ||||||
| <signal name="refactor_requested"> | ||||||
| <param index="0" name="type" type="int" /> | ||||||
| <description> | ||||||
| Emitted when the user requests a refactor. | ||||||
| </description> | ||||||
| </signal> | ||||||
| 
         
      Comment on lines
    
      +607
     to 
      +612
    
   
  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh my god, this is particularly egregious. In its current state (prone to future changes), it should not be exposed at all, let alone without its corresponding enum. CC @KoBeWi because of #69012 (comment). We somehow still can't choose to keep signals unexposed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CodeEdit has  ...if not the fact that this signal is only emitted externally. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like signals can be hidden from docs as of recently. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure that means they're completely hidden from the API, though. Things like autocompletion may recommend them, the Node dock may display them. GDExtension may have them exposed anyway, though the leading underscore is a deterrent. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My only concern with this PR is still this specific signal. @adamscott , can you consider a workaround as KoBeWi also discussed in #69012 (comment)? Line 556 in 7864ac8 
 Line 3906 in 7864ac8 
 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It could also just be removed, like I suggest here #102380 (comment)  | 
||||||
| <signal name="symbol_hovered"> | ||||||
| <param index="0" name="symbol" type="String" /> | ||||||
| <param index="1" name="line" type="int" /> | ||||||
| 
          
            
          
           | 
    ||||||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| 
          
            
          
           | 
    @@ -44,6 +44,7 @@ | |||
| #include "core/os/time.h" | ||||
| #include "core/string/print_string.h" | ||||
| #include "core/string/translation_server.h" | ||||
| #include "core/templates/local_vector.h" | ||||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
        Suggested change
       
    
  | 
||||
| #include "core/version.h" | ||||
| #include "editor/editor_string_names.h" | ||||
| #include "editor/inspector/editor_context_menu_plugin.h" | ||||
| 
          
            
          
           | 
    @@ -1605,7 +1606,9 @@ void EditorNode::edit_resource(const Ref<Resource> &p_resource) { | |||
| } | ||||
| 
     | 
||||
| void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path) { | ||||
| editor_data.apply_changes_in_editors(); | ||||
| if (!p_resource->has_meta("__resource_saved_in_bulk")) { | ||||
| editor_data.apply_changes_in_editors(); | ||||
| } | ||||
| 
     | 
||||
| if (saving_resources_in_path.has(p_resource)) { | ||||
| return; | ||||
| 
          
            
          
           | 
    @@ -1743,6 +1746,25 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String | |||
| file->popup_file_dialog(); | ||||
| } | ||||
| 
     | 
||||
| void EditorNode::save_resource_bulk(const LocalVector<Ref<Resource>> &p_resource_bulk) { | ||||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is my attempt to reduce the save time. I need to check if it's still needed, though  | 
||||
| LocalVector<String> paths; | ||||
| for (const Ref<Resource> &resource : p_resource_bulk) { | ||||
| paths.push_back(resource->get_path()); | ||||
| resource->set_meta("__resource_saved_in_bulk", true); | ||||
| save_resource(resource); | ||||
| } | ||||
| 
     | 
||||
| for (const Ref<Resource> &resource : p_resource_bulk) { | ||||
| resource->remove_meta("__resource_saved_in_bulk"); | ||||
| singleton->editor_folding.save_resource_folding(resource, resource->get_path()); | ||||
| emit_signal(SNAME("resource_saved"), resource); | ||||
| editor_data.notify_resource_saved(resource); | ||||
| } | ||||
| 
     | 
||||
| EditorFileSystem::get_singleton()->update_files(PackedStringArray(paths)); | ||||
| editor_data.apply_changes_in_editors(); | ||||
| } | ||||
| 
     | 
||||
| void EditorNode::_menu_option(int p_option) { | ||||
| _menu_option_confirm(p_option, false); | ||||
| } | ||||
| 
          
            
          
           | 
    @@ -7305,6 +7327,11 @@ void EditorNode::_set_renderer_name_save_and_restart() { | |||
| } | ||||
| 
     | 
||||
| void EditorNode::_resource_saved(Ref<Resource> p_resource, const String &p_path) { | ||||
| if (p_resource->has_meta("__resource_saved_in_bulk")) { | ||||
| singleton->saving_resources_in_path.erase(p_resource); | ||||
| return; | ||||
| } | ||||
| 
     | 
||||
| if (singleton->saving_resources_in_path.has(p_resource)) { | ||||
| // This is going to be handled by save_resource_in_path when the time is right. | ||||
| return; | ||||
| 
          
            
          
           | 
    ||||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| 
          
            
          
           | 
    @@ -31,6 +31,7 @@ | |||
| #pragma once | ||||
| 
     | 
||||
| #include "core/object/script_language.h" | ||||
| #include "core/string/string_name.h" | ||||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
        Suggested change
       
    
  | 
||||
| #include "core/templates/safe_refcount.h" | ||||
| #include "editor/editor_data.h" | ||||
| #include "editor/plugins/editor_plugin.h" | ||||
| 
          
            
          
           | 
    @@ -810,6 +811,8 @@ class EditorNode : public Node { | |||
| void save_resource(const Ref<Resource> &p_resource); | ||||
| void save_resource_as(const Ref<Resource> &p_resource, const String &p_at_path = String()); | ||||
| 
     | 
||||
| void save_resource_bulk(const LocalVector<Ref<Resource>> &p_bulk); | ||||
| 
     | 
||||
| void show_about() { _menu_option_confirm(HELP_ABOUT, false); } | ||||
| 
     | 
||||
| void push_item(Object *p_object, const String &p_property = "", bool p_inspector_only = false); | ||||
| 
          
            
          
           | 
    ||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.