Blender V5.0
text_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cerrno>
11#include <cstring>
12#include <sstream>
13
14#include "MEM_guardedalloc.h"
15
16#include "DNA_camera_types.h"
17#include "DNA_text_types.h"
18
19#include "BLI_fileops.h"
20#include "BLI_listbase.h"
21#include "BLI_math_base.h"
22#include "BLI_math_vector.h"
23#include "BLI_path_utils.hh"
24#include "BLI_rect.h"
25#include "BLI_string.h"
27#include "BLI_string_utf8.h"
28#include "BLI_time.h"
29#include "BLI_vector_set.hh"
30
31#include "BLT_translation.hh"
32
33#include "BKE_context.hh"
34#include "BKE_lib_id.hh"
35#include "BKE_main.hh"
36#include "BKE_node.hh"
38#include "BKE_node_runtime.hh"
39#include "BKE_report.hh"
40#include "BKE_text.h"
41
42#include "WM_api.hh"
43#include "WM_types.hh"
44
45#include "ED_curve.hh"
46#include "ED_screen.hh"
47#include "ED_text.hh"
48
49#include "UI_interface.hh"
51#include "UI_resources.hh"
52
53#include "RE_engine.h"
54
55#include "RNA_access.hh"
56#include "RNA_define.hh"
57
58#ifdef WITH_PYTHON
59# include "BPY_extern.hh"
60# include "BPY_extern_run.hh"
61#endif
62
63#include "text_format.hh"
64#include "text_intern.hh"
65
67
68static void space_text_screen_clamp(SpaceText *st, const ARegion *region);
69
70/* -------------------------------------------------------------------- */
73
81static void test_line_start(char c, bool *r_last_state)
82{
83 if (c == '\n') {
84 *r_last_state = true;
85 }
86 else if (!ELEM(c, '\t', ' ')) {
87 *r_last_state = false;
88 }
89}
90
96static char text_closing_character_pair_get(const char character)
97{
98
99 switch (character) {
100 case '(':
101 return ')';
102 case '[':
103 return ']';
104 case '{':
105 return '}';
106 case '"':
107 return '"';
108 case '\'':
109 return '\'';
110 default:
111 return 0;
112 }
113}
114
123static bool text_span_is_blank(TextLine *line1,
124 const int line1_char,
125 TextLine *line2,
126 const int line2_char)
127{
128 const TextLine *start_line;
129 const TextLine *end_line;
130 int start_char;
131 int end_char;
132
133 /* Get the start and end lines. */
134 if (txt_get_span(line1, line2) > 0 || (line1 == line2 && line1_char <= line2_char)) {
135 start_line = line1;
136 end_line = line2;
137 start_char = line1_char;
138 end_char = line2_char;
139 }
140 else {
141 start_line = line2;
142 end_line = line1;
143 start_char = line2_char;
144 end_char = line1_char;
145 }
146
147 for (const TextLine *line = start_line; line != end_line->next; line = line->next) {
148 const int start = (line == start_line) ? start_char : 0;
149 const int end = (line == end_line) ? end_char : line->len;
150
151 for (int i = start; i < end; i++) {
152 if (!ELEM(line->line[i], ' ', '\t', '\n')) {
153 return false;
154 }
155 }
156 }
157
158 return true;
159}
160
167static char *buf_tabs_to_spaces(const char *in_buf, const int tab_size, int *r_out_buf_len)
168{
169 /* Get the number of tab characters in buffer. */
170 bool line_start = true;
171 int num_tabs = 0;
172
173 for (int in_offset = 0; in_buf[in_offset]; in_offset++) {
174 /* Verify if is an indentation whitespace character. */
175 test_line_start(in_buf[in_offset], &line_start);
176
177 if (in_buf[in_offset] == '\t' && line_start) {
178 num_tabs++;
179 }
180 }
181
182 /* Allocate output before with extra space for expanded tabs. */
183 const int out_size = strlen(in_buf) + num_tabs * (tab_size - 1) + 1;
184 char *out_buf = MEM_malloc_arrayN<char>(out_size, __func__);
185
186 /* Fill output buffer. */
187 int spaces_until_tab = 0;
188 int out_offset = 0;
189 line_start = true;
190
191 for (int in_offset = 0; in_buf[in_offset]; in_offset++) {
192 /* Verify if is an indentation whitespace character. */
193 test_line_start(in_buf[in_offset], &line_start);
194
195 if (in_buf[in_offset] == '\t' && line_start) {
196 /* Calculate tab size so it fills until next indentation. */
197 int num_spaces = tab_size - (spaces_until_tab % tab_size);
198 spaces_until_tab = 0;
199
200 /* Write to buffer. */
201 memset(&out_buf[out_offset], ' ', num_spaces);
202 out_offset += num_spaces;
203 }
204 else {
205 if (in_buf[in_offset] == ' ') {
206 spaces_until_tab++;
207 }
208 else if (in_buf[in_offset] == '\n') {
209 spaces_until_tab = 0;
210 }
211
212 out_buf[out_offset++] = in_buf[in_offset];
213 }
214 }
215
216 out_buf[out_offset] = '\0';
217 *r_out_buf_len = out_offset;
218 return out_buf;
219}
220
222{
223 /* Add half the char width so mouse cursor selection is in between letters. */
224 return (x + (st->runtime->cwidth_px / 2)) / st->runtime->cwidth_px;
225}
226
228{
230 return;
231 }
232 if (!txt_has_sel(text)) {
233 return;
234 }
235 char *buf = txt_sel_to_buf(text, nullptr);
236 if (buf == nullptr) {
237 return;
238 }
239 WM_clipboard_text_set(buf, true);
240 MEM_freeN(buf);
241}
242
244
245/* -------------------------------------------------------------------- */
248
249static bool text_new_poll(bContext * /*C*/)
250{
251 return true;
252}
253
255{
256 Text *text = CTX_data_edit_text(C);
257 if (!text) {
258 return false;
259 }
260 return true;
261}
262
264{
265 Text *text = CTX_data_edit_text(C);
266
267 if (!text) {
268 return false;
269 }
270
271 if (!BKE_id_is_editable(CTX_data_main(C), &text->id)) {
272 // BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data");
273 return false;
274 }
275
276 return true;
277}
278
280{
282 Text *text = CTX_data_edit_text(C);
283
284 if (!st || !text) {
285 return false;
286 }
287
288 if (!BKE_id_is_editable(CTX_data_main(C), &text->id)) {
289 // BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data");
290 return false;
291 }
292
293 return true;
294}
295
297{
299 Text *text = CTX_data_edit_text(C);
300 ARegion *region = CTX_wm_region(C);
301
302 if (!st || !text) {
303 return false;
304 }
305
306 if (!region || region->regiontype != RGN_TYPE_WINDOW) {
307 return false;
308 }
309
310 if (!BKE_id_is_editable(CTX_data_main(C), &text->id)) {
311 // BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data");
312 return false;
313 }
314
315 return true;
316}
317
319
320/* -------------------------------------------------------------------- */
323
325{
326 if (!line) {
327 return;
328 }
329
330 /* We just free format here, and let it rebuild during draw. */
331 MEM_SAFE_FREE(line->format);
332}
333
335{
336 LISTBASE_FOREACH (TextLine *, line, &text->lines) {
338 }
339}
340
342
343/* -------------------------------------------------------------------- */
346
348{
350 Main *bmain = CTX_data_main(C);
351 Text *text;
353 PropertyRNA *prop;
354
355 text = BKE_text_add(bmain, DATA_("Text"));
356
357 /* Hook into UI. */
359
360 if (prop) {
361 PointerRNA idptr = RNA_id_pointer_create(&text->id);
362 RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
363 RNA_property_update(C, &ptr, prop);
364 }
365 else if (st) {
366 st->text = text;
367 st->left = 0;
368 st->top = 0;
369 st->runtime->scroll_ofs_px[0] = 0;
370 st->runtime->scroll_ofs_px[1] = 0;
372 }
373
375
376 return OPERATOR_FINISHED;
377}
378
380{
381 /* Identifiers. */
382 ot->name = "New Text";
383 ot->idname = "TEXT_OT_new";
384 ot->description = "Create a new text data-block";
385
386 /* API callbacks. */
387 ot->exec = text_new_exec;
388 ot->poll = text_new_poll;
389
390 /* Flags. */
391 ot->flag = OPTYPE_UNDO;
392}
393
395
396/* -------------------------------------------------------------------- */
399
401{
402 PropertyPointerRNA *pprop = MEM_new<PropertyPointerRNA>(__func__);
403
404 op->customdata = pprop;
406}
407
408static void text_open_cancel(bContext * /*C*/, wmOperator *op)
409{
410 MEM_delete(static_cast<PropertyPointerRNA *>(op->customdata));
411}
412
414{
416 Main *bmain = CTX_data_main(C);
417 Text *text;
418 char filepath[FILE_MAX];
419 const bool internal = RNA_boolean_get(op->ptr, "internal");
420
421 RNA_string_get(op->ptr, "filepath", filepath);
422
423 text = BKE_text_load_ex(bmain, filepath, BKE_main_blendfile_path(bmain), internal);
424
425 if (!text) {
426 PropertyPointerRNA *pprop = static_cast<PropertyPointerRNA *>(op->customdata);
427 MEM_delete(pprop);
428 op->customdata = nullptr;
429 return OPERATOR_CANCELLED;
430 }
431
432 if (!op->customdata) {
433 text_open_init(C, op);
434 }
435
436 /* Hook into UI. */
437 PropertyPointerRNA *pprop = static_cast<PropertyPointerRNA *>(op->customdata);
438 if (pprop->prop) {
439 PointerRNA idptr = RNA_id_pointer_create(&text->id);
440 RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, nullptr);
441 RNA_property_update(C, &pprop->ptr, pprop->prop);
442 }
443 else if (st) {
444 st->text = text;
445 st->left = 0;
446 st->top = 0;
447 st->runtime->scroll_ofs_px[0] = 0;
448 st->runtime->scroll_ofs_px[1] = 0;
449 }
450
453
454 MEM_delete(pprop);
455
456 return OPERATOR_FINISHED;
457}
458
460{
461 Main *bmain = CTX_data_main(C);
462 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
463 return text_open_exec(C, op);
464 }
465
466 Text *text = CTX_data_edit_text(C);
467 const char *filepath = nullptr;
468 char filepath_buf[FILE_MAX];
469 if (text && text->filepath) {
470 if (BLI_path_is_rel(text->filepath)) {
471 STRNCPY(filepath_buf, text->filepath);
472 BLI_path_abs(filepath_buf, ID_BLEND_PATH(bmain, &text->id));
473 filepath = filepath_buf;
474 }
475 else {
476 filepath = text->filepath;
477 }
478 }
479 else {
480 filepath = BKE_main_blendfile_path(bmain);
481 }
482 BLI_assert(filepath != nullptr);
483
484 text_open_init(C, op);
485 RNA_string_set(op->ptr, "filepath", filepath);
487
489}
490
492{
493 /* Identifiers. */
494 ot->name = "Open Text";
495 ot->idname = "TEXT_OT_open";
496 ot->description = "Open a new text data-block";
497
498 /* API callbacks. */
499 ot->exec = text_open_exec;
500 ot->invoke = text_open_invoke;
501 ot->cancel = text_open_cancel;
502 ot->poll = text_new_poll;
503
504 /* Flags. */
505 ot->flag = OPTYPE_UNDO;
506
507 /* Properties. */
516 ot->srna, "internal", false, "Make Internal", "Make text file internal after loading");
517}
518
520
521/* -------------------------------------------------------------------- */
524
526{
528 Text *text = CTX_data_edit_text(C);
529 ARegion *region = CTX_wm_region(C);
530
531 /* Store view & cursor state. */
532 const int orig_top = st->top;
533 const int orig_curl = BLI_findindex(&text->lines, text->curl);
534 const int orig_curc = text->curc;
535
536 /* Don't make this part of `poll`, since `Alt-R` will type `R`,
537 * if poll checks for the filename. */
538 if (text->filepath == nullptr) {
539 BKE_report(op->reports, RPT_ERROR, "This text has not been saved");
540 return OPERATOR_CANCELLED;
541 }
542
543 if (!BKE_text_reload(text)) {
544 BKE_report(op->reports, RPT_ERROR, "Could not reopen file");
545 return OPERATOR_CANCELLED;
546 }
547
548#ifdef WITH_PYTHON
549 if (text->compiled) {
550 BPY_text_free_code(text);
551 }
552#endif
553
554 text_update_edited(text);
558
559 text->flags &= ~TXT_ISDIRTY;
560
561 /* Return to scroll position. */
562 st->top = orig_top;
563 space_text_screen_clamp(st, region);
564 /* Return cursor. */
565 txt_move_to(text, orig_curl, orig_curc, false);
566
567 return OPERATOR_FINISHED;
568}
569
571{
573 op,
574 IFACE_("Reload active text file?"),
575 nullptr,
576 IFACE_("Reload"),
578 false);
579}
580
582{
583 /* Identifiers. */
584 ot->name = "Reload";
585 ot->idname = "TEXT_OT_reload";
586 ot->description = "Reload active text data-block from its file";
587
588 /* API callbacks. */
589 ot->exec = text_reload_exec;
590 ot->invoke = text_reload_invoke;
591 ot->poll = text_edit_poll;
592}
593
595
596/* -------------------------------------------------------------------- */
599
601{
602 /* It should be possible to unlink texts if they're lib-linked in. */
603 return CTX_data_edit_text(C) != nullptr;
604}
605
607{
608 Main *bmain = CTX_data_main(C);
610 Text *text = CTX_data_edit_text(C);
611
612 /* Make the previous text active, if its not there make the next text active. */
613 if (st) {
614 if (text->id.prev) {
615 st->text = static_cast<Text *>(text->id.prev);
617 }
618 else if (text->id.next) {
619 st->text = static_cast<Text *>(text->id.next);
621 }
622 }
623
624 BKE_id_delete(bmain, text);
625
628
629 return OPERATOR_FINISHED;
630}
631
633{
635 op,
636 IFACE_("Delete active text file?"),
637 nullptr,
638 IFACE_("Delete"),
640 false);
641}
642
644{
645 /* Identifiers. */
646 ot->name = "Unlink";
647 ot->idname = "TEXT_OT_unlink";
648 ot->description = "Unlink active text data-block";
649
650 /* API callbacks. */
651 ot->exec = text_unlink_exec;
652 ot->invoke = text_unlink_invoke;
653 ot->poll = text_unlink_poll;
654
655 /* Flags. */
656 ot->flag = OPTYPE_UNDO;
657}
658
660
661/* -------------------------------------------------------------------- */
664
678
680{
681 /* Identifiers. */
682 ot->name = "Make Internal";
683 ot->idname = "TEXT_OT_make_internal";
684 ot->description = "Make active text file internal";
685
686 /* API callbacks. */
688 ot->poll = text_edit_poll;
689
690 /* Flags. */
691 ot->flag = OPTYPE_UNDO;
692}
693
695
696/* -------------------------------------------------------------------- */
699
700static void txt_write_file(Main *bmain, Text *text, ReportList *reports)
701{
702 FILE *fp;
703 BLI_stat_t st;
704 char filepath[FILE_MAX];
705
706 if (text->filepath == nullptr) {
707 BKE_reportf(reports, RPT_ERROR, "No file path for \"%s\"", text->id.name + 2);
708 return;
709 }
710
711 STRNCPY(filepath, text->filepath);
712 BLI_path_abs(filepath, BKE_main_blendfile_path(bmain));
713
714 /* Check if file write permission is ok. */
715 if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) {
717 reports, RPT_ERROR, "Cannot save text file, path \"%s\" is not writable", filepath);
718 return;
719 }
720
721 fp = BLI_fopen(filepath, "w");
722 if (fp == nullptr) {
723 BKE_reportf(reports,
724 RPT_ERROR,
725 "Unable to save '%s': %s",
726 filepath,
727 errno ? strerror(errno) : RPT_("unknown error writing file"));
728 return;
729 }
730
731 LISTBASE_FOREACH (TextLine *, tmp, &text->lines) {
732 fputs(tmp->line, fp);
733 if (tmp->next) {
734 fputc('\n', fp);
735 }
736 }
737
738 fclose(fp);
739
740 if (BLI_stat(filepath, &st) == 0) {
741 text->mtime = st.st_mtime;
742
743 /* Report since this can be called from key shortcuts. */
744 BKE_reportf(reports, RPT_INFO, "Saved text \"%s\"", filepath);
745 }
746 else {
747 text->mtime = 0;
748 BKE_reportf(reports,
750 "Unable to stat '%s': %s",
751 filepath,
752 errno ? strerror(errno) : RPT_("unknown error statting file"));
753 }
754
755 text->flags &= ~TXT_ISDIRTY;
756}
757
759{
760 Main *bmain = CTX_data_main(C);
761 Text *text = CTX_data_edit_text(C);
762
763 txt_write_file(bmain, text, op->reports);
764
767
768 return OPERATOR_FINISHED;
769}
770
772{
773 Text *text = CTX_data_edit_text(C);
774
775 /* Internal and texts without a filepath will go to "Save As". */
776 if (text->filepath == nullptr || (text->flags & TXT_ISMEM)) {
778 C, "TEXT_OT_save_as", blender::wm::OpCallContext::InvokeDefault, nullptr, event);
779 return OPERATOR_CANCELLED;
780 }
781 return text_save_exec(C, op);
782}
783
785{
786 /* Identifiers. */
787 ot->name = "Save";
788 ot->idname = "TEXT_OT_save";
789 ot->description = "Save active text data-block";
790
791 /* API callbacks. */
792 ot->exec = text_save_exec;
793 ot->invoke = text_save_invoke;
794 ot->poll = text_edit_poll;
795}
796
798
799/* -------------------------------------------------------------------- */
802
804{
805 Main *bmain = CTX_data_main(C);
806 Text *text = CTX_data_edit_text(C);
807 char filepath[FILE_MAX];
808
809 if (!text) {
810 return OPERATOR_CANCELLED;
811 }
812
813 RNA_string_get(op->ptr, "filepath", filepath);
814
815 if (text->filepath) {
816 MEM_freeN(text->filepath);
817 }
818 text->filepath = BLI_strdup(filepath);
819 text->flags &= ~TXT_ISMEM;
820
821 txt_write_file(bmain, text, op->reports);
822
825
826 return OPERATOR_FINISHED;
827}
828
830{
831 Main *bmain = CTX_data_main(C);
832 Text *text = CTX_data_edit_text(C);
833
834 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
835 return text_save_as_exec(C, op);
836 }
837
838 const char *filepath = nullptr;
839 char filepath_buf[FILE_MAX];
840 if (text->filepath) {
841 if (BLI_path_is_rel(text->filepath)) {
842 STRNCPY(filepath_buf, text->filepath);
843 BLI_path_abs(filepath_buf, ID_BLEND_PATH(bmain, &text->id));
844 filepath = filepath_buf;
845 }
846 else {
847 filepath = text->filepath;
848 }
849 }
850 else if (text->flags & TXT_ISMEM) {
851 filepath = text->id.name + 2;
852 }
853 else {
854 filepath = BKE_main_blendfile_path(bmain);
855 }
856 BLI_assert(filepath != nullptr);
857
858 RNA_string_set(op->ptr, "filepath", filepath);
860
862}
863
865{
866 /* Identifiers. */
867 ot->name = "Save As";
868 ot->idname = "TEXT_OT_save_as";
869 ot->description = "Save active text file with options";
870
871 /* API callbacks. */
872 ot->exec = text_save_as_exec;
873 ot->invoke = text_save_as_invoke;
874 ot->poll = text_edit_poll;
875
876 /* Properties. */
880 FILE_SAVE,
883 FILE_SORT_DEFAULT); /* XXX TODO: relative_path. */
884}
885
887
888/* -------------------------------------------------------------------- */
891
893{
894#ifdef WITH_PYTHON
895 Text *text = CTX_data_edit_text(C);
896 const bool is_live = (reports == nullptr);
897
898 /* Only for comparison. */
899 void *curl_prev = text->curl;
900 int curc_prev = text->curc;
901 int selc_prev = text->selc;
902
903 if (BPY_run_text(C, text, reports, !is_live)) {
904 if (is_live) {
905 /* For nice live updates. */
907 }
908 return OPERATOR_FINISHED;
909 }
910
911 /* Don't report error messages while live editing. */
912 if (!is_live) {
913 /* Text may have freed itself. */
914 if (CTX_data_edit_text(C) == text) {
915 if (text->curl != curl_prev || curc_prev != text->curc || selc_prev != text->selc) {
918 }
919 }
920
921 /* No need to report the error, this has already been handled by #BPY_run_text. */
922 return OPERATOR_FINISHED;
923 }
924#else
925 (void)C;
926 (void)reports;
927#endif /* !WITH_PYTHON */
928 return OPERATOR_CANCELLED;
929}
930
932{
933#ifndef WITH_PYTHON
934 UNUSED_VARS(C);
935
936 BKE_report(op->reports, RPT_ERROR, "Python disabled in this build");
937
938 return OPERATOR_CANCELLED;
939#else
940 return text_run_script(C, op->reports);
941#endif /* WITH_PYTHON */
942}
943
945{
946 /* Identifiers. */
947 ot->name = "Run Script";
948 ot->idname = "TEXT_OT_run_script";
949 ot->description = "Run active script";
950
951 /* API callbacks. */
952 ot->poll = text_data_poll;
953 ot->exec = text_run_script_exec;
954
955 /* Flags. */
957}
958
960
961/* -------------------------------------------------------------------- */
964
966{
968 Text *text = CTX_data_edit_text(C);
969
970 const bool selection = RNA_boolean_get(op->ptr, "selection");
971
972 char *buf;
973 int buf_len;
974
975 /* No need for UTF8 validation as the conversion handles invalid sequences gracefully. */
976 buf = WM_clipboard_text_get(selection, false, &buf_len);
977
978 if (!buf) {
979 return OPERATOR_CANCELLED;
980 }
981
983
985
986 /* Convert clipboard content indentation to spaces if specified. */
987 if (text->flags & TXT_TABSTOSPACES) {
988 char *new_buf = buf_tabs_to_spaces(buf, TXT_TABSIZE, &buf_len);
989 MEM_freeN(buf);
990 buf = new_buf;
991 }
992
993 txt_insert_buf(text, buf, buf_len);
994 text_update_edited(text);
995
996 MEM_freeN(buf);
997
1000
1001 /* Run the script while editing, evil but useful. */
1002 if (st->live_edit) {
1003 text_run_script(C, nullptr);
1004 }
1005
1006 return OPERATOR_FINISHED;
1007}
1008
1010{
1011 /* Identifiers. */
1012 ot->name = "Paste";
1013 ot->idname = "TEXT_OT_paste";
1014 ot->description = "Paste text from clipboard";
1015
1016 /* API callbacks. */
1017 ot->exec = text_paste_exec;
1018 ot->poll = text_edit_poll;
1019
1020 /* Flags. */
1021 ot->flag = OPTYPE_UNDO;
1022
1023 /* Properties. */
1024 PropertyRNA *prop;
1025 prop = RNA_def_boolean(ot->srna,
1026 "selection",
1027 false,
1028 "Selection",
1029 "Paste text selected elsewhere rather than copied (X11/Wayland only)");
1031}
1032
1034
1035/* -------------------------------------------------------------------- */
1038
1040{
1041 Text *text = CTX_data_edit_text(C);
1042
1044
1045 txt_duplicate_line(text);
1046
1048
1049 /* Run the script while editing, evil but useful. */
1050 if (CTX_wm_space_text(C)->live_edit) {
1051 text_run_script(C, nullptr);
1052 }
1053
1054 return OPERATOR_FINISHED;
1055}
1056
1058{
1059 /* Identifiers. */
1060 ot->name = "Duplicate Line";
1061 ot->idname = "TEXT_OT_duplicate_line";
1062 ot->description = "Duplicate the current line";
1063
1064 /* API callbacks. */
1066 ot->poll = text_edit_poll;
1067
1068 /* Flags. */
1069 ot->flag = OPTYPE_UNDO;
1070}
1071
1073
1074/* -------------------------------------------------------------------- */
1077
1078static void txt_copy_clipboard(const Text *text)
1079{
1080 char *buf;
1081
1082 if (!txt_has_sel(text)) {
1083 return;
1084 }
1085
1086 buf = txt_sel_to_buf(text, nullptr);
1087
1088 if (buf) {
1089 WM_clipboard_text_set(buf, false);
1090 MEM_freeN(buf);
1091 }
1092}
1093
1095{
1096 const Text *text = CTX_data_edit_text(C);
1097
1098 txt_copy_clipboard(text);
1099
1100 return OPERATOR_FINISHED;
1101}
1102
1104{
1105 /* Identifiers. */
1106 ot->name = "Copy";
1107 ot->idname = "TEXT_OT_copy";
1108 ot->description = "Copy selected text to clipboard";
1109
1110 /* API callbacks. */
1111 ot->exec = text_copy_exec;
1112 ot->poll = text_edit_poll;
1113}
1114
1116
1117/* -------------------------------------------------------------------- */
1120
1122{
1124 Text *text = CTX_data_edit_text(C);
1125
1127
1128 txt_copy_clipboard(text);
1129
1131 txt_delete_selected(text);
1132
1135
1136 /* Run the script while editing, evil but useful. */
1137 if (st->live_edit) {
1138 text_run_script(C, nullptr);
1139 }
1140
1141 return OPERATOR_FINISHED;
1142}
1143
1145{
1146 /* Identifiers. */
1147 ot->name = "Cut";
1148 ot->idname = "TEXT_OT_cut";
1149 ot->description = "Cut selected text to clipboard";
1150
1151 /* API callbacks. */
1152 ot->exec = text_cut_exec;
1153 ot->poll = text_edit_poll;
1154
1155 /* Flags. */
1156 ot->flag = OPTYPE_UNDO;
1157}
1158
1160
1161/* -------------------------------------------------------------------- */
1164
1166{
1167 Text *text = CTX_data_edit_text(C);
1168 TextLine *line = text->curl;
1169 bool text_before_cursor = text->curc != 0 && !ELEM(line->line[text->curc - 1], ' ', '\t');
1170 if (text_before_cursor && (txt_has_sel(text) == false)) {
1172 C, "TEXT_OT_autocomplete", blender::wm::OpCallContext::InvokeDefault, nullptr, nullptr);
1173 }
1174 else {
1176 C, "TEXT_OT_indent", blender::wm::OpCallContext::ExecDefault, nullptr, nullptr);
1177 }
1178 return OPERATOR_FINISHED;
1179}
1180
1182{
1183 /* Identifiers. */
1184 ot->name = "Indent or Autocomplete";
1185 ot->idname = "TEXT_OT_indent_or_autocomplete";
1186 ot->description = "Indent selected text or autocomplete";
1187
1188 /* API callbacks. */
1190 ot->poll = text_edit_poll;
1191
1192 /* Flags. */
1193 ot->flag = 0;
1194}
1195
1197
1198/* -------------------------------------------------------------------- */
1201
1203{
1205 Text *text = CTX_data_edit_text(C);
1206
1208
1210
1211 if (txt_has_sel(text)) {
1212 txt_order_cursors(text, false);
1213 txt_indent(text);
1214 }
1215 else {
1216 txt_add_char(text, '\t');
1217 }
1218
1219 text_update_edited(text);
1220
1223
1224 return OPERATOR_FINISHED;
1225}
1226
1228{
1229 /* Identifiers. */
1230 ot->name = "Indent";
1231 ot->idname = "TEXT_OT_indent";
1232 ot->description = "Indent selected text";
1233
1234 /* API callbacks. */
1235 ot->exec = text_indent_exec;
1236 ot->poll = text_edit_poll;
1237
1238 /* Flags. */
1239 ot->flag = OPTYPE_UNDO;
1240}
1241
1243
1244/* -------------------------------------------------------------------- */
1247
1249{
1251 Text *text = CTX_data_edit_text(C);
1252
1254
1256
1257 txt_order_cursors(text, false);
1258 txt_unindent(text);
1259
1260 text_update_edited(text);
1261
1264
1265 return OPERATOR_FINISHED;
1266}
1267
1269{
1270 /* Identifiers. */
1271 ot->name = "Unindent";
1272 ot->idname = "TEXT_OT_unindent";
1273 ot->description = "Unindent selected text";
1274
1275 /* API callbacks. */
1276 ot->exec = text_unindent_exec;
1277 ot->poll = text_edit_poll;
1278
1279 /* Flags. */
1280 ot->flag = OPTYPE_UNDO;
1281}
1282
1284
1285/* -------------------------------------------------------------------- */
1288
1290{
1292 Text *text = CTX_data_edit_text(C);
1293 int a, curts;
1294 int space = (text->flags & TXT_TABSTOSPACES) ? st->tabnumber : 1;
1295
1297
1298 /* Double check tabs/spaces before splitting the line. */
1299 curts = txt_setcurr_tab_spaces(text, space);
1301 txt_split_curline(text);
1302
1303 for (a = 0; a < curts; a++) {
1304 if (text->flags & TXT_TABSTOSPACES) {
1305 txt_add_char(text, ' ');
1306 }
1307 else {
1308 txt_add_char(text, '\t');
1309 }
1310 }
1311
1312 if (text->curl) {
1313 if (text->curl->prev) {
1315 }
1317 }
1318
1321
1322 return OPERATOR_FINISHED;
1323}
1324
1326{
1327 /* Identifiers. */
1328 ot->name = "Line Break";
1329 ot->idname = "TEXT_OT_line_break";
1330 ot->description = "Insert line break at cursor position";
1331
1332 /* API callbacks. */
1333 ot->exec = text_line_break_exec;
1334 ot->poll = text_edit_poll;
1335
1336 /* Flags. */
1337 ot->flag = OPTYPE_UNDO;
1338}
1339
1341
1342/* -------------------------------------------------------------------- */
1345
1347{
1349 Text *text = CTX_data_edit_text(C);
1350 int type = RNA_enum_get(op->ptr, "type");
1351 const char *prefix = ED_text_format_comment_line_prefix(text);
1352
1354
1356
1357 if (txt_has_sel(text)) {
1358 txt_order_cursors(text, false);
1359 }
1360
1361 switch (type) {
1362 case 1:
1363 txt_comment(text, prefix);
1364 break;
1365 case -1:
1366 txt_uncomment(text, prefix);
1367 break;
1368 default:
1369 if (txt_uncomment(text, prefix) == false) {
1370 txt_comment(text, prefix);
1371 }
1372 break;
1373 }
1374
1375 text_update_edited(text);
1376
1379
1380 return OPERATOR_FINISHED;
1381}
1382
1384{
1385 static const EnumPropertyItem comment_items[] = {
1386 {0, "TOGGLE", 0, "Toggle Comments", nullptr},
1387 {1, "COMMENT", 0, "Comment", nullptr},
1388 {-1, "UNCOMMENT", 0, "Un-Comment", nullptr},
1389 {0, nullptr, 0, nullptr, nullptr},
1390 };
1391
1392 /* Identifiers. */
1393 ot->name = "Toggle Comments";
1394 ot->idname = "TEXT_OT_comment_toggle";
1395
1396 /* API callbacks. */
1397 ot->exec = text_comment_exec;
1398 ot->poll = text_edit_poll;
1399
1400 /* Flags. */
1401 ot->flag = OPTYPE_UNDO;
1402
1403 /* Properties. */
1404 PropertyRNA *prop;
1405 prop = RNA_def_enum(ot->srna, "type", comment_items, 0, "Type", "Add or remove comments");
1407}
1408
1410
1411/* -------------------------------------------------------------------- */
1414
1417 {TO_SPACES, "SPACES", 0, "To Spaces", nullptr},
1418 {TO_TABS, "TABS", 0, "To Tabs", nullptr},
1419 {0, nullptr, 0, nullptr, nullptr},
1420};
1421
1423{
1425 Text *text = CTX_data_edit_text(C);
1426 FlattenString fs;
1427 size_t a, j, max_len = 0;
1428 int type = RNA_enum_get(op->ptr, "type");
1429
1430 const int curc_column = text->curl ?
1432 text->curl->line, text->curl->len, text->curc, TXT_TABSIZE) :
1433 -1;
1434 const int selc_column = text->sell ?
1436 text->sell->line, text->sell->len, text->selc, TXT_TABSIZE) :
1437 -1;
1438
1439 /* First convert to all space, this make it a lot easier to convert to tabs
1440 * because there is no mixtures of ` ` && `\t`. */
1441 LISTBASE_FOREACH (TextLine *, tmp, &text->lines) {
1442 char *new_line;
1443
1444 BLI_assert(tmp->line);
1445
1446 flatten_string(st, &fs, tmp->line);
1447 new_line = BLI_strdup(fs.buf);
1449
1450 MEM_freeN(tmp->line);
1451 if (tmp->format) {
1452 MEM_freeN(tmp->format);
1453 }
1454
1455 /* Put new_line in the tmp->line spot still need to try and set the curc correctly. */
1456 tmp->line = new_line;
1457 tmp->len = strlen(new_line);
1458 tmp->format = nullptr;
1459 max_len = std::max<size_t>(tmp->len, max_len);
1460 }
1461
1462 if (type == TO_TABS) {
1463 char *tmp_line = MEM_malloc_arrayN<char>(max_len + 1, __func__);
1464
1465 LISTBASE_FOREACH (TextLine *, tmp, &text->lines) {
1466 const char *text_check_line = tmp->line;
1467 const int text_check_line_len = tmp->len;
1468 char *tmp_line_cur = tmp_line;
1469 const size_t tab_len = st->tabnumber;
1470
1471 BLI_assert(text_check_line);
1472
1473 for (a = 0; a < text_check_line_len;) {
1474 /* A tab can only start at a position multiple of `tab_len`. */
1475 if (!(a % tab_len) && (text_check_line[a] == ' ')) {
1476 /* A + 0 we already know to be ` ` character. */
1477 for (j = 1;
1478 (j < tab_len) && (a + j < text_check_line_len) && (text_check_line[a + j] == ' ');
1479 j++)
1480 {
1481 /* Pass. */
1482 }
1483
1484 if (j == tab_len) {
1485 /* We found a set of spaces that can be replaced by a tab... */
1486 if ((tmp_line_cur == tmp_line) && a != 0) {
1487 /* Copy all *valid* string already *parsed*. */
1488 memcpy(tmp_line_cur, text_check_line, a);
1489 tmp_line_cur += a;
1490 }
1491 *tmp_line_cur = '\t';
1492 tmp_line_cur++;
1493 a += j;
1494 }
1495 else {
1496 if (tmp_line_cur != tmp_line) {
1497 memcpy(tmp_line_cur, &text_check_line[a], j);
1498 tmp_line_cur += j;
1499 }
1500 a += j;
1501 }
1502 }
1503 else {
1504 size_t len = BLI_str_utf8_size_safe(&text_check_line[a]);
1505 if (tmp_line_cur != tmp_line) {
1506 memcpy(tmp_line_cur, &text_check_line[a], len);
1507 tmp_line_cur += len;
1508 }
1509 a += len;
1510 }
1511 }
1512
1513 if (tmp_line_cur != tmp_line) {
1514 *tmp_line_cur = '\0';
1515
1516#ifndef NDEBUG
1517 BLI_assert(tmp_line_cur - tmp_line <= max_len);
1518
1519 flatten_string(st, &fs, tmp_line);
1520 BLI_assert(STREQ(fs.buf, tmp->line));
1522#endif
1523
1524 MEM_freeN(tmp->line);
1525 if (tmp->format) {
1526 MEM_freeN(tmp->format);
1527 }
1528
1529 /* Put new_line in the `tmp->line` spot. */
1530 tmp->len = strlen(tmp_line);
1531 tmp->line = BLI_strdupn(tmp_line, tmp->len);
1532 tmp->format = nullptr;
1533 }
1534 }
1535
1536 MEM_freeN(tmp_line);
1537 }
1538
1539 if (curc_column != -1) {
1541 text->curl->line, text->curl->len, curc_column, TXT_TABSIZE);
1542 }
1543 if (selc_column != -1) {
1545 text->sell->line, text->sell->len, selc_column, TXT_TABSIZE);
1546 }
1547
1548 text_update_edited(text);
1552
1553 return OPERATOR_FINISHED;
1554}
1555
1557{
1558 /* Identifiers. */
1559 ot->name = "Convert Whitespace";
1560 ot->idname = "TEXT_OT_convert_whitespace";
1561 ot->description = "Convert whitespaces by type";
1562
1563 /* API callbacks. */
1565 ot->poll = text_edit_poll;
1566
1567 /* Flags. */
1568 ot->flag = OPTYPE_UNDO;
1569
1570 /* Properties. */
1571 RNA_def_enum(ot->srna,
1572 "type",
1574 TO_SPACES,
1575 "Type",
1576 "Type of whitespace to convert to");
1577}
1578
1580
1581/* -------------------------------------------------------------------- */
1584
1598
1600{
1601 /* Identifiers. */
1602 ot->name = "Select All";
1603 ot->idname = "TEXT_OT_select_all";
1604 ot->description = "Select all text";
1605
1606 /* API callbacks. */
1607 ot->exec = text_select_all_exec;
1608 ot->poll = text_edit_poll;
1609}
1610
1612
1613/* -------------------------------------------------------------------- */
1616
1630
1632{
1633 /* Identifiers. */
1634 ot->name = "Select Line";
1635 ot->idname = "TEXT_OT_select_line";
1636 ot->description = "Select text by line";
1637
1638 /* API callbacks. */
1639 ot->exec = text_select_line_exec;
1640 ot->poll = text_edit_poll;
1641}
1642
1644
1645/* -------------------------------------------------------------------- */
1648
1650{
1651 Text *text = CTX_data_edit_text(C);
1652
1654 text->curl->line, text->curl->len, text->selc, &text->curc, &text->selc);
1655
1658
1660
1661 return OPERATOR_FINISHED;
1662}
1663
1665{
1666 /* Identifiers. */
1667 ot->name = "Select Word";
1668 ot->idname = "TEXT_OT_select_word";
1669 ot->description = "Select word under cursor";
1670
1671 /* API callbacks. */
1672 ot->exec = text_select_word_exec;
1673 ot->poll = text_edit_poll;
1674}
1675
1677
1678/* -------------------------------------------------------------------- */
1681
1683{
1684 Text *text = CTX_data_edit_text(C);
1685 const int direction = RNA_enum_get(op->ptr, "direction");
1686
1688
1689 txt_move_lines(text, direction);
1690
1693
1694 /* Run the script while editing, evil but useful. */
1695 if (CTX_wm_space_text(C)->live_edit) {
1696 text_run_script(C, nullptr);
1697 }
1698
1699 return OPERATOR_FINISHED;
1700}
1701
1703{
1704 static const EnumPropertyItem direction_items[] = {
1705 {TXT_MOVE_LINE_UP, "UP", 0, "Up", ""},
1706 {TXT_MOVE_LINE_DOWN, "DOWN", 0, "Down", ""},
1707 {0, nullptr, 0, nullptr, nullptr},
1708 };
1709
1710 /* Identifiers. */
1711 ot->name = "Move Lines";
1712 ot->idname = "TEXT_OT_move_lines";
1713 ot->description = "Move the currently selected line(s) up/down";
1714
1715 /* API callbacks. */
1716 ot->exec = move_lines_exec;
1717 ot->poll = text_edit_poll;
1718
1719 /* Flags. */
1720 ot->flag = OPTYPE_UNDO;
1721
1722 /* Properties. */
1723 RNA_def_enum(ot->srna, "direction", direction_items, 1, "Direction", "");
1724}
1725
1727
1728/* -------------------------------------------------------------------- */
1731
1733 {LINE_BEGIN, "LINE_BEGIN", 0, "Line Begin", ""},
1734 {LINE_END, "LINE_END", 0, "Line End", ""},
1735 {FILE_TOP, "FILE_TOP", 0, "File Top", ""},
1736 {FILE_BOTTOM, "FILE_BOTTOM", 0, "File Bottom", ""},
1737 {PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
1738 {NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
1739 {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
1740 {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
1741 {PREV_LINE, "PREVIOUS_LINE", 0, "Previous Line", ""},
1742 {NEXT_LINE, "NEXT_LINE", 0, "Next Line", ""},
1743 {PREV_PAGE, "PREVIOUS_PAGE", 0, "Previous Page", ""},
1744 {NEXT_PAGE, "NEXT_PAGE", 0, "Next Page", ""},
1745 {0, nullptr, 0, nullptr, nullptr},
1746};
1747
1752 const SpaceText *st, const ARegion *region, TextLine *linein, int rell, int relc)
1753{
1754 int i, j, start, end, max, curs, endj, selc;
1755 bool chop, loop, found;
1756 char ch;
1757
1758 max = space_text_wrap_width(st, region);
1759
1760 selc = start = endj = curs = found = false;
1761 end = max;
1762 chop = loop = true;
1763
1764 for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe(linein->line + j)) {
1765 int chars;
1766 const int columns = BLI_str_utf8_char_width_safe(linein->line + j); /* = 1 for tab. */
1767
1768 /* Mimic replacement of tabs. */
1769 ch = linein->line[j];
1770 if (ch == '\t') {
1771 chars = st->tabnumber - i % st->tabnumber;
1772 ch = ' ';
1773 }
1774 else {
1775 chars = 1;
1776 }
1777
1778 while (chars--) {
1779 if (rell == 0 && i - start <= relc && i + columns - start > relc) {
1780 /* Current position could be wrapped to next line. */
1781 /* This should be checked when end of current line would be reached. */
1782 selc = j;
1783 found = true;
1784 }
1785 else if (i - end <= relc && i + columns - end > relc) {
1786 curs = j;
1787 }
1788 if (i + columns - start > max) {
1789 end = std::min(end, i);
1790
1791 if (found) {
1792 /* Exact cursor position was found, check if it's
1793 * still on needed line (hasn't been wrapped). */
1794 if (selc > endj && !chop) {
1795 selc = endj;
1796 }
1797 loop = false;
1798 break;
1799 }
1800
1801 if (chop) {
1802 endj = j;
1803 }
1804
1805 start = end;
1806 end += max;
1807 chop = true;
1808 rell--;
1809
1810 if (rell == 0 && i + columns - start > relc) {
1811 selc = curs;
1812 loop = false;
1813 break;
1814 }
1815 }
1816 else if (ch == '\0') {
1817 if (!found) {
1818 selc = linein->len;
1819 }
1820 loop = false;
1821 break;
1822 }
1823 else if (ELEM(ch, ' ', '-')) {
1824 if (found) {
1825 loop = false;
1826 break;
1827 }
1828
1829 if (rell == 0 && i + columns - start > relc) {
1830 selc = curs;
1831 loop = false;
1832 break;
1833 }
1834 end = i + 1;
1835 endj = j;
1836 chop = false;
1837 }
1838 i += columns;
1839 }
1840 }
1841
1842 return selc;
1843}
1844
1846 const ARegion *region,
1847 int lines,
1848 TextLine **linep,
1849 int *charp,
1850 int *rell,
1851 int *relc)
1852{
1853 int offl, offc, visible_lines;
1854
1855 space_text_wrap_offset_in_line(st, region, *linep, *charp, &offl, &offc);
1856 *relc = space_text_get_char_pos(st, (*linep)->line, *charp) + offc;
1857 *rell = lines;
1858
1859 /* Handle current line. */
1860 if (lines > 0) {
1861 visible_lines = space_text_get_visible_lines(st, region, (*linep)->line);
1862
1863 if (*rell - visible_lines + offl >= 0) {
1864 if (!(*linep)->next) {
1865 if (offl < visible_lines - 1) {
1866 *rell = visible_lines - 1;
1867 return 1;
1868 }
1869
1870 *charp = (*linep)->len;
1871 return 0;
1872 }
1873
1874 *rell -= visible_lines - offl;
1875 *linep = (*linep)->next;
1876 }
1877 else {
1878 *rell += offl;
1879 return 1;
1880 }
1881 }
1882 else {
1883 if (*rell + offl <= 0) {
1884 if (!(*linep)->prev) {
1885 if (offl) {
1886 *rell = 0;
1887 return 1;
1888 }
1889
1890 *charp = 0;
1891 return 0;
1892 }
1893
1894 *rell += offl;
1895 *linep = (*linep)->prev;
1896 }
1897 else {
1898 *rell += offl;
1899 return 1;
1900 }
1901 }
1902
1903 /* Skip lines and find destination line and offsets. */
1904 while (*linep) {
1905 visible_lines = space_text_get_visible_lines(st, region, (*linep)->line);
1906
1907 if (lines < 0) { /* Moving top. */
1908 if (*rell + visible_lines >= 0) {
1909 *rell += visible_lines;
1910 break;
1911 }
1912
1913 if (!(*linep)->prev) {
1914 *rell = 0;
1915 break;
1916 }
1917
1918 *rell += visible_lines;
1919 *linep = (*linep)->prev;
1920 }
1921 else { /* Moving bottom. */
1922 if (*rell - visible_lines < 0) {
1923 break;
1924 }
1925
1926 if (!(*linep)->next) {
1927 *rell = visible_lines - 1;
1928 break;
1929 }
1930
1931 *rell -= visible_lines;
1932 *linep = (*linep)->next;
1933 }
1934 }
1935
1936 return 1;
1937}
1938
1939static void txt_wrap_move_bol(SpaceText *st, ARegion *region, const bool sel)
1940{
1941 Text *text = st->text;
1942 TextLine **linep;
1943 int *charp;
1944 int oldc, i, j, max, start, end, endj;
1945 bool chop, loop;
1946 char ch;
1947
1949
1950 if (sel) {
1951 linep = &text->sell;
1952 charp = &text->selc;
1953 }
1954 else {
1955 linep = &text->curl;
1956 charp = &text->curc;
1957 }
1958
1959 oldc = *charp;
1960
1961 max = space_text_wrap_width(st, region);
1962
1963 start = endj = 0;
1964 end = max;
1965 chop = loop = true;
1966 *charp = 0;
1967
1968 for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) {
1969 int chars;
1970 const int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab. */
1971
1972 /* Mimic replacement of tabs. */
1973 ch = (*linep)->line[j];
1974 if (ch == '\t') {
1975 chars = st->tabnumber - i % st->tabnumber;
1976 ch = ' ';
1977 }
1978 else {
1979 chars = 1;
1980 }
1981
1982 while (chars--) {
1983 if (i + columns - start > max) {
1984 end = std::min(end, i);
1985
1986 *charp = endj;
1987
1988 if (j >= oldc) {
1989 if (ch == '\0') {
1991 (*linep)->line, (*linep)->len, start, TXT_TABSIZE);
1992 }
1993 loop = false;
1994 break;
1995 }
1996
1997 if (chop) {
1998 endj = j;
1999 }
2000
2001 start = end;
2002 end += max;
2003 chop = true;
2004 }
2005 else if (ELEM(ch, ' ', '-', '\0')) {
2006 if (j >= oldc) {
2008 (*linep)->line, (*linep)->len, start, TXT_TABSIZE);
2009 loop = false;
2010 break;
2011 }
2012
2013 end = i + 1;
2014 endj = j + 1;
2015 chop = false;
2016 }
2017 i += columns;
2018 }
2019 }
2020
2021 if (!sel) {
2022 txt_pop_sel(text);
2023 }
2024}
2025
2026static void txt_wrap_move_eol(SpaceText *st, ARegion *region, const bool sel)
2027{
2028 Text *text = st->text;
2029 TextLine **linep;
2030 int *charp;
2031 int oldc, i, j, max, start, end, endj;
2032 bool chop, loop;
2033 char ch;
2034
2036
2037 if (sel) {
2038 linep = &text->sell;
2039 charp = &text->selc;
2040 }
2041 else {
2042 linep = &text->curl;
2043 charp = &text->curc;
2044 }
2045
2046 oldc = *charp;
2047
2048 max = space_text_wrap_width(st, region);
2049
2050 start = endj = 0;
2051 end = max;
2052 chop = loop = true;
2053 *charp = 0;
2054
2055 for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) {
2056 int chars;
2057 const int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab. */
2058
2059 /* Mimic replacement of tabs. */
2060 ch = (*linep)->line[j];
2061 if (ch == '\t') {
2062 chars = st->tabnumber - i % st->tabnumber;
2063 ch = ' ';
2064 }
2065 else {
2066 chars = 1;
2067 }
2068
2069 while (chars--) {
2070 if (i + columns - start > max) {
2071 end = std::min(end, i);
2072
2073 if (chop) {
2074 endj = BLI_str_find_prev_char_utf8((*linep)->line + j, (*linep)->line) - (*linep)->line;
2075 }
2076
2077 if (endj >= oldc) {
2078 if (ch == '\0') {
2079 *charp = (*linep)->len;
2080 }
2081 else {
2082 *charp = endj;
2083 }
2084 loop = false;
2085 break;
2086 }
2087
2088 start = end;
2089 end += max;
2090 chop = true;
2091 }
2092 else if (ch == '\0') {
2093 *charp = (*linep)->len;
2094 loop = false;
2095 break;
2096 }
2097 else if (ELEM(ch, ' ', '-')) {
2098 end = i + 1;
2099 endj = j;
2100 chop = false;
2101 }
2102 i += columns;
2103 }
2104 }
2105
2106 if (!sel) {
2107 txt_pop_sel(text);
2108 }
2109}
2110
2111static void txt_wrap_move_up(SpaceText *st, ARegion *region, const bool sel)
2112{
2113 Text *text = st->text;
2114 TextLine **linep;
2115 int *charp;
2116 int offl, offc, col;
2117
2119
2120 if (sel) {
2121 linep = &text->sell;
2122 charp = &text->selc;
2123 }
2124 else {
2125 linep = &text->curl;
2126 charp = &text->curc;
2127 }
2128
2129 space_text_wrap_offset_in_line(st, region, *linep, *charp, &offl, &offc);
2130 col = space_text_get_char_pos(st, (*linep)->line, *charp) + offc;
2131 if (offl) {
2132 *charp = space_text_get_cursor_rel(st, region, *linep, offl - 1, col);
2133 }
2134 else {
2135 if ((*linep)->prev) {
2136 int visible_lines;
2137
2138 *linep = (*linep)->prev;
2139 visible_lines = space_text_get_visible_lines(st, region, (*linep)->line);
2140 *charp = space_text_get_cursor_rel(st, region, *linep, visible_lines - 1, col);
2141 }
2142 else {
2143 *charp = 0;
2144 }
2145 }
2146
2147 if (!sel) {
2148 txt_pop_sel(text);
2149 }
2150}
2151
2152static void txt_wrap_move_down(SpaceText *st, ARegion *region, const bool sel)
2153{
2154 Text *text = st->text;
2155 TextLine **linep;
2156 int *charp;
2157 int offl, offc, col, visible_lines;
2158
2160
2161 if (sel) {
2162 linep = &text->sell;
2163 charp = &text->selc;
2164 }
2165 else {
2166 linep = &text->curl;
2167 charp = &text->curc;
2168 }
2169
2170 space_text_wrap_offset_in_line(st, region, *linep, *charp, &offl, &offc);
2171 col = space_text_get_char_pos(st, (*linep)->line, *charp) + offc;
2172 visible_lines = space_text_get_visible_lines(st, region, (*linep)->line);
2173 if (offl < visible_lines - 1) {
2174 *charp = space_text_get_cursor_rel(st, region, *linep, offl + 1, col);
2175 }
2176 else {
2177 if ((*linep)->next) {
2178 *linep = (*linep)->next;
2179 *charp = space_text_get_cursor_rel(st, region, *linep, 0, col);
2180 }
2181 else {
2182 *charp = (*linep)->len;
2183 }
2184 }
2185
2186 if (!sel) {
2187 txt_pop_sel(text);
2188 }
2189}
2190
2199 const SpaceText *st, const ARegion *region, Text *text, int lines, const bool sel)
2200{
2201 TextLine **linep;
2202 int *charp;
2203
2204 if (sel) {
2205 linep = &text->sell;
2206 charp = &text->selc;
2207 }
2208 else {
2209 linep = &text->curl;
2210 charp = &text->curc;
2211 }
2212
2213 if (st && region && st->wordwrap) {
2214 int rell, relc;
2215
2216 /* Find line and offsets inside it needed to set cursor position. */
2217 if (cursor_skip_find_line(st, region, lines, linep, charp, &rell, &relc)) {
2218 *charp = space_text_get_cursor_rel(st, region, *linep, rell, relc);
2219 }
2220 }
2221 else {
2222 while (lines > 0 && (*linep)->next) {
2223 *linep = (*linep)->next;
2224 lines--;
2225 }
2226 while (lines < 0 && (*linep)->prev) {
2227 *linep = (*linep)->prev;
2228 lines++;
2229 }
2230 }
2231
2232 *charp = std::min(*charp, (*linep)->len);
2233
2234 if (!sel) {
2235 txt_pop_sel(text);
2236 }
2237}
2238
2240{
2242 Text *text = CTX_data_edit_text(C);
2243 ARegion *region = CTX_wm_region(C);
2244
2245 /* Ensure we have the right region, it's optional. */
2246 if (region && region->regiontype != RGN_TYPE_WINDOW) {
2247 region = nullptr;
2248 }
2249
2250 switch (type) {
2251 case LINE_BEGIN:
2252 if (!select) {
2253 txt_sel_clear(text);
2254 }
2255 if (st && st->wordwrap && region) {
2256 txt_wrap_move_bol(st, region, select);
2257 }
2258 else {
2259 txt_move_bol(text, select);
2260 }
2261 break;
2262
2263 case LINE_END:
2264 if (!select) {
2265 txt_sel_clear(text);
2266 }
2267 if (st && st->wordwrap && region) {
2268 txt_wrap_move_eol(st, region, select);
2269 }
2270 else {
2271 txt_move_eol(text, select);
2272 }
2273 break;
2274
2275 case FILE_TOP:
2276 txt_move_bof(text, select);
2277 break;
2278
2279 case FILE_BOTTOM:
2280 txt_move_eof(text, select);
2281 break;
2282
2283 case PREV_WORD:
2284 if (txt_cursor_is_line_start(text)) {
2285 txt_move_left(text, select);
2286 }
2287 txt_jump_left(text, select, true);
2288 break;
2289
2290 case NEXT_WORD:
2291 if (txt_cursor_is_line_end(text)) {
2292 txt_move_right(text, select);
2293 }
2294 txt_jump_right(text, select, true);
2295 break;
2296
2297 case PREV_CHAR:
2298 if (txt_has_sel(text) && !select) {
2299 txt_order_cursors(text, false);
2300 txt_pop_sel(text);
2301 }
2302 else {
2303 txt_move_left(text, select);
2304 }
2305 break;
2306
2307 case NEXT_CHAR:
2308 if (txt_has_sel(text) && !select) {
2309 txt_order_cursors(text, true);
2310 txt_pop_sel(text);
2311 }
2312 else {
2313 txt_move_right(text, select);
2314 }
2315 break;
2316
2317 case PREV_LINE:
2318 if (st && st->wordwrap && region) {
2319 txt_wrap_move_up(st, region, select);
2320 }
2321 else {
2322 txt_move_up(text, select);
2323 }
2324 break;
2325
2326 case NEXT_LINE:
2327 if (st && st->wordwrap && region) {
2328 txt_wrap_move_down(st, region, select);
2329 }
2330 else {
2331 txt_move_down(text, select);
2332 }
2333 break;
2334
2335 case PREV_PAGE:
2336 if (st) {
2337 space_text_cursor_skip(st, region, st->text, -st->runtime->viewlines, select);
2338 }
2339 else {
2340 space_text_cursor_skip(nullptr, nullptr, text, -10, select);
2341 }
2342 break;
2343
2344 case NEXT_PAGE:
2345 if (st) {
2346 space_text_cursor_skip(st, region, st->text, st->runtime->viewlines, select);
2347 }
2348 else {
2349 space_text_cursor_skip(nullptr, nullptr, text, 10, select);
2350 }
2351 break;
2352 }
2353
2355 if (select) {
2357 }
2358
2360
2361 return OPERATOR_FINISHED;
2362}
2363
2365{
2366 int type = RNA_enum_get(op->ptr, "type");
2367
2368 return text_move_cursor(C, type, false);
2369}
2370
2372{
2373 /* Identifiers. */
2374 ot->name = "Move Cursor";
2375 ot->idname = "TEXT_OT_move";
2376 ot->description = "Move cursor to position type";
2377
2378 /* API callbacks. */
2379 ot->exec = text_move_exec;
2380 ot->poll = text_edit_poll;
2381
2382 /* Properties. */
2383 RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to");
2384}
2385
2387
2388/* -------------------------------------------------------------------- */
2391
2393{
2394 int type = RNA_enum_get(op->ptr, "type");
2395
2396 return text_move_cursor(C, type, true);
2397}
2398
2400{
2401 /* Identifiers. */
2402 ot->name = "Move Select";
2403 ot->idname = "TEXT_OT_move_select";
2404 ot->description = "Move the cursor while selecting";
2405
2406 /* API callbacks. */
2407 ot->exec = text_move_select_exec;
2408 ot->poll = text_space_edit_poll;
2409
2410 /* Properties. */
2411 RNA_def_enum(ot->srna,
2412 "type",
2414 LINE_BEGIN,
2415 "Type",
2416 "Where to move cursor to, to make a selection");
2417}
2418
2420
2421/* -------------------------------------------------------------------- */
2424
2426{
2427 Text *text = CTX_data_edit_text(C);
2428 int line = RNA_int_get(op->ptr, "line");
2429 short nlines = txt_get_span(static_cast<TextLine *>(text->lines.first),
2430 static_cast<TextLine *>(text->lines.last)) +
2431 1;
2432
2433 if (line < 1) {
2434 txt_move_toline(text, 1, false);
2435 }
2436 else if (line > nlines) {
2437 txt_move_toline(text, nlines - 1, false);
2438 }
2439 else {
2440 txt_move_toline(text, line - 1, false);
2441 }
2442
2445
2446 return OPERATOR_FINISHED;
2447}
2448
2450{
2451 return WM_operator_props_dialog_popup(C, op, 200, IFACE_("Jump to Line Number"));
2452}
2453
2455{
2456 /* Identifiers. */
2457 ot->name = "Jump";
2458 ot->idname = "TEXT_OT_jump";
2459 ot->description = "Jump cursor to line";
2460
2461 /* API callbacks. */
2462 ot->invoke = text_jump_invoke;
2463 ot->exec = text_jump_exec;
2464 ot->poll = text_edit_poll;
2465
2466 /* Properties. */
2467 ot->prop = RNA_def_int(
2468 ot->srna, "line", 1, 1, INT_MAX, "Line", "Line number to jump to", 1, 10000);
2470}
2471
2473
2474/* -------------------------------------------------------------------- */
2477
2479 {DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
2480 {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
2481 {DEL_NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
2482 {DEL_PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
2483 {0, nullptr, 0, nullptr, nullptr},
2484};
2485
2487{
2489 Text *text = CTX_data_edit_text(C);
2490 int type = RNA_enum_get(op->ptr, "type");
2491
2493
2494 /* Behavior could be changed here,
2495 * but for now just don't jump words when we have a selection. */
2496 if (txt_has_sel(text)) {
2497 if (type == DEL_PREV_WORD) {
2498 type = DEL_PREV_CHAR;
2499 }
2500 else if (type == DEL_NEXT_WORD) {
2501 type = DEL_NEXT_CHAR;
2502 }
2503 }
2504
2506
2507 if (type == DEL_PREV_WORD) {
2508 if (txt_cursor_is_line_start(text)) {
2509 txt_backspace_char(text);
2510 }
2511 txt_backspace_word(text);
2512 }
2513 else if (type == DEL_PREV_CHAR) {
2514
2515 if (text->flags & TXT_TABSTOSPACES) {
2516 if (!txt_has_sel(text) && !txt_cursor_is_line_start(text)) {
2517 int tabsize = 0;
2518 tabsize = txt_calc_tab_left(text->curl, text->curc);
2519 if (tabsize) {
2520 text->sell = text->curl;
2521 text->selc = text->curc - tabsize;
2522 txt_order_cursors(text, false);
2523 }
2524 }
2525 }
2526 if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) {
2527 const char *curr = text->curl->line + text->curc;
2528 if (*curr != '\0') {
2529 const char *prev = BLI_str_find_prev_char_utf8(curr, text->curl->line);
2530 if ((curr != prev) && /* When back-spacing from the start of the line. */
2531 (*curr == text_closing_character_pair_get(*prev)))
2532 {
2533 txt_move_right(text, false);
2534 txt_backspace_char(text);
2535 }
2536 }
2537 }
2538 txt_backspace_char(text);
2539 }
2540 else if (type == DEL_NEXT_WORD) {
2541 if (txt_cursor_is_line_end(text)) {
2542 txt_delete_char(text);
2543 }
2544 txt_delete_word(text);
2545 }
2546 else if (type == DEL_NEXT_CHAR) {
2547
2548 if (text->flags & TXT_TABSTOSPACES) {
2549 if (!txt_has_sel(text) && !txt_cursor_is_line_end(text)) {
2550 int tabsize = 0;
2551 tabsize = txt_calc_tab_right(text->curl, text->curc);
2552 if (tabsize) {
2553 text->sell = text->curl;
2554 text->selc = text->curc + tabsize;
2555 txt_order_cursors(text, true);
2556 }
2557 }
2558 }
2559
2560 txt_delete_char(text);
2561 }
2562
2564
2567
2568 /* Run the script while editing, evil but useful. */
2569 if (st->live_edit) {
2570 text_run_script(C, nullptr);
2571 }
2572
2573 return OPERATOR_FINISHED;
2574}
2575
2577{
2578 /* Identifiers. */
2579 ot->name = "Delete";
2580 ot->idname = "TEXT_OT_delete";
2581 ot->description = "Delete text by cursor position";
2582
2583 /* API callbacks. */
2584 ot->exec = text_delete_exec;
2585 ot->poll = text_edit_poll;
2586
2587 /* Flags. */
2588 ot->flag = OPTYPE_UNDO;
2589
2590 /* Properties. */
2591 PropertyRNA *prop;
2592 prop = RNA_def_enum(ot->srna,
2593 "type",
2596 "Type",
2597 "Which part of the text to delete");
2599}
2600
2602
2603/* -------------------------------------------------------------------- */
2606
2608{
2610
2611 st->overwrite = !st->overwrite;
2612
2614
2615 return OPERATOR_FINISHED;
2616}
2617
2619{
2620 /* Identifiers. */
2621 ot->name = "Toggle Overwrite";
2622 ot->idname = "TEXT_OT_overwrite_toggle";
2623 ot->description = "Toggle overwrite while typing";
2624
2625 /* API callbacks. */
2627 ot->poll = text_space_edit_poll;
2628}
2629
2631
2632/* -------------------------------------------------------------------- */
2635
2636static void space_text_screen_clamp(SpaceText *st, const ARegion *region)
2637{
2638 if (st->top <= 0) {
2639 st->top = 0;
2640 }
2641 else {
2642 int last;
2643 last = space_text_get_total_lines(st, region);
2644 last = last - (st->runtime->viewlines / 2);
2645 if (last > 0 && st->top > last) {
2646 st->top = last;
2647 }
2648 }
2649}
2650
2651/* Moves the view vertically by the specified number of lines. */
2652static void space_text_screen_skip(SpaceText *st, ARegion *region, int lines)
2653{
2654 st->top += lines;
2655 space_text_screen_clamp(st, region);
2656}
2657
2665
2669
2672
2674
2675 /* Store the state of the display, cache some constant vars. */
2676 struct {
2677 int ofs_init[2];
2678 int ofs_max[2];
2679 int size_px[2];
2683};
2684
2686{
2687 tsc->state.ofs_init[0] = st->left;
2688 tsc->state.ofs_init[1] = st->top;
2689
2690 tsc->state.ofs_max[0] = INT_MAX;
2691 tsc->state.ofs_max[1] = max_ii(
2692 0, space_text_get_total_lines(st, region) - (st->runtime->viewlines / 2));
2693
2694 tsc->state.size_px[0] = st->runtime->cwidth_px;
2695 tsc->state.size_px[1] = TXT_LINE_HEIGHT(st);
2696}
2697
2699{
2700 /* It should be possible to still scroll linked texts to read them,
2701 * even if they can't be edited... */
2702 return CTX_data_edit_text(C) != nullptr;
2703}
2704
2706{
2708 ARegion *region = CTX_wm_region(C);
2709
2710 int lines = RNA_int_get(op->ptr, "lines");
2711
2712 if (lines == 0) {
2713 return OPERATOR_CANCELLED;
2714 }
2715
2716 space_text_screen_skip(st, region, lines * 3);
2717
2719
2720 return OPERATOR_FINISHED;
2721}
2722
2723static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event)
2724{
2726 TextScroll *tsc = static_cast<TextScroll *>(op->customdata);
2727 const int mval[2] = {event->xy[0], event->xy[1]};
2728
2730
2731 /* Compute mouse move distance. */
2732 if (tsc->is_first) {
2733 copy_v2_v2_int(tsc->mval_prev, mval);
2734 tsc->is_first = false;
2735 }
2736
2737 if (event->type != MOUSEPAN) {
2738 sub_v2_v2v2_int(tsc->mval_delta, mval, tsc->mval_prev);
2739 }
2740
2741 /* Accumulate scroll, in float values for events that give less than one
2742 * line offset but taken together should still scroll. */
2743 if (!tsc->is_scrollbar) {
2744 tsc->ofs_delta_px[0] -= tsc->mval_delta[0];
2745 tsc->ofs_delta_px[1] += tsc->mval_delta[1];
2746 }
2747 else {
2748 tsc->ofs_delta_px[1] -= (tsc->mval_delta[1] * st->runtime->scroll_px_per_line) *
2749 tsc->state.size_px[1];
2750 }
2751
2752 for (int i = 0; i < 2; i += 1) {
2753 int lines_from_pixels = tsc->ofs_delta_px[i] / tsc->state.size_px[i];
2754 tsc->ofs_delta[i] += lines_from_pixels;
2755 tsc->ofs_delta_px[i] -= lines_from_pixels * tsc->state.size_px[i];
2756 }
2757
2758 /* The final values need to be calculated from the inputs,
2759 * so clamping and ensuring an unsigned pixel offset doesn't conflict with
2760 * updating the cursor mval_delta. */
2761 int scroll_ofs_new[2] = {
2762 tsc->state.ofs_init[0] + tsc->ofs_delta[0],
2763 tsc->state.ofs_init[1] + tsc->ofs_delta[1],
2764 };
2765 int scroll_ofs_px_new[2] = {
2766 tsc->ofs_delta_px[0],
2767 tsc->ofs_delta_px[1],
2768 };
2769
2770 for (int i = 0; i < 2; i += 1) {
2771 /* Ensure always unsigned (adjusting line/column accordingly). */
2772 while (scroll_ofs_px_new[i] < 0) {
2773 scroll_ofs_px_new[i] += tsc->state.size_px[i];
2774 scroll_ofs_new[i] -= 1;
2775 }
2776
2777 /* Clamp within usable region. */
2778 if (scroll_ofs_new[i] < 0) {
2779 scroll_ofs_new[i] = 0;
2780 scroll_ofs_px_new[i] = 0;
2781 }
2782 else if (scroll_ofs_new[i] >= tsc->state.ofs_max[i]) {
2783 scroll_ofs_new[i] = tsc->state.ofs_max[i];
2784 scroll_ofs_px_new[i] = 0;
2785 }
2786 }
2787
2788 /* Override for word-wrap. */
2789 if (st->wordwrap) {
2790 scroll_ofs_new[0] = 0;
2791 scroll_ofs_px_new[0] = 0;
2792 }
2793
2794 /* Apply to the screen. */
2795 if (scroll_ofs_new[0] != st->left || scroll_ofs_new[1] != st->top ||
2796 /* Horizontal sub-pixel offset currently isn't used. */
2797 /* `scroll_ofs_px_new[0] != st->scroll_ofs_px[0] ||`. */
2798 scroll_ofs_px_new[1] != st->runtime->scroll_ofs_px[1])
2799 {
2800
2801 st->left = scroll_ofs_new[0];
2802 st->top = scroll_ofs_new[1];
2803 st->runtime->scroll_ofs_px[0] = scroll_ofs_px_new[0];
2804 st->runtime->scroll_ofs_px[1] = scroll_ofs_px_new[1];
2806 }
2807
2808 tsc->mval_prev[0] = mval[0];
2809 tsc->mval_prev[1] = mval[1];
2810}
2811
2813{
2815 TextScroll *tsc = static_cast<TextScroll *>(op->customdata);
2816
2817 st->flags &= ~ST_SCROLL_SELECT;
2818
2819 if (st->runtime->scroll_ofs_px[1] > tsc->state.size_px[1] / 2) {
2820 st->top += 1;
2821 }
2822
2823 st->runtime->scroll_ofs_px[0] = 0;
2824 st->runtime->scroll_ofs_px[1] = 0;
2826
2827 MEM_freeN(tsc);
2828 op->customdata = nullptr;
2829}
2830
2832{
2833 TextScroll *tsc = static_cast<TextScroll *>(op->customdata);
2835 ARegion *region = CTX_wm_region(C);
2836
2837 switch (event->type) {
2838 case MOUSEMOVE:
2839 if (tsc->zone == SCROLLHANDLE_BAR) {
2840 text_scroll_apply(C, op, event);
2841 }
2842 break;
2843 case LEFTMOUSE:
2844 case RIGHTMOUSE:
2845 case MIDDLEMOUSE:
2846 if (event->val == KM_RELEASE) {
2849 region,
2850 st->runtime->viewlines *
2851 (tsc->zone == SCROLLHANDLE_MIN_OUTSIDE ? 1 : -1));
2852
2854 }
2855 scroll_exit(C, op);
2856 return OPERATOR_FINISHED;
2857 }
2858 default: {
2859 break;
2860 }
2861 }
2862
2864}
2865
2867{
2868 scroll_exit(C, op);
2869}
2870
2872{
2874 ARegion *region = CTX_wm_region(C);
2875
2876 TextScroll *tsc;
2877
2878 if (RNA_struct_property_is_set(op->ptr, "lines")) {
2879 return text_scroll_exec(C, op);
2880 }
2881
2882 tsc = MEM_callocN<TextScroll>("TextScroll");
2883 tsc->is_first = true;
2884 tsc->zone = SCROLLHANDLE_BAR;
2885
2886 text_scroll_state_init(tsc, st, region);
2887
2888 op->customdata = tsc;
2889
2890 st->flags |= ST_SCROLL_SELECT;
2891
2892 if (event->type == MOUSEPAN) {
2894
2895 copy_v2_v2_int(tsc->mval_prev, event->xy);
2896 /* Sensitivity of scroll set to 4pix per line/char. */
2897 tsc->mval_delta[0] = (event->xy[0] - event->prev_xy[0]) * st->runtime->cwidth_px / 4;
2898 tsc->mval_delta[1] = (event->xy[1] - event->prev_xy[1]) * st->runtime->lheight_px / 4;
2899 tsc->is_first = false;
2900 tsc->is_scrollbar = false;
2901 text_scroll_apply(C, op, event);
2902 scroll_exit(C, op);
2903 return OPERATOR_FINISHED;
2904 }
2905
2907
2909}
2910
2912{
2913 /* Identifiers. */
2914 ot->name = "Scroll";
2915 /* Don't really see the difference between this and scroll_bar.
2916 * Both do basically the same thing (aside from key-maps). */
2917 ot->idname = "TEXT_OT_scroll";
2918
2919 /* API callbacks. */
2920 ot->exec = text_scroll_exec;
2921 ot->invoke = text_scroll_invoke;
2922 ot->modal = text_scroll_modal;
2923 ot->cancel = text_scroll_cancel;
2924 ot->poll = text_scroll_poll;
2925
2926 /* Flags. */
2928
2929 /* Properties. */
2930 PropertyRNA *prop;
2931 prop = RNA_def_int(
2932 ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
2934}
2935
2937
2938/* -------------------------------------------------------------------- */
2941
2943{
2944 /* Same as text_region_edit_poll except it works on libdata too. */
2946 Text *text = CTX_data_edit_text(C);
2947 ARegion *region = CTX_wm_region(C);
2948
2949 if (!st || !text) {
2950 return false;
2951 }
2952
2953 if (!region || region->regiontype != RGN_TYPE_WINDOW) {
2954 return false;
2955 }
2956
2957 return true;
2958}
2959
2961{
2963 ARegion *region = CTX_wm_region(C);
2964 TextScroll *tsc;
2965 const int *mval = event->mval;
2967
2968 if (RNA_struct_property_is_set(op->ptr, "lines")) {
2969 return text_scroll_exec(C, op);
2970 }
2971
2972 /* Verify we are in the right zone. */
2973 if (mval[0] > st->runtime->scroll_region_handle.xmin &&
2974 mval[0] < st->runtime->scroll_region_handle.xmax)
2975 {
2976 if (mval[1] >= st->runtime->scroll_region_handle.ymin &&
2977 mval[1] <= st->runtime->scroll_region_handle.ymax)
2978 {
2979 /* Mouse inside scroll handle. */
2980 zone = SCROLLHANDLE_BAR;
2981 }
2982 else if (mval[1] > TXT_SCROLL_SPACE && mval[1] < region->winy - TXT_SCROLL_SPACE) {
2983 if (mval[1] < st->runtime->scroll_region_handle.ymin) {
2985 }
2986 else {
2988 }
2989 }
2990 }
2991
2992 if (zone == SCROLLHANDLE_INVALID_OUTSIDE) {
2993 /* We are outside slider - nothing to do. */
2994 return OPERATOR_PASS_THROUGH;
2995 }
2996
2997 tsc = MEM_callocN<TextScroll>("TextScroll");
2998 tsc->is_first = true;
2999 tsc->is_scrollbar = true;
3000 tsc->zone = zone;
3001 op->customdata = tsc;
3002 st->flags |= ST_SCROLL_SELECT;
3003
3004 text_scroll_state_init(tsc, st, region);
3005
3006 /* Jump scroll, works in `v2d` but needs to be added here too unfortunately. */
3007 if (event->type == MIDDLEMOUSE) {
3008 tsc->mval_prev[0] = region->winrct.xmin + BLI_rcti_cent_x(&st->runtime->scroll_region_handle);
3009 tsc->mval_prev[1] = region->winrct.ymin + BLI_rcti_cent_y(&st->runtime->scroll_region_handle);
3010
3011 tsc->is_first = false;
3012 tsc->zone = SCROLLHANDLE_BAR;
3013 text_scroll_apply(C, op, event);
3014 }
3015
3017
3019}
3020
3022{
3023 /* Identifiers. */
3024 ot->name = "Scrollbar";
3025 /* Don't really see the difference between this and scroll.
3026 * Both do basically the same thing (aside from key-maps). */
3027 ot->idname = "TEXT_OT_scroll_bar";
3028
3029 /* API callbacks. */
3030 ot->invoke = text_scroll_bar_invoke;
3031 ot->modal = text_scroll_modal;
3032 ot->cancel = text_scroll_cancel;
3034
3035 /* Flags. */
3037
3038 /* Properties. */
3039 PropertyRNA *prop;
3040 prop = RNA_def_int(
3041 ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
3043}
3044
3046
3047/* -------------------------------------------------------------------- */
3050
3053 short mval_prev[2];
3054 wmTimer *timer; /* Needed for scrolling when mouse at region bounds. */
3055};
3056
3057static int flatten_width(SpaceText *st, const char *str)
3058{
3059 int total = 0;
3060
3061 for (int i = 0; str[i]; i += BLI_str_utf8_size_safe(str + i)) {
3062 const int columns = (str[i] == '\t') ? (st->tabnumber - total % st->tabnumber) :
3064 total += columns;
3065 }
3066
3067 return total;
3068}
3069
3070static int flatten_column_to_offset(SpaceText *st, const char *str, int index)
3071{
3072 int i = 0, j = 0;
3073
3074 while (*(str + j)) {
3075 const int col = (str[j] == '\t') ? (st->tabnumber - i % st->tabnumber) :
3077 if (i + col > index) {
3078 break;
3079 }
3080
3081 i += col;
3082 j += BLI_str_utf8_size_safe(str + j);
3083 }
3084
3085 return j;
3086}
3087
3089 const ARegion *region,
3090 int *y)
3091{
3092 TextLine *linep = static_cast<TextLine *>(st->text->lines.first);
3093 int i, lines;
3094
3095 if (*y < -st->top) {
3096 return nullptr; /* We are beyond the first line... */
3097 }
3098
3099 for (i = -st->top; i <= *y && linep; linep = linep->next, i += lines) {
3100 lines = space_text_get_visible_lines(st, region, linep->line);
3101
3102 if (i + lines > *y) {
3103 /* We found the line matching given vertical *coordinate*,
3104 * now set y relative to this line's start. */
3105 *y -= i;
3106 break;
3107 }
3108 }
3109 return linep;
3110}
3111
3113 const SpaceText *st, const ARegion *region, int x, int y, const bool sel)
3114{
3115 Text *text = st->text;
3116 int max = space_text_wrap_width(st, region); /* Column. */
3117 int charp = -1; /* Mem. */
3118 bool found = false; /* Flags. */
3119
3120 /* Point to line matching given y position, if any. */
3122
3123 if (linep) {
3124 int i = 0, start = 0, end = max; /* Column. */
3125 int j, curs = 0, endj = 0; /* Mem. */
3126 bool chop = true; /* Flags. */
3127 char ch;
3128
3129 for (j = 0; !found && ((ch = linep->line[j]) != '\0');
3130 j += BLI_str_utf8_size_safe(linep->line + j))
3131 {
3132 int chars;
3133 const int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab. */
3134
3135 /* Mimic replacement of tabs. */
3136 if (ch == '\t') {
3137 chars = st->tabnumber - i % st->tabnumber;
3138 ch = ' ';
3139 }
3140 else {
3141 chars = 1;
3142 }
3143
3144 while (chars--) {
3145 /* Gone too far, go back to last wrap point. */
3146 if (y < 0) {
3147 charp = endj;
3148 y = 0;
3149 found = true;
3150 break;
3151 /* Exactly at the cursor. */
3152 }
3153 if (y == 0 && i - start <= x && i + columns - start > x) {
3154 /* Current position could be wrapped to next line. */
3155 /* This should be checked when end of current line would be reached. */
3156 charp = curs = j;
3157 found = true;
3158 /* Prepare curs for next wrap. */
3159 }
3160 else if (i - end <= x && i + columns - end > x) {
3161 curs = j;
3162 }
3163 if (i + columns - start > max) {
3164 end = std::min(end, i);
3165
3166 if (found) {
3167 /* Exact cursor position was found, check if it's still on needed line
3168 * (hasn't been wrapped). */
3169 if (charp > endj && !chop && ch != '\0') {
3170 charp = endj;
3171 }
3172 break;
3173 }
3174
3175 if (chop) {
3176 endj = j;
3177 }
3178 start = end;
3179 end += max;
3180
3181 if (j < linep->len) {
3182 y--;
3183 }
3184
3185 chop = true;
3186 if (y == 0 && i + columns - start > x) {
3187 charp = curs;
3188 found = true;
3189 break;
3190 }
3191 }
3192 else if (ELEM(ch, ' ', '-', '\0')) {
3193 if (found) {
3194 break;
3195 }
3196
3197 if (y == 0 && i + columns - start > x) {
3198 charp = curs;
3199 found = true;
3200 break;
3201 }
3202 end = i + 1;
3203 endj = j;
3204 chop = false;
3205 }
3206 i += columns;
3207 }
3208 }
3209
3210 BLI_assert(y == 0);
3211
3212 if (!found) {
3213 /* On correct line but didn't meet cursor, must be at end. */
3214 charp = linep->len;
3215 }
3216 }
3217 else if (y < 0) { /* Before start of text. */
3218 linep = static_cast<TextLine *>(st->text->lines.first);
3219 charp = 0;
3220 }
3221 else { /* Beyond end of text. */
3222 linep = static_cast<TextLine *>(st->text->lines.last);
3223 charp = linep->len;
3224 }
3225
3226 BLI_assert(linep && charp != -1);
3227
3228 if (sel) {
3229 text->sell = linep;
3230 text->selc = charp;
3231 }
3232 else {
3233 text->curl = linep;
3234 text->curc = charp;
3235 }
3236}
3237
3239 SpaceText *st, const ARegion *region, int x, int y, const bool sel)
3240{
3241 Text *text = st->text;
3243 y = (region->winy - 2 - y) / TXT_LINE_HEIGHT(st);
3244
3245 x -= TXT_BODY_LEFT(st);
3246 x = std::max(x, 0);
3247 x = space_text_pixel_x_to_column(st, x) + st->left;
3248
3249 if (st->wordwrap) {
3250 space_text_cursor_set_to_pos_wrapped(st, region, x, y, sel);
3251 }
3252 else {
3253 TextLine **linep;
3254 int *charp;
3255 int w;
3256
3257 if (sel) {
3258 linep = &text->sell;
3259 charp = &text->selc;
3260 }
3261 else {
3262 linep = &text->curl;
3263 charp = &text->curc;
3264 }
3265
3266 y -= txt_get_span(static_cast<TextLine *>(text->lines.first), *linep) - st->top;
3267
3268 if (y > 0) {
3269 while (y-- != 0) {
3270 if ((*linep)->next) {
3271 *linep = (*linep)->next;
3272 }
3273 }
3274 }
3275 else if (y < 0) {
3276 while (y++ != 0) {
3277 if ((*linep)->prev) {
3278 *linep = (*linep)->prev;
3279 }
3280 }
3281 }
3282
3283 w = flatten_width(st, (*linep)->line);
3284 if (x < w) {
3285 *charp = flatten_column_to_offset(st, (*linep)->line, x);
3286 }
3287 else {
3288 *charp = (*linep)->len;
3289 }
3290 }
3291 if (!sel) {
3292 txt_pop_sel(text);
3293 }
3294}
3295
3297{
3298 if (ssel->timer == nullptr) {
3300 wmWindow *win = CTX_wm_window(C);
3301
3302 ssel->timer = WM_event_timer_add(wm, win, TIMER, 0.02f);
3303 }
3304}
3305
3307{
3308 if (ssel->timer) {
3310 wmWindow *win = CTX_wm_window(C);
3311
3312 WM_event_timer_remove(wm, win, ssel->timer);
3313 }
3314 ssel->timer = nullptr;
3315}
3316
3317static void text_cursor_set_apply(bContext *C, wmOperator *op, const wmEvent *event)
3318{
3320 ARegion *region = CTX_wm_region(C);
3321 SetSelection *ssel = static_cast<SetSelection *>(op->customdata);
3322
3323 if (event->mval[1] < 0 || event->mval[1] > region->winy) {
3325
3326 if (event->type == TIMER) {
3327 text_cursor_set_to_pos(st, region, event->mval[0], event->mval[1], true);
3328 ED_space_text_scroll_to_cursor(st, region, false);
3330 }
3331 }
3332 else if (!st->wordwrap && (event->mval[0] < 0 || event->mval[0] > region->winx)) {
3334
3335 if (event->type == TIMER) {
3337 st, region, std::clamp(event->mval[0], 0, int(region->winx)), event->mval[1], true);
3338 ED_space_text_scroll_to_cursor(st, region, false);
3340 }
3341 }
3342 else {
3344
3345 if (event->type != TIMER) {
3346 text_cursor_set_to_pos(st, region, event->mval[0], event->mval[1], true);
3347 ED_space_text_scroll_to_cursor(st, region, false);
3349
3350 ssel->mval_prev[0] = event->mval[0];
3351 ssel->mval_prev[1] = event->mval[1];
3352 }
3353 }
3354}
3355
3357{
3359 SetSelection *ssel = static_cast<SetSelection *>(op->customdata);
3360
3363
3365
3367 MEM_freeN(ssel);
3368}
3369
3371 wmOperator *op,
3372 const wmEvent *event)
3373{
3375 SetSelection *ssel;
3376
3377 if (event->mval[0] >= st->runtime->scroll_region_handle.xmin) {
3378 return OPERATOR_PASS_THROUGH;
3379 }
3380
3381 op->customdata = MEM_callocN(sizeof(SetSelection), "SetCursor");
3382 ssel = static_cast<SetSelection *>(op->customdata);
3383
3384 ssel->mval_prev[0] = event->mval[0];
3385 ssel->mval_prev[1] = event->mval[1];
3386
3387 ssel->sell = txt_get_span(static_cast<TextLine *>(st->text->lines.first), st->text->sell);
3388 ssel->selc = st->text->selc;
3389
3391
3392 text_cursor_set_apply(C, op, event);
3393
3395}
3396
3398{
3399 switch (event->type) {
3400 case LEFTMOUSE:
3401 case MIDDLEMOUSE:
3402 case RIGHTMOUSE:
3404 return OPERATOR_FINISHED;
3405 case TIMER:
3406 case MOUSEMOVE:
3407 text_cursor_set_apply(C, op, event);
3408 break;
3409 default: {
3410 break;
3411 }
3412 }
3413
3415}
3416
3418{
3420}
3421
3423{
3424 /* Identifiers. */
3425 ot->name = "Set Selection";
3426 ot->idname = "TEXT_OT_selection_set";
3427 ot->description = "Set text selection";
3428
3429 /* API callbacks. */
3430 ot->invoke = text_selection_set_invoke;
3432 ot->cancel = text_selection_set_cancel;
3433 ot->poll = text_region_edit_poll;
3434}
3435
3437
3438/* -------------------------------------------------------------------- */
3441
3443{
3445 ARegion *region = CTX_wm_region(C);
3446 int x = RNA_int_get(op->ptr, "x");
3447 int y = RNA_int_get(op->ptr, "y");
3448
3449 text_cursor_set_to_pos(st, region, x, y, false);
3450
3453
3454 return OPERATOR_PASS_THROUGH;
3455}
3456
3458{
3460
3461 if (event->mval[0] >= st->runtime->scroll_region_handle.xmin) {
3462 return OPERATOR_PASS_THROUGH;
3463 }
3464
3465 RNA_int_set(op->ptr, "x", event->mval[0]);
3466 RNA_int_set(op->ptr, "y", event->mval[1]);
3467
3468 return text_cursor_set_exec(C, op);
3469}
3470
3472{
3473 /* Identifiers. */
3474 ot->name = "Set Cursor";
3475 ot->idname = "TEXT_OT_cursor_set";
3476 ot->description = "Set cursor position";
3477
3478 /* API callbacks. */
3479 ot->invoke = text_cursor_set_invoke;
3480 ot->exec = text_cursor_set_exec;
3481 ot->poll = text_region_edit_poll;
3482
3483 /* Properties. */
3484 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
3485 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
3486}
3487
3489
3490/* -------------------------------------------------------------------- */
3493
3495 wmOperator * /*op*/,
3496 const wmEvent *event)
3497{
3499 Text *text = CTX_data_edit_text(C);
3500 ARegion *region = CTX_wm_region(C);
3501 const int *mval = event->mval;
3502 double time;
3503 static int jump_to = 0;
3504 static double last_jump = 0;
3505
3507
3508 if (!st->showlinenrs) {
3509 return OPERATOR_PASS_THROUGH;
3510 }
3511
3512 if (!(mval[0] > 2 &&
3513 mval[0] < (TXT_NUMCOL_WIDTH(st) + (TXT_BODY_LPAD * st->runtime->cwidth_px)) &&
3514 mval[1] > 2 && mval[1] < region->winy - 2))
3515 {
3516 return OPERATOR_PASS_THROUGH;
3517 }
3518
3519 const char event_ascii = WM_event_utf8_to_ascii(event);
3520 if (!(event_ascii >= '0' && event_ascii <= '9')) {
3521 return OPERATOR_PASS_THROUGH;
3522 }
3523
3524 time = BLI_time_now_seconds();
3525 if (last_jump < time - 1) {
3526 jump_to = 0;
3527 }
3528
3529 jump_to *= 10;
3530 jump_to += int(event_ascii - '0');
3531
3532 txt_move_toline(text, jump_to - 1, false);
3533 last_jump = time;
3534
3537
3538 return OPERATOR_FINISHED;
3539}
3540
3542{
3543 /* Identifiers. */
3544 ot->name = "Line Number";
3545 ot->idname = "TEXT_OT_line_number";
3546 ot->description = "The current line number";
3547
3548 /* API callbacks. */
3549 ot->invoke = text_line_number_invoke;
3550 ot->poll = text_region_edit_poll;
3551}
3552
3554
3555/* -------------------------------------------------------------------- */
3558
3560{
3562 Text *text = CTX_data_edit_text(C);
3563 char *str;
3564 int str_len;
3565 bool done = false;
3566 size_t i = 0;
3567 uint code;
3568
3570
3571 str = RNA_string_get_alloc(op->ptr, "text", nullptr, 0, &str_len);
3572
3574
3575 if (st && st->overwrite) {
3576 while (str[i]) {
3577 code = BLI_str_utf8_as_unicode_step_safe(str, str_len, &i);
3578 done |= txt_replace_char(text, code);
3579 }
3580 }
3581 else {
3582 while (str[i]) {
3583 code = BLI_str_utf8_as_unicode_step_safe(str, str_len, &i);
3584 done |= txt_add_char(text, code);
3585 }
3586 }
3587
3588 MEM_freeN(str);
3589
3590 if (!done) {
3591 return OPERATOR_CANCELLED;
3592 }
3593
3595
3598
3599 return OPERATOR_FINISHED;
3600}
3601
3603{
3606
3607 /* Auto-close variables. */
3608 bool do_auto_close = false;
3609 bool do_auto_close_select = false;
3610
3611 uint auto_close_char_input = 0;
3612 uint auto_close_char_match = 0;
3613 /* Variables needed to restore the selection when auto-closing around an existing selection. */
3614 struct {
3615 TextLine *sell;
3616 TextLine *curl;
3617 int selc;
3618 int curc;
3619 } auto_close_select = {nullptr}, auto_close_select_backup = {nullptr};
3620
3621 /* NOTE: the "text" property is always set from key-map,
3622 * so we can't use #RNA_struct_property_is_set, check the length instead. */
3623 if (!RNA_string_length(op->ptr, "text")) {
3624 /* If Alt/Control/Super are pressed pass through except for UTF8 character event
3625 * (when input method are used for UTF8 inputs, the user may assign key event
3626 * including Alt/Control/Super like Control-M to commit UTF8 string.
3627 * In such case, the modifiers in the UTF8 character event make no sense). */
3628 if ((event->modifier & (KM_CTRL | KM_OSKEY)) && !event->utf8_buf[0]) {
3629 return OPERATOR_PASS_THROUGH;
3630 }
3631
3632 char str[BLI_UTF8_MAX + 1];
3633 const size_t len = BLI_str_utf8_size_safe(event->utf8_buf);
3634 memcpy(str, event->utf8_buf, len);
3635 str[len] = '\0';
3636 RNA_string_set(op->ptr, "text", str);
3637
3638 if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) {
3639 auto_close_char_input = BLI_str_utf8_as_unicode_or_error(str);
3640 if (isascii(auto_close_char_input)) {
3641 auto_close_char_match = text_closing_character_pair_get(auto_close_char_input);
3642 if (auto_close_char_match != 0) {
3643 do_auto_close = true;
3644
3645 if (txt_has_sel(st->text) &&
3646 !text_span_is_blank(st->text->sell, st->text->selc, st->text->curl, st->text->curc))
3647 {
3648 do_auto_close_select = true;
3649
3650 auto_close_select_backup.curl = st->text->curl;
3651 auto_close_select_backup.curc = st->text->curc;
3652 auto_close_select_backup.sell = st->text->sell;
3653 auto_close_select_backup.selc = st->text->selc;
3654
3655 /* Movers the cursor to the start of the selection. */
3656 txt_order_cursors(st->text, false);
3657
3658 auto_close_select.curl = st->text->curl;
3659 auto_close_select.curc = st->text->curc;
3660 auto_close_select.sell = st->text->sell;
3661 auto_close_select.selc = st->text->selc;
3662
3663 txt_pop_sel(st->text);
3664 }
3665 }
3666 }
3667 }
3668 }
3669
3670 ret = text_insert_exec(C, op);
3671
3672 if (do_auto_close) {
3673 if (ret == OPERATOR_FINISHED) {
3674 const int auto_close_char_len = BLI_str_utf8_from_unicode_len(auto_close_char_input);
3675 /* If there was a selection, move cursor to the end of it. */
3676 if (do_auto_close_select) {
3677 /* Update the value in-place as needed. */
3678 if (auto_close_select.curl == auto_close_select.sell) {
3679 auto_close_select.selc += auto_close_char_len;
3680 }
3681 /* Move the cursor to the end of the selection. */
3682 st->text->curl = auto_close_select.sell;
3683 st->text->curc = auto_close_select.selc;
3684 txt_pop_sel(st->text);
3685 }
3686
3687 txt_add_char(st->text, auto_close_char_match);
3688 txt_move_left(st->text, false);
3689
3690 /* If there was a selection, restore it. */
3691 if (do_auto_close_select) {
3692 /* Mark the selection as edited. */
3693 if (auto_close_select.curl != auto_close_select.sell) {
3694 TextLine *line = auto_close_select.curl;
3695 do {
3696 line = line->next;
3698 } while (line != auto_close_select.sell);
3699 }
3700 st->text->curl = auto_close_select.curl;
3701 st->text->curc = auto_close_select.curc + auto_close_char_len;
3702 st->text->sell = auto_close_select.sell;
3703 st->text->selc = auto_close_select.selc;
3704 }
3705 }
3706 else {
3707 /* If nothing was done & the selection was removed, restore the selection. */
3708 if (do_auto_close_select) {
3709 st->text->curl = auto_close_select_backup.curl;
3710 st->text->curc = auto_close_select_backup.curc;
3711 st->text->sell = auto_close_select_backup.sell;
3712 st->text->selc = auto_close_select_backup.selc;
3713 }
3714 }
3715 }
3716
3717 /* Run the script while editing, evil but useful. */
3718 if (ret == OPERATOR_FINISHED && st->live_edit) {
3719 text_run_script(C, nullptr);
3720 }
3721
3722 return ret;
3723}
3724
3726{
3727 PropertyRNA *prop;
3728
3729 /* Identifiers. */
3730 ot->name = "Insert";
3731 ot->idname = "TEXT_OT_insert";
3732 ot->description = "Insert text at cursor position";
3733
3734 /* API callbacks. */
3735 ot->exec = text_insert_exec;
3736 ot->invoke = text_insert_invoke;
3737 ot->poll = text_edit_poll;
3738
3739 /* Flags. */
3740 ot->flag = OPTYPE_UNDO;
3741
3742 /* Properties. */
3743 prop = RNA_def_string(
3744 ot->srna, "text", nullptr, 0, "Text", "Text to insert at the cursor position");
3746}
3747
3749
3750/* -------------------------------------------------------------------- */
3753
3754/* Mode. */
3755enum {
3758};
3759
3761{
3762 Main *bmain = CTX_data_main(C);
3764 Text *text = st->text;
3765 int flags;
3766 bool found = false;
3767 char *tmp;
3768
3769 if (!st->findstr[0]) {
3770 return OPERATOR_CANCELLED;
3771 }
3772
3773 flags = st->flags;
3774 if (flags & ST_FIND_ALL) {
3775 flags &= ~ST_FIND_WRAP;
3776 }
3777
3778 /* Replace current. */
3779 if (mode != TEXT_FIND && txt_has_sel(text)) {
3780 tmp = txt_sel_to_buf(text, nullptr);
3781
3782 if (flags & ST_MATCH_CASE) {
3783 found = STREQ(st->findstr, tmp);
3784 }
3785 else {
3786 found = BLI_strcasecmp(st->findstr, tmp) == 0;
3787 }
3788
3789 if (found) {
3790 if (mode == TEXT_REPLACE) {
3792 txt_insert_buf(text, st->replacestr, strlen(st->replacestr));
3793 if (text->curl && text->curl->format) {
3794 MEM_freeN(text->curl->format);
3795 text->curl->format = nullptr;
3796 }
3800 }
3801 }
3802 MEM_freeN(tmp);
3803 tmp = nullptr;
3804 }
3805
3806 /* Find next. */
3807 if (txt_find_string(text, st->findstr, flags & ST_FIND_WRAP, flags & ST_MATCH_CASE)) {
3810 }
3811 else if (flags & ST_FIND_ALL) {
3812 if (text->id.next) {
3813 text = st->text = static_cast<Text *>(text->id.next);
3814 }
3815 else {
3816 text = st->text = static_cast<Text *>(bmain->texts.first);
3817 }
3818 txt_move_toline(text, 0, false);
3821 }
3822 else {
3823 if (!found) {
3824 BKE_reportf(op->reports, RPT_INFO, "Text not found: %s", st->findstr);
3825 }
3826 }
3827
3828 return OPERATOR_FINISHED;
3829}
3830
3835
3837{
3838 /* Identifiers. */
3839 ot->name = "Find Next";
3840 ot->idname = "TEXT_OT_find";
3841 ot->description = "Find specified text";
3842
3843 /* API callbacks. */
3844 ot->exec = text_find_exec;
3845 ot->poll = text_space_edit_poll;
3846}
3847
3849
3850/* -------------------------------------------------------------------- */
3853
3855{
3857 Text *text = st->text;
3858 const int flags = st->flags;
3859 bool found = false;
3860
3861 if (!st->findstr[0]) {
3862 return OPERATOR_CANCELLED;
3863 }
3864
3865 const int orig_curl = BLI_findindex(&text->lines, text->curl);
3866 const int orig_curc = text->curc;
3867 bool has_sel = txt_has_sel(text);
3868
3869 txt_move_toline(text, 0, false);
3870
3871 found = txt_find_string(text, st->findstr, 0, flags & ST_MATCH_CASE);
3872 if (found) {
3874
3875 do {
3876 txt_insert_buf(text, st->replacestr, strlen(st->replacestr));
3877 if (text->curl && text->curl->format) {
3878 MEM_freeN(text->curl->format);
3879 text->curl->format = nullptr;
3880 }
3881 found = txt_find_string(text, st->findstr, 0, flags & ST_MATCH_CASE);
3882 } while (found);
3883
3886 }
3887 else {
3888 /* Restore position. */
3889 txt_move_to(text, orig_curl, orig_curc, has_sel);
3890 return OPERATOR_CANCELLED;
3891 }
3892
3893 return OPERATOR_FINISHED;
3894}
3895
3897{
3898 bool replace_all = RNA_boolean_get(op->ptr, "all");
3899 if (replace_all) {
3900 return text_replace_all(C);
3901 }
3903}
3904
3906{
3907 /* Identifiers. */
3908 ot->name = "Replace";
3909 ot->idname = "TEXT_OT_replace";
3910 ot->description = "Replace text with the specified text";
3911
3912 /* API callbacks. */
3913 ot->exec = text_replace_exec;
3914 ot->poll = text_space_edit_poll;
3915
3916 /* Flags. */
3917 ot->flag = OPTYPE_UNDO;
3918
3919 /* Properties. */
3920 PropertyRNA *prop;
3921 prop = RNA_def_boolean(ot->srna, "all", false, "Replace All", "Replace all occurrences");
3923}
3924
3926
3927/* -------------------------------------------------------------------- */
3930
3932{
3934 Text *text = CTX_data_edit_text(C);
3935 char *tmp;
3936
3937 tmp = txt_sel_to_buf(text, nullptr);
3938 STRNCPY_UTF8(st->findstr, tmp);
3939 MEM_freeN(tmp);
3940
3941 if (!st->findstr[0]) {
3942 return OPERATOR_FINISHED;
3943 }
3944
3945 return text_find_and_replace(C, op, TEXT_FIND);
3946}
3947
3949{
3950 /* Identifiers. */
3951 ot->name = "Find & Set Selection";
3952 ot->idname = "TEXT_OT_find_set_selected";
3953 ot->description = "Find specified text and set as selected";
3954
3955 /* API callbacks. */
3957 ot->poll = text_space_edit_poll;
3958}
3959
3961
3962/* -------------------------------------------------------------------- */
3965
3967{
3969 Text *text = CTX_data_edit_text(C);
3970 char *tmp;
3971
3972 tmp = txt_sel_to_buf(text, nullptr);
3973 STRNCPY_UTF8(st->replacestr, tmp);
3974 MEM_freeN(tmp);
3975
3976 return OPERATOR_FINISHED;
3977}
3978
3980{
3981 /* Identifiers. */
3982 ot->name = "Replace & Set Selection";
3983 ot->idname = "TEXT_OT_replace_set_selected";
3984 ot->description = "Replace text with specified text and set as selected";
3985
3986 /* API callbacks. */
3988 ot->poll = text_space_edit_poll;
3989
3990 /* Flags. */
3991 ot->flag = OPTYPE_UNDO;
3992}
3993
3995
3996/* -------------------------------------------------------------------- */
3999
4001 ReportList *reports,
4002 const char *filepath,
4003 const int line_index,
4004 const int column_index)
4005{
4006 bool success = false;
4007#ifdef WITH_PYTHON
4008 BPy_RunErrInfo err_info = {};
4009 err_info.reports = reports;
4010 err_info.report_prefix = "External editor";
4011
4012 const char *expr_imports[] = {"_bl_text_utils", "_bl_text_utils.external_editor", "os", nullptr};
4013 std::string expr;
4014 {
4015 std::stringstream expr_stream;
4016 expr_stream << "_bl_text_utils.external_editor.open_external_editor(os.fsdecode(b'";
4017 for (const char *ch = filepath; *ch; ch++) {
4018 expr_stream << "\\x" << std::hex << int(*ch);
4019 }
4020 expr_stream << "'), " << std::dec << line_index << ", " << std::dec << column_index << ")";
4021 expr = expr_stream.str();
4022 }
4023
4024 char *expr_result = nullptr;
4025 if (BPY_run_string_as_string(C, expr_imports, expr.c_str(), &err_info, &expr_result)) {
4026 /* No error. */
4027 if (expr_result[0] == '\0') {
4029 reports, RPT_INFO, "See '%s' in the external editor", BLI_path_basename(filepath));
4030 success = true;
4031 }
4032 else {
4033 BKE_report(reports, RPT_ERROR, expr_result);
4034 }
4035 MEM_freeN(expr_result);
4036 }
4037#else
4038 UNUSED_VARS(C, reports, filepath, line_index, column_index);
4039#endif /* WITH_PYTHON */
4040 return success;
4041}
4042
4044 ReportList *reports,
4045 const char *filepath,
4046 const int line_index,
4047 const int column_index)
4048{
4049 Main *bmain = CTX_data_main(C);
4050 Text *text = nullptr;
4051 BLI_assert(!BLI_path_is_rel(filepath));
4052
4053 LISTBASE_FOREACH (Text *, text_iter, &bmain->texts) {
4054 if (text_iter->filepath == nullptr) {
4055 continue;
4056 }
4057 const char *filepath_iter;
4058 char filepath_iter_buf[FILE_MAX];
4059 if (BLI_path_is_rel(text_iter->filepath)) {
4060 STRNCPY(filepath_iter_buf, text_iter->filepath);
4061 BLI_path_abs(filepath_iter_buf, ID_BLEND_PATH(bmain, &text_iter->id));
4062 filepath_iter = filepath_iter_buf;
4063 }
4064 else {
4065 filepath_iter = text_iter->filepath;
4066 }
4067
4068 if (BLI_path_cmp(filepath, filepath_iter) == 0) {
4069 text = text_iter;
4070 break;
4071 }
4072 }
4073
4074 if (text == nullptr) {
4075 text = BKE_text_load(bmain, filepath, BKE_main_blendfile_path(bmain));
4076 }
4077
4078 if (text == nullptr) {
4079 BKE_reportf(reports, RPT_WARNING, "File '%s' cannot be opened", filepath);
4080 return false;
4081 }
4082
4083 txt_move_to(text, line_index, column_index, false);
4084
4085 /* NOTE(@ideasman42): it's bad practice that this operator searches for the text area to set.
4086 * not a good precedent, since this is a developer tool allow it. */
4087 if (!ED_text_activate_in_screen(C, text)) {
4088 BKE_reportf(reports, RPT_INFO, "See '%s' in the text editor", text->id.name + 2);
4089 }
4090
4092
4093 return true;
4094}
4095
4097{
4098 Main *bmain = CTX_data_main(C);
4099 PropertyRNA *prop_filepath = RNA_struct_find_property(op->ptr, "filepath");
4100 PropertyRNA *prop_line = RNA_struct_find_property(op->ptr, "line");
4101 PropertyRNA *prop_column = RNA_struct_find_property(op->ptr, "column");
4102
4103 if (!RNA_property_is_set(op->ptr, prop_filepath)) {
4104 if (const Text *text = CTX_data_edit_text(C)) {
4105 if (text->filepath != nullptr) {
4106 const TextLine *line = text->curl;
4107 const int line_index = BLI_findindex(&text->lines, text->curl);
4108 const int column_index = BLI_str_utf8_offset_to_index(line->line, line->len, text->curc);
4109
4110 char filepath[FILE_MAX];
4111 STRNCPY(filepath, text->filepath);
4112 BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &text->id));
4113 RNA_property_string_set(op->ptr, prop_filepath, filepath);
4114 RNA_property_int_set(op->ptr, prop_line, line_index);
4115 RNA_property_int_set(op->ptr, prop_column, column_index);
4116 }
4117 }
4118 }
4119
4120 char filepath[FILE_MAX];
4121 RNA_property_string_get(op->ptr, prop_filepath, filepath);
4122 if (UNLIKELY(BLI_path_is_rel(filepath))) {
4123 BLI_path_abs(filepath, BKE_main_blendfile_path(bmain));
4124 }
4125 const int line_index = RNA_property_int_get(op->ptr, prop_line);
4126 const int column_index = RNA_property_int_get(op->ptr, prop_column);
4127
4128 if (filepath[0] == '\0') {
4129 BKE_report(op->reports, RPT_WARNING, "File path property not set");
4130 return OPERATOR_CANCELLED;
4131 }
4132
4133 /* Useful to copy-paste from the terminal. */
4134 printf("%s:%d:%d\n", filepath, line_index + 1, column_index);
4135
4136 bool success;
4137 if (U.text_editor[0] != '\0') {
4139 C, op->reports, filepath, line_index, column_index);
4140 }
4141 else {
4143 C, op->reports, filepath, line_index, column_index);
4144 }
4145
4146 return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
4147}
4148
4150{
4151 PropertyRNA *prop;
4152
4153 /* Identifiers. */
4154 ot->name = "Jump to File at Point";
4155 ot->idname = "TEXT_OT_jump_to_file_at_point";
4156 ot->description = "Jump to a file for the text editor";
4157
4158 /* API callbacks. */
4160
4161 /* Flags. */
4162 ot->flag = 0;
4163
4164 prop = RNA_def_string(ot->srna, "filepath", nullptr, FILE_MAX, "Filepath", "");
4167 prop = RNA_def_int(ot->srna, "line", 0, 0, INT_MAX, "Line", "Line to jump to", 1, 10000);
4170 prop = RNA_def_int(ot->srna, "column", 0, 0, INT_MAX, "Column", "Column to jump to", 1, 10000);
4172}
4173
4175
4176/* -------------------------------------------------------------------- */
4179
4182 {RESOLVE_IGNORE, "IGNORE", 0, "Ignore", ""},
4183 {RESOLVE_RELOAD, "RELOAD", 0, "Reload", ""},
4184 {RESOLVE_SAVE, "SAVE", 0, "Save", ""},
4185 {RESOLVE_MAKE_INTERNAL, "MAKE_INTERNAL", 0, "Make Internal", ""},
4186 {0, nullptr, 0, nullptr, nullptr},
4187};
4188
4190{
4191 Text *text = CTX_data_edit_text(C);
4192
4193 if (!text_edit_poll(C)) {
4194 return false;
4195 }
4196
4197 return ((text->filepath != nullptr) && !(text->flags & TXT_ISMEM));
4198}
4199
4201{
4202 Text *text = CTX_data_edit_text(C);
4203 int resolution = RNA_enum_get(op->ptr, "resolution");
4204
4205 switch (resolution) {
4206 case RESOLVE_RELOAD:
4207 return text_reload_exec(C, op);
4208 case RESOLVE_SAVE:
4209 return text_save_exec(C, op);
4211 return text_make_internal_exec(C, op);
4212 case RESOLVE_IGNORE:
4214 return OPERATOR_FINISHED;
4215 }
4216
4217 return OPERATOR_CANCELLED;
4218}
4219
4221 wmOperator *op,
4222 const wmEvent * /*event*/)
4223{
4224 Text *text = CTX_data_edit_text(C);
4225 uiPopupMenu *pup;
4226 uiLayout *layout;
4227
4228 switch (BKE_text_file_modified_check(text)) {
4229 case 1:
4230 if (text->flags & TXT_ISDIRTY) {
4231 /* Modified locally and externally, ah. offer more possibilities. */
4232 pup = UI_popup_menu_begin(
4233 C, IFACE_("File Modified Outside and Inside Blender"), ICON_NONE);
4234 layout = UI_popup_menu_layout(pup);
4235 PointerRNA op_ptr = layout->op(
4236 op->type, IFACE_("Reload from disk (ignore local changes)"), ICON_NONE);
4237 RNA_enum_set(&op_ptr, "resolution", RESOLVE_RELOAD);
4238 op_ptr = layout->op(op->type, IFACE_("Save to disk (ignore outside changes)"), ICON_NONE);
4239 RNA_enum_set(&op_ptr, "resolution", RESOLVE_SAVE);
4240 op_ptr = layout->op(op->type, IFACE_("Make text internal (separate copy)"), ICON_NONE);
4241 RNA_enum_set(&op_ptr, "resolution", RESOLVE_MAKE_INTERNAL);
4242 UI_popup_menu_end(C, pup);
4243 }
4244 else {
4245 pup = UI_popup_menu_begin(C, IFACE_("File Modified Outside Blender"), ICON_NONE);
4246 layout = UI_popup_menu_layout(pup);
4247 PointerRNA op_ptr = layout->op(op->type, IFACE_("Reload from disk"), ICON_NONE);
4248 RNA_enum_set(&op_ptr, "resolution", RESOLVE_RELOAD);
4249 op_ptr = layout->op(op->type, IFACE_("Make text internal (separate copy)"), ICON_NONE);
4250 RNA_enum_set(&op_ptr, "resolution", RESOLVE_MAKE_INTERNAL);
4251 op_ptr = layout->op(op->type, IFACE_("Ignore"), ICON_NONE);
4252 RNA_enum_set(&op_ptr, "resolution", RESOLVE_IGNORE);
4253 UI_popup_menu_end(C, pup);
4254 }
4255 break;
4256 case 2:
4257 pup = UI_popup_menu_begin(C, IFACE_("File Deleted Outside Blender"), ICON_NONE);
4258 layout = UI_popup_menu_layout(pup);
4259 PointerRNA op_ptr = layout->op(op->type, IFACE_("Make text internal"), ICON_NONE);
4260 RNA_enum_set(&op_ptr, "resolution", RESOLVE_MAKE_INTERNAL);
4261 op_ptr = layout->op(op->type, IFACE_("Recreate file"), ICON_NONE);
4262 RNA_enum_set(&op_ptr, "resolution", RESOLVE_SAVE);
4263 UI_popup_menu_end(C, pup);
4264 break;
4265 }
4266
4267 return OPERATOR_INTERFACE;
4268}
4269
4271{
4272 /* Identifiers. */
4273 ot->name = "Resolve Conflict";
4274 ot->idname = "TEXT_OT_resolve_conflict";
4275 ot->description = "When external text is out of sync, resolve the conflict";
4276
4277 /* API callbacks. */
4281
4282 /* Properties. */
4283 RNA_def_enum(ot->srna,
4284 "resolution",
4287 "Resolution",
4288 "How to solve conflict due to differences in internal and external text");
4289}
4290
4292
4293/* -------------------------------------------------------------------- */
4296
4298{
4299 const Text *text = CTX_data_edit_text(C);
4300 const bool split_lines = RNA_boolean_get(op->ptr, "split_lines");
4301
4302 ED_text_to_object(C, text, split_lines);
4303
4304 return OPERATOR_FINISHED;
4305}
4306
4308{
4309 /* Identifiers. */
4310 ot->name = "To 3D Object";
4311 ot->idname = "TEXT_OT_to_3d_object";
4312 ot->description = "Create 3D text object from active text data-block";
4313
4314 /* API callbacks. */
4315 ot->exec = text_to_3d_object_exec;
4316 ot->poll = text_data_poll;
4317
4318 /* Flags. */
4319 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4320
4321 /* Properties. */
4323 ot->srna, "split_lines", false, "Split Lines", "Create one object per line in the text");
4324}
4325
4327
4328/* -------------------------------------------------------------------- */
4331
4333{
4335 const Text *text = CTX_data_edit_text(C);
4336
4337 /* See if we have a text datablock in context. */
4338 if (text == nullptr) {
4339 return false;
4340 }
4341
4342 /* Test if we have a render engine that supports shaders scripts. */
4343 if (!(type && (type->update_script_node || type->update_custom_camera))) {
4344 return false;
4345 }
4346
4347 /* We don't check if text datablock is actually in use, too slow for poll. */
4348 return true;
4349}
4350
4353 RenderEngineType *type,
4354 bNodeTree *ntree,
4355 Text *text,
4356 VectorSet<bNodeTree *> &done_trees)
4357{
4358 bool found = false;
4359
4360 done_trees.add_new(ntree);
4361
4362 /* Update each script that is using this text datablock. */
4363 for (bNode *node : ntree->all_nodes()) {
4364 if (node->type_legacy == NODE_GROUP) {
4365 bNodeTree *ngroup = (bNodeTree *)node->id;
4366 if (ngroup && !done_trees.contains(ngroup)) {
4367 found |= text_update_shader_text_recursive(engine, type, ngroup, text, done_trees);
4368 }
4369 }
4370 else if (node->type_legacy == SH_NODE_SCRIPT && node->id == &text->id) {
4371 type->update_script_node(engine, ntree, node);
4372 found = true;
4373 }
4374 }
4375
4376 return found;
4377}
4378
4380{
4381 Main *bmain = CTX_data_main(C);
4383 Text *text = CTX_data_edit_text(C);
4384 bool found = false;
4385
4386 /* Setup render engine. */
4387 RenderEngine *engine = RE_engine_create(type);
4388 engine->reports = op->reports;
4389
4390 /* Update all nodes using text datablock. */
4391 if (type->update_script_node != nullptr) {
4392 VectorSet<bNodeTree *> done_trees;
4393 FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
4394 if (ntree->type == NTREE_SHADER) {
4395 if (!done_trees.contains(ntree)) {
4396 found |= text_update_shader_text_recursive(engine, type, ntree, text, done_trees);
4397 }
4398 }
4399 }
4401 }
4402
4403 /* Update all cameras using text data-block. */
4404 if (type->update_custom_camera != nullptr) {
4405 LISTBASE_FOREACH (Camera *, cam, &bmain->cameras) {
4406 if (cam->custom_shader == text) {
4407 type->update_custom_camera(engine, cam);
4408 found = true;
4409 }
4410 }
4411 }
4412
4413 if (!found) {
4414 BKE_report(op->reports, RPT_INFO, "Text not used by any node or camera, no update done");
4415 }
4416
4417 RE_engine_free(engine);
4418
4419 return (found) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
4420}
4421
4423{
4424 /* Identifiers. */
4425 ot->name = "Shader Update";
4426 ot->description =
4427 "Update users of this shader, such as custom cameras and script nodes, with its new sockets "
4428 "and options";
4429 ot->idname = "TEXT_OT_update_shader";
4430
4431 /* API callbacks. */
4434
4435 /* Flags. */
4436 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4437}
4438
SpaceText * CTX_wm_space_text(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Text * CTX_data_edit_text(const bContext *C)
RenderEngineType * CTX_data_engine_type(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void BKE_id_delete(Main *bmain, void *idv) ATTR_NONNULL()
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2523
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
#define FOREACH_NODETREE_END
Definition BKE_node.hh:881
#define NODE_GROUP
Definition BKE_node.hh:811
#define FOREACH_NODETREE_BEGIN(bmain, _nodetree, _id)
Definition BKE_node.hh:871
#define SH_NODE_SCRIPT
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
void txt_move_down(struct Text *text, bool sel)
Definition text.cc:797
void void txt_split_curline(struct Text *text)
Definition text.cc:1653
int txt_setcurr_tab_spaces(struct Text *text, int space)
Definition text.cc:2210
bool txt_has_sel(const struct Text *text)
void txt_move_eof(struct Text *text, bool sel)
Definition text.cc:1072
void txt_delete_selected(struct Text *text)
Definition text.cc:1928
void txt_delete_char(struct Text *text)
Definition text.cc:1766
bool txt_cursor_is_line_end(const struct Text *text)
void txt_sel_line(struct Text *text)
Definition text.cc:1272
void txt_move_toline(struct Text *text, unsigned int line, bool sel)
Definition text.cc:1095
bool txt_replace_char(struct Text *text, unsigned int add)
Definition text.cc:1934
int txt_calc_tab_right(const struct TextLine *tl, int ch)
void txt_backspace_char(struct Text *text)
Definition text.cc:1811
void txt_sel_clear(struct Text *text)
Definition text.cc:1264
void txt_move_left(struct Text *text, bool sel)
Definition text.cc:870
bool txt_add_char(struct Text *text, unsigned int add)
Definition text.cc:1918
int txt_calc_tab_left(const struct TextLine *tl, int ch)
void txt_delete_word(struct Text *text)
Definition text.cc:1804
void txt_move_bof(struct Text *text, bool sel)
Definition text.cc:1049
void txt_move_right(struct Text *text, bool sel)
Definition text.cc:913
@ TXT_MOVE_LINE_UP
Definition BKE_text.h:142
@ TXT_MOVE_LINE_DOWN
Definition BKE_text.h:143
int txt_get_span(const struct TextLine *from, const struct TextLine *to)
void txt_move_lines(struct Text *text, int direction)
Definition text.cc:2179
struct Text * BKE_text_add(struct Main *bmain, const char *name)
Definition text.cc:281
void txt_comment(struct Text *text, const char *prefix)
Definition text.cc:2138
struct Text struct Text * BKE_text_load(struct Main *bmain, const char *filepath, const char *relbase) ATTR_NONNULL(1
void txt_jump_left(struct Text *text, bool sel, bool use_init_step)
Definition text.cc:957
void int BKE_text_file_modified_check(const struct Text *text)
void txt_move_eol(struct Text *text, bool sel)
Definition text.cc:1027
void txt_backspace_word(struct Text *text)
Definition text.cc:1853
void txt_jump_right(struct Text *text, bool sel, bool use_init_step)
Definition text.cc:981
void txt_move_up(struct Text *text, bool sel)
Definition text.cc:765
bool txt_find_string(struct Text *text, const char *findstr, int wrap, int match_case)
Definition text.cc:1595
void BKE_text_file_modified_ignore(struct Text *text)
Definition text.cc:559
void txt_move_bol(struct Text *text, bool sel)
Definition text.cc:1005
struct Text * BKE_text_load_ex(struct Main *bmain, const char *filepath, const char *relbase, bool is_internal) ATTR_NONNULL(1
void txt_sel_all(struct Text *text)
Definition text.cc:1255
void txt_order_cursors(struct Text *text, bool reverse)
Definition text.cc:1183
bool txt_unindent(struct Text *text)
Definition text.cc:2168
void txt_indent(struct Text *text)
Definition text.cc:2157
void txt_duplicate_line(struct Text *text)
Definition text.cc:1749
char * txt_sel_to_buf(const struct Text *text, size_t *r_buf_strlen)
void txt_insert_buf(struct Text *text, const char *in_buffer, int in_buffer_len) ATTR_NONNULL(1
void txt_move_to(struct Text *text, unsigned int line, unsigned int ch, bool sel)
Definition text.cc:1100
bool txt_cursor_is_line_start(const struct Text *text)
void txt_pop_sel(struct Text *text)
Definition text.cc:1177
bool BKE_text_reload(struct Text *text)
Definition text.cc:415
bool txt_uncomment(struct Text *text, const char *prefix)
Definition text.cc:2148
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_INLINE
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:360
bool BLI_file_is_writable(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition fileops_c.cc:291
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
struct stat BLI_stat_t
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
#define LISTBASE_FOREACH(type, var, list)
MINLINE int max_ii(int a, int b)
MINLINE void sub_v2_v2v2_int(int r[2], const int a[2], const int b[2])
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAX
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define BLI_path_cmp
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition BLI_rect.h:181
BLI_INLINE int BLI_rcti_cent_x(const struct rcti *rct)
Definition BLI_rect.h:177
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:30
int char char int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
void BLI_str_cursor_step_bounds_utf8(const char *str, int str_maxlen, int pos, int *r_start, int *r_end)
#define BLI_UTF8_MAX
int BLI_str_utf8_char_width_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_str_utf8_offset_to_index(const char *str, size_t str_len, int offset_target) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
const char * BLI_str_find_prev_char_utf8(const char *p, const char *str_start) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1
unsigned int BLI_str_utf8_as_unicode_step_safe(const char *__restrict p, size_t p_len, size_t *__restrict index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
unsigned int unsigned int size_t BLI_str_utf8_from_unicode_len(unsigned int c) ATTR_WARN_UNUSED_RESULT
#define STRNCPY_UTF8(dst, src)
unsigned int BLI_str_utf8_as_unicode_or_error(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_str_utf8_offset_from_column_with_tabs(const char *str, size_t str_len, int column_target, int tab_width) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_str_utf8_offset_to_column_with_tabs(const char *str, size_t str_len, int offset_target, int tab_width) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:113
#define UNUSED_VARS(...)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define BLT_I18NCONTEXT_ID_TEXT
#define RPT_(msgid)
#define IFACE_(msgid)
#define DATA_(msgid)
void BPY_text_free_code(Text *text)
bool bool BPY_run_text(bContext *C, Text *text, ReportList *reports, bool do_jump) ATTR_NONNULL(1
bool bool bool bool BPY_run_string_as_string(bContext *C, const char *imports[], const char *expr, BPy_RunErrInfo *err_info, char **r_value) ATTR_NONNULL(1
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:685
@ NTREE_SHADER
@ RGN_TYPE_WINDOW
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_TYPE_TEXT
@ FILE_TYPE_PYSCRIPT
@ FILE_TYPE_FOLDER
@ FILE_DEFAULTDISPLAY
@ ST_FIND_WRAP
@ ST_SCROLL_SELECT
@ ST_MATCH_CASE
@ ST_FIND_ALL
#define TXT_TABSIZE
@ TXT_TABSTOSPACES
@ TXT_ISDIRTY
@ TXT_ISMEM
@ USER_TEXT_EDIT_AUTO_CLOSE
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
bool ED_text_activate_in_screen(bContext *C, Text *text)
const char * ED_text_format_comment_line_prefix(Text *text)
UndoStep * ED_text_undo_push_init(bContext *C)
Definition text_undo.cc:249
void ED_space_text_scroll_to_cursor(SpaceText *st, ARegion *region, bool center)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
@ PROP_FILEPATH
Definition RNA_types.hh:236
#define C
Definition RandGen.cpp:29
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void UI_context_active_but_prop_get_templateID(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop)
@ ALERT_ICON_NONE
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1121
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1124
@ WM_CAPABILITY_CLIPBOARD_PRIMARY
Definition WM_api.hh:189
@ FILE_OPENFILE
Definition WM_api.hh:1133
@ FILE_SAVE
Definition WM_api.hh:1134
#define NC_WINDOW
Definition WM_types.hh:375
@ KM_CTRL
Definition WM_types.hh:279
@ KM_OSKEY
Definition WM_types.hh:282
#define ND_CURSOR
Definition WM_types.hh:490
@ KM_RELEASE
Definition WM_types.hh:312
#define NA_ADDED
Definition WM_types.hh:586
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_GRAB_CURSOR_XY
Definition WM_types.hh:188
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NA_EDITED
Definition WM_types.hh:584
#define NC_TEXT
Definition WM_types.hh:386
#define NA_REMOVED
Definition WM_types.hh:587
#define U
#define NEXT_CHAR(fmt)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
bool contains(const Key &key) const
void add_new(const Key &key)
@ DEL_PREV_WORD
@ DEL_PREV_CHAR
@ DEL_NEXT_WORD
@ DEL_NEXT_CHAR
@ NEXT_LINE
@ LINE_BEGIN
@ PREV_WORD
@ PREV_LINE
@ PREV_CHAR
@ LINE_END
@ PREV_PAGE
@ NEXT_PAGE
@ NEXT_WORD
void ED_text_to_object(bContext *C, const Text *text, const bool split_lines)
Definition editfont.cc:892
static const EnumPropertyItem delete_type_items[]
Definition editfont.cc:1706
static const EnumPropertyItem move_type_items[]
Definition editfont.cc:1301
#define str(s)
uint col
uint top
#define printf(...)
#define select(A, B, C)
RenderEngine * RE_engine_create(RenderEngineType *type)
void RE_engine_free(RenderEngine *engine)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong * next
static ulong state[N]
return ret
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_int_get(PointerRNA *ptr, const char *name)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
std::string RNA_string_get(PointerRNA *ptr, const char *name)
int RNA_string_length(PointerRNA *ptr, const char *name)
std::string RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_id_pointer_create(ID *id)
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const char * report_prefix
ReportList * reports
char name[258]
Definition DNA_ID.h:432
void * prev
Definition DNA_ID.h:417
void * next
Definition DNA_ID.h:417
void * last
void * first
ListBase texts
Definition BKE_main.hh:294
ListBase cameras
Definition BKE_main.hh:289
PropertyRNA * prop
Definition RNA_types.hh:146
void(* update_script_node)(struct RenderEngine *engine, struct bNodeTree *ntree, struct bNode *node)
Definition RE_engine.h:107
void(* update_custom_camera)(struct RenderEngine *engine, struct Camera *cam)
Definition RE_engine.h:113
struct ReportList * reports
Definition RE_engine.h:143
wmTimer * timer
Definition text_ops.cc:3054
short mval_prev[2]
Definition text_ops.cc:3053
char replacestr[256]
SpaceText_Runtime * runtime
struct Text * text
char findstr[256]
char * format
char * line
struct TextLine * prev
struct TextLine * next
bool is_first
Definition text_ops.cc:2670
int mval_delta[2]
Definition text_ops.cc:2668
bool is_scrollbar
Definition text_ops.cc:2671
int ofs_init[2]
Definition text_ops.cc:2677
struct TextScroll::@255150002250362276003247202274315002261237166372 state
enum eScrollZone zone
Definition text_ops.cc:2673
int mval_prev[2]
Definition text_ops.cc:2667
int size_px[2]
Definition text_ops.cc:2679
int ofs_max[2]
Definition text_ops.cc:2678
int ofs_delta[2]
Definition text_ops.cc:2681
int ofs_delta_px[2]
Definition text_ops.cc:2682
int flags
ListBase lines
TextLine * curl
double mtime
TextLine * sell
void * compiled
char * filepath
int ymin
int xmin
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
wmEventModifierFlag modifier
Definition WM_types.hh:774
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int xy[2]
Definition WM_types.hh:761
char utf8_buf[6]
Definition WM_types.hh:771
int mval[2]
Definition WM_types.hh:763
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
linep
Definition text_draw.cc:229
void space_text_drawcache_tag_update(SpaceText *st, const bool full)
Definition text_draw.cc:734
void space_text_update_cursor_moved(bContext *C)
void space_text_update_character_width(SpaceText *st)
int space_text_get_visible_lines(const SpaceText *st, const ARegion *region, const char *str)
Definition text_draw.cc:810
void space_text_wrap_offset_in_line(const SpaceText *st, const ARegion *region, TextLine *linein, int cursin, int *offl, int *offc)
Definition text_draw.cc:313
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
int space_text_get_total_lines(SpaceText *st, const ARegion *region)
Definition text_draw.cc:872
int space_text_get_char_pos(const SpaceText *st, const char *line, int cur)
Definition text_draw.cc:385
int flatten_string(const SpaceText *st, FlattenString *fs, const char *in)
void flatten_string_free(FlattenString *fs)
#define TXT_SCROLL_SPACE
int space_text_wrap_width(const SpaceText *st, const ARegion *region)
#define TXT_LINE_HEIGHT(st)
#define TXT_NUMCOL_WIDTH(st)
bool text_space_edit_poll(bContext *C)
Definition text_ops.cc:279
#define TXT_BODY_LEFT(st)
@ FILE_TOP
@ FILE_BOTTOM
#define TXT_BODY_LPAD
static wmOperatorStatus text_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:829
void TEXT_OT_replace_set_selected(wmOperatorType *ot)
Definition text_ops.cc:3979
static wmOperatorStatus text_convert_whitespace_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:1422
static bool text_edit_poll(bContext *C)
Definition text_ops.cc:263
static bool text_update_shader_text_recursive(RenderEngine *engine, RenderEngineType *type, bNodeTree *ntree, Text *text, VectorSet< bNodeTree * > &done_trees)
Definition text_ops.cc:4352
static bool text_span_is_blank(TextLine *line1, const int line1_char, TextLine *line2, const int line2_char)
Definition text_ops.cc:123
static bool text_data_poll(bContext *C)
Definition text_ops.cc:254
void TEXT_OT_unlink(wmOperatorType *ot)
Definition text_ops.cc:643
static wmOperatorStatus text_comment_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:1346
void TEXT_OT_overwrite_toggle(wmOperatorType *ot)
Definition text_ops.cc:2618
static void text_cursor_set_to_pos(SpaceText *st, const ARegion *region, int x, int y, const bool sel)
Definition text_ops.cc:3238
static void space_text_screen_clamp(SpaceText *st, const ARegion *region)
Definition text_ops.cc:2636
void TEXT_OT_reload(wmOperatorType *ot)
Definition text_ops.cc:581
static wmOperatorStatus text_selection_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:3370
void TEXT_OT_open(wmOperatorType *ot)
Definition text_ops.cc:491
void text_update_edited(Text *text)
Definition text_ops.cc:334
static int cursor_skip_find_line(const SpaceText *st, const ARegion *region, int lines, TextLine **linep, int *charp, int *rell, int *relc)
Definition text_ops.cc:1845
void TEXT_OT_update_shader(wmOperatorType *ot)
Definition text_ops.cc:4422
static wmOperatorStatus text_run_script_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:931
static void text_open_init(bContext *C, wmOperator *op)
Definition text_ops.cc:400
static wmOperatorStatus text_open_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:459
static wmOperatorStatus text_reload_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:525
void TEXT_OT_replace(wmOperatorType *ot)
Definition text_ops.cc:3905
static const EnumPropertyItem resolution_items[]
Definition text_ops.cc:4181
eScrollZone
Definition text_ops.cc:2659
@ SCROLLHANDLE_INVALID_OUTSIDE
Definition text_ops.cc:2660
void TEXT_OT_run_script(wmOperatorType *ot)
Definition text_ops.cc:944
static wmOperatorStatus text_jump_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:2449
static wmOperatorStatus text_line_number_invoke(bContext *C, wmOperator *, const wmEvent *event)
Definition text_ops.cc:3494
@ RESOLVE_SAVE
Definition text_ops.cc:4180
@ RESOLVE_MAKE_INTERNAL
Definition text_ops.cc:4180
@ RESOLVE_RELOAD
Definition text_ops.cc:4180
@ RESOLVE_IGNORE
Definition text_ops.cc:4180
static TextLine * space_text_get_line_pos_wrapped(const SpaceText *st, const ARegion *region, int *y)
Definition text_ops.cc:3088
static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:2723
static void text_scroll_state_init(TextScroll *tsc, SpaceText *st, ARegion *region)
Definition text_ops.cc:2685
static wmOperatorStatus text_replace_set_selected_exec(bContext *C, wmOperator *)
Definition text_ops.cc:3966
void TEXT_OT_copy(wmOperatorType *ot)
Definition text_ops.cc:1103
static wmOperatorStatus move_lines_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:1682
static wmOperatorStatus text_move_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:2364
static wmOperatorStatus text_unindent_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1248
static wmOperatorStatus text_select_line_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1617
static wmOperatorStatus text_resolve_conflict_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:4200
void TEXT_OT_select_line(wmOperatorType *ot)
Definition text_ops.cc:1631
static void text_selection_set_cancel(bContext *C, wmOperator *op)
Definition text_ops.cc:3417
static wmOperatorStatus text_find_and_replace(bContext *C, wmOperator *op, short mode)
Definition text_ops.cc:3760
static wmOperatorStatus text_delete_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:2486
static wmOperatorStatus text_save_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:771
void TEXT_OT_new(wmOperatorType *ot)
Definition text_ops.cc:379
void TEXT_OT_indent_or_autocomplete(wmOperatorType *ot)
Definition text_ops.cc:1181
void TEXT_OT_scroll(wmOperatorType *ot)
Definition text_ops.cc:2911
void TEXT_OT_line_break(wmOperatorType *ot)
Definition text_ops.cc:1325
static wmOperatorStatus text_line_break_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1289
static wmOperatorStatus text_select_all_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1585
static bool text_region_edit_poll(bContext *C)
Definition text_ops.cc:296
void TEXT_OT_save_as(wmOperatorType *ot)
Definition text_ops.cc:864
static wmOperatorStatus text_save_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:758
static bool text_region_scroll_poll(bContext *C)
Definition text_ops.cc:2942
static void txt_copy_clipboard(const Text *text)
Definition text_ops.cc:1078
static void text_cursor_set_exit(bContext *C, wmOperator *op)
Definition text_ops.cc:3356
void TEXT_OT_paste(wmOperatorType *ot)
Definition text_ops.cc:1009
void TEXT_OT_make_internal(wmOperatorType *ot)
Definition text_ops.cc:679
void TEXT_OT_to_3d_object(wmOperatorType *ot)
Definition text_ops.cc:4307
void TEXT_OT_indent(wmOperatorType *ot)
Definition text_ops.cc:1227
bool text_space_edit_poll(bContext *C)
Definition text_ops.cc:279
void TEXT_OT_select_all(wmOperatorType *ot)
Definition text_ops.cc:1599
static void txt_wrap_move_eol(SpaceText *st, ARegion *region, const bool sel)
Definition text_ops.cc:2026
static bool text_jump_to_file_at_point_external(bContext *C, ReportList *reports, const char *filepath, const int line_index, const int column_index)
Definition text_ops.cc:4000
static wmOperatorStatus text_cut_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1121
void TEXT_OT_select_word(wmOperatorType *ot)
Definition text_ops.cc:1664
static wmOperatorStatus text_copy_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1094
void TEXT_OT_save(wmOperatorType *ot)
Definition text_ops.cc:784
BLI_INLINE int space_text_pixel_x_to_column(const SpaceText *st, const int x)
Definition text_ops.cc:221
static wmOperatorStatus text_scroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:2871
static wmOperatorStatus text_reload_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:570
static wmOperatorStatus text_open_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:413
void TEXT_OT_move_lines(wmOperatorType *ot)
Definition text_ops.cc:1702
@ TO_SPACES
Definition text_ops.cc:1415
@ TO_TABS
Definition text_ops.cc:1415
static wmOperatorStatus text_resolve_conflict_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:4220
static wmOperatorStatus text_jump_to_file_at_point_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:4096
void TEXT_OT_cursor_set(wmOperatorType *ot)
Definition text_ops.cc:3471
static wmOperatorStatus text_paste_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:965
static char * buf_tabs_to_spaces(const char *in_buf, const int tab_size, int *r_out_buf_len)
Definition text_ops.cc:167
static wmOperatorStatus text_jump_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:2425
static void space_text_cursor_set_to_pos_wrapped(const SpaceText *st, const ARegion *region, int x, int y, const bool sel)
Definition text_ops.cc:3112
void TEXT_OT_scroll_bar(wmOperatorType *ot)
Definition text_ops.cc:3021
void TEXT_OT_find(wmOperatorType *ot)
Definition text_ops.cc:3836
static wmOperatorStatus text_toggle_overwrite_exec(bContext *C, wmOperator *)
Definition text_ops.cc:2607
void TEXT_OT_duplicate_line(wmOperatorType *ot)
Definition text_ops.cc:1057
void TEXT_OT_move_select(wmOperatorType *ot)
Definition text_ops.cc:2399
static int flatten_width(SpaceText *st, const char *str)
Definition text_ops.cc:3057
static wmOperatorStatus text_to_3d_object_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:4297
static wmOperatorStatus text_select_word_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1649
static wmOperatorStatus text_indent_or_autocomplete_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1165
static void text_cursor_timer_ensure(bContext *C, SetSelection *ssel)
Definition text_ops.cc:3296
static bool text_update_shader_poll(bContext *C)
Definition text_ops.cc:4332
static bool text_new_poll(bContext *)
Definition text_ops.cc:249
void TEXT_OT_jump(wmOperatorType *ot)
Definition text_ops.cc:2454
static wmOperatorStatus text_save_as_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:803
static void text_cursor_timer_remove(bContext *C, SetSelection *ssel)
Definition text_ops.cc:3306
static wmOperatorStatus text_new_exec(bContext *C, wmOperator *)
Definition text_ops.cc:347
void TEXT_OT_delete(wmOperatorType *ot)
Definition text_ops.cc:2576
static wmOperatorStatus text_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:632
void TEXT_OT_selection_set(wmOperatorType *ot)
Definition text_ops.cc:3422
static bool text_scroll_poll(bContext *C)
Definition text_ops.cc:2698
static int flatten_column_to_offset(SpaceText *st, const char *str, int index)
Definition text_ops.cc:3070
static wmOperatorStatus text_unlink_exec(bContext *C, wmOperator *)
Definition text_ops.cc:606
void TEXT_OT_find_set_selected(wmOperatorType *ot)
Definition text_ops.cc:3948
static wmOperatorStatus text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:3602
static wmOperatorStatus text_find_set_selected_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:3931
static wmOperatorStatus text_indent_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1202
static void txt_wrap_move_bol(SpaceText *st, ARegion *region, const bool sel)
Definition text_ops.cc:1939
static wmOperatorStatus text_scroll_bar_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:2960
static wmOperatorStatus text_scroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:2831
void TEXT_OT_unindent(wmOperatorType *ot)
Definition text_ops.cc:1268
void TEXT_OT_insert(wmOperatorType *ot)
Definition text_ops.cc:3725
static wmOperatorStatus text_cursor_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:3457
static const EnumPropertyItem whitespace_type_items[]
Definition text_ops.cc:1416
static wmOperatorStatus text_selection_set_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:3397
void TEXT_OT_comment_toggle(wmOperatorType *ot)
Definition text_ops.cc:1383
static int space_text_get_cursor_rel(const SpaceText *st, const ARegion *region, TextLine *linein, int rell, int relc)
Definition text_ops.cc:1751
void TEXT_OT_jump_to_file_at_point(wmOperatorType *ot)
Definition text_ops.cc:4149
static void space_text_cursor_skip(const SpaceText *st, const ARegion *region, Text *text, int lines, const bool sel)
Definition text_ops.cc:2198
static char text_closing_character_pair_get(const char character)
Definition text_ops.cc:96
static wmOperatorStatus text_replace_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:3896
static wmOperatorStatus text_update_shader_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:4379
static bool text_unlink_poll(bContext *C)
Definition text_ops.cc:600
@ TEXT_REPLACE
Definition text_ops.cc:3757
@ TEXT_FIND
Definition text_ops.cc:3756
static wmOperatorStatus text_find_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:3831
void TEXT_OT_resolve_conflict(wmOperatorType *ot)
Definition text_ops.cc:4270
static wmOperatorStatus text_scroll_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:2705
void TEXT_OT_move(wmOperatorType *ot)
Definition text_ops.cc:2371
static void space_text_screen_skip(SpaceText *st, ARegion *region, int lines)
Definition text_ops.cc:2652
static void text_open_cancel(bContext *, wmOperator *op)
Definition text_ops.cc:408
void TEXT_OT_line_number(wmOperatorType *ot)
Definition text_ops.cc:3541
void text_update_line_edited(TextLine *line)
Definition text_ops.cc:324
static void test_line_start(char c, bool *r_last_state)
Definition text_ops.cc:81
static bool text_resolve_conflict_poll(bContext *C)
Definition text_ops.cc:4189
void TEXT_OT_convert_whitespace(wmOperatorType *ot)
Definition text_ops.cc:1556
static void text_select_update_primary_clipboard(const Text *text)
Definition text_ops.cc:227
static wmOperatorStatus text_move_select_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:2392
static wmOperatorStatus text_make_internal_exec(bContext *C, wmOperator *)
Definition text_ops.cc:665
static wmOperatorStatus text_run_script(bContext *C, ReportList *reports)
Definition text_ops.cc:892
static void txt_wrap_move_down(SpaceText *st, ARegion *region, const bool sel)
Definition text_ops.cc:2152
void TEXT_OT_cut(wmOperatorType *ot)
Definition text_ops.cc:1144
static wmOperatorStatus text_cursor_set_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:3442
static wmOperatorStatus text_replace_all(bContext *C)
Definition text_ops.cc:3854
static wmOperatorStatus text_insert_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:3559
static bool text_jump_to_file_at_point_internal(bContext *C, ReportList *reports, const char *filepath, const int line_index, const int column_index)
Definition text_ops.cc:4043
static void txt_wrap_move_up(SpaceText *st, ARegion *region, const bool sel)
Definition text_ops.cc:2111
static void text_cursor_set_apply(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:3317
static void text_scroll_cancel(bContext *C, wmOperator *op)
Definition text_ops.cc:2866
static void scroll_exit(bContext *C, wmOperator *op)
Definition text_ops.cc:2812
static wmOperatorStatus text_duplicate_line_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1039
static wmOperatorStatus text_move_cursor(bContext *C, int type, bool select)
Definition text_ops.cc:2239
static void txt_write_file(Main *bmain, Text *text, ReportList *reports)
Definition text_ops.cc:700
uint len
@ SCROLLHANDLE_BAR
@ SCROLLHANDLE_MIN_OUTSIDE
@ SCROLLHANDLE_MAX_OUTSIDE
char WM_event_utf8_to_ascii(const wmEvent *event)
void WM_event_add_fileselect(bContext *C, wmOperator *op)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorStatus WM_operator_name_call(bContext *C, const char *opstring, blender::wm::OpCallContext context, PointerRNA *properties, const wmEvent *event)
@ MOUSEPAN
@ RIGHTMOUSE
@ TIMER
@ MOUSEMOVE
@ LEFTMOUSE
@ MIDDLEMOUSE
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
wmOperatorStatus WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, std::optional< std::string > title, std::optional< std::string > confirm_text, const bool cancel_default, std::optional< std::string > message)
wmOperatorStatus WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
void WM_clipboard_text_set(const char *buf, bool selection)
char * WM_clipboard_text_get(bool selection, bool ensure_utf8, int *r_len)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const wmEventType event_type, const double time_step)
eWM_CapabilitiesFlag WM_capabilities_flag()
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)