diff --git a/bytecode/bytecode_base.cpp b/bytecode/bytecode_base.cpp index 7c8e7ecc..c70cc878 100644 --- a/bytecode/bytecode_base.cpp +++ b/bytecode/bytecode_base.cpp @@ -12,6 +12,7 @@ #include "compat/variant_decoder_compat.h" #include "compat/variant_writer_compat.h" #include "utility/common.h" +#include "utility/gdre_config.h" #include "utility/gdre_settings.h" #include "utility/godotver.h" @@ -623,24 +624,6 @@ Error GDScriptDecomp::decompile_buffer(Vector p_buffer) { Error err = get_script_state(p_buffer, s); ERR_FAIL_COND_V(err != OK, err); - int tab_size = 4; - - if (s.columns.size() > 0) { - Vector diffs; - int prev_column = 1; - for (auto &[key, value] : s.columns) { - int curr_column = value; - if (curr_column > prev_column) { - diffs.push_back(curr_column - prev_column); - } - prev_column = curr_column; - } - tab_size = gdre::get_most_popular_value(diffs); - if (tab_size <= 1) { - tab_size = 4; - } - } - Ref tokenizer = GDScriptTokenizerCompat::create_buffer_tokenizer(this, p_buffer); if (tokenizer.is_null()) { return ERR_INVALID_DATA; @@ -655,7 +638,8 @@ Error GDScriptDecomp::decompile_buffer(Vector p_buffer) { current = tokenizer->scan(); } - bool use_spaces = false; + bool use_spaces = (IndentType)GDREConfig::get_singleton()->get_setting("Script/Indent/type", 0) == INDENT_TYPE_SPACES; + int tab_size = GDREConfig::get_singleton()->get_setting("Script/Indent/size", 4).operator int(); bool first_line = true; int version = s.bytecode_version; int bytecode_version = get_bytecode_version(); diff --git a/bytecode/bytecode_base.h b/bytecode/bytecode_base.h index 8bc82592..b0f5ee68 100644 --- a/bytecode/bytecode_base.h +++ b/bytecode/bytecode_base.h @@ -167,6 +167,12 @@ class GDScriptDecomp : public RefCounted { TOKEN_LINE_MASK = (1 << TOKEN_LINE_BITS) - 1, }; + enum IndentType { + INDENT_TYPE_TABS, + INDENT_TYPE_SPACES, + INDENT_TYPE_MAX, + }; + // bytecode_version, ids, constants, tokens, lines, columns struct ScriptState { int bytecode_version = -1; diff --git a/standalone/gdre_config_dialog.gd b/standalone/gdre_config_dialog.gd index 2629492e..8aa0141c 100644 --- a/standalone/gdre_config_dialog.gd +++ b/standalone/gdre_config_dialog.gd @@ -3,7 +3,7 @@ extends GDREWindow @export var show_ephemeral_settings: bool = false -signal config_changed(changed_settings: Dictionary[String, Variant]) +signal config_changed(changed_settings: Dictionary[String, Array]) func create_section_settings() -> LabelSettings: var label_settings: LabelSettings = LabelSettings.new() @@ -238,7 +238,9 @@ func create_setting_button(setting: GDREConfigSetting) -> Control: elif setting.get_type() == TYPE_INT: button = SpinBox.new() button.value = value - button.step = 1 + button.min_value = setting.get_min_value() + button.max_value = setting.get_max_value() + button.step = setting.get_step_value() var label: Label = make_button_label(setting.get_brief_description()) label.tooltip_text = setting.get_description() control = make_button_hbox(setting, button, label) @@ -246,7 +248,9 @@ func create_setting_button(setting: GDREConfigSetting) -> Control: elif setting.get_type() == TYPE_FLOAT: button = SpinBox.new() button.value = value - button.step = 0.1 + button.min_value = setting.get_min_value() + button.max_value = setting.get_max_value() + button.step = setting.get_step_value() var label: Label = make_button_label(setting.get_brief_description()) label.tooltip_text = setting.get_description() control = make_button_hbox(setting, button, label) @@ -325,10 +329,10 @@ func _render_settings(): func save_settings(): - var changed_settings: Dictionary[String, Variant] = {} + var changed_settings: Dictionary[String, Array] = {} for setting: GDREConfigSetting in setting_value_map.keys(): if setting.get_value() != setting_value_map[setting]: - changed_settings[setting.get_full_name()] = setting_value_map[setting] + changed_settings[setting.get_full_name()] = [setting.get_value(), setting_value_map[setting]] setting.set_value(setting_value_map[setting]) GDREConfig.save_config() if changed_settings.size() != 0 or force_change: diff --git a/standalone/gdre_recover.gd b/standalone/gdre_recover.gd index 8e7a1238..07799887 100644 --- a/standalone/gdre_recover.gd +++ b/standalone/gdre_recover.gd @@ -630,8 +630,9 @@ func _on_export_settings_button_pressed() -> void: %GDREConfigDialog.show() -func _on_gdre_config_dialog_config_changed(changed_settings: Dictionary[String, Variant]) -> void: +func _on_gdre_config_dialog_config_changed(changed_settings: Dictionary[String, Array]) -> void: GDRESettings.update_from_ephemeral_settings() + RESOURCE_PREVIEW.refresh() func _on_add_pcks_dialog_files_selected(paths: PackedStringArray) -> void: diff --git a/standalone/gdre_resource_preview.gd b/standalone/gdre_resource_preview.gd index 2529a72c..a8a5fd30 100644 --- a/standalone/gdre_resource_preview.gd +++ b/standalone/gdre_resource_preview.gd @@ -313,6 +313,12 @@ func load_resource(path: String) -> void: if (%ResourceInfo.text == ""): pop_resource_info(path, info) +func refresh(): + var current_view = get_currently_visible_view() + if current_view == %TextView and current_resource_path != "": + %TextView.reload_from_disk() + # TODO: handle other views? Not currently necessary, config settings only affect the text view currently + func try_text_preview(path, type, res_type): if type == -1: diff --git a/standalone/gdre_text_editor.gd b/standalone/gdre_text_editor.gd index 21a5e5fe..42fb7063 100644 --- a/standalone/gdre_text_editor.gd +++ b/standalone/gdre_text_editor.gd @@ -59,6 +59,8 @@ enum HighlightType { XML } +var current_type: HighlightType = HighlightType.UNKNOWN + func _add_regions_to_gdscript_highlighter(): # Not working, if it ends in a newline, the color wraps to the next line gdscript_highlighter.add_color_region("@", " ", Color("#ffb373")) @@ -112,13 +114,6 @@ func _add_regions_to_gdscript_highlighter(): get: return xml_highlighter -@export var default_highlighter: HighlightType = HighlightType.GDSCRIPT: - set(val): - set_highlight_type(val) - default_highlighter = val - get: - return default_highlighter - @onready var font_size = get_theme_font_size("TextEdit") var code_opts_panel_button_icon = preload("res://gdre_icons/gdre_GuiTabMenuHl.svg") @@ -204,17 +199,30 @@ func _init(): code_opts_box.add_child(code_opts_panel_button) code_opts_box.add_child(CODE_VIWER_OPTIONS) add_child(code_opts_box) - set_highlight_type(default_highlighter) + set_text_viewer_props() func _ready(): - set_highlight_type(default_highlighter) + set_highlight_type(HighlightType.UNKNOWN) func reset(): current_path = "" set_viewer_text("") - set_text_viewer_props() + set_highlight_type(HighlightType.UNKNOWN) pass +func reload_from_disk(): + if current_path.is_empty(): + return + var h_scroll = CODE_VIEWER.scroll_horizontal + var v_scroll = CODE_VIEWER.scroll_vertical + var caret_line = CODE_VIEWER.get_caret_line() + var caret_column = CODE_VIEWER.get_caret_column() + load_path(current_path, current_type) + CODE_VIEWER.scroll_horizontal = h_scroll + CODE_VIEWER.scroll_vertical = v_scroll + CODE_VIEWER.set_caret_line(caret_line, false) + CODE_VIEWER.set_caret_column(caret_column, false) + func set_viewer_text(text: String): # This is a workaround for a bug in CodeEdit where setting the text property throws errors when wrapping is enabled if CODE_VIEWER.wrap_mode == TextEdit.LINE_WRAPPING_BOUNDARY: @@ -271,12 +279,12 @@ func load_code(path, override_bytecode_revision: int = 0) -> bool: if GDRESettings.has_loaded_dotnet_assembly(): var decompiler = GDRESettings.get_dotnet_decompiler() code_text = decompiler.decompile_individual_file(path) - set_csharp_viewer_props() + set_highlight_type(HighlightType.CSHARP) else: code_text = "Error loading script:\nNo .NET assembly loaded" - set_text_viewer_props() + set_highlight_type(HighlightType.TEXT) else: - set_csharp_viewer_props() + set_highlight_type(HighlightType.CSHARP) elif ext == "gde" or ext == "gdc": var script: FakeGDScript = FakeGDScript.new() if (override_bytecode_revision != 0): @@ -284,26 +292,26 @@ func load_code(path, override_bytecode_revision: int = 0) -> bool: script.load_source_code(path) if not script.get_error_message().is_empty(): code_text = "Error loading script:\n" + script.get_error_message() - set_text_viewer_props() + set_highlight_type(HighlightType.TEXT) else: code_text = script.get_source_code() - set_code_viewer_props() + set_highlight_type(HighlightType.GDSCRIPT) else: # ext == "gd" code_text = FileAccess.get_file_as_string(path) - set_code_viewer_props() + set_highlight_type(HighlightType.GDSCRIPT) set_viewer_text(code_text) return true func load_text_resource(path): current_path = path - set_resource_viewer_props() + set_highlight_type(HighlightType.GDRESOURCE) set_viewer_text(ResourceCompatLoader.resource_to_string(path)) return true func load_text_string(text): current_path = "" - set_text_viewer_props() + set_highlight_type(HighlightType.TEXT) set_viewer_text(text) return true @@ -377,7 +385,10 @@ func recognize(path): return HighlightType.UNKNOWN func set_highlight_type(type: HighlightType): - match type: + if current_type == type: + return + current_type = type + match current_type: HighlightType.GDSHADER: set_shader_viewer_props() HighlightType.GDSCRIPT: @@ -419,6 +430,7 @@ func set_common_code_viewer_props(is_code: bool): CODE_VIEWER.gutters_draw_fold_gutter = is_code CODE_VIEWER.gutters_draw_line_numbers = is_code CODE_VIEWER.auto_brace_completion_highlight_matching = is_code + CODE_VIEWER.set_tab_size(GDREConfig.get_setting("Script/Indent/size")) func set_shader_viewer_props(): diff --git a/utility/gdre_config.cpp b/utility/gdre_config.cpp index 57cbd4d1..50003a65 100644 --- a/utility/gdre_config.cpp +++ b/utility/gdre_config.cpp @@ -277,6 +277,22 @@ HashMap> GDREConfig::_init_default_settings() { "Add imports to git repo", "Add .godot/imported/ (or .import/ for Godot 3) to the git repo.", false)), + memnew(GDREConfigSettingEnum( + "Script/Indent/type", + "Indent type", + "The type of indentation to use when decompiling and displaying scripts.", + 0, + "Tabs,Spaces", + false, + false)), + memnew(GDREConfigSettingRange( + "Script/Indent/size", + "Tab size", + "The number of spaces to use when decompiling and displaying scripts.", + 4, + "1,64,1", + false, + false)), memnew(GDREConfigSetting_BytecodeForceBytecodeRevision()), memnew(GDREConfigSetting_LoadCustomBytecode()), #if !GODOT_MONO_DECOMP_DISABLED @@ -594,6 +610,45 @@ void GDREConfigSetting::set_value(const Variant &p_value, bool p_force_ephemeral GDREConfig::get_singleton()->set_setting(full_name, p_value, p_force_ephemeral || ephemeral); } +Variant GDREConfigSetting::get_min_value() const { + switch (get_type()) { + case Variant::Type::INT: + return 0; + case Variant::Type::FLOAT: + return 0.0f; + case Variant::Type::BOOL: + return false; + default: + return Variant(); + } +} + +Variant GDREConfigSetting::get_max_value() const { + switch (get_type()) { + case Variant::Type::INT: + return INT_MAX; + case Variant::Type::FLOAT: + return 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0; + case Variant::Type::BOOL: + return true; + default: + return Variant(); + } +} + +Variant GDREConfigSetting::get_step_value() const { + switch (get_type()) { + case Variant::Type::INT: + return 1; + case Variant::Type::FLOAT: + return 0.01f; + case Variant::Type::BOOL: + return 1; + default: + return Variant(); + } +} + bool GDREConfigSetting::is_hidden() const { return hidden; } @@ -602,6 +657,68 @@ bool GDREConfigSetting::is_ephemeral() const { return ephemeral; } +GDREConfigSettingEnum::GDREConfigSettingEnum( + const String &p_full_name, + const String &p_brief, + const String &p_description, + const Variant &p_default_value, + const String &p_enum_values, + bool p_hidden, + bool p_ephemeral) : + GDREConfigSetting(p_full_name, p_brief, p_description, p_default_value, p_hidden, p_ephemeral) { + enum_values = p_enum_values.split(","); +} + +bool GDREConfigSettingEnum::has_special_value() const { + return true; +} + +Dictionary GDREConfigSettingEnum::get_list_of_possible_values() const { + Dictionary ret; + for (int i = 0; i < enum_values.size(); i++) { + ret[i] = enum_values[i]; + } + return ret; +} + +GDREConfigSettingRange::GDREConfigSettingRange( + const String &p_full_name, + const String &p_brief, + const String &p_description, + const Variant &p_default_value, + const String &p_range_string, bool p_hidden, bool p_ephemeral) : + GDREConfigSetting(p_full_name, p_brief, p_description, p_default_value, p_hidden, p_ephemeral) { + auto parts = p_range_string.split(","); + ERR_FAIL_COND_MSG(parts.size() != 3, "Invalid range string: " + p_range_string); + if (p_default_value.get_type() == Variant::Type::INT) { + min_value = parts[0].to_int(); + max_value = parts[1].to_int(); + step_value = parts[2].to_int(); + } else if (p_default_value.get_type() == Variant::Type::FLOAT) { + min_value = parts[0].to_float(); + max_value = parts[1].to_float(); + step_value = parts[2].to_float(); + } else { + ERR_FAIL_MSG("Invalid range string: " + p_range_string); + } +} + +Variant GDREConfigSettingRange::get_min_value() const { + return min_value; +} + +Variant GDREConfigSettingRange::get_max_value() const { + return max_value; +} + +Variant GDREConfigSettingRange::get_step_value() const { + return step_value; +} + +bool GDREConfigSettingRange::is_range_setting() const { + return true; +} + void GDREConfigSetting::_bind_methods() { ClassDB::bind_method(D_METHOD("reset"), &GDREConfigSetting::reset); ClassDB::bind_method(D_METHOD("set_value", "value", "force_ephemeral"), &GDREConfigSetting::set_value, DEFVAL(false)); @@ -617,6 +734,10 @@ void GDREConfigSetting::_bind_methods() { ClassDB::bind_method(D_METHOD("is_filepicker"), &GDREConfigSetting::is_filepicker); ClassDB::bind_method(D_METHOD("is_dirpicker"), &GDREConfigSetting::is_dirpicker); ClassDB::bind_method(D_METHOD("is_virtual_setting"), &GDREConfigSetting::is_virtual_setting); + ClassDB::bind_method(D_METHOD("is_range_setting"), &GDREConfigSetting::is_range_setting); + ClassDB::bind_method(D_METHOD("get_min_value"), &GDREConfigSetting::get_min_value); + ClassDB::bind_method(D_METHOD("get_max_value"), &GDREConfigSetting::get_max_value); + ClassDB::bind_method(D_METHOD("get_step_value"), &GDREConfigSetting::get_step_value); ClassDB::bind_method(D_METHOD("get_error_message"), &GDREConfigSetting::get_error_message); ClassDB::bind_method(D_METHOD("clear_error_message"), &GDREConfigSetting::clear_error_message); ClassDB::bind_method(D_METHOD("has_special_value"), &GDREConfigSetting::has_special_value); diff --git a/utility/gdre_config.h b/utility/gdre_config.h index a438c1c6..05877a41 100644 --- a/utility/gdre_config.h +++ b/utility/gdre_config.h @@ -32,6 +32,10 @@ class GDREConfigSetting : public RefCounted { bool is_hidden() const; Variant::Type get_type() const; bool is_ephemeral() const; + virtual bool is_range_setting() const { return false; } + virtual Variant get_min_value() const; + virtual Variant get_max_value() const; + virtual Variant get_step_value() const; virtual bool is_virtual_setting() const { return false; } virtual bool is_filepicker() const { return false; } virtual bool is_dirpicker() const { return false; } @@ -54,6 +58,44 @@ class GDREConfigSetting : public RefCounted { GDREConfigSetting() {} }; +class GDREConfigSettingEnum : public GDREConfigSetting { + GDSOFTCLASS(GDREConfigSettingEnum, GDREConfigSetting); + + Vector enum_values; + +public: + GDREConfigSettingEnum( + const String &p_full_name, + const String &p_brief, + const String &p_description, + const Variant &p_default_value, + const String &p_enum_values, + bool p_hidden = false, + bool p_ephemeral = false); + virtual bool has_special_value() const override; + virtual Dictionary get_list_of_possible_values() const override; +}; + +class GDREConfigSettingRange : public GDREConfigSetting { + GDSOFTCLASS(GDREConfigSettingRange, GDREConfigSetting); + + Variant min_value; + Variant max_value; + Variant step_value; + +public: + GDREConfigSettingRange( + const String &p_full_name, + const String &p_brief, + const String &p_description, + const Variant &p_default_value, + const String &p_range_string, bool p_hidden = false, bool p_ephemeral = false); + virtual Variant get_min_value() const override; + virtual Variant get_max_value() const override; + virtual Variant get_step_value() const override; + virtual bool is_range_setting() const override; +}; + class GDREConfig : public Object { GDCLASS(GDREConfig, Object); diff --git a/utility/import_exporter.cpp b/utility/import_exporter.cpp index 6aa1a182..47332f44 100644 --- a/utility/import_exporter.cpp +++ b/utility/import_exporter.cpp @@ -1544,13 +1544,12 @@ Error ImportExporter::export_imports(const String &p_out_dir, const Vectoris_project_config_loaded()) { // some pcks do not have project configs write_project_metadata_cfg(output_dir); - // if constexpr (GDScriptDecomp::FORCE_SPACES_FOR_2_0) { - // // if we're at v4.5 or higher (<4.5 doesn't support editor_overrides), we want to set "editor_overrides/text_editor/behavior/indent/type" to "Spaces" - // // This avoids editor churn on the scripts when they're resaved by the editor - // if (get_ver_major() == 4 && get_ver_minor() >= 5 && get_ver_minor() < 7 && !get_settings()->has_project_setting("editor_overrides/text_editor/behavior/indent/type")) { - // get_settings()->set_project_setting("editor_overrides/text_editor/behavior/indent/type", 1); - // } - // } + if ((get_ver_major() > 4 || (get_ver_major() == 4 && get_ver_minor() >= 5))) { + // if we're at v4.5 or higher (<4.5 doesn't support editor_overrides), we want to set "editor_overrides/text_editor/behavior/indent/type" to the user defined value + // This avoids editor churn on the scripts when they're resaved by the editor + get_settings()->set_project_setting("editor_overrides/text_editor/behavior/indent/type", GDREConfig::get_singleton()->get_setting("Script/Indent/type", 0)); + get_settings()->set_project_setting("editor_overrides/text_editor/behavior/indent/size", GDREConfig::get_singleton()->get_setting("Script/Indent/size", 4)); + } if (get_settings()->save_project_config(output_dir) != OK) { print_line("ERROR: Failed to save project config!"); } else {