2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* script_text_editor.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
2016-08-03 00:11:05 +02:00
# include "script_text_editor.h"
2017-01-16 08:04:19 +01:00
2022-02-12 02:46:22 +01:00
# include "core/config/project_settings.h"
2019-08-07 16:31:33 +02:00
# include "core/math/expression.h"
2018-09-11 18:13:45 +02:00
# include "core/os/keyboard.h"
2020-02-07 02:52:05 +01:00
# include "editor/debugger/editor_debugger_node.h"
2021-05-29 15:28:16 +02:00
# include "editor/editor_command_palette.h"
2017-03-05 14:21:25 +01:00
# include "editor/editor_node.h"
2019-12-24 08:17:23 +01:00
# include "editor/editor_scale.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"
2023-07-09 23:15:54 +02:00
# include "editor/gui/editor_toaster.h"
2023-04-12 21:02:28 +02:00
# include "scene/gui/rich_text_label.h"
2022-11-19 12:45:49 +01:00
# include "scene/gui/split_container.h"
2016-08-03 00:11:05 +02:00
2019-04-20 13:51:25 +02:00
void ConnectionInfoDialog : : ok_pressed ( ) {
}
void ConnectionInfoDialog : : popup_connections ( String p_method , Vector < Node * > p_nodes ) {
method - > set_text ( p_method ) ;
tree - > clear ( ) ;
TreeItem * root = tree - > create_item ( ) ;
for ( int i = 0 ; i < p_nodes . size ( ) ; i + + ) {
List < Connection > all_connections ;
p_nodes [ i ] - > get_signals_connected_to_this ( & all_connections ) ;
2021-07-24 15:46:25 +02:00
for ( const Connection & connection : all_connections ) {
2020-02-19 20:27:19 +01:00
if ( connection . callable . get_method ( ) ! = p_method ) {
2019-04-20 13:51:25 +02:00
continue ;
}
TreeItem * node_item = tree - > create_item ( root ) ;
2020-02-19 20:27:19 +01:00
node_item - > set_text ( 0 , Object : : cast_to < Node > ( connection . signal . get_object ( ) ) - > get_name ( ) ) ;
node_item - > set_icon ( 0 , EditorNode : : get_singleton ( ) - > get_object_icon ( connection . signal . get_object ( ) , " Node " ) ) ;
2019-04-20 13:51:25 +02:00
node_item - > set_selectable ( 0 , false ) ;
node_item - > set_editable ( 0 , false ) ;
2020-02-19 20:27:19 +01:00
node_item - > set_text ( 1 , connection . signal . get_name ( ) ) ;
2020-03-06 18:00:16 +01:00
Control * p = Object : : cast_to < Control > ( get_parent ( ) ) ;
2023-08-13 02:33:39 +02:00
node_item - > set_icon ( 1 , p - > get_editor_theme_icon ( SNAME ( " Slot " ) ) ) ;
2019-04-20 13:51:25 +02:00
node_item - > set_selectable ( 1 , false ) ;
node_item - > set_editable ( 1 , false ) ;
2020-02-19 20:27:19 +01:00
node_item - > set_text ( 2 , Object : : cast_to < Node > ( connection . callable . get_object ( ) ) - > get_name ( ) ) ;
node_item - > set_icon ( 2 , EditorNode : : get_singleton ( ) - > get_object_icon ( connection . callable . get_object ( ) , " Node " ) ) ;
2019-04-20 13:51:25 +02:00
node_item - > set_selectable ( 2 , false ) ;
node_item - > set_editable ( 2 , false ) ;
}
}
2020-02-15 16:36:10 +01:00
popup_centered ( Size2 ( 600 , 300 ) * EDSCALE ) ;
2019-04-20 13:51:25 +02:00
}
ConnectionInfoDialog : : ConnectionInfoDialog ( ) {
set_title ( TTR ( " Connections to method: " ) ) ;
VBoxContainer * vbc = memnew ( VBoxContainer ) ;
2020-12-22 17:24:29 +01:00
vbc - > set_anchor_and_offset ( SIDE_LEFT , Control : : ANCHOR_BEGIN , 8 * EDSCALE ) ;
vbc - > set_anchor_and_offset ( SIDE_TOP , Control : : ANCHOR_BEGIN , 8 * EDSCALE ) ;
vbc - > set_anchor_and_offset ( SIDE_RIGHT , Control : : ANCHOR_END , - 8 * EDSCALE ) ;
vbc - > set_anchor_and_offset ( SIDE_BOTTOM , Control : : ANCHOR_END , - 8 * EDSCALE ) ;
2019-04-20 13:51:25 +02:00
add_child ( vbc ) ;
method = memnew ( Label ) ;
2021-11-25 03:58:47 +01:00
method - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
2019-04-20 13:51:25 +02:00
vbc - > add_child ( method ) ;
tree = memnew ( Tree ) ;
tree - > set_columns ( 3 ) ;
tree - > set_hide_root ( true ) ;
tree - > set_column_titles_visible ( true ) ;
tree - > set_column_title ( 0 , TTR ( " Source " ) ) ;
tree - > set_column_title ( 1 , TTR ( " Signal " ) ) ;
tree - > set_column_title ( 2 , TTR ( " Target " ) ) ;
vbc - > add_child ( tree ) ;
2020-03-06 18:00:16 +01:00
tree - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2019-04-20 13:51:25 +02:00
tree - > set_allow_rmb_select ( true ) ;
}
////////////////////////////////////////////////////////////////////////////////
2016-08-03 00:11:05 +02:00
Vector < String > ScriptTextEditor : : get_functions ( ) {
2020-07-24 16:50:35 +02:00
CodeEdit * te = code_editor - > get_text_editor ( ) ;
2016-08-03 00:11:05 +02:00
String text = te - > get_text ( ) ;
List < String > fnc ;
2021-05-18 05:09:19 +02:00
if ( script - > get_language ( ) - > validate ( text , script - > get_path ( ) , & fnc ) ) {
2016-08-03 00:11:05 +02:00
//if valid rewrite functions to latest
functions . clear ( ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : fnc ) {
2021-07-16 05:45:57 +02:00
functions . push_back ( E ) ;
2016-08-03 00:11:05 +02:00
}
}
return functions ;
}
void ScriptTextEditor : : apply_code ( ) {
2020-05-14 16:41:43 +02:00
if ( script . is_null ( ) ) {
2016-08-03 00:11:05 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2020-07-24 16:50:35 +02:00
script - > set_source_code ( code_editor - > get_text_editor ( ) - > get_text ( ) ) ;
2016-08-03 00:11:05 +02:00
script - > update_exports ( ) ;
2020-07-24 16:50:35 +02:00
code_editor - > get_text_editor ( ) - > get_syntax_highlighter ( ) - > update_cache ( ) ;
2016-08-03 00:11:05 +02:00
}
2022-05-03 01:43:50 +02:00
Ref < Resource > ScriptTextEditor : : get_edited_resource ( ) const {
2016-08-03 00:11:05 +02:00
return script ;
}
2022-05-03 01:43:50 +02:00
void ScriptTextEditor : : set_edited_resource ( const Ref < Resource > & p_res ) {
2019-11-20 10:09:59 +01:00
ERR_FAIL_COND ( script . is_valid ( ) ) ;
ERR_FAIL_COND ( p_res . is_null ( ) ) ;
2018-05-28 17:52:28 +02:00
script = p_res ;
2020-07-24 16:50:35 +02:00
code_editor - > get_text_editor ( ) - > set_text ( script - > get_source_code ( ) ) ;
code_editor - > get_text_editor ( ) - > clear_undo_history ( ) ;
code_editor - > get_text_editor ( ) - > tag_saved_version ( ) ;
2018-05-28 17:52:28 +02:00
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " name_changed " ) ) ;
2018-05-28 17:52:28 +02:00
code_editor - > update_line_and_column ( ) ;
2019-11-20 10:09:59 +01:00
}
2022-10-23 10:45:44 +02:00
void ScriptTextEditor : : enable_editor ( Control * p_shortcut_context ) {
2019-11-20 10:09:59 +01:00
if ( editor_enabled ) {
return ;
}
editor_enabled = true ;
_enable_code_editor ( ) ;
2019-04-16 02:14:58 +02:00
_validate_script ( ) ;
2022-10-23 10:45:44 +02:00
if ( p_shortcut_context ) {
for ( int i = 0 ; i < edit_hb - > get_child_count ( ) ; + + i ) {
Control * c = cast_to < Control > ( edit_hb - > get_child ( i ) ) ;
if ( c ) {
c - > set_shortcut_context ( p_shortcut_context ) ;
}
}
}
2018-05-28 17:52:28 +02:00
}
2016-08-03 00:11:05 +02:00
void ScriptTextEditor : : _load_theme_settings ( ) {
2020-07-24 16:50:35 +02:00
CodeEdit * text_edit = code_editor - > get_text_editor ( ) ;
2016-08-03 00:11:05 +02:00
2021-08-15 19:14:46 +02:00
Color updated_marked_line_color = EDITOR_GET ( " text_editor/theme/highlighting/mark_color " ) ;
Color updated_safe_line_number_color = EDITOR_GET ( " text_editor/theme/highlighting/safe_line_number_color " ) ;
2023-03-12 17:48:37 +01:00
Color updated_folded_code_region_color = EDITOR_GET ( " text_editor/theme/highlighting/folded_code_region_color " ) ;
2020-09-10 22:25:00 +02:00
bool safe_line_number_color_updated = updated_safe_line_number_color ! = safe_line_number_color ;
bool marked_line_color_updated = updated_marked_line_color ! = marked_line_color ;
2023-03-12 17:48:37 +01:00
bool folded_code_region_color_updated = updated_folded_code_region_color ! = folded_code_region_color ;
if ( safe_line_number_color_updated | | marked_line_color_updated | | folded_code_region_color_updated ) {
2020-07-30 12:41:05 +02:00
safe_line_number_color = updated_safe_line_number_color ;
for ( int i = 0 ; i < text_edit - > get_line_count ( ) ; i + + ) {
2020-09-10 22:25:00 +02:00
if ( marked_line_color_updated & & text_edit - > get_line_background_color ( i ) = = marked_line_color ) {
text_edit - > set_line_background_color ( i , updated_marked_line_color ) ;
}
if ( safe_line_number_color_updated & & text_edit - > get_line_gutter_item_color ( i , line_number_gutter ) ! = default_line_number_color ) {
2020-07-30 12:41:05 +02:00
text_edit - > set_line_gutter_item_color ( i , line_number_gutter , safe_line_number_color ) ;
}
2023-03-12 17:48:37 +01:00
if ( folded_code_region_color_updated & & text_edit - > get_line_background_color ( i ) = = folded_code_region_color ) {
text_edit - > set_line_background_color ( i , updated_folded_code_region_color ) ;
}
2020-07-30 12:41:05 +02:00
}
2020-09-10 22:25:00 +02:00
marked_line_color = updated_marked_line_color ;
2023-03-12 17:48:37 +01:00
folded_code_region_color = updated_folded_code_region_color ;
2020-07-30 12:41:05 +02:00
}
2017-10-03 01:33:42 +02:00
theme_loaded = true ;
2020-05-14 16:41:43 +02:00
if ( ! script . is_null ( ) ) {
2017-10-03 01:33:42 +02:00
_set_theme_for_script ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-10-03 01:33:42 +02:00
}
void ScriptTextEditor : : _set_theme_for_script ( ) {
2020-05-14 16:41:43 +02:00
if ( ! theme_loaded ) {
2017-10-03 01:33:42 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-10-03 01:33:42 +02:00
2020-07-24 16:50:35 +02:00
CodeEdit * text_edit = code_editor - > get_text_editor ( ) ;
2020-05-03 18:08:15 +02:00
text_edit - > get_syntax_highlighter ( ) - > update_cache ( ) ;
2017-10-03 01:33:42 +02:00
2020-09-10 22:25:40 +02:00
List < String > strings ;
script - > get_language ( ) - > get_string_delimiters ( & strings ) ;
text_edit - > clear_string_delimiters ( ) ;
2021-07-24 15:46:25 +02:00
for ( const String & string : strings ) {
2020-09-10 22:25:40 +02:00
String beg = string . get_slice ( " " , 0 ) ;
String end = string . get_slice_count ( " " ) > 1 ? string . get_slice ( " " , 1 ) : String ( ) ;
2021-07-01 18:40:59 +02:00
if ( ! text_edit - > has_string_delimiter ( beg ) ) {
2021-12-09 10:42:46 +01:00
text_edit - > add_string_delimiter ( beg , end , end . is_empty ( ) ) ;
2021-07-01 18:40:59 +02:00
}
2021-06-28 18:14:44 +02:00
if ( ! end . is_empty ( ) & & ! text_edit - > has_auto_brace_completion_open_key ( beg ) ) {
text_edit - > add_auto_brace_completion_pair ( beg , end ) ;
}
2020-09-10 22:25:40 +02:00
}
List < String > comments ;
script - > get_language ( ) - > get_comment_delimiters ( & comments ) ;
text_edit - > clear_comment_delimiters ( ) ;
2021-07-24 15:46:25 +02:00
for ( const String & comment : comments ) {
2020-09-10 22:25:40 +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
text_edit - > add_comment_delimiter ( beg , end , end . is_empty ( ) ) ;
2021-06-28 18:14:44 +02:00
if ( ! end . is_empty ( ) & & ! text_edit - > has_auto_brace_completion_open_key ( beg ) ) {
text_edit - > add_auto_brace_completion_pair ( beg , end ) ;
}
2020-09-10 22:25:40 +02:00
}
2016-08-03 00:11:05 +02:00
}
2021-05-18 05:09:19 +02:00
void ScriptTextEditor : : _show_errors_panel ( bool p_show ) {
errors_panel - > set_visible ( p_show ) ;
}
2019-02-13 10:12:31 +01:00
void ScriptTextEditor : : _show_warnings_panel ( bool p_show ) {
warnings_panel - > set_visible ( p_show ) ;
2018-07-01 18:17:40 +02:00
}
void ScriptTextEditor : : _warning_clicked ( Variant p_line ) {
if ( p_line . get_type ( ) = = Variant : : INT ) {
2021-05-12 12:45:30 +02:00
goto_line_centered ( p_line . operator int64_t ( ) ) ;
2022-04-26 05:13:24 +02:00
} else if ( p_line . get_type ( ) = = Variant : : DICTIONARY ) {
Dictionary meta = p_line . operator Dictionary ( ) ;
const int line = meta [ " line " ] . operator int64_t ( ) - 1 ;
2023-01-18 18:12:33 +01:00
const String code = meta [ " code " ] . operator String ( ) ;
const String quote_style = EDITOR_GET ( " text_editor/completion/use_single_quotes " ) ? " ' " : " \" " ;
2022-04-26 05:13:24 +02:00
CodeEdit * text_editor = code_editor - > get_text_editor ( ) ;
String prev_line = line > 0 ? text_editor - > get_line ( line - 1 ) : " " ;
if ( prev_line . contains ( " @warning_ignore " ) ) {
const int closing_bracket_idx = prev_line . find ( " ) " ) ;
2023-01-18 18:12:33 +01:00
const String text_to_insert = " , " + code . quote ( quote_style ) ;
2022-04-26 05:13:24 +02:00
prev_line = prev_line . insert ( closing_bracket_idx , text_to_insert ) ;
text_editor - > set_line ( line - 1 , prev_line ) ;
} else {
const int indent = text_editor - > get_indent_level ( line ) / text_editor - > get_indent_size ( ) ;
String annotation_indent ;
if ( ! text_editor - > is_indent_using_spaces ( ) ) {
annotation_indent = String ( " \t " ) . repeat ( indent ) ;
} else {
annotation_indent = String ( " " ) . repeat ( text_editor - > get_indent_size ( ) * indent ) ;
}
2023-01-18 18:12:33 +01:00
text_editor - > insert_line_at ( line , annotation_indent + " @warning_ignore( " + code . quote ( quote_style ) + " ) " ) ;
2022-04-26 05:13:24 +02:00
}
_validate_script ( ) ;
2018-07-01 18:17:40 +02:00
}
}
2021-05-18 05:09:19 +02:00
void ScriptTextEditor : : _error_clicked ( Variant p_line ) {
if ( p_line . get_type ( ) = = Variant : : INT ) {
2022-06-08 23:41:38 +02:00
code_editor - > get_text_editor ( ) - > remove_secondary_carets ( ) ;
2021-07-08 19:35:56 +02:00
code_editor - > get_text_editor ( ) - > set_caret_line ( p_line . operator int64_t ( ) ) ;
2023-07-24 15:49:39 +02:00
} else if ( p_line . get_type ( ) = = Variant : : DICTIONARY ) {
Dictionary meta = p_line . operator Dictionary ( ) ;
const String path = meta [ " path " ] . operator String ( ) ;
const int line = meta [ " line " ] . operator int64_t ( ) ;
const int column = meta [ " column " ] . operator int64_t ( ) ;
if ( path . is_empty ( ) ) {
code_editor - > get_text_editor ( ) - > remove_secondary_carets ( ) ;
code_editor - > get_text_editor ( ) - > set_caret_line ( line ) ;
} else {
Ref < Resource > scr = ResourceLoader : : load ( path ) ;
if ( ! scr . is_valid ( ) ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Could not load file at: " ) + " \n \n " + path , TTR ( " Error! " ) ) ;
} else {
ScriptEditor : : get_singleton ( ) - > edit ( scr , line , column ) ;
}
}
2021-05-18 05:09:19 +02:00
}
}
2016-08-03 00:11:05 +02:00
void ScriptTextEditor : : reload_text ( ) {
ERR_FAIL_COND ( script . is_null ( ) ) ;
2020-07-24 16:50:35 +02:00
CodeEdit * te = code_editor - > get_text_editor ( ) ;
2021-07-08 19:35:56 +02:00
int column = te - > get_caret_column ( ) ;
int row = te - > get_caret_line ( ) ;
2016-08-03 00:11:05 +02:00
int h = te - > get_h_scroll ( ) ;
int v = te - > get_v_scroll ( ) ;
te - > set_text ( script - > get_source_code ( ) ) ;
2021-07-08 19:35:56 +02:00
te - > set_caret_line ( row ) ;
te - > set_caret_column ( column ) ;
2016-08-03 00:11:05 +02:00
te - > set_h_scroll ( h ) ;
te - > set_v_scroll ( v ) ;
te - > tag_saved_version ( ) ;
code_editor - > update_line_and_column ( ) ;
2022-10-03 12:38:24 +02:00
_validate_script ( ) ;
2016-08-03 00:11:05 +02:00
}
2020-02-17 22:06:54 +01:00
void ScriptTextEditor : : add_callback ( const String & p_function , PackedStringArray p_args ) {
2020-07-24 16:50:35 +02:00
String code = code_editor - > get_text_editor ( ) - > get_text ( ) ;
2016-08-03 00:11:05 +02:00
int pos = script - > get_language ( ) - > find_function ( p_function , code ) ;
2022-06-08 23:41:38 +02:00
code_editor - > get_text_editor ( ) - > remove_secondary_carets ( ) ;
2016-08-03 00:11:05 +02:00
if ( pos = = - 1 ) {
//does not exist
2020-07-24 16:50:35 +02:00
code_editor - > get_text_editor ( ) - > deselect ( ) ;
pos = code_editor - > get_text_editor ( ) - > get_line_count ( ) + 2 ;
2016-08-03 00:11:05 +02:00
String func = script - > get_language ( ) - > make_function ( " " , p_function , p_args ) ;
//code=code+func;
2021-07-08 19:35:56 +02:00
code_editor - > get_text_editor ( ) - > set_caret_line ( pos + 1 ) ;
code_editor - > get_text_editor ( ) - > set_caret_column ( 1000000 ) ; //none shall be that big
code_editor - > get_text_editor ( ) - > insert_text_at_caret ( " \n \n " + func ) ;
2016-08-03 00:11:05 +02:00
}
2021-07-08 19:35:56 +02:00
code_editor - > get_text_editor ( ) - > set_caret_line ( pos ) ;
code_editor - > get_text_editor ( ) - > set_caret_column ( 1 ) ;
2016-08-03 00:11:05 +02:00
}
2017-05-28 16:20:38 +02:00
bool ScriptTextEditor : : show_members_overview ( ) {
return true ;
}
2016-08-03 00:11:05 +02:00
void ScriptTextEditor : : update_settings ( ) {
2022-10-18 16:43:37 +02:00
code_editor - > get_text_editor ( ) - > set_gutter_draw ( connection_gutter , EDITOR_GET ( " text_editor/appearance/gutters/show_info_gutter " ) ) ;
2016-10-10 10:38:12 +02:00
code_editor - > update_editor_settings ( ) ;
2016-08-03 00:11:05 +02:00
}
bool ScriptTextEditor : : is_unsaved ( ) {
2020-07-23 14:21:28 +02:00
const bool unsaved =
2020-07-24 16:50:35 +02:00
code_editor - > get_text_editor ( ) - > get_version ( ) ! = code_editor - > get_text_editor ( ) - > get_saved_version ( ) | |
2020-12-15 13:04:21 +01:00
script - > get_path ( ) . is_empty ( ) ; // In memory.
2020-07-23 14:21:28 +02:00
return unsaved ;
2016-08-03 00:11:05 +02:00
}
Variant ScriptTextEditor : : get_edit_state ( ) {
2018-05-26 00:49:35 +02:00
return code_editor - > get_edit_state ( ) ;
}
2016-08-03 00:11:05 +02:00
2018-05-26 00:49:35 +02:00
void ScriptTextEditor : : set_edit_state ( const Variant & p_state ) {
code_editor - > set_edit_state ( p_state ) ;
2019-04-13 13:43:35 +02:00
Dictionary state = p_state ;
if ( state . has ( " syntax_highlighter " ) ) {
int idx = highlighter_menu - > get_item_idx_from_text ( state [ " syntax_highlighter " ] ) ;
if ( idx > = 0 ) {
_change_syntax_highlighter ( idx ) ;
}
}
2019-11-20 10:09:59 +01:00
if ( editor_enabled ) {
2022-09-06 07:13:03 +02:00
# ifndef ANDROID_ENABLED
2019-11-20 10:09:59 +01:00
ensure_focus ( ) ;
2022-09-06 07:13:03 +02:00
# endif
2019-11-20 10:09:59 +01:00
}
2016-08-03 00:11:05 +02:00
}
2022-09-23 14:46:28 +02:00
Variant ScriptTextEditor : : get_navigation_state ( ) {
return code_editor - > get_navigation_state ( ) ;
}
2018-05-26 00:49:35 +02:00
void ScriptTextEditor : : _convert_case ( CodeTextEditor : : CaseStyle p_case ) {
code_editor - > convert_case ( p_case ) ;
2017-04-24 20:59:55 +02:00
}
2016-08-03 00:11:05 +02:00
void ScriptTextEditor : : trim_trailing_whitespace ( ) {
2018-05-26 00:49:35 +02:00
code_editor - > trim_trailing_whitespace ( ) ;
2016-08-03 00:11:05 +02:00
}
2019-05-28 23:27:32 +02:00
void ScriptTextEditor : : insert_final_newline ( ) {
code_editor - > insert_final_newline ( ) ;
}
2023-05-01 22:41:50 +02:00
void ScriptTextEditor : : convert_indent ( ) {
code_editor - > get_text_editor ( ) - > convert_indent ( ) ;
2017-04-16 17:47:59 +02:00
}
2016-08-03 00:11:05 +02:00
void ScriptTextEditor : : tag_saved_version ( ) {
2020-07-24 16:50:35 +02:00
code_editor - > get_text_editor ( ) - > tag_saved_version ( ) ;
2016-08-03 00:11:05 +02:00
}
2016-08-07 00:00:54 +02:00
void ScriptTextEditor : : goto_line ( int p_line , bool p_with_error ) {
2018-05-26 00:49:35 +02:00
code_editor - > goto_line ( p_line ) ;
2018-02-12 02:36:15 +01:00
}
2018-05-26 00:49:35 +02:00
void ScriptTextEditor : : goto_line_selection ( int p_line , int p_begin , int p_end ) {
code_editor - > goto_line_selection ( p_line , p_begin , p_end ) ;
2016-08-03 00:11:05 +02:00
}
2019-01-04 13:09:01 +01:00
void ScriptTextEditor : : goto_line_centered ( int p_line ) {
code_editor - > goto_line_centered ( p_line ) ;
}
2019-04-22 18:20:27 +02:00
void ScriptTextEditor : : set_executing_line ( int p_line ) {
code_editor - > set_executing_line ( p_line ) ;
}
void ScriptTextEditor : : clear_executing_line ( ) {
code_editor - > clear_executing_line ( ) ;
}
2018-05-26 00:49:35 +02:00
void ScriptTextEditor : : ensure_focus ( ) {
2020-07-24 16:50:35 +02:00
code_editor - > get_text_editor ( ) - > grab_focus ( ) ;
2016-08-03 00:11:05 +02:00
}
String ScriptTextEditor : : get_name ( ) {
String name ;
2021-11-06 02:15:19 +01:00
name = script - > get_path ( ) . get_file ( ) ;
if ( name . is_empty ( ) ) {
// This appears for newly created built-in scripts before saving the scene.
name = TTR ( " [unsaved] " ) ;
} else if ( script - > is_built_in ( ) ) {
const String & script_name = script - > get_name ( ) ;
2021-12-09 10:42:46 +01:00
if ( ! script_name . is_empty ( ) ) {
2021-11-06 02:15:19 +01:00
// If the built-in script has a custom resource name defined,
// display the built-in script name as follows: `ResourceName (scene_file.tscn)`
name = vformat ( " %s (%s) " , script_name , name . get_slice ( " :: " , 0 ) ) ;
2016-08-03 00:11:05 +02:00
}
2021-11-06 02:15:19 +01:00
}
if ( is_unsaved ( ) ) {
name + = " (*) " ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
return name ;
}
2020-03-12 13:37:40 +01:00
Ref < Texture2D > ScriptTextEditor : : get_theme_icon ( ) {
2021-12-02 13:01:49 +01:00
if ( get_parent_control ( ) ) {
String icon_name = script - > get_class ( ) ;
if ( script - > is_built_in ( ) ) {
icon_name + = " Internal " ;
}
2023-08-13 02:33:39 +02:00
if ( get_parent_control ( ) - > has_theme_icon ( icon_name , EditorStringName ( EditorIcons ) ) ) {
return get_parent_control ( ) - > get_editor_theme_icon ( icon_name ) ;
} else if ( get_parent_control ( ) - > has_theme_icon ( script - > get_class ( ) , EditorStringName ( EditorIcons ) ) ) {
return get_parent_control ( ) - > get_editor_theme_icon ( script - > get_class ( ) ) ;
2021-12-02 13:01:49 +01:00
}
2016-08-03 00:11:05 +02:00
}
2019-06-11 20:43:37 +02:00
return Ref < Texture2D > ( ) ;
2016-08-03 00:11:05 +02:00
}
void ScriptTextEditor : : _validate_script ( ) {
2020-07-24 16:50:35 +02:00
CodeEdit * te = code_editor - > get_text_editor ( ) ;
2016-08-03 00:11:05 +02:00
String text = te - > get_text ( ) ;
List < String > fnc ;
2022-01-19 06:31:39 +01:00
warnings . clear ( ) ;
errors . clear ( ) ;
2023-07-24 15:49:39 +02:00
depended_errors . clear ( ) ;
2022-01-19 06:31:39 +01:00
safe_lines . clear ( ) ;
2016-08-03 00:11:05 +02:00
2021-05-18 05:09:19 +02:00
if ( ! script - > get_language ( ) - > validate ( text , script - > get_path ( ) , & fnc , & errors , & warnings , & safe_lines ) ) {
2023-07-24 15:49:39 +02:00
for ( List < ScriptLanguage : : ScriptError > : : Element * E = errors . front ( ) ; E ; E = E - > next ( ) ) {
2023-08-30 11:43:16 +02:00
if ( ( E - > get ( ) . path . is_empty ( ) & & ! script - > get_path ( ) . is_empty ( ) ) | | E - > get ( ) . path ! = script - > get_path ( ) ) {
2023-07-24 15:49:39 +02:00
depended_errors [ E - > get ( ) . path ] . push_back ( E - > get ( ) ) ;
E - > erase ( ) ;
}
}
2023-08-30 11:43:16 +02:00
if ( errors . size ( ) > 0 ) {
// TRANSLATORS: Script error pointing to a line and column number.
String error_text = vformat ( TTR ( " Error at (%d, %d): " ) , errors [ 0 ] . line , errors [ 0 ] . column ) + " " + errors [ 0 ] . message ;
code_editor - > set_error ( error_text ) ;
code_editor - > set_error_pos ( errors [ 0 ] . line - 1 , errors [ 0 ] . column - 1 ) ;
}
2019-11-02 14:38:25 +01:00
script_is_valid = false ;
2016-08-03 00:11:05 +02:00
} else {
code_editor - > set_error ( " " ) ;
if ( ! script - > is_tool ( ) ) {
script - > set_source_code ( text ) ;
script - > update_exports ( ) ;
2020-05-03 18:08:15 +02:00
te - > get_syntax_highlighter ( ) - > update_cache ( ) ;
2016-08-03 00:11:05 +02:00
}
functions . clear ( ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : fnc ) {
2021-07-16 05:45:57 +02:00
functions . push_back ( E ) ;
2016-08-03 00:11:05 +02:00
}
2019-11-02 14:38:25 +01:00
script_is_valid = true ;
2016-08-03 00:11:05 +02:00
}
2019-04-20 13:51:25 +02:00
_update_connected_methods ( ) ;
2022-01-19 06:31:39 +01:00
_update_warnings ( ) ;
_update_errors ( ) ;
2016-08-03 00:11:05 +02:00
2022-01-19 06:31:39 +01:00
emit_signal ( SNAME ( " name_changed " ) ) ;
emit_signal ( SNAME ( " edited_script_changed " ) ) ;
}
void ScriptTextEditor : : _update_warnings ( ) {
2019-06-12 00:48:35 +02:00
int warning_nb = warnings . size ( ) ;
2018-07-01 18:17:40 +02:00
warnings_panel - > clear ( ) ;
2019-04-20 13:51:25 +02:00
2021-10-04 10:03:26 +02:00
bool has_connections_table = false ;
2019-06-12 00:48:35 +02:00
// Add missing connections.
if ( GLOBAL_GET ( " debug/gdscript/warnings/enable " ) . booleanize ( ) ) {
Node * base = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( base & & missing_connections . size ( ) > 0 ) {
2021-10-04 10:03:26 +02:00
has_connections_table = true ;
2019-06-12 00:48:35 +02:00
warnings_panel - > push_table ( 1 ) ;
2021-07-24 15:46:25 +02:00
for ( const Connection & connection : missing_connections ) {
2019-06-12 00:48:35 +02:00
String base_path = base - > get_name ( ) ;
2020-02-19 20:27:19 +01:00
String source_path = base = = connection . signal . get_object ( ) ? base_path : base_path + " / " + base - > get_path_to ( Object : : cast_to < Node > ( connection . signal . get_object ( ) ) ) ;
String target_path = base = = connection . callable . get_object ( ) ? base_path : base_path + " / " + base - > get_path_to ( Object : : cast_to < Node > ( connection . callable . get_object ( ) ) ) ;
2019-06-12 00:48:35 +02:00
warnings_panel - > push_cell ( ) ;
2023-08-13 02:33:39 +02:00
warnings_panel - > push_color ( warnings_panel - > get_theme_color ( SNAME ( " warning_color " ) , EditorStringName ( Editor ) ) ) ;
2020-02-19 20:27:19 +01:00
warnings_panel - > add_text ( vformat ( TTR ( " Missing connected method '%s' for signal '%s' from node '%s' to node '%s'. " ) , connection . callable . get_method ( ) , connection . signal . get_name ( ) , source_path , target_path ) ) ;
2019-06-12 00:48:35 +02:00
warnings_panel - > pop ( ) ; // Color.
warnings_panel - > pop ( ) ; // Cell.
}
warnings_panel - > pop ( ) ; // Table.
2019-04-20 13:51:25 +02:00
2019-06-12 00:48:35 +02:00
warning_nb + = missing_connections . size ( ) ;
2019-04-20 13:51:25 +02:00
}
}
2021-05-18 05:09:19 +02:00
code_editor - > set_warning_count ( warning_nb ) ;
2019-06-12 00:48:35 +02:00
2021-10-04 10:03:26 +02:00
if ( has_connections_table ) {
warnings_panel - > add_newline ( ) ;
}
2019-06-12 00:48:35 +02:00
// Add script warnings.
2022-04-26 05:13:24 +02:00
warnings_panel - > push_table ( 3 ) ;
2021-07-24 15:46:25 +02:00
for ( const ScriptLanguage : : Warning & w : warnings ) {
2022-04-26 05:13:24 +02:00
Dictionary ignore_meta ;
ignore_meta [ " line " ] = w . start_line ;
ignore_meta [ " code " ] = w . string_code . to_lower ( ) ;
warnings_panel - > push_cell ( ) ;
warnings_panel - > push_meta ( ignore_meta ) ;
warnings_panel - > push_color (
2023-08-13 02:33:39 +02:00
warnings_panel - > get_theme_color ( SNAME ( " accent_color " ) , EditorStringName ( Editor ) ) . lerp ( warnings_panel - > get_theme_color ( SNAME ( " mono_color " ) , EditorStringName ( Editor ) ) , 0.5f ) ) ;
2022-04-26 05:13:24 +02:00
warnings_panel - > add_text ( TTR ( " [Ignore] " ) ) ;
warnings_panel - > pop ( ) ; // Color.
warnings_panel - > pop ( ) ; // Meta ignore.
warnings_panel - > pop ( ) ; // Cell.
2018-07-01 18:17:40 +02:00
warnings_panel - > push_cell ( ) ;
2020-06-12 00:31:28 +02:00
warnings_panel - > push_meta ( w . start_line - 1 ) ;
2023-08-13 02:33:39 +02:00
warnings_panel - > push_color ( warnings_panel - > get_theme_color ( SNAME ( " warning_color " ) , EditorStringName ( Editor ) ) ) ;
2020-06-12 00:31:28 +02:00
warnings_panel - > add_text ( TTR ( " Line " ) + " " + itos ( w . start_line ) ) ;
2018-07-01 18:17:40 +02:00
warnings_panel - > add_text ( " ( " + w . string_code + " ): " ) ;
2019-06-12 00:48:35 +02:00
warnings_panel - > pop ( ) ; // Color.
warnings_panel - > pop ( ) ; // Meta goto.
warnings_panel - > pop ( ) ; // Cell.
2018-07-01 18:17:40 +02:00
warnings_panel - > push_cell ( ) ;
warnings_panel - > add_text ( w . message ) ;
2023-01-07 09:01:10 +01:00
warnings_panel - > add_newline ( ) ;
2019-06-12 00:48:35 +02:00
warnings_panel - > pop ( ) ; // Cell.
2018-07-01 18:17:40 +02:00
}
2019-06-12 00:48:35 +02:00
warnings_panel - > pop ( ) ; // Table.
2022-01-19 06:31:39 +01:00
}
void ScriptTextEditor : : _update_errors ( ) {
code_editor - > set_error_count ( errors . size ( ) ) ;
2018-07-01 18:17:40 +02:00
2021-05-18 05:09:19 +02:00
errors_panel - > clear ( ) ;
errors_panel - > push_table ( 2 ) ;
2021-07-24 15:46:25 +02:00
for ( const ScriptLanguage : : ScriptError & err : errors ) {
2023-07-24 15:49:39 +02:00
Dictionary click_meta ;
click_meta [ " line " ] = err . line ;
click_meta [ " column " ] = err . column ;
2021-05-18 05:09:19 +02:00
errors_panel - > push_cell ( ) ;
errors_panel - > push_meta ( err . line - 1 ) ;
2023-08-13 02:33:39 +02:00
errors_panel - > push_color ( warnings_panel - > get_theme_color ( SNAME ( " error_color " ) , EditorStringName ( Editor ) ) ) ;
2021-05-18 05:09:19 +02:00
errors_panel - > add_text ( TTR ( " Line " ) + " " + itos ( err . line ) + " : " ) ;
errors_panel - > pop ( ) ; // Color.
errors_panel - > pop ( ) ; // Meta goto.
errors_panel - > pop ( ) ; // Cell.
errors_panel - > push_cell ( ) ;
errors_panel - > add_text ( err . message ) ;
2023-01-07 09:01:10 +01:00
errors_panel - > add_newline ( ) ;
2021-05-18 05:09:19 +02:00
errors_panel - > pop ( ) ; // Cell.
}
errors_panel - > pop ( ) ; // Table
2023-07-24 15:49:39 +02:00
for ( const KeyValue < String , List < ScriptLanguage : : ScriptError > > & KV : depended_errors ) {
Dictionary click_meta ;
click_meta [ " path " ] = KV . key ;
click_meta [ " line " ] = 1 ;
errors_panel - > add_newline ( ) ;
errors_panel - > add_newline ( ) ;
errors_panel - > push_meta ( click_meta ) ;
errors_panel - > add_text ( vformat ( R " (%s:) " , KV . key ) ) ;
errors_panel - > pop ( ) ; // Meta goto.
errors_panel - > add_newline ( ) ;
errors_panel - > push_indent ( 1 ) ;
errors_panel - > push_table ( 2 ) ;
String filename = KV . key . get_file ( ) ;
for ( const ScriptLanguage : : ScriptError & err : KV . value ) {
click_meta [ " line " ] = err . line ;
click_meta [ " column " ] = err . column ;
errors_panel - > push_cell ( ) ;
errors_panel - > push_meta ( click_meta ) ;
2023-08-13 02:33:39 +02:00
errors_panel - > push_color ( errors_panel - > get_theme_color ( SNAME ( " error_color " ) , EditorStringName ( Editor ) ) ) ;
2023-07-24 15:49:39 +02:00
errors_panel - > add_text ( TTR ( " Line " ) + " " + itos ( err . line ) + " : " ) ;
errors_panel - > pop ( ) ; // Color.
errors_panel - > pop ( ) ; // Meta goto.
errors_panel - > pop ( ) ; // Cell.
errors_panel - > push_cell ( ) ;
errors_panel - > add_text ( err . message ) ;
errors_panel - > pop ( ) ; // Cell.
}
errors_panel - > pop ( ) ; // Table
errors_panel - > pop ( ) ; // Indent.
}
2022-01-19 06:31:39 +01:00
CodeEdit * te = code_editor - > get_text_editor ( ) ;
2022-03-06 21:39:19 +01:00
bool highlight_safe = EDITOR_GET ( " text_editor/appearance/gutters/highlight_type_safe_lines " ) ;
2018-06-05 18:50:21 +02:00
bool last_is_safe = false ;
2016-08-03 00:11:05 +02:00
for ( int i = 0 ; i < te - > get_line_count ( ) ; i + + ) {
2021-05-18 05:09:19 +02:00
if ( errors . is_empty ( ) ) {
2023-03-12 17:48:37 +01:00
bool is_folded_code_region = te - > is_line_code_region_start ( i ) & & te - > is_line_folded ( i ) ;
te - > set_line_background_color ( i , is_folded_code_region ? folded_code_region_color : Color ( 0 , 0 , 0 , 0 ) ) ;
2021-05-18 05:09:19 +02:00
} else {
2021-07-24 15:46:25 +02:00
for ( const ScriptLanguage : : ScriptError & E : errors ) {
2021-07-16 05:45:57 +02:00
bool error_line = i = = E . line - 1 ;
2021-05-18 05:09:19 +02:00
te - > set_line_background_color ( i , error_line ? marked_line_color : Color ( 0 , 0 , 0 , 0 ) ) ;
if ( error_line ) {
break ;
}
}
}
2018-06-05 18:50:21 +02:00
if ( highlight_safe ) {
if ( safe_lines . has ( i + 1 ) ) {
2020-07-30 12:41:05 +02:00
te - > set_line_gutter_item_color ( i , line_number_gutter , safe_line_number_color ) ;
2018-06-05 18:50:21 +02:00
last_is_safe = true ;
2021-06-15 16:05:01 +02:00
} else if ( last_is_safe & & ( te - > is_in_comment ( i ) ! = - 1 | | te - > get_line ( i ) . strip_edges ( ) . is_empty ( ) ) ) {
2020-07-30 12:41:05 +02:00
te - > set_line_gutter_item_color ( i , line_number_gutter , safe_line_number_color ) ;
2018-06-05 18:50:21 +02:00
} else {
2020-07-30 12:41:05 +02:00
te - > set_line_gutter_item_color ( i , line_number_gutter , default_line_number_color ) ;
2018-06-05 18:50:21 +02:00
last_is_safe = false ;
}
} else {
2021-05-18 05:09:19 +02:00
te - > set_line_gutter_item_color ( i , 1 , default_line_number_color ) ;
2018-06-05 18:50:21 +02:00
}
2016-08-03 00:11:05 +02:00
}
}
2019-05-21 10:07:48 +02:00
void ScriptTextEditor : : _update_bookmark_list ( ) {
2019-07-01 21:00:05 +02:00
bookmarks_menu - > clear ( ) ;
2021-11-20 09:04:57 +01:00
bookmarks_menu - > reset_size ( ) ;
2019-05-21 10:07:48 +02:00
2019-07-01 21:00:05 +02:00
bookmarks_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_bookmark " ) , BOOKMARK_TOGGLE ) ;
bookmarks_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/remove_all_bookmarks " ) , BOOKMARK_REMOVE_ALL ) ;
bookmarks_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/goto_next_bookmark " ) , BOOKMARK_GOTO_NEXT ) ;
bookmarks_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/goto_previous_bookmark " ) , BOOKMARK_GOTO_PREV ) ;
2019-05-21 10:07:48 +02:00
2022-08-05 03:41:48 +02:00
PackedInt32Array bookmark_list = code_editor - > get_text_editor ( ) - > get_bookmarked_lines ( ) ;
2019-05-21 10:07:48 +02:00
if ( bookmark_list . size ( ) = = 0 ) {
return ;
}
2019-07-01 21:00:05 +02:00
bookmarks_menu - > add_separator ( ) ;
2019-05-21 10:07:48 +02:00
for ( int i = 0 ; i < bookmark_list . size ( ) ; i + + ) {
2019-12-03 17:19:57 +01:00
// Strip edges to remove spaces or tabs.
// Also replace any tabs by spaces, since we can't print tabs in the menu.
2020-07-24 16:50:35 +02:00
String line = code_editor - > get_text_editor ( ) - > get_line ( bookmark_list [ i ] ) . replace ( " \t " , " " ) . strip_edges ( ) ;
2019-12-03 17:19:57 +01:00
2019-05-21 10:07:48 +02:00
// Limit the size of the line if too big.
if ( line . length ( ) > 50 ) {
line = line . substr ( 0 , 50 ) ;
}
2019-12-03 17:19:57 +01:00
bookmarks_menu - > add_item ( String : : num ( ( int ) bookmark_list [ i ] + 1 ) + " - ` " + line + " ` " ) ;
2022-03-12 01:06:45 +01:00
bookmarks_menu - > set_item_metadata ( - 1 , bookmark_list [ i ] ) ;
2019-05-21 10:07:48 +02:00
}
}
void ScriptTextEditor : : _bookmark_item_pressed ( int p_idx ) {
if ( p_idx < 4 ) { // Any item before the separator.
2019-07-01 21:00:05 +02:00
_edit_option ( bookmarks_menu - > get_item_id ( p_idx ) ) ;
2019-05-21 10:07:48 +02:00
} else {
2021-03-24 17:29:14 +01:00
code_editor - > goto_line_centered ( bookmarks_menu - > get_item_metadata ( p_idx ) ) ;
2019-05-21 10:07:48 +02:00
}
}
2019-04-20 13:51:25 +02:00
static Vector < Node * > _find_all_node_for_script ( Node * p_base , Node * p_current , const Ref < Script > & p_script ) {
Vector < Node * > nodes ;
if ( p_current - > get_owner ( ) ! = p_base & & p_base ! = p_current ) {
return nodes ;
}
Ref < Script > c = p_current - > get_script ( ) ;
if ( c = = p_script ) {
nodes . push_back ( p_current ) ;
}
for ( int i = 0 ; i < p_current - > get_child_count ( ) ; i + + ) {
Vector < Node * > found = _find_all_node_for_script ( p_base , p_current - > get_child ( i ) , p_script ) ;
nodes . append_array ( found ) ;
}
return nodes ;
}
2016-08-03 00:11:05 +02:00
static Node * _find_node_for_script ( Node * p_base , Node * p_current , const Ref < Script > & p_script ) {
2020-05-14 16:41:43 +02:00
if ( p_current - > get_owner ( ) ! = p_base & & p_base ! = p_current ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
Ref < Script > c = p_current - > get_script ( ) ;
2020-05-14 16:41:43 +02:00
if ( c = = p_script ) {
2016-08-03 00:11:05 +02:00
return p_current ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
for ( int i = 0 ; i < p_current - > get_child_count ( ) ; i + + ) {
Node * found = _find_node_for_script ( p_base , p_current - > get_child ( i ) , p_script ) ;
2020-05-14 16:41:43 +02:00
if ( found ) {
2016-08-03 00:11:05 +02:00
return found ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
}
2020-04-02 01:20:12 +02:00
return nullptr ;
2016-08-03 00:11:05 +02:00
}
2022-05-19 17:00:06 +02:00
static void _find_changed_scripts_for_external_editor ( Node * p_base , Node * p_current , HashSet < Ref < Script > > & r_scripts ) {
2020-05-14 16:41:43 +02:00
if ( p_current - > get_owner ( ) ! = p_base & & p_base ! = p_current ) {
2016-08-03 00:11:05 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
Ref < Script > c = p_current - > get_script ( ) ;
2020-05-14 16:41:43 +02:00
if ( c . is_valid ( ) ) {
2016-08-03 00:11:05 +02:00
r_scripts . insert ( c ) ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
for ( int i = 0 ; i < p_current - > get_child_count ( ) ; i + + ) {
_find_changed_scripts_for_external_editor ( p_base , p_current - > get_child ( i ) , r_scripts ) ;
}
}
void ScriptEditor : : _update_modified_scripts_for_external_editor ( Ref < Script > p_for_script ) {
2022-10-18 16:43:37 +02:00
if ( ! bool ( EDITOR_GET ( " text_editor/external/use_external_editor " ) ) ) {
2016-08-03 00:11:05 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
2017-06-25 11:20:01 +02:00
ERR_FAIL_COND ( ! get_tree ( ) ) ;
2022-05-19 17:00:06 +02:00
HashSet < Ref < Script > > scripts ;
2016-08-03 00:11:05 +02:00
Node * base = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( base ) {
_find_changed_scripts_for_external_editor ( base , base , scripts ) ;
}
2022-05-19 01:43:40 +02:00
for ( const Ref < Script > & E : scripts ) {
2022-09-29 11:53:28 +02:00
Ref < Script > scr = E ;
2016-08-03 00:11:05 +02:00
2022-09-29 11:53:28 +02:00
if ( p_for_script . is_valid ( ) & & p_for_script ! = scr ) {
2016-08-03 00:11:05 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
2022-09-29 11:53:28 +02:00
if ( scr - > is_built_in ( ) ) {
2016-08-03 00:11:05 +02:00
continue ; //internal script, who cares, though weird
}
2022-09-29 11:53:28 +02:00
uint64_t last_date = scr - > get_last_modified_time ( ) ;
uint64_t date = FileAccess : : get_modified_time ( scr - > get_path ( ) ) ;
2016-08-03 00:11:05 +02:00
if ( last_date ! = date ) {
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 - > update_exports ( ) ;
2021-08-17 10:32:23 +02:00
_trigger_live_script_reload ( ) ;
2016-08-03 00:11:05 +02:00
}
}
}
2022-03-26 16:48:43 +01:00
void ScriptTextEditor : : _code_complete_scripts ( void * p_ud , const String & p_code , List < ScriptLanguage : : CodeCompletionOption > * r_options , bool & r_force ) {
2016-08-03 00:11:05 +02:00
ScriptTextEditor * ste = ( ScriptTextEditor * ) p_ud ;
2017-08-24 05:06:56 +02:00
ste - > _code_complete_script ( p_code , r_options , r_force ) ;
2016-08-03 00:11:05 +02:00
}
2022-03-26 16:48:43 +01:00
void ScriptTextEditor : : _code_complete_script ( const String & p_code , List < ScriptLanguage : : CodeCompletionOption > * r_options , bool & r_force ) {
2020-05-14 16:41:43 +02:00
if ( color_panel - > is_visible ( ) ) {
2020-03-12 13:37:40 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
Node * base = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( base ) {
base = _find_node_for_script ( base , base , script ) ;
}
String hint ;
2019-04-16 22:27:13 +02:00
Error err = script - > get_language ( ) - > complete_code ( p_code , script - > get_path ( ) , base , r_options , r_force , hint ) ;
2022-03-08 15:03:36 +01:00
2019-10-02 11:21:48 +02:00
if ( err = = OK ) {
2020-07-24 16:50:35 +02:00
code_editor - > get_text_editor ( ) - > set_code_hint ( hint ) ;
2016-08-03 00:11:05 +02:00
}
}
2019-07-01 21:00:05 +02:00
void ScriptTextEditor : : _update_breakpoint_list ( ) {
breakpoints_menu - > clear ( ) ;
2021-11-20 09:04:57 +01:00
breakpoints_menu - > reset_size ( ) ;
2019-07-01 21:00:05 +02:00
breakpoints_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_breakpoint " ) , DEBUG_TOGGLE_BREAKPOINT ) ;
breakpoints_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/remove_all_breakpoints " ) , DEBUG_REMOVE_ALL_BREAKPOINTS ) ;
breakpoints_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/goto_next_breakpoint " ) , DEBUG_GOTO_NEXT_BREAKPOINT ) ;
breakpoints_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/goto_previous_breakpoint " ) , DEBUG_GOTO_PREV_BREAKPOINT ) ;
2022-08-05 03:41:48 +02:00
PackedInt32Array breakpoint_list = code_editor - > get_text_editor ( ) - > get_breakpointed_lines ( ) ;
2019-07-01 21:00:05 +02:00
if ( breakpoint_list . size ( ) = = 0 ) {
return ;
}
breakpoints_menu - > add_separator ( ) ;
for ( int i = 0 ; i < breakpoint_list . size ( ) ; i + + ) {
2019-12-03 17:19:57 +01:00
// Strip edges to remove spaces or tabs.
// Also replace any tabs by spaces, since we can't print tabs in the menu.
2020-07-24 16:50:35 +02:00
String line = code_editor - > get_text_editor ( ) - > get_line ( breakpoint_list [ i ] ) . replace ( " \t " , " " ) . strip_edges ( ) ;
2019-12-03 17:19:57 +01:00
2019-07-01 21:00:05 +02:00
// Limit the size of the line if too big.
if ( line . length ( ) > 50 ) {
line = line . substr ( 0 , 50 ) ;
}
2019-12-03 17:19:57 +01:00
breakpoints_menu - > add_item ( String : : num ( ( int ) breakpoint_list [ i ] + 1 ) + " - ` " + line + " ` " ) ;
2022-03-12 01:06:45 +01:00
breakpoints_menu - > set_item_metadata ( - 1 , breakpoint_list [ i ] ) ;
2019-07-01 21:00:05 +02:00
}
}
void ScriptTextEditor : : _breakpoint_item_pressed ( int p_idx ) {
if ( p_idx < 4 ) { // Any item before the separator.
_edit_option ( breakpoints_menu - > get_item_id ( p_idx ) ) ;
} else {
code_editor - > goto_line ( breakpoints_menu - > get_item_metadata ( p_idx ) ) ;
2021-07-08 19:35:56 +02:00
code_editor - > get_text_editor ( ) - > call_deferred ( SNAME ( " center_viewport_to_caret " ) ) ; //Need to be deferred, because goto uses call_deferred().
2019-07-01 21:00:05 +02:00
}
}
2016-08-03 00:11:05 +02:00
void ScriptTextEditor : : _breakpoint_toggled ( int p_row ) {
2020-07-26 16:57:23 +02:00
EditorDebuggerNode : : get_singleton ( ) - > set_breakpoint ( script - > get_path ( ) , p_row + 1 , code_editor - > get_text_editor ( ) - > is_line_breakpointed ( p_row ) ) ;
2016-08-03 00:11:05 +02:00
}
2016-09-12 15:52:29 +02:00
void ScriptTextEditor : : _lookup_symbol ( const String & p_symbol , int p_row , int p_column ) {
Node * base = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( base ) {
base = _find_node_for_script ( base , base , script ) ;
}
ScriptLanguage : : LookupResult result ;
2023-02-13 05:33:10 +01:00
String code_text = code_editor - > get_text_editor ( ) - > get_text_with_cursor_char ( p_row , p_column ) ;
Error lc_error = script - > get_language ( ) - > lookup_code ( code_text , p_symbol , script - > get_path ( ) , base , result ) ;
2019-03-11 16:25:54 +01:00
if ( ScriptServer : : is_global_class ( p_symbol ) ) {
EditorNode : : get_singleton ( ) - > load_resource ( ScriptServer : : get_global_class_path ( p_symbol ) ) ;
2023-09-19 15:23:28 +02:00
} else if ( p_symbol . is_resource_file ( ) | | p_symbol . begins_with ( " uid:// " ) ) {
String symbol = p_symbol ;
if ( symbol . begins_with ( " uid:// " ) ) {
symbol = ResourceUID : : get_singleton ( ) - > get_id_path ( ResourceUID : : get_singleton ( ) - > text_to_id ( symbol ) ) ;
}
2017-08-02 19:20:27 +02:00
List < String > scene_extensions ;
ResourceLoader : : get_recognized_extensions_for_type ( " PackedScene " , & scene_extensions ) ;
2023-09-19 15:23:28 +02:00
if ( scene_extensions . find ( symbol . get_extension ( ) ) ) {
EditorNode : : get_singleton ( ) - > load_scene ( symbol ) ;
2017-08-02 19:20:27 +02:00
} else {
2023-09-19 15:23:28 +02:00
EditorNode : : get_singleton ( ) - > load_resource ( symbol ) ;
2017-08-02 19:20:27 +02:00
}
2023-02-13 05:33:10 +01:00
} else if ( lc_error = = OK ) {
2016-09-12 15:52:29 +02:00
_goto_line ( p_row ) ;
switch ( result . type ) {
2022-03-26 16:48:43 +01:00
case ScriptLanguage : : LOOKUP_RESULT_SCRIPT_LOCATION : {
2016-09-12 15:52:29 +02:00
if ( result . script . is_valid ( ) ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " request_open_script_at_line " ) , result . script , result . location - 1 ) ;
2016-09-12 15:52:29 +02:00
} else {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " request_save_history " ) ) ;
2021-03-24 17:29:14 +01:00
goto_line_centered ( result . location - 1 ) ;
2016-09-12 15:52:29 +02:00
}
} break ;
2022-03-26 16:48:43 +01:00
case ScriptLanguage : : LOOKUP_RESULT_CLASS : {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " go_to_help " ) , " class_name: " + result . class_name ) ;
2016-09-12 15:52:29 +02:00
} break ;
2022-03-26 16:48:43 +01:00
case ScriptLanguage : : LOOKUP_RESULT_CLASS_CONSTANT : {
2016-09-12 15:52:29 +02:00
StringName cname = result . class_name ;
bool success ;
while ( true ) {
2017-01-03 03:03:46 +01:00
ClassDB : : get_integer_constant ( cname , result . class_member , & success ) ;
2016-09-12 15:52:29 +02:00
if ( success ) {
result . class_name = cname ;
2017-01-03 03:03:46 +01:00
cname = ClassDB : : get_parent_class ( cname ) ;
2016-09-12 15:52:29 +02:00
} else {
break ;
}
}
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " go_to_help " ) , " class_constant: " + result . class_name + " : " + result . class_member ) ;
2016-09-12 15:52:29 +02:00
} break ;
2022-03-26 16:48:43 +01:00
case ScriptLanguage : : LOOKUP_RESULT_CLASS_PROPERTY : {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " go_to_help " ) , " class_property: " + result . class_name + " : " + result . class_member ) ;
2016-09-12 15:52:29 +02:00
} break ;
2022-03-26 16:48:43 +01:00
case ScriptLanguage : : LOOKUP_RESULT_CLASS_METHOD : {
2016-09-12 15:52:29 +02:00
StringName cname = result . class_name ;
while ( true ) {
2017-01-03 03:03:46 +01:00
if ( ClassDB : : has_method ( cname , result . class_member ) ) {
2016-09-12 15:52:29 +02:00
result . class_name = cname ;
2017-01-03 03:03:46 +01:00
cname = ClassDB : : get_parent_class ( cname ) ;
2016-09-12 15:52:29 +02:00
} else {
break ;
}
}
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " go_to_help " ) , " class_method: " + result . class_name + " : " + result . class_member ) ;
2016-09-12 15:52:29 +02:00
2022-05-12 15:07:05 +02:00
} break ;
case ScriptLanguage : : LOOKUP_RESULT_CLASS_SIGNAL : {
StringName cname = result . class_name ;
while ( true ) {
if ( ClassDB : : has_signal ( cname , result . class_member ) ) {
result . class_name = cname ;
cname = ClassDB : : get_parent_class ( cname ) ;
} else {
break ;
}
}
emit_signal ( SNAME ( " go_to_help " ) , " class_signal: " + result . class_name + " : " + result . class_member ) ;
2016-09-12 15:52:29 +02:00
} break ;
2022-03-26 16:48:43 +01:00
case ScriptLanguage : : LOOKUP_RESULT_CLASS_ENUM : {
2018-03-30 16:20:24 +02:00
StringName cname = result . class_name ;
StringName success ;
while ( true ) {
success = ClassDB : : get_integer_constant_enum ( cname , result . class_member , true ) ;
if ( success ! = StringName ( ) ) {
result . class_name = cname ;
cname = ClassDB : : get_parent_class ( cname ) ;
} else {
break ;
}
}
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " go_to_help " ) , " class_enum: " + result . class_name + " : " + result . class_member ) ;
2018-03-30 16:20:24 +02:00
} break ;
2022-07-04 17:56:34 +02:00
case ScriptLanguage : : LOOKUP_RESULT_CLASS_ANNOTATION : {
emit_signal ( SNAME ( " go_to_help " ) , " class_annotation: " + result . class_name + " : " + result . class_member ) ;
} break ;
2022-03-26 16:48:43 +01:00
case ScriptLanguage : : LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE : {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " go_to_help " ) , " class_global: " + result . class_name + " : " + result . class_member ) ;
2018-03-30 16:20:24 +02:00
} break ;
2022-03-26 16:48:43 +01:00
default : {
}
2016-09-12 15:52:29 +02:00
}
2020-06-18 01:45:08 +02:00
} else if ( ProjectSettings : : get_singleton ( ) - > has_autoload ( p_symbol ) ) {
// Check for Autoload scenes.
const ProjectSettings : : AutoloadInfo & info = ProjectSettings : : get_singleton ( ) - > get_autoload ( p_symbol ) ;
if ( info . is_singleton ) {
EditorNode : : get_singleton ( ) - > load_scene ( info . path ) ;
2020-03-28 09:12:19 +01:00
}
2021-08-30 01:43:47 +02:00
} else if ( p_symbol . is_relative_path ( ) ) {
2020-03-28 09:12:19 +01:00
// Every symbol other than absolute path is relative path so keep this condition at last.
String path = _get_absolute_path ( p_symbol ) ;
if ( FileAccess : : exists ( path ) ) {
List < String > scene_extensions ;
ResourceLoader : : get_recognized_extensions_for_type ( " PackedScene " , & scene_extensions ) ;
if ( scene_extensions . find ( path . get_extension ( ) ) ) {
EditorNode : : get_singleton ( ) - > load_scene ( path ) ;
} else {
EditorNode : : get_singleton ( ) - > load_resource ( path ) ;
}
}
2016-09-12 15:52:29 +02:00
}
}
2016-08-03 00:11:05 +02:00
2020-03-01 09:13:41 +01:00
void ScriptTextEditor : : _validate_symbol ( const String & p_symbol ) {
2020-07-24 16:50:35 +02:00
CodeEdit * text_edit = code_editor - > get_text_editor ( ) ;
2020-03-01 09:13:41 +01:00
Node * base = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( base ) {
base = _find_node_for_script ( base , base , script ) ;
}
ScriptLanguage : : LookupResult result ;
2023-02-13 05:33:10 +01:00
String lc_text = code_editor - > get_text_editor ( ) - > get_text_for_symbol_lookup ( ) ;
Error lc_error = script - > get_language ( ) - > lookup_code ( lc_text , p_symbol , script - > get_path ( ) , base , result ) ;
bool is_singleton = ProjectSettings : : get_singleton ( ) - > has_autoload ( p_symbol ) & & ProjectSettings : : get_singleton ( ) - > get_autoload ( p_symbol ) . is_singleton ;
2023-09-19 15:23:28 +02:00
if ( lc_error = = OK | | is_singleton | | ScriptServer : : is_global_class ( p_symbol ) | | p_symbol . is_resource_file ( ) | | p_symbol . begins_with ( " uid:// " ) ) {
2021-07-01 18:10:54 +02:00
text_edit - > set_symbol_lookup_word_as_valid ( true ) ;
2021-08-30 01:43:47 +02:00
} else if ( p_symbol . is_relative_path ( ) ) {
2020-03-28 09:12:19 +01:00
String path = _get_absolute_path ( p_symbol ) ;
if ( FileAccess : : exists ( path ) ) {
2021-07-01 18:10:54 +02:00
text_edit - > set_symbol_lookup_word_as_valid ( true ) ;
2020-03-28 09:12:19 +01:00
} else {
2021-07-01 18:10:54 +02:00
text_edit - > set_symbol_lookup_word_as_valid ( false ) ;
2020-03-28 09:12:19 +01:00
}
2020-03-01 09:13:41 +01:00
} else {
2021-07-01 18:10:54 +02:00
text_edit - > set_symbol_lookup_word_as_valid ( false ) ;
2020-03-01 09:13:41 +01:00
}
}
2020-03-28 09:12:19 +01:00
String ScriptTextEditor : : _get_absolute_path ( const String & rel_path ) {
String base_path = script - > get_path ( ) . get_base_dir ( ) ;
2022-08-30 02:34:01 +02:00
String path = base_path . path_join ( rel_path ) ;
2020-03-28 09:12:19 +01:00
return path . replace ( " /// " , " // " ) . simplify_path ( ) ;
}
2019-12-18 20:32:25 +01:00
void ScriptTextEditor : : update_toggle_scripts_button ( ) {
2021-09-14 11:17:47 +02:00
code_editor - > update_toggle_scripts_button ( ) ;
2019-12-18 20:32:25 +01:00
}
2019-04-20 13:51:25 +02:00
void ScriptTextEditor : : _update_connected_methods ( ) {
2020-07-24 16:50:35 +02:00
CodeEdit * text_edit = code_editor - > get_text_editor ( ) ;
2021-07-10 12:41:38 +02:00
text_edit - > set_gutter_width ( connection_gutter , text_edit - > get_line_height ( ) ) ;
2020-07-29 23:26:49 +02:00
for ( int i = 0 ; i < text_edit - > get_line_count ( ) ; i + + ) {
2022-09-09 16:36:07 +02:00
text_edit - > set_line_gutter_metadata ( i , connection_gutter , Dictionary ( ) ) ;
2020-07-29 23:26:49 +02:00
text_edit - > set_line_gutter_icon ( i , connection_gutter , nullptr ) ;
text_edit - > set_line_gutter_clickable ( i , connection_gutter , false ) ;
}
2019-04-20 13:51:25 +02:00
missing_connections . clear ( ) ;
2019-11-02 14:38:25 +01:00
if ( ! script_is_valid ) {
2019-10-27 12:07:19 +01:00
return ;
}
2019-04-20 13:51:25 +02:00
Node * base = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( ! base ) {
return ;
}
2022-09-09 16:36:07 +02:00
// Add connection icons to methods.
2019-04-20 13:51:25 +02:00
Vector < Node * > nodes = _find_all_node_for_script ( base , base , script ) ;
2022-05-19 17:00:06 +02:00
HashSet < StringName > methods_found ;
2019-04-20 13:51:25 +02:00
for ( int i = 0 ; i < nodes . size ( ) ; i + + ) {
2022-09-29 11:53:28 +02:00
List < Connection > signal_connections ;
nodes [ i ] - > get_signals_connected_to_this ( & signal_connections ) ;
2019-04-20 13:51:25 +02:00
2022-09-29 11:53:28 +02:00
for ( const Connection & connection : signal_connections ) {
2019-04-20 13:51:25 +02:00
if ( ! ( connection . flags & CONNECT_PERSIST ) ) {
continue ;
}
2019-06-11 00:35:22 +02:00
// As deleted nodes are still accessible via the undo/redo system, check if they're still on the tree.
2020-02-19 20:27:19 +01:00
Node * source = Object : : cast_to < Node > ( connection . signal . get_object ( ) ) ;
2019-06-11 00:35:22 +02:00
if ( source & & ! source - > is_inside_tree ( ) ) {
continue ;
}
2022-02-06 19:02:53 +01:00
const StringName method = connection . callable . get_method ( ) ;
if ( methods_found . has ( method ) ) {
2019-10-27 12:07:19 +01:00
continue ;
}
2022-02-06 19:02:53 +01:00
if ( ! ClassDB : : has_method ( script - > get_instance_base_type ( ) , method ) ) {
2019-10-27 12:07:19 +01:00
int line = - 1 ;
2019-11-02 14:38:25 +01:00
for ( int j = 0 ; j < functions . size ( ) ; j + + ) {
String name = functions [ j ] . get_slice ( " : " , 0 ) ;
2022-02-06 19:02:53 +01:00
if ( name = = method ) {
2022-09-09 16:36:07 +02:00
Dictionary line_meta ;
line_meta [ " type " ] = " connection " ;
line_meta [ " method " ] = method ;
2020-07-29 23:26:49 +02:00
line = functions [ j ] . get_slice ( " : " , 1 ) . to_int ( ) - 1 ;
2022-09-09 16:36:07 +02:00
text_edit - > set_line_gutter_metadata ( line , connection_gutter , line_meta ) ;
2023-08-13 02:33:39 +02:00
text_edit - > set_line_gutter_icon ( line , connection_gutter , get_parent_control ( ) - > get_editor_theme_icon ( SNAME ( " Slot " ) ) ) ;
2020-07-29 23:26:49 +02:00
text_edit - > set_line_gutter_clickable ( line , connection_gutter , true ) ;
2022-02-06 19:02:53 +01:00
methods_found . insert ( method ) ;
2019-11-02 14:38:25 +01:00
break ;
}
}
if ( line > = 0 ) {
2019-10-27 12:07:19 +01:00
continue ;
}
2019-06-13 17:15:13 +02:00
2019-10-27 12:07:19 +01:00
// There is a chance that the method is inherited from another script.
bool found_inherited_function = false ;
Ref < Script > inherited_script = script - > get_base_script ( ) ;
while ( ! inherited_script . is_null ( ) ) {
2022-02-06 19:02:53 +01:00
if ( inherited_script - > has_method ( method ) ) {
2019-10-27 12:07:19 +01:00
found_inherited_function = true ;
break ;
2019-06-12 00:48:35 +02:00
}
2019-10-27 12:07:19 +01:00
inherited_script = inherited_script - > get_base_script ( ) ;
}
if ( ! found_inherited_function ) {
missing_connections . push_back ( connection ) ;
2019-06-12 00:48:35 +02:00
}
2019-04-20 13:51:25 +02:00
}
}
}
2022-09-09 16:36:07 +02:00
// Add override icons to methods.
methods_found . clear ( ) ;
for ( int i = 0 ; i < functions . size ( ) ; i + + ) {
StringName name = StringName ( functions [ i ] . get_slice ( " : " , 0 ) ) ;
if ( methods_found . has ( name ) ) {
continue ;
}
String found_base_class ;
StringName base_class = script - > get_instance_base_type ( ) ;
Ref < Script > inherited_script = script - > get_base_script ( ) ;
while ( ! inherited_script . is_null ( ) ) {
if ( inherited_script - > has_method ( name ) ) {
found_base_class = " script: " + inherited_script - > get_path ( ) ;
break ;
}
base_class = inherited_script - > get_instance_base_type ( ) ;
inherited_script = inherited_script - > get_base_script ( ) ;
}
2022-09-30 02:11:52 +02:00
if ( found_base_class . is_empty ( ) ) {
while ( base_class ) {
List < MethodInfo > methods ;
ClassDB : : get_method_list ( base_class , & methods , true ) ;
for ( int j = 0 ; j < methods . size ( ) ; j + + ) {
if ( methods [ j ] . name = = name ) {
found_base_class = " builtin: " + base_class ;
break ;
}
}
ClassDB : : ClassInfo * base_class_ptr = ClassDB : : classes . getptr ( base_class ) - > inherits_ptr ;
if ( base_class_ptr = = nullptr ) {
2022-09-09 16:36:07 +02:00
break ;
}
2022-09-30 02:11:52 +02:00
base_class = base_class_ptr - > name ;
2022-09-09 16:36:07 +02:00
}
}
if ( ! found_base_class . is_empty ( ) ) {
int line = functions [ i ] . get_slice ( " : " , 1 ) . to_int ( ) - 1 ;
Dictionary line_meta = text_edit - > get_line_gutter_metadata ( line , connection_gutter ) ;
if ( line_meta . is_empty ( ) ) {
// Add override icon to gutter.
line_meta [ " type " ] = " inherits " ;
line_meta [ " method " ] = name ;
line_meta [ " base_class " ] = found_base_class ;
2023-08-13 02:33:39 +02:00
text_edit - > set_line_gutter_icon ( line , connection_gutter , get_parent_control ( ) - > get_editor_theme_icon ( SNAME ( " MethodOverride " ) ) ) ;
2022-09-09 16:36:07 +02:00
text_edit - > set_line_gutter_clickable ( line , connection_gutter , true ) ;
} else {
// If method is also connected to signal, then merge icons and keep the click behavior of the slot.
2023-08-13 02:33:39 +02:00
text_edit - > set_line_gutter_icon ( line , connection_gutter , get_parent_control ( ) - > get_editor_theme_icon ( SNAME ( " MethodOverrideAndSlot " ) ) ) ;
2022-09-09 16:36:07 +02:00
}
methods_found . insert ( name ) ;
}
}
2019-04-20 13:51:25 +02:00
}
2020-07-29 23:26:49 +02:00
void ScriptTextEditor : : _update_gutter_indexes ( ) {
for ( int i = 0 ; i < code_editor - > get_text_editor ( ) - > get_gutter_count ( ) ; i + + ) {
if ( code_editor - > get_text_editor ( ) - > get_gutter_name ( i ) = = " connection_gutter " ) {
connection_gutter = i ;
2020-07-30 12:41:05 +02:00
continue ;
}
if ( code_editor - > get_text_editor ( ) - > get_gutter_name ( i ) = = " line_numbers " ) {
line_number_gutter = i ;
continue ;
2020-07-29 23:26:49 +02:00
}
}
}
void ScriptTextEditor : : _gutter_clicked ( int p_line , int p_gutter ) {
if ( p_gutter ! = connection_gutter ) {
return ;
}
2022-09-09 16:36:07 +02:00
Dictionary meta = code_editor - > get_text_editor ( ) - > get_line_gutter_metadata ( p_line , p_gutter ) ;
String type = meta . get ( " type " , " " ) ;
if ( type . is_empty ( ) ) {
2020-07-29 23:26:49 +02:00
return ;
}
2022-09-09 16:36:07 +02:00
// All types currently need a method name.
String method = meta . get ( " method " , " " ) ;
if ( method . is_empty ( ) ) {
2019-04-20 13:51:25 +02:00
return ;
}
2022-09-09 16:36:07 +02:00
if ( type = = " connection " ) {
Node * base = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( ! base ) {
return ;
}
Vector < Node * > nodes = _find_all_node_for_script ( base , base , script ) ;
connection_info_dialog - > popup_connections ( method , nodes ) ;
} else if ( type = = " inherits " ) {
String base_class_raw = meta [ " base_class " ] ;
PackedStringArray base_class_split = base_class_raw . split ( " : " , true , 1 ) ;
if ( base_class_split [ 0 ] = = " script " ) {
// Go to function declaration.
Ref < Script > base_script = ResourceLoader : : load ( base_class_split [ 1 ] ) ;
ERR_FAIL_COND ( ! base_script . is_valid ( ) ) ;
emit_signal ( SNAME ( " go_to_method " ) , base_script , method ) ;
} else if ( base_class_split [ 0 ] = = " builtin " ) {
// Open method documentation.
emit_signal ( SNAME ( " go_to_help " ) , " class_method: " + base_class_split [ 1 ] + " : " + method ) ;
}
}
2019-04-20 13:51:25 +02:00
}
2016-08-03 00:11:05 +02:00
void ScriptTextEditor : : _edit_option ( int p_op ) {
2020-07-24 16:50:35 +02:00
CodeEdit * tx = code_editor - > get_text_editor ( ) ;
2017-11-16 05:00:27 +01:00
2016-08-03 00:11:05 +02:00
switch ( p_op ) {
case EDIT_UNDO : {
2017-11-16 05:00:27 +01:00
tx - > undo ( ) ;
2021-07-17 23:22:52 +02:00
tx - > call_deferred ( SNAME ( " grab_focus " ) ) ;
2016-08-03 00:11:05 +02:00
} break ;
case EDIT_REDO : {
2017-11-16 05:00:27 +01:00
tx - > redo ( ) ;
2021-07-17 23:22:52 +02:00
tx - > call_deferred ( SNAME ( " grab_focus " ) ) ;
2016-08-03 00:11:05 +02:00
} break ;
case EDIT_CUT : {
2017-11-16 05:00:27 +01:00
tx - > cut ( ) ;
2021-07-17 23:22:52 +02:00
tx - > call_deferred ( SNAME ( " grab_focus " ) ) ;
2016-08-03 00:11:05 +02:00
} break ;
case EDIT_COPY : {
2017-11-16 05:00:27 +01:00
tx - > copy ( ) ;
2021-07-17 23:22:52 +02:00
tx - > call_deferred ( SNAME ( " grab_focus " ) ) ;
2016-08-03 00:11:05 +02:00
} break ;
case EDIT_PASTE : {
2017-11-16 05:00:27 +01:00
tx - > paste ( ) ;
2021-07-17 23:22:52 +02:00
tx - > call_deferred ( SNAME ( " grab_focus " ) ) ;
2016-08-03 00:11:05 +02:00
} break ;
case EDIT_SELECT_ALL : {
2017-11-16 05:00:27 +01:00
tx - > select_all ( ) ;
2021-07-17 23:22:52 +02:00
tx - > call_deferred ( SNAME ( " grab_focus " ) ) ;
2016-08-03 00:11:05 +02:00
} break ;
case EDIT_MOVE_LINE_UP : {
2018-05-26 00:49:35 +02:00
code_editor - > move_lines_up ( ) ;
2016-08-03 00:11:05 +02:00
} break ;
case EDIT_MOVE_LINE_DOWN : {
2018-05-26 00:49:35 +02:00
code_editor - > move_lines_down ( ) ;
2016-08-03 00:11:05 +02:00
} break ;
2022-09-29 04:12:52 +02:00
case EDIT_INDENT : {
2018-05-28 17:52:28 +02:00
Ref < Script > scr = script ;
2020-05-14 16:41:43 +02:00
if ( scr . is_null ( ) ) {
2016-08-03 00:11:05 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2022-09-29 04:12:52 +02:00
tx - > indent_lines ( ) ;
2016-08-03 00:11:05 +02:00
} break ;
2022-09-29 04:12:52 +02:00
case EDIT_UNINDENT : {
2018-05-28 17:52:28 +02:00
Ref < Script > scr = script ;
2020-05-14 16:41:43 +02:00
if ( scr . is_null ( ) ) {
2016-08-03 00:11:05 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2022-09-29 04:12:52 +02:00
tx - > unindent_lines ( ) ;
2017-08-20 14:31:30 +02:00
} break ;
case EDIT_DELETE_LINE : {
2018-05-26 00:49:35 +02:00
code_editor - > delete_lines ( ) ;
2016-08-03 00:11:05 +02:00
} break ;
2021-06-29 12:09:07 +02:00
case EDIT_DUPLICATE_SELECTION : {
code_editor - > duplicate_selection ( ) ;
2016-08-03 00:11:05 +02:00
} break ;
2022-09-28 17:09:45 +02:00
case EDIT_DUPLICATE_LINES : {
code_editor - > get_text_editor ( ) - > duplicate_lines ( ) ;
} break ;
2017-12-08 19:17:10 +01:00
case EDIT_TOGGLE_FOLD_LINE : {
2023-02-21 21:28:26 +01:00
int previous_line = - 1 ;
for ( int caret_idx : tx - > get_caret_index_edit_order ( ) ) {
int line_idx = tx - > get_caret_line ( caret_idx ) ;
if ( line_idx ! = previous_line ) {
tx - > toggle_foldable_line ( line_idx ) ;
previous_line = line_idx ;
}
2022-12-05 19:05:02 +01:00
}
2022-08-13 23:21:24 +02:00
tx - > queue_redraw ( ) ;
2017-11-13 00:12:17 +01:00
} break ;
2017-11-16 05:00:27 +01:00
case EDIT_FOLD_ALL_LINES : {
tx - > fold_all_lines ( ) ;
2022-08-13 23:21:24 +02:00
tx - > queue_redraw ( ) ;
2017-11-16 05:00:27 +01:00
} break ;
2017-11-13 00:12:17 +01:00
case EDIT_UNFOLD_ALL_LINES : {
2021-07-09 14:07:10 +02:00
tx - > unfold_all_lines ( ) ;
2022-08-13 23:21:24 +02:00
tx - > queue_redraw ( ) ;
2017-11-13 00:12:17 +01:00
} break ;
2023-03-12 17:48:37 +01:00
case EDIT_CREATE_CODE_REGION : {
tx - > create_code_region ( ) ;
} break ;
2016-08-03 00:11:05 +02:00
case EDIT_TOGGLE_COMMENT : {
2019-02-04 20:17:44 +01:00
_edit_option_toggle_inline_comment ( ) ;
2016-08-03 00:11:05 +02:00
} break ;
case EDIT_COMPLETE : {
2020-09-13 22:14:20 +02:00
tx - > request_code_completion ( true ) ;
2016-08-03 00:11:05 +02:00
} break ;
case EDIT_AUTO_INDENT : {
2017-11-16 05:00:27 +01:00
String text = tx - > get_text ( ) ;
2018-05-28 17:52:28 +02:00
Ref < Script > scr = script ;
2020-05-14 16:41:43 +02:00
if ( scr . is_null ( ) ) {
2016-08-03 00:11:05 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-08-22 19:52:17 +02:00
2017-11-16 05:00:27 +01:00
tx - > begin_complex_operation ( ) ;
2016-08-03 00:11:05 +02:00
int begin , end ;
2021-07-09 13:42:55 +02:00
if ( tx - > has_selection ( ) ) {
2017-11-16 05:00:27 +01:00
begin = tx - > get_selection_from_line ( ) ;
end = tx - > get_selection_to_line ( ) ;
2017-08-22 19:52:17 +02:00
// ignore if the cursor is not past the first column
2017-11-16 05:00:27 +01:00
if ( tx - > get_selection_to_column ( ) = = 0 ) {
2017-08-22 19:52:17 +02:00
end - - ;
}
2016-08-03 00:11:05 +02:00
} else {
begin = 0 ;
2017-11-16 05:00:27 +01:00
end = tx - > get_line_count ( ) - 1 ;
2016-08-03 00:11:05 +02:00
}
scr - > get_language ( ) - > auto_indent_code ( text , begin , end ) ;
2017-08-22 19:52:17 +02:00
Vector < String > lines = text . split ( " \n " ) ;
for ( int i = begin ; i < = end ; + + i ) {
2017-11-16 05:00:27 +01:00
tx - > set_line ( i , lines [ i ] ) ;
2017-08-22 19:52:17 +02:00
}
2017-11-16 05:00:27 +01:00
tx - > end_complex_operation ( ) ;
2016-08-03 00:11:05 +02:00
} break ;
case EDIT_TRIM_TRAILING_WHITESAPCE : {
trim_trailing_whitespace ( ) ;
} break ;
2017-04-16 17:47:59 +02:00
case EDIT_CONVERT_INDENT_TO_SPACES : {
2023-05-01 22:41:50 +02:00
tx - > set_indent_using_spaces ( true ) ;
convert_indent ( ) ;
2017-04-16 17:47:59 +02:00
} break ;
case EDIT_CONVERT_INDENT_TO_TABS : {
2023-05-01 22:41:50 +02:00
tx - > set_indent_using_spaces ( false ) ;
convert_indent ( ) ;
2017-04-16 17:47:59 +02:00
} break ;
2016-09-29 09:12:45 +02:00
case EDIT_PICK_COLOR : {
color_panel - > popup ( ) ;
} break ;
2017-04-24 20:59:55 +02:00
case EDIT_TO_UPPERCASE : {
2018-05-26 00:49:35 +02:00
_convert_case ( CodeTextEditor : : UPPER ) ;
2017-04-24 20:59:55 +02:00
} break ;
case EDIT_TO_LOWERCASE : {
2018-05-26 00:49:35 +02:00
_convert_case ( CodeTextEditor : : LOWER ) ;
2017-04-24 20:59:55 +02:00
} break ;
case EDIT_CAPITALIZE : {
2018-05-26 00:49:35 +02:00
_convert_case ( CodeTextEditor : : CAPITALIZE ) ;
2017-04-24 20:59:55 +02:00
} break ;
2019-08-07 16:31:33 +02:00
case EDIT_EVALUATE : {
Expression expression ;
2022-12-05 19:05:02 +01:00
tx - > begin_complex_operation ( ) ;
for ( int caret_idx = 0 ; caret_idx < tx - > get_caret_count ( ) ; caret_idx + + ) {
Vector < String > lines = tx - > get_selected_text ( caret_idx ) . split ( " \n " ) ;
PackedStringArray results ;
for ( int i = 0 ; i < lines . size ( ) ; i + + ) {
String line = lines [ i ] ;
String whitespace = line . substr ( 0 , line . size ( ) - line . strip_edges ( true , false ) . size ( ) ) ; // Extract the whitespace at the beginning.
if ( expression . parse ( line ) = = OK ) {
Variant result = expression . execute ( Array ( ) , Variant ( ) , false , true ) ;
if ( expression . get_error_text ( ) . is_empty ( ) ) {
results . push_back ( whitespace + result . get_construct_string ( ) ) ;
} else {
results . push_back ( line ) ;
}
2019-08-07 16:31:33 +02:00
} else {
2020-02-17 22:06:54 +01:00
results . push_back ( line ) ;
2019-08-07 16:31:33 +02:00
}
}
2022-12-05 19:05:02 +01:00
tx - > insert_text_at_caret ( String ( " \n " ) . join ( results ) , caret_idx ) ;
2019-08-07 16:31:33 +02:00
}
2022-12-05 19:05:02 +01:00
tx - > end_complex_operation ( ) ;
2019-08-07 16:31:33 +02:00
} break ;
2023-04-19 23:46:22 +02:00
case EDIT_TOGGLE_WORD_WRAP : {
TextEdit : : LineWrappingMode wrap = code_editor - > get_text_editor ( ) - > get_line_wrapping_mode ( ) ;
code_editor - > get_text_editor ( ) - > set_line_wrapping_mode ( wrap = = TextEdit : : LINE_WRAPPING_BOUNDARY ? TextEdit : : LINE_WRAPPING_NONE : TextEdit : : LINE_WRAPPING_BOUNDARY ) ;
} break ;
2016-08-03 00:11:05 +02:00
case SEARCH_FIND : {
code_editor - > get_find_replace_bar ( ) - > popup_search ( ) ;
} break ;
case SEARCH_FIND_NEXT : {
code_editor - > get_find_replace_bar ( ) - > search_next ( ) ;
} break ;
case SEARCH_FIND_PREV : {
code_editor - > get_find_replace_bar ( ) - > search_prev ( ) ;
} break ;
case SEARCH_REPLACE : {
code_editor - > get_find_replace_bar ( ) - > popup_replace ( ) ;
} break ;
2018-02-12 02:36:15 +01:00
case SEARCH_IN_FILES : {
2022-12-05 19:05:02 +01:00
String selected_text = tx - > get_selected_text ( ) ;
2018-02-12 02:36:15 +01:00
// Yep, because it doesn't make sense to instance this dialog for every single script open...
2019-05-21 10:07:48 +02:00
// So this will be delegated to the ScriptEditor.
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " search_in_files_requested " ) , selected_text ) ;
2018-02-12 02:36:15 +01:00
} break ;
2020-02-09 10:10:58 +01:00
case REPLACE_IN_FILES : {
2022-12-05 19:05:02 +01:00
String selected_text = tx - > get_selected_text ( ) ;
2020-02-09 10:10:58 +01:00
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " replace_in_files_requested " ) , selected_text ) ;
2020-02-09 10:10:58 +01:00
} break ;
2016-08-03 00:11:05 +02:00
case SEARCH_LOCATE_FUNCTION : {
2018-10-02 12:07:44 +02:00
quick_open - > popup_dialog ( get_functions ( ) ) ;
2018-09-25 22:44:50 +02:00
quick_open - > set_title ( TTR ( " Go to Function " ) ) ;
2016-08-03 00:11:05 +02:00
} break ;
case SEARCH_GOTO_LINE : {
2017-11-16 05:00:27 +01:00
goto_line_dialog - > popup_find_line ( tx ) ;
2016-08-03 00:11:05 +02:00
} break ;
2019-04-20 01:51:25 +02:00
case BOOKMARK_TOGGLE : {
code_editor - > toggle_bookmark ( ) ;
} break ;
case BOOKMARK_GOTO_NEXT : {
code_editor - > goto_next_bookmark ( ) ;
} break ;
case BOOKMARK_GOTO_PREV : {
code_editor - > goto_prev_bookmark ( ) ;
} break ;
case BOOKMARK_REMOVE_ALL : {
code_editor - > remove_all_bookmarks ( ) ;
} break ;
2016-08-03 00:11:05 +02:00
case DEBUG_TOGGLE_BREAKPOINT : {
2023-02-01 14:35:35 +01:00
Vector < int > caret_edit_order = tx - > get_caret_index_edit_order ( ) ;
caret_edit_order . reverse ( ) ;
int last_line = - 1 ;
for ( const int & c : caret_edit_order ) {
int from = tx - > has_selection ( c ) ? tx - > get_selection_from_line ( c ) : tx - > get_caret_line ( c ) ;
from + = from = = last_line ? 1 : 0 ;
int to = tx - > has_selection ( c ) ? tx - > get_selection_to_line ( c ) : tx - > get_caret_line ( c ) ;
if ( to < from ) {
continue ;
}
// Check first if there's any lines with breakpoints in the selection.
bool selection_has_breakpoints = false ;
for ( int line = from ; line < = to ; line + + ) {
if ( tx - > is_line_breakpointed ( line ) ) {
selection_has_breakpoints = true ;
break ;
}
}
// Set breakpoint on caret or remove all bookmarks from the selection.
if ( ! selection_has_breakpoints ) {
if ( tx - > get_caret_line ( c ) ! = last_line ) {
tx - > set_line_as_breakpoint ( tx - > get_caret_line ( c ) , true ) ;
}
} else {
for ( int line = from ; line < = to ; line + + ) {
tx - > set_line_as_breakpoint ( line , false ) ;
}
}
last_line = to ;
2022-12-05 19:05:02 +01:00
}
2016-08-03 00:11:05 +02:00
} break ;
case DEBUG_REMOVE_ALL_BREAKPOINTS : {
2022-08-05 03:41:48 +02:00
PackedInt32Array bpoints = tx - > get_breakpointed_lines ( ) ;
2016-08-03 00:11:05 +02:00
2020-07-26 16:57:23 +02:00
for ( int i = 0 ; i < bpoints . size ( ) ; i + + ) {
int line = bpoints [ i ] ;
bool dobreak = ! tx - > is_line_breakpointed ( line ) ;
2017-11-16 05:00:27 +01:00
tx - > set_line_as_breakpoint ( line , dobreak ) ;
2020-02-07 02:52:05 +01:00
EditorDebuggerNode : : get_singleton ( ) - > set_breakpoint ( script - > get_path ( ) , line + 1 , dobreak ) ;
2016-08-03 00:11:05 +02:00
}
2019-04-05 14:06:16 +02:00
} break ;
2016-08-03 00:11:05 +02:00
case DEBUG_GOTO_NEXT_BREAKPOINT : {
2022-08-05 03:41:48 +02:00
PackedInt32Array bpoints = tx - > get_breakpointed_lines ( ) ;
2016-08-03 00:11:05 +02:00
if ( bpoints . size ( ) < = 0 ) {
return ;
}
2022-12-05 19:05:02 +01:00
int current_line = tx - > get_caret_line ( ) ;
int bpoint_idx = 0 ;
if ( current_line < ( int ) bpoints [ bpoints . size ( ) - 1 ] ) {
while ( bpoint_idx < bpoints . size ( ) & & bpoints [ bpoint_idx ] < = current_line ) {
bpoint_idx + + ;
2016-08-03 00:11:05 +02:00
}
}
2022-12-05 19:05:02 +01:00
code_editor - > goto_line_centered ( bpoints [ bpoint_idx ] ) ;
2016-08-03 00:11:05 +02:00
} break ;
case DEBUG_GOTO_PREV_BREAKPOINT : {
2022-08-05 03:41:48 +02:00
PackedInt32Array bpoints = tx - > get_breakpointed_lines ( ) ;
2016-08-03 00:11:05 +02:00
if ( bpoints . size ( ) < = 0 ) {
return ;
}
2022-12-05 19:05:02 +01:00
int current_line = tx - > get_caret_line ( ) ;
int bpoint_idx = bpoints . size ( ) - 1 ;
if ( current_line > ( int ) bpoints [ 0 ] ) {
while ( bpoint_idx > = 0 & & bpoints [ bpoint_idx ] > = current_line ) {
bpoint_idx - - ;
2016-08-03 00:11:05 +02:00
}
}
2022-12-05 19:05:02 +01:00
code_editor - > goto_line_centered ( bpoints [ bpoint_idx ] ) ;
2016-08-03 00:11:05 +02:00
} break ;
case HELP_CONTEXTUAL : {
2022-06-08 23:41:38 +02:00
String text = tx - > get_selected_text ( 0 ) ;
2021-12-09 10:42:46 +01:00
if ( text . is_empty ( ) ) {
2022-06-08 23:41:38 +02:00
text = tx - > get_word_under_caret ( 0 ) ;
2020-05-14 16:41:43 +02:00
}
2021-12-09 10:42:46 +01:00
if ( ! text . is_empty ( ) ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " request_help " ) , text ) ;
2016-08-03 00:11:05 +02:00
}
} break ;
2018-01-02 08:10:49 +01:00
case LOOKUP_SYMBOL : {
2022-06-08 23:41:38 +02:00
String text = tx - > get_word_under_caret ( 0 ) ;
2021-12-09 10:42:46 +01:00
if ( text . is_empty ( ) ) {
2022-06-08 23:41:38 +02:00
text = tx - > get_selected_text ( 0 ) ;
2020-05-14 16:41:43 +02:00
}
2021-12-09 10:42:46 +01:00
if ( ! text . is_empty ( ) ) {
2022-06-08 23:41:38 +02:00
_lookup_symbol ( text , tx - > get_caret_line ( 0 ) , tx - > get_caret_column ( 0 ) ) ;
2018-01-02 08:10:49 +01:00
}
} break ;
2016-08-03 00:11:05 +02:00
}
}
2019-02-04 20:17:44 +01:00
void ScriptTextEditor : : _edit_option_toggle_inline_comment ( ) {
2020-05-14 16:41:43 +02:00
if ( script . is_null ( ) ) {
2019-02-04 20:17:44 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2019-02-04 20:17:44 +01:00
String delimiter = " # " ;
List < String > comment_delimiters ;
script - > get_language ( ) - > get_comment_delimiters ( & comment_delimiters ) ;
2021-07-24 15:46:25 +02:00
for ( const String & script_delimiter : comment_delimiters ) {
2022-02-03 17:03:38 +01:00
if ( ! script_delimiter . contains ( " " ) ) {
2019-02-04 20:17:44 +01:00
delimiter = script_delimiter ;
break ;
}
}
code_editor - > toggle_inline_comment ( delimiter ) ;
}
2020-05-03 18:08:15 +02:00
void ScriptTextEditor : : add_syntax_highlighter ( Ref < EditorSyntaxHighlighter > p_highlighter ) {
2019-11-20 10:09:59 +01:00
ERR_FAIL_COND ( p_highlighter . is_null ( ) ) ;
2020-03-07 12:17:18 +01:00
highlighters [ p_highlighter - > _get_name ( ) ] = p_highlighter ;
highlighter_menu - > add_radio_check_item ( p_highlighter - > _get_name ( ) ) ;
2018-04-02 13:41:44 +02:00
}
2020-05-03 18:08:15 +02:00
void ScriptTextEditor : : set_syntax_highlighter ( Ref < EditorSyntaxHighlighter > p_highlighter ) {
2019-11-20 10:09:59 +01:00
ERR_FAIL_COND ( p_highlighter . is_null ( ) ) ;
2022-05-13 15:04:37 +02:00
HashMap < String , Ref < EditorSyntaxHighlighter > > : : Iterator el = highlighters . begin ( ) ;
while ( el ) {
int highlighter_index = highlighter_menu - > get_item_idx_from_text ( el - > key ) ;
highlighter_menu - > set_item_checked ( highlighter_index , el - > value = = p_highlighter ) ;
+ + el ;
2019-11-20 10:09:59 +01:00
}
2020-07-24 16:50:35 +02:00
CodeEdit * te = code_editor - > get_text_editor ( ) ;
2020-05-03 18:08:15 +02:00
p_highlighter - > _set_edited_resource ( script ) ;
te - > set_syntax_highlighter ( p_highlighter ) ;
2018-04-02 13:41:44 +02:00
}
void ScriptTextEditor : : _change_syntax_highlighter ( int p_idx ) {
2018-06-01 21:32:19 +02:00
set_syntax_highlighter ( highlighters [ highlighter_menu - > get_item_text ( p_idx ) ] ) ;
2018-04-02 13:41:44 +02:00
}
2020-07-29 23:26:49 +02:00
void ScriptTextEditor : : _notification ( int p_what ) {
switch ( p_what ) {
2022-08-29 11:04:31 +02:00
case NOTIFICATION_THEME_CHANGED :
2022-03-08 19:20:09 +01:00
if ( ! editor_enabled ) {
break ;
}
2022-01-19 06:31:39 +01:00
if ( is_visible_in_tree ( ) ) {
_update_warnings ( ) ;
_update_errors ( ) ;
}
2022-08-29 11:04:31 +02:00
[[fallthrough]] ;
case NOTIFICATION_ENTER_TREE : {
code_editor - > get_text_editor ( ) - > set_gutter_width ( connection_gutter , code_editor - > get_text_editor ( ) - > get_line_height ( ) ) ;
2020-07-29 23:26:49 +02:00
} break ;
}
}
2016-08-03 00:11:05 +02:00
Control * ScriptTextEditor : : get_edit_menu ( ) {
return edit_hb ;
}
2017-07-01 02:30:17 +02:00
void ScriptTextEditor : : clear_edit_menu ( ) {
2022-07-19 13:09:10 +02:00
if ( editor_enabled ) {
memdelete ( edit_hb ) ;
}
2017-07-01 02:30:17 +02:00
}
2021-06-03 01:05:41 +02:00
void ScriptTextEditor : : set_find_replace_bar ( FindReplaceBar * p_bar ) {
code_editor - > set_find_replace_bar ( p_bar ) ;
}
2016-08-03 00:11:05 +02:00
void ScriptTextEditor : : reload ( bool p_soft ) {
2020-07-24 16:50:35 +02:00
CodeEdit * te = code_editor - > get_text_editor ( ) ;
2018-05-28 17:52:28 +02:00
Ref < Script > scr = script ;
2020-05-14 16:41:43 +02:00
if ( scr . is_null ( ) ) {
2016-08-03 00:11:05 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
scr - > set_source_code ( te - > get_text ( ) ) ;
2022-02-06 14:12:19 +01:00
bool soft = p_soft | | scr - > get_instance_base_type ( ) = = " EditorPlugin " ; // Always soft-reload editor plugins.
2016-08-03 00:11:05 +02:00
scr - > get_language ( ) - > reload_tool_script ( scr , soft ) ;
}
2022-08-05 03:41:48 +02:00
PackedInt32Array ScriptTextEditor : : get_breakpoints ( ) {
2020-07-26 16:57:23 +02:00
return code_editor - > get_text_editor ( ) - > get_breakpointed_lines ( ) ;
2016-08-03 00:11:05 +02:00
}
2021-07-20 13:24:56 +02:00
void ScriptTextEditor : : set_breakpoint ( int p_line , bool p_enabled ) {
code_editor - > get_text_editor ( ) - > set_line_as_breakpoint ( p_line , p_enabled ) ;
}
void ScriptTextEditor : : clear_breakpoints ( ) {
code_editor - > get_text_editor ( ) - > clear_breakpointed_lines ( ) ;
}
2021-11-07 18:26:15 +01:00
void ScriptTextEditor : : set_tooltip_request_func ( const Callable & p_toolip_callback ) {
Variant args [ 1 ] = { this } ;
const Variant * argp [ ] = { & args [ 0 ] } ;
2022-07-28 22:56:41 +02:00
code_editor - > get_text_editor ( ) - > set_tooltip_request_func ( p_toolip_callback . bindp ( argp , 1 ) ) ;
2016-08-03 00:11:05 +02:00
}
2016-08-07 00:00:54 +02:00
void ScriptTextEditor : : set_debugger_active ( bool p_active ) {
}
2021-05-13 21:50:25 +02:00
Control * ScriptTextEditor : : get_base_editor ( ) const {
return code_editor - > get_text_editor ( ) ;
}
2016-09-11 16:28:01 +02:00
Variant ScriptTextEditor : : get_drag_data_fw ( const Point2 & p_point , Control * p_from ) {
return Variant ( ) ;
}
bool ScriptTextEditor : : can_drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) const {
Dictionary d = p_data ;
2021-10-28 15:19:35 +02:00
if ( d . has ( " type " ) & &
( String ( d [ " type " ] ) = = " resource " | |
String ( d [ " type " ] ) = = " files " | |
String ( d [ " type " ] ) = = " nodes " | |
String ( d [ " type " ] ) = = " obj_property " | |
String ( d [ " type " ] ) = = " files_and_dirs " ) ) {
2016-09-11 16:28:01 +02:00
return true ;
}
return false ;
}
static Node * _find_script_node ( Node * p_edited_scene , Node * p_current_node , const Ref < Script > & script ) {
2022-09-21 15:46:30 +02:00
// Check scripts only for the nodes belonging to the edited scene.
if ( p_current_node = = p_edited_scene | | p_current_node - > get_owner ( ) = = p_edited_scene ) {
Ref < Script > scr = p_current_node - > get_script ( ) ;
if ( scr . is_valid ( ) & & scr = = script ) {
return p_current_node ;
}
2020-05-14 16:41:43 +02:00
}
2016-09-11 16:28:01 +02:00
2022-09-21 15:46:30 +02:00
// Traverse all children, even the ones not owned by the edited scene as they
// can still have child nodes added within the edited scene and thus owned by
// it (e.g. nodes added to subscene's root or to its editable children).
2016-09-11 16:28:01 +02:00
for ( int i = 0 ; i < p_current_node - > get_child_count ( ) ; i + + ) {
Node * n = _find_script_node ( p_edited_scene , p_current_node - > get_child ( i ) , script ) ;
2020-05-14 16:41:43 +02:00
if ( n ) {
2016-09-11 16:28:01 +02:00
return n ;
2020-05-14 16:41:43 +02:00
}
2016-09-11 16:28:01 +02:00
}
2020-04-02 01:20:12 +02:00
return nullptr ;
2016-09-11 16:28:01 +02:00
}
2022-10-12 01:25:31 +02:00
static String _quote_drop_data ( const String & str ) {
// This function prepares a string for being "dropped" into the script editor.
// The string can be a resource path, node path or property name.
const bool using_single_quotes = EDITOR_GET ( " text_editor/completion/use_single_quotes " ) ;
String escaped = str . c_escape ( ) ;
// If string is double quoted, there is no need to escape single quotes.
// We can revert the extra escaping added in c_escape().
if ( ! using_single_quotes ) {
escaped = escaped . replace ( " \\ ' " , " \' " ) ;
}
return escaped . quote ( using_single_quotes ? " ' " : " \" " ) ;
}
2021-08-13 21:24:02 +02:00
2023-09-15 22:00:18 +02:00
static String _get_dropped_resource_line ( const Ref < Resource > & p_resource , bool p_create_field ) {
const String & path = p_resource - > get_path ( ) ;
const bool is_script = ClassDB : : is_parent_class ( p_resource - > get_class ( ) , " Script " ) ;
if ( ! p_create_field ) {
return vformat ( " preload(%s) " , _quote_drop_data(path)) ;
}
String variable_name = p_resource - > get_name ( ) ;
if ( variable_name . is_empty ( ) ) {
variable_name = path . get_file ( ) . get_basename ( ) ;
}
if ( is_script ) {
variable_name = variable_name . to_pascal_case ( ) . validate_identifier ( ) ;
} else {
variable_name = variable_name . to_snake_case ( ) . to_upper ( ) . validate_identifier ( ) ;
}
return vformat ( " const %s = preload(%s) " , variable_name, _quote_drop_data(path)) ;
}
2022-10-12 01:25:31 +02:00
void ScriptTextEditor : : drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) {
2016-09-11 16:28:01 +02:00
Dictionary d = p_data ;
2020-07-24 16:50:35 +02:00
CodeEdit * te = code_editor - > get_text_editor ( ) ;
2021-07-10 12:41:38 +02:00
Point2i pos = te - > get_line_column_at_pos ( p_point ) ;
int row = pos . y ;
int col = pos . x ;
2018-02-04 03:33:32 +01:00
2023-09-15 22:00:18 +02:00
const bool drop_modifier_pressed = Input : : get_singleton ( ) - > is_key_pressed ( Key : : CMD_OR_CTRL ) ;
const String & line = te - > get_line ( row ) ;
const bool is_empty_line = line . is_empty ( ) | | te - > get_first_non_whitespace_column ( row ) = = line . length ( ) ;
2016-09-11 16:28:01 +02:00
if ( d . has ( " type " ) & & String ( d [ " type " ] ) = = " resource " ) {
2022-06-08 23:41:38 +02:00
te - > remove_secondary_carets ( ) ;
2023-09-15 22:00:18 +02:00
Ref < Resource > resource = d [ " resource " ] ;
if ( resource . is_null ( ) ) {
2016-09-11 16:28:01 +02:00
return ;
}
2023-09-15 22:00:18 +02:00
const String & path = resource - > get_path ( ) ;
if ( path . is_empty ( ) | | path . ends_with ( " :: " ) ) {
String warning = TTR ( " The resource does not have a valid path because it has not been saved. \n Please save the scene or resource that contains this resource and try again. " ) ;
EditorToaster : : get_singleton ( ) - > popup_str ( warning , EditorToaster : : SEVERITY_ERROR ) ;
2016-09-11 16:28:01 +02:00
return ;
}
2023-09-15 22:00:18 +02:00
String text_to_drop ;
if ( drop_modifier_pressed ) {
if ( resource - > is_built_in ( ) ) {
String warning = TTR ( " Preloading internal resources is not supported. " ) ;
EditorToaster : : get_singleton ( ) - > popup_str ( warning , EditorToaster : : SEVERITY_ERROR ) ;
} else {
text_to_drop = _get_dropped_resource_line ( resource , is_empty_line ) ;
}
} else {
text_to_drop = _quote_drop_data ( path ) ;
}
2021-07-08 19:35:56 +02:00
te - > set_caret_line ( row ) ;
te - > set_caret_column ( col ) ;
2023-09-15 22:00:18 +02:00
te - > insert_text_at_caret ( text_to_drop ) ;
2022-05-28 19:46:17 +02:00
te - > grab_focus ( ) ;
2016-09-11 16:28:01 +02:00
}
2019-05-15 19:36:26 +02:00
if ( d . has ( " type " ) & & ( String ( d [ " type " ] ) = = " files " | | String ( d [ " type " ] ) = = " files_and_dirs " ) ) {
2022-06-08 23:41:38 +02:00
te - > remove_secondary_carets ( ) ;
2016-09-11 16:28:01 +02:00
2023-09-15 22:00:18 +02:00
Array files = d [ " files " ] ;
2016-09-11 16:28:01 +02:00
String text_to_drop ;
2023-09-15 22:00:18 +02:00
2016-09-11 16:28:01 +02:00
for ( int i = 0 ; i < files . size ( ) ; i + + ) {
2023-09-15 22:00:18 +02:00
const String & path = String ( files [ i ] ) ;
2021-05-27 00:29:36 +02:00
2023-09-15 22:00:18 +02:00
if ( drop_modifier_pressed & & ResourceLoader : : exists ( path ) ) {
Ref < Resource > resource = ResourceLoader : : load ( path ) ;
text_to_drop + = _get_dropped_resource_line ( resource , is_empty_line ) ;
2021-05-27 00:29:36 +02:00
} else {
2023-09-15 22:00:18 +02:00
text_to_drop + = _quote_drop_data ( path ) ;
}
if ( i < files . size ( ) - 1 ) {
text_to_drop + = is_empty_line ? " \n " : " , " ;
2020-05-14 16:41:43 +02:00
}
2016-09-11 16:28:01 +02:00
}
2021-07-08 19:35:56 +02:00
te - > set_caret_line ( row ) ;
te - > set_caret_column ( col ) ;
te - > insert_text_at_caret ( text_to_drop ) ;
2022-05-28 19:46:17 +02:00
te - > grab_focus ( ) ;
2016-09-11 16:28:01 +02:00
}
if ( d . has ( " type " ) & & String ( d [ " type " ] ) = = " nodes " ) {
2022-06-08 23:41:38 +02:00
te - > remove_secondary_carets ( ) ;
2022-09-21 02:48:01 +02:00
Node * scene_root = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( ! scene_root ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Can't drop nodes without an open scene. " ) ) ;
return ;
}
2016-09-11 16:28:01 +02:00
2023-07-09 23:15:54 +02:00
if ( ! ClassDB : : is_parent_class ( script - > get_instance_base_type ( ) , " Node " ) ) {
EditorToaster : : get_singleton ( ) - > popup_str ( vformat ( TTR ( " Can't drop nodes because script '%s' does not inherit Node. " ) , get_name ( ) ) , EditorToaster : : SEVERITY_WARNING ) ;
return ;
}
2022-09-21 02:48:01 +02:00
Node * sn = _find_script_node ( scene_root , scene_root , script ) ;
2016-09-11 16:28:01 +02:00
if ( ! sn ) {
2023-07-09 23:15:54 +02:00
sn = scene_root ;
2016-09-11 16:28:01 +02:00
}
Array nodes = d [ " nodes " ] ;
String text_to_drop ;
2023-09-15 22:00:18 +02:00
if ( drop_modifier_pressed ) {
const bool use_type = EDITOR_GET ( " text_editor/completion/add_type_hints " ) ;
2022-05-02 15:04:17 +02:00
for ( int i = 0 ; i < nodes . size ( ) ; i + + ) {
NodePath np = nodes [ i ] ;
Node * node = get_node ( np ) ;
if ( ! node ) {
continue ;
}
2022-05-26 17:56:39 +02:00
bool is_unique = false ;
2022-05-18 12:19:56 +02:00
String path ;
if ( node - > is_unique_name_in_owner ( ) ) {
2022-05-26 17:56:39 +02:00
path = node - > get_name ( ) ;
is_unique = true ;
2022-05-18 12:19:56 +02:00
} else {
path = sn - > get_path_to ( node ) ;
}
2022-05-02 15:04:17 +02:00
for ( const String & segment : path . split ( " / " ) ) {
if ( ! segment . is_valid_identifier ( ) ) {
2022-10-12 01:25:31 +02:00
path = _quote_drop_data ( path ) ;
2022-05-02 15:04:17 +02:00
break ;
}
}
2022-08-30 11:36:24 +02:00
String variable_name = String ( node - > get_name ( ) ) . to_snake_case ( ) . validate_identifier ( ) ;
2022-05-02 15:04:17 +02:00
if ( use_type ) {
2023-07-08 13:23:01 +02:00
StringName class_name = node - > get_class_name ( ) ;
Ref < Script > node_script = node - > get_script ( ) ;
if ( node_script . is_valid ( ) ) {
StringName global_node_script_name = node_script - > get_global_name ( ) ;
if ( global_node_script_name ! = StringName ( ) ) {
class_name = global_node_script_name ;
}
}
text_to_drop + = vformat ( " @onready var %s: %s = %c%s \n " , variable_name , class_name , is_unique ? ' % ' : ' $ ' , path ) ;
2022-05-02 15:04:17 +02:00
} else {
2023-07-08 13:23:01 +02:00
text_to_drop + = vformat ( " @onready var %s = %c%s \n " , variable_name , is_unique ? ' % ' : ' $ ' , path ) ;
2022-05-02 15:04:17 +02:00
}
2016-09-11 16:28:01 +02:00
}
2022-05-02 15:04:17 +02:00
} else {
for ( int i = 0 ; i < nodes . size ( ) ; i + + ) {
if ( i > 0 ) {
2022-05-17 14:56:16 +02:00
text_to_drop + = " , " ;
2022-05-02 15:04:17 +02:00
}
2016-09-11 16:28:01 +02:00
2022-05-02 15:04:17 +02:00
NodePath np = nodes [ i ] ;
Node * node = get_node ( np ) ;
if ( ! node ) {
continue ;
}
2022-05-26 17:56:39 +02:00
bool is_unique = false ;
2022-05-18 12:19:56 +02:00
String path ;
if ( node - > is_unique_name_in_owner ( ) ) {
2022-05-26 17:56:39 +02:00
path = node - > get_name ( ) ;
is_unique = true ;
2022-05-18 12:19:56 +02:00
} else {
path = sn - > get_path_to ( node ) ;
}
2022-05-26 17:56:39 +02:00
2022-05-17 14:56:16 +02:00
for ( const String & segment : path . split ( " / " ) ) {
if ( ! segment . is_valid_identifier ( ) ) {
2022-10-12 01:25:31 +02:00
path = _quote_drop_data ( path ) ;
2022-05-17 14:56:16 +02:00
break ;
}
}
2022-05-26 17:56:39 +02:00
text_to_drop + = ( is_unique ? " % " : " $ " ) + path ;
2022-05-02 15:04:17 +02:00
}
2016-09-11 16:28:01 +02:00
}
2021-07-08 19:35:56 +02:00
te - > set_caret_line ( row ) ;
te - > set_caret_column ( col ) ;
te - > insert_text_at_caret ( text_to_drop ) ;
2022-05-28 19:46:17 +02:00
te - > grab_focus ( ) ;
2016-09-11 16:28:01 +02:00
}
2021-08-13 17:01:40 +02:00
if ( d . has ( " type " ) & & String ( d [ " type " ] ) = = " obj_property " ) {
2022-06-08 23:41:38 +02:00
te - > remove_secondary_carets ( ) ;
2022-10-12 01:25:31 +02:00
// It is unclear whether properties may contain single or double quotes.
// Assume here that double-quotes may not exist. We are escaping single-quotes if necessary.
const String text_to_drop = _quote_drop_data ( String ( d [ " property " ] ) ) ;
2021-08-13 17:01:40 +02:00
te - > set_caret_line ( row ) ;
te - > set_caret_column ( col ) ;
te - > insert_text_at_caret ( text_to_drop ) ;
2022-05-28 19:46:17 +02:00
te - > grab_focus ( ) ;
2021-08-13 17:01:40 +02:00
}
2016-09-11 16:28:01 +02:00
}
2017-05-20 17:38:03 +02:00
void ScriptTextEditor : : _text_edit_gui_input ( const Ref < InputEvent > & ev ) {
Ref < InputEventMouseButton > mb = ev ;
2019-06-22 20:22:52 +02:00
Ref < InputEventKey > k = ev ;
Point2 local_pos ;
bool create_menu = false ;
2017-05-20 17:38:03 +02:00
2020-07-24 16:50:35 +02:00
CodeEdit * tx = code_editor - > get_text_editor ( ) ;
2021-08-13 23:31:57 +02:00
if ( mb . is_valid ( ) & & mb - > get_button_index ( ) = = MouseButton : : RIGHT & & mb - > is_pressed ( ) ) {
2019-06-22 20:22:52 +02:00
local_pos = mb - > get_global_position ( ) - tx - > get_global_position ( ) ;
create_menu = true ;
2021-07-08 19:35:56 +02:00
} else if ( k . is_valid ( ) & & k - > is_action ( " ui_menu " , true ) ) {
2022-06-08 23:41:38 +02:00
tx - > adjust_viewport_to_caret ( 0 ) ;
local_pos = tx - > get_caret_draw_pos ( 0 ) ;
2019-06-22 20:22:52 +02:00
create_menu = true ;
}
2017-12-20 02:36:47 +01:00
2019-06-22 20:22:52 +02:00
if ( create_menu ) {
2021-07-10 12:41:38 +02:00
Point2i pos = tx - > get_line_column_at_pos ( local_pos ) ;
int row = pos . y ;
int col = pos . x ;
2017-12-20 02:36:47 +01:00
2022-10-18 16:43:37 +02:00
tx - > set_move_caret_on_right_click_enabled ( EDITOR_GET ( " text_editor/behavior/navigation/move_caret_on_right_click " ) ) ;
2023-04-30 18:28:21 +02:00
int caret_clicked = - 1 ;
2021-07-08 19:35:56 +02:00
if ( tx - > is_move_caret_on_right_click_enabled ( ) ) {
2021-07-09 13:42:55 +02:00
if ( tx - > has_selection ( ) ) {
2023-04-30 18:28:21 +02:00
for ( int i = 0 ; i < tx - > get_caret_count ( ) ; i + + ) {
int from_line = tx - > get_selection_from_line ( i ) ;
int to_line = tx - > get_selection_to_line ( i ) ;
int from_column = tx - > get_selection_from_column ( i ) ;
int to_column = tx - > get_selection_to_column ( i ) ;
if ( row > = from_line & & row < = to_line & & ( row ! = from_line | | col > = from_column ) & & ( row ! = to_line | | col < = to_column ) ) {
// Right click in one of the selected text
caret_clicked = i ;
break ;
}
2017-12-20 02:36:47 +01:00
}
}
2023-05-08 21:54:42 +02:00
if ( caret_clicked < 0 ) {
2023-04-30 18:28:21 +02:00
tx - > deselect ( ) ;
tx - > remove_secondary_carets ( ) ;
caret_clicked = 0 ;
2021-07-08 19:35:56 +02:00
tx - > set_caret_line ( row , false , false ) ;
tx - > set_caret_column ( col ) ;
2019-06-22 20:22:52 +02:00
}
}
2017-12-20 02:36:47 +01:00
2019-06-22 20:22:52 +02:00
String word_at_pos = tx - > get_word_at_pos ( local_pos ) ;
2021-12-09 10:42:46 +01:00
if ( word_at_pos . is_empty ( ) ) {
2023-04-30 18:28:21 +02:00
word_at_pos = tx - > get_word_under_caret ( caret_clicked ) ;
2020-05-14 16:41:43 +02:00
}
2021-12-09 10:42:46 +01:00
if ( word_at_pos . is_empty ( ) ) {
2023-04-30 18:28:21 +02:00
word_at_pos = tx - > get_selected_text ( caret_clicked ) ;
2020-05-14 16:41:43 +02:00
}
2018-01-02 08:10:49 +01:00
2019-06-22 20:22:52 +02:00
bool has_color = ( word_at_pos = = " Color " ) ;
2021-03-13 15:09:49 +01:00
bool foldable = tx - > can_fold_line ( row ) | | tx - > is_line_folded ( row ) ;
2019-06-22 20:22:52 +02:00
bool open_docs = false ;
bool goto_definition = false ;
2018-01-02 08:10:49 +01:00
2023-02-13 05:33:10 +01:00
if ( ScriptServer : : is_global_class ( word_at_pos ) | | word_at_pos . is_resource_file ( ) ) {
2019-06-22 20:22:52 +02:00
open_docs = true ;
} else {
Node * base = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( base ) {
base = _find_node_for_script ( base , base , script ) ;
}
ScriptLanguage : : LookupResult result ;
2022-12-05 19:05:02 +01:00
if ( script - > get_language ( ) - > lookup_code ( tx - > get_text_for_symbol_lookup ( ) , word_at_pos , script - > get_path ( ) , base , result ) = = OK ) {
2018-01-02 08:10:49 +01:00
open_docs = true ;
}
2019-06-22 20:22:52 +02:00
}
2018-01-02 08:10:49 +01:00
2019-06-22 20:22:52 +02:00
if ( has_color ) {
String line = tx - > get_line ( row ) ;
color_position . x = row ;
color_position . y = col ;
2022-08-04 13:11:07 +02:00
int begin = - 1 ;
int end = - 1 ;
enum EXPRESSION_PATTERNS {
NOT_PARSED ,
RGBA_PARAMETER , // Color(float,float,float) or Color(float,float,float,float)
COLOR_NAME , // Color.COLOR_NAME
} expression_pattern = NOT_PARSED ;
2019-06-22 20:22:52 +02:00
for ( int i = col ; i < line . length ( ) ; i + + ) {
if ( line [ i ] = = ' ( ' ) {
2022-08-04 13:11:07 +02:00
if ( expression_pattern = = NOT_PARSED ) {
begin = i ;
expression_pattern = RGBA_PARAMETER ;
} else {
// Method call or '(' appearing twice.
expression_pattern = NOT_PARSED ;
break ;
}
} else if ( expression_pattern = = RGBA_PARAMETER & & line [ i ] = = ' ) ' & & end < 0 ) {
end = i + 1 ;
break ;
} else if ( expression_pattern = = NOT_PARSED & & line [ i ] = = ' . ' ) {
2019-06-22 20:22:52 +02:00
begin = i ;
2022-08-04 13:11:07 +02:00
expression_pattern = COLOR_NAME ;
} else if ( expression_pattern = = COLOR_NAME & & end < 0 & & ( line [ i ] = = ' ' | | line [ i ] = = ' \t ' ) ) {
// Including '.' and spaces.
2019-06-22 20:22:52 +02:00
continue ;
2022-08-04 13:11:07 +02:00
} else if ( expression_pattern = = COLOR_NAME & & ! ( line [ i ] = = ' _ ' | | ( ' A ' < = line [ i ] & & line [ i ] < = ' Z ' ) ) ) {
end = i ;
2019-06-22 20:22:52 +02:00
break ;
2018-01-02 08:10:49 +01:00
}
2019-06-22 20:22:52 +02:00
}
2022-08-04 13:11:07 +02:00
switch ( expression_pattern ) {
case RGBA_PARAMETER : {
color_args = line . substr ( begin , end - begin ) ;
String stripped = color_args . replace ( " " , " " ) . replace ( " \t " , " " ) . replace ( " ( " , " " ) . replace ( " ) " , " " ) ;
PackedFloat64Array color = stripped . split_floats ( " , " ) ;
if ( color . size ( ) > 2 ) {
float alpha = color . size ( ) > 3 ? color [ 3 ] : 1.0f ;
color_picker - > set_pick_color ( Color ( color [ 0 ] , color [ 1 ] , color [ 2 ] , alpha ) ) ;
}
} break ;
case COLOR_NAME : {
if ( end < 0 ) {
end = line . length ( ) ;
}
color_args = line . substr ( begin , end - begin ) ;
const String color_name = color_args . replace ( " " , " " ) . replace ( " \t " , " " ) . replace ( " . " , " " ) ;
const int color_index = Color : : find_named_color ( color_name ) ;
if ( 0 < = color_index ) {
const Color color_constant = Color : : get_named_color ( color_index ) ;
color_picker - > set_pick_color ( color_constant ) ;
} else {
has_color = false ;
}
} break ;
default :
has_color = false ;
break ;
}
if ( has_color ) {
2021-08-31 17:43:35 +02:00
color_panel - > set_position ( get_screen_position ( ) + local_pos ) ;
2016-09-29 09:12:45 +02:00
}
}
2021-07-09 13:42:55 +02:00
_make_context_menu ( tx - > has_selection ( ) , has_color , foldable , open_docs , goto_definition , local_pos ) ;
2016-09-29 09:12:45 +02:00
}
}
void ScriptTextEditor : : _color_changed ( const Color & p_color ) {
String new_args ;
if ( p_color . a = = 1.0f ) {
new_args = String ( " ( " + rtos ( p_color . r ) + " , " + rtos ( p_color . g ) + " , " + rtos ( p_color . b ) + " ) " ) ;
} else {
new_args = String ( " ( " + rtos ( p_color . r ) + " , " + rtos ( p_color . g ) + " , " + rtos ( p_color . b ) + " , " + rtos ( p_color . a ) + " ) " ) ;
}
2020-07-24 16:50:35 +02:00
String line = code_editor - > get_text_editor ( ) - > get_line ( color_position . x ) ;
2021-11-11 09:08:08 +01:00
String line_with_replaced_args = line . replace ( color_args , new_args ) ;
2019-08-02 22:32:33 +02:00
2016-09-29 09:12:45 +02:00
color_args = new_args ;
2020-07-24 16:50:35 +02:00
code_editor - > get_text_editor ( ) - > begin_complex_operation ( ) ;
code_editor - > get_text_editor ( ) - > set_line ( color_position . x , line_with_replaced_args ) ;
code_editor - > get_text_editor ( ) - > end_complex_operation ( ) ;
2022-08-13 23:21:24 +02:00
code_editor - > get_text_editor ( ) - > queue_redraw ( ) ;
2016-09-29 09:12:45 +02:00
}
2021-08-17 05:41:46 +02:00
void ScriptTextEditor : : _prepare_edit_menu ( ) {
const CodeEdit * tx = code_editor - > get_text_editor ( ) ;
PopupMenu * popup = edit_menu - > get_popup ( ) ;
popup - > set_item_disabled ( popup - > get_item_index ( EDIT_UNDO ) , ! tx - > has_undo ( ) ) ;
popup - > set_item_disabled ( popup - > get_item_index ( EDIT_REDO ) , ! tx - > has_redo ( ) ) ;
}
2019-06-22 20:22:52 +02:00
void ScriptTextEditor : : _make_context_menu ( bool p_selection , bool p_color , bool p_foldable , bool p_open_docs , bool p_goto_definition , Vector2 p_pos ) {
2016-09-29 09:12:45 +02:00
context_menu - > clear ( ) ;
2020-12-07 12:32:00 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_undo " ) , EDIT_UNDO ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_redo " ) , EDIT_REDO ) ;
2016-09-29 09:12:45 +02:00
2019-08-12 22:23:00 +02:00
context_menu - > add_separator ( ) ;
2020-12-07 12:32:00 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_cut " ) , EDIT_CUT ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_copy " ) , EDIT_COPY ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_paste " ) , EDIT_PASTE ) ;
2019-08-12 22:23:00 +02:00
2016-09-29 09:12:45 +02:00
context_menu - > add_separator ( ) ;
2020-12-07 12:32:00 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " ui_text_select_all " ) , EDIT_SELECT_ALL ) ;
2019-08-12 22:23:00 +02:00
2017-12-14 10:10:53 +01:00
context_menu - > add_separator ( ) ;
2022-09-29 04:12:52 +02:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/indent " ) , EDIT_INDENT ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/unindent " ) , EDIT_UNINDENT ) ;
2017-12-14 10:10:53 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_comment " ) , EDIT_TOGGLE_COMMENT ) ;
2019-04-20 01:51:25 +02:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_bookmark " ) , BOOKMARK_TOGGLE ) ;
2016-09-29 09:12:45 +02:00
if ( p_selection ) {
context_menu - > add_separator ( ) ;
2017-12-07 09:09:02 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/convert_to_uppercase " ) , EDIT_TO_UPPERCASE ) ;
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/convert_to_lowercase " ) , EDIT_TO_LOWERCASE ) ;
2019-08-07 16:31:33 +02:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/evaluate_selection " ) , EDIT_EVALUATE ) ;
2023-03-12 17:48:37 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/create_code_region " ) , EDIT_CREATE_CODE_REGION ) ;
2016-09-29 09:12:45 +02:00
}
2020-05-14 16:41:43 +02:00
if ( p_foldable ) {
2017-12-08 19:17:10 +01:00
context_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_fold_line " ) , EDIT_TOGGLE_FOLD_LINE ) ;
2020-05-14 16:41:43 +02:00
}
2017-12-08 19:17:10 +01:00
2018-01-02 08:10:49 +01:00
if ( p_color | | p_open_docs | | p_goto_definition ) {
2016-09-29 09:12:45 +02:00
context_menu - > add_separator ( ) ;
2020-05-14 16:41:43 +02:00
if ( p_open_docs ) {
2018-01-02 08:10:49 +01:00
context_menu - > add_item ( TTR ( " Lookup Symbol " ) , LOOKUP_SYMBOL ) ;
2020-05-14 16:41:43 +02:00
}
if ( p_color ) {
2018-01-02 08:10:49 +01:00
context_menu - > add_item ( TTR ( " Pick Color " ) , EDIT_PICK_COLOR ) ;
2020-05-14 16:41:43 +02:00
}
2016-09-29 09:12:45 +02:00
}
2018-01-02 08:10:49 +01:00
2021-08-17 05:41:46 +02:00
const CodeEdit * tx = code_editor - > get_text_editor ( ) ;
context_menu - > set_item_disabled ( context_menu - > get_item_index ( EDIT_UNDO ) , ! tx - > has_undo ( ) ) ;
context_menu - > set_item_disabled ( context_menu - > get_item_index ( EDIT_REDO ) , ! tx - > has_redo ( ) ) ;
2021-08-31 17:43:35 +02:00
context_menu - > set_position ( get_screen_position ( ) + p_pos ) ;
2021-11-20 09:04:57 +01:00
context_menu - > reset_size ( ) ;
2016-09-29 09:12:45 +02:00
context_menu - > popup ( ) ;
}
2016-09-11 16:28:01 +02:00
2019-11-20 10:09:59 +01:00
void ScriptTextEditor : : _enable_code_editor ( ) {
ERR_FAIL_COND ( code_editor - > get_parent ( ) ) ;
2017-10-03 01:33:42 +02:00
2018-07-01 18:17:40 +02:00
VSplitContainer * editor_box = memnew ( VSplitContainer ) ;
add_child ( editor_box ) ;
2022-03-19 01:02:57 +01:00
editor_box - > set_anchors_and_offsets_preset ( Control : : PRESET_FULL_RECT ) ;
2018-07-01 18:17:40 +02:00
editor_box - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
editor_box - > add_child ( code_editor ) ;
2021-05-18 05:09:19 +02:00
code_editor - > connect ( " show_errors_panel " , callable_mp ( this , & ScriptTextEditor : : _show_errors_panel ) ) ;
2019-11-20 10:09:59 +01:00
code_editor - > connect ( " show_warnings_panel " , callable_mp ( this , & ScriptTextEditor : : _show_warnings_panel ) ) ;
2020-02-21 18:28:45 +01:00
code_editor - > connect ( " validate_script " , callable_mp ( this , & ScriptTextEditor : : _validate_script ) ) ;
code_editor - > connect ( " load_theme_settings " , callable_mp ( this , & ScriptTextEditor : : _load_theme_settings ) ) ;
2020-07-24 16:50:35 +02:00
code_editor - > get_text_editor ( ) - > connect ( " symbol_lookup " , callable_mp ( this , & ScriptTextEditor : : _lookup_symbol ) ) ;
code_editor - > get_text_editor ( ) - > connect ( " symbol_validate " , callable_mp ( this , & ScriptTextEditor : : _validate_symbol ) ) ;
2020-07-29 23:26:49 +02:00
code_editor - > get_text_editor ( ) - > connect ( " gutter_added " , callable_mp ( this , & ScriptTextEditor : : _update_gutter_indexes ) ) ;
code_editor - > get_text_editor ( ) - > connect ( " gutter_removed " , callable_mp ( this , & ScriptTextEditor : : _update_gutter_indexes ) ) ;
code_editor - > get_text_editor ( ) - > connect ( " gutter_clicked " , callable_mp ( this , & ScriptTextEditor : : _gutter_clicked ) ) ;
2020-07-24 16:50:35 +02:00
code_editor - > get_text_editor ( ) - > connect ( " gui_input " , callable_mp ( this , & ScriptTextEditor : : _text_edit_gui_input ) ) ;
2019-12-17 09:16:17 +01:00
code_editor - > show_toggle_scripts_button ( ) ;
2020-07-30 12:41:05 +02:00
_update_gutter_indexes ( ) ;
2018-07-01 18:17:40 +02:00
editor_box - > add_child ( warnings_panel ) ;
2020-05-24 14:30:09 +02:00
warnings_panel - > add_theme_font_override (
2023-09-13 13:14:07 +02:00
" normal_font " , EditorNode : : get_singleton ( ) - > get_editor_theme ( ) - > get_font ( SNAME ( " main " ) , EditorStringName ( EditorFonts ) ) ) ;
2020-09-03 13:22:16 +02:00
warnings_panel - > add_theme_font_size_override (
2023-09-13 13:14:07 +02:00
" normal_font_size " , EditorNode : : get_singleton ( ) - > get_editor_theme ( ) - > get_font_size ( SNAME ( " main_size " ) , EditorStringName ( EditorFonts ) ) ) ;
2020-02-21 18:28:45 +01:00
warnings_panel - > connect ( " meta_clicked " , callable_mp ( this , & ScriptTextEditor : : _warning_clicked ) ) ;
2016-09-12 15:52:29 +02:00
2021-05-18 05:09:19 +02:00
editor_box - > add_child ( errors_panel ) ;
errors_panel - > add_theme_font_override (
2023-09-13 13:14:07 +02:00
" normal_font " , EditorNode : : get_singleton ( ) - > get_editor_theme ( ) - > get_font ( SNAME ( " main " ) , EditorStringName ( EditorFonts ) ) ) ;
2021-05-18 05:09:19 +02:00
errors_panel - > add_theme_font_size_override (
2023-09-13 13:14:07 +02:00
" normal_font_size " , EditorNode : : get_singleton ( ) - > get_editor_theme ( ) - > get_font_size ( SNAME ( " main_size " ) , EditorStringName ( EditorFonts ) ) ) ;
2021-05-18 05:09:19 +02:00
errors_panel - > connect ( " meta_clicked " , callable_mp ( this , & ScriptTextEditor : : _error_clicked ) ) ;
2016-09-29 09:12:45 +02:00
add_child ( context_menu ) ;
2020-02-21 18:28:45 +01:00
context_menu - > connect ( " id_pressed " , callable_mp ( this , & ScriptTextEditor : : _edit_option ) ) ;
2016-09-29 09:12:45 +02:00
add_child ( color_panel ) ;
2019-11-20 10:09:59 +01:00
2016-09-29 09:12:45 +02:00
color_picker = memnew ( ColorPicker ) ;
2019-08-02 22:32:33 +02:00
color_picker - > set_deferred_mode ( true ) ;
2020-02-21 18:28:45 +01:00
color_picker - > connect ( " color_changed " , callable_mp ( this , & ScriptTextEditor : : _color_changed ) ) ;
2022-07-28 22:56:41 +02:00
color_panel - > connect ( " about_to_popup " , callable_mp ( EditorNode : : get_singleton ( ) , & EditorNode : : setup_color_picker ) . bind ( color_picker ) ) ;
2016-09-12 15:52:29 +02:00
2019-11-20 10:09:59 +01:00
color_panel - > add_child ( color_picker ) ;
quick_open = memnew ( ScriptEditorQuickOpen ) ;
quick_open - > connect ( " goto_line " , callable_mp ( this , & ScriptTextEditor : : _goto_line ) ) ;
add_child ( quick_open ) ;
2016-08-03 00:11:05 +02:00
2019-11-20 10:09:59 +01:00
goto_line_dialog = memnew ( GotoLineDialog ) ;
add_child ( goto_line_dialog ) ;
add_child ( connection_info_dialog ) ;
edit_hb - > add_child ( edit_menu ) ;
2021-08-17 05:41:46 +02:00
edit_menu - > connect ( " about_to_popup " , callable_mp ( this , & ScriptTextEditor : : _prepare_edit_menu ) ) ;
2020-12-07 12:32:00 +01:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_undo " ) , EDIT_UNDO ) ;
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_redo " ) , EDIT_REDO ) ;
2016-08-03 00:11:05 +02:00
edit_menu - > get_popup ( ) - > add_separator ( ) ;
2020-12-07 12:32:00 +01:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_cut " ) , EDIT_CUT ) ;
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_copy " ) , EDIT_COPY ) ;
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_paste " ) , EDIT_PASTE ) ;
2016-08-03 00:11:05 +02:00
edit_menu - > get_popup ( ) - > add_separator ( ) ;
2020-12-07 12:32:00 +01:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_text_select_all " ) , EDIT_SELECT_ALL ) ;
2022-08-11 17:15:15 +02:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/duplicate_selection " ) , EDIT_DUPLICATE_SELECTION ) ;
2022-09-28 17:09:45 +02:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/duplicate_lines " ) , EDIT_DUPLICATE_LINES ) ;
2022-08-11 17:15:15 +02:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/evaluate_selection " ) , EDIT_EVALUATE ) ;
2023-04-19 23:46:22 +02:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_word_wrap " ) , EDIT_TOGGLE_WORD_WRAP ) ;
2016-08-03 00:11:05 +02:00
edit_menu - > get_popup ( ) - > add_separator ( ) ;
2022-08-11 17:15:15 +02:00
{
PopupMenu * sub_menu = memnew ( PopupMenu ) ;
sub_menu - > set_name ( " line_menu " ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/move_up " ) , EDIT_MOVE_LINE_UP ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/move_down " ) , EDIT_MOVE_LINE_DOWN ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/indent " ) , EDIT_INDENT ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/unindent " ) , EDIT_UNINDENT ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/delete_line " ) , EDIT_DELETE_LINE ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_comment " ) , EDIT_TOGGLE_COMMENT ) ;
sub_menu - > connect ( " id_pressed " , callable_mp ( this , & ScriptTextEditor : : _edit_option ) ) ;
edit_menu - > get_popup ( ) - > add_child ( sub_menu ) ;
edit_menu - > get_popup ( ) - > add_submenu_item ( TTR ( " Line " ) , " line_menu " ) ;
}
{
PopupMenu * sub_menu = memnew ( PopupMenu ) ;
sub_menu - > set_name ( " folding_menu " ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/toggle_fold_line " ) , EDIT_TOGGLE_FOLD_LINE ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/fold_all_lines " ) , EDIT_FOLD_ALL_LINES ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/unfold_all_lines " ) , EDIT_UNFOLD_ALL_LINES ) ;
2023-03-12 17:48:37 +01:00
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/create_code_region " ) , EDIT_CREATE_CODE_REGION ) ;
2022-08-11 17:15:15 +02:00
sub_menu - > connect ( " id_pressed " , callable_mp ( this , & ScriptTextEditor : : _edit_option ) ) ;
edit_menu - > get_popup ( ) - > add_child ( sub_menu ) ;
edit_menu - > get_popup ( ) - > add_submenu_item ( TTR ( " Folding " ) , " folding_menu " ) ;
}
2016-08-03 00:11:05 +02:00
edit_menu - > get_popup ( ) - > add_separator ( ) ;
2020-12-07 12:32:00 +01:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " ui_text_completion_query " ) , EDIT_COMPLETE ) ;
2016-08-03 00:11:05 +02:00
edit_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/trim_trailing_whitespace " ) , EDIT_TRIM_TRAILING_WHITESAPCE ) ;
2022-08-11 17:15:15 +02:00
{
PopupMenu * sub_menu = memnew ( PopupMenu ) ;
sub_menu - > set_name ( " indent_menu " ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/convert_indent_to_spaces " ) , EDIT_CONVERT_INDENT_TO_SPACES ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/convert_indent_to_tabs " ) , EDIT_CONVERT_INDENT_TO_TABS ) ;
sub_menu - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/auto_indent " ) , EDIT_AUTO_INDENT ) ;
sub_menu - > connect ( " id_pressed " , callable_mp ( this , & ScriptTextEditor : : _edit_option ) ) ;
edit_menu - > get_popup ( ) - > add_child ( sub_menu ) ;
edit_menu - > get_popup ( ) - > add_submenu_item ( TTR ( " Indentation " ) , " indent_menu " ) ;
}
2020-02-21 18:28:45 +01:00
edit_menu - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & ScriptTextEditor : : _edit_option ) ) ;
2016-08-03 00:11:05 +02:00
edit_menu - > get_popup ( ) - > add_separator ( ) ;
2022-08-11 17:15:15 +02:00
{
PopupMenu * sub_menu = memnew ( PopupMenu ) ;
sub_menu - > set_name ( " convert_case " ) ;
sub_menu - > add_shortcut ( ED_SHORTCUT ( " script_text_editor/convert_to_uppercase " , TTR ( " Uppercase " ) , KeyModifierMask : : SHIFT | Key : : F4 ) , EDIT_TO_UPPERCASE ) ;
sub_menu - > add_shortcut ( ED_SHORTCUT ( " script_text_editor/convert_to_lowercase " , TTR ( " Lowercase " ) , KeyModifierMask : : SHIFT | Key : : F5 ) , EDIT_TO_LOWERCASE ) ;
sub_menu - > add_shortcut ( ED_SHORTCUT ( " script_text_editor/capitalize " , TTR ( " Capitalize " ) , KeyModifierMask : : SHIFT | Key : : F6 ) , EDIT_CAPITALIZE ) ;
sub_menu - > connect ( " id_pressed " , callable_mp ( this , & ScriptTextEditor : : _edit_option ) ) ;
edit_menu - > get_popup ( ) - > add_child ( sub_menu ) ;
edit_menu - > get_popup ( ) - > add_submenu_item ( TTR ( " Convert Case " ) , " convert_case " ) ;
}
2018-06-01 21:32:19 +02:00
edit_menu - > get_popup ( ) - > add_child ( highlighter_menu ) ;
edit_menu - > get_popup ( ) - > add_submenu_item ( TTR ( " Syntax Highlighter " ) , " highlighter_menu " ) ;
2020-02-21 18:28:45 +01:00
highlighter_menu - > connect ( " id_pressed " , callable_mp ( this , & ScriptTextEditor : : _change_syntax_highlighter ) ) ;
2018-06-01 21:32:19 +02:00
2022-08-11 17:15:15 +02:00
edit_hb - > add_child ( search_menu ) ;
search_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/find " ) , SEARCH_FIND ) ;
search_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/find_next " ) , SEARCH_FIND_NEXT ) ;
search_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/find_previous " ) , SEARCH_FIND_PREV ) ;
search_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/replace " ) , SEARCH_REPLACE ) ;
search_menu - > get_popup ( ) - > add_separator ( ) ;
search_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/find_in_files " ) , SEARCH_IN_FILES ) ;
search_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/replace_in_files " ) , REPLACE_IN_FILES ) ;
search_menu - > get_popup ( ) - > add_separator ( ) ;
search_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/contextual_help " ) , HELP_CONTEXTUAL ) ;
search_menu - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & ScriptTextEditor : : _edit_option ) ) ;
2019-11-20 10:09:59 +01:00
_load_theme_settings ( ) ;
edit_hb - > add_child ( goto_menu ) ;
goto_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/goto_function " ) , SEARCH_LOCATE_FUNCTION ) ;
goto_menu - > get_popup ( ) - > add_shortcut ( ED_GET_SHORTCUT ( " script_text_editor/goto_line " ) , SEARCH_GOTO_LINE ) ;
goto_menu - > get_popup ( ) - > add_separator ( ) ;
goto_menu - > get_popup ( ) - > add_child ( bookmarks_menu ) ;
goto_menu - > get_popup ( ) - > add_submenu_item ( TTR ( " Bookmarks " ) , " Bookmarks " ) ;
_update_bookmark_list ( ) ;
bookmarks_menu - > connect ( " about_to_popup " , callable_mp ( this , & ScriptTextEditor : : _update_bookmark_list ) ) ;
bookmarks_menu - > connect ( " index_pressed " , callable_mp ( this , & ScriptTextEditor : : _bookmark_item_pressed ) ) ;
goto_menu - > get_popup ( ) - > add_child ( breakpoints_menu ) ;
goto_menu - > get_popup ( ) - > add_submenu_item ( TTR ( " Breakpoints " ) , " Breakpoints " ) ;
_update_breakpoint_list ( ) ;
breakpoints_menu - > connect ( " about_to_popup " , callable_mp ( this , & ScriptTextEditor : : _update_breakpoint_list ) ) ;
breakpoints_menu - > connect ( " index_pressed " , callable_mp ( this , & ScriptTextEditor : : _breakpoint_item_pressed ) ) ;
goto_menu - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & ScriptTextEditor : : _edit_option ) ) ;
}
ScriptTextEditor : : ScriptTextEditor ( ) {
code_editor = memnew ( CodeTextEditor ) ;
2022-02-08 10:14:58 +01:00
code_editor - > add_theme_constant_override ( " separation " , 2 ) ;
2022-03-19 01:02:57 +01:00
code_editor - > set_anchors_and_offsets_preset ( Control : : PRESET_FULL_RECT ) ;
2019-11-20 10:09:59 +01:00
code_editor - > set_code_complete_func ( _code_complete_scripts , this ) ;
code_editor - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2020-07-30 13:22:09 +02:00
code_editor - > get_text_editor ( ) - > set_draw_breakpoints_gutter ( true ) ;
code_editor - > get_text_editor ( ) - > set_draw_executing_lines_gutter ( true ) ;
2021-10-07 20:46:44 +02:00
code_editor - > get_text_editor ( ) - > connect ( " breakpoint_toggled " , callable_mp ( this , & ScriptTextEditor : : _breakpoint_toggled ) ) ;
2020-07-30 13:22:09 +02:00
2020-07-29 23:26:49 +02:00
connection_gutter = 1 ;
code_editor - > get_text_editor ( ) - > add_gutter ( connection_gutter ) ;
code_editor - > get_text_editor ( ) - > set_gutter_name ( connection_gutter , " connection_gutter " ) ;
code_editor - > get_text_editor ( ) - > set_gutter_draw ( connection_gutter , false ) ;
code_editor - > get_text_editor ( ) - > set_gutter_overwritable ( connection_gutter , true ) ;
2021-07-19 10:16:00 +02:00
code_editor - > get_text_editor ( ) - > set_gutter_type ( connection_gutter , TextEdit : : GUTTER_TYPE_ICON ) ;
2020-07-29 23:26:49 +02:00
2019-11-20 10:09:59 +01:00
warnings_panel = memnew ( RichTextLabel ) ;
warnings_panel - > set_custom_minimum_size ( Size2 ( 0 , 100 * EDSCALE ) ) ;
warnings_panel - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
warnings_panel - > set_meta_underline ( true ) ;
warnings_panel - > set_selection_enabled ( true ) ;
2023-02-28 14:19:48 +01:00
warnings_panel - > set_context_menu_enabled ( true ) ;
2019-11-20 10:09:59 +01:00
warnings_panel - > set_focus_mode ( FOCUS_CLICK ) ;
warnings_panel - > hide ( ) ;
2021-05-18 05:09:19 +02:00
errors_panel = memnew ( RichTextLabel ) ;
errors_panel - > set_custom_minimum_size ( Size2 ( 0 , 100 * EDSCALE ) ) ;
errors_panel - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
errors_panel - > set_meta_underline ( true ) ;
errors_panel - > set_selection_enabled ( true ) ;
2023-02-28 14:19:48 +01:00
errors_panel - > set_context_menu_enabled ( true ) ;
2021-05-18 05:09:19 +02:00
errors_panel - > set_focus_mode ( FOCUS_CLICK ) ;
errors_panel - > hide ( ) ;
2019-11-20 10:09:59 +01:00
update_settings ( ) ;
2022-10-18 16:43:37 +02:00
code_editor - > get_text_editor ( ) - > set_code_hint_draw_below ( EDITOR_GET ( " text_editor/completion/put_callhint_tooltip_below_current_line " ) ) ;
2019-11-20 10:09:59 +01:00
2021-07-01 18:10:54 +02:00
code_editor - > get_text_editor ( ) - > set_symbol_lookup_on_click_enabled ( true ) ;
2020-07-24 16:50:35 +02:00
code_editor - > get_text_editor ( ) - > set_context_menu_enabled ( false ) ;
2019-11-20 10:09:59 +01:00
context_menu = memnew ( PopupMenu ) ;
color_panel = memnew ( PopupPanel ) ;
edit_hb = memnew ( HBoxContainer ) ;
edit_menu = memnew ( MenuButton ) ;
edit_menu - > set_text ( TTR ( " Edit " ) ) ;
edit_menu - > set_switch_on_hover ( true ) ;
2020-09-17 03:40:00 +02:00
edit_menu - > set_shortcut_context ( this ) ;
2019-11-20 10:09:59 +01:00
highlighter_menu = memnew ( PopupMenu ) ;
highlighter_menu - > set_name ( " highlighter_menu " ) ;
2020-05-03 18:08:15 +02:00
Ref < EditorPlainTextSyntaxHighlighter > plain_highlighter ;
2021-06-18 00:03:09 +02:00
plain_highlighter . instantiate ( ) ;
2020-05-03 18:08:15 +02:00
add_syntax_highlighter ( plain_highlighter ) ;
Ref < EditorStandardSyntaxHighlighter > highlighter ;
2021-06-18 00:03:09 +02:00
highlighter . instantiate ( ) ;
2020-05-03 18:08:15 +02:00
add_syntax_highlighter ( highlighter ) ;
set_syntax_highlighter ( highlighter ) ;
2016-08-03 00:11:05 +02:00
search_menu = memnew ( MenuButton ) ;
search_menu - > set_text ( TTR ( " Search " ) ) ;
2018-07-30 00:26:43 +02:00
search_menu - > set_switch_on_hover ( true ) ;
2020-09-17 03:40:00 +02:00
search_menu - > set_shortcut_context ( this ) ;
2020-03-12 13:37:40 +01:00
2019-11-20 10:09:59 +01:00
goto_menu = memnew ( MenuButton ) ;
2019-07-01 21:00:05 +02:00
goto_menu - > set_text ( TTR ( " Go To " ) ) ;
goto_menu - > set_switch_on_hover ( true ) ;
2020-09-17 03:40:00 +02:00
goto_menu - > set_shortcut_context ( this ) ;
2019-07-01 21:00:05 +02:00
bookmarks_menu = memnew ( PopupMenu ) ;
bookmarks_menu - > set_name ( " Bookmarks " ) ;
breakpoints_menu = memnew ( PopupMenu ) ;
breakpoints_menu - > set_name ( " Breakpoints " ) ;
2016-09-11 16:28:01 +02:00
2019-04-20 13:51:25 +02:00
connection_info_dialog = memnew ( ConnectionInfoDialog ) ;
2023-01-22 17:07:55 +01:00
SET_DRAG_FORWARDING_GCD ( code_editor - > get_text_editor ( ) , ScriptTextEditor ) ;
2016-08-03 00:11:05 +02:00
}
2019-07-25 18:30:48 +02:00
ScriptTextEditor : : ~ ScriptTextEditor ( ) {
highlighters . clear ( ) ;
2019-11-20 10:09:59 +01:00
if ( ! editor_enabled ) {
memdelete ( code_editor ) ;
memdelete ( warnings_panel ) ;
2021-05-18 05:09:19 +02:00
memdelete ( errors_panel ) ;
2019-11-20 10:09:59 +01:00
memdelete ( context_menu ) ;
memdelete ( color_panel ) ;
memdelete ( edit_hb ) ;
memdelete ( edit_menu ) ;
memdelete ( highlighter_menu ) ;
memdelete ( search_menu ) ;
memdelete ( goto_menu ) ;
memdelete ( bookmarks_menu ) ;
memdelete ( breakpoints_menu ) ;
memdelete ( connection_info_dialog ) ;
}
2019-07-25 18:30:48 +02:00
}
2022-05-03 01:43:50 +02:00
static ScriptEditorBase * create_editor ( const Ref < Resource > & p_resource ) {
2018-05-28 17:52:28 +02:00
if ( Object : : cast_to < Script > ( * p_resource ) ) {
return memnew ( ScriptTextEditor ) ;
}
2020-04-02 01:20:12 +02:00
return nullptr ;
2016-08-03 00:11:05 +02:00
}
void ScriptTextEditor : : register_editor ( ) {
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " script_text_editor/move_up " , TTR ( " Move Up " ) , KeyModifierMask : : ALT | Key : : UP ) ;
ED_SHORTCUT ( " script_text_editor/move_down " , TTR ( " Move Down " ) , KeyModifierMask : : ALT | Key : : DOWN ) ;
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " script_text_editor/delete_line " , TTR ( " Delete Line " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : K ) ;
2017-01-04 21:37:45 +01:00
2019-08-09 03:36:51 +02:00
// Leave these at zero, same can be accomplished with tab/shift-tab, including selection.
// The next/previous in history shortcut in this case makes a lot more sense.
2017-01-04 21:37:45 +01:00
2022-09-29 04:12:52 +02:00
ED_SHORTCUT ( " script_text_editor/indent " , TTR ( " Indent " ) , Key : : NONE ) ;
ED_SHORTCUT ( " script_text_editor/unindent " , TTR ( " Unindent " ) , KeyModifierMask : : SHIFT | Key : : TAB ) ;
2023-07-18 14:00:59 +02:00
ED_SHORTCUT_ARRAY ( " script_text_editor/toggle_comment " , TTR ( " Toggle Comment " ) , { int32_t ( KeyModifierMask : : CMD_OR_CTRL | Key : : K ) , int32_t ( KeyModifierMask : : CMD_OR_CTRL | Key : : SLASH ) } ) ;
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " script_text_editor/toggle_fold_line " , TTR ( " Fold/Unfold Line " ) , KeyModifierMask : : ALT | Key : : F ) ;
2023-02-16 10:28:04 +01:00
ED_SHORTCUT_OVERRIDE ( " script_text_editor/toggle_fold_line " , " macos " , KeyModifierMask : : CTRL | KeyModifierMask : : META | Key : : F ) ;
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " script_text_editor/fold_all_lines " , TTR ( " Fold All Lines " ) , Key : : NONE ) ;
2023-03-12 17:48:37 +01:00
ED_SHORTCUT ( " script_text_editor/create_code_region " , TTR ( " Create Code Region " ) , KeyModifierMask : : ALT | Key : : R ) ;
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " script_text_editor/unfold_all_lines " , TTR ( " Unfold All Lines " ) , Key : : NONE ) ;
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " script_text_editor/duplicate_selection " , TTR ( " Duplicate Selection " ) , KeyModifierMask : : SHIFT | KeyModifierMask : : CTRL | Key : : D ) ;
ED_SHORTCUT_OVERRIDE ( " script_text_editor/duplicate_selection " , " macos " , KeyModifierMask : : SHIFT | KeyModifierMask : : META | Key : : C ) ;
2022-09-28 17:09:45 +02:00
ED_SHORTCUT ( " script_text_editor/duplicate_lines " , TTR ( " Duplicate Lines " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : ALT | Key : : DOWN ) ;
ED_SHORTCUT_OVERRIDE ( " script_text_editor/duplicate_lines " , " macos " , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : DOWN ) ;
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " script_text_editor/evaluate_selection " , TTR ( " Evaluate Selection " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : E ) ;
2023-04-19 23:46:22 +02:00
ED_SHORTCUT ( " script_text_editor/toggle_word_wrap " , TTR ( " Toggle Word Wrap " ) , KeyModifierMask : : ALT | Key : : Z ) ;
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " script_text_editor/trim_trailing_whitespace " , TTR ( " Trim Trailing Whitespace " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : ALT | Key : : T ) ;
ED_SHORTCUT ( " script_text_editor/convert_indent_to_spaces " , TTR ( " Convert Indent to Spaces " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : Y ) ;
ED_SHORTCUT ( " script_text_editor/convert_indent_to_tabs " , TTR ( " Convert Indent to Tabs " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : I ) ;
ED_SHORTCUT ( " script_text_editor/auto_indent " , TTR ( " Auto Indent " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : I ) ;
2016-08-03 00:11:05 +02:00
2022-09-02 11:37:48 +02:00
ED_SHORTCUT_AND_COMMAND ( " script_text_editor/find " , TTR ( " Find... " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : F ) ;
2021-08-08 05:52:00 +02:00
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " script_text_editor/find_next " , TTR ( " Find Next " ) , Key : : F3 ) ;
2022-09-02 11:37:48 +02:00
ED_SHORTCUT_OVERRIDE ( " script_text_editor/find_next " , " macos " , KeyModifierMask : : META | Key : : G ) ;
2021-08-08 05:52:00 +02:00
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " script_text_editor/find_previous " , TTR ( " Find Previous " ) , KeyModifierMask : : SHIFT | Key : : F3 ) ;
2022-09-02 11:37:48 +02:00
ED_SHORTCUT_OVERRIDE ( " script_text_editor/find_previous " , " macos " , KeyModifierMask : : META | KeyModifierMask : : SHIFT | Key : : G ) ;
2021-08-08 05:52:00 +02:00
2022-09-02 11:37:48 +02:00
ED_SHORTCUT_AND_COMMAND ( " script_text_editor/replace " , TTR ( " Replace... " ) , KeyModifierMask : : CTRL | Key : : R ) ;
ED_SHORTCUT_OVERRIDE ( " script_text_editor/replace " , " macos " , KeyModifierMask : : ALT | KeyModifierMask : : META | Key : : F ) ;
2016-08-03 00:11:05 +02:00
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " script_text_editor/find_in_files " , TTR ( " Find in Files... " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : F ) ;
ED_SHORTCUT ( " script_text_editor/replace_in_files " , TTR ( " Replace in Files... " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : R ) ;
2018-02-12 02:36:15 +01:00
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " script_text_editor/contextual_help " , TTR ( " Contextual Help " ) , KeyModifierMask : : ALT | Key : : F1 ) ;
ED_SHORTCUT_OVERRIDE ( " script_text_editor/contextual_help " , " macos " , KeyModifierMask : : ALT | KeyModifierMask : : SHIFT | Key : : SPACE ) ;
2019-08-09 03:36:51 +02:00
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " script_text_editor/toggle_bookmark " , TTR ( " Toggle Bookmark " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : ALT | Key : : B ) ;
ED_SHORTCUT ( " script_text_editor/goto_next_bookmark " , TTR ( " Go to Next Bookmark " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : B ) ;
ED_SHORTCUT ( " script_text_editor/goto_previous_bookmark " , TTR ( " Go to Previous Bookmark " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : B ) ;
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " script_text_editor/remove_all_bookmarks " , TTR ( " Remove All Bookmarks " ) , Key : : NONE ) ;
2019-08-09 03:36:51 +02:00
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " script_text_editor/goto_function " , TTR ( " Go to Function... " ) , KeyModifierMask : : ALT | KeyModifierMask : : CTRL | Key : : F ) ;
ED_SHORTCUT_OVERRIDE ( " script_text_editor/goto_function " , " macos " , KeyModifierMask : : CTRL | KeyModifierMask : : META | Key : : J ) ;
2021-08-08 05:52:00 +02:00
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " script_text_editor/goto_line " , TTR ( " Go to Line... " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : L ) ;
2016-08-03 00:11:05 +02:00
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " script_text_editor/toggle_breakpoint " , TTR ( " Toggle Breakpoint " ) , Key : : F9 ) ;
2022-09-02 11:37:48 +02:00
ED_SHORTCUT_OVERRIDE ( " script_text_editor/toggle_breakpoint " , " macos " , KeyModifierMask : : META | KeyModifierMask : : SHIFT | Key : : B ) ;
2021-08-08 05:52:00 +02:00
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " script_text_editor/remove_all_breakpoints " , TTR ( " Remove All Breakpoints " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : F9 ) ;
ED_SHORTCUT ( " script_text_editor/goto_next_breakpoint " , TTR ( " Go to Next Breakpoint " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : PERIOD ) ;
ED_SHORTCUT ( " script_text_editor/goto_previous_breakpoint " , TTR ( " Go to Previous Breakpoint " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : COMMA ) ;
2016-08-03 00:11:05 +02:00
ScriptEditor : : register_create_script_editor_function ( create_editor ) ;
}
2019-05-08 18:49:49 +02:00
void ScriptTextEditor : : validate ( ) {
this - > code_editor - > validate_script ( ) ;
}