| 
									
										
										
										
											2023-01-05 13:25:55 +01:00
										 |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*  code_completion.cpp                                                   */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*                         This file is part of:                          */ | 
					
						
							|  |  |  | /*                             GODOT ENGINE                               */ | 
					
						
							|  |  |  | /*                        https://godotengine.org                         */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
					
						
							|  |  |  | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining  */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the        */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including    */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,    */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to     */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to  */ | 
					
						
							|  |  |  | /* the following conditions:                                              */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be         */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.        */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "code_completion.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 19:33:38 -03:00
										 |  |  | #include "core/config/project_settings.h"
 | 
					
						
							| 
									
										
										
										
											2023-09-06 21:02:52 +02:00
										 |  |  | #include "core/object/script_language.h"
 | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | #include "editor/editor_file_system.h"
 | 
					
						
							|  |  |  | #include "editor/editor_settings.h"
 | 
					
						
							|  |  |  | #include "scene/gui/control.h"
 | 
					
						
							|  |  |  | #include "scene/main/node.h"
 | 
					
						
							| 
									
										
										
										
											2022-08-08 19:29:36 +03:00
										 |  |  | #include "scene/theme/theme_db.h"
 | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace gdmono { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Almost everything here is taken from functions used by GDScript for code completion, adapted for C#.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _FORCE_INLINE_ String quoted(const String &p_str) { | 
					
						
							|  |  |  | 	return "\"" + p_str + "\""; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void _add_nodes_suggestions(const Node *p_base, const Node *p_node, PackedStringArray &r_suggestions) { | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 	if (p_node != p_base && !p_node->get_owner()) { | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	String path_relative_to_orig = p_base->get_path_to(p_node); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	r_suggestions.push_back(quoted(path_relative_to_orig)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (int i = 0; i < p_node->get_child_count(); i++) { | 
					
						
							|  |  |  | 		_add_nodes_suggestions(p_base, p_node->get_child(i), r_suggestions); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Node *_find_node_for_script(Node *p_base, Node *p_current, const Ref<Script> &p_script) { | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 	if (p_current->get_owner() != p_base && p_base != p_current) { | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 		return nullptr; | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Ref<Script> c = p_current->get_script(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 	if (c == p_script) { | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 		return p_current; | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (int i = 0; i < p_current->get_child_count(); i++) { | 
					
						
							|  |  |  | 		Node *found = _find_node_for_script(p_base, p_current->get_child(i), p_script); | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 		if (found) { | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 			return found; | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nullptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void _get_directory_contents(EditorFileSystemDirectory *p_dir, PackedStringArray &r_suggestions) { | 
					
						
							|  |  |  | 	for (int i = 0; i < p_dir->get_file_count(); i++) { | 
					
						
							|  |  |  | 		r_suggestions.push_back(quoted(p_dir->get_file_path(i))); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (int i = 0; i < p_dir->get_subdir_count(); i++) { | 
					
						
							|  |  |  | 		_get_directory_contents(p_dir->get_subdir(i), r_suggestions); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Node *_try_find_owner_node_in_tree(const Ref<Script> p_script) { | 
					
						
							|  |  |  | 	SceneTree *tree = SceneTree::get_singleton(); | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 	if (!tree) { | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 		return nullptr; | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 	Node *base = tree->get_edited_scene_root(); | 
					
						
							|  |  |  | 	if (base) { | 
					
						
							|  |  |  | 		base = _find_node_for_script(base, base, p_script); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return base; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_script_file) { | 
					
						
							|  |  |  | 	PackedStringArray suggestions; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (p_kind) { | 
					
						
							|  |  |  | 		case CompletionKind::INPUT_ACTIONS: { | 
					
						
							|  |  |  | 			List<PropertyInfo> project_props; | 
					
						
							|  |  |  | 			ProjectSettings::get_singleton()->get_property_list(&project_props); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 15:46:25 +02:00
										 |  |  | 			for (const PropertyInfo &prop : project_props) { | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 				if (!prop.name.begins_with("input/")) { | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 					continue; | 
					
						
							| 
									
										
										
										
											2020-07-05 19:19:36 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				String name = prop.name.substr(prop.name.find("/") + 1, prop.name.length()); | 
					
						
							|  |  |  | 				suggestions.push_back(quoted(name)); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 		case CompletionKind::NODE_PATHS: { | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2022-03-09 15:03:03 +08:00
										 |  |  | 				// Autoloads.
 | 
					
						
							| 
									
										
										
										
											2022-05-08 10:09:19 +02:00
										 |  |  | 				HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); | 
					
						
							| 
									
										
										
										
											2020-06-17 20:45:08 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-08 10:09:19 +02:00
										 |  |  | 				for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) { | 
					
						
							|  |  |  | 					const ProjectSettings::AutoloadInfo &info = E.value; | 
					
						
							| 
									
										
										
										
											2020-06-17 20:45:08 -03:00
										 |  |  | 					suggestions.push_back(quoted("/root/" + String(info.name))); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				// Current edited scene tree
 | 
					
						
							|  |  |  | 				Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path()); | 
					
						
							|  |  |  | 				Node *base = _try_find_owner_node_in_tree(script); | 
					
						
							|  |  |  | 				if (base) { | 
					
						
							|  |  |  | 					_add_nodes_suggestions(base, base, suggestions); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 		case CompletionKind::RESOURCE_PATHS: { | 
					
						
							| 
									
										
										
										
											2022-10-18 16:43:37 +02:00
										 |  |  | 			if (bool(EDITOR_GET("text_editor/completion/complete_file_paths"))) { | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 				_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), suggestions); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 		case CompletionKind::SCENE_PATHS: { | 
					
						
							| 
									
										
										
										
											2022-03-23 11:08:58 +02:00
										 |  |  | 			Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 			List<String> directories; | 
					
						
							|  |  |  | 			directories.push_back(dir_access->get_current_dir()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 12:04:21 +00:00
										 |  |  | 			while (!directories.is_empty()) { | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 				dir_access->change_dir(directories.back()->get()); | 
					
						
							|  |  |  | 				directories.pop_back(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				dir_access->list_dir_begin(); | 
					
						
							|  |  |  | 				String filename = dir_access->get_next(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-09 03:42:46 -06:00
										 |  |  | 				while (!filename.is_empty()) { | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 					if (filename == "." || filename == "..") { | 
					
						
							|  |  |  | 						filename = dir_access->get_next(); | 
					
						
							|  |  |  | 						continue; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if (dir_access->dir_exists(filename)) { | 
					
						
							| 
									
										
										
										
											2022-08-29 19:34:01 -05:00
										 |  |  | 						directories.push_back(dir_access->get_current_dir().path_join(filename)); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 					} else if (filename.ends_with(".tscn") || filename.ends_with(".scn")) { | 
					
						
							| 
									
										
										
										
											2022-08-29 19:34:01 -05:00
										 |  |  | 						suggestions.push_back(quoted(dir_access->get_current_dir().path_join(filename))); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					filename = dir_access->get_next(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 		case CompletionKind::SHADER_PARAMS: { | 
					
						
							| 
									
										
										
										
											2022-04-03 19:09:09 +02:00
										 |  |  | 			print_verbose("Shader uniforms completion for C# is not implemented yet."); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case CompletionKind::SIGNALS: { | 
					
						
							|  |  |  | 			Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			List<MethodInfo> signals; | 
					
						
							|  |  |  | 			script->get_script_signal_list(&signals); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			StringName native = script->get_instance_base_type(); | 
					
						
							|  |  |  | 			if (native != StringName()) { | 
					
						
							|  |  |  | 				ClassDB::get_signal_list(native, &signals, /* p_no_inheritance: */ false); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 15:46:25 +02:00
										 |  |  | 			for (const MethodInfo &E : signals) { | 
					
						
							| 
									
										
										
										
											2021-07-15 23:45:57 -04:00
										 |  |  | 				const String &signal = E.name; | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 				suggestions.push_back(quoted(signal)); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 		case CompletionKind::THEME_COLORS: { | 
					
						
							|  |  |  | 			Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path()); | 
					
						
							|  |  |  | 			Node *base = _try_find_owner_node_in_tree(script); | 
					
						
							|  |  |  | 			if (base && Object::cast_to<Control>(base)) { | 
					
						
							|  |  |  | 				List<StringName> sn; | 
					
						
							| 
									
										
										
										
											2022-08-08 19:29:36 +03:00
										 |  |  | 				ThemeDB::get_singleton()->get_default_theme()->get_color_list(base->get_class(), &sn); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 15:46:25 +02:00
										 |  |  | 				for (const StringName &E : sn) { | 
					
						
							| 
									
										
										
										
											2021-07-15 23:45:57 -04:00
										 |  |  | 					suggestions.push_back(quoted(E)); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 		case CompletionKind::THEME_CONSTANTS: { | 
					
						
							|  |  |  | 			Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path()); | 
					
						
							|  |  |  | 			Node *base = _try_find_owner_node_in_tree(script); | 
					
						
							|  |  |  | 			if (base && Object::cast_to<Control>(base)) { | 
					
						
							|  |  |  | 				List<StringName> sn; | 
					
						
							| 
									
										
										
										
											2022-08-08 19:29:36 +03:00
										 |  |  | 				ThemeDB::get_singleton()->get_default_theme()->get_constant_list(base->get_class(), &sn); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 15:46:25 +02:00
										 |  |  | 				for (const StringName &E : sn) { | 
					
						
							| 
									
										
										
										
											2021-07-15 23:45:57 -04:00
										 |  |  | 					suggestions.push_back(quoted(E)); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 		case CompletionKind::THEME_FONTS: { | 
					
						
							|  |  |  | 			Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path()); | 
					
						
							|  |  |  | 			Node *base = _try_find_owner_node_in_tree(script); | 
					
						
							|  |  |  | 			if (base && Object::cast_to<Control>(base)) { | 
					
						
							|  |  |  | 				List<StringName> sn; | 
					
						
							| 
									
										
										
										
											2022-08-08 19:29:36 +03:00
										 |  |  | 				ThemeDB::get_singleton()->get_default_theme()->get_font_list(base->get_class(), &sn); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 15:46:25 +02:00
										 |  |  | 				for (const StringName &E : sn) { | 
					
						
							| 
									
										
										
										
											2021-07-15 23:45:57 -04:00
										 |  |  | 					suggestions.push_back(quoted(E)); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							| 
									
										
										
										
											2020-09-03 14:22:16 +03:00
										 |  |  | 		case CompletionKind::THEME_FONT_SIZES: { | 
					
						
							|  |  |  | 			Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path()); | 
					
						
							|  |  |  | 			Node *base = _try_find_owner_node_in_tree(script); | 
					
						
							|  |  |  | 			if (base && Object::cast_to<Control>(base)) { | 
					
						
							|  |  |  | 				List<StringName> sn; | 
					
						
							| 
									
										
										
										
											2022-08-08 19:29:36 +03:00
										 |  |  | 				ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(base->get_class(), &sn); | 
					
						
							| 
									
										
										
										
											2020-09-03 14:22:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 15:46:25 +02:00
										 |  |  | 				for (const StringName &E : sn) { | 
					
						
							| 
									
										
										
										
											2021-07-15 23:45:57 -04:00
										 |  |  | 					suggestions.push_back(quoted(E)); | 
					
						
							| 
									
										
										
										
											2020-09-03 14:22:16 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 		case CompletionKind::THEME_STYLES: { | 
					
						
							|  |  |  | 			Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path()); | 
					
						
							|  |  |  | 			Node *base = _try_find_owner_node_in_tree(script); | 
					
						
							|  |  |  | 			if (base && Object::cast_to<Control>(base)) { | 
					
						
							|  |  |  | 				List<StringName> sn; | 
					
						
							| 
									
										
										
										
											2022-08-08 19:29:36 +03:00
										 |  |  | 				ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(base->get_class(), &sn); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 15:46:25 +02:00
										 |  |  | 				for (const StringName &E : sn) { | 
					
						
							| 
									
										
										
										
											2021-07-15 23:45:57 -04:00
										 |  |  | 					suggestions.push_back(quoted(E)); | 
					
						
							| 
									
										
										
										
											2020-05-09 20:45:43 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			ERR_FAIL_V_MSG(suggestions, "Invalid completion kind."); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return suggestions; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | } // namespace gdmono
 |