extends SceneTree var Optparse = load('res://addons/gut/cli/optparse.gd') var WarningsManager = load("res://addons/gut/warnings_manager.gd") const WARN_VALUE_PRINT_POSITION = 36 var godot_default_warnings = { "assert_always_false": 1, "assert_always_true": 1, "confusable_identifier": 1, "confusable_local_declaration": 1, "confusable_local_usage": 1, "constant_used_as_function": 1, "deprecated_keyword": 1, "empty_file": 1, "enable": true, "exclude_addons": true, "function_used_as_property": 1, "get_node_default_without_onready": 2, "incompatible_ternary": 1, "inference_on_variant": 2, "inferred_declaration": 0, "int_as_enum_without_cast": 1, "int_as_enum_without_match": 1, "integer_division": 1, "narrowing_conversion": 1, "native_method_override": 2, "onready_with_export": 2, "property_used_as_function": 1, "redundant_await": 1, "redundant_static_unload": 1, "renamed_in_godot_4_hint": 1, "return_value_discarded": 0, "shadowed_global_identifier": 1, "shadowed_variable": 1, "shadowed_variable_base_class": 1, "standalone_expression": 1, "standalone_ternary": 1, "static_called_on_instance": 1, "unassigned_variable": 1, "unassigned_variable_op_assign": 1, "unreachable_code": 1, "unreachable_pattern": 1, "unsafe_call_argument": 0, "unsafe_cast": 0, "unsafe_method_access": 0, "unsafe_property_access": 0, "unsafe_void_return": 1, "untyped_declaration": 0, "unused_local_constant": 1, "unused_parameter": 1, "unused_private_class_variable": 1, "unused_signal": 1, "unused_variable": 1 } var gut_default_changes = { "exclude_addons": false, "redundant_await": 0, } var warning_settings = {} func _setup_warning_settings(): warning_settings["godot_default"] = godot_default_warnings warning_settings["current"] = WarningsManager.create_warnings_dictionary_from_project_settings() warning_settings["all_warn"] = WarningsManager.create_warn_all_warnings_dictionary() var gut_default = godot_default_warnings.duplicate() gut_default.merge(gut_default_changes, true) warning_settings["gut_default"] = gut_default func _warn_value_to_s(value): var readable = str(value).capitalize() if(typeof(value) == TYPE_INT): readable = WarningsManager.WARNING_LOOKUP.get(value, str(readable, ' ???')) readable = readable.capitalize() return readable func _human_readable(warnings): var to_return = "" for key in warnings: var readable = _warn_value_to_s(warnings[key]) to_return += str(key.capitalize().rpad(35, ' '), readable, "\n") return to_return func _dump_settings(which): if(warning_settings.has(which)): GutUtils.pretty_print(warning_settings[which]) else: print("UNKNOWN print option ", which) func _print_settings(which): if(warning_settings.has(which)): print(_human_readable(warning_settings[which])) else: print("UNKNOWN print option ", which) func _apply_settings(which): if(!warning_settings.has(which)): print("UNKNOWN set option ", which) return var pre_settings = warning_settings["current"] var new_settings = warning_settings[which] if(new_settings == pre_settings): print("-- Settings are the same, no changes were made --") return WarningsManager.apply_warnings_dictionary(new_settings) ProjectSettings.save() print("-- Project Warning Settings have been updated --") print(_diff_changes_text(pre_settings)) func _diff_text(w1, w2, diff_col_pad=10): var to_return = "" for key in w1: var v1_text = _warn_value_to_s(w1[key]) var v2_text = _warn_value_to_s(w2[key]) var diff_text = v1_text var prefix = " " if(v1_text != v2_text): var diff_prefix = " " if(w1[key] > w2[key]): diff_prefix = "-" else: diff_prefix = "+" prefix = "* " diff_text = str(v1_text.rpad(diff_col_pad, ' '), diff_prefix, v2_text) to_return += str(str(prefix, key.capitalize()).rpad(WARN_VALUE_PRINT_POSITION, ' '), diff_text, "\n") return to_return.rstrip("\n") func _diff_changes_text(pre_settings): var orig_diff_text = _diff_text( pre_settings, WarningsManager.create_warnings_dictionary_from_project_settings(), 0) # these next two lines are fragile and brute force...enjoy var diff_text = orig_diff_text.replace("-", " -> ") diff_text = diff_text.replace("+", " -> ") if(orig_diff_text == diff_text): diff_text += "\n-- No changes were made --" else: diff_text += "\nChanges will not be visible in Godot until it is restarted.\n" diff_text += "Even if it asks you to reload...Maybe. Probably." return diff_text func _diff(name_1, name_2): if(warning_settings.has(name_1) and warning_settings.has(name_2)): var c2_pad = name_1.length() + 2 var heading = str(" ".repeat(WARN_VALUE_PRINT_POSITION), name_1.rpad(c2_pad, ' '), name_2, "\n") heading += str( " ".repeat(WARN_VALUE_PRINT_POSITION), "-".repeat(name_1.length()).rpad(c2_pad, " "), "-".repeat(name_2.length()), "\n") var text = _diff_text(warning_settings[name_1], warning_settings[name_2], c2_pad) print(heading) print(text) var diff_count = 0 for line in text.split("\n"): if(!line.begins_with(" ")): diff_count += 1 if(diff_count == 0): print('-- [', name_1, "] and [", name_2, "] are the same --") else: print('-- There are ', diff_count, ' differences between [', name_1, "] and [", name_2, "] --") else: print("One or more unknown Warning Level Names:, [", name_1, "] [", name_2, "]") func _set_settings(nvps): var pre_settings = warning_settings["current"] for i in range(nvps.size()/2): var s_name = nvps[i * 2] var s_value = nvps[i * 2 + 1] if(godot_default_warnings.has(s_name)): var t = typeof(godot_default_warnings[s_name]) if(t == TYPE_INT): s_value = s_value.to_int() elif(t == TYPE_BOOL): s_value = s_value.to_lower() == 'true' WarningsManager.set_project_setting_warning(s_name, s_value) ProjectSettings.save() print(_diff_changes_text(pre_settings)) func _setup_options(): var opts = Optparse.new() opts.banner = """ This script prints info about or sets the warning settings for the project. Each action requires one or more Warning Level Names. Warning Level Names: * current The current settings for the project. * godot_default The default settings for Godot. * gut_default The warning settings that is used when developing GUT. * all_warn Everything set to warn. """.dedent() opts.add('-h', false, 'Print this help') opts.add('-set', [], "Sets a single setting in the project settings and saves.\n" + "Use -dump to see a list of setting names and values.\n" + "Example: -set enabled,true -set unsafe_cast,2 -set unreachable_code,0") opts.add_heading(" Actions (require Warning Level Name)") opts.add('-diff', [], "Shows the difference between two Warning Level Names.\n" + "Example: -diff current,all_warn") opts.add('-dump', 'none', "Prints a dictionary of the warning values.") opts.add('-print', 'none', "Print human readable warning values.") opts.add('-apply', 'none', "Applys one of the Warning Level Names to the project settings. You should restart after using this") return opts func _print_help(opts): opts.print_help() func _init(): # Testing might set this flag but it should never be disabled for this tool # or it cannot save project settings, but says it did. Sneakily use the # private property to get around this property being read-only. Don't # try this at home. WarningsManager._disabled = false _setup_warning_settings() var opts = _setup_options() opts.parse() if(opts.unused.size() != 0): opts.print_help() print("Unknown arguments ", opts.unused) if(opts.values.h): opts.print_help() elif(opts.values.print != 'none'): _print_settings(opts.values.print) elif(opts.values.dump != 'none'): _dump_settings(opts.values.dump) elif(opts.values.apply != 'none'): _apply_settings(opts.values.apply ) elif(opts.values.diff.size() == 2): _diff(opts.values.diff[0], opts.values.diff[1]) elif(opts.values.set.size() % 2 == 0): _set_settings(opts.values.set) else: opts.print_help() print("You didn't specify any options or too many or not the right size or something invalid. I don't know what you want to do.") quit()