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