2014-02-10 02:10:30 +01:00
/**************************************************************************/
/* script_editor_plugin.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. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "script_editor_plugin.h"
2017-01-16 08:04:19 +01:00
2020-11-07 23:33:38 +01:00
# include "core/config/project_settings.h"
2020-04-28 15:19:37 +02:00
# include "core/input/input.h"
2021-06-11 14:51:48 +02:00
# include "core/io/file_access.h"
2023-01-28 15:05:23 +01:00
# include "core/io/json.h"
2017-08-26 17:46:49 +02:00
# include "core/io/resource_loader.h"
# include "core/os/keyboard.h"
# include "core/os/os.h"
2022-02-17 18:16:11 +01:00
# include "core/version.h"
2024-02-18 03:16:58 +01:00
# include "editor/code_editor.h"
2020-02-07 02:52:05 +01:00
# include "editor/debugger/editor_debugger_node.h"
2021-07-20 13:24:56 +02:00
# include "editor/debugger/script_editor_debugger.h"
2022-11-02 15:23:25 +01:00
# include "editor/editor_command_palette.h"
2022-11-19 12:45:49 +01:00
# include "editor/editor_help_search.h"
2022-11-02 15:23:25 +01:00
# include "editor/editor_interface.h"
2017-03-05 14:21:25 +01:00
# include "editor/editor_node.h"
2022-07-29 02:36:26 +02:00
# include "editor/editor_paths.h"
2023-04-12 21:02:28 +02:00
# include "editor/editor_script.h"
2017-03-05 14:21:25 +01:00
# include "editor/editor_settings.h"
2023-08-13 02:33:39 +02:00
# include "editor/editor_string_names.h"
2019-12-24 08:17:23 +01:00
# include "editor/filesystem_dock.h"
2018-02-12 02:36:15 +01:00
# include "editor/find_in_files.h"
2024-01-30 23:22:22 +01:00
# include "editor/gui/editor_bottom_panel.h"
2023-04-07 18:59:49 +02:00
# include "editor/gui/editor_file_dialog.h"
2023-04-12 21:02:28 +02:00
# include "editor/gui/editor_run_bar.h"
2023-08-26 20:38:29 +02:00
# include "editor/gui/editor_toaster.h"
2022-11-19 12:45:49 +01:00
# include "editor/inspector_dock.h"
2017-08-26 17:46:49 +02:00
# include "editor/node_dock.h"
2018-10-27 17:24:41 +02:00
# include "editor/plugins/shader_editor_plugin.h"
2022-09-03 06:15:21 +02:00
# include "editor/plugins/text_shader_editor.h"
2024-01-15 13:14:55 +01:00
# include "editor/themes/editor_scale.h"
2024-02-24 00:06:15 +01:00
# include "editor/themes/editor_theme_manager.h"
2022-11-02 15:23:25 +01:00
# include "editor/window_wrapper.h"
# include "scene/main/node.h"
2020-03-04 02:51:12 +01:00
# include "scene/main/window.h"
2019-10-10 22:19:47 +02:00
# include "scene/scene_string_names.h"
2018-02-12 02:36:15 +01:00
# include "script_text_editor.h"
2020-03-03 14:36:29 +01:00
# include "servers/display_server.h"
2019-08-07 08:41:10 +02:00
# include "text_editor.h"
2017-08-26 17:46:49 +02:00
2020-05-03 18:08:15 +02:00
/*** SYNTAX HIGHLIGHTER ****/
String EditorSyntaxHighlighter : : _get_name ( ) const {
2022-10-18 18:47:44 +02:00
String ret = " Unnamed " ;
GDVIRTUAL_CALL ( _get_name , ret ) ;
return ret ;
2020-05-03 18:08:15 +02:00
}
2022-08-05 03:41:48 +02:00
PackedStringArray EditorSyntaxHighlighter : : _get_supported_languages ( ) const {
PackedStringArray ret ;
2022-10-18 18:47:44 +02:00
GDVIRTUAL_CALL ( _get_supported_languages , ret ) ;
return ret ;
2020-05-03 18:08:15 +02:00
}
Ref < EditorSyntaxHighlighter > EditorSyntaxHighlighter : : _create ( ) const {
Ref < EditorSyntaxHighlighter > syntax_highlighter ;
2021-06-18 00:03:09 +02:00
syntax_highlighter . instantiate ( ) ;
2020-05-03 18:08:15 +02:00
if ( get_script_instance ( ) ) {
syntax_highlighter - > set_script ( get_script_instance ( ) - > get_script ( ) ) ;
}
return syntax_highlighter ;
}
void EditorSyntaxHighlighter : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " _get_edited_resource " ) , & EditorSyntaxHighlighter : : _get_edited_resource ) ;
2021-08-22 03:52:44 +02:00
GDVIRTUAL_BIND ( _get_name )
GDVIRTUAL_BIND ( _get_supported_languages )
2020-05-03 18:08:15 +02:00
}
////
void EditorStandardSyntaxHighlighter : : _update_cache ( ) {
highlighter - > set_text_edit ( text_edit ) ;
highlighter - > clear_keyword_colors ( ) ;
highlighter - > clear_member_keyword_colors ( ) ;
highlighter - > clear_color_regions ( ) ;
2021-08-15 19:14:46 +02:00
highlighter - > set_symbol_color ( EDITOR_GET ( " text_editor/theme/highlighting/symbol_color " ) ) ;
highlighter - > set_function_color ( EDITOR_GET ( " text_editor/theme/highlighting/function_color " ) ) ;
highlighter - > set_number_color ( EDITOR_GET ( " text_editor/theme/highlighting/number_color " ) ) ;
highlighter - > set_member_variable_color ( EDITOR_GET ( " text_editor/theme/highlighting/member_variable_color " ) ) ;
2020-05-03 18:08:15 +02:00
/* Engine types. */
2021-08-15 19:14:46 +02:00
const Color type_color = EDITOR_GET ( " text_editor/theme/highlighting/engine_type_color " ) ;
2020-05-03 18:08:15 +02:00
List < StringName > types ;
ClassDB : : get_class_list ( & types ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & E : types ) {
2021-08-17 15:06:54 +02:00
highlighter - > add_keyword_color ( E , type_color ) ;
2020-05-03 18:08:15 +02:00
}
/* User types. */
2021-08-15 19:14:46 +02:00
const Color usertype_color = EDITOR_GET ( " text_editor/theme/highlighting/user_type_color " ) ;
2020-05-03 18:08:15 +02:00
List < StringName > global_classes ;
ScriptServer : : get_global_class_list ( & global_classes ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & E : global_classes ) {
2021-07-16 05:45:57 +02:00
highlighter - > add_keyword_color ( E , usertype_color ) ;
2020-05-03 18:08:15 +02:00
}
/* Autoloads. */
2022-05-08 10:09:19 +02:00
HashMap < StringName , ProjectSettings : : AutoloadInfo > autoloads = ProjectSettings : : get_singleton ( ) - > get_autoload_list ( ) ;
for ( const KeyValue < StringName , ProjectSettings : : AutoloadInfo > & E : autoloads ) {
const ProjectSettings : : AutoloadInfo & info = E . value ;
2020-05-03 18:08:15 +02:00
if ( info . is_singleton ) {
highlighter - > add_keyword_color ( info . name , usertype_color ) ;
}
}
2024-03-24 18:09:07 +01:00
const ScriptLanguage * scr_lang = script_language ;
StringName instance_base ;
if ( scr_lang = = nullptr ) {
const Ref < Script > scr = _get_edited_resource ( ) ;
if ( scr . is_valid ( ) ) {
scr_lang = scr - > get_language ( ) ;
instance_base = scr - > get_instance_base_type ( ) ;
}
}
if ( scr_lang ! = nullptr ) {
2020-05-03 18:08:15 +02:00
/* Core types. */
2021-08-15 19:14:46 +02:00
const Color basetype_color = EDITOR_GET ( " text_editor/theme/highlighting/base_type_color " ) ;
2020-05-03 18:08:15 +02:00
List < String > core_types ;
2024-03-24 18:09:07 +01:00
scr_lang - > get_core_type_words ( & core_types ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : core_types ) {
2021-07-16 05:45:57 +02:00
highlighter - > add_keyword_color ( E , basetype_color ) ;
2020-05-03 18:08:15 +02:00
}
/* Reserved words. */
2021-08-15 19:14:46 +02:00
const Color keyword_color = EDITOR_GET ( " text_editor/theme/highlighting/keyword_color " ) ;
const Color control_flow_keyword_color = EDITOR_GET ( " text_editor/theme/highlighting/control_flow_keyword_color " ) ;
2020-05-03 18:08:15 +02:00
List < String > keywords ;
2024-03-24 18:09:07 +01:00
scr_lang - > get_reserved_words ( & keywords ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : keywords ) {
2024-03-24 18:09:07 +01:00
if ( scr_lang - > is_control_flow_keyword ( E ) ) {
2021-07-16 05:45:57 +02:00
highlighter - > add_keyword_color ( E , control_flow_keyword_color ) ;
2021-04-08 16:12:22 +02:00
} else {
2021-07-16 05:45:57 +02:00
highlighter - > add_keyword_color ( E , keyword_color ) ;
2021-04-08 16:12:22 +02:00
}
2020-05-03 18:08:15 +02:00
}
/* Member types. */
2021-08-15 19:14:46 +02:00
const Color member_variable_color = EDITOR_GET ( " text_editor/theme/highlighting/member_variable_color " ) ;
2020-05-03 18:08:15 +02:00
if ( instance_base ! = StringName ( ) ) {
List < PropertyInfo > plist ;
ClassDB : : get_property_list ( instance_base , & plist ) ;
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : plist ) {
2022-09-29 11:53:28 +02:00
String prop_name = E . name ;
2021-07-16 05:45:57 +02:00
if ( E . usage & PROPERTY_USAGE_CATEGORY | | E . usage & PROPERTY_USAGE_GROUP | | E . usage & PROPERTY_USAGE_SUBGROUP ) {
2020-05-03 18:08:15 +02:00
continue ;
}
2022-09-29 11:53:28 +02:00
if ( prop_name . contains ( " / " ) ) {
2020-05-03 18:08:15 +02:00
continue ;
}
2022-09-29 11:53:28 +02:00
highlighter - > add_member_keyword_color ( prop_name , member_variable_color ) ;
2020-05-03 18:08:15 +02:00
}
List < String > clist ;
ClassDB : : get_integer_constant_list ( instance_base , & clist ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : clist ) {
2021-07-16 05:45:57 +02:00
highlighter - > add_member_keyword_color ( E , member_variable_color ) ;
2020-05-03 18:08:15 +02:00
}
}
/* Comments */
2021-08-15 19:14:46 +02:00
const Color comment_color = EDITOR_GET ( " text_editor/theme/highlighting/comment_color " ) ;
2020-05-03 18:08:15 +02:00
List < String > comments ;
2024-03-24 18:09:07 +01:00
scr_lang - > get_comment_delimiters ( & comments ) ;
2021-07-24 15:46:25 +02:00
for ( const String & comment : comments ) {
2020-05-03 18:08:15 +02:00
String beg = comment . get_slice ( " " , 0 ) ;
String end = comment . get_slice_count ( " " ) > 1 ? comment . get_slice ( " " , 1 ) : String ( ) ;
2021-12-09 10:42:46 +01:00
highlighter - > add_color_region ( beg , end , comment_color , end . is_empty ( ) ) ;
2020-05-03 18:08:15 +02:00
}
2023-02-05 10:01:01 +01:00
/* Doc comments */
const Color doc_comment_color = EDITOR_GET ( " text_editor/theme/highlighting/doc_comment_color " ) ;
List < String > doc_comments ;
2024-03-24 18:09:07 +01:00
scr_lang - > get_doc_comment_delimiters ( & doc_comments ) ;
2023-02-05 10:01:01 +01:00
for ( const String & doc_comment : doc_comments ) {
String beg = doc_comment . get_slice ( " " , 0 ) ;
String end = doc_comment . get_slice_count ( " " ) > 1 ? doc_comment . get_slice ( " " , 1 ) : String ( ) ;
highlighter - > add_color_region ( beg , end , doc_comment_color , end . is_empty ( ) ) ;
}
2020-05-03 18:08:15 +02:00
/* Strings */
2021-08-15 19:14:46 +02:00
const Color string_color = EDITOR_GET ( " text_editor/theme/highlighting/string_color " ) ;
2020-05-03 18:08:15 +02:00
List < String > strings ;
2024-03-24 18:09:07 +01:00
scr_lang - > get_string_delimiters ( & strings ) ;
2021-07-24 15:46:25 +02:00
for ( const String & string : strings ) {
2020-05-03 18:08:15 +02:00
String beg = string . get_slice ( " " , 0 ) ;
String end = string . get_slice_count ( " " ) > 1 ? string . get_slice ( " " , 1 ) : String ( ) ;
2021-12-09 10:42:46 +01:00
highlighter - > add_color_region ( beg , end , string_color , end . is_empty ( ) ) ;
2020-05-03 18:08:15 +02:00
}
}
}
Ref < EditorSyntaxHighlighter > EditorStandardSyntaxHighlighter : : _create ( ) const {
Ref < EditorStandardSyntaxHighlighter > syntax_highlighter ;
2021-06-18 00:03:09 +02:00
syntax_highlighter . instantiate ( ) ;
2020-05-03 18:08:15 +02:00
return syntax_highlighter ;
}
////
Ref < EditorSyntaxHighlighter > EditorPlainTextSyntaxHighlighter : : _create ( ) const {
Ref < EditorPlainTextSyntaxHighlighter > syntax_highlighter ;
2021-06-18 00:03:09 +02:00
syntax_highlighter . instantiate ( ) ;
2020-05-03 18:08:15 +02:00
return syntax_highlighter ;
}
2023-01-28 15:05:23 +01:00
////
void EditorJSONSyntaxHighlighter : : _update_cache ( ) {
highlighter - > set_text_edit ( text_edit ) ;
highlighter - > clear_keyword_colors ( ) ;
highlighter - > clear_member_keyword_colors ( ) ;
highlighter - > clear_color_regions ( ) ;
highlighter - > set_symbol_color ( EDITOR_GET ( " text_editor/theme/highlighting/symbol_color " ) ) ;
highlighter - > set_number_color ( EDITOR_GET ( " text_editor/theme/highlighting/number_color " ) ) ;
const Color string_color = EDITOR_GET ( " text_editor/theme/highlighting/string_color " ) ;
highlighter - > add_color_region ( " \" " , " \" " , string_color ) ;
}
Ref < EditorSyntaxHighlighter > EditorJSONSyntaxHighlighter : : _create ( ) const {
Ref < EditorJSONSyntaxHighlighter > syntax_highlighter ;
syntax_highlighter . instantiate ( ) ;
return syntax_highlighter ;
}
2020-05-03 18:08:15 +02:00
////////////////////////////////////////////////////////////////////////////////
2015-06-22 05:03:19 +02:00
/*** SCRIPT EDITOR ****/
2014-02-10 02:10:30 +01:00
2016-09-12 15:52:29 +02:00
void ScriptEditorBase : : _bind_methods ( ) {
2021-05-13 21:50:25 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_base_editor " ) , & ScriptEditorBase : : get_base_editor ) ;
2021-10-11 19:13:31 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_syntax_highlighter " , " highlighter " ) , & ScriptEditorBase : : add_syntax_highlighter ) ;
2021-05-13 21:50:25 +02:00
2016-09-12 15:52:29 +02:00
ADD_SIGNAL ( MethodInfo ( " name_changed " ) ) ;
2017-08-29 12:00:37 +02:00
ADD_SIGNAL ( MethodInfo ( " edited_script_changed " ) ) ;
2017-12-11 00:56:49 +01:00
ADD_SIGNAL ( MethodInfo ( " request_help " , PropertyInfo ( Variant : : STRING , " topic " ) ) ) ;
2016-09-12 15:52:29 +02:00
ADD_SIGNAL ( MethodInfo ( " request_open_script_at_line " , PropertyInfo ( Variant : : OBJECT , " script " ) , PropertyInfo ( Variant : : INT , " line " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " request_save_history " ) ) ;
2022-10-22 23:54:37 +02:00
ADD_SIGNAL ( MethodInfo ( " request_save_previous_state " , PropertyInfo ( Variant : : INT , " line " ) ) ) ;
2016-09-12 15:52:29 +02:00
ADD_SIGNAL ( MethodInfo ( " go_to_help " , PropertyInfo ( Variant : : STRING , " what " ) ) ) ;
2018-02-12 02:36:15 +01:00
ADD_SIGNAL ( MethodInfo ( " search_in_files_requested " , PropertyInfo ( Variant : : STRING , " text " ) ) ) ;
2020-02-09 10:10:58 +01:00
ADD_SIGNAL ( MethodInfo ( " replace_in_files_requested " , PropertyInfo ( Variant : : STRING , " text " ) ) ) ;
2022-09-09 16:36:07 +02:00
ADD_SIGNAL ( MethodInfo ( " go_to_method " , PropertyInfo ( Variant : : OBJECT , " script " ) , PropertyInfo ( Variant : : STRING , " method " ) ) ) ;
2016-09-12 15:52:29 +02:00
}
2015-06-26 06:14:31 +02:00
class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache {
struct Cache {
2020-11-24 10:12:55 +01:00
uint64_t time_loaded = 0 ;
2022-05-03 01:43:50 +02:00
Ref < Resource > cache ;
2015-06-26 06:14:31 +02:00
} ;
2022-05-13 15:04:37 +02:00
HashMap < String , Cache > cached ;
2015-06-26 06:14:31 +02:00
public :
2020-11-24 10:12:55 +01:00
uint64_t max_time_cache = 5 * 60 * 1000 ; //minutes, five
2022-05-13 15:04:37 +02:00
uint32_t max_cache_size = 128 ;
2015-06-26 06:14:31 +02:00
void cleanup ( ) {
2022-05-13 15:04:37 +02:00
List < String > to_clean ;
2015-06-26 06:14:31 +02:00
2022-05-13 15:04:37 +02:00
HashMap < String , Cache > : : Iterator I = cached . begin ( ) ;
2015-06-26 06:14:31 +02:00
while ( I ) {
2022-05-13 15:04:37 +02:00
if ( ( OS : : get_singleton ( ) - > get_ticks_msec ( ) - I - > value . time_loaded ) > max_time_cache ) {
to_clean . push_back ( I - > key ) ;
2015-06-26 06:14:31 +02:00
}
2022-05-13 15:04:37 +02:00
+ + I ;
2015-06-26 06:14:31 +02:00
}
while ( to_clean . front ( ) ) {
cached . erase ( to_clean . front ( ) - > get ( ) ) ;
to_clean . pop_front ( ) ;
}
}
2022-05-03 01:43:50 +02:00
virtual Ref < Resource > get_cached_resource ( const String & p_path ) {
2022-05-13 15:04:37 +02:00
HashMap < String , Cache > : : Iterator E = cached . find ( p_path ) ;
2015-06-26 06:14:31 +02:00
if ( ! E ) {
Cache c ;
c . cache = ResourceLoader : : load ( p_path ) ;
E = cached . insert ( p_path , c ) ;
}
2022-05-13 15:04:37 +02:00
E - > value . time_loaded = OS : : get_singleton ( ) - > get_ticks_msec ( ) ;
2015-06-26 06:14:31 +02:00
if ( cached . size ( ) > max_cache_size ) {
uint64_t older ;
2022-05-13 15:04:37 +02:00
HashMap < String , Cache > : : Iterator O = cached . begin ( ) ;
older = O - > value . time_loaded ;
HashMap < String , Cache > : : Iterator I = O ;
2015-06-26 06:14:31 +02:00
while ( I ) {
2022-05-13 15:04:37 +02:00
if ( I - > value . time_loaded < older ) {
older = I - > value . time_loaded ;
2015-06-26 06:14:31 +02:00
O = I ;
}
2022-05-13 15:04:37 +02:00
+ + I ;
2015-06-26 06:14:31 +02:00
}
2017-12-18 18:46:17 +01:00
if ( O ! = E ) { //should never happen..
2022-05-13 15:04:37 +02:00
cached . remove ( O ) ;
2015-06-26 06:14:31 +02:00
}
}
2022-05-13 15:04:37 +02:00
return E - > value . cache ;
2015-06-26 06:14:31 +02:00
}
2018-10-02 12:07:44 +02:00
virtual ~ EditorScriptCodeCompletionCache ( ) { }
2015-06-26 06:14:31 +02:00
} ;
2018-10-02 12:07:44 +02:00
void ScriptEditorQuickOpen : : popup_dialog ( const Vector < String > & p_functions , bool p_dontclear ) {
2014-02-10 02:10:30 +01:00
popup_centered_ratio ( 0.6 ) ;
2020-05-14 16:41:43 +02:00
if ( p_dontclear ) {
2014-02-10 02:10:30 +01:00
search_box - > select_all ( ) ;
2020-05-14 16:41:43 +02:00
} else {
2014-02-10 02:10:30 +01:00
search_box - > clear ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
search_box - > grab_focus ( ) ;
functions = p_functions ;
_update_search ( ) ;
}
void ScriptEditorQuickOpen : : _text_changed ( const String & p_newtext ) {
_update_search ( ) ;
}
2017-05-20 17:38:03 +02:00
void ScriptEditorQuickOpen : : _sbox_input ( const Ref < InputEvent > & p_ie ) {
Ref < InputEventKey > k = p_ie ;
2014-02-10 02:10:30 +01:00
2021-08-13 23:31:57 +02:00
if ( k . is_valid ( ) & & ( k - > get_keycode ( ) = = Key : : UP | | k - > get_keycode ( ) = = Key : : DOWN | | k - > get_keycode ( ) = = Key : : PAGEUP | | k - > get_keycode ( ) = = Key : : PAGEDOWN ) ) {
2021-08-22 17:37:22 +02:00
search_options - > gui_input ( k ) ;
2014-02-10 02:10:30 +01:00
search_box - > accept_event ( ) ;
}
}
void ScriptEditorQuickOpen : : _update_search ( ) {
search_options - > clear ( ) ;
TreeItem * root = search_options - > create_item ( ) ;
for ( int i = 0 ; i < functions . size ( ) ; i + + ) {
String file = functions [ i ] ;
2021-12-09 10:42:46 +01:00
if ( ( search_box - > get_text ( ) . is_empty ( ) | | file . findn ( search_box - > get_text ( ) ) ! = - 1 ) ) {
2014-02-10 02:10:30 +01:00
TreeItem * ti = search_options - > create_item ( root ) ;
ti - > set_text ( 0 , file ) ;
2021-03-07 21:07:30 +01:00
if ( root - > get_first_child ( ) = = ti ) {
2014-02-10 02:10:30 +01:00
ti - > select ( 0 ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2021-03-07 21:07:30 +01:00
get_ok_button ( ) - > set_disabled ( root - > get_first_child ( ) = = nullptr ) ;
2014-02-10 02:10:30 +01:00
}
void ScriptEditorQuickOpen : : _confirmed ( ) {
TreeItem * ti = search_options - > get_selected ( ) ;
2020-05-14 16:41:43 +02:00
if ( ! ti ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
int line = ti - > get_text ( 0 ) . get_slice ( " : " , 1 ) . to_int ( ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " goto_line " ) , line - 1 ) ;
2014-02-10 02:10:30 +01:00
hide ( ) ;
}
void ScriptEditorQuickOpen : : _notification ( int p_what ) {
2017-07-26 16:02:53 +02:00
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
2020-02-21 18:28:45 +01:00
connect ( " confirmed " , callable_mp ( this , & ScriptEditorQuickOpen : : _confirmed ) ) ;
2018-07-26 13:45:38 +02:00
search_box - > set_clear_button_enabled ( true ) ;
2022-08-29 11:04:31 +02:00
[[fallthrough]] ;
}
case NOTIFICATION_VISIBILITY_CHANGED : {
2023-08-13 02:33:39 +02:00
search_box - > set_right_icon ( search_options - > get_editor_theme_icon ( SNAME ( " Search " ) ) ) ;
2017-07-26 16:02:53 +02:00
} break ;
2022-02-16 03:44:22 +01:00
2018-11-05 03:45:25 +01:00
case NOTIFICATION_EXIT_TREE : {
2020-02-21 18:28:45 +01:00
disconnect ( " confirmed " , callable_mp ( this , & ScriptEditorQuickOpen : : _confirmed ) ) ;
2018-11-05 03:45:25 +01:00
} break ;
2014-02-10 02:10:30 +01:00
}
}
void ScriptEditorQuickOpen : : _bind_methods ( ) {
ADD_SIGNAL ( MethodInfo ( " goto_line " , PropertyInfo ( Variant : : INT , " line " ) ) ) ;
}
ScriptEditorQuickOpen : : ScriptEditorQuickOpen ( ) {
VBoxContainer * vbc = memnew ( VBoxContainer ) ;
add_child ( vbc ) ;
search_box = memnew ( LineEdit ) ;
2016-05-04 03:25:37 +02:00
vbc - > add_margin_child ( TTR ( " Search: " ) , search_box ) ;
2020-02-21 18:28:45 +01:00
search_box - > connect ( " text_changed " , callable_mp ( this , & ScriptEditorQuickOpen : : _text_changed ) ) ;
search_box - > connect ( " gui_input " , callable_mp ( this , & ScriptEditorQuickOpen : : _sbox_input ) ) ;
2014-02-10 02:10:30 +01:00
search_options = memnew ( Tree ) ;
2016-05-04 03:25:37 +02:00
vbc - > add_margin_child ( TTR ( " Matches: " ) , search_options , true ) ;
2022-07-08 02:31:19 +02:00
set_ok_button_text ( TTR ( " Open " ) ) ;
2020-12-14 19:37:30 +01:00
get_ok_button ( ) - > set_disabled ( true ) ;
2014-02-10 02:10:30 +01:00
register_text_enter ( search_box ) ;
set_hide_on_ok ( false ) ;
2020-02-21 18:28:45 +01:00
search_options - > connect ( " item_activated " , callable_mp ( this , & ScriptEditorQuickOpen : : _confirmed ) ) ;
2024-03-17 09:28:18 +01:00
search_options - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2014-02-10 02:10:30 +01:00
search_options - > set_hide_root ( true ) ;
2019-08-09 04:22:33 +02:00
search_options - > set_hide_folding ( true ) ;
2022-02-08 10:14:58 +01:00
search_options - > add_theme_constant_override ( " draw_guides " , 1 ) ;
2014-02-10 02:10:30 +01:00
}
/////////////////////////////////
2020-04-02 01:20:12 +02:00
ScriptEditor * ScriptEditor : : script_editor = nullptr ;
2014-02-10 02:10:30 +01:00
/*** SCRIPT EDITOR ******/
2016-08-03 00:11:05 +02:00
String ScriptEditor : : _get_debug_tooltip ( const String & p_text , Node * _se ) {
2020-02-07 02:52:05 +01:00
String val = EditorDebuggerNode : : get_singleton ( ) - > get_var_value ( p_text ) ;
2023-08-26 18:17:43 +02:00
const int display_limit = 300 ;
2021-12-09 10:42:46 +01:00
if ( ! val . is_empty ( ) ) {
2023-08-26 18:17:43 +02:00
if ( val . size ( ) > display_limit ) {
val = val . left ( display_limit ) + " [...] truncated! " ;
}
2014-02-10 02:10:30 +01:00
return p_text + " : " + val ;
} else {
return String ( ) ;
}
}
void ScriptEditor : : _breaked ( bool p_breaked , bool p_can_debug ) {
2023-10-07 13:05:36 +02:00
if ( external_editor_active ) {
2017-02-20 21:22:50 +01:00
return ;
}
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2016-08-07 00:00:54 +02:00
if ( ! se ) {
continue ;
}
se - > set_debugger_active ( p_breaked ) ;
}
2014-02-10 02:10:30 +01:00
}
2015-08-10 01:39:59 +02:00
void ScriptEditor : : _script_created ( Ref < Script > p_script ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > push_item ( p_script . operator - > ( ) ) ;
2015-08-10 01:39:59 +02:00
}
2014-02-10 02:10:30 +01:00
void ScriptEditor : : _goto_script_line2 ( int p_line ) {
2018-02-12 02:36:15 +01:00
ScriptEditorBase * current = _get_current_editor ( ) ;
2020-05-14 16:41:43 +02:00
if ( current ) {
2018-02-12 02:36:15 +01:00
current - > goto_line ( p_line ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2022-05-03 01:43:50 +02:00
void ScriptEditor : : _goto_script_line ( Ref < RefCounted > p_script , int p_line ) {
2022-09-29 11:53:28 +02:00
Ref < Script > scr = Object : : cast_to < Script > ( * p_script ) ;
if ( scr . is_valid ( ) & & ( scr - > has_source_code ( ) | | scr - > get_path ( ) . is_resource_file ( ) ) ) {
2018-01-09 17:19:37 +01:00
if ( edit ( p_script , p_line , 0 ) ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > push_item ( p_script . ptr ( ) ) ;
2016-08-07 00:00:54 +02:00
2018-02-12 02:36:15 +01:00
ScriptEditorBase * current = _get_current_editor ( ) ;
2019-01-04 13:09:01 +01:00
if ( ScriptTextEditor * script_text_editor = Object : : cast_to < ScriptTextEditor > ( current ) ) {
script_text_editor - > goto_line_centered ( p_line ) ;
} else if ( current ) {
2018-02-12 02:36:15 +01:00
current - > goto_line ( p_line , true ) ;
2019-01-04 13:09:01 +01:00
}
2023-01-16 00:04:35 +01:00
_save_history ( ) ;
2018-01-09 17:19:37 +01:00
}
}
2014-02-10 02:10:30 +01:00
}
2022-05-03 01:43:50 +02:00
void ScriptEditor : : _set_execution ( Ref < RefCounted > p_script , int p_line ) {
2022-09-29 11:53:28 +02:00
Ref < Script > scr = Object : : cast_to < Script > ( * p_script ) ;
if ( scr . is_valid ( ) & & ( scr - > has_source_code ( ) | | scr - > get_path ( ) . is_resource_file ( ) ) ) {
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! se ) {
2019-04-22 18:20:27 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2019-04-22 18:20:27 +02:00
2022-09-29 11:53:28 +02:00
if ( ( scr ! = nullptr & & se - > get_edited_resource ( ) = = p_script ) | | se - > get_edited_resource ( ) - > get_path ( ) = = scr - > get_path ( ) ) {
2019-04-22 18:20:27 +02:00
se - > set_executing_line ( p_line ) ;
}
}
}
}
2022-05-03 01:43:50 +02:00
void ScriptEditor : : _clear_execution ( Ref < RefCounted > p_script ) {
2022-09-29 11:53:28 +02:00
Ref < Script > scr = Object : : cast_to < Script > ( * p_script ) ;
if ( scr . is_valid ( ) & & ( scr - > has_source_code ( ) | | scr - > get_path ( ) . is_resource_file ( ) ) ) {
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! se ) {
2019-04-22 18:20:27 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2019-04-22 18:20:27 +02:00
2022-09-29 11:53:28 +02:00
if ( ( scr ! = nullptr & & se - > get_edited_resource ( ) = = p_script ) | | se - > get_edited_resource ( ) - > get_path ( ) = = scr - > get_path ( ) ) {
2019-04-22 18:20:27 +02:00
se - > clear_executing_line ( ) ;
}
}
}
}
2022-05-03 01:43:50 +02:00
void ScriptEditor : : _set_breakpoint ( Ref < RefCounted > p_script , int p_line , bool p_enabled ) {
2022-09-29 11:53:28 +02:00
Ref < Script > scr = Object : : cast_to < Script > ( * p_script ) ;
if ( scr . is_valid ( ) & & ( scr - > has_source_code ( ) | | scr - > get_path ( ) . is_resource_file ( ) ) ) {
2021-10-07 20:46:44 +02:00
// Update if open.
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2022-09-29 11:53:28 +02:00
if ( se & & se - > get_edited_resource ( ) - > get_path ( ) = = scr - > get_path ( ) ) {
2021-07-20 13:24:56 +02:00
se - > set_breakpoint ( p_line , p_enabled ) ;
2021-10-07 20:46:44 +02:00
return ;
}
}
// Handle closed.
2022-09-29 11:53:28 +02:00
Dictionary state = script_editor_cache - > get_value ( scr - > get_path ( ) , " state " ) ;
2021-10-07 20:46:44 +02:00
Array breakpoints ;
if ( state . has ( " breakpoints " ) ) {
breakpoints = state [ " breakpoints " ] ;
}
if ( breakpoints . has ( p_line ) ) {
if ( ! p_enabled ) {
breakpoints . erase ( p_line ) ;
2021-07-20 13:24:56 +02:00
}
2021-10-07 20:46:44 +02:00
} else if ( p_enabled ) {
breakpoints . push_back ( p_line ) ;
2021-07-20 13:24:56 +02:00
}
2021-10-07 20:46:44 +02:00
state [ " breakpoints " ] = breakpoints ;
2022-09-29 11:53:28 +02:00
script_editor_cache - > set_value ( scr - > get_path ( ) , " state " , state ) ;
2023-11-14 17:51:38 +01:00
EditorDebuggerNode : : get_singleton ( ) - > set_breakpoint ( scr - > get_path ( ) , p_line + 1 , p_enabled ) ;
2021-07-20 13:24:56 +02:00
}
}
void ScriptEditor : : _clear_breakpoints ( ) {
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2021-07-20 13:24:56 +02:00
if ( se ) {
se - > clear_breakpoints ( ) ;
}
}
2021-10-07 20:46:44 +02:00
// Clear from closed scripts.
List < String > cached_editors ;
script_editor_cache - > get_sections ( & cached_editors ) ;
for ( const String & E : cached_editors ) {
Array breakpoints = _get_cached_breakpoints_for_script ( E ) ;
for ( int i = 0 ; i < breakpoints . size ( ) ; i + + ) {
EditorDebuggerNode : : get_singleton ( ) - > set_breakpoint ( E , ( int ) breakpoints [ i ] + 1 , false ) ;
}
if ( breakpoints . size ( ) > 0 ) {
Dictionary state = script_editor_cache - > get_value ( E , " state " ) ;
state [ " breakpoints " ] = Array ( ) ;
script_editor_cache - > set_value ( E , " state " , state ) ;
}
}
}
Array ScriptEditor : : _get_cached_breakpoints_for_script ( const String & p_path ) const {
if ( ! ResourceLoader : : exists ( p_path , " Script " ) | | p_path . begins_with ( " local:// " ) | | ! script_editor_cache - > has_section_key ( p_path , " state " ) ) {
return Array ( ) ;
}
Dictionary state = script_editor_cache - > get_value ( p_path , " state " ) ;
if ( ! state . has ( " breakpoints " ) ) {
return Array ( ) ;
}
return state [ " breakpoints " ] ;
2021-07-20 13:24:56 +02:00
}
2018-02-12 02:36:15 +01:00
ScriptEditorBase * ScriptEditor : : _get_current_editor ( ) const {
int selected = tab_container - > get_current_tab ( ) ;
2022-03-02 15:37:10 +01:00
if ( selected < 0 | | selected > = tab_container - > get_tab_count ( ) ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2018-02-12 02:36:15 +01:00
2022-03-02 15:37:10 +01:00
return Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( selected ) ) ;
2018-02-12 02:36:15 +01:00
}
2015-11-17 13:46:08 +01:00
void ScriptEditor : : _update_history_arrows ( ) {
script_back - > set_disabled ( history_pos < = 0 ) ;
script_forward - > set_disabled ( history_pos > = history . size ( ) - 1 ) ;
}
2016-09-12 15:52:29 +02:00
void ScriptEditor : : _save_history ( ) {
if ( history_pos > = 0 & & history_pos < history . size ( ) & & history [ history_pos ] . control = = tab_container - > get_current_tab_control ( ) ) {
Node * n = tab_container - > get_current_tab_control ( ) ;
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < ScriptEditorBase > ( n ) ) {
2022-09-23 14:46:28 +02:00
history . write [ history_pos ] . state = Object : : cast_to < ScriptEditorBase > ( n ) - > get_navigation_state ( ) ;
2016-09-12 15:52:29 +02:00
}
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < EditorHelp > ( n ) ) {
2018-07-25 03:11:03 +02:00
history . write [ history_pos ] . state = Object : : cast_to < EditorHelp > ( n ) - > get_scroll ( ) ;
2016-09-12 15:52:29 +02:00
}
}
history . resize ( history_pos + 1 ) ;
ScriptHistory sh ;
sh . control = tab_container - > get_current_tab_control ( ) ;
sh . state = Variant ( ) ;
history . push_back ( sh ) ;
history_pos + + ;
_update_history_arrows ( ) ;
}
2022-10-22 23:54:37 +02:00
void ScriptEditor : : _save_previous_state ( Dictionary p_state ) {
if ( lock_history ) {
// Done as a result of a deferred call triggered by set_edit_state().
lock_history = false ;
return ;
}
if ( history_pos > = 0 & & history_pos < history . size ( ) & & history [ history_pos ] . control = = tab_container - > get_current_tab_control ( ) ) {
Node * n = tab_container - > get_current_tab_control ( ) ;
if ( Object : : cast_to < ScriptTextEditor > ( n ) ) {
history . write [ history_pos ] . state = p_state ;
}
}
history . resize ( history_pos + 1 ) ;
ScriptHistory sh ;
sh . control = tab_container - > get_current_tab_control ( ) ;
sh . state = Variant ( ) ;
history . push_back ( sh ) ;
history_pos + + ;
_update_history_arrows ( ) ;
}
2015-11-17 13:46:08 +01:00
void ScriptEditor : : _go_to_tab ( int p_idx ) {
2019-05-05 06:56:19 +02:00
ScriptEditorBase * current = _get_current_editor ( ) ;
if ( current ) {
if ( current - > is_unsaved ( ) ) {
current - > apply_code ( ) ;
}
}
2022-07-31 21:43:11 +02:00
Control * c = tab_container - > get_tab_control ( p_idx ) ;
2020-05-14 16:41:43 +02:00
if ( ! c ) {
2015-11-17 13:46:08 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-11-17 13:46:08 +01:00
if ( history_pos > = 0 & & history_pos < history . size ( ) & & history [ history_pos ] . control = = tab_container - > get_current_tab_control ( ) ) {
Node * n = tab_container - > get_current_tab_control ( ) ;
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < ScriptEditorBase > ( n ) ) {
2022-09-23 14:46:28 +02:00
history . write [ history_pos ] . state = Object : : cast_to < ScriptEditorBase > ( n ) - > get_navigation_state ( ) ;
2015-11-17 13:46:08 +01:00
}
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < EditorHelp > ( n ) ) {
2018-07-25 03:11:03 +02:00
history . write [ history_pos ] . state = Object : : cast_to < EditorHelp > ( n ) - > get_scroll ( ) ;
2015-11-17 13:46:08 +01:00
}
}
history . resize ( history_pos + 1 ) ;
ScriptHistory sh ;
sh . control = c ;
2016-08-03 00:11:05 +02:00
sh . state = Variant ( ) ;
2015-11-17 13:46:08 +01:00
2022-10-22 23:54:37 +02:00
if ( ! lock_history & & ( history . is_empty ( ) | | history [ history . size ( ) - 1 ] . control ! = sh . control ) ) {
history . push_back ( sh ) ;
history_pos + + ;
}
2015-11-17 13:46:08 +01:00
tab_container - > set_current_tab ( p_idx ) ;
c = tab_container - > get_current_tab_control ( ) ;
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < ScriptEditorBase > ( c ) ) {
script_name_label - > set_text ( Object : : cast_to < ScriptEditorBase > ( c ) - > get_name ( ) ) ;
2020-03-12 13:37:40 +01:00
script_icon - > set_texture ( Object : : cast_to < ScriptEditorBase > ( c ) - > get_theme_icon ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( is_visible_in_tree ( ) ) {
2017-08-24 22:58:51 +02:00
Object : : cast_to < ScriptEditorBase > ( c ) - > ensure_focus ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-07-06 09:18:20 +02:00
2022-09-29 11:53:28 +02:00
Ref < Script > scr = Object : : cast_to < ScriptEditorBase > ( c ) - > get_edited_resource ( ) ;
if ( scr ! = nullptr ) {
notify_script_changed ( scr ) ;
2018-05-28 17:52:28 +02:00
}
2019-05-08 18:49:49 +02:00
Object : : cast_to < ScriptEditorBase > ( c ) - > validate ( ) ;
2015-11-17 13:46:08 +01:00
}
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < EditorHelp > ( c ) ) {
script_name_label - > set_text ( Object : : cast_to < EditorHelp > ( c ) - > get_class ( ) ) ;
2023-08-13 02:33:39 +02:00
script_icon - > set_texture ( get_editor_theme_icon ( SNAME ( " Help " ) ) ) ;
2020-05-14 16:41:43 +02:00
if ( is_visible_in_tree ( ) ) {
2017-08-24 22:58:51 +02:00
Object : : cast_to < EditorHelp > ( c ) - > set_focused ( ) ;
2020-05-14 16:41:43 +02:00
}
2015-11-17 13:46:08 +01:00
}
c - > set_meta ( " __editor_pass " , + + edit_pass ) ;
_update_history_arrows ( ) ;
2016-08-03 00:11:05 +02:00
_update_script_colors ( ) ;
2017-05-28 16:20:38 +02:00
_update_members_overview ( ) ;
2017-09-14 02:56:37 +02:00
_update_help_overview ( ) ;
2016-08-03 00:11:05 +02:00
_update_selected_editor_menu ( ) ;
2017-05-28 16:20:38 +02:00
_update_members_overview_visibility ( ) ;
2017-09-14 02:56:37 +02:00
_update_help_overview_visibility ( ) ;
2015-11-17 13:46:08 +01:00
}
2024-02-15 17:25:58 +01:00
void ScriptEditor : : _add_recent_script ( const String & p_path ) {
2020-12-15 13:04:21 +01:00
if ( p_path . is_empty ( ) ) {
2017-04-27 17:07:39 +02:00
return ;
}
2018-01-08 01:31:36 +01:00
Array rc = EditorSettings : : get_singleton ( ) - > get_project_metadata ( " recent_files " , " scripts " , Array ( ) ) ;
if ( rc . find ( p_path ) ! = - 1 ) {
rc . erase ( p_path ) ;
}
rc . push_front ( p_path ) ;
if ( rc . size ( ) > 10 ) {
rc . resize ( 10 ) ;
2017-04-27 17:07:39 +02:00
}
2018-01-08 01:31:36 +01:00
EditorSettings : : get_singleton ( ) - > set_project_metadata ( " recent_files " , " scripts " , rc ) ;
2017-04-27 17:07:39 +02:00
_update_recent_scripts ( ) ;
}
void ScriptEditor : : _update_recent_scripts ( ) {
2018-01-08 01:31:36 +01:00
Array rc = EditorSettings : : get_singleton ( ) - > get_project_metadata ( " recent_files " , " scripts " , Array ( ) ) ;
2017-04-27 17:07:39 +02:00
recent_scripts - > clear ( ) ;
2018-01-08 01:31:36 +01:00
String path ;
for ( int i = 0 ; i < rc . size ( ) ; i + + ) {
path = rc [ i ] ;
recent_scripts - > add_item ( path . replace ( " res:// " , " " ) ) ;
2017-04-27 17:07:39 +02:00
}
recent_scripts - > add_separator ( ) ;
recent_scripts - > add_shortcut ( ED_SHORTCUT ( " script_editor/clear_recent " , TTR ( " Clear Recent Files " ) ) ) ;
2022-01-21 05:12:48 +01:00
recent_scripts - > set_item_disabled ( recent_scripts - > get_item_id ( recent_scripts - > get_item_count ( ) - 1 ) , rc . is_empty ( ) ) ;
2017-10-11 10:24:57 +02:00
2022-03-06 00:57:42 +01:00
recent_scripts - > reset_size ( ) ;
2017-04-27 17:07:39 +02:00
}
void ScriptEditor : : _open_recent_script ( int p_idx ) {
// clear button
if ( p_idx = = recent_scripts - > get_item_count ( ) - 1 ) {
2018-01-08 01:31:36 +01:00
EditorSettings : : get_singleton ( ) - > set_project_metadata ( " recent_files " , " scripts " , Array ( ) ) ;
2023-12-18 15:46:56 +01:00
callable_mp ( this , & ScriptEditor : : _update_recent_scripts ) . call_deferred ( ) ;
2017-04-27 17:07:39 +02:00
return ;
}
2018-01-08 01:31:36 +01:00
Array rc = EditorSettings : : get_singleton ( ) - > get_project_metadata ( " recent_files " , " scripts " , Array ( ) ) ;
ERR_FAIL_INDEX ( p_idx , rc . size ( ) ) ;
2017-04-27 17:07:39 +02:00
2018-01-08 01:31:36 +01:00
String path = rc [ p_idx ] ;
// if its not on disk its a help file or deleted
if ( FileAccess : : exists ( path ) ) {
2018-05-28 17:52:28 +02:00
List < String > extensions ;
ResourceLoader : : get_recognized_extensions_for_type ( " Script " , & extensions ) ;
2023-01-28 15:05:23 +01:00
ResourceLoader : : get_recognized_extensions_for_type ( " JSON " , & extensions ) ;
2018-05-28 17:52:28 +02:00
if ( extensions . find ( path . get_extension ( ) ) ) {
2023-01-28 15:05:23 +01:00
Ref < Resource > scr = ResourceLoader : : load ( path ) ;
2022-09-29 11:53:28 +02:00
if ( scr . is_valid ( ) ) {
edit ( scr , true ) ;
2018-05-28 17:52:28 +02:00
return ;
}
2017-04-27 17:07:39 +02:00
}
2018-01-08 01:31:36 +01:00
2018-05-28 17:52:28 +02:00
Error err ;
Ref < TextFile > text_file = _load_text_file ( path , & err ) ;
if ( text_file . is_valid ( ) ) {
edit ( text_file , true ) ;
return ;
}
2018-10-25 02:19:21 +02:00
// if it's a path then it's most likely a deleted file not help
2022-02-03 17:03:38 +01:00
} else if ( path . contains ( " :: " ) ) {
2018-09-09 04:26:05 +02:00
// built-in script
2019-09-04 20:00:09 +02:00
String res_path = path . get_slice ( " :: " , 0 ) ;
if ( ResourceLoader : : get_resource_type ( res_path ) = = " PackedScene " ) {
if ( ! EditorNode : : get_singleton ( ) - > is_scene_open ( res_path ) ) {
EditorNode : : get_singleton ( ) - > load_scene ( res_path ) ;
}
} else {
EditorNode : : get_singleton ( ) - > load_resource ( res_path ) ;
2019-09-04 19:14:47 +02:00
}
2022-09-29 11:53:28 +02:00
Ref < Script > scr = ResourceLoader : : load ( path ) ;
if ( scr . is_valid ( ) ) {
edit ( scr , true ) ;
2018-09-09 04:26:05 +02:00
return ;
}
2018-01-08 01:31:36 +01:00
} else if ( ! path . is_resource_file ( ) ) {
_help_class_open ( path ) ;
return ;
2017-04-27 17:07:39 +02:00
}
2018-01-08 01:31:36 +01:00
2021-07-04 00:17:03 +02:00
rc . remove_at ( p_idx ) ;
2018-01-08 01:31:36 +01:00
EditorSettings : : get_singleton ( ) - > set_project_metadata ( " recent_files " , " scripts " , rc ) ;
_update_recent_scripts ( ) ;
_show_error_dialog ( path ) ;
}
2024-02-15 17:25:58 +01:00
void ScriptEditor : : _show_error_dialog ( const String & p_path ) {
2018-01-08 01:31:36 +01:00
error_dialog - > set_text ( vformat ( TTR ( " Can't open '%s'. The file could have been moved or deleted. " ) , p_path ) ) ;
2020-03-06 18:00:16 +01:00
error_dialog - > popup_centered ( ) ;
2017-04-27 17:07:39 +02:00
}
2018-02-06 22:32:03 +01:00
void ScriptEditor : : _close_tab ( int p_idx , bool p_save , bool p_history_back ) {
2016-07-07 01:35:49 +02:00
int selected = p_idx ;
2022-03-02 15:37:10 +01:00
if ( selected < 0 | | selected > = tab_container - > get_tab_count ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2022-03-02 15:37:10 +01:00
Node * tselected = tab_container - > get_tab_control ( selected ) ;
2018-05-28 17:52:28 +02:00
2019-11-20 10:09:59 +01:00
ScriptEditorBase * current = Object : : cast_to < ScriptEditorBase > ( tselected ) ;
2015-11-17 13:46:08 +01:00
if ( current ) {
2022-05-03 01:43:50 +02:00
Ref < Resource > file = current - > get_edited_resource ( ) ;
2021-10-12 18:13:24 +02:00
if ( p_save & & file . is_valid ( ) ) {
2020-07-23 14:21:28 +02:00
// Do not try to save internal scripts, but prompt to save in-memory
// scripts which are not saved to disk yet (have empty path).
2022-03-01 01:23:26 +01:00
if ( ! file - > is_built_in ( ) ) {
2021-05-09 12:29:50 +02:00
save_current_script ( ) ;
2020-07-08 18:53:18 +02:00
}
2017-01-02 19:45:59 +01:00
}
2021-10-12 18:13:24 +02:00
if ( file . is_valid ( ) ) {
if ( ! file - > get_path ( ) . is_empty ( ) ) {
2020-07-23 14:21:28 +02:00
// Only saved scripts can be restored.
2021-10-12 18:13:24 +02:00
previous_scripts . push_back ( file - > get_path ( ) ) ;
}
2022-09-29 11:53:28 +02:00
Ref < Script > scr = file ;
if ( scr . is_valid ( ) ) {
notify_script_close ( scr ) ;
2020-07-23 14:21:28 +02:00
}
2018-05-28 17:52:28 +02:00
}
2015-11-17 13:46:08 +01:00
}
2014-02-10 02:10:30 +01:00
2017-07-22 11:08:56 +02:00
// roll back to previous tab
2018-02-06 22:32:03 +01:00
if ( p_history_back ) {
_history_back ( ) ;
}
2017-07-22 11:08:56 +02:00
2015-11-17 13:46:08 +01:00
//remove from history
history . resize ( history_pos + 1 ) ;
for ( int i = 0 ; i < history . size ( ) ; i + + ) {
if ( history [ i ] . control = = tselected ) {
2021-07-04 00:17:03 +02:00
history . remove_at ( i ) ;
2015-11-17 13:46:08 +01:00
i - - ;
history_pos - - ;
}
}
if ( history_pos > = history . size ( ) ) {
history_pos = history . size ( ) - 1 ;
}
2014-02-10 02:10:30 +01:00
int idx = tab_container - > get_current_tab ( ) ;
2018-01-08 19:47:47 +01:00
if ( current ) {
current - > clear_edit_menu ( ) ;
2021-10-07 20:44:23 +02:00
_save_editor_state ( current ) ;
2018-01-08 19:47:47 +01:00
}
2015-11-17 13:46:08 +01:00
memdelete ( tselected ) ;
2015-06-22 05:03:19 +02:00
2023-06-23 11:19:09 +02:00
if ( script_close_queue . is_empty ( ) ) {
2024-04-23 23:33:01 +02:00
if ( idx > = tab_container - > get_tab_count ( ) ) {
idx = tab_container - > get_tab_count ( ) - 1 ;
}
if ( idx > = 0 ) {
if ( history_pos > = 0 ) {
idx = tab_container - > get_tab_idx_from_control ( history [ history_pos ] . control ) ;
}
_go_to_tab ( idx ) ;
} else {
_update_selected_editor_menu ( ) ;
}
2023-06-23 11:19:09 +02:00
_update_history_arrows ( ) ;
_update_script_names ( ) ;
_save_layout ( ) ;
_update_find_replace_bar ( ) ;
}
2016-07-07 01:35:49 +02:00
}
2024-04-23 23:33:01 +02:00
void ScriptEditor : : _close_current_tab ( bool p_save , bool p_history_back ) {
_close_tab ( tab_container - > get_current_tab ( ) , p_save , p_history_back ) ;
2014-02-10 02:10:30 +01:00
}
2017-01-02 19:45:59 +01:00
void ScriptEditor : : _close_discard_current_tab ( const String & p_str ) {
2023-10-05 14:03:02 +02:00
Ref < Script > scr = _get_current_script ( ) ;
if ( scr . is_valid ( ) ) {
scr - > reload_from_file ( ) ;
}
2017-01-02 19:45:59 +01:00
_close_tab ( tab_container - > get_current_tab ( ) , false ) ;
erase_tab_confirm - > hide ( ) ;
}
2016-07-18 00:18:48 +02:00
void ScriptEditor : : _close_docs_tab ( ) {
2022-03-02 15:37:10 +01:00
int child_count = tab_container - > get_tab_count ( ) ;
2016-07-18 00:18:48 +02:00
for ( int i = child_count - 1 ; i > = 0 ; i - - ) {
2022-03-02 15:37:10 +01:00
EditorHelp * se = Object : : cast_to < EditorHelp > ( tab_container - > get_tab_control ( i ) ) ;
2016-07-18 00:18:48 +02:00
2016-08-03 00:11:05 +02:00
if ( se ) {
2018-02-06 22:32:03 +01:00
_close_tab ( i , true , false ) ;
2016-07-18 00:18:48 +02:00
}
}
}
2017-12-07 04:57:41 +01:00
void ScriptEditor : : _copy_script_path ( ) {
2018-02-12 02:36:15 +01:00
ScriptEditorBase * se = _get_current_editor ( ) ;
2019-11-20 10:09:59 +01:00
if ( se ) {
2022-09-29 11:53:28 +02:00
Ref < Resource > scr = se - > get_edited_resource ( ) ;
DisplayServer : : get_singleton ( ) - > clipboard_set ( scr - > get_path ( ) ) ;
2019-11-20 10:09:59 +01:00
}
2017-12-07 04:57:41 +01:00
}
2017-11-20 06:15:40 +01:00
void ScriptEditor : : _close_other_tabs ( ) {
int current_idx = tab_container - > get_current_tab ( ) ;
2022-03-02 15:37:10 +01:00
for ( int i = tab_container - > get_tab_count ( ) - 1 ; i > = 0 ; i - - ) {
2021-09-07 23:38:19 +02:00
if ( i ! = current_idx ) {
script_close_queue . push_back ( i ) ;
2017-11-20 06:15:40 +01:00
}
}
2021-09-07 23:38:19 +02:00
_queue_close_tabs ( ) ;
2017-11-20 06:15:40 +01:00
}
2016-08-13 02:56:38 +02:00
void ScriptEditor : : _close_all_tabs ( ) {
2022-03-02 15:37:10 +01:00
for ( int i = tab_container - > get_tab_count ( ) - 1 ; i > = 0 ; i - - ) {
2021-09-07 23:38:19 +02:00
script_close_queue . push_back ( i ) ;
}
_queue_close_tabs ( ) ;
}
void ScriptEditor : : _queue_close_tabs ( ) {
while ( ! script_close_queue . is_empty ( ) ) {
int idx = script_close_queue . front ( ) - > get ( ) ;
script_close_queue . pop_front ( ) ;
2016-08-13 02:56:38 +02:00
2021-09-07 23:38:19 +02:00
tab_container - > set_current_tab ( idx ) ;
2022-03-02 15:37:10 +01:00
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( idx ) ) ;
2016-08-13 02:56:38 +02:00
if ( se ) {
2021-09-07 23:38:19 +02:00
// Maybe there are unsaved changes.
2016-08-13 02:56:38 +02:00
if ( se - > is_unsaved ( ) ) {
_ask_close_current_unsaved_tab ( se ) ;
2022-09-01 15:44:42 +02:00
erase_tab_confirm - > connect ( SceneStringNames : : get_singleton ( ) - > visibility_changed , callable_mp ( this , & ScriptEditor : : _queue_close_tabs ) , CONNECT_ONE_SHOT ) ;
2021-09-07 23:38:19 +02:00
break ;
2016-08-13 02:56:38 +02:00
}
}
2024-04-23 23:33:01 +02:00
_close_current_tab ( false , false ) ;
2016-08-13 02:56:38 +02:00
}
2021-06-24 15:38:29 +02:00
_update_find_replace_bar ( ) ;
2016-08-13 02:56:38 +02:00
}
void ScriptEditor : : _ask_close_current_unsaved_tab ( ScriptEditorBase * current ) {
2018-01-06 14:32:21 +01:00
erase_tab_confirm - > set_text ( TTR ( " Close and save changes? " ) + " \n \" " + current - > get_name ( ) + " \" " ) ;
2020-03-06 18:00:16 +01:00
erase_tab_confirm - > popup_centered ( ) ;
2016-08-13 02:56:38 +02:00
}
2016-07-18 00:18:48 +02:00
2014-02-10 02:10:30 +01:00
void ScriptEditor : : _resave_scripts ( const String & p_str ) {
apply_scripts ( ) ;
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! se ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
Ref < Resource > scr = se - > get_edited_resource ( ) ;
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
if ( scr - > is_built_in ( ) ) {
2014-02-10 02:10:30 +01:00
continue ; //internal script, who cares
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2016-04-23 20:21:34 +02:00
if ( trim_trailing_whitespace_on_save ) {
2016-08-03 00:11:05 +02:00
se - > trim_trailing_whitespace ( ) ;
2016-04-23 20:21:34 +02:00
}
2017-04-17 15:46:00 +02:00
2019-05-28 23:27:32 +02:00
se - > insert_final_newline ( ) ;
2017-04-17 15:46:00 +02:00
if ( convert_indent_on_save ) {
2023-05-01 22:41:50 +02:00
se - > convert_indent ( ) ;
2017-04-17 15:46:00 +02:00
}
2022-09-29 11:53:28 +02:00
Ref < TextFile > text_file = scr ;
2020-04-02 01:20:12 +02:00
if ( text_file ! = nullptr ) {
2018-05-28 17:52:28 +02:00
se - > apply_code ( ) ;
_save_text_file ( text_file , text_file - > get_path ( ) ) ;
break ;
} else {
2022-09-29 11:53:28 +02:00
EditorNode : : get_singleton ( ) - > save_resource ( scr ) ;
2018-05-28 17:52:28 +02:00
}
2016-08-03 00:11:05 +02:00
se - > tag_saved_version ( ) ;
2014-02-10 02:10:30 +01:00
}
disk_changed - > hide ( ) ;
}
void ScriptEditor : : _res_saved_callback ( const Ref < Resource > & p_res ) {
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2016-08-03 00:11:05 +02:00
if ( ! se ) {
2014-02-10 02:10:30 +01:00
continue ;
}
2022-09-29 11:53:28 +02:00
Ref < Resource > scr = se - > get_edited_resource ( ) ;
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
if ( scr = = p_res ) {
2016-08-03 00:11:05 +02:00
se - > tag_saved_version ( ) ;
2014-02-10 02:10:30 +01:00
}
}
2024-01-02 12:53:18 +01:00
if ( p_res . is_valid ( ) ) {
// In case the Resource has built-in scripts.
_mark_built_in_scripts_as_saved ( p_res - > get_path ( ) ) ;
}
2015-06-22 05:03:19 +02:00
_update_script_names ( ) ;
2023-12-30 08:06:54 +01:00
Ref < Script > scr = p_res ;
if ( scr . is_valid ( ) ) {
trigger_live_script_reload ( scr - > get_path ( ) ) ;
}
2021-08-17 10:32:23 +02:00
}
2015-06-22 05:03:19 +02:00
2021-11-06 02:15:19 +01:00
void ScriptEditor : : _scene_saved_callback ( const String & p_path ) {
// If scene was saved, mark all built-in scripts from that scene as saved.
2024-01-02 12:53:18 +01:00
_mark_built_in_scripts_as_saved ( p_path ) ;
}
void ScriptEditor : : _mark_built_in_scripts_as_saved ( const String & p_parent_path ) {
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2021-11-06 02:15:19 +01:00
if ( ! se ) {
continue ;
}
2022-05-03 01:43:50 +02:00
Ref < Resource > edited_res = se - > get_edited_resource ( ) ;
2021-11-06 02:15:19 +01:00
if ( ! edited_res - > is_built_in ( ) ) {
continue ; // External script, who cares.
}
2024-01-02 12:53:18 +01:00
if ( edited_res - > get_path ( ) . get_slice ( " :: " , 0 ) = = p_parent_path ) {
2021-11-06 02:15:19 +01:00
se - > tag_saved_version ( ) ;
}
2021-11-06 14:32:14 +01:00
Ref < Script > scr = edited_res ;
if ( scr . is_valid ( ) & & scr - > is_tool ( ) ) {
scr - > reload ( true ) ;
}
2021-11-06 02:15:19 +01:00
}
}
2023-12-30 08:06:54 +01:00
void ScriptEditor : : trigger_live_script_reload ( const String & p_script_path ) {
if ( ! script_paths_to_reload . has ( p_script_path ) ) {
script_paths_to_reload . append ( p_script_path ) ;
}
2016-06-03 17:34:11 +02:00
if ( ! pending_auto_reload & & auto_reload_running_scripts ) {
2023-12-18 15:46:56 +01:00
callable_mp ( this , & ScriptEditor : : _live_auto_reload_running_scripts ) . call_deferred ( ) ;
2016-06-03 17:34:11 +02:00
pending_auto_reload = true ;
}
}
2023-12-30 08:06:54 +01:00
void ScriptEditor : : trigger_live_script_reload_all ( ) {
if ( ! pending_auto_reload & & auto_reload_running_scripts ) {
call_deferred ( SNAME ( " _live_auto_reload_running_scripts " ) ) ;
pending_auto_reload = true ;
reload_all_scripts = true ;
}
}
2016-06-03 17:34:11 +02:00
void ScriptEditor : : _live_auto_reload_running_scripts ( ) {
pending_auto_reload = false ;
2023-12-30 08:06:54 +01:00
if ( reload_all_scripts ) {
EditorDebuggerNode : : get_singleton ( ) - > reload_all_scripts ( ) ;
} else {
EditorDebuggerNode : : get_singleton ( ) - > reload_scripts ( script_paths_to_reload ) ;
}
reload_all_scripts = false ;
script_paths_to_reload . clear ( ) ;
2014-02-10 02:10:30 +01:00
}
2022-05-03 01:43:50 +02:00
bool ScriptEditor : : _test_script_times_on_disk ( Ref < Resource > p_for_script ) {
2014-02-10 02:10:30 +01:00
disk_changed_list - > clear ( ) ;
TreeItem * r = disk_changed_list - > create_item ( ) ;
disk_changed_list - > set_hide_root ( true ) ;
2015-12-09 13:08:41 +01:00
bool need_ask = false ;
bool need_reload = false ;
2022-03-06 21:39:19 +01:00
bool use_autoreload = bool ( EDITOR_GET ( " text_editor/behavior/files/auto_reload_scripts_on_external_change " ) ) ;
2014-02-10 02:10:30 +01:00
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2016-08-03 00:11:05 +02:00
if ( se ) {
2022-05-03 01:43:50 +02:00
Ref < Resource > edited_res = se - > get_edited_resource ( ) ;
2020-05-14 16:41:43 +02:00
if ( p_for_script . is_valid ( ) & & edited_res . is_valid ( ) & & p_for_script ! = edited_res ) {
2016-06-20 03:07:07 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2016-06-20 03:07:07 +02:00
2021-07-10 21:17:41 +02:00
if ( edited_res - > is_built_in ( ) ) {
2015-12-09 13:08:41 +01:00
continue ; //internal script, who cares
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2018-05-28 17:52:28 +02:00
uint64_t last_date = edited_res - > get_last_modified_time ( ) ;
uint64_t date = FileAccess : : get_modified_time ( edited_res - > get_path ( ) ) ;
2014-02-10 02:10:30 +01:00
2015-12-09 13:08:41 +01:00
if ( last_date ! = date ) {
TreeItem * ti = disk_changed_list - > create_item ( r ) ;
2018-05-28 17:52:28 +02:00
ti - > set_text ( 0 , edited_res - > get_path ( ) . get_file ( ) ) ;
2014-02-10 02:10:30 +01:00
2016-08-03 00:11:05 +02:00
if ( ! use_autoreload | | se - > is_unsaved ( ) ) {
2015-12-09 13:08:41 +01:00
need_ask = true ;
}
need_reload = true ;
}
2014-02-10 02:10:30 +01:00
}
}
2015-12-09 13:08:41 +01:00
if ( need_reload ) {
if ( ! need_ask ) {
2022-06-13 20:47:40 +02:00
script_editor - > reload_scripts ( ) ;
2015-12-09 13:08:41 +01:00
need_reload = false ;
2015-02-17 03:58:41 +01:00
} else {
2023-12-18 15:46:56 +01:00
callable_mp ( ( Window * ) disk_changed , & Window : : popup_centered_ratio ) . call_deferred ( 0.3 ) ;
2015-02-17 03:58:41 +01:00
}
}
2014-02-10 02:10:30 +01:00
2015-12-09 13:08:41 +01:00
return need_reload ;
2014-02-10 02:10:30 +01:00
}
2024-02-15 17:25:58 +01:00
void ScriptEditor : : _file_dialog_action ( const String & p_file ) {
2016-04-12 16:45:31 +02:00
switch ( file_dialog_option ) {
2018-08-15 00:41:23 +02:00
case FILE_NEW_TEXTFILE : {
Error err ;
2022-04-12 09:12:40 +02:00
{
Ref < FileAccess > file = FileAccess : : open ( p_file , FileAccess : : WRITE , & err ) ;
if ( err ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Error writing TextFile: " ) + " \n " + p_file , TTR ( " Error! " ) ) ;
break ;
}
2018-08-15 00:41:23 +02:00
}
2018-05-28 17:52:28 +02:00
2021-09-23 23:09:15 +02:00
if ( EditorFileSystem : : get_singleton ( ) ) {
if ( textfile_extensions . has ( p_file . get_extension ( ) ) ) {
EditorFileSystem : : get_singleton ( ) - > update_file ( p_file ) ;
}
2018-05-28 17:52:28 +02:00
}
2021-09-23 23:09:15 +02:00
if ( ! open_textfile_after_create ) {
2018-05-28 17:52:28 +02:00
return ;
}
2021-09-23 23:09:15 +02:00
[[fallthrough]] ;
}
case FILE_OPEN : {
open_file ( p_file ) ;
file_dialog_option = - 1 ;
2018-08-15 00:41:23 +02:00
} break ;
2018-05-28 17:52:28 +02:00
case FILE_SAVE_AS : {
ScriptEditorBase * current = _get_current_editor ( ) ;
2019-11-20 10:09:59 +01:00
if ( current ) {
2022-05-03 01:43:50 +02:00
Ref < Resource > resource = current - > get_edited_resource ( ) ;
2019-11-20 10:09:59 +01:00
String path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_file ) ;
Error err = _save_text_file ( resource , path ) ;
2018-05-28 17:52:28 +02:00
2019-11-20 10:09:59 +01:00
if ( err ! = OK ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > show_accept ( TTR ( " Error saving file! " ) , TTR ( " OK " ) ) ;
2019-11-20 10:09:59 +01:00
return ;
}
2018-05-28 17:52:28 +02:00
2019-11-20 10:09:59 +01:00
resource - > set_path ( path ) ;
_update_script_names ( ) ;
2018-05-28 17:52:28 +02:00
}
} break ;
2018-06-21 11:10:43 +02:00
case THEME_SAVE_AS : {
2016-04-12 16:45:31 +02:00
if ( ! EditorSettings : : get_singleton ( ) - > save_text_editor_theme_as ( p_file ) ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Error while saving theme. " ) , TTR ( " Error Saving " ) ) ;
2016-04-12 16:45:31 +02:00
}
} break ;
2018-06-21 11:10:43 +02:00
case THEME_IMPORT : {
2016-04-12 16:45:31 +02:00
if ( ! EditorSettings : : get_singleton ( ) - > import_text_editor_theme ( p_file ) ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Error importing theme. " ) , TTR ( " Error Importing " ) ) ;
2016-04-12 16:45:31 +02:00
}
} break ;
}
file_dialog_option = - 1 ;
}
2017-07-06 09:18:20 +02:00
Ref < Script > ScriptEditor : : _get_current_script ( ) {
2018-02-12 02:36:15 +01:00
ScriptEditorBase * current = _get_current_editor ( ) ;
2017-07-06 09:18:20 +02:00
if ( current ) {
2022-09-29 11:53:28 +02:00
Ref < Script > scr = current - > get_edited_resource ( ) ;
return scr ! = nullptr ? scr : nullptr ;
2017-07-06 09:18:20 +02:00
} else {
2020-04-02 01:20:12 +02:00
return nullptr ;
2017-07-06 09:18:20 +02:00
}
}
2022-08-05 20:35:08 +02:00
TypedArray < Script > ScriptEditor : : _get_open_scripts ( ) const {
TypedArray < Script > ret ;
2020-03-17 07:33:00 +01:00
Vector < Ref < Script > > scripts = get_open_scripts ( ) ;
2017-07-06 09:18:20 +02:00
int scrits_amount = scripts . size ( ) ;
for ( int idx_script = 0 ; idx_script < scrits_amount ; idx_script + + ) {
ret . push_back ( scripts [ idx_script ] ) ;
}
return ret ;
}
2019-12-18 20:32:25 +01:00
bool ScriptEditor : : toggle_scripts_panel ( ) {
2019-12-15 14:35:16 +01:00
list_split - > set_visible ( ! list_split - > is_visible ( ) ) ;
2022-10-01 19:23:13 +02:00
EditorSettings : : get_singleton ( ) - > set_project_metadata ( " scripts_panel " , " show_scripts_panel " , list_split - > is_visible ( ) ) ;
2019-12-15 14:35:16 +01:00
return list_split - > is_visible ( ) ;
}
bool ScriptEditor : : is_scripts_panel_toggled ( ) {
return list_split - > is_visible ( ) ;
}
2014-02-10 02:10:30 +01:00
void ScriptEditor : : _menu_option ( int p_option ) {
2019-12-17 14:51:49 +01:00
ScriptEditorBase * current = _get_current_editor ( ) ;
2014-02-10 02:10:30 +01:00
switch ( p_option ) {
2015-08-10 01:39:59 +02:00
case FILE_NEW : {
2020-01-08 23:43:55 +01:00
script_create_dialog - > config ( " Node " , " new_script " , false , false ) ;
2020-01-08 05:15:05 +01:00
script_create_dialog - > popup_centered ( ) ;
2015-08-10 01:39:59 +02:00
} break ;
2018-08-15 00:41:23 +02:00
case FILE_NEW_TEXTFILE : {
2020-03-06 18:00:16 +01:00
file_dialog - > set_file_mode ( EditorFileDialog : : FILE_MODE_SAVE_FILE ) ;
2018-08-15 00:41:23 +02:00
file_dialog - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
file_dialog_option = FILE_NEW_TEXTFILE ;
file_dialog - > clear_filters ( ) ;
2021-10-12 18:31:20 +02:00
for ( const String & E : textfile_extensions ) {
2022-07-04 23:26:26 +02:00
file_dialog - > add_filter ( " *. " + E , E . to_upper ( ) ) ;
2021-09-23 23:09:15 +02:00
}
2019-08-12 22:23:00 +02:00
file_dialog - > set_title ( TTR ( " New Text File... " ) ) ;
2024-03-21 09:42:38 +01:00
file_dialog - > popup_file_dialog ( ) ;
2021-09-23 23:09:15 +02:00
open_textfile_after_create = true ;
2018-08-15 00:41:23 +02:00
} break ;
2015-11-17 13:46:08 +01:00
case FILE_OPEN : {
2020-03-06 18:00:16 +01:00
file_dialog - > set_file_mode ( EditorFileDialog : : FILE_MODE_OPEN_FILE ) ;
2018-05-28 17:52:28 +02:00
file_dialog - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
file_dialog_option = FILE_OPEN ;
2014-02-10 02:10:30 +01:00
2018-05-28 17:52:28 +02:00
List < String > extensions ;
ResourceLoader : : get_recognized_extensions_for_type ( " Script " , & extensions ) ;
file_dialog - > clear_filters ( ) ;
for ( int i = 0 ; i < extensions . size ( ) ; i + + ) {
2022-07-04 23:26:26 +02:00
file_dialog - > add_filter ( " *. " + extensions [ i ] , extensions [ i ] . to_upper ( ) ) ;
2018-05-28 17:52:28 +02:00
}
2021-10-12 18:31:20 +02:00
for ( const String & E : textfile_extensions ) {
2022-07-04 23:26:26 +02:00
file_dialog - > add_filter ( " *. " + E , E . to_upper ( ) ) ;
2021-09-23 23:09:15 +02:00
}
2018-05-28 17:52:28 +02:00
file_dialog - > set_title ( TTR ( " Open File " ) ) ;
2024-03-21 09:42:38 +01:00
file_dialog - > popup_file_dialog ( ) ;
2015-11-17 13:46:08 +01:00
return ;
2014-02-10 02:10:30 +01:00
} break ;
2019-07-31 21:06:15 +02:00
case FILE_REOPEN_CLOSED : {
2020-12-15 13:04:21 +01:00
if ( previous_scripts . is_empty ( ) ) {
2019-07-31 21:06:15 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2019-07-31 21:06:15 +02:00
String path = previous_scripts . back ( ) - > get ( ) ;
previous_scripts . pop_back ( ) ;
List < String > extensions ;
ResourceLoader : : get_recognized_extensions_for_type ( " Script " , & extensions ) ;
2023-01-28 15:05:23 +01:00
ResourceLoader : : get_recognized_extensions_for_type ( " JSON " , & extensions ) ;
2019-07-31 21:06:15 +02:00
bool built_in = ! path . is_resource_file ( ) ;
if ( extensions . find ( path . get_extension ( ) ) | | built_in ) {
if ( built_in ) {
2019-09-04 20:00:09 +02:00
String res_path = path . get_slice ( " :: " , 0 ) ;
if ( ResourceLoader : : get_resource_type ( res_path ) = = " PackedScene " ) {
if ( ! EditorNode : : get_singleton ( ) - > is_scene_open ( res_path ) ) {
EditorNode : : get_singleton ( ) - > load_scene ( res_path ) ;
}
} else {
EditorNode : : get_singleton ( ) - > load_resource ( res_path ) ;
2019-07-31 21:06:15 +02:00
}
}
2023-01-28 15:05:23 +01:00
Ref < Resource > scr = ResourceLoader : : load ( path ) ;
2019-07-31 21:06:15 +02:00
if ( ! scr . is_valid ( ) ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Could not load file at: " ) + " \n \n " + path , TTR ( " Error! " ) ) ;
2019-07-31 21:06:15 +02:00
file_dialog_option = - 1 ;
return ;
}
edit ( scr ) ;
file_dialog_option = - 1 ;
} else {
Error error ;
Ref < TextFile > text_file = _load_text_file ( path , & error ) ;
2020-05-14 16:41:43 +02:00
if ( error ! = OK ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Could not load file at: " ) + " \n \n " + path , TTR ( " Error! " ) ) ;
2020-05-14 16:41:43 +02:00
}
2019-07-31 21:06:15 +02:00
if ( text_file . is_valid ( ) ) {
edit ( text_file ) ;
file_dialog_option = - 1 ;
}
}
} break ;
2014-02-10 02:10:30 +01:00
case FILE_SAVE_ALL : {
2020-05-14 16:41:43 +02:00
if ( _test_script_times_on_disk ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2016-02-03 01:10:52 +01:00
save_all_scripts ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
2019-05-03 01:07:06 +02:00
case SEARCH_IN_FILES : {
_on_find_in_files_requested ( " " ) ;
} break ;
2020-02-09 10:10:58 +01:00
case REPLACE_IN_FILES : {
_on_replace_in_files_requested ( " " ) ;
} break ;
2015-11-17 13:46:08 +01:00
case SEARCH_HELP : {
2018-10-02 12:07:44 +02:00
help_search_dialog - > popup_dialog ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
2015-11-17 13:46:08 +01:00
case SEARCH_WEBSITE : {
2022-02-17 18:16:11 +01:00
OS : : get_singleton ( ) - > shell_open ( VERSION_DOCS_URL " / " ) ;
2014-02-10 02:10:30 +01:00
} break ;
2015-11-17 13:46:08 +01:00
case WINDOW_NEXT : {
_history_forward ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
2015-11-17 13:46:08 +01:00
case WINDOW_PREV : {
_history_back ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
2017-11-12 03:42:56 +01:00
case WINDOW_SORT : {
_sort_list_on_update = true ;
_update_script_names ( ) ;
} break ;
2017-07-10 14:11:31 +02:00
case TOGGLE_SCRIPTS_PANEL : {
2021-09-14 11:17:47 +02:00
toggle_scripts_panel ( ) ;
2019-12-17 14:51:49 +01:00
if ( current ) {
2021-09-14 11:17:47 +02:00
current - > update_toggle_scripts_button ( ) ;
2019-12-17 14:51:49 +01:00
} else {
2021-09-14 11:17:47 +02:00
Control * tab = tab_container - > get_current_tab_control ( ) ;
EditorHelp * editor_help = Object : : cast_to < EditorHelp > ( tab ) ;
if ( editor_help ) {
editor_help - > update_toggle_scripts_button ( ) ;
}
2019-12-17 14:51:49 +01:00
}
2017-06-25 11:20:01 +02:00
}
2015-11-17 13:46:08 +01:00
}
2014-02-10 02:10:30 +01:00
2015-11-17 13:46:08 +01:00
if ( current ) {
switch ( p_option ) {
case FILE_SAVE : {
2021-05-09 12:29:50 +02:00
save_current_script ( ) ;
2015-11-17 13:46:08 +01:00
} break ;
case FILE_SAVE_AS : {
2020-05-14 16:41:43 +02:00
if ( trim_trailing_whitespace_on_save ) {
2019-05-28 23:27:32 +02:00
current - > trim_trailing_whitespace ( ) ;
2020-05-14 16:41:43 +02:00
}
2019-05-28 23:27:32 +02:00
current - > insert_final_newline ( ) ;
2017-04-17 15:46:00 +02:00
if ( convert_indent_on_save ) {
2023-05-01 22:41:50 +02:00
current - > convert_indent ( ) ;
2017-04-17 15:46:00 +02:00
}
2018-05-28 17:52:28 +02:00
2022-05-03 01:43:50 +02:00
Ref < Resource > resource = current - > get_edited_resource ( ) ;
2019-11-20 10:09:59 +01:00
Ref < TextFile > text_file = resource ;
2022-09-29 11:53:28 +02:00
Ref < Script > scr = resource ;
2020-11-29 04:42:06 +01:00
2020-04-02 01:20:12 +02:00
if ( text_file ! = nullptr ) {
2020-03-06 18:00:16 +01:00
file_dialog - > set_file_mode ( EditorFileDialog : : FILE_MODE_SAVE_FILE ) ;
2018-05-28 17:52:28 +02:00
file_dialog - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
file_dialog_option = FILE_SAVE_AS ;
List < String > extensions ;
ResourceLoader : : get_recognized_extensions_for_type ( " Script " , & extensions ) ;
file_dialog - > clear_filters ( ) ;
file_dialog - > set_current_dir ( text_file - > get_path ( ) . get_base_dir ( ) ) ;
file_dialog - > set_current_file ( text_file - > get_path ( ) . get_file ( ) ) ;
file_dialog - > set_title ( TTR ( " Save File As... " ) ) ;
2024-03-21 09:42:38 +01:00
file_dialog - > popup_file_dialog ( ) ;
2018-05-28 17:52:28 +02:00
break ;
}
2022-09-29 11:53:28 +02:00
if ( scr . is_valid ( ) ) {
clear_docs_from_script ( scr ) ;
2020-11-29 04:42:06 +01:00
}
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > push_item ( resource . ptr ( ) ) ;
EditorNode : : get_singleton ( ) - > save_resource_as ( resource ) ;
2015-11-17 13:46:08 +01:00
2022-09-29 11:53:28 +02:00
if ( scr . is_valid ( ) ) {
update_docs_from_script ( scr ) ;
2020-11-29 04:42:06 +01:00
}
2015-11-17 13:46:08 +01:00
} break ;
2016-06-09 01:00:02 +02:00
case FILE_TOOL_RELOAD_SOFT : {
2021-11-19 17:45:16 +01:00
Ref < Script > scr = current - > get_edited_resource ( ) ;
if ( scr = = nullptr | | scr . is_null ( ) ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Can't obtain the script for reloading. " ) ) ;
break ;
}
if ( ! scr - > is_tool ( ) ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Reload only takes effect on tool scripts. " ) ) ;
return ;
}
scr - > reload ( true ) ;
2016-07-19 00:24:38 +02:00
2016-04-23 20:21:34 +02:00
} break ;
2023-08-26 20:38:29 +02:00
2017-08-28 00:03:19 +02:00
case FILE_RUN : {
2018-05-28 17:52:28 +02:00
Ref < Script > scr = current - > get_edited_resource ( ) ;
2020-04-02 01:20:12 +02:00
if ( scr = = nullptr | | scr . is_null ( ) ) {
2023-08-26 20:38:29 +02:00
EditorToaster : : get_singleton ( ) - > popup_str ( TTR ( " Cannot run the edited file because it's not a script. " ) , EditorToaster : : SEVERITY_WARNING ) ;
2017-08-28 00:03:19 +02:00
break ;
}
2017-09-03 19:53:17 +02:00
current - > apply_code ( ) ;
2023-08-26 20:38:29 +02:00
Error err = scr - > reload ( false ) ; // Always hard reload the script before running.
if ( err ! = OK | | ! scr - > is_valid ( ) ) {
EditorToaster : : get_singleton ( ) - > popup_str ( TTR ( " Cannot run the script because it contains errors, check the output log. " ) , EditorToaster : : SEVERITY_WARNING ) ;
2017-09-03 19:53:17 +02:00
return ;
}
2017-08-28 00:03:19 +02:00
2023-08-26 20:38:29 +02:00
// Perform additional checks on the script to evaluate if it's runnable.
bool is_runnable = true ;
2017-08-28 00:03:19 +02:00
if ( ! ClassDB : : is_parent_class ( scr - > get_instance_base_type ( ) , " EditorScript " ) ) {
2023-08-26 20:38:29 +02:00
is_runnable = false ;
EditorToaster : : get_singleton ( ) - > popup_str ( TTR ( " Cannot run the script because it doesn't extend EditorScript. " ) , EditorToaster : : SEVERITY_WARNING ) ;
}
if ( ! scr - > is_tool ( ) ) {
is_runnable = false ;
if ( scr - > get_class ( ) = = " GDScript " ) {
EditorToaster : : get_singleton ( ) - > popup_str ( TTR ( " Cannot run the script because it's not a tool script (add the @tool annotation at the top). " ) , EditorToaster : : SEVERITY_WARNING ) ;
} else {
EditorToaster : : get_singleton ( ) - > popup_str ( TTR ( " Cannot run the script because it's not a tool script. " ) , EditorToaster : : SEVERITY_WARNING ) ;
}
}
if ( ! is_runnable ) {
2017-08-28 00:03:19 +02:00
return ;
}
Ref < EditorScript > es = memnew ( EditorScript ) ;
2020-02-13 20:03:10 +01:00
es - > set_script ( scr ) ;
2023-04-12 21:02:28 +02:00
es - > run ( ) ;
2017-08-28 00:03:19 +02:00
} break ;
2023-08-26 20:38:29 +02:00
2016-08-03 00:11:05 +02:00
case FILE_CLOSE : {
if ( current - > is_unsaved ( ) ) {
2016-08-13 02:56:38 +02:00
_ask_close_current_unsaved_tab ( current ) ;
2016-05-27 16:29:04 +02:00
} else {
2021-03-04 01:04:31 +01:00
_close_current_tab ( false ) ;
2016-05-27 16:29:04 +02:00
}
} break ;
2017-12-07 04:57:41 +01:00
case FILE_COPY_PATH : {
_copy_script_path ( ) ;
} break ;
2018-01-02 03:11:54 +01:00
case SHOW_IN_FILE_SYSTEM : {
2022-09-29 11:53:28 +02:00
const Ref < Resource > scr = current - > get_edited_resource ( ) ;
String path = scr - > get_path ( ) ;
2020-12-15 13:04:21 +01:00
if ( ! path . is_empty ( ) ) {
2022-09-29 11:53:28 +02:00
if ( scr - > is_built_in ( ) ) {
2021-11-24 13:05:18 +01:00
path = path . get_slice ( " :: " , 0 ) ; // Show the scene instead.
}
2023-11-14 12:55:36 +01:00
FileSystemDock : : get_singleton ( ) - > navigate_to_path ( path ) ;
2019-12-30 02:49:52 +01:00
}
2018-01-02 03:11:54 +01:00
} break ;
2016-08-03 00:11:05 +02:00
case CLOSE_DOCS : {
_close_docs_tab ( ) ;
2016-05-27 16:29:04 +02:00
} break ;
2017-11-20 06:15:40 +01:00
case CLOSE_OTHER_TABS : {
_close_other_tabs ( ) ;
} break ;
2016-08-13 02:56:38 +02:00
case CLOSE_ALL : {
_close_all_tabs ( ) ;
} break ;
2017-11-12 03:42:56 +01:00
case WINDOW_MOVE_UP : {
2015-11-17 13:46:08 +01:00
if ( tab_container - > get_current_tab ( ) > 0 ) {
tab_container - > move_child ( current , tab_container - > get_current_tab ( ) - 1 ) ;
2022-07-31 21:43:11 +02:00
tab_container - > set_current_tab ( tab_container - > get_current_tab ( ) ) ;
2015-11-17 13:46:08 +01:00
_update_script_names ( ) ;
}
} break ;
2017-11-12 03:42:56 +01:00
case WINDOW_MOVE_DOWN : {
2022-03-02 15:37:10 +01:00
if ( tab_container - > get_current_tab ( ) < tab_container - > get_tab_count ( ) - 1 ) {
2015-11-17 13:46:08 +01:00
tab_container - > move_child ( current , tab_container - > get_current_tab ( ) + 1 ) ;
2022-07-31 21:43:11 +02:00
tab_container - > set_current_tab ( tab_container - > get_current_tab ( ) ) ;
2015-11-17 13:46:08 +01:00
_update_script_names ( ) ;
}
} break ;
default : {
if ( p_option > = WINDOW_SELECT_BASE ) {
2022-07-31 21:43:11 +02:00
_go_to_tab ( p_option - WINDOW_SELECT_BASE ) ;
2019-06-03 21:57:06 +02:00
_update_script_names ( ) ;
2015-11-17 13:46:08 +01:00
}
2014-02-10 02:10:30 +01:00
}
2015-11-17 13:46:08 +01:00
}
2017-04-17 02:41:24 +02:00
} else {
2017-08-24 22:58:51 +02:00
EditorHelp * help = Object : : cast_to < EditorHelp > ( tab_container - > get_current_tab_control ( ) ) ;
2017-04-17 02:41:24 +02:00
if ( help ) {
switch ( p_option ) {
case HELP_SEARCH_FIND : {
help - > popup_search ( ) ;
} break ;
case HELP_SEARCH_FIND_NEXT : {
help - > search_again ( ) ;
} break ;
2019-10-09 17:41:49 +02:00
case HELP_SEARCH_FIND_PREVIOUS : {
help - > search_again ( true ) ;
} break ;
2017-04-17 02:41:24 +02:00
case FILE_CLOSE : {
_close_current_tab ( ) ;
} break ;
case CLOSE_DOCS : {
_close_docs_tab ( ) ;
} break ;
2017-11-20 06:15:40 +01:00
case CLOSE_OTHER_TABS : {
_close_other_tabs ( ) ;
} break ;
2017-04-17 02:41:24 +02:00
case CLOSE_ALL : {
_close_all_tabs ( ) ;
} break ;
2017-11-12 03:42:56 +01:00
case WINDOW_MOVE_UP : {
if ( tab_container - > get_current_tab ( ) > 0 ) {
tab_container - > move_child ( help , tab_container - > get_current_tab ( ) - 1 ) ;
2022-07-31 21:43:11 +02:00
tab_container - > set_current_tab ( tab_container - > get_current_tab ( ) ) ;
2017-11-12 03:42:56 +01:00
_update_script_names ( ) ;
}
} break ;
case WINDOW_MOVE_DOWN : {
2022-03-02 15:37:10 +01:00
if ( tab_container - > get_current_tab ( ) < tab_container - > get_tab_count ( ) - 1 ) {
2017-11-12 03:42:56 +01:00
tab_container - > move_child ( help , tab_container - > get_current_tab ( ) + 1 ) ;
2022-07-31 21:43:11 +02:00
tab_container - > set_current_tab ( tab_container - > get_current_tab ( ) ) ;
2017-11-12 03:42:56 +01:00
_update_script_names ( ) ;
}
} break ;
2017-04-17 02:41:24 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
}
2018-06-21 11:10:43 +02:00
void ScriptEditor : : _theme_option ( int p_option ) {
switch ( p_option ) {
case THEME_IMPORT : {
2020-03-06 18:00:16 +01:00
file_dialog - > set_file_mode ( EditorFileDialog : : FILE_MODE_OPEN_FILE ) ;
2018-06-21 11:10:43 +02:00
file_dialog - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
file_dialog_option = THEME_IMPORT ;
file_dialog - > clear_filters ( ) ;
file_dialog - > add_filter ( " *.tet " ) ;
file_dialog - > set_title ( TTR ( " Import Theme " ) ) ;
2024-03-21 09:42:38 +01:00
file_dialog - > popup_file_dialog ( ) ;
2018-06-21 11:10:43 +02:00
} break ;
case THEME_RELOAD : {
EditorSettings : : get_singleton ( ) - > load_text_editor_theme ( ) ;
} break ;
case THEME_SAVE : {
2019-05-23 17:18:24 +02:00
if ( EditorSettings : : get_singleton ( ) - > is_default_text_editor_theme ( ) ) {
ScriptEditor : : _show_save_theme_as_dialog ( ) ;
} else if ( ! EditorSettings : : get_singleton ( ) - > save_text_editor_theme ( ) ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Error while saving theme " ) , TTR ( " Error saving " ) ) ;
2018-06-21 11:10:43 +02:00
}
} break ;
case THEME_SAVE_AS : {
2019-05-23 17:18:24 +02:00
ScriptEditor : : _show_save_theme_as_dialog ( ) ;
2018-06-21 11:10:43 +02:00
} break ;
}
}
2019-05-23 17:18:24 +02:00
void ScriptEditor : : _show_save_theme_as_dialog ( ) {
2020-03-06 18:00:16 +01:00
file_dialog - > set_file_mode ( EditorFileDialog : : FILE_MODE_SAVE_FILE ) ;
2019-05-23 17:18:24 +02:00
file_dialog - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
file_dialog_option = THEME_SAVE_AS ;
file_dialog - > clear_filters ( ) ;
file_dialog - > add_filter ( " *.tet " ) ;
2022-10-18 16:43:37 +02:00
file_dialog - > set_current_path ( EditorPaths : : get_singleton ( ) - > get_text_editor_themes_dir ( ) . path_join ( EDITOR_GET ( " text_editor/theme/color_theme " ) ) ) ;
2019-05-23 17:18:24 +02:00
file_dialog - > set_title ( TTR ( " Save Theme As... " ) ) ;
2024-03-21 09:42:38 +01:00
file_dialog - > popup_file_dialog ( ) ;
2019-05-23 17:18:24 +02:00
}
2022-01-21 05:12:48 +01:00
bool ScriptEditor : : _has_docs_tab ( ) const {
2022-03-02 15:37:10 +01:00
const int child_count = tab_container - > get_tab_count ( ) ;
2022-01-21 05:12:48 +01:00
for ( int i = 0 ; i < child_count ; i + + ) {
2022-03-02 15:37:10 +01:00
if ( Object : : cast_to < EditorHelp > ( tab_container - > get_tab_control ( i ) ) ) {
2022-01-21 05:12:48 +01:00
return true ;
}
}
return false ;
}
bool ScriptEditor : : _has_script_tab ( ) const {
2022-03-02 15:37:10 +01:00
const int child_count = tab_container - > get_tab_count ( ) ;
2022-01-21 05:12:48 +01:00
for ( int i = 0 ; i < child_count ; i + + ) {
2022-03-02 15:37:10 +01:00
if ( Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ) {
2022-01-21 05:12:48 +01:00
return true ;
}
}
return false ;
}
void ScriptEditor : : _prepare_file_menu ( ) {
PopupMenu * menu = file_menu - > get_popup ( ) ;
const bool current_is_doc = _get_current_editor ( ) = = nullptr ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_REOPEN_CLOSED ) , previous_scripts . is_empty ( ) ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_SAVE ) , current_is_doc ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_SAVE_AS ) , current_is_doc ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_SAVE_ALL ) , ! _has_script_tab ( ) ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_TOOL_RELOAD_SOFT ) , current_is_doc ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_COPY_PATH ) , current_is_doc ) ;
menu - > set_item_disabled ( menu - > get_item_index ( SHOW_IN_FILE_SYSTEM ) , current_is_doc ) ;
menu - > set_item_disabled ( menu - > get_item_index ( WINDOW_PREV ) , history_pos < = 0 ) ;
menu - > set_item_disabled ( menu - > get_item_index ( WINDOW_NEXT ) , history_pos > = history . size ( ) - 1 ) ;
2022-03-02 15:37:10 +01:00
menu - > set_item_disabled ( menu - > get_item_index ( FILE_CLOSE ) , tab_container - > get_tab_count ( ) < 1 ) ;
menu - > set_item_disabled ( menu - > get_item_index ( CLOSE_ALL ) , tab_container - > get_tab_count ( ) < 1 ) ;
menu - > set_item_disabled ( menu - > get_item_index ( CLOSE_OTHER_TABS ) , tab_container - > get_tab_count ( ) < = 1 ) ;
2022-01-21 05:12:48 +01:00
menu - > set_item_disabled ( menu - > get_item_index ( CLOSE_DOCS ) , ! _has_docs_tab ( ) ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_RUN ) , current_is_doc ) ;
}
2023-03-03 19:13:58 +01:00
void ScriptEditor : : _file_menu_closed ( ) {
PopupMenu * menu = file_menu - > get_popup ( ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_REOPEN_CLOSED ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_SAVE ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_SAVE_AS ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_SAVE_ALL ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_TOOL_RELOAD_SOFT ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_COPY_PATH ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( SHOW_IN_FILE_SYSTEM ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( WINDOW_PREV ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( WINDOW_NEXT ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_CLOSE ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( CLOSE_ALL ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( CLOSE_OTHER_TABS ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( CLOSE_DOCS ) , false ) ;
menu - > set_item_disabled ( menu - > get_item_index ( FILE_RUN ) , false ) ;
}
2014-02-10 02:10:30 +01:00
void ScriptEditor : : _tab_changed ( int p_which ) {
ensure_select_current ( ) ;
}
void ScriptEditor : : _notification ( int p_what ) {
2017-07-26 16:02:53 +02:00
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
2023-04-12 21:02:28 +02:00
EditorRunBar : : get_singleton ( ) - > connect ( " stop_pressed " , callable_mp ( this , & ScriptEditor : : _editor_stop ) ) ;
2024-02-18 03:16:58 +01:00
_apply_editor_settings ( ) ;
2022-08-29 11:04:31 +02:00
[[fallthrough]] ;
}
2022-11-02 15:23:25 +01:00
2020-09-03 13:22:16 +02:00
case NOTIFICATION_TRANSLATION_CHANGED :
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED :
2019-08-08 18:39:53 +02:00
case NOTIFICATION_THEME_CHANGED : {
2023-09-06 16:11:05 +02:00
tab_container - > add_theme_style_override ( " panel " , get_theme_stylebox ( SNAME ( " ScriptEditor " ) , EditorStringName ( EditorStyles ) ) ) ;
2023-08-13 02:33:39 +02:00
help_search - > set_icon ( get_editor_theme_icon ( SNAME ( " HelpSearch " ) ) ) ;
site_search - > set_icon ( get_editor_theme_icon ( SNAME ( " ExternalLink " ) ) ) ;
2014-02-10 02:10:30 +01:00
2020-09-03 13:22:16 +02:00
if ( is_layout_rtl ( ) ) {
2023-08-13 02:33:39 +02:00
script_forward - > set_icon ( get_editor_theme_icon ( SNAME ( " Back " ) ) ) ;
script_back - > set_icon ( get_editor_theme_icon ( SNAME ( " Forward " ) ) ) ;
2020-09-03 13:22:16 +02:00
} else {
2023-08-13 02:33:39 +02:00
script_forward - > set_icon ( get_editor_theme_icon ( SNAME ( " Forward " ) ) ) ;
script_back - > set_icon ( get_editor_theme_icon ( SNAME ( " Back " ) ) ) ;
2020-09-03 13:22:16 +02:00
}
2019-08-08 18:39:53 +02:00
2023-08-13 02:33:39 +02:00
members_overview_alphabeta_sort_button - > set_icon ( get_editor_theme_icon ( SNAME ( " Sort " ) ) ) ;
2019-08-08 18:39:53 +02:00
2023-08-13 02:33:39 +02:00
filter_scripts - > set_right_icon ( get_editor_theme_icon ( SNAME ( " Search " ) ) ) ;
filter_methods - > set_right_icon ( get_editor_theme_icon ( SNAME ( " Search " ) ) ) ;
2019-08-08 18:39:53 +02:00
2023-09-06 16:11:05 +02:00
filename - > add_theme_style_override ( " normal " , get_theme_stylebox ( SNAME ( " normal " ) , SNAME ( " LineEdit " ) ) ) ;
2019-08-08 18:39:53 +02:00
2022-03-06 00:57:42 +01:00
recent_scripts - > reset_size ( ) ;
2021-05-20 07:55:32 +02:00
2021-05-26 18:28:38 +02:00
if ( is_inside_tree ( ) ) {
_update_script_names ( ) ;
}
2017-07-26 16:02:53 +02:00
} break ;
2014-02-10 02:10:30 +01:00
2017-07-26 16:02:53 +02:00
case NOTIFICATION_READY : {
2023-09-06 16:11:05 +02:00
// Can't set own styles in NOTIFICATION_THEME_CHANGED, so for now this will do.
add_theme_style_override ( " panel " , get_theme_stylebox ( SNAME ( " ScriptEditorPanel " ) , SNAME ( " EditorStyles " ) ) ) ;
2020-02-21 18:28:45 +01:00
get_tree ( ) - > connect ( " tree_changed " , callable_mp ( this , & ScriptEditor : : _tree_changed ) ) ;
2021-11-17 21:08:55 +01:00
InspectorDock : : get_singleton ( ) - > connect ( " request_help " , callable_mp ( this , & ScriptEditor : : _help_class_open ) ) ;
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > connect ( " request_help_search " , callable_mp ( this , & ScriptEditor : : _help_search ) ) ;
2023-04-09 20:43:55 +02:00
EditorNode : : get_singleton ( ) - > connect ( " scene_closed " , callable_mp ( this , & ScriptEditor : : _close_builtin_scripts_from_scene ) ) ;
2022-11-02 15:23:25 +01:00
EditorNode : : get_singleton ( ) - > connect ( " script_add_function_request " , callable_mp ( this , & ScriptEditor : : _add_callback ) ) ;
EditorNode : : get_singleton ( ) - > connect ( " resource_saved " , callable_mp ( this , & ScriptEditor : : _res_saved_callback ) ) ;
EditorNode : : get_singleton ( ) - > connect ( " scene_saved " , callable_mp ( this , & ScriptEditor : : _scene_saved_callback ) ) ;
FileSystemDock : : get_singleton ( ) - > connect ( " files_moved " , callable_mp ( this , & ScriptEditor : : _files_moved ) ) ;
FileSystemDock : : get_singleton ( ) - > connect ( " file_removed " , callable_mp ( this , & ScriptEditor : : _file_removed ) ) ;
script_list - > connect ( " item_selected " , callable_mp ( this , & ScriptEditor : : _script_selected ) ) ;
members_overview - > connect ( " item_selected " , callable_mp ( this , & ScriptEditor : : _members_overview_selected ) ) ;
help_overview - > connect ( " item_selected " , callable_mp ( this , & ScriptEditor : : _help_overview_selected ) ) ;
script_split - > connect ( " dragged " , callable_mp ( this , & ScriptEditor : : _split_dragged ) ) ;
list_split - > connect ( " dragged " , callable_mp ( this , & ScriptEditor : : _split_dragged ) ) ;
EditorSettings : : get_singleton ( ) - > connect ( " settings_changed " , callable_mp ( this , & ScriptEditor : : _editor_settings_changed ) ) ;
EditorFileSystem : : get_singleton ( ) - > connect ( " filesystem_changed " , callable_mp ( this , & ScriptEditor : : _filesystem_changed ) ) ;
2017-07-26 16:02:53 +02:00
} break ;
2014-02-10 02:10:30 +01:00
2017-07-26 16:02:53 +02:00
case NOTIFICATION_EXIT_TREE : {
2023-04-12 21:02:28 +02:00
EditorRunBar : : get_singleton ( ) - > disconnect ( " stop_pressed " , callable_mp ( this , & ScriptEditor : : _editor_stop ) ) ;
2017-07-26 16:02:53 +02:00
} break ;
2014-02-10 02:10:30 +01:00
2022-10-03 12:41:56 +02:00
case NOTIFICATION_APPLICATION_FOCUS_IN : {
2017-07-26 16:02:53 +02:00
_test_script_times_on_disk ( ) ;
_update_modified_scripts_for_external_editor ( ) ;
} break ;
2014-02-10 02:10:30 +01:00
}
}
2016-08-25 22:45:20 +02:00
bool ScriptEditor : : can_take_away_focus ( ) const {
2018-02-12 02:36:15 +01:00
ScriptEditorBase * current = _get_current_editor ( ) ;
2020-05-14 16:41:43 +02:00
if ( current ) {
2018-02-12 02:36:15 +01:00
return current - > can_lose_focus_on_node_selection ( ) ;
2020-05-14 16:41:43 +02:00
} else {
2016-08-25 22:45:20 +02:00
return true ;
2020-05-14 16:41:43 +02:00
}
2016-08-25 22:45:20 +02:00
}
2016-07-07 01:35:49 +02:00
2023-04-09 20:43:55 +02:00
void ScriptEditor : : _close_builtin_scripts_from_scene ( const String & p_scene ) {
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2016-07-07 01:35:49 +02:00
2016-08-03 00:11:05 +02:00
if ( se ) {
2022-09-29 11:53:28 +02:00
Ref < Script > scr = se - > get_edited_resource ( ) ;
if ( scr = = nullptr | | ! scr . is_valid ( ) ) {
2016-07-07 01:35:49 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2016-07-07 01:35:49 +02:00
2023-04-09 20:43:55 +02:00
if ( scr - > is_built_in ( ) & & scr - > get_path ( ) . begins_with ( p_scene ) ) { // Is an internal script and belongs to scene being closed.
2021-11-06 02:15:19 +01:00
_close_tab ( i , false ) ;
2016-07-07 01:35:49 +02:00
i - - ;
}
}
}
}
2015-12-09 13:08:41 +01:00
void ScriptEditor : : edited_scene_changed ( ) {
_update_modified_scripts_for_external_editor ( ) ;
}
2014-02-10 02:10:30 +01:00
2017-07-06 09:18:20 +02:00
void ScriptEditor : : notify_script_close ( const Ref < Script > & p_script ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " script_close " ) , p_script ) ;
2017-07-06 09:18:20 +02:00
}
void ScriptEditor : : notify_script_changed ( const Ref < Script > & p_script ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " editor_script_changed " ) , p_script ) ;
2017-07-06 09:18:20 +02:00
}
2014-02-10 02:10:30 +01:00
void ScriptEditor : : get_breakpoints ( List < String > * p_breakpoints ) {
2022-05-19 17:00:06 +02:00
HashSet < String > loaded_scripts ;
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! se ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
Ref < Script > scr = se - > get_edited_resource ( ) ;
if ( scr = = nullptr ) {
2018-05-28 17:52:28 +02:00
continue ;
}
2022-09-29 11:53:28 +02:00
String base = scr - > get_path ( ) ;
2021-10-07 20:46:44 +02:00
loaded_scripts . insert ( base ) ;
2021-12-09 10:42:46 +01:00
if ( base . begins_with ( " local:// " ) | | base . is_empty ( ) ) {
2020-07-23 19:51:17 +02:00
continue ;
}
2014-02-10 02:10:30 +01:00
2022-08-05 03:41:48 +02:00
PackedInt32Array bpoints = se - > get_breakpoints ( ) ;
2020-07-26 16:57:23 +02:00
for ( int j = 0 ; j < bpoints . size ( ) ; j + + ) {
p_breakpoints - > push_back ( base + " : " + itos ( ( int ) bpoints [ j ] + 1 ) ) ;
2014-02-10 02:10:30 +01:00
}
}
2021-10-07 20:46:44 +02:00
// Load breakpoints that are in closed scripts.
List < String > cached_editors ;
script_editor_cache - > get_sections ( & cached_editors ) ;
for ( const String & E : cached_editors ) {
if ( loaded_scripts . has ( E ) ) {
continue ;
}
Array breakpoints = _get_cached_breakpoints_for_script ( E ) ;
for ( int i = 0 ; i < breakpoints . size ( ) ; i + + ) {
p_breakpoints - > push_back ( E + " : " + itos ( ( int ) breakpoints [ i ] + 1 ) ) ;
}
}
2014-02-10 02:10:30 +01:00
}
2017-05-28 16:20:38 +02:00
void ScriptEditor : : _members_overview_selected ( int p_idx ) {
2018-02-12 02:36:15 +01:00
ScriptEditorBase * se = _get_current_editor ( ) ;
2017-05-28 16:20:38 +02:00
if ( ! se ) {
return ;
}
2018-02-09 18:35:28 +01:00
// Go to the member's line and reset the cursor column. We can't change scroll_position
// directly until we have gone to the line first, since code might be folded.
2017-12-13 06:40:12 +01:00
se - > goto_line ( members_overview - > get_item_metadata ( p_idx ) ) ;
Dictionary state = se - > get_edit_state ( ) ;
2017-10-08 15:29:27 +02:00
state [ " column " ] = 0 ;
2018-02-09 18:35:28 +01:00
state [ " scroll_position " ] = members_overview - > get_item_metadata ( p_idx ) ;
2017-10-08 15:29:27 +02:00
se - > set_edit_state ( state ) ;
2017-05-28 16:20:38 +02:00
}
2017-09-14 02:56:37 +02:00
void ScriptEditor : : _help_overview_selected ( int p_idx ) {
2022-03-02 15:37:10 +01:00
Node * current = tab_container - > get_tab_control ( tab_container - > get_current_tab ( ) ) ;
2017-09-14 02:56:37 +02:00
EditorHelp * se = Object : : cast_to < EditorHelp > ( current ) ;
if ( ! se ) {
return ;
}
se - > scroll_to_section ( help_overview - > get_item_metadata ( p_idx ) ) ;
}
2015-06-22 05:03:19 +02:00
void ScriptEditor : : _script_selected ( int p_idx ) {
2021-08-13 23:31:57 +02:00
grab_focus_block = ! Input : : get_singleton ( ) - > is_mouse_button_pressed ( MouseButton : : LEFT ) ; //amazing hack, simply amazing
2015-11-17 13:46:08 +01:00
_go_to_tab ( script_list - > get_item_metadata ( p_idx ) ) ;
2015-06-22 05:03:19 +02:00
grab_focus_block = false ;
}
2014-02-10 02:10:30 +01:00
void ScriptEditor : : ensure_select_current ( ) {
2022-03-02 15:37:10 +01:00
if ( tab_container - > get_tab_count ( ) & & tab_container - > get_current_tab ( ) > = 0 ) {
2018-02-12 02:36:15 +01:00
ScriptEditorBase * se = _get_current_editor ( ) ;
2016-08-03 00:11:05 +02:00
if ( se ) {
2022-10-23 10:45:44 +02:00
se - > enable_editor ( this ) ;
2019-11-20 10:09:59 +01:00
2020-05-14 16:41:43 +02:00
if ( ! grab_focus_block & & is_visible_in_tree ( ) ) {
2016-08-03 00:11:05 +02:00
se - > ensure_focus ( ) ;
2020-05-14 16:41:43 +02:00
}
2015-11-17 13:46:08 +01:00
}
2015-06-22 05:03:19 +02:00
}
2021-06-24 15:38:29 +02:00
_update_find_replace_bar ( ) ;
2015-06-22 05:03:19 +02:00
2016-08-03 00:11:05 +02:00
_update_selected_editor_menu ( ) ;
2015-06-22 05:03:19 +02:00
}
2023-08-15 06:40:32 +02:00
bool ScriptEditor : : is_editor_floating ( ) {
return is_floating ;
}
2022-05-19 17:00:06 +02:00
void ScriptEditor : : _find_scripts ( Node * p_base , Node * p_current , HashSet < Ref < Script > > & used ) {
2020-05-14 16:41:43 +02:00
if ( p_current ! = p_base & & p_current - > get_owner ( ) ! = p_base ) {
2015-06-22 05:03:19 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-06-22 05:03:19 +02:00
if ( p_current - > get_script_instance ( ) ) {
Ref < Script > scr = p_current - > get_script ( ) ;
2020-05-14 16:41:43 +02:00
if ( scr . is_valid ( ) ) {
2015-06-22 05:03:19 +02:00
used . insert ( scr ) ;
2020-05-14 16:41:43 +02:00
}
2015-06-22 05:03:19 +02:00
}
for ( int i = 0 ; i < p_current - > get_child_count ( ) ; i + + ) {
_find_scripts ( p_base , p_current - > get_child ( i ) , used ) ;
}
}
2015-11-17 13:46:08 +01:00
struct _ScriptEditorItemData {
String name ;
2017-02-02 13:31:01 +01:00
String sort_key ;
2019-06-11 20:43:37 +02:00
Ref < Texture2D > icon ;
2021-12-02 13:01:49 +01:00
bool tool = false ;
2020-11-24 10:12:55 +01:00
int index = 0 ;
2015-11-17 13:46:08 +01:00
String tooltip ;
2020-11-24 10:12:55 +01:00
bool used = false ;
int category = 0 ;
Node * ref = nullptr ;
2015-11-17 13:46:08 +01:00
bool operator < ( const _ScriptEditorItemData & id ) const {
2019-05-22 22:38:14 +02:00
if ( category = = id . category ) {
if ( sort_key = = id . sort_key ) {
return index < id . index ;
} else {
2024-02-02 16:50:23 +01:00
return sort_key . filenocasecmp_to ( id . sort_key ) < 0 ;
2019-05-22 22:38:14 +02:00
}
} else {
return category < id . category ;
}
2015-11-17 13:46:08 +01:00
}
} ;
2017-05-28 16:20:38 +02:00
void ScriptEditor : : _update_members_overview_visibility ( ) {
2018-02-12 02:36:15 +01:00
ScriptEditorBase * se = _get_current_editor ( ) ;
2017-05-28 16:20:38 +02:00
if ( ! se ) {
2018-06-05 23:18:11 +02:00
members_overview_alphabeta_sort_button - > set_visible ( false ) ;
2017-05-28 16:20:38 +02:00
members_overview - > set_visible ( false ) ;
2018-06-02 02:28:49 +02:00
overview_vbox - > set_visible ( false ) ;
2017-05-28 16:20:38 +02:00
return ;
}
if ( members_overview_enabled & & se - > show_members_overview ( ) ) {
2018-06-05 23:18:11 +02:00
members_overview_alphabeta_sort_button - > set_visible ( true ) ;
2022-07-31 01:07:46 +02:00
filter_methods - > set_visible ( true ) ;
2017-05-28 16:20:38 +02:00
members_overview - > set_visible ( true ) ;
2018-06-02 02:28:49 +02:00
overview_vbox - > set_visible ( true ) ;
2017-05-28 16:20:38 +02:00
} else {
2018-06-05 23:18:11 +02:00
members_overview_alphabeta_sort_button - > set_visible ( false ) ;
2022-07-31 01:07:46 +02:00
filter_methods - > set_visible ( false ) ;
2017-05-28 16:20:38 +02:00
members_overview - > set_visible ( false ) ;
2018-06-02 02:28:49 +02:00
overview_vbox - > set_visible ( false ) ;
2017-05-28 16:20:38 +02:00
}
}
2018-04-30 14:27:00 +02:00
void ScriptEditor : : _toggle_members_overview_alpha_sort ( bool p_alphabetic_sort ) {
2021-08-15 19:14:46 +02:00
EditorSettings : : get_singleton ( ) - > set ( " text_editor/script_list/sort_members_outline_alphabetically " , p_alphabetic_sort ) ;
2018-04-30 14:27:00 +02:00
_update_members_overview ( ) ;
}
2017-05-28 16:20:38 +02:00
void ScriptEditor : : _update_members_overview ( ) {
members_overview - > clear ( ) ;
2018-02-12 02:36:15 +01:00
ScriptEditorBase * se = _get_current_editor ( ) ;
2017-05-28 16:20:38 +02:00
if ( ! se ) {
return ;
}
Vector < String > functions = se - > get_functions ( ) ;
2022-10-18 16:43:37 +02:00
if ( EDITOR_GET ( " text_editor/script_list/sort_members_outline_alphabetically " ) ) {
2018-04-30 14:27:00 +02:00
functions . sort ( ) ;
}
2017-05-28 16:20:38 +02:00
for ( int i = 0 ; i < functions . size ( ) ; i + + ) {
2019-06-03 21:57:06 +02:00
String filter = filter_methods - > get_text ( ) ;
String name = functions [ i ] . get_slice ( " : " , 0 ) ;
2022-01-27 00:03:56 +01:00
if ( filter . is_empty ( ) | | filter . is_subsequence_ofn ( name ) ) {
2019-06-03 21:57:06 +02:00
members_overview - > add_item ( name ) ;
2022-03-12 01:06:45 +01:00
members_overview - > set_item_metadata ( - 1 , functions [ i ] . get_slice ( " : " , 1 ) . to_int ( ) - 1 ) ;
2019-06-03 21:57:06 +02:00
}
2017-05-28 16:20:38 +02:00
}
2018-06-05 23:18:11 +02:00
2018-05-28 17:52:28 +02:00
String path = se - > get_edited_resource ( ) - > get_path ( ) ;
2018-06-05 23:18:11 +02:00
bool built_in = ! path . is_resource_file ( ) ;
String name = built_in ? path . get_file ( ) : se - > get_name ( ) ;
filename - > set_text ( name ) ;
2017-05-28 16:20:38 +02:00
}
2017-09-14 02:56:37 +02:00
void ScriptEditor : : _update_help_overview_visibility ( ) {
int selected = tab_container - > get_current_tab ( ) ;
2022-03-02 15:37:10 +01:00
if ( selected < 0 | | selected > = tab_container - > get_tab_count ( ) ) {
2017-10-14 19:51:35 +02:00
help_overview - > set_visible ( false ) ;
2017-09-14 02:56:37 +02:00
return ;
2017-10-14 19:51:35 +02:00
}
2017-09-14 02:56:37 +02:00
2022-03-02 15:37:10 +01:00
Node * current = tab_container - > get_tab_control ( tab_container - > get_current_tab ( ) ) ;
2017-09-14 02:56:37 +02:00
EditorHelp * se = Object : : cast_to < EditorHelp > ( current ) ;
if ( ! se ) {
help_overview - > set_visible ( false ) ;
return ;
}
if ( help_overview_enabled ) {
2018-06-05 23:18:11 +02:00
members_overview_alphabeta_sort_button - > set_visible ( false ) ;
2022-07-31 01:07:46 +02:00
filter_methods - > set_visible ( false ) ;
2017-09-14 02:56:37 +02:00
help_overview - > set_visible ( true ) ;
2018-06-02 02:28:49 +02:00
overview_vbox - > set_visible ( true ) ;
2018-06-05 23:18:11 +02:00
filename - > set_text ( se - > get_name ( ) ) ;
2017-09-14 02:56:37 +02:00
} else {
help_overview - > set_visible ( false ) ;
2018-06-02 02:28:49 +02:00
overview_vbox - > set_visible ( false ) ;
2017-09-14 02:56:37 +02:00
}
}
void ScriptEditor : : _update_help_overview ( ) {
2017-10-14 19:51:35 +02:00
help_overview - > clear ( ) ;
2017-09-14 02:56:37 +02:00
int selected = tab_container - > get_current_tab ( ) ;
2022-03-02 15:37:10 +01:00
if ( selected < 0 | | selected > = tab_container - > get_tab_count ( ) ) {
2017-09-14 02:56:37 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-09-14 02:56:37 +02:00
2022-03-02 15:37:10 +01:00
Node * current = tab_container - > get_tab_control ( tab_container - > get_current_tab ( ) ) ;
2017-09-14 02:56:37 +02:00
EditorHelp * se = Object : : cast_to < EditorHelp > ( current ) ;
if ( ! se ) {
return ;
}
2020-03-17 07:33:00 +01:00
Vector < Pair < String , int > > sections = se - > get_sections ( ) ;
2017-09-14 02:56:37 +02:00
for ( int i = 0 ; i < sections . size ( ) ; i + + ) {
help_overview - > add_item ( sections [ i ] . first ) ;
help_overview - > set_item_metadata ( i , sections [ i ] . second ) ;
}
}
2015-11-17 13:46:08 +01:00
void ScriptEditor : : _update_script_colors ( ) {
2022-10-18 16:43:37 +02:00
bool script_temperature_enabled = EDITOR_GET ( " text_editor/script_list/script_temperature_enabled " ) ;
2015-11-17 13:46:08 +01:00
2022-10-18 16:43:37 +02:00
int hist_size = EDITOR_GET ( " text_editor/script_list/script_temperature_history_size " ) ;
2023-08-13 02:33:39 +02:00
Color hot_color = get_theme_color ( SNAME ( " accent_color " ) , EditorStringName ( Editor ) ) ;
2021-12-02 13:01:49 +01:00
hot_color . set_s ( hot_color . get_s ( ) * 0.9 ) ;
2023-08-13 02:33:39 +02:00
Color cold_color = get_theme_color ( SNAME ( " font_color " ) , EditorStringName ( Editor ) ) ;
2015-11-17 13:46:08 +01:00
for ( int i = 0 ; i < script_list - > get_item_count ( ) ; i + + ) {
int c = script_list - > get_item_metadata ( i ) ;
2022-03-02 15:37:10 +01:00
Node * n = tab_container - > get_tab_control ( c ) ;
2020-05-14 16:41:43 +02:00
if ( ! n ) {
2015-11-17 13:46:08 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-11-17 13:46:08 +01:00
script_list - > set_item_custom_bg_color ( i , Color ( 0 , 0 , 0 , 0 ) ) ;
2019-03-23 01:57:28 +01:00
if ( script_temperature_enabled ) {
2022-04-01 20:30:23 +02:00
int pass = n - > get_meta ( " __editor_pass " , - 1 ) ;
if ( pass < 0 ) {
2016-09-15 16:35:25 +02:00
continue ;
}
int h = edit_pass - pass ;
if ( h > hist_size ) {
continue ;
}
int non_zero_hist_size = ( hist_size = = 0 ) ? 1 : hist_size ;
float v = Math : : ease ( ( edit_pass - pass ) / float ( non_zero_hist_size ) , 0.4 ) ;
2020-03-16 10:07:33 +01:00
script_list - > set_item_custom_fg_color ( i , hot_color . lerp ( cold_color , v ) ) ;
2016-09-07 18:54:20 +02:00
}
2015-11-17 13:46:08 +01:00
}
}
2015-06-22 05:03:19 +02:00
void ScriptEditor : : _update_script_names ( ) {
2020-05-14 16:41:43 +02:00
if ( restoring_layout ) {
2016-07-18 17:30:43 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-07-18 17:30:43 +02:00
2022-05-19 17:00:06 +02:00
HashSet < Ref < Script > > used ;
2015-06-22 05:03:19 +02:00
Node * edited = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ;
if ( edited ) {
_find_scripts ( edited , edited , used ) ;
}
script_list - > clear ( ) ;
2022-10-18 16:43:37 +02:00
bool split_script_help = EDITOR_GET ( " text_editor/script_list/group_help_pages " ) ;
ScriptSortBy sort_by = ( ScriptSortBy ) ( int ) EDITOR_GET ( " text_editor/script_list/sort_scripts_by " ) ;
ScriptListName display_as = ( ScriptListName ) ( int ) EDITOR_GET ( " text_editor/script_list/list_script_names_as " ) ;
2015-11-17 13:46:08 +01:00
Vector < _ScriptEditorItemData > sedata ;
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2016-08-03 00:11:05 +02:00
if ( se ) {
2020-03-12 13:37:40 +01:00
Ref < Texture2D > icon = se - > get_theme_icon ( ) ;
2018-05-28 17:52:28 +02:00
String path = se - > get_edited_resource ( ) - > get_path ( ) ;
2020-12-15 13:04:21 +01:00
bool saved = ! path . is_empty ( ) ;
2020-07-23 14:21:28 +02:00
if ( saved ) {
// The script might be deleted, moved, or renamed, so make sure
// to update original path to previously edited resource.
se - > set_meta ( " _edit_res_path " , path ) ;
}
2021-11-06 02:15:19 +01:00
String name = se - > get_name ( ) ;
2021-12-02 13:01:49 +01:00
Ref < Script > scr = se - > get_edited_resource ( ) ;
2015-06-22 05:03:19 +02:00
2015-11-17 13:46:08 +01:00
_ScriptEditorItemData sd ;
sd . icon = icon ;
sd . name = name ;
2020-07-23 14:21:28 +02:00
sd . tooltip = saved ? path : TTR ( " Unsaved file. " ) ;
2015-11-17 13:46:08 +01:00
sd . index = i ;
2018-05-28 17:52:28 +02:00
sd . used = used . has ( se - > get_edited_resource ( ) ) ;
2015-11-18 13:20:46 +01:00
sd . category = 0 ;
2017-11-12 03:42:56 +01:00
sd . ref = se ;
2021-12-02 13:01:49 +01:00
if ( scr . is_valid ( ) ) {
sd . tool = scr - > is_tool ( ) ;
}
2017-03-05 16:44:50 +01:00
2017-02-02 13:31:01 +01:00
switch ( sort_by ) {
case SORT_BY_NAME : {
sd . sort_key = name . to_lower ( ) ;
} break ;
case SORT_BY_PATH : {
sd . sort_key = path ;
} break ;
2018-02-14 17:32:33 +01:00
case SORT_BY_NONE : {
sd . sort_key = " " ;
} break ;
2017-02-02 13:31:01 +01:00
}
2017-03-05 16:44:50 +01:00
2017-02-02 13:31:01 +01:00
switch ( display_as ) {
case DISPLAY_NAME : {
sd . name = name ;
} break ;
case DISPLAY_DIR_AND_NAME : {
2020-12-15 13:04:21 +01:00
if ( ! path . get_base_dir ( ) . get_file ( ) . is_empty ( ) ) {
2022-08-30 02:34:01 +02:00
sd . name = path . get_base_dir ( ) . get_file ( ) . path_join ( name ) ;
2017-02-02 13:31:01 +01:00
} else {
sd . name = name ;
}
} break ;
case DISPLAY_FULL_PATH : {
sd . name = path ;
} break ;
}
2020-07-23 14:21:28 +02:00
if ( ! saved ) {
sd . name = se - > get_name ( ) ;
}
2017-02-02 13:31:01 +01:00
2015-11-17 13:46:08 +01:00
sedata . push_back ( sd ) ;
}
2015-06-22 05:03:19 +02:00
2020-05-27 06:49:05 +02:00
Vector < String > disambiguated_script_names ;
Vector < String > full_script_paths ;
for ( int j = 0 ; j < sedata . size ( ) ; j + + ) {
2021-01-11 22:01:21 +01:00
String name = sedata [ j ] . name . replace ( " (*) " , " " ) ;
2022-10-18 16:43:37 +02:00
ScriptListName script_display = ( ScriptListName ) ( int ) EDITOR_GET ( " text_editor/script_list/list_script_names_as " ) ;
2021-01-11 22:01:21 +01:00
switch ( script_display ) {
case DISPLAY_NAME : {
name = name . get_file ( ) ;
} break ;
case DISPLAY_DIR_AND_NAME : {
2022-08-30 02:34:01 +02:00
name = name . get_base_dir ( ) . get_file ( ) . path_join ( name . get_file ( ) ) ;
2021-01-11 22:01:21 +01:00
} break ;
default :
break ;
}
disambiguated_script_names . append ( name ) ;
2020-05-27 06:49:05 +02:00
full_script_paths . append ( sedata [ j ] . tooltip ) ;
}
EditorNode : : disambiguate_filenames ( full_script_paths , disambiguated_script_names ) ;
for ( int j = 0 ; j < sedata . size ( ) ; j + + ) {
2020-07-31 22:43:40 +02:00
if ( sedata [ j ] . name . ends_with ( " (*) " ) ) {
sedata . write [ j ] . name = disambiguated_script_names [ j ] + " (*) " ;
} else {
sedata . write [ j ] . name = disambiguated_script_names [ j ] ;
}
2020-05-27 06:49:05 +02:00
}
2022-03-02 15:37:10 +01:00
EditorHelp * eh = Object : : cast_to < EditorHelp > ( tab_container - > get_tab_control ( i ) ) ;
2015-11-17 13:46:08 +01:00
if ( eh ) {
2017-01-03 03:03:46 +01:00
String name = eh - > get_class ( ) ;
2023-08-13 02:33:39 +02:00
Ref < Texture2D > icon = get_editor_theme_icon ( SNAME ( " Help " ) ) ;
2019-04-09 16:06:37 +02:00
String tooltip = vformat ( TTR ( " %s Class Reference " ) , name ) ;
2015-11-17 13:46:08 +01:00
_ScriptEditorItemData sd ;
sd . icon = icon ;
sd . name = name ;
2017-11-12 03:42:56 +01:00
sd . sort_key = name . to_lower ( ) ;
2015-11-17 13:46:08 +01:00
sd . tooltip = tooltip ;
sd . index = i ;
sd . used = false ;
2015-11-18 13:20:46 +01:00
sd . category = split_script_help ? 1 : 0 ;
2017-11-12 03:42:56 +01:00
sd . ref = eh ;
2015-11-17 13:46:08 +01:00
sedata . push_back ( sd ) ;
}
}
2020-12-15 13:04:21 +01:00
if ( _sort_list_on_update & & ! sedata . is_empty ( ) ) {
2017-11-12 03:42:56 +01:00
sedata . sort ( ) ;
// change actual order of tab_container so that the order can be rearranged by user
int cur_tab = tab_container - > get_current_tab ( ) ;
int prev_tab = tab_container - > get_previous_tab ( ) ;
int new_cur_tab = - 1 ;
int new_prev_tab = - 1 ;
for ( int i = 0 ; i < sedata . size ( ) ; i + + ) {
tab_container - > move_child ( sedata [ i ] . ref , i ) ;
if ( new_prev_tab = = - 1 & & sedata [ i ] . index = = prev_tab ) {
new_prev_tab = i ;
}
if ( new_cur_tab = = - 1 & & sedata [ i ] . index = = cur_tab ) {
new_cur_tab = i ;
}
2020-04-26 19:23:00 +02:00
// Update index of sd entries for sorted order
_ScriptEditorItemData sd = sedata [ i ] ;
sd . index = i ;
sedata . set ( i , sd ) ;
2017-11-12 03:42:56 +01:00
}
2022-10-22 23:54:37 +02:00
lock_history = true ;
2022-07-31 21:43:11 +02:00
_go_to_tab ( new_prev_tab ) ;
_go_to_tab ( new_cur_tab ) ;
2022-10-22 23:54:37 +02:00
lock_history = false ;
2017-11-12 03:42:56 +01:00
_sort_list_on_update = false ;
}
2015-11-17 13:46:08 +01:00
2019-06-03 21:57:06 +02:00
Vector < _ScriptEditorItemData > sedata_filtered ;
2015-11-17 13:46:08 +01:00
for ( int i = 0 ; i < sedata . size ( ) ; i + + ) {
2019-06-03 21:57:06 +02:00
String filter = filter_scripts - > get_text ( ) ;
2022-01-27 00:03:56 +01:00
if ( filter . is_empty ( ) | | filter . is_subsequence_ofn ( sedata [ i ] . name ) ) {
2019-06-03 21:57:06 +02:00
sedata_filtered . push_back ( sedata [ i ] ) ;
}
}
2015-11-17 13:46:08 +01:00
2023-08-13 02:33:39 +02:00
Color tool_color = get_theme_color ( SNAME ( " accent_color " ) , EditorStringName ( Editor ) ) ;
2021-12-02 13:01:49 +01:00
tool_color . set_s ( tool_color . get_s ( ) * 1.5 ) ;
2019-06-03 21:57:06 +02:00
for ( int i = 0 ; i < sedata_filtered . size ( ) ; i + + ) {
script_list - > add_item ( sedata_filtered [ i ] . name , sedata_filtered [ i ] . icon ) ;
2021-12-02 13:01:49 +01:00
if ( sedata_filtered [ i ] . tool ) {
2022-03-12 01:06:45 +01:00
script_list - > set_item_icon_modulate ( - 1 , tool_color ) ;
2021-12-02 13:01:49 +01:00
}
2015-11-17 13:46:08 +01:00
int index = script_list - > get_item_count ( ) - 1 ;
2019-06-03 21:57:06 +02:00
script_list - > set_item_tooltip ( index , sedata_filtered [ i ] . tooltip ) ;
script_list - > set_item_metadata ( index , sedata_filtered [ i ] . index ) ; /* Saving as metadata the script's index in the tab container and not the filtered one */
if ( sedata_filtered [ i ] . used ) {
2015-06-22 05:03:19 +02:00
script_list - > set_item_custom_bg_color ( index , Color ( 88 / 255.0 , 88 / 255.0 , 60 / 255.0 ) ) ;
}
2019-06-03 21:57:06 +02:00
if ( tab_container - > get_current_tab ( ) = = sedata_filtered [ i ] . index ) {
2015-06-22 05:03:19 +02:00
script_list - > select ( index ) ;
2022-07-31 00:14:44 +02:00
2019-06-03 21:57:06 +02:00
script_name_label - > set_text ( sedata_filtered [ i ] . name ) ;
script_icon - > set_texture ( sedata_filtered [ i ] . icon ) ;
2022-07-31 00:14:44 +02:00
2019-11-20 10:09:59 +01:00
ScriptEditorBase * se = _get_current_editor ( ) ;
if ( se ) {
2022-10-23 10:45:44 +02:00
se - > enable_editor ( this ) ;
2019-11-20 10:09:59 +01:00
_update_selected_editor_menu ( ) ;
}
2015-06-22 05:03:19 +02:00
}
2014-02-10 02:10:30 +01:00
}
2015-06-22 05:03:19 +02:00
2018-08-26 17:35:33 +02:00
if ( ! waiting_update_names ) {
_update_members_overview ( ) ;
_update_help_overview ( ) ;
} else {
waiting_update_names = false ;
}
2017-10-14 19:51:35 +02:00
_update_members_overview_visibility ( ) ;
_update_help_overview_visibility ( ) ;
2015-11-17 13:46:08 +01:00
_update_script_colors ( ) ;
2014-02-10 02:10:30 +01:00
}
2021-10-12 18:31:20 +02:00
Ref < TextFile > ScriptEditor : : _load_text_file ( const String & p_path , Error * r_error ) const {
2018-05-28 17:52:28 +02:00
if ( r_error ) {
* r_error = ERR_FILE_CANT_OPEN ;
}
String local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
String path = ResourceLoader : : path_remap ( local_path ) ;
TextFile * text_file = memnew ( TextFile ) ;
Ref < TextFile > text_res ( text_file ) ;
Error err = text_file - > load_text ( path ) ;
2022-05-03 01:43:50 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , Ref < Resource > ( ) , " Cannot load text file ' " + path + " '. " ) ;
2018-05-28 17:52:28 +02:00
text_file - > set_file_path ( local_path ) ;
text_file - > set_path ( local_path , true ) ;
2018-12-02 17:24:23 +01:00
if ( ResourceLoader : : get_timestamp_on_load ( ) ) {
text_file - > set_last_modified_time ( FileAccess : : get_modified_time ( path ) ) ;
}
2018-05-28 17:52:28 +02:00
if ( r_error ) {
* r_error = OK ;
}
return text_res ;
}
Error ScriptEditor : : _save_text_file ( Ref < TextFile > p_text_file , const String & p_path ) {
Ref < TextFile > sqscr = p_text_file ;
ERR_FAIL_COND_V ( sqscr . is_null ( ) , ERR_INVALID_PARAMETER ) ;
String source = sqscr - > get_text ( ) ;
Error err ;
2022-04-12 09:12:40 +02:00
{
Ref < FileAccess > file = FileAccess : : open ( p_path , FileAccess : : WRITE , & err ) ;
2018-05-28 17:52:28 +02:00
2022-04-12 09:12:40 +02:00
ERR_FAIL_COND_V_MSG ( err , err , " Cannot save text file ' " + p_path + " '. " ) ;
2018-05-28 17:52:28 +02:00
2022-04-12 09:12:40 +02:00
file - > store_string ( source ) ;
if ( file - > get_error ( ) ! = OK & & file - > get_error ( ) ! = ERR_FILE_EOF ) {
return ERR_CANT_CREATE ;
}
2018-05-28 17:52:28 +02:00
}
2018-12-02 17:24:23 +01:00
if ( ResourceSaver : : get_timestamp_on_save ( ) ) {
p_text_file - > set_last_modified_time ( FileAccess : : get_modified_time ( p_path ) ) ;
}
2023-01-18 17:32:28 +01:00
EditorFileSystem : : get_singleton ( ) - > update_file ( p_path ) ;
2018-05-28 17:52:28 +02:00
_res_saved_callback ( sqscr ) ;
return OK ;
}
2022-05-03 01:43:50 +02:00
bool ScriptEditor : : edit ( const Ref < Resource > & p_resource , int p_line , int p_col , bool p_grab_focus ) {
2020-05-14 16:41:43 +02:00
if ( p_resource . is_null ( ) ) {
2017-04-15 19:48:10 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
Ref < Script > scr = p_resource ;
2018-05-28 17:52:28 +02:00
2020-07-26 23:18:05 +02:00
// Don't open dominant script if using an external editor.
2021-11-04 14:30:04 +01:00
bool use_external_editor =
2023-10-07 13:05:36 +02:00
external_editor_active | |
2022-09-29 11:53:28 +02:00
( scr . is_valid ( ) & & scr - > get_language ( ) - > overrides_external_editor ( ) ) ;
use_external_editor = use_external_editor & & ! ( scr . is_valid ( ) & & scr - > is_built_in ( ) ) ; // Ignore external editor for built-in scripts.
2022-10-18 16:43:37 +02:00
const bool open_dominant = EDITOR_GET ( " text_editor/behavior/files/open_dominant_script_on_scene_change " ) ;
2016-07-07 01:35:49 +02:00
2020-07-26 23:18:05 +02:00
const bool should_open = ( open_dominant & & ! use_external_editor ) | | ! EditorNode : : get_singleton ( ) - > is_changing_scene ( ) ;
2018-01-14 12:34:00 +01:00
2022-09-29 11:53:28 +02:00
if ( scr . is_valid ( ) & & scr - > get_language ( ) - > overrides_external_editor ( ) ) {
2018-01-14 12:34:00 +01:00
if ( should_open ) {
2022-09-29 11:53:28 +02:00
Error err = scr - > get_language ( ) - > open_in_external_editor ( scr , p_line > = 0 ? p_line : 0 , p_col ) ;
2020-05-14 16:41:43 +02:00
if ( err ! = OK ) {
2018-01-14 12:34:00 +01:00
ERR_PRINT ( " Couldn't open script in the overridden external text editor " ) ;
2020-05-14 16:41:43 +02:00
}
2018-01-14 12:34:00 +01:00
}
2017-09-03 21:23:36 +02:00
return false ;
}
2020-07-26 23:18:05 +02:00
if ( use_external_editor & &
( EditorDebuggerNode : : get_singleton ( ) - > get_dump_stack_script ( ) ! = p_resource | | EditorDebuggerNode : : get_singleton ( ) - > get_debug_with_external_editor ( ) ) & &
2023-01-09 15:31:44 +01:00
p_resource - > get_path ( ) . is_resource_file ( ) ) {
2022-10-18 16:43:37 +02:00
String path = EDITOR_GET ( " text_editor/external/exec_path " ) ;
String flags = EDITOR_GET ( " text_editor/external/exec_flags " ) ;
2017-04-15 19:48:10 +02:00
2014-02-10 02:10:30 +01:00
List < String > args ;
2019-06-11 09:20:42 +02:00
bool has_file_flag = false ;
String script_path = ProjectSettings : : get_singleton ( ) - > globalize_path ( p_resource - > get_path ( ) ) ;
2017-04-15 19:48:10 +02:00
if ( flags . size ( ) ) {
2018-02-04 11:18:54 +01:00
String project_path = ProjectSettings : : get_singleton ( ) - > get_resource_path ( ) ;
flags = flags . replacen ( " {line} " , itos ( p_line > 0 ? p_line : 0 ) ) ;
flags = flags . replacen ( " {col} " , itos ( p_col ) ) ;
flags = flags . strip_edges ( ) . replace ( " \\ \\ " , " \\ " ) ;
int from = 0 ;
int num_chars = 0 ;
2017-04-15 19:48:10 +02:00
bool inside_quotes = false ;
2018-02-04 11:18:54 +01:00
2017-04-15 19:48:10 +02:00
for ( int i = 0 ; i < flags . size ( ) ; i + + ) {
if ( flags [ i ] = = ' " ' & & ( ! i | | flags [ i - 1 ] ! = ' \\ ' ) ) {
2018-02-04 11:18:54 +01:00
if ( ! inside_quotes ) {
from + + ;
}
2017-04-15 19:48:10 +02:00
inside_quotes = ! inside_quotes ;
2018-02-04 11:18:54 +01:00
2017-04-15 19:48:10 +02:00
} else if ( flags [ i ] = = ' \0 ' | | ( ! inside_quotes & & flags [ i ] = = ' ' ) ) {
2018-02-04 11:18:54 +01:00
String arg = flags . substr ( from , num_chars ) ;
2022-02-03 17:03:38 +01:00
if ( arg . contains ( " {file} " ) ) {
2019-06-11 09:20:42 +02:00
has_file_flag = true ;
}
2018-02-04 11:18:54 +01:00
// do path replacement here, else there will be issues with spaces and quotes
arg = arg . replacen ( " {project} " , project_path ) ;
arg = arg . replacen ( " {file} " , script_path ) ;
args . push_back ( arg ) ;
2017-04-15 19:48:10 +02:00
from = i + 1 ;
2018-02-04 11:18:54 +01:00
num_chars = 0 ;
2017-04-15 19:48:10 +02:00
} else {
2018-02-04 11:18:54 +01:00
num_chars + + ;
2017-04-15 19:48:10 +02:00
}
}
2014-02-10 02:10:30 +01:00
}
2019-06-11 09:20:42 +02:00
// Default to passing script path if no {file} flag is specified.
if ( ! has_file_flag ) {
args . push_back ( script_path ) ;
}
2023-01-16 22:32:23 +01:00
if ( ! path . is_empty ( ) ) {
Error err = OS : : get_singleton ( ) - > create_process ( path , args ) ;
if ( err = = OK ) {
return false ;
}
2020-05-14 16:41:43 +02:00
}
2023-01-16 22:32:23 +01:00
ERR_PRINT ( " Couldn't open external text editor, falling back to the internal editor. Review your `text_editor/external/` editor settings. " ) ;
2014-02-10 02:10:30 +01:00
}
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! se ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
if ( ( scr ! = nullptr & & se - > get_edited_resource ( ) = = p_resource ) | | se - > get_edited_resource ( ) - > get_path ( ) = = p_resource - > get_path ( ) ) {
2018-01-14 12:34:00 +01:00
if ( should_open ) {
2022-10-23 10:45:44 +02:00
se - > enable_editor ( this ) ;
2019-11-20 10:09:59 +01:00
2015-06-22 05:03:19 +02:00
if ( tab_container - > get_current_tab ( ) ! = i ) {
2015-11-17 13:46:08 +01:00
_go_to_tab ( i ) ;
2015-06-22 05:03:19 +02:00
}
2020-05-14 16:41:43 +02:00
if ( is_visible_in_tree ( ) ) {
2016-08-03 00:11:05 +02:00
se - > ensure_focus ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-04-15 19:48:10 +02:00
2019-03-17 20:47:04 +01:00
if ( p_line > 0 ) {
2023-07-13 02:52:09 +02:00
se - > goto_line ( p_line ) ;
2019-03-17 20:47:04 +01:00
}
2015-06-22 05:03:19 +02:00
}
2019-06-15 16:24:03 +02:00
_update_script_names ( ) ;
script_list - > ensure_current_is_visible ( ) ;
2017-04-15 19:48:10 +02:00
return true ;
2014-02-10 02:10:30 +01:00
}
}
// doesn't have it, make a new one
2020-04-02 01:20:12 +02:00
ScriptEditorBase * se = nullptr ;
2016-08-03 00:11:05 +02:00
for ( int i = script_editor_func_count - 1 ; i > = 0 ; i - - ) {
2018-05-28 17:52:28 +02:00
se = script_editor_funcs [ i ] ( p_resource ) ;
2020-05-14 16:41:43 +02:00
if ( se ) {
2016-08-03 00:11:05 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
}
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL_V ( se , false ) ;
2016-09-11 15:01:52 +02:00
2019-11-20 10:09:59 +01:00
se - > set_edited_resource ( p_resource ) ;
2023-01-09 15:31:44 +01:00
// Syntax highlighting.
bool highlighter_set = false ;
for ( int i = 0 ; i < syntax_highlighters . size ( ) ; i + + ) {
Ref < EditorSyntaxHighlighter > highlighter = syntax_highlighters [ i ] - > _create ( ) ;
if ( highlighter . is_null ( ) ) {
continue ;
}
se - > add_syntax_highlighter ( highlighter ) ;
2019-07-25 18:30:48 +02:00
2023-01-28 15:05:23 +01:00
if ( highlighter_set ) {
continue ;
}
PackedStringArray languages = highlighter - > _get_supported_languages ( ) ;
// If script try language, else use extension.
if ( scr ! = nullptr ) {
2023-01-09 15:31:44 +01:00
if ( languages . has ( scr - > get_language ( ) - > get_name ( ) ) ) {
se - > set_syntax_highlighter ( highlighter ) ;
highlighter_set = true ;
2018-04-02 13:41:44 +02:00
}
2023-01-28 15:05:23 +01:00
continue ;
}
if ( languages . has ( p_resource - > get_path ( ) . get_extension ( ) ) ) {
se - > set_syntax_highlighter ( highlighter ) ;
highlighter_set = true ;
2018-04-02 13:41:44 +02:00
}
}
2017-09-17 15:19:38 +02:00
tab_container - > add_child ( se ) ;
2019-11-20 10:09:59 +01:00
if ( p_grab_focus ) {
2022-10-23 10:45:44 +02:00
se - > enable_editor ( this ) ;
2019-11-20 10:09:59 +01:00
}
2020-07-23 14:21:28 +02:00
// If we delete a script within the filesystem, the original resource path
// is lost, so keep it as metadata to figure out the exact tab to delete.
se - > set_meta ( " _edit_res_path " , p_resource - > get_path ( ) ) ;
2021-11-07 18:26:15 +01:00
se - > set_tooltip_request_func ( callable_mp ( this , & ScriptEditor : : _get_debug_tooltip ) ) ;
2016-08-03 00:11:05 +02:00
if ( se - > get_edit_menu ( ) ) {
se - > get_edit_menu ( ) - > hide ( ) ;
menu_hb - > add_child ( se - > get_edit_menu ( ) ) ;
menu_hb - > move_child ( se - > get_edit_menu ( ) , 1 ) ;
}
2016-08-25 22:45:20 +02:00
if ( p_grab_focus ) {
_go_to_tab ( tab_container - > get_tab_count ( ) - 1 ) ;
2019-11-20 10:09:59 +01:00
_add_recent_script ( p_resource - > get_path ( ) ) ;
2016-08-25 22:45:20 +02:00
}
2015-11-17 13:46:08 +01:00
2021-10-07 20:44:23 +02:00
if ( script_editor_cache - > has_section ( p_resource - > get_path ( ) ) ) {
se - > set_edit_state ( script_editor_cache - > get_value ( p_resource - > get_path ( ) , " state " ) ) ;
2022-10-22 23:54:37 +02:00
ScriptTextEditor * ste = Object : : cast_to < ScriptTextEditor > ( se ) ;
if ( ste ) {
ste - > store_previous_state ( ) ;
}
2021-10-07 20:44:23 +02:00
}
2018-09-08 20:33:54 +02:00
_sort_list_on_update = true ;
2015-06-22 05:03:19 +02:00
_update_script_names ( ) ;
2016-07-18 17:30:43 +02:00
_save_layout ( ) ;
2020-02-21 18:28:45 +01:00
se - > connect ( " name_changed " , callable_mp ( this , & ScriptEditor : : _update_script_names ) ) ;
se - > connect ( " edited_script_changed " , callable_mp ( this , & ScriptEditor : : _script_changed ) ) ;
se - > connect ( " request_help " , callable_mp ( this , & ScriptEditor : : _help_search ) ) ;
se - > connect ( " request_open_script_at_line " , callable_mp ( this , & ScriptEditor : : _goto_script_line ) ) ;
se - > connect ( " go_to_help " , callable_mp ( this , & ScriptEditor : : _help_class_goto ) ) ;
se - > connect ( " request_save_history " , callable_mp ( this , & ScriptEditor : : _save_history ) ) ;
2022-10-22 23:54:37 +02:00
se - > connect ( " request_save_previous_state " , callable_mp ( this , & ScriptEditor : : _save_previous_state ) ) ;
2020-02-21 18:28:45 +01:00
se - > connect ( " search_in_files_requested " , callable_mp ( this , & ScriptEditor : : _on_find_in_files_requested ) ) ;
se - > connect ( " replace_in_files_requested " , callable_mp ( this , & ScriptEditor : : _on_replace_in_files_requested ) ) ;
2022-09-09 16:36:07 +02:00
se - > connect ( " go_to_method " , callable_mp ( this , & ScriptEditor : : script_goto_method ) ) ;
2016-06-20 03:07:07 +02:00
2024-02-18 03:16:58 +01:00
CodeTextEditor * cte = se - > get_code_editor ( ) ;
if ( cte ) {
cte - > set_zoom_factor ( zoom_factor ) ;
cte - > connect ( " zoomed " , callable_mp ( this , & ScriptEditor : : _set_zoom_factor ) ) ;
}
2016-06-20 03:07:07 +02:00
//test for modification, maybe the script was not edited but was loaded
2018-05-28 17:52:28 +02:00
_test_script_times_on_disk ( p_resource ) ;
_update_modified_scripts_for_external_editor ( p_resource ) ;
2017-04-15 19:48:10 +02:00
2023-07-13 02:52:09 +02:00
if ( p_line > = 0 ) {
se - > goto_line ( p_line ) ;
2019-03-17 20:47:04 +01:00
}
2017-04-15 19:48:10 +02:00
2018-05-28 17:52:28 +02:00
notify_script_changed ( p_resource ) ;
2017-04-15 19:48:10 +02:00
return true ;
2014-02-10 02:10:30 +01:00
}
2022-10-16 19:30:38 +02:00
PackedStringArray ScriptEditor : : get_unsaved_scripts ( ) const {
PackedStringArray unsaved_list ;
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2023-04-05 15:45:41 +02:00
if ( se & & se - > is_unsaved ( ) ) {
2022-10-16 19:30:38 +02:00
unsaved_list . append ( se - > get_name ( ) ) ;
}
}
return unsaved_list ;
}
2021-05-09 12:29:50 +02:00
void ScriptEditor : : save_current_script ( ) {
ScriptEditorBase * current = _get_current_editor ( ) ;
2021-05-18 19:43:54 +02:00
if ( ! current | | _test_script_times_on_disk ( ) ) {
2021-05-09 12:29:50 +02:00
return ;
}
if ( trim_trailing_whitespace_on_save ) {
current - > trim_trailing_whitespace ( ) ;
}
current - > insert_final_newline ( ) ;
if ( convert_indent_on_save ) {
2023-05-01 22:41:50 +02:00
current - > convert_indent ( ) ;
2021-05-09 12:29:50 +02:00
}
2022-05-03 01:43:50 +02:00
Ref < Resource > resource = current - > get_edited_resource ( ) ;
2021-05-09 12:29:50 +02:00
Ref < TextFile > text_file = resource ;
2022-09-29 11:53:28 +02:00
Ref < Script > scr = resource ;
2021-05-09 12:29:50 +02:00
if ( text_file ! = nullptr ) {
current - > apply_code ( ) ;
_save_text_file ( text_file , text_file - > get_path ( ) ) ;
return ;
}
2022-09-29 11:53:28 +02:00
if ( scr . is_valid ( ) ) {
clear_docs_from_script ( scr ) ;
2021-05-09 12:29:50 +02:00
}
2023-11-08 21:08:24 +01:00
EditorNode : : get_singleton ( ) - > save_resource ( resource ) ;
2021-05-09 12:29:50 +02:00
2022-09-29 11:53:28 +02:00
if ( scr . is_valid ( ) ) {
update_docs_from_script ( scr ) ;
2021-05-09 12:29:50 +02:00
}
}
2016-02-03 01:10:52 +01:00
void ScriptEditor : : save_all_scripts ( ) {
2023-10-25 15:16:38 +02:00
HashSet < String > scenes_to_save ;
2021-11-06 02:15:19 +01:00
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! se ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2017-04-17 15:46:00 +02:00
if ( convert_indent_on_save ) {
2023-05-01 22:41:50 +02:00
se - > convert_indent ( ) ;
2017-04-17 15:46:00 +02:00
}
2017-04-23 20:19:30 +02:00
if ( trim_trailing_whitespace_on_save ) {
se - > trim_trailing_whitespace ( ) ;
}
2019-05-28 23:27:32 +02:00
se - > insert_final_newline ( ) ;
2020-05-14 16:41:43 +02:00
if ( ! se - > is_unsaved ( ) ) {
2017-04-23 20:19:30 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-04-23 20:19:30 +02:00
2022-05-03 01:43:50 +02:00
Ref < Resource > edited_res = se - > get_edited_resource ( ) ;
2018-05-28 17:52:28 +02:00
if ( edited_res . is_valid ( ) ) {
2016-08-03 00:11:05 +02:00
se - > apply_code ( ) ;
2018-05-28 17:52:28 +02:00
}
2016-06-12 02:59:35 +02:00
2021-07-10 21:17:41 +02:00
if ( ! edited_res - > is_built_in ( ) ) {
2018-05-28 17:52:28 +02:00
Ref < TextFile > text_file = edited_res ;
2022-09-29 11:53:28 +02:00
Ref < Script > scr = edited_res ;
2020-11-29 04:42:06 +01:00
2020-04-02 01:20:12 +02:00
if ( text_file ! = nullptr ) {
2018-05-28 17:52:28 +02:00
_save_text_file ( text_file , text_file - > get_path ( ) ) ;
continue ;
}
2020-11-29 04:42:06 +01:00
2022-09-29 11:53:28 +02:00
if ( scr . is_valid ( ) ) {
clear_docs_from_script ( scr ) ;
2020-11-29 04:42:06 +01:00
}
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > save_resource ( edited_res ) ; //external script, save it
2020-11-29 04:42:06 +01:00
2022-09-29 11:53:28 +02:00
if ( scr . is_valid ( ) ) {
update_docs_from_script ( scr ) ;
2020-11-29 04:42:06 +01:00
}
2021-11-06 02:15:19 +01:00
} else {
// For built-in scripts, save their scenes instead.
const String scene_path = edited_res - > get_path ( ) . get_slice ( " :: " , 0 ) ;
2023-02-15 17:29:52 +01:00
if ( ! scene_path . is_empty ( ) & & ! scenes_to_save . has ( scene_path ) ) {
2023-10-25 15:16:38 +02:00
scenes_to_save . insert ( scene_path ) ;
2021-11-06 02:15:19 +01:00
}
2018-05-28 17:52:28 +02:00
}
2014-02-10 02:10:30 +01:00
}
2021-11-06 02:15:19 +01:00
if ( ! scenes_to_save . is_empty ( ) ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > save_scene_list ( scenes_to_save ) ;
2021-11-06 02:15:19 +01:00
}
2016-08-07 00:00:54 +02:00
_update_script_names ( ) ;
2014-02-10 02:10:30 +01:00
}
void ScriptEditor : : apply_scripts ( ) const {
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! se ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
se - > apply_code ( ) ;
2014-02-10 02:10:30 +01:00
}
}
2022-09-25 17:13:39 +02:00
void ScriptEditor : : reload_scripts ( bool p_refresh_only ) {
2023-10-07 13:05:36 +02:00
if ( external_editor_active ) {
return ;
}
2022-06-13 20:47:40 +02:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
if ( ! se ) {
continue ;
}
Ref < Resource > edited_res = se - > get_edited_resource ( ) ;
if ( edited_res - > is_built_in ( ) ) {
continue ; //internal script, who cares
}
2022-09-25 17:13:39 +02:00
if ( ! p_refresh_only ) {
uint64_t last_date = edited_res - > get_last_modified_time ( ) ;
uint64_t date = FileAccess : : get_modified_time ( edited_res - > get_path ( ) ) ;
2022-06-13 20:47:40 +02:00
2022-09-25 17:13:39 +02:00
if ( last_date = = date ) {
continue ;
}
2022-06-13 20:47:40 +02:00
2022-09-29 11:53:28 +02:00
Ref < Script > scr = edited_res ;
2022-12-04 03:59:31 +01:00
if ( scr . is_valid ( ) ) {
2022-09-29 11:53:28 +02:00
Ref < Script > rel_scr = ResourceLoader : : load ( scr - > get_path ( ) , scr - > get_class ( ) , ResourceFormatLoader : : CACHE_MODE_IGNORE ) ;
ERR_CONTINUE ( ! rel_scr . is_valid ( ) ) ;
scr - > set_source_code ( rel_scr - > get_source_code ( ) ) ;
scr - > set_last_modified_time ( rel_scr - > get_last_modified_time ( ) ) ;
scr - > reload ( true ) ;
2022-09-25 17:13:39 +02:00
}
2022-06-13 20:47:40 +02:00
2023-01-28 15:05:23 +01:00
Ref < JSON > json = edited_res ;
if ( json ! = nullptr ) {
Ref < JSON > rel_json = ResourceLoader : : load ( json - > get_path ( ) , json - > get_class ( ) , ResourceFormatLoader : : CACHE_MODE_IGNORE ) ;
ERR_CONTINUE ( ! rel_json . is_valid ( ) ) ;
json - > parse ( rel_json - > get_parsed_text ( ) , true ) ;
json - > set_last_modified_time ( rel_json - > get_last_modified_time ( ) ) ;
}
2022-09-25 17:13:39 +02:00
Ref < TextFile > text_file = edited_res ;
2022-12-04 03:59:31 +01:00
if ( text_file . is_valid ( ) ) {
text_file - > reload_from_file ( ) ;
2022-09-25 17:13:39 +02:00
}
2022-06-13 20:47:40 +02:00
}
2022-09-25 17:13:39 +02:00
2022-06-13 20:47:40 +02:00
se - > reload_text ( ) ;
}
disk_changed - > hide ( ) ;
_update_script_names ( ) ;
}
2017-12-13 18:41:28 +01:00
void ScriptEditor : : open_script_create_dialog ( const String & p_base_name , const String & p_base_path ) {
_menu_option ( FILE_NEW ) ;
script_create_dialog - > config ( p_base_name , p_base_path ) ;
}
2021-09-23 23:09:15 +02:00
void ScriptEditor : : open_text_file_create_dialog ( const String & p_base_path , const String & p_base_name ) {
_menu_option ( FILE_NEW_TEXTFILE ) ;
2023-01-14 17:43:33 +01:00
file_dialog - > set_current_dir ( p_base_path ) ;
file_dialog - > set_current_file ( p_base_name ) ;
2021-09-23 23:09:15 +02:00
open_textfile_after_create = false ;
}
2022-05-03 01:43:50 +02:00
Ref < Resource > ScriptEditor : : open_file ( const String & p_file ) {
2021-09-23 23:09:15 +02:00
List < String > extensions ;
ResourceLoader : : get_recognized_extensions_for_type ( " Script " , & extensions ) ;
2023-01-28 15:05:23 +01:00
ResourceLoader : : get_recognized_extensions_for_type ( " JSON " , & extensions ) ;
2021-09-23 23:09:15 +02:00
if ( extensions . find ( p_file . get_extension ( ) ) ) {
2023-01-28 15:05:23 +01:00
Ref < Resource > scr = ResourceLoader : : load ( p_file ) ;
2021-09-23 23:09:15 +02:00
if ( ! scr . is_valid ( ) ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Could not load file at: " ) + " \n \n " + p_file , TTR ( " Error! " ) ) ;
2022-05-03 01:43:50 +02:00
return Ref < Resource > ( ) ;
2021-09-23 23:09:15 +02:00
}
edit ( scr ) ;
return scr ;
}
Error error ;
Ref < TextFile > text_file = _load_text_file ( p_file , & error ) ;
if ( error ! = OK ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Could not load file at: " ) + " \n \n " + p_file , TTR ( " Error! " ) ) ;
2022-05-03 01:43:50 +02:00
return Ref < Resource > ( ) ;
2021-09-23 23:09:15 +02:00
}
if ( text_file . is_valid ( ) ) {
edit ( text_file ) ;
return text_file ;
}
2022-05-03 01:43:50 +02:00
return Ref < Resource > ( ) ;
2021-09-23 23:09:15 +02:00
}
2014-02-10 02:10:30 +01:00
void ScriptEditor : : _editor_stop ( ) {
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2016-08-07 00:00:54 +02:00
if ( ! se ) {
continue ;
}
se - > set_debugger_active ( false ) ;
}
2014-02-10 02:10:30 +01:00
}
2020-02-17 22:06:54 +01:00
void ScriptEditor : : _add_callback ( Object * p_obj , const String & p_function , const PackedStringArray & p_args ) {
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( p_obj ) ;
2022-09-29 11:53:28 +02:00
Ref < Script > scr = p_obj - > get_script ( ) ;
ERR_FAIL_COND ( ! scr . is_valid ( ) ) ;
2014-02-10 02:10:30 +01:00
2024-02-04 19:08:41 +01:00
if ( ! scr - > get_language ( ) - > can_make_function ( ) ) {
return ;
}
2022-09-29 11:53:28 +02:00
EditorNode : : get_singleton ( ) - > push_item ( scr . ptr ( ) ) ;
2014-02-10 02:10:30 +01:00
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! se ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2022-09-29 11:53:28 +02:00
if ( se - > get_edited_resource ( ) ! = scr ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2016-08-03 00:11:05 +02:00
se - > add_callback ( p_function , p_args ) ;
2014-02-10 02:10:30 +01:00
2015-11-17 13:46:08 +01:00
_go_to_tab ( i ) ;
2014-02-10 02:10:30 +01:00
2015-06-22 05:03:19 +02:00
script_list - > select ( script_list - > find_metadata ( i ) ) ;
2020-09-29 23:00:34 +02:00
// Save the current script so the changes can be picked up by an external editor.
2022-09-29 11:53:28 +02:00
if ( ! scr . ptr ( ) - > is_built_in ( ) ) { // But only if it's not built-in script.
2021-06-06 23:58:35 +02:00
save_current_script ( ) ;
}
2020-09-29 23:00:34 +02:00
2014-02-10 02:10:30 +01:00
break ;
}
}
2021-10-07 20:44:23 +02:00
void ScriptEditor : : _save_editor_state ( ScriptEditorBase * p_editor ) {
if ( restoring_layout ) {
return ;
}
const String & path = p_editor - > get_edited_resource ( ) - > get_path ( ) ;
if ( ! path . is_resource_file ( ) ) {
return ;
}
script_editor_cache - > set_value ( path , " state " , p_editor - > get_edit_state ( ) ) ;
// This is saved later when we save the editor layout.
}
2016-07-18 17:30:43 +02:00
void ScriptEditor : : _save_layout ( ) {
if ( restoring_layout ) {
return ;
}
2023-05-11 04:17:03 +02:00
EditorNode : : get_singleton ( ) - > save_editor_layout_delayed ( ) ;
2016-07-18 17:30:43 +02:00
}
2015-05-05 04:32:40 +02:00
void ScriptEditor : : _editor_settings_changed ( ) {
2024-02-24 00:06:15 +01:00
if ( ! EditorThemeManager : : is_generated_theme_outdated ( ) & &
! EditorSettings : : get_singleton ( ) - > check_changed_settings_in_group ( " interface/editor " ) & &
2024-02-18 03:16:58 +01:00
! EditorSettings : : get_singleton ( ) - > check_changed_settings_in_group ( " text_editor " ) & &
2022-11-23 00:14:08 +01:00
! EditorSettings : : get_singleton ( ) - > check_changed_settings_in_group ( " docks/filesystem " ) ) {
return ;
}
2024-02-18 03:16:58 +01:00
_apply_editor_settings ( ) ;
}
void ScriptEditor : : _apply_editor_settings ( ) {
2021-10-12 18:31:20 +02:00
textfile_extensions . clear ( ) ;
2022-10-18 16:43:37 +02:00
const Vector < String > textfile_ext = ( ( String ) ( EDITOR_GET ( " docks/filesystem/textfile_extensions " ) ) ) . split ( " , " , false ) ;
2021-10-12 18:31:20 +02:00
for ( const String & E : textfile_ext ) {
textfile_extensions . insert ( E ) ;
}
2022-10-18 16:43:37 +02:00
trim_trailing_whitespace_on_save = EDITOR_GET ( " text_editor/behavior/files/trim_trailing_whitespace_on_save " ) ;
convert_indent_on_save = EDITOR_GET ( " text_editor/behavior/files/convert_indent_on_save " ) ;
2017-04-17 15:24:30 +02:00
2022-10-18 16:43:37 +02:00
members_overview_enabled = EDITOR_GET ( " text_editor/script_list/show_members_overview " ) ;
help_overview_enabled = EDITOR_GET ( " text_editor/help/show_help_index " ) ;
2023-10-07 13:05:36 +02:00
external_editor_active = EDITOR_GET ( " text_editor/external/use_external_editor " ) ;
2017-05-28 16:20:38 +02:00
_update_members_overview_visibility ( ) ;
2017-09-14 02:56:37 +02:00
_update_help_overview_visibility ( ) ;
2017-05-28 16:20:38 +02:00
2019-10-10 22:19:47 +02:00
_update_autosave_timer ( ) ;
2015-05-05 04:32:40 +02:00
2021-12-09 10:42:46 +01:00
if ( current_theme . is_empty ( ) ) {
2022-10-18 16:43:37 +02:00
current_theme = EDITOR_GET ( " text_editor/theme/color_theme " ) ;
} else if ( current_theme ! = String ( EDITOR_GET ( " text_editor/theme/color_theme " ) ) ) {
current_theme = EDITOR_GET ( " text_editor/theme/color_theme " ) ;
2016-04-12 16:45:31 +02:00
EditorSettings : : get_singleton ( ) - > load_text_editor_theme ( ) ;
}
2024-02-18 03:16:58 +01:00
_update_script_names ( ) ;
ScriptServer : : set_reload_scripts_on_save ( EDITOR_GET ( " text_editor/behavior/files/auto_reload_and_parse_scripts_on_save " ) ) ;
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! se ) {
2016-01-01 13:52:01 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2016-01-01 13:52:01 +01:00
2016-08-03 00:11:05 +02:00
se - > update_settings ( ) ;
2016-01-01 13:52:01 +01:00
}
2015-05-05 04:32:40 +02:00
}
2020-07-23 14:21:28 +02:00
void ScriptEditor : : _filesystem_changed ( ) {
_update_script_names ( ) ;
}
2021-10-07 20:44:23 +02:00
void ScriptEditor : : _files_moved ( const String & p_old_file , const String & p_new_file ) {
if ( ! script_editor_cache - > has_section ( p_old_file ) ) {
return ;
}
Variant state = script_editor_cache - > get_value ( p_old_file , " state " ) ;
script_editor_cache - > erase_section ( p_old_file ) ;
script_editor_cache - > set_value ( p_new_file , " state " , state ) ;
2021-10-07 20:46:44 +02:00
// If Script, update breakpoints with debugger.
Array breakpoints = _get_cached_breakpoints_for_script ( p_new_file ) ;
for ( int i = 0 ; i < breakpoints . size ( ) ; i + + ) {
int line = ( int ) breakpoints [ i ] + 1 ;
EditorDebuggerNode : : get_singleton ( ) - > set_breakpoint ( p_old_file , line , false ) ;
if ( ! p_new_file . begins_with ( " local:// " ) & & ResourceLoader : : exists ( p_new_file , " Script " ) ) {
EditorDebuggerNode : : get_singleton ( ) - > set_breakpoint ( p_new_file , line , true ) ;
}
}
2021-10-07 20:44:23 +02:00
// This is saved later when we save the editor layout.
}
2020-07-23 14:21:28 +02:00
void ScriptEditor : : _file_removed ( const String & p_removed_file ) {
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-07-23 14:21:28 +02:00
if ( ! se ) {
continue ;
}
if ( se - > get_meta ( " _edit_res_path " ) = = p_removed_file ) {
// The script is deleted with no undo, so just close the tab.
_close_tab ( i , false , false ) ;
}
}
2021-10-07 20:44:23 +02:00
2021-10-07 20:46:44 +02:00
// Check closed.
2021-10-07 20:44:23 +02:00
if ( script_editor_cache - > has_section ( p_removed_file ) ) {
2021-10-07 20:46:44 +02:00
Array breakpoints = _get_cached_breakpoints_for_script ( p_removed_file ) ;
for ( int i = 0 ; i < breakpoints . size ( ) ; i + + ) {
EditorDebuggerNode : : get_singleton ( ) - > set_breakpoint ( p_removed_file , ( int ) breakpoints [ i ] + 1 , false ) ;
}
2021-10-07 20:44:23 +02:00
script_editor_cache - > erase_section ( p_removed_file ) ;
}
2020-07-23 14:21:28 +02:00
}
2021-06-24 15:38:29 +02:00
void ScriptEditor : : _update_find_replace_bar ( ) {
ScriptEditorBase * se = _get_current_editor ( ) ;
if ( se ) {
se - > set_find_replace_bar ( find_replace_bar ) ;
} else {
find_replace_bar - > set_text_edit ( nullptr ) ;
find_replace_bar - > hide ( ) ;
}
}
2015-05-05 04:32:40 +02:00
void ScriptEditor : : _autosave_scripts ( ) {
2016-02-03 01:10:52 +01:00
save_all_scripts ( ) ;
2015-05-05 04:32:40 +02:00
}
2019-10-10 22:19:47 +02:00
void ScriptEditor : : _update_autosave_timer ( ) {
if ( ! autosave_timer - > is_inside_tree ( ) ) {
return ;
}
2022-10-18 16:43:37 +02:00
float autosave_time = EDITOR_GET ( " text_editor/behavior/files/autosave_interval_secs " ) ;
2019-10-10 22:19:47 +02:00
if ( autosave_time > 0 ) {
autosave_timer - > set_wait_time ( autosave_time ) ;
autosave_timer - > start ( ) ;
} else {
autosave_timer - > stop ( ) ;
}
}
2015-06-22 05:03:19 +02:00
void ScriptEditor : : _tree_changed ( ) {
2020-05-14 16:41:43 +02:00
if ( waiting_update_names ) {
2015-06-22 05:03:19 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-06-22 05:03:19 +02:00
waiting_update_names = true ;
2023-12-18 15:46:56 +01:00
callable_mp ( this , & ScriptEditor : : _update_script_names ) . call_deferred ( ) ;
2015-06-22 05:03:19 +02:00
}
2022-02-02 22:35:40 +01:00
void ScriptEditor : : _split_dragged ( float ) {
2016-07-18 17:30:43 +02:00
_save_layout ( ) ;
2015-06-22 05:03:19 +02:00
}
2017-11-12 20:21:09 +01:00
Variant ScriptEditor : : get_drag_data_fw ( const Point2 & p_point , Control * p_from ) {
2022-03-02 15:37:10 +01:00
if ( tab_container - > get_tab_count ( ) = = 0 ) {
2019-03-07 16:09:02 +01:00
return Variant ( ) ;
2020-05-14 16:41:43 +02:00
}
2019-03-07 16:09:02 +01:00
2022-03-02 15:37:10 +01:00
Node * cur_node = tab_container - > get_tab_control ( tab_container - > get_current_tab ( ) ) ;
2017-11-12 03:42:56 +01:00
2017-11-12 20:21:09 +01:00
HBoxContainer * drag_preview = memnew ( HBoxContainer ) ;
String preview_name = " " ;
2019-06-11 20:43:37 +02:00
Ref < Texture2D > preview_icon ;
2017-11-12 20:21:09 +01:00
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( cur_node ) ;
if ( se ) {
preview_name = se - > get_name ( ) ;
2020-03-12 13:37:40 +01:00
preview_icon = se - > get_theme_icon ( ) ;
2017-11-12 20:21:09 +01:00
}
EditorHelp * eh = Object : : cast_to < EditorHelp > ( cur_node ) ;
if ( eh ) {
preview_name = eh - > get_class ( ) ;
2023-08-13 02:33:39 +02:00
preview_icon = get_editor_theme_icon ( SNAME ( " Help " ) ) ;
2017-11-12 20:21:09 +01:00
}
if ( ! preview_icon . is_null ( ) ) {
TextureRect * tf = memnew ( TextureRect ) ;
tf - > set_texture ( preview_icon ) ;
2022-01-21 17:00:02 +01:00
tf - > set_stretch_mode ( TextureRect : : STRETCH_KEEP_CENTERED ) ;
2017-11-12 20:21:09 +01:00
drag_preview - > add_child ( tf ) ;
}
Label * label = memnew ( Label ( preview_name ) ) ;
drag_preview - > add_child ( label ) ;
set_drag_preview ( drag_preview ) ;
Dictionary drag_data ;
drag_data [ " type " ] = " script_list_element " ; // using a custom type because node caused problems when dragging to scene tree
drag_data [ " script_list_element " ] = cur_node ;
return drag_data ;
2017-11-12 03:42:56 +01:00
}
2017-11-12 20:21:09 +01:00
2017-11-12 03:42:56 +01:00
bool ScriptEditor : : can_drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) const {
2017-11-12 20:21:09 +01:00
Dictionary d = p_data ;
2020-05-14 16:41:43 +02:00
if ( ! d . has ( " type " ) ) {
2017-11-12 20:21:09 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
2017-11-12 20:21:09 +01:00
if ( String ( d [ " type " ] ) = = " script_list_element " ) {
2022-01-25 16:37:41 +01:00
Node * node = Object : : cast_to < Node > ( d [ " script_list_element " ] ) ;
2017-11-12 20:21:09 +01:00
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( node ) ;
if ( se ) {
return true ;
}
EditorHelp * eh = Object : : cast_to < EditorHelp > ( node ) ;
if ( eh ) {
return true ;
}
}
if ( String ( d [ " type " ] ) = = " nodes " ) {
Array nodes = d [ " nodes " ] ;
2020-05-14 16:41:43 +02:00
if ( nodes . size ( ) = = 0 ) {
2017-11-12 20:21:09 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
2017-11-12 20:21:09 +01:00
Node * node = get_node ( ( nodes [ 0 ] ) ) ;
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( node ) ;
if ( se ) {
return true ;
}
EditorHelp * eh = Object : : cast_to < EditorHelp > ( node ) ;
if ( eh ) {
return true ;
}
}
if ( String ( d [ " type " ] ) = = " files " ) {
Vector < String > files = d [ " files " ] ;
2020-05-14 16:41:43 +02:00
if ( files . size ( ) = = 0 ) {
2017-11-12 20:21:09 +01:00
return false ; //weird
2020-05-14 16:41:43 +02:00
}
2017-11-12 20:21:09 +01:00
for ( int i = 0 ; i < files . size ( ) ; i + + ) {
2023-11-18 23:40:56 +01:00
const String & file = files [ i ] ;
2021-12-09 10:42:46 +01:00
if ( file . is_empty ( ) | | ! FileAccess : : exists ( file ) ) {
2017-11-12 20:21:09 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2023-01-28 15:05:23 +01:00
if ( ResourceLoader : : exists ( file , " Script " ) | | ResourceLoader : : exists ( file , " JSON " ) ) {
Ref < Resource > scr = ResourceLoader : : load ( file ) ;
2021-10-12 18:31:20 +02:00
if ( scr . is_valid ( ) ) {
return true ;
}
}
if ( textfile_extensions . has ( file . get_extension ( ) ) ) {
Error err ;
Ref < TextFile > text_file = _load_text_file ( file , & err ) ;
if ( text_file . is_valid ( ) & & err = = OK ) {
return true ;
}
2017-11-12 20:21:09 +01:00
}
}
2021-10-12 18:31:20 +02:00
return false ;
2017-11-12 20:21:09 +01:00
}
2017-11-12 03:42:56 +01:00
return false ;
}
2017-11-12 20:21:09 +01:00
2017-11-12 03:42:56 +01:00
void ScriptEditor : : drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) {
2020-05-14 16:41:43 +02:00
if ( ! can_drop_data_fw ( p_point , p_data , p_from ) ) {
2017-11-12 20:21:09 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-11-12 20:21:09 +01:00
Dictionary d = p_data ;
2020-05-14 16:41:43 +02:00
if ( ! d . has ( " type " ) ) {
2017-11-12 20:21:09 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-11-12 20:21:09 +01:00
if ( String ( d [ " type " ] ) = = " script_list_element " ) {
2022-01-25 16:37:41 +01:00
Node * node = Object : : cast_to < Node > ( d [ " script_list_element " ] ) ;
2017-11-12 20:21:09 +01:00
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( node ) ;
EditorHelp * eh = Object : : cast_to < EditorHelp > ( node ) ;
if ( se | | eh ) {
2019-11-25 17:16:29 +01:00
int new_index = 0 ;
if ( script_list - > get_item_count ( ) > 0 ) {
new_index = script_list - > get_item_metadata ( script_list - > get_item_at_position ( p_point ) ) ;
}
2017-11-12 20:21:09 +01:00
tab_container - > move_child ( node , new_index ) ;
tab_container - > set_current_tab ( new_index ) ;
_update_script_names ( ) ;
}
}
if ( String ( d [ " type " ] ) = = " nodes " ) {
Array nodes = d [ " nodes " ] ;
2020-05-14 16:41:43 +02:00
if ( nodes . size ( ) = = 0 ) {
2017-11-12 20:21:09 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-11-12 20:21:09 +01:00
Node * node = get_node ( nodes [ 0 ] ) ;
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( node ) ;
EditorHelp * eh = Object : : cast_to < EditorHelp > ( node ) ;
if ( se | | eh ) {
2019-11-25 17:16:29 +01:00
int new_index = 0 ;
if ( script_list - > get_item_count ( ) > 0 ) {
new_index = script_list - > get_item_metadata ( script_list - > get_item_at_position ( p_point ) ) ;
}
2017-11-12 20:21:09 +01:00
tab_container - > move_child ( node , new_index ) ;
tab_container - > set_current_tab ( new_index ) ;
_update_script_names ( ) ;
}
}
if ( String ( d [ " type " ] ) = = " files " ) {
Vector < String > files = d [ " files " ] ;
2019-11-25 17:16:29 +01:00
int new_index = 0 ;
if ( script_list - > get_item_count ( ) > 0 ) {
new_index = script_list - > get_item_metadata ( script_list - > get_item_at_position ( p_point ) ) ;
}
2022-03-02 15:37:10 +01:00
int num_tabs_before = tab_container - > get_tab_count ( ) ;
2017-11-12 20:21:09 +01:00
for ( int i = 0 ; i < files . size ( ) ; i + + ) {
2023-11-18 23:40:56 +01:00
const String & file = files [ i ] ;
2021-12-09 10:42:46 +01:00
if ( file . is_empty ( ) | | ! FileAccess : : exists ( file ) ) {
2017-11-12 20:21:09 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2021-10-12 18:31:20 +02:00
2023-01-28 15:05:23 +01:00
if ( ! ResourceLoader : : exists ( file , " Script " ) & & ! ResourceLoader : : exists ( file , " JSON " ) & & ! textfile_extensions . has ( file . get_extension ( ) ) ) {
2021-10-12 18:31:20 +02:00
continue ;
}
2022-05-03 01:43:50 +02:00
Ref < Resource > res = open_file ( file ) ;
2021-10-12 18:31:20 +02:00
if ( res . is_valid ( ) ) {
2022-12-26 07:34:37 +01:00
const int num_tabs = tab_container - > get_tab_count ( ) ;
if ( num_tabs > num_tabs_before ) {
2022-03-02 15:37:10 +01:00
tab_container - > move_child ( tab_container - > get_tab_control ( tab_container - > get_tab_count ( ) - 1 ) , new_index ) ;
2022-12-26 07:34:37 +01:00
num_tabs_before = num_tabs ;
} else if ( num_tabs > 0 ) { /* Maybe script was already open */
2022-03-02 15:37:10 +01:00
tab_container - > move_child ( tab_container - > get_tab_control ( tab_container - > get_current_tab ( ) ) , new_index ) ;
2017-11-12 20:21:09 +01:00
}
}
}
2022-12-26 07:34:37 +01:00
if ( tab_container - > get_tab_count ( ) > 0 ) {
tab_container - > set_current_tab ( new_index ) ;
}
2017-11-12 20:21:09 +01:00
_update_script_names ( ) ;
}
2017-11-12 03:42:56 +01:00
}
2020-03-08 17:32:49 +01:00
void ScriptEditor : : input ( const Ref < InputEvent > & p_event ) {
// This is implemented in `input()` rather than `unhandled_input()` to allow
// the shortcut to be used regardless of the click location.
// This feature can be disabled to avoid interfering with other uses of the additional
// mouse buttons, such as push-to-talk in a VoIP program.
if ( EDITOR_GET ( " interface/editor/mouse_extra_buttons_navigate_history " ) ) {
const Ref < InputEventMouseButton > mb = p_event ;
// Navigate the script history using additional mouse buttons present on some mice.
// This must be hardcoded as the editor shortcuts dialog doesn't allow assigning
// more than one shortcut per action.
if ( mb . is_valid ( ) & & mb - > is_pressed ( ) & & is_visible_in_tree ( ) ) {
2021-08-13 23:31:57 +02:00
if ( mb - > get_button_index ( ) = = MouseButton : : MB_XBUTTON1 ) {
2020-03-08 17:32:49 +01:00
_history_back ( ) ;
}
2021-08-13 23:31:57 +02:00
if ( mb - > get_button_index ( ) = = MouseButton : : MB_XBUTTON2 ) {
2020-03-08 17:32:49 +01:00
_history_forward ( ) ;
}
}
}
}
2022-01-11 14:59:52 +01:00
void ScriptEditor : : shortcut_input ( const Ref < InputEvent > & p_event ) {
2021-04-05 08:52:21 +02:00
ERR_FAIL_COND ( p_event . is_null ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! is_visible_in_tree ( ) | | ! p_event - > is_pressed ( ) | | p_event - > is_echo ( ) ) {
2017-11-12 03:42:56 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-06-26 02:02:17 +02:00
if ( ED_IS_SHORTCUT ( " script_editor/next_script " , p_event ) ) {
2019-11-25 17:16:29 +01:00
if ( script_list - > get_item_count ( ) > 1 ) {
int next_tab = script_list - > get_current ( ) + 1 ;
next_tab % = script_list - > get_item_count ( ) ;
_go_to_tab ( script_list - > get_item_metadata ( next_tab ) ) ;
_update_script_names ( ) ;
}
2022-12-23 19:44:58 +01:00
accept_event ( ) ;
2016-06-26 02:02:17 +02:00
}
if ( ED_IS_SHORTCUT ( " script_editor/prev_script " , p_event ) ) {
2019-11-25 17:16:29 +01:00
if ( script_list - > get_item_count ( ) > 1 ) {
int next_tab = script_list - > get_current ( ) - 1 ;
next_tab = next_tab > = 0 ? next_tab : script_list - > get_item_count ( ) - 1 ;
_go_to_tab ( script_list - > get_item_metadata ( next_tab ) ) ;
_update_script_names ( ) ;
}
2022-12-23 19:44:58 +01:00
accept_event ( ) ;
2016-06-26 02:02:17 +02:00
}
2017-11-12 03:42:56 +01:00
if ( ED_IS_SHORTCUT ( " script_editor/window_move_up " , p_event ) ) {
_menu_option ( WINDOW_MOVE_UP ) ;
2022-12-23 19:44:58 +01:00
accept_event ( ) ;
2017-11-12 03:42:56 +01:00
}
if ( ED_IS_SHORTCUT ( " script_editor/window_move_down " , p_event ) ) {
_menu_option ( WINDOW_MOVE_DOWN ) ;
2022-12-23 19:44:58 +01:00
accept_event ( ) ;
2017-11-12 03:42:56 +01:00
}
2016-06-26 02:02:17 +02:00
}
2022-07-28 13:38:13 +02:00
void ScriptEditor : : _script_list_clicked ( int p_item , Vector2 p_local_mouse_pos , MouseButton p_mouse_button_index ) {
if ( p_mouse_button_index = = MouseButton : : MIDDLE ) {
script_list - > select ( p_item ) ;
_script_selected ( p_item ) ;
_menu_option ( FILE_CLOSE ) ;
}
2017-11-11 22:36:46 +01:00
2022-07-28 13:38:13 +02:00
if ( p_mouse_button_index = = MouseButton : : RIGHT ) {
_make_script_list_context_menu ( ) ;
2017-11-11 22:36:46 +01:00
}
}
void ScriptEditor : : _make_script_list_context_menu ( ) {
context_menu - > clear ( ) ;
int selected = tab_container - > get_current_tab ( ) ;
2022-03-02 15:37:10 +01:00
if ( selected < 0 | | selected > = tab_container - > get_tab_count ( ) ) {
2017-11-11 22:36:46 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-11-11 22:36:46 +01:00
2022-03-02 15:37:10 +01:00
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( selected ) ) ;
2017-11-11 22:36:46 +01:00
if ( se ) {
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/save " ) , FILE_SAVE ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/save_as " ) , FILE_SAVE_AS ) ;
2018-01-02 08:10:49 +01:00
}
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/close_file " ) , FILE_CLOSE ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/close_all " ) , CLOSE_ALL ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/close_other_tabs " ) , CLOSE_OTHER_TABS ) ;
2023-04-18 16:30:14 +02:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/close_docs " ) , CLOSE_DOCS ) ;
2018-01-02 08:10:49 +01:00
context_menu - > add_separator ( ) ;
if ( se ) {
2018-07-25 20:20:11 +02:00
Ref < Script > scr = se - > get_edited_resource ( ) ;
2020-04-02 01:20:12 +02:00
if ( scr ! = nullptr ) {
2018-07-25 20:20:11 +02:00
if ( ! scr . is_null ( ) & & scr - > is_tool ( ) ) {
2021-11-19 17:45:16 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/reload_script_soft " ) , FILE_TOOL_RELOAD_SOFT ) ;
2018-07-25 20:20:11 +02:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/run_file " ) , FILE_RUN ) ;
2018-01-02 08:10:49 +01:00
context_menu - > add_separator ( ) ;
2018-07-25 20:20:11 +02:00
}
2017-11-11 22:36:46 +01:00
}
2018-01-02 08:10:49 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/copy_path " ) , FILE_COPY_PATH ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/show_in_file_system " ) , SHOW_IN_FILE_SYSTEM ) ;
context_menu - > add_separator ( ) ;
2017-11-11 22:36:46 +01:00
}
2017-11-12 03:42:56 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/window_move_up " ) , WINDOW_MOVE_UP ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/window_move_down " ) , WINDOW_MOVE_DOWN ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/window_sort " ) , WINDOW_SORT ) ;
2017-11-11 22:36:46 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_editor/toggle_scripts_panel " ) , TOGGLE_SCRIPTS_PANEL ) ;
2022-03-02 15:37:10 +01:00
context_menu - > set_item_disabled ( context_menu - > get_item_index ( CLOSE_ALL ) , tab_container - > get_tab_count ( ) < = 0 ) ;
context_menu - > set_item_disabled ( context_menu - > get_item_index ( CLOSE_OTHER_TABS ) , tab_container - > get_tab_count ( ) < = 1 ) ;
2023-04-18 16:30:14 +02:00
context_menu - > set_item_disabled ( context_menu - > get_item_index ( CLOSE_DOCS ) , ! _has_docs_tab ( ) ) ;
2022-01-21 05:12:48 +01:00
context_menu - > set_item_disabled ( context_menu - > get_item_index ( WINDOW_MOVE_UP ) , tab_container - > get_current_tab ( ) < = 0 ) ;
2022-03-02 15:37:10 +01:00
context_menu - > set_item_disabled ( context_menu - > get_item_index ( WINDOW_MOVE_DOWN ) , tab_container - > get_current_tab ( ) > = tab_container - > get_tab_count ( ) - 1 ) ;
context_menu - > set_item_disabled ( context_menu - > get_item_index ( WINDOW_SORT ) , tab_container - > get_tab_count ( ) < = 1 ) ;
2022-01-21 05:12:48 +01:00
2021-08-31 17:43:35 +02:00
context_menu - > set_position ( get_screen_position ( ) + get_local_mouse_position ( ) ) ;
2021-11-20 09:04:57 +01:00
context_menu - > reset_size ( ) ;
2017-11-11 22:36:46 +01:00
context_menu - > popup ( ) ;
}
2015-06-22 05:03:19 +02:00
void ScriptEditor : : set_window_layout ( Ref < ConfigFile > p_layout ) {
2022-03-06 21:39:19 +01:00
if ( ! bool ( EDITOR_GET ( " text_editor/behavior/files/restore_scripts_on_load " ) ) ) {
2015-06-22 05:03:19 +02:00
return ;
}
2020-05-14 16:41:43 +02:00
if ( ! p_layout - > has_section_key ( " ScriptEditor " , " open_scripts " ) & & ! p_layout - > has_section_key ( " ScriptEditor " , " open_help " ) ) {
2015-06-22 05:03:19 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-06-22 05:03:19 +02:00
Array scripts = p_layout - > get_value ( " ScriptEditor " , " open_scripts " ) ;
2015-11-17 13:46:08 +01:00
Array helps ;
2020-05-14 16:41:43 +02:00
if ( p_layout - > has_section_key ( " ScriptEditor " , " open_help " ) ) {
2015-11-17 13:46:08 +01:00
helps = p_layout - > get_value ( " ScriptEditor " , " open_help " ) ;
2020-05-14 16:41:43 +02:00
}
2015-06-22 05:03:19 +02:00
restoring_layout = true ;
2022-05-19 17:00:06 +02:00
HashSet < String > loaded_scripts ;
2018-05-28 17:52:28 +02:00
List < String > extensions ;
ResourceLoader : : get_recognized_extensions_for_type ( " Script " , & extensions ) ;
2023-01-28 15:05:23 +01:00
ResourceLoader : : get_recognized_extensions_for_type ( " JSON " , & extensions ) ;
2018-05-28 17:52:28 +02:00
2015-06-22 05:03:19 +02:00
for ( int i = 0 ; i < scripts . size ( ) ; i + + ) {
String path = scripts [ i ] ;
2019-04-13 13:43:35 +02:00
Dictionary script_info = scripts [ i ] ;
2020-12-15 13:04:21 +01:00
if ( ! script_info . is_empty ( ) ) {
2019-04-13 13:43:35 +02:00
path = script_info [ " path " ] ;
}
2020-05-14 16:41:43 +02:00
if ( ! FileAccess : : exists ( path ) ) {
2021-10-07 20:44:23 +02:00
if ( script_editor_cache - > has_section ( path ) ) {
script_editor_cache - > erase_section ( path ) ;
}
2016-07-08 02:27:20 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2021-10-07 20:44:23 +02:00
loaded_scripts . insert ( path ) ;
2018-05-28 17:52:28 +02:00
if ( extensions . find ( path . get_extension ( ) ) ) {
2023-01-28 15:05:23 +01:00
Ref < Resource > scr = ResourceLoader : : load ( path ) ;
2019-04-13 13:43:35 +02:00
if ( ! scr . is_valid ( ) ) {
2018-05-28 17:52:28 +02:00
continue ;
}
2019-11-20 10:09:59 +01:00
if ( ! edit ( scr , false ) ) {
2019-04-23 21:52:30 +02:00
continue ;
}
2019-04-13 13:43:35 +02:00
} else {
Error error ;
Ref < TextFile > text_file = _load_text_file ( path , & error ) ;
if ( error ! = OK | | ! text_file . is_valid ( ) ) {
continue ;
}
2019-11-20 10:09:59 +01:00
if ( ! edit ( text_file , false ) ) {
2019-04-23 21:52:30 +02:00
continue ;
}
2018-05-28 17:52:28 +02:00
}
2020-12-15 13:04:21 +01:00
if ( ! script_info . is_empty ( ) ) {
2022-03-02 15:37:10 +01:00
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( tab_container - > get_tab_count ( ) - 1 ) ) ;
2019-04-23 21:52:30 +02:00
if ( se ) {
se - > set_edit_state ( script_info [ " state " ] ) ;
}
2015-06-22 05:03:19 +02:00
}
}
2015-11-17 13:46:08 +01:00
for ( int i = 0 ; i < helps . size ( ) ; i + + ) {
String path = helps [ i ] ;
2021-12-09 10:42:46 +01:00
if ( path . is_empty ( ) ) { // invalid, skip
2017-07-02 12:31:08 +02:00
continue ;
}
2015-11-17 13:46:08 +01:00
_help_class_open ( path ) ;
}
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
tab_container - > get_tab_control ( i ) - > set_meta ( " __editor_pass " , Variant ( ) ) ;
2015-11-17 13:46:08 +01:00
}
2022-02-02 22:35:40 +01:00
if ( p_layout - > has_section_key ( " ScriptEditor " , " script_split_offset " ) ) {
script_split - > set_split_offset ( p_layout - > get_value ( " ScriptEditor " , " script_split_offset " ) ) ;
}
if ( p_layout - > has_section_key ( " ScriptEditor " , " list_split_offset " ) ) {
list_split - > set_split_offset ( p_layout - > get_value ( " ScriptEditor " , " list_split_offset " ) ) ;
2015-06-22 05:03:19 +02:00
}
2021-10-07 20:44:23 +02:00
// Remove any deleted editors that have been removed between launches.
// and if a Script, register breakpoints with the debugger.
List < String > cached_editors ;
script_editor_cache - > get_sections ( & cached_editors ) ;
for ( const String & E : cached_editors ) {
if ( loaded_scripts . has ( E ) ) {
continue ;
}
if ( ! FileAccess : : exists ( E ) ) {
script_editor_cache - > erase_section ( E ) ;
2021-10-07 20:46:44 +02:00
continue ;
}
Array breakpoints = _get_cached_breakpoints_for_script ( E ) ;
for ( int i = 0 ; i < breakpoints . size ( ) ; i + + ) {
EditorDebuggerNode : : get_singleton ( ) - > set_breakpoint ( E , ( int ) breakpoints [ i ] + 1 , true ) ;
2021-10-07 20:44:23 +02:00
}
}
2024-02-18 03:16:58 +01:00
_set_zoom_factor ( p_layout - > get_value ( " ScriptEditor " , " zoom_factor " , 1.0f ) ) ;
2015-06-22 05:03:19 +02:00
restoring_layout = false ;
2016-07-18 17:30:43 +02:00
_update_script_names ( ) ;
2023-05-11 04:17:03 +02:00
if ( p_layout - > has_section_key ( " ScriptEditor " , " selected_script " ) ) {
String selected_script = p_layout - > get_value ( " ScriptEditor " , " selected_script " ) ;
// If the selected script is not in the list of open scripts, select nothing.
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
if ( se & & se - > get_edited_resource ( ) - > get_path ( ) = = selected_script ) {
_go_to_tab ( i ) ;
break ;
}
}
}
2015-06-22 05:03:19 +02:00
}
void ScriptEditor : : get_window_layout ( Ref < ConfigFile > p_layout ) {
Array scripts ;
2015-11-17 13:46:08 +01:00
Array helps ;
2023-05-11 04:17:03 +02:00
String selected_script ;
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2016-08-03 00:11:05 +02:00
if ( se ) {
2018-05-28 17:52:28 +02:00
String path = se - > get_edited_resource ( ) - > get_path ( ) ;
2020-05-14 16:41:43 +02:00
if ( ! path . is_resource_file ( ) ) {
2015-11-17 13:46:08 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-11-17 13:46:08 +01:00
2023-05-11 04:17:03 +02:00
if ( tab_container - > get_current_tab_control ( ) = = tab_container - > get_tab_control ( i ) ) {
selected_script = path ;
}
2021-10-07 20:44:23 +02:00
_save_editor_state ( se ) ;
scripts . push_back ( path ) ;
2015-11-17 13:46:08 +01:00
}
2022-03-02 15:37:10 +01:00
EditorHelp * eh = Object : : cast_to < EditorHelp > ( tab_container - > get_tab_control ( i ) ) ;
2015-11-17 13:46:08 +01:00
if ( eh ) {
2017-01-03 03:03:46 +01:00
helps . push_back ( eh - > get_class ( ) ) ;
2015-11-17 13:46:08 +01:00
}
2015-06-22 05:03:19 +02:00
}
p_layout - > set_value ( " ScriptEditor " , " open_scripts " , scripts ) ;
2023-05-11 04:17:03 +02:00
p_layout - > set_value ( " ScriptEditor " , " selected_script " , selected_script ) ;
2015-11-17 13:46:08 +01:00
p_layout - > set_value ( " ScriptEditor " , " open_help " , helps ) ;
2022-02-02 22:35:40 +01:00
p_layout - > set_value ( " ScriptEditor " , " script_split_offset " , script_split - > get_split_offset ( ) ) ;
p_layout - > set_value ( " ScriptEditor " , " list_split_offset " , list_split - > get_split_offset ( ) ) ;
2024-02-18 03:16:58 +01:00
p_layout - > set_value ( " ScriptEditor " , " zoom_factor " , zoom_factor ) ;
2021-10-07 20:44:23 +02:00
// Save the cache.
2022-08-30 02:34:01 +02:00
script_editor_cache - > save ( EditorPaths : : get_singleton ( ) - > get_project_settings_dir ( ) . path_join ( " script_editor_cache.cfg " ) ) ;
2015-06-22 05:03:19 +02:00
}
2015-11-17 13:46:08 +01:00
void ScriptEditor : : _help_class_open ( const String & p_class ) {
2021-12-09 10:42:46 +01:00
if ( p_class . is_empty ( ) ) {
2016-11-25 00:46:55 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-11-17 13:46:08 +01:00
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
EditorHelp * eh = Object : : cast_to < EditorHelp > ( tab_container - > get_tab_control ( i ) ) ;
2015-11-17 13:46:08 +01:00
2017-01-03 03:03:46 +01:00
if ( eh & & eh - > get_class ( ) = = p_class ) {
2015-11-17 13:46:08 +01:00
_go_to_tab ( i ) ;
_update_script_names ( ) ;
return ;
}
}
EditorHelp * eh = memnew ( EditorHelp ) ;
eh - > set_name ( p_class ) ;
tab_container - > add_child ( eh ) ;
_go_to_tab ( tab_container - > get_tab_count ( ) - 1 ) ;
2023-04-21 15:32:26 +02:00
eh - > go_to_class ( p_class ) ;
2020-02-21 18:28:45 +01:00
eh - > connect ( " go_to_help " , callable_mp ( this , & ScriptEditor : : _help_class_goto ) ) ;
2022-10-22 23:54:37 +02:00
eh - > connect ( " request_save_history " , callable_mp ( this , & ScriptEditor : : _save_history ) ) ;
2018-01-08 01:31:36 +01:00
_add_recent_script ( p_class ) ;
2018-09-08 20:33:54 +02:00
_sort_list_on_update = true ;
2015-11-17 13:46:08 +01:00
_update_script_names ( ) ;
2016-07-18 17:30:43 +02:00
_save_layout ( ) ;
2015-11-17 13:46:08 +01:00
}
void ScriptEditor : : _help_class_goto ( const String & p_desc ) {
String cname = p_desc . get_slice ( " : " , 1 ) ;
2022-04-05 09:18:45 +02:00
if ( _help_tab_goto ( cname , p_desc ) ) {
return ;
2015-11-17 13:46:08 +01:00
}
EditorHelp * eh = memnew ( EditorHelp ) ;
eh - > set_name ( cname ) ;
tab_container - > add_child ( eh ) ;
eh - > go_to_help ( p_desc ) ;
2020-02-21 18:28:45 +01:00
eh - > connect ( " go_to_help " , callable_mp ( this , & ScriptEditor : : _help_class_goto ) ) ;
2018-01-08 01:31:36 +01:00
_add_recent_script ( eh - > get_class ( ) ) ;
2018-09-08 20:33:54 +02:00
_sort_list_on_update = true ;
2015-11-17 13:46:08 +01:00
_update_script_names ( ) ;
2016-07-18 17:30:43 +02:00
_save_layout ( ) ;
2022-04-05 09:18:45 +02:00
2023-12-18 15:46:56 +01:00
callable_mp ( this , & ScriptEditor : : _help_tab_goto ) . call_deferred ( cname , p_desc ) ;
2022-04-05 09:18:45 +02:00
}
bool ScriptEditor : : _help_tab_goto ( const String & p_name , const String & p_desc ) {
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
EditorHelp * eh = Object : : cast_to < EditorHelp > ( tab_container - > get_tab_control ( i ) ) ;
if ( eh & & eh - > get_class ( ) = = p_name ) {
_go_to_tab ( i ) ;
eh - > go_to_help ( p_desc ) ;
_update_script_names ( ) ;
return true ;
}
}
return false ;
2015-11-17 13:46:08 +01:00
}
2020-11-29 03:37:57 +01:00
void ScriptEditor : : update_doc ( const String & p_name ) {
ERR_FAIL_COND ( ! EditorHelp : : get_doc_data ( ) - > has_doc ( p_name ) ) ;
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
EditorHelp * eh = Object : : cast_to < EditorHelp > ( tab_container - > get_tab_control ( i ) ) ;
2020-11-29 03:37:57 +01:00
if ( eh & & eh - > get_class ( ) = = p_name ) {
eh - > update_doc ( ) ;
return ;
}
}
}
2022-10-04 07:58:58 +02:00
void ScriptEditor : : clear_docs_from_script ( const Ref < Script > & p_script ) {
ERR_FAIL_COND ( p_script . is_null ( ) ) ;
Vector < DocData : : ClassDoc > documentations = p_script - > get_documentation ( ) ;
for ( int j = 0 ; j < documentations . size ( ) ; j + + ) {
const DocData : : ClassDoc & doc = documentations . get ( j ) ;
if ( EditorHelp : : get_doc_data ( ) - > has_doc ( doc . name ) ) {
EditorHelp : : get_doc_data ( ) - > remove_doc ( doc . name ) ;
}
}
}
void ScriptEditor : : update_docs_from_script ( const Ref < Script > & p_script ) {
ERR_FAIL_COND ( p_script . is_null ( ) ) ;
Vector < DocData : : ClassDoc > documentations = p_script - > get_documentation ( ) ;
for ( int j = 0 ; j < documentations . size ( ) ; j + + ) {
const DocData : : ClassDoc & doc = documentations . get ( j ) ;
EditorHelp : : get_doc_data ( ) - > add_doc ( doc ) ;
update_doc ( doc . name ) ;
}
}
2016-08-03 00:11:05 +02:00
void ScriptEditor : : _update_selected_editor_menu ( ) {
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
2016-08-03 00:11:05 +02:00
bool current = tab_container - > get_current_tab ( ) = = i ;
2022-03-02 15:37:10 +01:00
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2016-08-03 00:11:05 +02:00
if ( se & & se - > get_edit_menu ( ) ) {
2020-05-14 16:41:43 +02:00
if ( current ) {
2016-08-03 00:11:05 +02:00
se - > get_edit_menu ( ) - > show ( ) ;
2020-05-14 16:41:43 +02:00
} else {
2016-08-03 00:11:05 +02:00
se - > get_edit_menu ( ) - > hide ( ) ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
}
}
2017-08-24 22:58:51 +02:00
EditorHelp * eh = Object : : cast_to < EditorHelp > ( tab_container - > get_current_tab_control ( ) ) ;
2019-05-03 01:07:06 +02:00
script_search_menu - > get_popup ( ) - > clear ( ) ;
2016-10-30 16:07:16 +01:00
if ( eh ) {
2022-09-02 11:37:48 +02:00
script_search_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/find " , TTR ( " Find... " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : F ) , HELP_SEARCH_FIND ) ;
2021-08-13 23:31:57 +02:00
script_search_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/find_next " , TTR ( " Find Next " ) , Key : : F3 ) , HELP_SEARCH_FIND_NEXT ) ;
script_search_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/find_previous " , TTR ( " Find Previous " ) , KeyModifierMask : : SHIFT | Key : : F3 ) , HELP_SEARCH_FIND_PREVIOUS ) ;
2019-05-03 01:07:06 +02:00
script_search_menu - > get_popup ( ) - > add_separator ( ) ;
2022-09-02 11:37:48 +02:00
script_search_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/find_in_files " , TTR ( " Find in Files " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : F ) , SEARCH_IN_FILES ) ;
2022-09-25 02:49:53 +02:00
script_search_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/replace_in_files " , TTR ( " Replace in Files " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : R ) , REPLACE_IN_FILES ) ;
2016-10-30 16:07:16 +01:00
script_search_menu - > show ( ) ;
} else {
2022-03-02 15:37:10 +01:00
if ( tab_container - > get_tab_count ( ) = = 0 ) {
2022-09-02 11:37:48 +02:00
script_search_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/find_in_files " , TTR ( " Find in Files " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : F ) , SEARCH_IN_FILES ) ;
2022-09-25 02:49:53 +02:00
script_search_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/replace_in_files " , TTR ( " Replace in Files " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : R ) , REPLACE_IN_FILES ) ;
2019-05-03 01:07:06 +02:00
script_search_menu - > show ( ) ;
} else {
script_search_menu - > hide ( ) ;
}
2016-10-30 16:07:16 +01:00
}
2016-08-03 00:11:05 +02:00
}
2015-11-17 13:46:08 +01:00
void ScriptEditor : : _update_history_pos ( int p_new_pos ) {
Node * n = tab_container - > get_current_tab_control ( ) ;
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < ScriptEditorBase > ( n ) ) {
2022-09-23 14:46:28 +02:00
history . write [ history_pos ] . state = Object : : cast_to < ScriptEditorBase > ( n ) - > get_navigation_state ( ) ;
2015-11-17 13:46:08 +01:00
}
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < EditorHelp > ( n ) ) {
2018-07-25 03:11:03 +02:00
history . write [ history_pos ] . state = Object : : cast_to < EditorHelp > ( n ) - > get_scroll ( ) ;
2015-11-17 13:46:08 +01:00
}
history_pos = p_new_pos ;
2022-03-04 23:16:33 +01:00
tab_container - > set_current_tab ( tab_container - > get_tab_idx_from_control ( history [ history_pos ] . control ) ) ;
2015-11-17 13:46:08 +01:00
n = history [ history_pos ] . control ;
2022-09-23 14:46:28 +02:00
ScriptEditorBase * seb = Object : : cast_to < ScriptEditorBase > ( n ) ;
if ( seb ) {
2022-10-22 23:54:37 +02:00
lock_history = true ;
2022-09-23 14:46:28 +02:00
seb - > set_edit_state ( history [ history_pos ] . state ) ;
seb - > ensure_focus ( ) ;
2017-07-06 09:18:20 +02:00
2022-09-29 11:53:28 +02:00
Ref < Script > scr = seb - > get_edited_resource ( ) ;
if ( scr ! = nullptr ) {
notify_script_changed ( scr ) ;
2018-05-28 17:52:28 +02:00
}
2015-11-17 13:46:08 +01:00
}
2022-10-22 23:54:37 +02:00
EditorHelp * eh = Object : : cast_to < EditorHelp > ( n ) ;
if ( eh ) {
eh - > set_scroll ( history [ history_pos ] . state ) ;
eh - > set_focused ( ) ;
2015-11-17 13:46:08 +01:00
}
n - > set_meta ( " __editor_pass " , + + edit_pass ) ;
_update_script_names ( ) ;
_update_history_arrows ( ) ;
2016-08-03 00:11:05 +02:00
_update_selected_editor_menu ( ) ;
2015-11-17 13:46:08 +01:00
}
void ScriptEditor : : _history_forward ( ) {
if ( history_pos < history . size ( ) - 1 ) {
_update_history_pos ( history_pos + 1 ) ;
}
}
void ScriptEditor : : _history_back ( ) {
if ( history_pos > 0 ) {
_update_history_pos ( history_pos - 1 ) ;
}
}
2017-07-06 09:18:20 +02:00
2020-03-17 07:33:00 +01:00
Vector < Ref < Script > > ScriptEditor : : get_open_scripts ( ) const {
Vector < Ref < Script > > out_scripts = Vector < Ref < Script > > ( ) ;
2017-07-06 09:18:20 +02:00
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! se ) {
2017-07-06 09:18:20 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-05-28 17:52:28 +02:00
2022-09-29 11:53:28 +02:00
Ref < Script > scr = se - > get_edited_resource ( ) ;
if ( scr ! = nullptr ) {
out_scripts . push_back ( scr ) ;
2018-05-28 17:52:28 +02:00
}
2017-07-06 09:18:20 +02:00
}
return out_scripts ;
}
2022-08-05 20:35:08 +02:00
TypedArray < ScriptEditorBase > ScriptEditor : : _get_open_script_editors ( ) const {
TypedArray < ScriptEditorBase > script_editors ;
2022-03-02 15:37:10 +01:00
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
2020-03-07 15:29:44 +01:00
if ( ! se ) {
continue ;
}
script_editors . push_back ( se ) ;
}
return script_editors ;
}
2015-11-17 13:46:08 +01:00
void ScriptEditor : : set_scene_root_script ( Ref < Script > p_script ) {
2020-07-26 23:18:05 +02:00
// Don't open dominant script if using an external editor.
2021-11-04 14:30:04 +01:00
bool use_external_editor =
2023-10-07 13:05:36 +02:00
external_editor_active | |
2020-07-27 15:05:14 +02:00
( p_script . is_valid ( ) & & p_script - > get_language ( ) - > overrides_external_editor ( ) ) ;
2021-11-04 14:30:04 +01:00
use_external_editor = use_external_editor & & ! ( p_script . is_valid ( ) & & p_script - > is_built_in ( ) ) ; // Ignore external editor for built-in scripts.
2022-10-18 16:43:37 +02:00
const bool open_dominant = EDITOR_GET ( " text_editor/behavior/files/open_dominant_script_on_scene_change " ) ;
2015-12-14 12:21:18 +01:00
2020-07-26 23:18:05 +02:00
if ( open_dominant & & ! use_external_editor & & p_script . is_valid ( ) ) {
2015-11-17 13:46:08 +01:00
edit ( p_script ) ;
}
}
2017-04-15 19:48:10 +02:00
bool ScriptEditor : : script_goto_method ( Ref < Script > p_script , const String & p_method ) {
int line = p_script - > get_member_line ( p_method ) ;
2016-06-12 01:01:17 +02:00
2020-05-14 16:41:43 +02:00
if ( line = = - 1 ) {
2017-04-15 19:48:10 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2017-04-15 19:48:10 +02:00
return edit ( p_script , line , 0 ) ;
2016-08-03 00:11:05 +02:00
}
2016-06-12 01:01:17 +02:00
2016-08-03 00:11:05 +02:00
void ScriptEditor : : set_live_auto_reload_running_scripts ( bool p_enabled ) {
auto_reload_running_scripts = p_enabled ;
}
2016-06-12 01:01:17 +02:00
2024-02-15 17:25:58 +01:00
void ScriptEditor : : _help_search ( const String & p_text ) {
2018-10-02 12:07:44 +02:00
help_search_dialog - > popup_dialog ( p_text ) ;
2016-08-03 00:11:05 +02:00
}
2016-06-12 01:01:17 +02:00
2016-08-25 22:45:20 +02:00
void ScriptEditor : : _open_script_request ( const String & p_path ) {
2022-09-29 11:53:28 +02:00
Ref < Script > scr = ResourceLoader : : load ( p_path ) ;
if ( scr . is_valid ( ) ) {
script_editor - > edit ( scr , false ) ;
2018-05-28 17:52:28 +02:00
return ;
}
2023-01-28 15:05:23 +01:00
Ref < JSON > json = ResourceLoader : : load ( p_path ) ;
if ( json . is_valid ( ) ) {
script_editor - > edit ( json , false ) ;
return ;
}
2018-05-28 17:52:28 +02:00
Error err ;
Ref < TextFile > text_file = script_editor - > _load_text_file ( p_path , & err ) ;
if ( text_file . is_valid ( ) ) {
script_editor - > edit ( text_file , false ) ;
return ;
2016-08-25 22:45:20 +02:00
}
}
2016-06-12 01:01:17 +02:00
2020-05-03 18:08:15 +02:00
void ScriptEditor : : register_syntax_highlighter ( const Ref < EditorSyntaxHighlighter > & p_syntax_highlighter ) {
ERR_FAIL_COND ( p_syntax_highlighter . is_null ( ) ) ;
2022-02-01 19:19:13 +01:00
if ( ! syntax_highlighters . has ( p_syntax_highlighter ) ) {
2020-03-07 15:29:44 +01:00
syntax_highlighters . push_back ( p_syntax_highlighter ) ;
}
}
2018-04-02 13:41:44 +02:00
2020-05-03 18:08:15 +02:00
void ScriptEditor : : unregister_syntax_highlighter ( const Ref < EditorSyntaxHighlighter > & p_syntax_highlighter ) {
ERR_FAIL_COND ( p_syntax_highlighter . is_null ( ) ) ;
2020-03-07 15:29:44 +01:00
syntax_highlighters . erase ( p_syntax_highlighter ) ;
2018-04-02 13:41:44 +02:00
}
2016-08-03 00:11:05 +02:00
int ScriptEditor : : script_editor_func_count = 0 ;
CreateScriptEditorFunc ScriptEditor : : script_editor_funcs [ ScriptEditor : : SCRIPT_EDITOR_FUNC_MAX ] ;
2016-06-12 01:01:17 +02:00
2016-08-03 00:11:05 +02:00
void ScriptEditor : : register_create_script_editor_function ( CreateScriptEditorFunc p_func ) {
ERR_FAIL_COND ( script_editor_func_count = = SCRIPT_EDITOR_FUNC_MAX ) ;
script_editor_funcs [ script_editor_func_count + + ] = p_func ;
2016-06-03 17:34:11 +02:00
}
2017-08-18 21:43:23 +02:00
void ScriptEditor : : _script_changed ( ) {
2021-11-17 21:08:55 +01:00
NodeDock : : get_singleton ( ) - > update_lists ( ) ;
2017-08-18 21:43:23 +02:00
}
2024-02-15 17:25:58 +01:00
void ScriptEditor : : _on_find_in_files_requested ( const String & text ) {
2020-02-09 10:10:58 +01:00
find_in_files_dialog - > set_find_in_files_mode ( FindInFilesDialog : : SEARCH_MODE ) ;
find_in_files_dialog - > set_search_text ( text ) ;
2020-03-06 18:00:16 +01:00
find_in_files_dialog - > popup_centered ( ) ;
2020-02-09 10:10:58 +01:00
}
2024-02-15 17:25:58 +01:00
void ScriptEditor : : _on_replace_in_files_requested ( const String & text ) {
2020-02-09 10:10:58 +01:00
find_in_files_dialog - > set_find_in_files_mode ( FindInFilesDialog : : REPLACE_MODE ) ;
2018-02-12 02:36:15 +01:00
find_in_files_dialog - > set_search_text ( text ) ;
2020-02-09 10:10:58 +01:00
find_in_files_dialog - > set_replace_text ( " " ) ;
2020-03-06 18:00:16 +01:00
find_in_files_dialog - > popup_centered ( ) ;
2018-02-12 02:36:15 +01:00
}
2024-02-15 17:25:58 +01:00
void ScriptEditor : : _on_find_in_files_result_selected ( const String & fpath , int line_number , int begin , int end ) {
2019-08-08 04:06:33 +02:00
if ( ResourceLoader : : exists ( fpath ) ) {
2022-05-03 01:43:50 +02:00
Ref < Resource > res = ResourceLoader : : load ( fpath ) ;
2019-08-08 04:06:33 +02:00
2021-03-24 19:50:41 +01:00
if ( fpath . get_extension ( ) = = " gdshader " ) {
2023-08-11 15:55:47 +02:00
ShaderEditorPlugin * shader_editor = Object : : cast_to < ShaderEditorPlugin > ( EditorNode : : get_editor_data ( ) . get_editor_by_name ( " Shader " ) ) ;
2019-08-08 04:06:33 +02:00
shader_editor - > edit ( res . ptr ( ) ) ;
shader_editor - > make_visible ( true ) ;
2022-05-27 11:02:55 +02:00
shader_editor - > get_shader_editor ( res ) - > goto_line_selection ( line_number - 1 , begin , end ) ;
2019-08-08 04:06:33 +02:00
return ;
2021-11-08 02:28:55 +01:00
} else if ( fpath . get_extension ( ) = = " tscn " ) {
2023-03-06 21:19:14 +01:00
Ref < FileAccess > f = FileAccess : : open ( fpath , FileAccess : : READ ) ;
bool is_script_found = false ;
// Starting from top of the tscn file.
int scr_start_line = 1 ;
String scr_header = " [sub_resource type= \" GDScript \" id= \" " ;
String scr_id = " " ;
String line = " " ;
int l = 0 ;
while ( ! f - > eof_reached ( ) ) {
line = f - > get_line ( ) ;
l + + ;
if ( ! line . begins_with ( scr_header ) ) {
continue ;
}
// Found the end of the script.
scr_id = line . get_slice ( scr_header , 1 ) ;
scr_id = scr_id . get_slice ( " \" " , 0 ) ;
scr_start_line = l + 1 ;
int scr_line_count = 0 ;
do {
line = f - > get_line ( ) ;
l + + ;
String strline = line . strip_edges ( ) ;
if ( strline . ends_with ( " \" " ) & & ! strline . ends_with ( " \\ \" " ) ) {
// Found the end of script.
break ;
}
scr_line_count + + ;
} while ( ! f - > eof_reached ( ) ) ;
if ( line_number > scr_start_line + scr_line_count ) {
// Find in another built-in GDScript.
continue ;
}
// Real line number of the built-in script.
line_number = line_number - scr_start_line ;
is_script_found = true ;
break ;
}
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > load_scene ( fpath ) ;
2023-03-06 21:19:14 +01:00
if ( is_script_found & & ! scr_id . is_empty ( ) ) {
Ref < Script > scr = ResourceLoader : : load ( fpath + " :: " + scr_id , " Script " ) ;
if ( scr . is_valid ( ) ) {
edit ( scr ) ;
ScriptTextEditor * ste = Object : : cast_to < ScriptTextEditor > ( _get_current_editor ( ) ) ;
if ( ste ) {
2024-02-25 15:40:39 +01:00
EditorInterface : : get_singleton ( ) - > set_main_screen_editor ( " Script " ) ;
2023-03-06 21:19:14 +01:00
ste - > goto_line_selection ( line_number , begin , end ) ;
}
}
}
2021-11-08 02:28:55 +01:00
return ;
2019-08-08 04:06:33 +02:00
} else {
2022-09-29 11:53:28 +02:00
Ref < Script > scr = res ;
2023-01-28 15:05:23 +01:00
Ref < JSON > json = res ;
if ( scr . is_valid ( ) | | json . is_valid ( ) ) {
2022-09-29 11:53:28 +02:00
edit ( scr ) ;
2019-08-07 08:41:10 +02:00
2019-08-08 04:06:33 +02:00
ScriptTextEditor * ste = Object : : cast_to < ScriptTextEditor > ( _get_current_editor ( ) ) ;
if ( ste ) {
2024-02-25 15:40:39 +01:00
EditorInterface : : get_singleton ( ) - > set_main_screen_editor ( " Script " ) ;
2019-08-08 04:06:33 +02:00
ste - > goto_line_selection ( line_number - 1 , begin , end ) ;
}
return ;
2019-08-07 08:41:10 +02:00
}
2019-08-08 04:06:33 +02:00
}
}
2018-02-12 02:36:15 +01:00
2019-08-08 04:06:33 +02:00
// If the file is not a valid resource/script, load it as a text file.
Error err ;
Ref < TextFile > text_file = _load_text_file ( fpath , & err ) ;
if ( text_file . is_valid ( ) ) {
edit ( text_file ) ;
2019-08-07 08:41:10 +02:00
2019-08-08 04:06:33 +02:00
TextEditor * te = Object : : cast_to < TextEditor > ( _get_current_editor ( ) ) ;
if ( te ) {
te - > goto_line_selection ( line_number - 1 , begin , end ) ;
2018-10-27 17:24:41 +02:00
}
2018-02-12 02:36:15 +01:00
}
}
void ScriptEditor : : _start_find_in_files ( bool with_replace ) {
FindInFiles * f = find_in_files - > get_finder ( ) ;
f - > set_search_text ( find_in_files_dialog - > get_search_text ( ) ) ;
f - > set_match_case ( find_in_files_dialog - > is_match_case ( ) ) ;
2019-01-09 06:23:46 +01:00
f - > set_whole_words ( find_in_files_dialog - > is_whole_words ( ) ) ;
2018-02-12 02:36:15 +01:00
f - > set_folder ( find_in_files_dialog - > get_folder ( ) ) ;
f - > set_filter ( find_in_files_dialog - > get_filter ( ) ) ;
find_in_files - > set_with_replace ( with_replace ) ;
2020-02-09 10:10:58 +01:00
find_in_files - > set_replace_text ( find_in_files_dialog - > get_replace_text ( ) ) ;
2018-02-12 02:36:15 +01:00
find_in_files - > start_search ( ) ;
2024-02-25 15:40:39 +01:00
if ( find_in_files_button - > get_index ( ) ! = find_in_files_button - > get_parent ( ) - > get_child_count ( ) ) {
find_in_files_button - > get_parent ( ) - > move_child ( find_in_files_button , - 1 ) ;
}
if ( ! find_in_files_button - > is_visible ( ) ) {
find_in_files_button - > show ( ) ;
}
2024-01-30 23:22:22 +01:00
EditorNode : : get_bottom_panel ( ) - > make_item_visible ( find_in_files ) ;
2018-02-12 02:36:15 +01:00
}
2024-02-15 17:25:58 +01:00
void ScriptEditor : : _on_find_in_files_modified_files ( const PackedStringArray & paths ) {
2018-02-12 02:36:15 +01:00
_test_script_times_on_disk ( ) ;
_update_modified_scripts_for_external_editor ( ) ;
}
2024-02-18 03:16:58 +01:00
void ScriptEditor : : _set_zoom_factor ( float p_zoom_factor ) {
if ( zoom_factor = = p_zoom_factor ) {
return ;
}
zoom_factor = p_zoom_factor ;
for ( int i = 0 ; i < tab_container - > get_tab_count ( ) ; i + + ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( tab_container - > get_tab_control ( i ) ) ;
if ( se ) {
CodeTextEditor * cte = se - > get_code_editor ( ) ;
if ( cte ) {
if ( zoom_factor ! = cte - > get_zoom_factor ( ) ) {
cte - > set_zoom_factor ( zoom_factor ) ;
}
}
}
}
}
2024-02-25 15:40:39 +01:00
void ScriptEditor : : _on_find_in_files_close_button_clicked ( ) {
EditorNode : : get_bottom_panel ( ) - > hide_bottom_panel ( ) ;
find_in_files_button - > hide ( ) ;
}
2022-11-02 15:23:25 +01:00
void ScriptEditor : : _window_changed ( bool p_visible ) {
make_floating - > set_visible ( ! p_visible ) ;
2023-08-15 06:40:32 +02:00
is_floating = p_visible ;
2022-11-02 15:23:25 +01:00
}
2019-06-03 21:57:06 +02:00
void ScriptEditor : : _filter_scripts_text_changed ( const String & p_newtext ) {
_update_script_names ( ) ;
}
void ScriptEditor : : _filter_methods_text_changed ( const String & p_newtext ) {
_update_members_overview ( ) ;
}
2015-11-17 13:46:08 +01:00
void ScriptEditor : : _bind_methods ( ) {
2022-04-05 09:18:45 +02:00
ClassDB : : bind_method ( " _help_tab_goto " , & ScriptEditor : : _help_tab_goto ) ;
2020-03-07 15:29:44 +01:00
ClassDB : : bind_method ( " get_current_editor " , & ScriptEditor : : _get_current_editor ) ;
ClassDB : : bind_method ( " get_open_script_editors " , & ScriptEditor : : _get_open_script_editors ) ;
ClassDB : : bind_method ( D_METHOD ( " register_syntax_highlighter " , " syntax_highlighter " ) , & ScriptEditor : : register_syntax_highlighter ) ;
ClassDB : : bind_method ( D_METHOD ( " unregister_syntax_highlighter " , " syntax_highlighter " ) , & ScriptEditor : : unregister_syntax_highlighter ) ;
2019-04-09 22:07:13 +02:00
ClassDB : : bind_method ( D_METHOD ( " goto_line " , " line_number " ) , & ScriptEditor : : _goto_script_line2 ) ;
2017-07-06 09:18:20 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_current_script " ) , & ScriptEditor : : _get_current_script ) ;
2017-07-19 19:47:43 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_open_scripts " ) , & ScriptEditor : : _get_open_scripts ) ;
2017-12-13 18:41:28 +01:00
ClassDB : : bind_method ( D_METHOD ( " open_script_create_dialog " , " base_name " , " base_path " ) , & ScriptEditor : : open_script_create_dialog ) ;
2017-07-06 09:18:20 +02:00
2024-04-04 04:28:54 +02:00
ClassDB : : bind_method ( D_METHOD ( " goto_help " , " topic " ) , & ScriptEditor : : goto_help ) ;
2017-08-29 07:15:46 +02:00
ADD_SIGNAL ( MethodInfo ( " editor_script_changed " , PropertyInfo ( Variant : : OBJECT , " script " , PROPERTY_HINT_RESOURCE_TYPE , " Script " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " script_close " , PropertyInfo ( Variant : : OBJECT , " script " , PROPERTY_HINT_RESOURCE_TYPE , " Script " ) ) ) ;
2015-11-17 13:46:08 +01:00
}
2015-06-22 05:03:19 +02:00
2022-11-02 15:23:25 +01:00
ScriptEditor : : ScriptEditor ( WindowWrapper * p_wrapper ) {
window_wrapper = p_wrapper ;
2016-04-12 16:45:31 +02:00
current_theme = " " ;
2021-10-07 20:44:23 +02:00
script_editor_cache . instantiate ( ) ;
2022-08-30 02:34:01 +02:00
script_editor_cache - > load ( EditorPaths : : get_singleton ( ) - > get_project_settings_dir ( ) . path_join ( " script_editor_cache.cfg " ) ) ;
2021-10-07 20:44:23 +02:00
2015-06-26 06:14:31 +02:00
completion_cache = memnew ( EditorScriptCodeCompletionCache ) ;
2015-06-22 05:03:19 +02:00
restoring_layout = false ;
waiting_update_names = false ;
2016-07-29 14:50:26 +02:00
pending_auto_reload = false ;
2018-11-11 13:14:06 +01:00
auto_reload_running_scripts = true ;
2023-10-07 13:05:36 +02:00
external_editor_active = false ;
2022-10-18 16:43:37 +02:00
members_overview_enabled = EDITOR_GET ( " text_editor/script_list/show_members_overview " ) ;
help_overview_enabled = EDITOR_GET ( " text_editor/help/show_help_index " ) ;
2014-02-10 02:10:30 +01:00
2017-07-15 06:40:17 +02:00
VBoxContainer * main_container = memnew ( VBoxContainer ) ;
add_child ( main_container ) ;
2014-02-10 02:10:30 +01:00
menu_hb = memnew ( HBoxContainer ) ;
2017-07-15 06:40:17 +02:00
main_container - > add_child ( menu_hb ) ;
2014-02-10 02:10:30 +01:00
2015-06-22 05:03:19 +02:00
script_split = memnew ( HSplitContainer ) ;
2017-07-15 06:40:17 +02:00
main_container - > add_child ( script_split ) ;
2015-06-22 05:03:19 +02:00
script_split - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2017-05-28 16:20:38 +02:00
list_split = memnew ( VSplitContainer ) ;
script_split - > add_child ( list_split ) ;
list_split - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2019-06-03 21:57:06 +02:00
scripts_vbox = memnew ( VBoxContainer ) ;
scripts_vbox - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
list_split - > add_child ( scripts_vbox ) ;
filter_scripts = memnew ( LineEdit ) ;
2022-05-27 06:02:48 +02:00
filter_scripts - > set_placeholder ( TTR ( " Filter Scripts " ) ) ;
2019-06-03 21:57:06 +02:00
filter_scripts - > set_clear_button_enabled ( true ) ;
2020-02-21 18:28:45 +01:00
filter_scripts - > connect ( " text_changed " , callable_mp ( this , & ScriptEditor : : _filter_scripts_text_changed ) ) ;
2019-06-03 21:57:06 +02:00
scripts_vbox - > add_child ( filter_scripts ) ;
2015-06-22 05:03:19 +02:00
script_list = memnew ( ItemList ) ;
2024-01-23 22:29:45 +01:00
script_list - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2019-06-03 21:57:06 +02:00
scripts_vbox - > add_child ( script_list ) ;
2020-02-05 06:16:54 +01:00
script_list - > set_custom_minimum_size ( Size2 ( 150 , 60 ) * EDSCALE ) ; //need to give a bit of limit to avoid it from disappearing
2017-07-01 02:30:17 +02:00
script_list - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2020-02-18 22:57:40 +01:00
script_split - > set_split_offset ( 70 * EDSCALE ) ;
2017-11-12 20:21:09 +01:00
_sort_list_on_update = true ;
2022-07-28 13:38:13 +02:00
script_list - > connect ( " item_clicked " , callable_mp ( this , & ScriptEditor : : _script_list_clicked ) , CONNECT_DEFERRED ) ;
2017-11-11 22:36:46 +01:00
script_list - > set_allow_rmb_select ( true ) ;
2023-01-14 03:37:19 +01:00
SET_DRAG_FORWARDING_GCD ( script_list , ScriptEditor ) ;
2017-11-12 03:42:56 +01:00
2017-11-11 22:36:46 +01:00
context_menu = memnew ( PopupMenu ) ;
add_child ( context_menu ) ;
2020-02-21 18:28:45 +01:00
context_menu - > connect ( " id_pressed " , callable_mp ( this , & ScriptEditor : : _menu_option ) ) ;
2017-11-11 22:36:46 +01:00
2018-06-02 02:28:49 +02:00
overview_vbox = memnew ( VBoxContainer ) ;
overview_vbox - > set_custom_minimum_size ( Size2 ( 0 , 90 ) ) ;
overview_vbox - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2018-04-30 14:27:00 +02:00
2018-06-02 02:28:49 +02:00
list_split - > add_child ( overview_vbox ) ;
2022-10-01 19:23:13 +02:00
list_split - > set_visible ( EditorSettings : : get_singleton ( ) - > get_project_metadata ( " scripts_panel " , " show_scripts_panel " , true ) ) ;
2018-06-02 02:28:49 +02:00
buttons_hbox = memnew ( HBoxContainer ) ;
overview_vbox - > add_child ( buttons_hbox ) ;
2018-04-30 14:27:00 +02:00
2018-06-05 23:18:11 +02:00
filename = memnew ( Label ) ;
filename - > set_clip_text ( true ) ;
filename - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2023-09-13 13:14:07 +02:00
filename - > add_theme_style_override ( " normal " , EditorNode : : get_singleton ( ) - > get_editor_theme ( ) - > get_stylebox ( SNAME ( " normal " ) , SNAME ( " LineEdit " ) ) ) ;
2018-06-02 02:28:49 +02:00
buttons_hbox - > add_child ( filename ) ;
2018-06-05 23:18:11 +02:00
2020-06-19 20:49:04 +02:00
members_overview_alphabeta_sort_button = memnew ( Button ) ;
members_overview_alphabeta_sort_button - > set_flat ( true ) ;
2022-08-25 12:42:17 +02:00
members_overview_alphabeta_sort_button - > set_tooltip_text ( TTR ( " Toggle alphabetical sorting of the method list. " ) ) ;
2018-04-30 14:27:00 +02:00
members_overview_alphabeta_sort_button - > set_toggle_mode ( true ) ;
2022-10-18 16:43:37 +02:00
members_overview_alphabeta_sort_button - > set_pressed ( EDITOR_GET ( " text_editor/script_list/sort_members_outline_alphabetically " ) ) ;
2020-02-21 18:28:45 +01:00
members_overview_alphabeta_sort_button - > connect ( " toggled " , callable_mp ( this , & ScriptEditor : : _toggle_members_overview_alpha_sort ) ) ;
2018-04-30 14:27:00 +02:00
2018-06-02 02:28:49 +02:00
buttons_hbox - > add_child ( members_overview_alphabeta_sort_button ) ;
2018-04-30 14:27:00 +02:00
2019-06-03 21:57:06 +02:00
filter_methods = memnew ( LineEdit ) ;
2022-05-27 06:02:48 +02:00
filter_methods - > set_placeholder ( TTR ( " Filter Methods " ) ) ;
2019-06-03 21:57:06 +02:00
filter_methods - > set_clear_button_enabled ( true ) ;
2020-02-21 18:28:45 +01:00
filter_methods - > connect ( " text_changed " , callable_mp ( this , & ScriptEditor : : _filter_methods_text_changed ) ) ;
2019-06-03 21:57:06 +02:00
overview_vbox - > add_child ( filter_methods ) ;
2017-05-28 16:20:38 +02:00
members_overview = memnew ( ItemList ) ;
2024-01-23 22:29:45 +01:00
members_overview - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2018-06-02 02:28:49 +02:00
overview_vbox - > add_child ( members_overview ) ;
2018-04-30 14:27:00 +02:00
2018-02-14 04:24:57 +01:00
members_overview - > set_allow_reselect ( true ) ;
2020-02-05 06:16:54 +01:00
members_overview - > set_custom_minimum_size ( Size2 ( 0 , 60 ) * EDSCALE ) ; //need to give a bit of limit to avoid it from disappearing
2017-07-01 02:30:17 +02:00
members_overview - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2018-04-30 14:27:00 +02:00
members_overview - > set_allow_rmb_select ( true ) ;
2015-06-22 05:03:19 +02:00
2017-09-14 02:56:37 +02:00
help_overview = memnew ( ItemList ) ;
2024-01-23 22:29:45 +01:00
help_overview - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2018-06-02 02:28:49 +02:00
overview_vbox - > add_child ( help_overview ) ;
2018-02-14 04:24:57 +01:00
help_overview - > set_allow_reselect ( true ) ;
2020-02-05 06:16:54 +01:00
help_overview - > set_custom_minimum_size ( Size2 ( 0 , 60 ) * EDSCALE ) ; //need to give a bit of limit to avoid it from disappearing
2017-09-14 02:56:37 +02:00
help_overview - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2021-06-03 01:05:41 +02:00
VBoxContainer * code_editor_container = memnew ( VBoxContainer ) ;
script_split - > add_child ( code_editor_container ) ;
2014-02-10 02:10:30 +01:00
tab_container = memnew ( TabContainer ) ;
2015-06-22 05:03:19 +02:00
tab_container - > set_tabs_visible ( false ) ;
2018-10-20 22:05:11 +02:00
tab_container - > set_custom_minimum_size ( Size2 ( 200 , 0 ) * EDSCALE ) ;
2021-06-03 01:05:41 +02:00
code_editor_container - > add_child ( tab_container ) ;
2015-06-22 05:03:19 +02:00
tab_container - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2021-06-03 01:05:41 +02:00
tab_container - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
find_replace_bar = memnew ( FindReplaceBar ) ;
code_editor_container - > add_child ( find_replace_bar ) ;
find_replace_bar - > hide ( ) ;
2017-11-12 20:21:09 +01:00
2017-11-12 03:42:56 +01:00
ED_SHORTCUT ( " script_editor/window_sort " , TTR ( " Sort " ) ) ;
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " script_editor/window_move_up " , TTR ( " Move Up " ) , KeyModifierMask : : SHIFT | KeyModifierMask : : ALT | Key : : UP ) ;
ED_SHORTCUT ( " script_editor/window_move_down " , TTR ( " Move Down " ) , KeyModifierMask : : SHIFT | KeyModifierMask : : ALT | Key : : DOWN ) ;
// FIXME: These should be `Key::GREATER` and `Key::LESS` but those don't work.
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " script_editor/next_script " , TTR ( " Next Script " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : PERIOD ) ;
ED_SHORTCUT ( " script_editor/prev_script " , TTR ( " Previous Script " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : COMMA ) ;
2020-03-08 17:32:49 +01:00
set_process_input ( true ) ;
2022-01-11 14:59:52 +01:00
set_process_shortcut_input ( true ) ;
2016-06-26 02:02:17 +02:00
2014-02-10 02:10:30 +01:00
file_menu = memnew ( MenuButton ) ;
2016-05-04 03:25:37 +02:00
file_menu - > set_text ( TTR ( " File " ) ) ;
2018-07-30 00:26:43 +02:00
file_menu - > set_switch_on_hover ( true ) ;
2020-09-17 03:40:00 +02:00
file_menu - > set_shortcut_context ( this ) ;
menu_hb - > add_child ( file_menu ) ;
2020-03-12 13:37:40 +01:00
2022-09-02 11:37:48 +02:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/new " , TTR ( " New Script... " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : N ) , FILE_NEW ) ;
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/new_textfile " , TTR ( " New Text File... " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : N ) , FILE_NEW_TEXTFILE ) ;
2018-12-08 17:18:04 +01:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/open " , TTR ( " Open... " ) ) , FILE_OPEN ) ;
2022-09-02 11:37:48 +02:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/reopen_closed_script " , TTR ( " Reopen Closed Script " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : T ) , FILE_REOPEN_CLOSED ) ;
2017-04-27 17:07:39 +02:00
recent_scripts = memnew ( PopupMenu ) ;
2023-11-28 17:33:04 +01:00
file_menu - > get_popup ( ) - > add_submenu_node_item ( TTR ( " Open Recent " ) , recent_scripts , FILE_OPEN_RECENT ) ;
2020-02-21 18:28:45 +01:00
recent_scripts - > connect ( " id_pressed " , callable_mp ( this , & ScriptEditor : : _open_recent_script ) ) ;
2023-11-28 17:33:04 +01:00
2017-04-27 17:07:39 +02:00
_update_recent_scripts ( ) ;
2015-06-22 05:03:19 +02:00
file_menu - > get_popup ( ) - > add_separator ( ) ;
2023-11-15 11:17:16 +01:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/save " , TTR ( " Save " ) , KeyModifierMask : : ALT | KeyModifierMask : : CMD_OR_CTRL | Key : : S ) , FILE_SAVE ) ;
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/save_as " , TTR ( " Save As... " ) ) , FILE_SAVE_AS ) ;
2021-08-13 23:31:57 +02:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/save_all " , TTR ( " Save All " ) , KeyModifierMask : : SHIFT | KeyModifierMask : : ALT | Key : : S ) , FILE_SAVE_ALL ) ;
2023-02-16 10:28:04 +01:00
ED_SHORTCUT_OVERRIDE ( " script_editor/save_all " , " macos " , KeyModifierMask : : META | KeyModifierMask : : CTRL | Key : : S ) ;
2015-06-22 05:03:19 +02:00
file_menu - > get_popup ( ) - > add_separator ( ) ;
2022-09-02 11:37:48 +02:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/reload_script_soft " , TTR ( " Soft Reload Tool Script " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : ALT | Key : : R ) , FILE_TOOL_RELOAD_SOFT ) ;
2017-12-07 04:57:41 +01:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/copy_path " , TTR ( " Copy Script Path " ) ) , FILE_COPY_PATH ) ;
2018-10-26 21:11:36 +02:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/show_in_file_system " , TTR ( " Show in FileSystem " ) ) , SHOW_IN_FILE_SYSTEM ) ;
2016-08-03 00:11:05 +02:00
file_menu - > get_popup ( ) - > add_separator ( ) ;
2021-08-13 23:31:57 +02:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/history_previous " , TTR ( " History Previous " ) , KeyModifierMask : : ALT | Key : : LEFT ) , WINDOW_PREV ) ;
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/history_next " , TTR ( " History Next " ) , KeyModifierMask : : ALT | Key : : RIGHT ) , WINDOW_NEXT ) ;
2015-11-17 13:46:08 +01:00
file_menu - > get_popup ( ) - > add_separator ( ) ;
2018-06-21 11:10:43 +02:00
theme_submenu = memnew ( PopupMenu ) ;
2018-12-08 17:18:04 +01:00
theme_submenu - > add_shortcut ( ED_SHORTCUT ( " script_editor/import_theme " , TTR ( " Import Theme... " ) ) , THEME_IMPORT ) ;
2018-06-21 11:10:43 +02:00
theme_submenu - > add_shortcut ( ED_SHORTCUT ( " script_editor/reload_theme " , TTR ( " Reload Theme " ) ) , THEME_RELOAD ) ;
2023-11-28 17:33:04 +01:00
file_menu - > get_popup ( ) - > add_submenu_node_item ( TTR ( " Theme " ) , theme_submenu , FILE_THEME ) ;
theme_submenu - > connect ( " id_pressed " , callable_mp ( this , & ScriptEditor : : _theme_option ) ) ;
2019-08-12 22:23:00 +02:00
2018-12-08 17:18:04 +01:00
theme_submenu - > add_separator ( ) ;
2018-06-21 11:10:43 +02:00
theme_submenu - > add_shortcut ( ED_SHORTCUT ( " script_editor/save_theme " , TTR ( " Save Theme " ) ) , THEME_SAVE ) ;
2018-12-08 17:18:04 +01:00
theme_submenu - > add_shortcut ( ED_SHORTCUT ( " script_editor/save_theme_as " , TTR ( " Save Theme As... " ) ) , THEME_SAVE_AS ) ;
2018-06-21 11:10:43 +02:00
2016-04-12 16:45:31 +02:00
file_menu - > get_popup ( ) - > add_separator ( ) ;
2022-09-02 11:37:48 +02:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/close_file " , TTR ( " Close " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : W ) , FILE_CLOSE ) ;
2016-08-13 02:56:38 +02:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/close_all " , TTR ( " Close All " ) ) , CLOSE_ALL ) ;
2017-11-20 06:15:40 +01:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/close_other_tabs " , TTR ( " Close Other Tabs " ) ) , CLOSE_OTHER_TABS ) ;
2019-08-12 22:23:00 +02:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/close_docs " , TTR ( " Close Docs " ) ) , CLOSE_DOCS ) ;
2017-07-10 14:11:31 +02:00
file_menu - > get_popup ( ) - > add_separator ( ) ;
2022-09-02 11:37:48 +02:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/run_file " , TTR ( " Run " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : X ) , FILE_RUN ) ;
2019-12-17 14:51:49 +01:00
file_menu - > get_popup ( ) - > add_separator ( ) ;
2022-09-02 11:37:48 +02:00
file_menu - > get_popup ( ) - > add_shortcut ( ED_SHORTCUT ( " script_editor/toggle_scripts_panel " , TTR ( " Toggle Scripts Panel " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : BACKSLASH ) , TOGGLE_SCRIPTS_PANEL ) ;
2020-02-21 18:28:45 +01:00
file_menu - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & ScriptEditor : : _menu_option ) ) ;
2022-01-21 05:12:48 +01:00
file_menu - > get_popup ( ) - > connect ( " about_to_popup " , callable_mp ( this , & ScriptEditor : : _prepare_file_menu ) ) ;
2023-03-03 19:13:58 +01:00
file_menu - > get_popup ( ) - > connect ( " popup_hide " , callable_mp ( this , & ScriptEditor : : _file_menu_closed ) ) ;
2016-08-03 00:11:05 +02:00
2015-11-17 13:46:08 +01:00
script_search_menu = memnew ( MenuButton ) ;
2016-05-04 03:25:37 +02:00
script_search_menu - > set_text ( TTR ( " Search " ) ) ;
2018-07-30 00:26:43 +02:00
script_search_menu - > set_switch_on_hover ( true ) ;
2020-09-17 03:40:00 +02:00
script_search_menu - > set_shortcut_context ( this ) ;
2020-02-21 18:28:45 +01:00
script_search_menu - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & ScriptEditor : : _menu_option ) ) ;
2020-09-17 03:40:00 +02:00
menu_hb - > add_child ( script_search_menu ) ;
2015-11-17 13:46:08 +01:00
2022-09-29 11:53:28 +02:00
MenuButton * debug_menu_btn = memnew ( MenuButton ) ;
menu_hb - > add_child ( debug_menu_btn ) ;
debug_menu_btn - > hide ( ) ; // Handled by EditorDebuggerNode below.
2020-02-07 02:52:05 +01:00
EditorDebuggerNode * debugger = EditorDebuggerNode : : get_singleton ( ) ;
2022-09-29 11:53:28 +02:00
debugger - > set_script_debug_button ( debug_menu_btn ) ;
2020-02-21 18:28:45 +01:00
debugger - > connect ( " goto_script_line " , callable_mp ( this , & ScriptEditor : : _goto_script_line ) ) ;
debugger - > connect ( " set_execution " , callable_mp ( this , & ScriptEditor : : _set_execution ) ) ;
debugger - > connect ( " clear_execution " , callable_mp ( this , & ScriptEditor : : _clear_execution ) ) ;
debugger - > connect ( " breaked " , callable_mp ( this , & ScriptEditor : : _breaked ) ) ;
2023-10-05 18:45:27 +02:00
debugger - > connect ( " breakpoint_set_in_tree " , callable_mp ( this , & ScriptEditor : : _set_breakpoint ) ) ;
debugger - > connect ( " breakpoints_cleared_in_tree " , callable_mp ( this , & ScriptEditor : : _clear_breakpoints ) ) ;
2014-02-10 02:10:30 +01:00
2015-11-17 13:46:08 +01:00
menu_hb - > add_spacer ( ) ;
2017-01-12 22:27:27 +01:00
script_icon = memnew ( TextureRect ) ;
2015-11-17 13:46:08 +01:00
menu_hb - > add_child ( script_icon ) ;
script_name_label = memnew ( Label ) ;
menu_hb - > add_child ( script_name_label ) ;
script_icon - > hide ( ) ;
script_name_label - > hide ( ) ;
menu_hb - > add_spacer ( ) ;
2020-06-19 20:49:04 +02:00
site_search = memnew ( Button ) ;
site_search - > set_flat ( true ) ;
2017-05-26 16:34:41 +02:00
site_search - > set_text ( TTR ( " Online Docs " ) ) ;
2022-07-28 22:56:41 +02:00
site_search - > connect ( " pressed " , callable_mp ( this , & ScriptEditor : : _menu_option ) . bind ( SEARCH_WEBSITE ) ) ;
2015-11-17 13:46:08 +01:00
menu_hb - > add_child ( site_search ) ;
2022-08-25 12:42:17 +02:00
site_search - > set_tooltip_text ( TTR ( " Open Godot online documentation. " ) ) ;
2015-11-17 13:46:08 +01:00
2020-06-19 20:49:04 +02:00
help_search = memnew ( Button ) ;
help_search - > set_flat ( true ) ;
2016-05-04 03:25:37 +02:00
help_search - > set_text ( TTR ( " Search Help " ) ) ;
2022-07-28 22:56:41 +02:00
help_search - > connect ( " pressed " , callable_mp ( this , & ScriptEditor : : _menu_option ) . bind ( SEARCH_HELP ) ) ;
2015-11-17 13:46:08 +01:00
menu_hb - > add_child ( help_search ) ;
2022-08-25 12:42:17 +02:00
help_search - > set_tooltip_text ( TTR ( " Search the reference documentation. " ) ) ;
2015-11-17 13:46:08 +01:00
menu_hb - > add_child ( memnew ( VSeparator ) ) ;
2020-06-19 20:49:04 +02:00
script_back = memnew ( Button ) ;
script_back - > set_flat ( true ) ;
2020-02-21 18:28:45 +01:00
script_back - > connect ( " pressed " , callable_mp ( this , & ScriptEditor : : _history_back ) ) ;
2015-11-17 13:46:08 +01:00
menu_hb - > add_child ( script_back ) ;
script_back - > set_disabled ( true ) ;
2022-08-25 12:42:17 +02:00
script_back - > set_tooltip_text ( TTR ( " Go to previous edited document. " ) ) ;
2015-11-17 13:46:08 +01:00
2020-06-19 20:49:04 +02:00
script_forward = memnew ( Button ) ;
script_forward - > set_flat ( true ) ;
2020-02-21 18:28:45 +01:00
script_forward - > connect ( " pressed " , callable_mp ( this , & ScriptEditor : : _history_forward ) ) ;
2015-11-17 13:46:08 +01:00
menu_hb - > add_child ( script_forward ) ;
script_forward - > set_disabled ( true ) ;
2022-08-25 12:42:17 +02:00
script_forward - > set_tooltip_text ( TTR ( " Go to next edited document. " ) ) ;
2015-11-17 13:46:08 +01:00
2023-11-06 12:41:08 +01:00
menu_hb - > add_child ( memnew ( VSeparator ) ) ;
2023-06-21 01:00:37 +02:00
2023-11-06 12:41:08 +01:00
make_floating = memnew ( ScreenSelect ) ;
make_floating - > set_flat ( true ) ;
make_floating - > connect ( " request_open_in_screen " , callable_mp ( window_wrapper , & WindowWrapper : : enable_window_on_screen ) . bind ( true ) ) ;
if ( ! make_floating - > is_disabled ( ) ) {
// Override default ScreenSelect tooltip if multi-window support is available.
2023-06-21 01:00:37 +02:00
make_floating - > set_tooltip_text ( TTR ( " Make the script editor floating. " ) ) ;
}
2023-11-06 12:41:08 +01:00
menu_hb - > add_child ( make_floating ) ;
p_wrapper - > connect ( " window_visibility_changed " , callable_mp ( this , & ScriptEditor : : _window_changed ) ) ;
2020-02-21 18:28:45 +01:00
tab_container - > connect ( " tab_changed " , callable_mp ( this , & ScriptEditor : : _tab_changed ) ) ;
2015-11-17 13:46:08 +01:00
2014-02-10 02:10:30 +01:00
erase_tab_confirm = memnew ( ConfirmationDialog ) ;
2022-07-08 02:31:19 +02:00
erase_tab_confirm - > set_ok_button_text ( TTR ( " Save " ) ) ;
2020-07-09 01:02:38 +02:00
erase_tab_confirm - > add_button ( TTR ( " Discard " ) , DisplayServer : : get_singleton ( ) - > get_swap_cancel_ok ( ) , " discard " ) ;
2024-04-23 23:33:01 +02:00
erase_tab_confirm - > connect ( " confirmed " , callable_mp ( this , & ScriptEditor : : _close_current_tab ) . bind ( true , true ) ) ;
2020-02-21 18:28:45 +01:00
erase_tab_confirm - > connect ( " custom_action " , callable_mp ( this , & ScriptEditor : : _close_discard_current_tab ) ) ;
2017-01-02 19:45:59 +01:00
add_child ( erase_tab_confirm ) ;
2014-02-10 02:10:30 +01:00
2015-08-10 01:39:59 +02:00
script_create_dialog = memnew ( ScriptCreateDialog ) ;
2016-05-04 03:25:37 +02:00
script_create_dialog - > set_title ( TTR ( " Create Script " ) ) ;
2015-08-10 01:39:59 +02:00
add_child ( script_create_dialog ) ;
2020-02-21 18:28:45 +01:00
script_create_dialog - > connect ( " script_created " , callable_mp ( this , & ScriptEditor : : _script_created ) ) ;
2014-02-10 02:10:30 +01:00
2016-04-12 16:45:31 +02:00
file_dialog_option = - 1 ;
file_dialog = memnew ( EditorFileDialog ) ;
add_child ( file_dialog ) ;
2020-02-21 18:28:45 +01:00
file_dialog - > connect ( " file_selected " , callable_mp ( this , & ScriptEditor : : _file_dialog_action ) ) ;
2014-02-10 02:10:30 +01:00
2018-01-08 01:31:36 +01:00
error_dialog = memnew ( AcceptDialog ) ;
add_child ( error_dialog ) ;
2014-02-10 02:10:30 +01:00
disk_changed = memnew ( ConfirmationDialog ) ;
{
VBoxContainer * vbc = memnew ( VBoxContainer ) ;
disk_changed - > add_child ( vbc ) ;
Label * dl = memnew ( Label ) ;
2016-05-21 01:18:35 +02:00
dl - > set_text ( TTR ( " The following files are newer on disk. \n What action should be taken?: " ) ) ;
2014-02-10 02:10:30 +01:00
vbc - > add_child ( dl ) ;
disk_changed_list = memnew ( Tree ) ;
vbc - > add_child ( disk_changed_list ) ;
2024-03-17 09:28:18 +01:00
disk_changed_list - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2014-02-10 02:10:30 +01:00
disk_changed_list - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2022-11-03 10:06:51 +01:00
disk_changed - > connect ( " confirmed " , callable_mp ( this , & ScriptEditor : : reload_scripts ) . bind ( false ) ) ;
2022-07-08 02:31:19 +02:00
disk_changed - > set_ok_button_text ( TTR ( " Reload " ) ) ;
2014-02-10 02:10:30 +01:00
2020-07-09 01:02:38 +02:00
disk_changed - > add_button ( TTR ( " Resave " ) , ! DisplayServer : : get_singleton ( ) - > get_swap_cancel_ok ( ) , " resave " ) ;
2020-02-21 18:28:45 +01:00
disk_changed - > connect ( " custom_action " , callable_mp ( this , & ScriptEditor : : _resave_scripts ) ) ;
2014-02-10 02:10:30 +01:00
}
add_child ( disk_changed ) ;
script_editor = this ;
2015-05-05 04:32:40 +02:00
autosave_timer = memnew ( Timer ) ;
autosave_timer - > set_one_shot ( false ) ;
2020-02-21 23:26:13 +01:00
autosave_timer - > connect ( SceneStringNames : : get_singleton ( ) - > tree_entered , callable_mp ( this , & ScriptEditor : : _update_autosave_timer ) ) ;
2020-02-21 18:28:45 +01:00
autosave_timer - > connect ( " timeout " , callable_mp ( this , & ScriptEditor : : _autosave_scripts ) ) ;
2015-05-05 04:32:40 +02:00
add_child ( autosave_timer ) ;
2015-06-22 05:03:19 +02:00
grab_focus_block = false ;
2015-11-17 13:46:08 +01:00
help_search_dialog = memnew ( EditorHelpSearch ) ;
add_child ( help_search_dialog ) ;
2020-02-21 18:28:45 +01:00
help_search_dialog - > connect ( " go_to_help " , callable_mp ( this , & ScriptEditor : : _help_class_goto ) ) ;
2015-11-17 13:46:08 +01:00
2018-02-12 02:36:15 +01:00
find_in_files_dialog = memnew ( FindInFilesDialog ) ;
2022-07-28 22:56:41 +02:00
find_in_files_dialog - > connect ( FindInFilesDialog : : SIGNAL_FIND_REQUESTED , callable_mp ( this , & ScriptEditor : : _start_find_in_files ) . bind ( false ) ) ;
find_in_files_dialog - > connect ( FindInFilesDialog : : SIGNAL_REPLACE_REQUESTED , callable_mp ( this , & ScriptEditor : : _start_find_in_files ) . bind ( true ) ) ;
2018-02-12 02:36:15 +01:00
add_child ( find_in_files_dialog ) ;
find_in_files = memnew ( FindInFilesPanel ) ;
2024-02-08 00:08:07 +01:00
find_in_files_button = EditorNode : : get_bottom_panel ( ) - > add_item ( TTR ( " Search Results " ) , find_in_files , ED_SHORTCUT_AND_COMMAND ( " bottom_panels/toggle_search_results_bottom_panel " , TTR ( " Toggle Search Results Bottom Panel " ) ) ) ;
2018-10-03 22:43:26 +02:00
find_in_files - > set_custom_minimum_size ( Size2 ( 0 , 200 ) * EDSCALE ) ;
2020-02-21 23:26:13 +01:00
find_in_files - > connect ( FindInFilesPanel : : SIGNAL_RESULT_SELECTED , callable_mp ( this , & ScriptEditor : : _on_find_in_files_result_selected ) ) ;
find_in_files - > connect ( FindInFilesPanel : : SIGNAL_FILES_MODIFIED , callable_mp ( this , & ScriptEditor : : _on_find_in_files_modified_files ) ) ;
2024-02-25 15:40:39 +01:00
find_in_files - > connect ( FindInFilesPanel : : SIGNAL_CLOSE_BUTTON_CLICKED , callable_mp ( this , & ScriptEditor : : _on_find_in_files_close_button_clicked ) ) ;
2018-02-12 02:36:15 +01:00
find_in_files - > hide ( ) ;
find_in_files_button - > hide ( ) ;
2015-11-17 13:46:08 +01:00
history_pos = - 1 ;
2014-05-06 11:43:14 +02:00
2015-11-17 13:46:08 +01:00
edit_pass = 0 ;
2022-10-18 16:43:37 +02:00
trim_trailing_whitespace_on_save = EDITOR_GET ( " text_editor/behavior/files/trim_trailing_whitespace_on_save " ) ;
convert_indent_on_save = EDITOR_GET ( " text_editor/behavior/files/convert_indent_on_save " ) ;
2016-08-25 22:45:20 +02:00
ScriptServer : : edit_request_func = _open_script_request ;
2017-09-06 23:25:57 +02:00
2023-01-28 15:05:23 +01:00
Ref < EditorJSONSyntaxHighlighter > json_syntax_highlighter ;
json_syntax_highlighter . instantiate ( ) ;
register_syntax_highlighter ( json_syntax_highlighter ) ;
2014-02-10 02:10:30 +01:00
}
2015-06-26 06:14:31 +02:00
ScriptEditor : : ~ ScriptEditor ( ) {
memdelete ( completion_cache ) ;
}
2022-11-02 15:23:25 +01:00
void ScriptEditorPlugin : : _focus_another_editor ( ) {
if ( window_wrapper - > get_window_enabled ( ) ) {
ERR_FAIL_COND ( last_editor . is_empty ( ) ) ;
EditorInterface : : get_singleton ( ) - > set_main_screen_editor ( last_editor ) ;
}
}
2024-02-15 17:25:58 +01:00
void ScriptEditorPlugin : : _save_last_editor ( const String & p_editor ) {
2022-11-02 15:23:25 +01:00
if ( p_editor ! = get_name ( ) ) {
last_editor = p_editor ;
}
}
void ScriptEditorPlugin : : _window_visibility_changed ( bool p_visible ) {
_focus_another_editor ( ) ;
if ( p_visible ) {
2023-08-13 02:33:39 +02:00
script_editor - > add_theme_style_override ( " panel " , script_editor - > get_theme_stylebox ( " ScriptEditorPanelFloating " , EditorStringName ( EditorStyles ) ) ) ;
2022-11-02 15:23:25 +01:00
} else {
2023-08-13 02:33:39 +02:00
script_editor - > add_theme_style_override ( " panel " , script_editor - > get_theme_stylebox ( " ScriptEditorPanel " , EditorStringName ( EditorStyles ) ) ) ;
2022-11-02 15:23:25 +01:00
}
}
void ScriptEditorPlugin : : _notification ( int p_what ) {
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
connect ( " main_screen_changed " , callable_mp ( this , & ScriptEditorPlugin : : _save_last_editor ) ) ;
} break ;
case NOTIFICATION_EXIT_TREE : {
disconnect ( " main_screen_changed " , callable_mp ( this , & ScriptEditorPlugin : : _save_last_editor ) ) ;
} break ;
}
}
2014-02-10 02:10:30 +01:00
void ScriptEditorPlugin : : edit ( Object * p_object ) {
2018-05-28 17:52:28 +02:00
if ( Object : : cast_to < Script > ( p_object ) ) {
2018-09-06 23:33:44 +02:00
Script * p_script = Object : : cast_to < Script > ( p_object ) ;
2019-09-04 20:00:09 +02:00
String res_path = p_script - > get_path ( ) . get_slice ( " :: " , 0 ) ;
2018-09-06 23:33:44 +02:00
2022-04-03 01:32:19 +02:00
if ( p_script - > is_built_in ( ) & & ! res_path . is_empty ( ) ) {
2019-09-04 20:00:09 +02:00
if ( ResourceLoader : : get_resource_type ( res_path ) = = " PackedScene " ) {
if ( ! EditorNode : : get_singleton ( ) - > is_scene_open ( res_path ) ) {
EditorNode : : get_singleton ( ) - > load_scene ( res_path ) ;
}
} else {
EditorNode : : get_singleton ( ) - > load_resource ( res_path ) ;
}
2018-09-06 23:33:44 +02:00
}
2019-09-04 20:00:09 +02:00
script_editor - > edit ( p_script ) ;
2023-01-28 15:05:23 +01:00
} else if ( Object : : cast_to < JSON > ( p_object ) ) {
script_editor - > edit ( Object : : cast_to < JSON > ( p_object ) ) ;
2019-05-18 01:27:52 +02:00
} else if ( Object : : cast_to < TextFile > ( p_object ) ) {
2018-05-28 17:52:28 +02:00
script_editor - > edit ( Object : : cast_to < TextFile > ( p_object ) ) ;
}
2014-02-10 02:10:30 +01:00
}
bool ScriptEditorPlugin : : handles ( Object * p_object ) const {
2018-05-28 17:52:28 +02:00
if ( Object : : cast_to < TextFile > ( p_object ) ) {
return true ;
}
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < Script > ( p_object ) ) {
2023-01-28 15:05:23 +01:00
return true ;
}
if ( Object : : cast_to < JSON > ( p_object ) ) {
2018-09-06 23:33:44 +02:00
return true ;
2016-07-07 01:35:49 +02:00
}
2017-01-03 03:03:46 +01:00
return p_object - > is_class ( " Script " ) ;
2014-02-10 02:10:30 +01:00
}
void ScriptEditorPlugin : : make_visible ( bool p_visible ) {
if ( p_visible ) {
2022-11-02 15:23:25 +01:00
window_wrapper - > show ( ) ;
2014-02-10 02:10:30 +01:00
script_editor - > set_process ( true ) ;
script_editor - > ensure_select_current ( ) ;
} else {
2022-11-02 15:23:25 +01:00
window_wrapper - > hide ( ) ;
if ( ! window_wrapper - > get_window_enabled ( ) ) {
script_editor - > set_process ( false ) ;
}
2014-02-10 02:10:30 +01:00
}
}
void ScriptEditorPlugin : : selected_notify ( ) {
script_editor - > ensure_select_current ( ) ;
2022-11-02 15:23:25 +01:00
_focus_another_editor ( ) ;
2014-02-10 02:10:30 +01:00
}
2023-04-05 15:45:41 +02:00
String ScriptEditorPlugin : : get_unsaved_status ( const String & p_for_scene ) const {
2022-10-16 19:30:38 +02:00
const PackedStringArray unsaved_scripts = script_editor - > get_unsaved_scripts ( ) ;
if ( unsaved_scripts . is_empty ( ) ) {
return String ( ) ;
}
PackedStringArray message ;
2023-04-05 15:45:41 +02:00
if ( ! p_for_scene . is_empty ( ) ) {
PackedStringArray unsaved_built_in_scripts ;
const String scene_file = p_for_scene . get_file ( ) ;
for ( const String & E : unsaved_scripts ) {
if ( ! E . is_resource_file ( ) & & E . contains ( scene_file ) ) {
unsaved_built_in_scripts . append ( E ) ;
}
}
if ( unsaved_built_in_scripts . is_empty ( ) ) {
return String ( ) ;
} else {
message . resize ( unsaved_built_in_scripts . size ( ) + 1 ) ;
message . write [ 0 ] = TTR ( " There are unsaved changes in the following built-in script(s): " ) ;
int i = 1 ;
for ( const String & E : unsaved_built_in_scripts ) {
message . write [ i ] = E . trim_suffix ( " (*) " ) ;
i + + ;
}
return String ( " \n " ) . join ( message ) ;
}
}
2022-10-16 19:30:38 +02:00
message . resize ( unsaved_scripts . size ( ) + 1 ) ;
2023-04-05 15:45:41 +02:00
message . write [ 0 ] = TTR ( " Save changes to the following script(s) before quitting? " ) ;
2022-10-16 19:30:38 +02:00
int i = 1 ;
for ( const String & E : unsaved_scripts ) {
message . write [ i ] = E . trim_suffix ( " (*) " ) ;
i + + ;
}
return String ( " \n " ) . join ( message ) ;
}
2014-02-10 02:10:30 +01:00
void ScriptEditorPlugin : : save_external_data ( ) {
2023-02-20 19:29:20 +01:00
if ( ! EditorNode : : get_singleton ( ) - > is_exiting ( ) ) {
script_editor - > save_all_scripts ( ) ;
}
2014-02-10 02:10:30 +01:00
}
void ScriptEditorPlugin : : apply_changes ( ) {
script_editor - > apply_scripts ( ) ;
}
2015-06-22 05:03:19 +02:00
void ScriptEditorPlugin : : set_window_layout ( Ref < ConfigFile > p_layout ) {
script_editor - > set_window_layout ( p_layout ) ;
2022-11-02 15:23:25 +01:00
if ( EDITOR_GET ( " interface/multi_window/restore_windows_on_load " ) & & window_wrapper - > is_window_available ( ) & & p_layout - > has_section_key ( " ScriptEditor " , " window_rect " ) ) {
window_wrapper - > restore_window_from_saved_position (
p_layout - > get_value ( " ScriptEditor " , " window_rect " , Rect2i ( ) ) ,
p_layout - > get_value ( " ScriptEditor " , " window_screen " , - 1 ) ,
p_layout - > get_value ( " ScriptEditor " , " window_screen_rect " , Rect2i ( ) ) ) ;
} else {
window_wrapper - > set_window_enabled ( false ) ;
}
2014-02-10 02:10:30 +01:00
}
2015-06-22 05:03:19 +02:00
void ScriptEditorPlugin : : get_window_layout ( Ref < ConfigFile > p_layout ) {
script_editor - > get_window_layout ( p_layout ) ;
2022-11-02 15:23:25 +01:00
if ( window_wrapper - > get_window_enabled ( ) ) {
p_layout - > set_value ( " ScriptEditor " , " window_rect " , window_wrapper - > get_window_rect ( ) ) ;
int screen = window_wrapper - > get_window_screen ( ) ;
p_layout - > set_value ( " ScriptEditor " , " window_screen " , screen ) ;
p_layout - > set_value ( " ScriptEditor " , " window_screen_rect " , DisplayServer : : get_singleton ( ) - > screen_get_usable_rect ( screen ) ) ;
} else {
if ( p_layout - > has_section_key ( " ScriptEditor " , " window_rect " ) ) {
p_layout - > erase_section_key ( " ScriptEditor " , " window_rect " ) ;
}
if ( p_layout - > has_section_key ( " ScriptEditor " , " window_screen " ) ) {
p_layout - > erase_section_key ( " ScriptEditor " , " window_screen " ) ;
}
if ( p_layout - > has_section_key ( " ScriptEditor " , " window_screen_rect " ) ) {
p_layout - > erase_section_key ( " ScriptEditor " , " window_screen_rect " ) ;
}
}
2015-06-22 05:03:19 +02:00
}
2014-02-10 02:10:30 +01:00
void ScriptEditorPlugin : : get_breakpoints ( List < String > * p_breakpoints ) {
2019-07-01 12:59:42 +02:00
script_editor - > get_breakpoints ( p_breakpoints ) ;
2014-02-10 02:10:30 +01:00
}
2015-12-09 13:08:41 +01:00
void ScriptEditorPlugin : : edited_scene_changed ( ) {
script_editor - > edited_scene_changed ( ) ;
}
2022-01-27 10:36:51 +01:00
ScriptEditorPlugin : : ScriptEditorPlugin ( ) {
2022-11-02 15:23:25 +01:00
window_wrapper = memnew ( WindowWrapper ) ;
2023-06-23 12:21:56 +02:00
window_wrapper - > set_window_title ( vformat ( TTR ( " %s - Godot Engine " ) , TTR ( " Script Editor " ) ) ) ;
2022-11-02 15:23:25 +01:00
window_wrapper - > set_margins_enabled ( true ) ;
script_editor = memnew ( ScriptEditor ( window_wrapper ) ) ;
Ref < Shortcut > make_floating_shortcut = ED_SHORTCUT_AND_COMMAND ( " script_editor/make_floating " , TTR ( " Make Floating " ) ) ;
window_wrapper - > set_wrapped_control ( script_editor , make_floating_shortcut ) ;
EditorNode : : get_singleton ( ) - > get_main_screen_control ( ) - > add_child ( window_wrapper ) ;
window_wrapper - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
window_wrapper - > hide ( ) ;
window_wrapper - > connect ( " window_visibility_changed " , callable_mp ( this , & ScriptEditorPlugin : : _window_visibility_changed ) ) ;
2014-02-10 02:10:30 +01:00
2022-03-06 21:39:19 +01:00
EDITOR_GET ( " text_editor/behavior/files/auto_reload_scripts_on_external_change " ) ;
2021-08-15 19:14:46 +02:00
ScriptServer : : set_reload_scripts_on_save ( EDITOR_DEF ( " text_editor/behavior/files/auto_reload_and_parse_scripts_on_save " , true ) ) ;
EDITOR_DEF ( " text_editor/behavior/files/open_dominant_script_on_scene_change " , true ) ;
2017-01-05 23:41:36 +01:00
EDITOR_DEF ( " text_editor/external/use_external_editor " , false ) ;
EDITOR_DEF ( " text_editor/external/exec_path " , " " ) ;
2019-09-01 13:28:57 +02:00
EDITOR_DEF ( " text_editor/script_list/script_temperature_enabled " , true ) ;
EDITOR_DEF ( " text_editor/script_list/script_temperature_history_size " , 15 ) ;
EDITOR_DEF ( " text_editor/script_list/group_help_pages " , true ) ;
EditorSettings : : get_singleton ( ) - > add_property_hint ( PropertyInfo ( Variant : : INT , " text_editor/script_list/sort_scripts_by " , PROPERTY_HINT_ENUM , " Name,Path,None " ) ) ;
EDITOR_DEF ( " text_editor/script_list/sort_scripts_by " , 0 ) ;
EditorSettings : : get_singleton ( ) - > add_property_hint ( PropertyInfo ( Variant : : INT , " text_editor/script_list/list_script_names_as " , PROPERTY_HINT_ENUM , " Name,Parent Directory And Name,Full Path " ) ) ;
EDITOR_DEF ( " text_editor/script_list/list_script_names_as " , 0 ) ;
2017-01-05 23:41:36 +01:00
EditorSettings : : get_singleton ( ) - > add_property_hint ( PropertyInfo ( Variant : : STRING , " text_editor/external/exec_path " , PROPERTY_HINT_GLOBAL_FILE ) ) ;
2019-06-11 09:20:42 +02:00
EDITOR_DEF ( " text_editor/external/exec_flags " , " {file} " ) ;
EditorSettings : : get_singleton ( ) - > add_property_hint ( PropertyInfo ( Variant : : STRING , " text_editor/external/exec_flags " , PROPERTY_HINT_PLACEHOLDER_TEXT , " Call flags with placeholders: {project}, {file}, {col}, {line}. " ) ) ;
2017-04-27 17:07:39 +02:00
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " script_editor/reopen_closed_script " , TTR ( " Reopen Closed Script " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : T ) ;
2019-08-12 22:23:00 +02:00
ED_SHORTCUT ( " script_editor/clear_recent " , TTR ( " Clear Recent Scripts " ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
2014-02-10 02:10:30 +01:00
ScriptEditorPlugin : : ~ ScriptEditorPlugin ( ) {
}