diff --git a/addons/gdLinter/Settings/ignore.gd b/addons/gdLinter/Settings/ignore.gd new file mode 100644 index 0000000..6c763c3 --- /dev/null +++ b/addons/gdLinter/Settings/ignore.gd @@ -0,0 +1,44 @@ +class_name GDLinterIgnore +extends Resource + +@export_group("Name Checks") +@export var _function_name: bool = false +@export var _class_name: bool = false +@export var _sub_class_name: bool = false +@export var _signal_name: bool = false +@export var _class_variable_name: bool = false +@export var _class_load_variable_name: bool = false +@export var _function_variable_name: bool = false +@export var _function_preload_variable_name: bool = false +@export var _function_argument_name: bool = false +@export var _loop_variable_name: bool = false +@export var _enum_name: bool = false +@export var _enum_element_name: bool = false +@export var _constant_name: bool = false +@export var _load_constant_name: bool = false + +@export_group("Basic Checks") +@export var _duplicated_load: bool = false +@export var _expression_not_assigned: bool = false +@export var _unnecessary_pass: bool = false +@export var _unused_argument: bool = false +@export var _comparison_with_itself: bool = false + +@export_group("Class Checks") +@export var _private_method_call: bool = false +@export var _class_definitions_order: bool = false + +@export_group("Design Checks") +@export var _max_public_methods: bool = false +@export var _function_arguments_number: bool = false + +@export_group("Format Checks") +@export var _max_file_lines: bool = false +@export var _trailing_whitespace: bool = false +@export var _max_line_length: bool = false +@export var _mixed_tabs_and_spaces: bool = false + +@export_group("Misc Checks") +@export var _no_elif_return: bool = false +@export var _no_else_return: bool = false + diff --git a/addons/gdLinter/Settings/ignore.tres b/addons/gdLinter/Settings/ignore.tres new file mode 100644 index 0000000..ec32cbf --- /dev/null +++ b/addons/gdLinter/Settings/ignore.tres @@ -0,0 +1,35 @@ +[gd_resource type="Resource" script_class="GDLinterIgnore" load_steps=2 format=3 uid="uid://6ip8eigu30by"] + +[ext_resource type="Script" path="res://addons/gdLinter/Settings/ignore.gd" id="1_8j37n"] + +[resource] +script = ExtResource("1_8j37n") +_function_name = false +_class_name = false +_sub_class_name = false +_signal_name = false +_class_variable_name = false +_class_load_variable_name = false +_function_variable_name = false +_function_preload_variable_name = false +_function_argument_name = false +_loop_variable_name = false +_enum_name = false +_enum_element_name = false +_constant_name = false +_load_constant_name = false +_duplicated_load = false +_expression_not_assigned = false +_unnecessary_pass = false +_unused_argument = false +_comparison_with_itself = false +_private_method_call = false +_class_definitions_order = false +_max_public_methods = false +_function_arguments_number = false +_max_file_lines = false +_trailing_whitespace = false +_max_line_length = false +_mixed_tabs_and_spaces = false +_no_elif_return = false +_no_else_return = false diff --git a/addons/gdLinter/UI/Basic.gd b/addons/gdLinter/UI/Basic.gd new file mode 100644 index 0000000..d3a6cb4 --- /dev/null +++ b/addons/gdLinter/UI/Basic.gd @@ -0,0 +1,39 @@ +@tool +extends MarginContainer + +var _owner: GDLinterIgnoreWindow = owner + +@onready var duplicated_load: CheckBox = %DuplicatedLoad +@onready var expression_not_assigned: CheckBox = %ExpressionNotAssigned +@onready var unnecessary_pass: CheckBox = %UnnecessaryPass +@onready var unused_argument: CheckBox = %UnusedArgument +@onready var comparision_with_itself: CheckBox = %ComparisionWithItself + + +func init() -> void: + _owner = owner + duplicated_load.button_pressed = _owner.ignore.get("_duplicated_load") + expression_not_assigned.button_pressed = _owner.ignore.get("_expression_not_assigned") + unnecessary_pass.button_pressed = _owner.ignore.get("_unnecessary_pass") + unused_argument.button_pressed = _owner.ignore.get("_unused_argument") + comparision_with_itself.button_pressed = _owner.ignore.get("_comparison_with_itself") + + +func _on_duplicated_load_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_duplicated_load", toggled_on) + + +func _on_expression_not_assigned_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_expression_not_assigned", toggled_on) + + +func _on_unnecessary_pass_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_unnecessary_pass", toggled_on) + + +func _on_unused_argument_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_unused_argument", toggled_on) + + +func _on_comparision_with_itself_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_comparison_with_itself", toggled_on) diff --git a/addons/gdLinter/UI/Class.gd b/addons/gdLinter/UI/Class.gd new file mode 100644 index 0000000..c415576 --- /dev/null +++ b/addons/gdLinter/UI/Class.gd @@ -0,0 +1,21 @@ +@tool +extends MarginContainer + +var _owner: GDLinterIgnoreWindow = owner + +@onready var private_method_call: CheckBox = %PrivateMethodCall +@onready var class_definition_order: CheckBox = %ClassDefinitionOrder + + +func init() -> void: + _owner = owner + private_method_call.button_pressed = _owner.ignore.get("_private_method_call") + class_definition_order.button_pressed = _owner.ignore.get("_class_definitions_order") + + +func _on_private_method_call_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_private_method_call", toggled_on) + + +func _on_class_definition_order_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_class_definitions_order", toggled_on) diff --git a/addons/gdLinter/UI/Design.gd b/addons/gdLinter/UI/Design.gd new file mode 100644 index 0000000..9c81347 --- /dev/null +++ b/addons/gdLinter/UI/Design.gd @@ -0,0 +1,21 @@ +@tool +extends MarginContainer + +var _owner: GDLinterIgnoreWindow = owner + +@onready var max_public_methods: CheckBox = %MaxPublicMethods +@onready var function_argument_number: CheckBox = %FunctionArgumentNumber + + +func init() -> void: + _owner = owner + max_public_methods.button_pressed = _owner.ignore.get("_max_public_methods") + function_argument_number.button_pressed = _owner.ignore.get("_function_arguments_number") + + +func _on_max_public_methods_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_max_public_methods", toggled_on) + + +func _on_function_argument_number_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_function_arguments_number", toggled_on) diff --git a/addons/gdLinter/UI/Dock.gd b/addons/gdLinter/UI/Dock.gd index a67ef97..4f38490 100644 --- a/addons/gdLinter/UI/Dock.gd +++ b/addons/gdLinter/UI/Dock.gd @@ -2,23 +2,100 @@ class_name GDLinterDock extends Control -const ERROR_BUTTON = preload("res://addons/gdLinter/UI/ErrorButton.tscn") - +var gd_linter: GDLinter +var error_descriptions := preload("res://addons/gdLinter/error_descriptions.gd").new() var script_text_editor: ScriptEditorBase +var color_error: Color = EditorInterface.get_editor_settings()\ + .get_setting("text_editor/theme/highlighting/comment_markers/critical_color") + +var num_problems: int = 0 +var num_ignored_problems: int = 0 + +var _ignore: GDLinterIgnore = preload("res://addons/gdLinter/Settings/ignore.tres") @onready var file: Label = %File -@onready var label: Label = %Label -@onready var error_holder: VBoxContainer = %ErrorHolder +@onready var problems_num: Label = %ProblemsNum +@onready var ignored_problems_num: Label = %IgnoredProblemsNum @onready var version: Label = %Version +@onready var tree: Tree = %Tree +@onready var gd_linter_ignore_window: GDLinterIgnoreWindow = $GdLinterIgnoreWindow + + +func _ready() -> void: + gd_linter_ignore_window.ignore = _ignore + gd_linter_ignore_window.dock_ui = self + tree.add_theme_color_override("font_color", color_error) + tree.set_column_title(0, "Line") + tree.set_column_title(1, "Error") + tree.set_column_title_alignment(0, HORIZONTAL_ALIGNMENT_LEFT) + tree.set_column_title_alignment(1, HORIZONTAL_ALIGNMENT_LEFT) + tree.set_column_custom_minimum_width(0, 75) + tree.set_column_custom_minimum_width(1, 0) + tree.set_column_expand(0, false) + tree.set_column_expand(1, true) + tree.set_column_clip_content(0, false) + tree.set_column_clip_content(1, true) + tree.set_column_expand_ratio(0, 4) + tree.item_activated.connect(_on_item_activated) + +func reset_problem_num() -> void: + num_problems = 0 + num_ignored_problems = 0 + + +func create_item(line: int, name: String) -> void: + var regex = RegEx.new() + regex.compile("(?<=\\()[^\\)]+") + var result := regex.search_all(name) + var error_type := result[-1].strings[0] + if _ignore.get(str_dash_to_underscore(error_type)): + num_ignored_problems += 1 + return + + var item := tree.create_item() + item.set_text(0, str(line)) + item.set_text(1, name) + item.set_metadata(0, line) + + if error_descriptions.error.has(error_type): + item.set_tooltip_text(1, error_descriptions.error[error_type]) + num_problems += 1 + + +func set_problems_label(number: int) -> void: + problems_num.text = str(number) + + +func set_ignored_problems_label(number: int) -> void: + ignored_problems_num.text = str(number) + +func clear_items() -> void: + reset_problem_num() + tree.clear() + tree.create_item() + + +func _on_item_activated() -> void: + var selected: TreeItem = tree.get_selected() + var line := selected.get_metadata(0) + EditorInterface.edit_script(load(file.text), line) + + if not EditorInterface.get_editor_settings().get("text_editor/external/use_external_editor"): + EditorInterface.set_main_screen_editor("Script") + + +func str_dash_to_underscore(string: String) -> String: + return "_" + string.replace("-", "_") + + +func is_error_ignored(name: String) -> bool: + var regex = RegEx.new() + regex.compile("(?<=\\()[^\\)]+") + var result := regex.search_all(name) + var error_type := result[-1].strings[0] + return _ignore.get(str_dash_to_underscore(error_type)) -func create_error(name: String) -> Button: - var error: Button = ERROR_BUTTON.instantiate() - error.text = name - error_holder.add_child(error) - return error -func delete_errors() -> void: - var children := error_holder.get_children() - for child: Button in children: - child.queue_free() +func _on_button_pressed() -> void: + gd_linter_ignore_window.popup() diff --git a/addons/gdLinter/UI/Dock.tscn b/addons/gdLinter/UI/Dock.tscn index bd17705..9dd1d49 100644 --- a/addons/gdLinter/UI/Dock.tscn +++ b/addons/gdLinter/UI/Dock.tscn @@ -1,6 +1,7 @@ -[gd_scene load_steps=2 format=3 uid="uid://d1eqlqvotirg1"] +[gd_scene load_steps=3 format=3 uid="uid://d1eqlqvotirg1"] [ext_resource type="Script" path="res://addons/gdLinter/UI/Dock.gd" id="1_u5r3b"] +[ext_resource type="PackedScene" uid="uid://cgk7hjif0ujw1" path="res://addons/gdLinter/UI/GDLinterIgnoreWindow.tscn" id="3_ib5aw"] [node name="Dock" type="Control"] layout_mode = 3 @@ -25,7 +26,7 @@ layout_mode = 2 [node name="RichTextLabel" type="RichTextLabel" parent="VBoxContainer/Header"] layout_mode = 2 bbcode_enabled = true -text = "[center]GDLint Plugin 1.0.1[/center]" +text = "[center]GDLint Plugin 2.0.0[/center]" fit_content = true [node name="LintedFile" type="PanelContainer" parent="VBoxContainer"] @@ -42,26 +43,69 @@ text = "Currently linted file:" unique_name_in_owner = true layout_mode = 2 -[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer"] +[node name="MiddleContainer" type="HBoxContainer" parent="VBoxContainer"] layout_mode = 2 size_flags_vertical = 3 size_flags_stretch_ratio = 20.0 -[node name="ErrorHolder" type="VBoxContainer" parent="VBoxContainer/ScrollContainer"] +[node name="Tree" type="Tree" parent="VBoxContainer/MiddleContainer"] unique_name_in_owner = true layout_mode = 2 +size_flags_horizontal = 3 +focus_mode = 0 +theme_override_colors/font_color = Color(0.77, 0.35, 0.35, 1) +theme_override_constants/v_separation = 0 +columns = 2 +column_titles_visible = true +hide_folding = true +hide_root = true +select_mode = 1 +scroll_horizontal_enabled = false + +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/MiddleContainer"] +layout_mode = 2 + +[node name="Button" type="Button" parent="VBoxContainer/MiddleContainer/VBoxContainer"] +layout_mode = 2 +text = "Ignore +Settings" [node name="Statusbar" type="HBoxContainer" parent="VBoxContainer"] layout_mode = 2 size_flags_vertical = 10 -[node name="Label" type="Label" parent="VBoxContainer/Statusbar"] +[node name="ProblemsContainer" type="HBoxContainer" parent="VBoxContainer/Statusbar"] +layout_mode = 2 +theme_override_constants/separation = 0 + +[node name="ProblemsNum" type="Label" parent="VBoxContainer/Statusbar/ProblemsContainer"] unique_name_in_owner = true layout_mode = 2 -size_flags_horizontal = 3 +text = "0" + +[node name="ProblemsLbl" type="Label" parent="VBoxContainer/Statusbar/ProblemsContainer"] +layout_mode = 2 +text = "problems found" + +[node name="VSeparator" type="VSeparator" parent="VBoxContainer/Statusbar/ProblemsContainer"] +layout_mode = 2 + +[node name="IgnoredProblemsNum" type="Label" parent="VBoxContainer/Statusbar/ProblemsContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "0" + +[node name="IgnoredProblemsLbl" type="Label" parent="VBoxContainer/Statusbar/ProblemsContainer"] +layout_mode = 2 +text = "problems ignored" [node name="Version" type="Label" parent="VBoxContainer/Statusbar"] unique_name_in_owner = true layout_mode = 2 size_flags_horizontal = 3 horizontal_alignment = 2 + +[node name="GdLinterIgnoreWindow" parent="." instance=ExtResource("3_ib5aw")] +dialog_text = "" + +[connection signal="pressed" from="VBoxContainer/MiddleContainer/VBoxContainer/Button" to="." method="_on_button_pressed"] diff --git a/addons/gdLinter/UI/ErrorButton.tscn b/addons/gdLinter/UI/ErrorButton.tscn deleted file mode 100644 index 73d3006..0000000 --- a/addons/gdLinter/UI/ErrorButton.tscn +++ /dev/null @@ -1,41 +0,0 @@ -[gd_scene load_steps=9 format=3 uid="uid://bl23jxwmiyv68"] - -[ext_resource type="Script" path="res://addons/gdLinter/UI/ErrorButton.gd" id="1_jgnf2"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_mserg"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_mp80h"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_tdjso"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_4lagt"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_v8xyu"] - -[sub_resource type="Image" id="Image_q8lpg"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 128, 110, 30, 255, 121, 107, 169, 255, 120, 107, 231, 255, 120, 107, 231, 255, 120, 108, 168, 255, 123, 114, 29, 255, 255, 255, 0, 255, 128, 110, 30, 255, 121, 107, 239, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 238, 255, 123, 114, 29, 255, 121, 107, 169, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 121, 107, 167, 255, 120, 107, 231, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 231, 255, 120, 107, 231, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 230, 255, 120, 108, 168, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 166, 255, 123, 114, 29, 255, 120, 107, 238, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 107, 255, 255, 120, 108, 237, 255, 128, 109, 28, 255, 255, 255, 0, 255, 123, 114, 29, 255, 121, 107, 167, 255, 120, 107, 231, 255, 120, 107, 230, 255, 120, 107, 166, 255, 128, 109, 28, 255, 255, 255, 0), -"format": "RGBA8", -"height": 8, -"mipmaps": false, -"width": 8 -} - -[sub_resource type="ImageTexture" id="ImageTexture_hkk5h"] -image = SubResource("Image_q8lpg") - -[node name="ErrorButton" type="Button"] -modulate = Color(0.77, 0.35, 0.35, 1) -anchors_preset = 10 -anchor_right = 1.0 -offset_bottom = 8.0 -grow_horizontal = 2 -theme_override_styles/normal = SubResource("StyleBoxEmpty_mserg") -theme_override_styles/hover = SubResource("StyleBoxEmpty_mp80h") -theme_override_styles/pressed = SubResource("StyleBoxEmpty_tdjso") -theme_override_styles/disabled = SubResource("StyleBoxEmpty_4lagt") -theme_override_styles/focus = SubResource("StyleBoxEmpty_v8xyu") -icon = SubResource("ImageTexture_hkk5h") -flat = true -alignment = 0 -script = ExtResource("1_jgnf2") diff --git a/addons/gdLinter/UI/Format.gd b/addons/gdLinter/UI/Format.gd new file mode 100644 index 0000000..f61661e --- /dev/null +++ b/addons/gdLinter/UI/Format.gd @@ -0,0 +1,33 @@ +@tool +extends MarginContainer + +var _owner: GDLinterIgnoreWindow = owner + +@onready var max_file_lines: CheckBox = %MaxFileLines +@onready var trailing_whitespace_check_box: CheckBox = %TrailingWhitespaceCheckBox +@onready var max_line_length: CheckBox = %MaxLineLength +@onready var mixed_tabs_and_spaces: CheckBox = %MixedTabsAndSpaces + + +func init() -> void: + _owner = owner + max_file_lines.button_pressed = _owner.ignore.get("_max_file_lines") + trailing_whitespace_check_box.button_pressed = _owner.ignore.get("_trailing_whitespace") + max_line_length.button_pressed = _owner.ignore.get("_max_line_length") + mixed_tabs_and_spaces.button_pressed = _owner.ignore.get("_mixed_tabs_and_spaces") + + +func _on_max_file_lines_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_max_file_lines", toggled_on) + + +func _on_trailing_whitespace_check_box_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_trailing_whitespace", toggled_on) + + +func _on_max_line_length_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_max_line_length", toggled_on) + + +func _on_mixed_tabs_and_spaces_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_mixed_tabs_and_spaces", toggled_on) diff --git a/addons/gdLinter/UI/GDLinterIgnoreWindow.gd b/addons/gdLinter/UI/GDLinterIgnoreWindow.gd new file mode 100644 index 0000000..7a00b80 --- /dev/null +++ b/addons/gdLinter/UI/GDLinterIgnoreWindow.gd @@ -0,0 +1,31 @@ +@tool +class_name GDLinterIgnoreWindow +extends AcceptDialog + +var ignore: GDLinterIgnore +var dock_ui: GDLinterDock + +@onready var basic: MarginContainer = %Basic +@onready var design: MarginContainer = %Design +@onready var format: MarginContainer = %Format +@onready var misc: MarginContainer = %Misc +@onready var _name: MarginContainer = %Name +@onready var _class: MarginContainer = %Class + + +func reapply_linting() -> void: + var current_script := EditorInterface.get_script_editor().get_current_script() + dock_ui.gd_linter.script_editor.editor_script_changed.emit(current_script) + + +func _on_confirmed() -> void: + reapply_linting() + + +func _on_about_to_popup() -> void: + basic.init() + design.init() + format.init() + misc.init() + _name.init() + _class.init() diff --git a/addons/gdLinter/UI/GDLinterIgnoreWindow.tscn b/addons/gdLinter/UI/GDLinterIgnoreWindow.tscn new file mode 100644 index 0000000..1974c03 --- /dev/null +++ b/addons/gdLinter/UI/GDLinterIgnoreWindow.tscn @@ -0,0 +1,261 @@ +[gd_scene load_steps=8 format=3 uid="uid://cgk7hjif0ujw1"] + +[ext_resource type="Script" path="res://addons/gdLinter/UI/GDLinterIgnoreWindow.gd" id="1_71hhq"] +[ext_resource type="Script" path="res://addons/gdLinter/UI/Name.gd" id="2_35t2j"] +[ext_resource type="Script" path="res://addons/gdLinter/UI/Basic.gd" id="3_ijjp7"] +[ext_resource type="Script" path="res://addons/gdLinter/UI/Class.gd" id="4_s2mg3"] +[ext_resource type="Script" path="res://addons/gdLinter/UI/Design.gd" id="5_2ncqt"] +[ext_resource type="Script" path="res://addons/gdLinter/UI/Format.gd" id="6_5fvrg"] +[ext_resource type="Script" path="res://addons/gdLinter/UI/Misc.gd" id="7_l8gkb"] + +[node name="GdLinterIgnoreWindow" type="AcceptDialog"] +disable_3d = true +title = "GDLinter Ignore Settings" +initial_position = 1 +size = Vector2i(480, 539) +dialog_text = "fghgfdfggfd" +script = ExtResource("1_71hhq") + +[node name="PanelContainer" type="PanelContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 8.0 +offset_top = 8.0 +offset_right = -8.0 +offset_bottom = -34.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="TabContainer" type="TabContainer" parent="PanelContainer"] +layout_mode = 2 + +[node name="Name" type="MarginContainer" parent="PanelContainer/TabContainer"] +unique_name_in_owner = true +layout_mode = 2 +script = ExtResource("2_35t2j") + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/TabContainer/Name"] +layout_mode = 2 + +[node name="FunctionName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Function Name" + +[node name="ClassName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Class Name" + +[node name="SubClassName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Sub Class Name" + +[node name="SignalName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Signal Name" + +[node name="ClassVariableName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Class Variable Name" + +[node name="ClassLoadVariableName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Class Load Variable Name" + +[node name="FunctionVariableName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Function Variable Name" + +[node name="FunctionPreloadVariableName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Function Preload Variable Name" + +[node name="FunctionArgumentName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Function Argument Name" + +[node name="LoopVariableName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Loop Variable Name" + +[node name="EnumName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Enum Name" + +[node name="EnumElementName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Enum Element Name" + +[node name="ConstantName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Constant Name" + +[node name="LoadConstantName" type="CheckBox" parent="PanelContainer/TabContainer/Name/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Load Constant Name" + +[node name="Basic" type="MarginContainer" parent="PanelContainer/TabContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +script = ExtResource("3_ijjp7") + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/TabContainer/Basic"] +layout_mode = 2 + +[node name="DuplicatedLoad" type="CheckBox" parent="PanelContainer/TabContainer/Basic/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Duplicated Load" + +[node name="ExpressionNotAssigned" type="CheckBox" parent="PanelContainer/TabContainer/Basic/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Expression Not Assigned" + +[node name="UnnecessaryPass" type="CheckBox" parent="PanelContainer/TabContainer/Basic/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Unnecessary Pass" + +[node name="UnusedArgument" type="CheckBox" parent="PanelContainer/TabContainer/Basic/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Unused Argument" + +[node name="ComparisionWithItself" type="CheckBox" parent="PanelContainer/TabContainer/Basic/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Comparision With Itself" + +[node name="Class" type="MarginContainer" parent="PanelContainer/TabContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +script = ExtResource("4_s2mg3") + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/TabContainer/Class"] +layout_mode = 2 + +[node name="PrivateMethodCall" type="CheckBox" parent="PanelContainer/TabContainer/Class/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Private Method Call" + +[node name="ClassDefinitionOrder" type="CheckBox" parent="PanelContainer/TabContainer/Class/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Class Definition Order" + +[node name="Design" type="MarginContainer" parent="PanelContainer/TabContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +script = ExtResource("5_2ncqt") + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/TabContainer/Design"] +layout_mode = 2 + +[node name="MaxPublicMethods" type="CheckBox" parent="PanelContainer/TabContainer/Design/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Max Public Methods" + +[node name="FunctionArgumentNumber" type="CheckBox" parent="PanelContainer/TabContainer/Design/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Function Argument Number" + +[node name="Format" type="MarginContainer" parent="PanelContainer/TabContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +script = ExtResource("6_5fvrg") + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/TabContainer/Format"] +layout_mode = 2 + +[node name="MaxFileLines" type="CheckBox" parent="PanelContainer/TabContainer/Format/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Max File Lines" + +[node name="TrailingWhitespaceCheckBox" type="CheckBox" parent="PanelContainer/TabContainer/Format/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Trailing Whitespace" + +[node name="MaxLineLength" type="CheckBox" parent="PanelContainer/TabContainer/Format/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Max Line Length" + +[node name="MixedTabsAndSpaces" type="CheckBox" parent="PanelContainer/TabContainer/Format/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Mixed Tabs And Spaces" + +[node name="Misc" type="MarginContainer" parent="PanelContainer/TabContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +script = ExtResource("7_l8gkb") + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/TabContainer/Misc"] +layout_mode = 2 + +[node name="NoElifReturn" type="CheckBox" parent="PanelContainer/TabContainer/Misc/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "No Elif Return" + +[node name="NoElseReturn" type="CheckBox" parent="PanelContainer/TabContainer/Misc/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "No Else Return" + +[connection signal="about_to_popup" from="." to="." method="_on_about_to_popup"] +[connection signal="confirmed" from="." to="." method="_on_confirmed"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/FunctionName" to="PanelContainer/TabContainer/Name" method="_on_function_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/ClassName" to="PanelContainer/TabContainer/Name" method="_on_class_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/SubClassName" to="PanelContainer/TabContainer/Name" method="_on_sub_class_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/SignalName" to="PanelContainer/TabContainer/Name" method="_on_signal_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/ClassVariableName" to="PanelContainer/TabContainer/Name" method="_on_class_variable_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/ClassLoadVariableName" to="PanelContainer/TabContainer/Name" method="_on_class_load_variable_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/FunctionVariableName" to="PanelContainer/TabContainer/Name" method="_on_function_variable_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/FunctionPreloadVariableName" to="PanelContainer/TabContainer/Name" method="_on_function_preload_variable_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/FunctionArgumentName" to="PanelContainer/TabContainer/Name" method="_on_function_argument_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/LoopVariableName" to="PanelContainer/TabContainer/Name" method="_on_loop_variable_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/EnumName" to="PanelContainer/TabContainer/Name" method="_on_enum_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/EnumElementName" to="PanelContainer/TabContainer/Name" method="_on_enum_element_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/ConstantName" to="PanelContainer/TabContainer/Name" method="_on_constant_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Name/VBoxContainer/LoadConstantName" to="PanelContainer/TabContainer/Name" method="_on_load_constant_name_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Basic/VBoxContainer/DuplicatedLoad" to="PanelContainer/TabContainer/Basic" method="_on_duplicated_load_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Basic/VBoxContainer/ExpressionNotAssigned" to="PanelContainer/TabContainer/Basic" method="_on_expression_not_assigned_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Basic/VBoxContainer/UnnecessaryPass" to="PanelContainer/TabContainer/Basic" method="_on_unnecessary_pass_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Basic/VBoxContainer/UnusedArgument" to="PanelContainer/TabContainer/Basic" method="_on_unused_argument_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Basic/VBoxContainer/ComparisionWithItself" to="PanelContainer/TabContainer/Basic" method="_on_comparision_with_itself_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Class/VBoxContainer/PrivateMethodCall" to="PanelContainer/TabContainer/Class" method="_on_private_method_call_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Class/VBoxContainer/ClassDefinitionOrder" to="PanelContainer/TabContainer/Class" method="_on_class_definition_order_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Design/VBoxContainer/MaxPublicMethods" to="PanelContainer/TabContainer/Design" method="_on_max_public_methods_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Design/VBoxContainer/FunctionArgumentNumber" to="PanelContainer/TabContainer/Design" method="_on_function_argument_number_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Format/VBoxContainer/MaxFileLines" to="PanelContainer/TabContainer/Format" method="_on_max_file_lines_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Format/VBoxContainer/TrailingWhitespaceCheckBox" to="PanelContainer/TabContainer/Format" method="_on_trailing_whitespace_check_box_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Format/VBoxContainer/MaxLineLength" to="PanelContainer/TabContainer/Format" method="_on_max_line_length_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Format/VBoxContainer/MixedTabsAndSpaces" to="PanelContainer/TabContainer/Format" method="_on_mixed_tabs_and_spaces_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Misc/VBoxContainer/NoElifReturn" to="PanelContainer/TabContainer/Misc" method="_on_no_elif_return_toggled"] +[connection signal="toggled" from="PanelContainer/TabContainer/Misc/VBoxContainer/NoElseReturn" to="PanelContainer/TabContainer/Misc" method="_on_no_else_return_toggled"] diff --git a/addons/gdLinter/UI/Misc.gd b/addons/gdLinter/UI/Misc.gd new file mode 100644 index 0000000..6e6bbe5 --- /dev/null +++ b/addons/gdLinter/UI/Misc.gd @@ -0,0 +1,21 @@ +@tool +extends MarginContainer + +var _owner: GDLinterIgnoreWindow = owner + +@onready var no_elif_return: CheckBox = %NoElifReturn +@onready var no_else_return: CheckBox = %NoElseReturn + + +func init() -> void: + _owner = owner + no_elif_return.button_pressed = _owner.ignore.get("_no_elif_return") + no_else_return.button_pressed = _owner.ignore.get("_no_else_return") + + +func _on_no_elif_return_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_no_elif_return", toggled_on) + + +func _on_no_else_return_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_no_else_return", toggled_on) diff --git a/addons/gdLinter/UI/Name.gd b/addons/gdLinter/UI/Name.gd new file mode 100644 index 0000000..6b3920e --- /dev/null +++ b/addons/gdLinter/UI/Name.gd @@ -0,0 +1,93 @@ +@tool +extends MarginContainer + +var _owner: GDLinterIgnoreWindow = owner + +@onready var function_name: CheckBox = %FunctionName +@onready var sub_class_name: CheckBox = %SubClassName +@onready var signal_name: CheckBox = %SignalName +@onready var class_variable_name: CheckBox = %ClassVariableName +@onready var class_load_variable_name: CheckBox = %ClassLoadVariableName +@onready var function_variable_name: CheckBox = %FunctionVariableName +@onready var function_preload_variable_name: CheckBox = %FunctionPreloadVariableName +@onready var function_argument_name: CheckBox = %FunctionArgumentName +@onready var loop_variable_name: CheckBox = %LoopVariableName +@onready var enum_name: CheckBox = %EnumName +@onready var enum_element_name: CheckBox = %EnumElementName +@onready var constant_name: CheckBox = %ConstantName +@onready var load_constant_name: CheckBox = %LoadConstantName +@onready var _class_name: CheckBox = %ClassName + + +func init() -> void: + _owner = owner + function_name.button_pressed = _owner.ignore.get("_function_name") + _class_name.button_pressed = _owner.ignore.get("_class_name") + sub_class_name.button_pressed = _owner.ignore.get("_sub_class_name") + signal_name.button_pressed = _owner.ignore.get("_signal_name") + class_variable_name.button_pressed = _owner.ignore.get("_class_variable_name") + class_load_variable_name.button_pressed = _owner.ignore.get("_class_load_variable_name") + function_variable_name.button_pressed = _owner.ignore.get("_function_variable_name") + function_preload_variable_name.button_pressed = _owner.ignore.get("_function_preload_variable_name") + function_argument_name.button_pressed = _owner.ignore.get("_function_argument_name") + loop_variable_name.button_pressed = _owner.ignore.get("_loop_variable_name") + enum_name.button_pressed = _owner.ignore.get("_enum_name") + enum_element_name.button_pressed = _owner.ignore.get("_enum_element_name") + constant_name.button_pressed = _owner.ignore.get("_constant_name") + load_constant_name.button_pressed = _owner.ignore.get("_load_constant_name") + + +func _on_function_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_function_name", toggled_on) + + +func _on_class_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_class_name", toggled_on) + + +func _on_sub_class_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_sub_class_name", toggled_on) + + +func _on_signal_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_signal_name", toggled_on) + + +func _on_class_variable_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_class_variable_name", toggled_on) + + +func _on_class_load_variable_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_class_load_variable_name", toggled_on) + + +func _on_function_variable_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_function_variable_name", toggled_on) + + +func _on_function_preload_variable_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_function_preload_variable_name", toggled_on) + + +func _on_function_argument_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_function_argument_name", toggled_on) + + +func _on_loop_variable_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_loop_variable_name", toggled_on) + + +func _on_enum_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_enum_name", toggled_on) + + +func _on_enum_element_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_enum_element_name", toggled_on) + + +func _on_constant_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_constant_name", toggled_on) + + +func _on_load_constant_name_toggled(toggled_on: bool) -> void: + _owner.ignore.set("_load_constant_name", toggled_on) diff --git a/addons/gdLinter/UI/ErrorButton.gd b/addons/gdLinter/error_descriptions.gd similarity index 87% rename from addons/gdLinter/UI/ErrorButton.gd rename to addons/gdLinter/error_descriptions.gd index e48a6c6..684d888 100644 --- a/addons/gdLinter/UI/ErrorButton.gd +++ b/addons/gdLinter/error_descriptions.gd @@ -1,5 +1,4 @@ -@tool -extends Button +extends Resource var error := { #region Name Checks @@ -50,19 +49,3 @@ var error := { "no-else-return": "Validates if unnecessary else is present in case if (and each elif) body was ended with return." #endregion } - -var color: Color = EditorInterface.get_editor_settings()\ -.get_setting("text_editor/theme/highlighting/comment_markers/critical_color") - - -func _ready() -> void: - modulate = color - - icon = EditorInterface.get_editor_theme().get_icon("Error", "EditorIcons") - - var regex = RegEx.new() - regex.compile("(?<=\\()[^\\)]+") - var result := regex.search_all(text) - var error_type := result[-1].strings[0] - if error.has(error_type): - tooltip_text = error[error_type] diff --git a/addons/gdLinter/gdLinter.gd b/addons/gdLinter/gdLinter.gd index 2650621..5b1e5f0 100644 --- a/addons/gdLinter/gdLinter.gd +++ b/addons/gdLinter/gdLinter.gd @@ -1,12 +1,17 @@ @tool +class_name GDLinter extends EditorPlugin const DockScene := preload("res://addons/gdLinter/UI/Dock.tscn") + var icon_error := EditorInterface.get_editor_theme().get_icon("Error", "EditorIcons") var color_error: Color = EditorInterface.get_editor_settings()\ .get_setting("text_editor/theme/highlighting/comment_markers/critical_color") +var icon_error_ignore := EditorInterface.get_editor_theme().get_icon("ErrorWarning", "EditorIcons") +var icon_ignore := EditorInterface.get_editor_theme().get_icon("Warning", "EditorIcons") + var icon_success := EditorInterface.get_editor_theme().get_icon("StatusSuccess", "EditorIcons") var color_success: Color = EditorInterface.get_editor_settings()\ .get_setting("text_editor/theme/highlighting/comment_markers/notice_color") @@ -14,49 +19,48 @@ var color_success: Color = EditorInterface.get_editor_settings()\ var bottom_panel_button: Button var highlight_lines: PackedInt32Array var item_lists: Array[ItemList] +var script_editor: ScriptEditor var _dock_ui: GDLinterDock var _is_gdlint_installed: bool +var _ignore: Resource +var _gdlint_path: String func _enter_tree() -> void: # install the GDLint dock _dock_ui = DockScene.instantiate() + _dock_ui.gd_linter = self bottom_panel_button = add_control_to_bottom_panel(_dock_ui, "GDLint") # connect signal to lint on save resource_saved.connect(on_resource_saved) - await get_tree().create_timer(1.0).timeout # Workaround so the script editor gets loaded - var current_open_script = load(ProjectSettings.globalize_path( - EditorInterface.get_script_editor().get_current_script().resource_path) - ) as Resource - on_resource_saved(current_open_script) - var script_editor := EditorInterface.get_script_editor() + script_editor = EditorInterface.get_script_editor() script_editor.editor_script_changed.connect(_on_editor_script_changed) + _gdlint_path = get_gdlint_path() get_gdlint_version() - - get_item_list(script_editor) - prints("Loading GDLint Plugin success") - +# TODO: Reenable again? # Dunno how highlighting lines in Godot works, since it get removed after a second or so # So I use this evil workaround straight from hell: -func _process(_delta: float) -> void: - if not highlight_lines.is_empty(): - set_line_color(color_error) +#func _process(_delta: float) -> void: + #if not get_current_editor(): + #return + # + #if not highlight_lines.is_empty(): + #set_line_color(color_error) -func _on_editor_script_changed(_script: Script) -> void: - var current_open_script = load(ProjectSettings.globalize_path( - EditorInterface.get_script_editor().get_current_script().resource_path)) as Resource - on_resource_saved(current_open_script) +func _on_editor_script_changed(script: Script) -> void: + _dock_ui.clear_items() + on_resource_saved(script) func get_gdlint_version() -> void: var output := [] - OS.execute("gdlint", ["--version"], output) + OS.execute(_gdlint_path, ["--version"], output) _is_gdlint_installed = true if not output[0].is_empty() else false if _is_gdlint_installed: _dock_ui.version.text = "Using %s" % output[0] @@ -73,8 +77,11 @@ func _exit_tree() -> void: prints("Unload GDLint Plugin success") -func on_resource_saved(resource: Resource): - _dock_ui.delete_errors() +func on_resource_saved(resource: Resource) -> void: + if not resource is GDScript: + return + + _dock_ui.clear_items() clear_highlights() # Show resource path in the GDLint Dock @@ -84,17 +91,26 @@ func on_resource_saved(resource: Resource): var filepath: String = ProjectSettings.globalize_path(resource.resource_path) var gdlint_output: Array = [] var output_array: PackedStringArray - var exit_code = OS.execute("gdlint", [filepath], gdlint_output, true) + var exit_code = OS.execute(_gdlint_path, [filepath], gdlint_output, true) if not exit_code == -1: var output_string: String = gdlint_output[0] output_array = output_string.replace(filepath+":", "Line ").split("\n") + _dock_ui.set_problems_label(_dock_ui.num_problems) + _dock_ui.set_ignored_problems_label(_dock_ui.num_ignored_problems) + + # Workaround until unique name bug is fixed + # https://github.com/Scony/godot-gdscript-toolkit/issues/284 + # Hope I won't break other stuff with it + if output_array[0] == "Line ": + printerr("gdLint Error: ", output_array, "\n File can't be linted!") + return + # When there is no error if output_array.size() <= 2: - print(output_array) - _dock_ui.label.text = output_array[0] - _dock_ui.label.modulate = color_success + bottom_panel_button.add_theme_constant_override(&"icon_max_width", 8) bottom_panel_button.icon = icon_success + return # When errors are found create buttons in the dock else: @@ -103,42 +119,38 @@ func on_resource_saved(resource: Resource): regex.compile("\\d+") var result := regex.search(output_array[i]) var current_line := int(result.strings[0])-1 + var error := output_array[i].rsplit(":", true, 1) + _dock_ui.create_item(current_line+1, error[1]) + if _dock_ui.is_error_ignored(error[1]): + continue highlight_lines.append(current_line) - - var button: Button = _dock_ui.create_error(output_array[i]) - button.pressed.connect(go_to_line.bind(current_line)) - - _dock_ui.label.text = output_array[output_array.size()-2] - _dock_ui.label.modulate = Color(255, 255, 255) - bottom_panel_button.icon = icon_error - _dock_ui.script_text_editor = EditorInterface.get_script_editor().get_current_editor() - - -func go_to_line(line: int) -> void: - var tab_container := _dock_ui.script_text_editor.get_parent() as TabContainer - for index in tab_container.get_child_count(): - if tab_container.get_child(index) == _dock_ui.script_text_editor: - item_lists[0].select(index) - item_lists[0].item_selected.emit(index) + _dock_ui.set_problems_label(_dock_ui.num_problems) + _dock_ui.set_ignored_problems_label(_dock_ui.num_ignored_problems) - var current_code_editor := get_current_editor() - current_code_editor.set_caret_line(line) - - -func get_item_list(node: Node) -> void: - for child: Node in node.get_children(): - if not child is ItemList: - if child is Window: - break - get_item_list(child) - else: - item_lists.append(child) + # Error, no Ignore + if _dock_ui.num_problems > 0 and _dock_ui.num_ignored_problems <= 0: + bottom_panel_button.icon = icon_error + # no Error, Ignore + elif _dock_ui.num_problems <= 0 and _dock_ui.num_ignored_problems > 0: + bottom_panel_button.icon = icon_ignore + # Error, Ignore + elif _dock_ui.num_problems > 0 and _dock_ui.num_ignored_problems > 0: + bottom_panel_button.icon = icon_error_ignore + else: + bottom_panel_button.icon = null + _dock_ui.script_text_editor = EditorInterface.get_script_editor().get_current_editor() func set_line_color(color: Color) -> void: + var current_code_editor := get_current_editor() + if current_code_editor == null: + return + for line: int in highlight_lines: - var current_code_editor := get_current_editor() + # Skip line if this one is from the old code editor + if line > current_code_editor.get_line_count()-1: + continue current_code_editor.set_line_background_color(line, color.darkened(0.5)) @@ -149,4 +161,16 @@ func clear_highlights() -> void: func get_current_editor() -> CodeEdit: - return EditorInterface.get_script_editor().get_current_editor().get_base_editor() as CodeEdit + var current_editor := EditorInterface.get_script_editor().get_current_editor() + if current_editor == null: + return + return current_editor.get_base_editor() as CodeEdit + + +func get_gdlint_path() -> String: + var output := [] + + OS.execute("python3", ["-m", "site", "--user-base"], output) + var python_bin_folder := (output[0] as String).strip_edges().path_join("bin") + + return python_bin_folder.path_join("gdlint") diff --git a/addons/gdLinter/plugin.cfg b/addons/gdLinter/plugin.cfg index 73ff238..586b78c 100644 --- a/addons/gdLinter/plugin.cfg +++ b/addons/gdLinter/plugin.cfg @@ -3,5 +3,5 @@ name="gdLinter" description="Runs `gdlint` on save to automatically lint your GDScript as you code." author="Falli" -version="1.0.1" +version="2.0.0" script="gdLinter.gd"