diff --git a/addons/dialogic/Core/DialogicUtil.gd b/addons/dialogic/Core/DialogicUtil.gd index 8abc1c636..9e95ad589 100644 --- a/addons/dialogic/Core/DialogicUtil.gd +++ b/addons/dialogic/Core/DialogicUtil.gd @@ -682,3 +682,57 @@ static func get_portrait_position_suggestions(search_text := "") -> Dictionary: suggestions.erase(search_text) return suggestions + + +static func get_autoload_suggestions(filter:String="") -> Dictionary: + var suggestions := {} + + for prop in ProjectSettings.get_property_list(): + if prop.name.begins_with('autoload/'): + var autoload: String = prop.name.trim_prefix('autoload/') + suggestions[autoload] = {'value': autoload, 'tooltip':autoload, 'editor_icon': ["Node", "EditorIcons"]} + if filter.begins_with(autoload): + suggestions[filter] = {'value': filter, 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]} + return suggestions + + +static func get_autoload_script_resource(autoload_name:String) -> Script: + var script: Script + if autoload_name and ProjectSettings.has_setting('autoload/'+autoload_name): + var loaded_autoload := load(ProjectSettings.get_setting('autoload/'+autoload_name).trim_prefix('*')) + + if loaded_autoload is PackedScene: + var packed_scene: PackedScene = loaded_autoload + script = packed_scene.instantiate().get_script() + + else: + script = loaded_autoload + return script + + +static func get_autoload_method_suggestions(filter:String, autoload_name:String) -> Dictionary: + var suggestions := {} + + var script := get_autoload_script_resource(autoload_name) + if script: + for script_method in script.get_script_method_list(): + if script_method.name.begins_with('@') or script_method.name.begins_with('_'): + continue + suggestions[script_method.name] = {'value': script_method.name, 'tooltip':script_method.name, 'editor_icon': ["Callable", "EditorIcons"]} + + if not filter.is_empty(): + suggestions[filter] = {'value': filter, 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]} + + return suggestions + + +static func get_autoload_property_suggestions(filter:String, autoload_name:String) -> Dictionary: + var suggestions := {} + var script := get_autoload_script_resource(autoload_name) + if script: + for property in script.get_script_property_list(): + if property.name.ends_with('.gd') or property.name.begins_with('_'): + continue + suggestions[property.name] = {'value': property.name, 'tooltip':property.name, 'editor_icon': ["MemberProperty", "EditorIcons"]} + + return suggestions diff --git a/addons/dialogic/Editor/Events/Fields/field_options_dynamic.gd b/addons/dialogic/Editor/Events/Fields/field_options_dynamic.gd index 16a315f14..836cd2467 100644 --- a/addons/dialogic/Editor/Events/Fields/field_options_dynamic.gd +++ b/addons/dialogic/Editor/Events/Fields/field_options_dynamic.gd @@ -123,11 +123,14 @@ func _on_Search_text_entered(new_text:String) -> void: func _on_Search_text_changed(new_text:String, just_update:bool = false) -> void: %Suggestions.clear() - if new_text == "" and !just_update: + if new_text == "" and not just_update: change_to_empty() else: %Search.show() + if just_update and new_text.is_empty() and %Search.text.ends_with("."): + new_text = %Search.text + var suggestions: Dictionary = get_suggestions_func.call(new_text) var line_length := 0 diff --git a/addons/dialogic/Editor/TimelineEditor/TextEditor/CodeCompletionHelper.gd b/addons/dialogic/Editor/TimelineEditor/TextEditor/CodeCompletionHelper.gd index 8a12cd5e3..fbbcbde0a 100644 --- a/addons/dialogic/Editor/TimelineEditor/TextEditor/CodeCompletionHelper.gd +++ b/addons/dialogic/Editor/TimelineEditor/TextEditor/CodeCompletionHelper.gd @@ -23,9 +23,10 @@ var shortcode_events := {} var custom_syntax_events := [] var text_event: DialogicTextEvent = null + func _ready() -> void: # Compile RegEx's - completion_word_regex.compile("(?(\\W)|^)(?\\w*)\\x{FFFF}") + completion_word_regex.compile(r"(?(\W)|^)(?[\w]*)\x{FFFF}") completion_shortcode_getter_regex.compile("\\[(?\\w*)") completion_shortcode_param_getter_regex.compile("(?\\w*)\\W*=\\s*\"?(\\w|\\s)*"+String.chr(0xFFFF)) completion_shortcode_value_regex.compile(r'(\[|\s)[^\[\s=]*="(?[^"$]*)'+String.chr(0xFFFF)) @@ -172,7 +173,7 @@ func request_code_completion(force:bool, text:CodeEdit, mode:=Modes.FULL_HIGHLIG if mode == Modes.TEXT_EVENT_ONLY and !event is DialogicTextEvent: continue - if ! ' ' in line_part: + if not ' ' in line_part: event._get_start_code_completion(self, text) if event.is_valid_event(line): @@ -182,6 +183,9 @@ func request_code_completion(force:bool, text:CodeEdit, mode:=Modes.FULL_HIGHLIG # Force update and showing of the popup text.update_code_completion_options(true) + # USEFUL FOR DEBUGGING + #print(text.get_code_completion_options().map(func(x):return "{display_text}".format(x))) + # Helper that adds all characters as options @@ -209,7 +213,7 @@ func suggest_labels(text:CodeEdit, timeline:String='', end:='', color:=Color()) # Helper that adds all portraits of a given character as options func suggest_portraits(text:CodeEdit, character_name:String, end_check:=')') -> void: - if !character_name in DialogicResourceUtil.get_character_directory(): + if not character_name in DialogicResourceUtil.get_character_directory(): return var character_resource: DialogicCharacter = load(DialogicResourceUtil.get_character_directory()[character_name]) for portrait in character_resource.portraits: @@ -242,7 +246,9 @@ func suggest_custom_suggestions(suggestions:Dictionary, text:CodeEdit, color:Col # Purpose of the different Kinds is explained in [_request_code_completion] func filter_code_completion_candidates(candidates:Array, text:CodeEdit) -> Array: var valid_candidates := [] + var current_word := get_code_completion_word(text) + for candidate in candidates: if candidate.kind == text.KIND_PLAIN_TEXT: if !current_word.is_empty() and candidate.insert_text.begins_with(current_word): diff --git a/addons/dialogic/Modules/Call/event_call.gd b/addons/dialogic/Modules/Call/event_call.gd index 0f2c05ddc..9a8cf9d81 100644 --- a/addons/dialogic/Modules/Call/event_call.gd +++ b/addons/dialogic/Modules/Call/event_call.gd @@ -139,53 +139,17 @@ func get_shortcode_parameters() -> Dictionary: func build_event_editor() -> void: add_header_edit('autoload_name', ValueType.DYNAMIC_OPTIONS, {'left_text':'On autoload', 'empty_text':'Autoload', - 'suggestions_func':get_autoload_suggestions, + 'suggestions_func': DialogicUtil.get_autoload_suggestions, 'editor_icon':["Node", "EditorIcons"]}) add_header_edit('method', ValueType.DYNAMIC_OPTIONS, {'left_text':'call', 'empty_text':'Method', - 'suggestions_func':get_method_suggestions, + 'suggestions_func': get_method_suggestions, 'editor_icon':["Callable", "EditorIcons"]}, 'autoload_name') add_body_edit('arguments', ValueType.ARRAY, {'left_text':'Arguments:'}, 'not autoload_name.is_empty() and not method.is_empty()') - -func get_autoload_suggestions(filter:String="") -> Dictionary: - var suggestions := {} - - for prop in ProjectSettings.get_property_list(): - if prop.name.begins_with('autoload/'): - var autoload: String = prop.name.trim_prefix('autoload/') - suggestions[autoload] = {'value': autoload, 'tooltip':autoload, 'editor_icon': ["Node", "EditorIcons"]} - if filter.begins_with(autoload): - suggestions[filter] = {'value': filter, 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]} - return suggestions - - -func get_method_suggestions(filter:String="", temp_autoload:String = "") -> Dictionary: - var suggestions := {} - - var script: Script - if temp_autoload and ProjectSettings.has_setting('autoload/'+temp_autoload): - script = load(ProjectSettings.get_setting('autoload/'+temp_autoload).trim_prefix('*')) - - elif autoload_name and ProjectSettings.has_setting('autoload/'+autoload_name): - var loaded_autoload := load(ProjectSettings.get_setting('autoload/'+autoload_name).trim_prefix('*')) - - if loaded_autoload is PackedScene: - var packed_scene: PackedScene = loaded_autoload - script = packed_scene.instantiate().get_script() - - else: - script = loaded_autoload - - if script: - for script_method in script.get_script_method_list(): - if script_method.name.begins_with('@') or script_method.name.begins_with('_'): - continue - suggestions[script_method.name] = {'value': script_method.name, 'tooltip':script_method.name, 'editor_icon': ["Callable", "EditorIcons"]} - if !filter.is_empty(): - suggestions[filter] = {'value': filter, 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]} - return suggestions +func get_method_suggestions(filter:="") -> Dictionary: + return DialogicUtil.get_autoload_method_suggestions(filter, autoload_name) func update_argument_info() -> void: @@ -236,13 +200,21 @@ func check_arguments_and_update_warning() -> void: ####################### CODE COMPLETION ######################################## ################################################################################ -func _get_code_completion(_CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void: +func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, word:String, symbol:String) -> void: + var autoloads := DialogicUtil.get_autoload_suggestions() + var line_until_caret: String = CodeCompletionHelper.get_line_untill_caret(line) + if line.count(' ') == 1 and not '.' in line: - for i in get_autoload_suggestions(): + for i in autoloads: TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, i, i+'.', event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.3), TextNode.get_theme_icon("Node", "EditorIcons")) - elif symbol == '.' and not '(' in line: - for i in get_method_suggestions('', line.get_slice('.', 0).trim_prefix('do ')): - TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, i, i+'(', event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.3), TextNode.get_theme_icon("Callable", "EditorIcons")) + + elif (line_until_caret.ends_with(".") or symbol == "."): + var autoload_name := line_until_caret.split(" ")[-1].split(".")[0] + if autoload_name in autoloads: + var methods := DialogicUtil.get_autoload_method_suggestions("", autoload_name) + for i in methods.keys(): + TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, i, i+'(', event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.3), TextNode.get_theme_icon("MemberMethod", "EditorIcons")) + func _get_start_code_completion(_CodeCompletionHelper:Node, TextNode:TextEdit) -> void: diff --git a/addons/dialogic/Modules/Character/event_character.gd b/addons/dialogic/Modules/Character/event_character.gd index 9c167d6e4..f48ab593c 100644 --- a/addons/dialogic/Modules/Character/event_character.gd +++ b/addons/dialogic/Modules/Character/event_character.gd @@ -478,7 +478,7 @@ func get_fade_suggestions(search_text:String='') -> Dictionary: func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void: var line_until_caret: String = CodeCompletionHelper.get_line_untill_caret(line) - if symbol == ' ' and line_until_caret.count(' ') == 1: + if symbol == ' ' and line_until_caret.split(" ", false).size() == 1: CodeCompletionHelper.suggest_characters(TextNode, CodeEdit.KIND_MEMBER) if line.begins_with('leave'): TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, 'All', '--All-- ', event_color, TextNode.get_theme_icon("GuiEllipsis", "EditorIcons")) @@ -487,7 +487,7 @@ func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:Str var completion_character := regex.search(line).get_string('name') CodeCompletionHelper.suggest_portraits(TextNode, completion_character) - elif not '[' in line_until_caret and symbol == ' ': + elif not '[' in line_until_caret and symbol == ' ' and line_until_caret.split(" ", false).size() > 1: if not line.begins_with("leave"): for position in get_position_suggestions(): TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, position, position+' ', TextNode.syntax_highlighter.normal_color) diff --git a/addons/dialogic/Modules/Variable/event_variable.gd b/addons/dialogic/Modules/Variable/event_variable.gd index 3111bdb9b..f23c347db 100644 --- a/addons/dialogic/Modules/Variable/event_variable.gd +++ b/addons/dialogic/Modules/Variable/event_variable.gd @@ -303,10 +303,26 @@ func build_event_editor() -> void: func get_var_suggestions(filter:String) -> Dictionary: var suggestions := {} - if filter: - suggestions[filter] = {'value':filter, 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]} for var_path in DialogicUtil.list_variables(DialogicUtil.get_default_variables()): suggestions[var_path] = {'value':var_path, 'icon':load("res://addons/dialogic/Editor/Images/Pieces/variable.svg")} + + var autoloads := DialogicUtil.get_autoload_suggestions().keys() + var is_autoload := "" + for autoload in autoloads: + if autoload == filter: + is_autoload = autoload + break + suggestions[autoload] = {'value':autoload, 'editor_icon':["Node", "EditorIcons"]} + + if is_autoload or filter.count(".") == 1 and filter.split(".")[0] in autoloads: + var autoload := filter.trim_suffix(".") + var properties := DialogicUtil.get_autoload_property_suggestions("", autoload) + for property in properties: + suggestions["."+property] = {'value':autoload+"."+property, 'editor_icon':["MemberProperty", "EditorIcons"]} + + if not filter in suggestions: + suggestions[filter] = {'value':filter, 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]} + return suggestions @@ -342,9 +358,22 @@ func update_editor_warning() -> void: ################################################################################ func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void: - if CodeCompletionHelper.get_line_untill_caret(line) == 'set ': + var autoloads := DialogicUtil.get_autoload_suggestions() + var line_until_caret: String = CodeCompletionHelper.get_line_untill_caret(line) + if line_until_caret.count(" ") == 1 and not "{" in line and not line_until_caret.ends_with("."): + TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, '{', '{', TextNode.syntax_highlighter.variable_color) - if symbol == '{': + for i in autoloads: + TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, i, i+'.', event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.3), TextNode.get_theme_icon("Node", "EditorIcons")) + + if (line_until_caret.ends_with(".") or symbol == "."): + var autoload_name := line_until_caret.split(" ")[-1].split(".")[0] + if autoload_name in autoloads: + var properties := DialogicUtil.get_autoload_property_suggestions("", autoload_name) + for i in properties.keys(): + TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, i, i+" ", event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.3), TextNode.get_theme_icon("MemberMethod", "EditorIcons")) + + elif symbol == '{': CodeCompletionHelper.suggest_variables(TextNode)