1 | /**************************************************************************/ |
2 | /* code_edit.h */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #ifndef CODE_EDIT_H |
32 | #define CODE_EDIT_H |
33 | |
34 | #include "core/object/script_language.h" |
35 | #include "scene/gui/text_edit.h" |
36 | |
37 | class CodeEdit : public TextEdit { |
38 | GDCLASS(CodeEdit, TextEdit) |
39 | |
40 | public: |
41 | // Keep enums in sync with: |
42 | // core/object/script_language.h - ScriptLanguage::CodeCompletionKind |
43 | enum CodeCompletionKind { |
44 | KIND_CLASS, |
45 | KIND_FUNCTION, |
46 | KIND_SIGNAL, |
47 | KIND_VARIABLE, |
48 | KIND_MEMBER, |
49 | KIND_ENUM, |
50 | KIND_CONSTANT, |
51 | KIND_NODE_PATH, |
52 | KIND_FILE_PATH, |
53 | KIND_PLAIN_TEXT, |
54 | }; |
55 | |
56 | // core/object/script_language.h - ScriptLanguage::CodeCompletionLocation |
57 | enum CodeCompletionLocation { |
58 | LOCATION_LOCAL = 0, |
59 | LOCATION_PARENT_MASK = 1 << 8, |
60 | LOCATION_OTHER_USER_CODE = 1 << 9, |
61 | LOCATION_OTHER = 1 << 10, |
62 | }; |
63 | |
64 | private: |
65 | /* Indent management */ |
66 | int indent_size = 4; |
67 | String indent_text = "\t" ; |
68 | |
69 | bool auto_indent = false; |
70 | HashSet<char32_t> auto_indent_prefixes; |
71 | |
72 | bool indent_using_spaces = false; |
73 | int _calculate_spaces_till_next_left_indent(int p_column) const; |
74 | int _calculate_spaces_till_next_right_indent(int p_column) const; |
75 | |
76 | void _new_line(bool p_split_current_line = true, bool p_above = false); |
77 | |
78 | /* Auto brace completion */ |
79 | bool auto_brace_completion_enabled = false; |
80 | |
81 | /* BracePair open_key must be uniquie and ordered by length. */ |
82 | struct BracePair { |
83 | String open_key = "" ; |
84 | String close_key = "" ; |
85 | }; |
86 | Vector<BracePair> auto_brace_completion_pairs; |
87 | |
88 | int _get_auto_brace_pair_open_at_pos(int p_line, int p_col); |
89 | int _get_auto_brace_pair_close_at_pos(int p_line, int p_col); |
90 | |
91 | /* Main Gutter */ |
92 | enum MainGutterType { |
93 | MAIN_GUTTER_BREAKPOINT = 0x01, |
94 | MAIN_GUTTER_BOOKMARK = 0x02, |
95 | MAIN_GUTTER_EXECUTING = 0x04 |
96 | }; |
97 | |
98 | int main_gutter = -1; |
99 | void _update_draw_main_gutter(); |
100 | void _main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region); |
101 | |
102 | // breakpoints |
103 | HashMap<int, bool> breakpointed_lines; |
104 | bool draw_breakpoints = false; |
105 | |
106 | // bookmarks |
107 | bool draw_bookmarks = false; |
108 | |
109 | // executing lines |
110 | bool draw_executing_lines = false; |
111 | |
112 | /* Line numbers */ |
113 | int line_number_gutter = -1; |
114 | int line_number_digits = 1; |
115 | String line_number_padding = " " ; |
116 | void _line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region); |
117 | |
118 | /* Fold Gutter */ |
119 | int fold_gutter = -1; |
120 | bool draw_fold_gutter = false; |
121 | void _fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_region); |
122 | |
123 | void _gutter_clicked(int p_line, int p_gutter); |
124 | void _update_gutter_indexes(); |
125 | |
126 | /* Line Folding */ |
127 | bool line_folding_enabled = false; |
128 | String code_region_start_string; |
129 | String code_region_end_string; |
130 | String code_region_start_tag = "region" ; |
131 | String code_region_end_tag = "endregion" ; |
132 | void _update_code_region_tags(); |
133 | |
134 | /* Delimiters */ |
135 | enum DelimiterType { |
136 | TYPE_STRING, |
137 | , |
138 | }; |
139 | |
140 | struct Delimiter { |
141 | DelimiterType type; |
142 | String start_key = "" ; |
143 | String end_key = "" ; |
144 | bool line_only = true; |
145 | }; |
146 | bool setting_delimiters = false; |
147 | Vector<Delimiter> delimiters; |
148 | /* |
149 | * Vector entry per line, contains a Map of column numbers to delimiter index, -1 marks the end of a region. |
150 | * e.g the following text will be stored as so: |
151 | * |
152 | * 0: nothing here |
153 | * 1: |
154 | * 2: # test |
155 | * 3: "test" text "multiline |
156 | * 4: |
157 | * 5: test |
158 | * 6: string" |
159 | * |
160 | * Vector [ |
161 | * 0 = [] |
162 | * 1 = [] |
163 | * 2 = [ |
164 | * 1 = 1 |
165 | * 6 = -1 |
166 | * ] |
167 | * 3 = [ |
168 | * 1 = 0 |
169 | * 6 = -1 |
170 | * 13 = 0 |
171 | * ] |
172 | * 4 = [ |
173 | * 0 = 0 |
174 | * ] |
175 | * 5 = [ |
176 | * 5 = 0 |
177 | * ] |
178 | * 6 = [ |
179 | * 7 = -1 |
180 | * ] |
181 | * ] |
182 | */ |
183 | Vector<RBMap<int, int>> delimiter_cache; |
184 | |
185 | void _update_delimiter_cache(int p_from_line = 0, int p_to_line = -1); |
186 | int _is_in_delimiter(int p_line, int p_column, DelimiterType p_type) const; |
187 | |
188 | void _add_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only, DelimiterType p_type); |
189 | void _remove_delimiter(const String &p_start_key, DelimiterType p_type); |
190 | bool _has_delimiter(const String &p_start_key, DelimiterType p_type) const; |
191 | |
192 | void _set_delimiters(const TypedArray<String> &p_delimiters, DelimiterType p_type); |
193 | void _clear_delimiters(DelimiterType p_type); |
194 | TypedArray<String> _get_delimiters(DelimiterType p_type) const; |
195 | |
196 | /* Code Hint */ |
197 | String code_hint = "" ; |
198 | |
199 | bool code_hint_draw_below = true; |
200 | int code_hint_xpos = -0xFFFF; |
201 | |
202 | /* Code Completion */ |
203 | bool code_completion_enabled = false; |
204 | bool code_completion_forced = false; |
205 | |
206 | bool code_completion_active = false; |
207 | bool is_code_completion_scroll_hovered = false; |
208 | bool is_code_completion_scroll_pressed = false; |
209 | bool is_code_completion_drag_started = false; |
210 | Vector<ScriptLanguage::CodeCompletionOption> code_completion_options; |
211 | int code_completion_line_ofs = 0; |
212 | int code_completion_current_selected = 0; |
213 | int code_completion_force_item_center = -1; |
214 | int code_completion_longest_line = 0; |
215 | Rect2i code_completion_rect; |
216 | Rect2i code_completion_scroll_rect; |
217 | |
218 | HashSet<char32_t> code_completion_prefixes; |
219 | List<ScriptLanguage::CodeCompletionOption> code_completion_option_submitted; |
220 | List<ScriptLanguage::CodeCompletionOption> code_completion_option_sources; |
221 | String code_completion_base; |
222 | |
223 | void _update_scroll_selected_line(float p_mouse_y); |
224 | void _filter_code_completion_candidates_impl(); |
225 | |
226 | /* Line length guidelines */ |
227 | TypedArray<int> line_length_guideline_columns; |
228 | |
229 | /* Symbol lookup */ |
230 | bool symbol_lookup_on_click_enabled = false; |
231 | |
232 | String symbol_lookup_new_word = "" ; |
233 | String symbol_lookup_word = "" ; |
234 | Point2i symbol_lookup_pos; |
235 | |
236 | /* Visual */ |
237 | struct ThemeCache { |
238 | /* Gutters */ |
239 | Color code_folding_color = Color(1, 1, 1); |
240 | Color folded_code_region_color = Color(1, 1, 1); |
241 | Ref<Texture2D> can_fold_icon; |
242 | Ref<Texture2D> folded_icon; |
243 | Ref<Texture2D> can_fold_code_region_icon; |
244 | Ref<Texture2D> folded_code_region_icon; |
245 | Ref<Texture2D> folded_eol_icon; |
246 | |
247 | Color breakpoint_color = Color(1, 1, 1); |
248 | Ref<Texture2D> breakpoint_icon = Ref<Texture2D>(); |
249 | |
250 | Color bookmark_color = Color(1, 1, 1); |
251 | Ref<Texture2D> bookmark_icon = Ref<Texture2D>(); |
252 | |
253 | Color executing_line_color = Color(1, 1, 1); |
254 | Ref<Texture2D> executing_line_icon = Ref<Texture2D>(); |
255 | |
256 | Color line_number_color = Color(1, 1, 1); |
257 | |
258 | /* Code Completion */ |
259 | Ref<StyleBox> code_completion_style; |
260 | int code_completion_icon_separation = 0; |
261 | |
262 | int code_completion_max_width = 0; |
263 | int code_completion_max_lines = 7; |
264 | int code_completion_scroll_width = 0; |
265 | Color code_completion_scroll_color = Color(0, 0, 0, 0); |
266 | Color code_completion_scroll_hovered_color = Color(0, 0, 0, 0); |
267 | Color code_completion_background_color = Color(0, 0, 0, 0); |
268 | Color code_completion_selected_color = Color(0, 0, 0, 0); |
269 | Color code_completion_existing_color = Color(0, 0, 0, 0); |
270 | |
271 | /* Code hint */ |
272 | Ref<StyleBox> code_hint_style; |
273 | Color code_hint_color; |
274 | |
275 | /* Line length guideline */ |
276 | Color line_length_guideline_color; |
277 | |
278 | /* Other visuals */ |
279 | Ref<StyleBox> style_normal; |
280 | |
281 | Color brace_mismatch_color; |
282 | |
283 | Ref<Font> font; |
284 | int font_size = 16; |
285 | int line_spacing = 1; |
286 | } theme_cache; |
287 | |
288 | virtual Color _get_brace_mismatch_color() const override; |
289 | virtual Color _get_code_folding_color() const override; |
290 | virtual Ref<Texture2D> _get_folded_eol_icon() const override; |
291 | |
292 | /* Callbacks */ |
293 | int lines_edited_changed = 0; |
294 | int lines_edited_from = -1; |
295 | int lines_edited_to = -1; |
296 | |
297 | void _lines_edited_from(int p_from_line, int p_to_line); |
298 | void _text_set(); |
299 | void _text_changed(); |
300 | |
301 | protected: |
302 | void _notification(int p_what); |
303 | static void _bind_methods(); |
304 | |
305 | #ifndef DISABLE_DEPRECATED |
306 | String _get_text_for_symbol_lookup_bind_compat_73196(); |
307 | static void _bind_compatibility_methods(); |
308 | #endif |
309 | |
310 | /* Text manipulation */ |
311 | |
312 | // Overridable actions |
313 | virtual void _handle_unicode_input_internal(const uint32_t p_unicode, int p_caret) override; |
314 | virtual void _backspace_internal(int p_caret) override; |
315 | |
316 | GDVIRTUAL1(_confirm_code_completion, bool) |
317 | GDVIRTUAL1(_request_code_completion, bool) |
318 | GDVIRTUAL1RC(TypedArray<Dictionary>, _filter_code_completion_candidates, TypedArray<Dictionary>) |
319 | |
320 | public: |
321 | /* General overrides */ |
322 | virtual void gui_input(const Ref<InputEvent> &p_gui_input) override; |
323 | virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override; |
324 | |
325 | /* Indent management */ |
326 | void set_indent_size(const int p_size); |
327 | int get_indent_size() const; |
328 | |
329 | void set_indent_using_spaces(const bool p_use_spaces); |
330 | bool is_indent_using_spaces() const; |
331 | |
332 | void set_auto_indent_enabled(bool p_enabled); |
333 | bool is_auto_indent_enabled() const; |
334 | |
335 | void set_auto_indent_prefixes(const TypedArray<String> &p_prefixes); |
336 | TypedArray<String> get_auto_indent_prefixes() const; |
337 | |
338 | void do_indent(); |
339 | |
340 | void indent_lines(); |
341 | void unindent_lines(); |
342 | |
343 | void convert_indent(int p_from_line = -1, int p_to_line = -1); |
344 | |
345 | /* Auto brace completion */ |
346 | void set_auto_brace_completion_enabled(bool p_enabled); |
347 | bool is_auto_brace_completion_enabled() const; |
348 | |
349 | void set_highlight_matching_braces_enabled(bool p_enabled); |
350 | bool is_highlight_matching_braces_enabled() const; |
351 | |
352 | void add_auto_brace_completion_pair(const String &p_open_key, const String &p_close_key); |
353 | void set_auto_brace_completion_pairs(const Dictionary &p_auto_brace_completion_pairs); |
354 | Dictionary get_auto_brace_completion_pairs() const; |
355 | |
356 | bool has_auto_brace_completion_open_key(const String &p_open_key) const; |
357 | bool has_auto_brace_completion_close_key(const String &p_close_key) const; |
358 | |
359 | String get_auto_brace_completion_close_key(const String &p_open_key) const; |
360 | |
361 | /* Main Gutter */ |
362 | void set_draw_breakpoints_gutter(bool p_draw); |
363 | bool is_drawing_breakpoints_gutter() const; |
364 | |
365 | void set_draw_bookmarks_gutter(bool p_draw); |
366 | bool is_drawing_bookmarks_gutter() const; |
367 | |
368 | void set_draw_executing_lines_gutter(bool p_draw); |
369 | bool is_drawing_executing_lines_gutter() const; |
370 | |
371 | // breakpoints |
372 | void set_line_as_breakpoint(int p_line, bool p_breakpointed); |
373 | bool is_line_breakpointed(int p_line) const; |
374 | void clear_breakpointed_lines(); |
375 | PackedInt32Array get_breakpointed_lines() const; |
376 | |
377 | // bookmarks |
378 | void set_line_as_bookmarked(int p_line, bool p_bookmarked); |
379 | bool is_line_bookmarked(int p_line) const; |
380 | void clear_bookmarked_lines(); |
381 | PackedInt32Array get_bookmarked_lines() const; |
382 | |
383 | // executing lines |
384 | void set_line_as_executing(int p_line, bool p_executing); |
385 | bool is_line_executing(int p_line) const; |
386 | void clear_executing_lines(); |
387 | PackedInt32Array get_executing_lines() const; |
388 | |
389 | /* Line numbers */ |
390 | void set_draw_line_numbers(bool p_draw); |
391 | bool is_draw_line_numbers_enabled() const; |
392 | void set_line_numbers_zero_padded(bool p_zero_padded); |
393 | bool is_line_numbers_zero_padded() const; |
394 | |
395 | /* Fold gutter */ |
396 | void set_draw_fold_gutter(bool p_draw); |
397 | bool is_drawing_fold_gutter() const; |
398 | |
399 | /* Line Folding */ |
400 | void set_line_folding_enabled(bool p_enabled); |
401 | bool is_line_folding_enabled() const; |
402 | |
403 | bool can_fold_line(int p_line) const; |
404 | |
405 | void fold_line(int p_line); |
406 | void unfold_line(int p_line); |
407 | void fold_all_lines(); |
408 | void unfold_all_lines(); |
409 | void toggle_foldable_line(int p_line); |
410 | |
411 | bool is_line_folded(int p_line) const; |
412 | TypedArray<int> get_folded_lines() const; |
413 | |
414 | /* Code region */ |
415 | void create_code_region(); |
416 | String get_code_region_start_tag() const; |
417 | String get_code_region_end_tag() const; |
418 | void set_code_region_tags(const String &p_start = "region" , const String &p_end = "endregion" ); |
419 | bool is_line_code_region_start(int p_line) const; |
420 | bool is_line_code_region_end(int p_line) const; |
421 | |
422 | /* Delimiters */ |
423 | void add_string_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only = false); |
424 | void remove_string_delimiter(const String &p_start_key); |
425 | bool has_string_delimiter(const String &p_start_key) const; |
426 | |
427 | void set_string_delimiters(const TypedArray<String> &p_string_delimiters); |
428 | void clear_string_delimiters(); |
429 | TypedArray<String> get_string_delimiters() const; |
430 | |
431 | int is_in_string(int p_line, int p_column = -1) const; |
432 | |
433 | void (const String &p_start_key, const String &p_end_key, bool p_line_only = false); |
434 | void (const String &p_start_key); |
435 | bool (const String &p_start_key) const; |
436 | |
437 | void (const TypedArray<String> &); |
438 | void (); |
439 | TypedArray<String> () const; |
440 | |
441 | int (int p_line, int p_column = -1) const; |
442 | |
443 | String get_delimiter_start_key(int p_delimiter_idx) const; |
444 | String get_delimiter_end_key(int p_delimiter_idx) const; |
445 | |
446 | Point2 get_delimiter_start_position(int p_line, int p_column) const; |
447 | Point2 get_delimiter_end_position(int p_line, int p_column) const; |
448 | |
449 | /* Code hint */ |
450 | void set_code_hint(const String &p_hint); |
451 | void set_code_hint_draw_below(bool p_below); |
452 | |
453 | /* Code Completion */ |
454 | void set_code_completion_enabled(bool p_enable); |
455 | bool is_code_completion_enabled() const; |
456 | |
457 | void set_code_completion_prefixes(const TypedArray<String> &p_prefixes); |
458 | TypedArray<String> get_code_completion_prefixes() const; |
459 | |
460 | String get_text_for_code_completion() const; |
461 | |
462 | void request_code_completion(bool p_force = false); |
463 | |
464 | void add_code_completion_option(CodeCompletionKind p_type, const String &p_display_text, const String &p_insert_text, const Color &p_text_color = Color(1, 1, 1), const Ref<Resource> &p_icon = Ref<Resource>(), const Variant &p_value = Variant::NIL, int p_location = LOCATION_OTHER); |
465 | void update_code_completion_options(bool p_forced = false); |
466 | |
467 | TypedArray<Dictionary> get_code_completion_options() const; |
468 | Dictionary get_code_completion_option(int p_index) const; |
469 | |
470 | int get_code_completion_selected_index() const; |
471 | void set_code_completion_selected_index(int p_index); |
472 | |
473 | void confirm_code_completion(bool p_replace = false); |
474 | void cancel_code_completion(); |
475 | |
476 | /* Line length guidelines */ |
477 | void set_line_length_guidelines(TypedArray<int> p_guideline_columns); |
478 | TypedArray<int> get_line_length_guidelines() const; |
479 | |
480 | /* Symbol lookup */ |
481 | void set_symbol_lookup_on_click_enabled(bool p_enabled); |
482 | bool is_symbol_lookup_on_click_enabled() const; |
483 | |
484 | String get_text_for_symbol_lookup() const; |
485 | String get_text_with_cursor_char(int p_line, int p_column) const; |
486 | |
487 | void set_symbol_lookup_word_as_valid(bool p_valid); |
488 | |
489 | CodeEdit(); |
490 | ~CodeEdit(); |
491 | }; |
492 | |
493 | VARIANT_ENUM_CAST(CodeEdit::CodeCompletionKind); |
494 | VARIANT_ENUM_CAST(CodeEdit::CodeCompletionLocation); |
495 | |
496 | // The custom comparer which will sort completion options. |
497 | struct CodeCompletionOptionCompare { |
498 | _FORCE_INLINE_ bool operator()(const ScriptLanguage::CodeCompletionOption &l, const ScriptLanguage::CodeCompletionOption &r) const; |
499 | }; |
500 | |
501 | #endif // CODE_EDIT_H |
502 | |