Blender  V3.3
text_ops.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include <errno.h>
9 #include <string.h>
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "DNA_text_types.h"
14 
15 #include "BLI_blenlib.h"
16 #include "BLI_math.h"
17 #include "BLI_math_base.h"
18 
19 #include "BLT_translation.h"
20 
21 #include "PIL_time.h"
22 
23 #include "BKE_context.h"
24 #include "BKE_lib_id.h"
25 #include "BKE_main.h"
26 #include "BKE_report.h"
27 #include "BKE_text.h"
28 
29 #include "WM_api.h"
30 #include "WM_types.h"
31 
32 #include "ED_curve.h"
33 #include "ED_screen.h"
34 #include "ED_text.h"
35 #include "UI_interface.h"
36 #include "UI_resources.h"
37 
38 #include "RNA_access.h"
39 #include "RNA_define.h"
40 
41 #ifdef WITH_PYTHON
42 # include "BPY_extern.h"
43 # include "BPY_extern_run.h"
44 #endif
45 
46 #include "text_format.h"
47 #include "text_intern.h"
48 
49 static void txt_screen_clamp(SpaceText *st, ARegion *region);
50 
51 /* -------------------------------------------------------------------- */
62 static void test_line_start(char c, bool *r_last_state)
63 {
64  if (c == '\n') {
65  *r_last_state = true;
66  }
67  else if (!ELEM(c, '\t', ' ')) {
68  *r_last_state = false;
69  }
70 }
71 
77 static char text_closing_character_pair_get(const char character)
78 {
79 
80  switch (character) {
81  case '(':
82  return ')';
83  case '[':
84  return ']';
85  case '{':
86  return '}';
87  case '"':
88  return '"';
89  case '\'':
90  return '\'';
91  default:
92  return 0;
93  }
94 }
95 
102 static char *buf_tabs_to_spaces(const char *in_buf, const int tab_size, int *r_out_buf_len)
103 {
104  /* Get the number of tab characters in buffer. */
105  bool line_start = true;
106  int num_tabs = 0;
107 
108  for (int in_offset = 0; in_buf[in_offset]; in_offset++) {
109  /* Verify if is an indentation whitespace character. */
110  test_line_start(in_buf[in_offset], &line_start);
111 
112  if (in_buf[in_offset] == '\t' && line_start) {
113  num_tabs++;
114  }
115  }
116 
117  /* Allocate output before with extra space for expanded tabs. */
118  const int out_size = strlen(in_buf) + num_tabs * (tab_size - 1) + 1;
119  char *out_buf = MEM_mallocN(out_size * sizeof(char), __func__);
120 
121  /* Fill output buffer. */
122  int spaces_until_tab = 0;
123  int out_offset = 0;
124  line_start = true;
125 
126  for (int in_offset = 0; in_buf[in_offset]; in_offset++) {
127  /* Verify if is an indentation whitespace character. */
128  test_line_start(in_buf[in_offset], &line_start);
129 
130  if (in_buf[in_offset] == '\t' && line_start) {
131  /* Calculate tab size so it fills until next indentation. */
132  int num_spaces = tab_size - (spaces_until_tab % tab_size);
133  spaces_until_tab = 0;
134 
135  /* Write to buffer. */
136  memset(&out_buf[out_offset], ' ', num_spaces);
137  out_offset += num_spaces;
138  }
139  else {
140  if (in_buf[in_offset] == ' ') {
141  spaces_until_tab++;
142  }
143  else if (in_buf[in_offset] == '\n') {
144  spaces_until_tab = 0;
145  }
146 
147  out_buf[out_offset++] = in_buf[in_offset];
148  }
149  }
150 
151  out_buf[out_offset] = '\0';
152  *r_out_buf_len = out_offset;
153  return out_buf;
154 }
155 
157 {
158  /* Add half the char width so mouse cursor selection is in between letters. */
159  return (x + (st->runtime.cwidth_px / 2)) / st->runtime.cwidth_px;
160 }
161 
164 /* -------------------------------------------------------------------- */
169 {
170  return true;
171 }
172 
173 static bool text_data_poll(bContext *C)
174 {
175  Text *text = CTX_data_edit_text(C);
176  if (!text) {
177  return false;
178  }
179  return true;
180 }
181 
182 static bool text_edit_poll(bContext *C)
183 {
184  Text *text = CTX_data_edit_text(C);
185 
186  if (!text) {
187  return false;
188  }
189 
190  if (!BKE_id_is_editable(CTX_data_main(C), &text->id)) {
191  // BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data");
192  return false;
193  }
194 
195  return true;
196 }
197 
199 {
201  Text *text = CTX_data_edit_text(C);
202 
203  if (!st || !text) {
204  return false;
205  }
206 
207  if (!BKE_id_is_editable(CTX_data_main(C), &text->id)) {
208  // BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data");
209  return false;
210  }
211 
212  return true;
213 }
214 
216 {
218  Text *text = CTX_data_edit_text(C);
219  ARegion *region = CTX_wm_region(C);
220 
221  if (!st || !text) {
222  return false;
223  }
224 
225  if (!region || region->regiontype != RGN_TYPE_WINDOW) {
226  return false;
227  }
228 
229  if (!BKE_id_is_editable(CTX_data_main(C), &text->id)) {
230  // BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data");
231  return false;
232  }
233 
234  return true;
235 }
236 
239 /* -------------------------------------------------------------------- */
244 {
245  if (!line) {
246  return;
247  }
248 
249  /* we just free format here, and let it rebuild during draw */
250  MEM_SAFE_FREE(line->format);
251 }
252 
254 {
255  TextLine *line;
256 
257  for (line = text->lines.first; line; line = line->next) {
259  }
260 }
261 
264 /* -------------------------------------------------------------------- */
269 {
271  Main *bmain = CTX_data_main(C);
272  Text *text;
273  PointerRNA ptr, idptr;
274  PropertyRNA *prop;
275 
276  text = BKE_text_add(bmain, DATA_("Text"));
277 
278  /* hook into UI */
280 
281  if (prop) {
282  RNA_id_pointer_create(&text->id, &idptr);
283  RNA_property_pointer_set(&ptr, prop, idptr, NULL);
284  RNA_property_update(C, &ptr, prop);
285  }
286  else if (st) {
287  st->text = text;
288  st->left = 0;
289  st->top = 0;
290  st->runtime.scroll_ofs_px[0] = 0;
291  st->runtime.scroll_ofs_px[1] = 0;
293  }
294 
296 
297  return OPERATOR_FINISHED;
298 }
299 
301 {
302  /* identifiers */
303  ot->name = "New Text";
304  ot->idname = "TEXT_OT_new";
305  ot->description = "Create a new text data-block";
306 
307  /* api callbacks */
308  ot->exec = text_new_exec;
309  ot->poll = text_new_poll;
310 
311  /* flags */
312  ot->flag = OPTYPE_UNDO;
313 }
314 
317 /* -------------------------------------------------------------------- */
322 {
323  PropertyPointerRNA *pprop;
324 
325  op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
327 }
328 
330 {
331  MEM_freeN(op->customdata);
332 }
333 
335 {
337  Main *bmain = CTX_data_main(C);
338  Text *text;
339  PropertyPointerRNA *pprop;
340  PointerRNA idptr;
341  char str[FILE_MAX];
342  const bool internal = RNA_boolean_get(op->ptr, "internal");
343 
344  RNA_string_get(op->ptr, "filepath", str);
345 
346  text = BKE_text_load_ex(bmain, str, BKE_main_blendfile_path(bmain), internal);
347 
348  if (!text) {
349  if (op->customdata) {
350  MEM_freeN(op->customdata);
351  }
352  return OPERATOR_CANCELLED;
353  }
354 
355  if (!op->customdata) {
356  text_open_init(C, op);
357  }
358 
359  /* hook into UI */
360  pprop = op->customdata;
361 
362  if (pprop->prop) {
363  RNA_id_pointer_create(&text->id, &idptr);
364  RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL);
365  RNA_property_update(C, &pprop->ptr, pprop->prop);
366  }
367  else if (st) {
368  st->text = text;
369  st->left = 0;
370  st->top = 0;
371  st->runtime.scroll_ofs_px[0] = 0;
372  st->runtime.scroll_ofs_px[1] = 0;
373  }
374 
377 
378  MEM_freeN(op->customdata);
379 
380  return OPERATOR_FINISHED;
381 }
382 
383 static int text_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
384 {
385  Main *bmain = CTX_data_main(C);
386  Text *text = CTX_data_edit_text(C);
387  const char *path = (text && text->filepath) ? text->filepath : BKE_main_blendfile_path(bmain);
388 
389  if (RNA_struct_property_is_set(op->ptr, "filepath")) {
390  return text_open_exec(C, op);
391  }
392 
393  text_open_init(C, op);
394  RNA_string_set(op->ptr, "filepath", path);
396 
397  return OPERATOR_RUNNING_MODAL;
398 }
399 
401 {
402  /* identifiers */
403  ot->name = "Open Text";
404  ot->idname = "TEXT_OT_open";
405  ot->description = "Open a new text data-block";
406 
407  /* api callbacks */
411  ot->poll = text_new_poll;
412 
413  /* flags */
414  ot->flag = OPTYPE_UNDO;
415 
416  /* properties */
419  FILE_SPECIAL,
423  FILE_SORT_DEFAULT); /* TODO: relative_path. */
425  ot->srna, "internal", 0, "Make Internal", "Make text file internal after loading");
426 }
427 
430 /* -------------------------------------------------------------------- */
435 {
437  Text *text = CTX_data_edit_text(C);
438  ARegion *region = CTX_wm_region(C);
439 
440  /* store view & cursor state */
441  const int orig_top = st->top;
442  const int orig_curl = BLI_findindex(&text->lines, text->curl);
443  const int orig_curc = text->curc;
444 
445  /* Don't make this part of 'poll', since 'Alt-R' will type 'R',
446  * if poll checks for the filename. */
447  if (text->filepath == NULL) {
448  BKE_report(op->reports, RPT_ERROR, "This text has not been saved");
449  return OPERATOR_CANCELLED;
450  }
451 
452  if (!BKE_text_reload(text)) {
453  BKE_report(op->reports, RPT_ERROR, "Could not reopen file");
454  return OPERATOR_CANCELLED;
455  }
456 
457 #ifdef WITH_PYTHON
458  if (text->compiled) {
459  BPY_text_free_code(text);
460  }
461 #endif
462 
463  text_update_edited(text);
467 
468  text->flags &= ~TXT_ISDIRTY;
469 
470  /* return to scroll position */
471  st->top = orig_top;
472  txt_screen_clamp(st, region);
473  /* return cursor */
474  txt_move_to(text, orig_curl, orig_curc, false);
475 
476  return OPERATOR_FINISHED;
477 }
478 
480 {
481  /* identifiers */
482  ot->name = "Reload";
483  ot->idname = "TEXT_OT_reload";
484  ot->description = "Reload active text data-block from its file";
485 
486  /* api callbacks */
490 }
491 
494 /* -------------------------------------------------------------------- */
499 {
500  /* it should be possible to unlink texts if they're lib-linked in... */
501  return CTX_data_edit_text(C) != NULL;
502 }
503 
505 {
506  Main *bmain = CTX_data_main(C);
508  Text *text = CTX_data_edit_text(C);
509 
510  /* make the previous text active, if its not there make the next text active */
511  if (st) {
512  if (text->id.prev) {
513  st->text = text->id.prev;
515  }
516  else if (text->id.next) {
517  st->text = text->id.next;
519  }
520  }
521 
522  BKE_id_delete(bmain, text);
523 
526 
527  return OPERATOR_FINISHED;
528 }
529 
531 {
532  /* identifiers */
533  ot->name = "Unlink";
534  ot->idname = "TEXT_OT_unlink";
535  ot->description = "Unlink active text data-block";
536 
537  /* api callbacks */
541 
542  /* flags */
543  ot->flag = OPTYPE_UNDO;
544 }
545 
548 /* -------------------------------------------------------------------- */
553 {
554  Text *text = CTX_data_edit_text(C);
555 
556  text->flags |= TXT_ISMEM | TXT_ISDIRTY;
557 
558  MEM_SAFE_FREE(text->filepath);
559 
562 
563  return OPERATOR_FINISHED;
564 }
565 
567 {
568  /* identifiers */
569  ot->name = "Make Internal";
570  ot->idname = "TEXT_OT_make_internal";
571  ot->description = "Make active text file internal";
572 
573  /* api callbacks */
576 
577  /* flags */
578  ot->flag = OPTYPE_UNDO;
579 }
580 
583 /* -------------------------------------------------------------------- */
587 static void txt_write_file(Main *bmain, Text *text, ReportList *reports)
588 {
589  FILE *fp;
590  TextLine *tmp;
591  BLI_stat_t st;
592  char filepath[FILE_MAX];
593 
594  BLI_strncpy(filepath, text->filepath, FILE_MAX);
595  BLI_path_abs(filepath, BKE_main_blendfile_path(bmain));
596 
597  /* Check if file write permission is ok. */
598  if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) {
599  BKE_reportf(
600  reports, RPT_ERROR, "Cannot save text file, path \"%s\" is not writable", filepath);
601  return;
602  }
603 
604  fp = BLI_fopen(filepath, "w");
605  if (fp == NULL) {
606  BKE_reportf(reports,
607  RPT_ERROR,
608  "Unable to save '%s': %s",
609  filepath,
610  errno ? strerror(errno) : TIP_("unknown error writing file"));
611  return;
612  }
613 
614  for (tmp = text->lines.first; tmp; tmp = tmp->next) {
615  fputs(tmp->line, fp);
616  if (tmp->next) {
617  fputc('\n', fp);
618  }
619  }
620 
621  fclose(fp);
622 
623  if (BLI_stat(filepath, &st) == 0) {
624  text->mtime = st.st_mtime;
625 
626  /* Report since this can be called from key shortcuts. */
627  BKE_reportf(reports, RPT_INFO, "Saved text \"%s\"", filepath);
628  }
629  else {
630  text->mtime = 0;
631  BKE_reportf(reports,
632  RPT_WARNING,
633  "Unable to stat '%s': %s",
634  filepath,
635  errno ? strerror(errno) : TIP_("unknown error stating file"));
636  }
637 
638  text->flags &= ~TXT_ISDIRTY;
639 }
640 
642 {
643  Main *bmain = CTX_data_main(C);
644  Text *text = CTX_data_edit_text(C);
645 
646  txt_write_file(bmain, text, op->reports);
647 
650 
651  return OPERATOR_FINISHED;
652 }
653 
654 static int text_save_invoke(bContext *C, wmOperator *op, const wmEvent *event)
655 {
656  Text *text = CTX_data_edit_text(C);
657 
658  /* Internal and texts without a filepath will go to "Save As". */
659  if (text->filepath == NULL || (text->flags & TXT_ISMEM)) {
660  WM_operator_name_call(C, "TEXT_OT_save_as", WM_OP_INVOKE_DEFAULT, NULL, event);
661  return OPERATOR_CANCELLED;
662  }
663  return text_save_exec(C, op);
664 }
665 
667 {
668  /* identifiers */
669  ot->name = "Save";
670  ot->idname = "TEXT_OT_save";
671  ot->description = "Save active text data-block";
672 
673  /* api callbacks */
677 }
678 
681 /* -------------------------------------------------------------------- */
686 {
687  Main *bmain = CTX_data_main(C);
688  Text *text = CTX_data_edit_text(C);
689  char str[FILE_MAX];
690 
691  if (!text) {
692  return OPERATOR_CANCELLED;
693  }
694 
695  RNA_string_get(op->ptr, "filepath", str);
696 
697  if (text->filepath) {
698  MEM_freeN(text->filepath);
699  }
700  text->filepath = BLI_strdup(str);
701  text->flags &= ~TXT_ISMEM;
702 
703  txt_write_file(bmain, text, op->reports);
704 
707 
708  return OPERATOR_FINISHED;
709 }
710 
711 static int text_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
712 {
713  Main *bmain = CTX_data_main(C);
714  Text *text = CTX_data_edit_text(C);
715  const char *str;
716 
717  if (RNA_struct_property_is_set(op->ptr, "filepath")) {
718  return text_save_as_exec(C, op);
719  }
720 
721  if (text->filepath) {
722  str = text->filepath;
723  }
724  else if (text->flags & TXT_ISMEM) {
725  str = text->id.name + 2;
726  }
727  else {
728  str = BKE_main_blendfile_path(bmain);
729  }
730 
731  RNA_string_set(op->ptr, "filepath", str);
733 
734  return OPERATOR_RUNNING_MODAL;
735 }
736 
738 {
739  /* identifiers */
740  ot->name = "Save As";
741  ot->idname = "TEXT_OT_save_as";
742  ot->description = "Save active text file with options";
743 
744  /* api callbacks */
748 
749  /* properties */
752  FILE_SPECIAL,
753  FILE_SAVE,
756  FILE_SORT_DEFAULT); /* XXX TODO: relative_path. */
757 }
758 
761 /* -------------------------------------------------------------------- */
765 static int text_run_script(bContext *C, ReportList *reports)
766 {
767 #ifdef WITH_PYTHON
768  Text *text = CTX_data_edit_text(C);
769  const bool is_live = (reports == NULL);
770 
771  /* only for comparison */
772  void *curl_prev = text->curl;
773  int curc_prev = text->curc;
774 
775  if (BPY_run_text(C, text, reports, !is_live)) {
776  if (is_live) {
777  /* for nice live updates */
779  }
780  return OPERATOR_FINISHED;
781  }
782 
783  /* Don't report error messages while live editing */
784  if (!is_live) {
785  /* text may have freed itself */
786  if (CTX_data_edit_text(C) == text) {
787  if (text->curl != curl_prev || curc_prev != text->curc) {
790  }
791  }
792 
793  /* No need to report the error, this has already been handled by #BPY_run_text. */
794  return OPERATOR_FINISHED;
795  }
796 #else
797  (void)C;
798  (void)reports;
799 #endif /* !WITH_PYTHON */
800  return OPERATOR_CANCELLED;
801 }
802 
804 {
805 #ifndef WITH_PYTHON
806  (void)C; /* unused */
807 
808  BKE_report(op->reports, RPT_ERROR, "Python disabled in this build");
809 
810  return OPERATOR_CANCELLED;
811 #else
812  return text_run_script(C, op->reports);
813 #endif
814 }
815 
817 {
818  /* identifiers */
819  ot->name = "Run Script";
820  ot->idname = "TEXT_OT_run_script";
821  ot->description = "Run active script";
822 
823  /* api callbacks */
826 
827  /* flags */
829 }
830 
833 /* -------------------------------------------------------------------- */
838 {
839 #ifdef WITH_PYTHON
840 # if 0
841  Main *bmain = CTX_data_main(C);
842  Text *text = CTX_data_edit_text(C);
843  Object *ob;
844  bConstraint *con;
845  short update;
846 
847  /* check all pyconstraints */
848  for (ob = bmain->objects.first; ob; ob = ob->id.next) {
849  update = 0;
850  if (ob->type == OB_ARMATURE && ob->pose) {
851  bPoseChannel *pchan;
852  for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
853  for (con = pchan->constraints.first; con; con = con->next) {
854  if (con->type == CONSTRAINT_TYPE_PYTHON) {
855  bPythonConstraint *data = con->data;
856  if (data->text == text) {
857  BPY_pyconstraint_update(ob, con);
858  }
859  update = 1;
860  }
861  }
862  }
863  }
864  for (con = ob->constraints.first; con; con = con->next) {
865  if (con->type == CONSTRAINT_TYPE_PYTHON) {
866  bPythonConstraint *data = con->data;
867  if (data->text == text) {
868  BPY_pyconstraint_update(ob, con);
869  }
870  update = 1;
871  }
872  }
873 
874  if (update) {
876  }
877  }
878 # endif
879 #endif
880 
881  return OPERATOR_FINISHED;
882 }
883 
885 {
886  /* identifiers */
887  ot->name = "Refresh PyConstraints";
888  ot->idname = "TEXT_OT_refresh_pyconstraints";
889  ot->description = "Refresh all pyconstraints";
890 
891  /* api callbacks */
894 }
895 
898 /* -------------------------------------------------------------------- */
903 {
904  const bool selection = RNA_boolean_get(op->ptr, "selection");
905  Text *text = CTX_data_edit_text(C);
906  char *buf;
907  int buf_len;
908 
909  buf = WM_clipboard_text_get(selection, &buf_len);
910 
911  if (!buf) {
912  return OPERATOR_CANCELLED;
913  }
914 
916 
918 
919  /* Convert clipboard content indentation to spaces if specified */
920  if (text->flags & TXT_TABSTOSPACES) {
921  char *new_buf = buf_tabs_to_spaces(buf, TXT_TABSIZE, &buf_len);
922  MEM_freeN(buf);
923  buf = new_buf;
924  }
925 
926  txt_insert_buf(text, buf, buf_len);
927  text_update_edited(text);
928 
929  MEM_freeN(buf);
930 
933 
934  /* run the script while editing, evil but useful */
935  if (CTX_wm_space_text(C)->live_edit) {
937  }
938 
939  return OPERATOR_FINISHED;
940 }
941 
943 {
944  /* identifiers */
945  ot->name = "Paste";
946  ot->idname = "TEXT_OT_paste";
947  ot->description = "Paste text from clipboard";
948 
949  /* api callbacks */
952 
953  /* flags */
954  ot->flag = OPTYPE_UNDO;
955 
956  /* properties */
958  "selection",
959  0,
960  "Selection",
961  "Paste text selected elsewhere rather than copied (X11 only)");
962 }
963 
966 /* -------------------------------------------------------------------- */
971 {
972  Text *text = CTX_data_edit_text(C);
973 
975 
976  txt_duplicate_line(text);
977 
979 
980  /* run the script while editing, evil but useful */
981  if (CTX_wm_space_text(C)->live_edit) {
983  }
984 
985  return OPERATOR_FINISHED;
986 }
987 
989 {
990  /* identifiers */
991  ot->name = "Duplicate Line";
992  ot->idname = "TEXT_OT_duplicate_line";
993  ot->description = "Duplicate the current line";
994 
995  /* api callbacks */
998 
999  /* flags */
1000  ot->flag = OPTYPE_UNDO;
1001 }
1002 
1005 /* -------------------------------------------------------------------- */
1009 static void txt_copy_clipboard(Text *text)
1010 {
1011  char *buf;
1012 
1013  if (!txt_has_sel(text)) {
1014  return;
1015  }
1016 
1017  buf = txt_sel_to_buf(text, NULL);
1018 
1019  if (buf) {
1020  WM_clipboard_text_set(buf, 0);
1021  MEM_freeN(buf);
1022  }
1023 }
1024 
1026 {
1027  Text *text = CTX_data_edit_text(C);
1028 
1029  txt_copy_clipboard(text);
1030 
1031  return OPERATOR_FINISHED;
1032 }
1033 
1035 {
1036  /* identifiers */
1037  ot->name = "Copy";
1038  ot->idname = "TEXT_OT_copy";
1039  ot->description = "Copy selected text to clipboard";
1040 
1041  /* api callbacks */
1042  ot->exec = text_copy_exec;
1043  ot->poll = text_edit_poll;
1044 }
1045 
1048 /* -------------------------------------------------------------------- */
1053 {
1054  Text *text = CTX_data_edit_text(C);
1055 
1057 
1058  txt_copy_clipboard(text);
1059 
1061  txt_delete_selected(text);
1062 
1065 
1066  /* run the script while editing, evil but useful */
1067  if (CTX_wm_space_text(C)->live_edit) {
1069  }
1070 
1071  return OPERATOR_FINISHED;
1072 }
1073 
1075 {
1076  /* identifiers */
1077  ot->name = "Cut";
1078  ot->idname = "TEXT_OT_cut";
1079  ot->description = "Cut selected text to clipboard";
1080 
1081  /* api callbacks */
1082  ot->exec = text_cut_exec;
1083  ot->poll = text_edit_poll;
1084 
1085  /* flags */
1086  ot->flag = OPTYPE_UNDO;
1087 }
1088 
1091 /* -------------------------------------------------------------------- */
1096 {
1097  Text *text = CTX_data_edit_text(C);
1098  TextLine *line = text->curl;
1099  bool text_before_cursor = text->curc != 0 && !ELEM(line->line[text->curc - 1], ' ', '\t');
1100  if (text_before_cursor && (txt_has_sel(text) == false)) {
1101  WM_operator_name_call(C, "TEXT_OT_autocomplete", WM_OP_INVOKE_DEFAULT, NULL, NULL);
1102  }
1103  else {
1104  WM_operator_name_call(C, "TEXT_OT_indent", WM_OP_EXEC_DEFAULT, NULL, NULL);
1105  }
1106  return OPERATOR_FINISHED;
1107 }
1108 
1110 {
1111  /* identifiers */
1112  ot->name = "Indent or Autocomplete";
1113  ot->idname = "TEXT_OT_indent_or_autocomplete";
1114  ot->description = "Indent selected text or autocomplete";
1115 
1116  /* api callbacks */
1118  ot->poll = text_edit_poll;
1119 
1120  /* flags */
1121  ot->flag = 0;
1122 }
1123 
1126 /* -------------------------------------------------------------------- */
1131 {
1132  Text *text = CTX_data_edit_text(C);
1133 
1135 
1137 
1138  if (txt_has_sel(text)) {
1139  txt_order_cursors(text, false);
1140  txt_indent(text);
1141  }
1142  else {
1143  txt_add_char(text, '\t');
1144  }
1145 
1146  text_update_edited(text);
1147 
1150 
1151  return OPERATOR_FINISHED;
1152 }
1153 
1155 {
1156  /* identifiers */
1157  ot->name = "Indent";
1158  ot->idname = "TEXT_OT_indent";
1159  ot->description = "Indent selected text";
1160 
1161  /* api callbacks */
1163  ot->poll = text_edit_poll;
1164 
1165  /* flags */
1166  ot->flag = OPTYPE_UNDO;
1167 }
1168 
1171 /* -------------------------------------------------------------------- */
1176 {
1177  Text *text = CTX_data_edit_text(C);
1178 
1180 
1182 
1183  txt_order_cursors(text, false);
1184  txt_unindent(text);
1185 
1186  text_update_edited(text);
1187 
1190 
1191  return OPERATOR_FINISHED;
1192 }
1193 
1195 {
1196  /* identifiers */
1197  ot->name = "Unindent";
1198  ot->idname = "TEXT_OT_unindent";
1199  ot->description = "Unindent selected text";
1200 
1201  /* api callbacks */
1203  ot->poll = text_edit_poll;
1204 
1205  /* flags */
1206  ot->flag = OPTYPE_UNDO;
1207 }
1208 
1211 /* -------------------------------------------------------------------- */
1216 {
1218  Text *text = CTX_data_edit_text(C);
1219  int a, curts;
1220  int space = (text->flags & TXT_TABSTOSPACES) ? st->tabnumber : 1;
1221 
1223 
1224  /* Double check tabs/spaces before splitting the line. */
1225  curts = txt_setcurr_tab_spaces(text, space);
1227  txt_split_curline(text);
1228 
1229  for (a = 0; a < curts; a++) {
1230  if (text->flags & TXT_TABSTOSPACES) {
1231  txt_add_char(text, ' ');
1232  }
1233  else {
1234  txt_add_char(text, '\t');
1235  }
1236  }
1237 
1238  if (text->curl) {
1239  if (text->curl->prev) {
1241  }
1243  }
1244 
1247 
1248  return OPERATOR_FINISHED;
1249 }
1250 
1252 {
1253  /* identifiers */
1254  ot->name = "Line Break";
1255  ot->idname = "TEXT_OT_line_break";
1256  ot->description = "Insert line break at cursor position";
1257 
1258  /* api callbacks */
1260  ot->poll = text_edit_poll;
1261 
1262  /* flags */
1263  ot->flag = OPTYPE_UNDO;
1264 }
1265 
1268 /* -------------------------------------------------------------------- */
1273 {
1274  Text *text = CTX_data_edit_text(C);
1275  int type = RNA_enum_get(op->ptr, "type");
1276 
1278 
1280 
1281  if (txt_has_sel(text)) {
1282  txt_order_cursors(text, false);
1283  }
1284 
1285  switch (type) {
1286  case 1:
1287  txt_comment(text);
1288  break;
1289  case -1:
1290  txt_uncomment(text);
1291  break;
1292  default:
1293  if (txt_uncomment(text) == false) {
1294  txt_comment(text);
1295  }
1296  break;
1297  }
1298 
1299  text_update_edited(text);
1300 
1303 
1304  return OPERATOR_FINISHED;
1305 }
1306 
1308 {
1309  static const EnumPropertyItem comment_items[] = {
1310  {0, "TOGGLE", 0, "Toggle Comments", NULL},
1311  {1, "COMMENT", 0, "Comment", NULL},
1312  {-1, "UNCOMMENT", 0, "Un-Comment", NULL},
1313  {0, NULL, 0, NULL, NULL},
1314  };
1315 
1316  /* identifiers */
1317  ot->name = "Toggle Comments";
1318  ot->idname = "TEXT_OT_comment_toggle";
1319 
1320  /* api callbacks */
1322  ot->poll = text_edit_poll;
1323 
1324  /* flags */
1325  ot->flag = OPTYPE_UNDO;
1326 
1327  /* properties */
1328  PropertyRNA *prop;
1329  prop = RNA_def_enum(ot->srna, "type", comment_items, 0, "Type", "Add or remove comments");
1331 }
1332 
1335 /* -------------------------------------------------------------------- */
1339 enum { TO_SPACES, TO_TABS };
1341  {TO_SPACES, "SPACES", 0, "To Spaces", NULL},
1342  {TO_TABS, "TABS", 0, "To Tabs", NULL},
1343  {0, NULL, 0, NULL, NULL},
1344 };
1345 
1347 {
1349  Text *text = CTX_data_edit_text(C);
1350  TextLine *tmp;
1351  FlattenString fs;
1352  size_t a, j, max_len = 0;
1353  int type = RNA_enum_get(op->ptr, "type");
1354 
1355  /* first convert to all space, this make it a lot easier to convert to tabs
1356  * because there is no mixtures of ' ' && '\t' */
1357  for (tmp = text->lines.first; tmp; tmp = tmp->next) {
1358  char *new_line;
1359 
1360  BLI_assert(tmp->line);
1361 
1362  flatten_string(st, &fs, tmp->line);
1363  new_line = BLI_strdup(fs.buf);
1364  flatten_string_free(&fs);
1365 
1366  MEM_freeN(tmp->line);
1367  if (tmp->format) {
1368  MEM_freeN(tmp->format);
1369  }
1370 
1371  /* Put new_line in the tmp->line spot still need to try and set the curc correctly. */
1372  tmp->line = new_line;
1373  tmp->len = strlen(new_line);
1374  tmp->format = NULL;
1375  if (tmp->len > max_len) {
1376  max_len = tmp->len;
1377  }
1378  }
1379 
1380  if (type == TO_TABS) {
1381  char *tmp_line = MEM_mallocN(sizeof(*tmp_line) * (max_len + 1), __func__);
1382 
1383  for (tmp = text->lines.first; tmp; tmp = tmp->next) {
1384  const char *text_check_line = tmp->line;
1385  const int text_check_line_len = tmp->len;
1386  char *tmp_line_cur = tmp_line;
1387  const size_t tab_len = st->tabnumber;
1388 
1389  BLI_assert(text_check_line);
1390 
1391  for (a = 0; a < text_check_line_len;) {
1392  /* A tab can only start at a position multiple of tab_len... */
1393  if (!(a % tab_len) && (text_check_line[a] == ' ')) {
1394  /* a + 0 we already know to be ' ' char... */
1395  for (j = 1;
1396  (j < tab_len) && (a + j < text_check_line_len) && (text_check_line[a + j] == ' ');
1397  j++) {
1398  /* pass */
1399  }
1400 
1401  if (j == tab_len) {
1402  /* We found a set of spaces that can be replaced by a tab... */
1403  if ((tmp_line_cur == tmp_line) && a != 0) {
1404  /* Copy all 'valid' string already 'parsed'... */
1405  memcpy(tmp_line_cur, text_check_line, a);
1406  tmp_line_cur += a;
1407  }
1408  *tmp_line_cur = '\t';
1409  tmp_line_cur++;
1410  a += j;
1411  }
1412  else {
1413  if (tmp_line_cur != tmp_line) {
1414  memcpy(tmp_line_cur, &text_check_line[a], j);
1415  tmp_line_cur += j;
1416  }
1417  a += j;
1418  }
1419  }
1420  else {
1421  size_t len = BLI_str_utf8_size_safe(&text_check_line[a]);
1422  if (tmp_line_cur != tmp_line) {
1423  memcpy(tmp_line_cur, &text_check_line[a], len);
1424  tmp_line_cur += len;
1425  }
1426  a += len;
1427  }
1428  }
1429 
1430  if (tmp_line_cur != tmp_line) {
1431  *tmp_line_cur = '\0';
1432 
1433 #ifndef NDEBUG
1434  BLI_assert(tmp_line_cur - tmp_line <= max_len);
1435 
1436  flatten_string(st, &fs, tmp_line);
1437  BLI_assert(STREQ(fs.buf, tmp->line));
1438  flatten_string_free(&fs);
1439 #endif
1440 
1441  MEM_freeN(tmp->line);
1442  if (tmp->format) {
1443  MEM_freeN(tmp->format);
1444  }
1445 
1446  /* Put new_line in the tmp->line spot
1447  * still need to try and set the curc correctly. */
1448  tmp->line = BLI_strdup(tmp_line);
1449  tmp->len = strlen(tmp_line);
1450  tmp->format = NULL;
1451  }
1452  }
1453 
1454  MEM_freeN(tmp_line);
1455  }
1456 
1457  text_update_edited(text);
1461 
1462  return OPERATOR_FINISHED;
1463 }
1464 
1466 {
1467  /* identifiers */
1468  ot->name = "Convert Whitespace";
1469  ot->idname = "TEXT_OT_convert_whitespace";
1470  ot->description = "Convert whitespaces by type";
1471 
1472  /* api callbacks */
1474  ot->poll = text_edit_poll;
1475 
1476  /* flags */
1477  ot->flag = OPTYPE_UNDO;
1478 
1479  /* properties */
1480  RNA_def_enum(ot->srna,
1481  "type",
1483  TO_SPACES,
1484  "Type",
1485  "Type of whitespace to convert to");
1486 }
1487 
1490 /* -------------------------------------------------------------------- */
1495 {
1496  Text *text = CTX_data_edit_text(C);
1497 
1498  txt_sel_all(text);
1499 
1502 
1503  return OPERATOR_FINISHED;
1504 }
1505 
1507 {
1508  /* identifiers */
1509  ot->name = "Select All";
1510  ot->idname = "TEXT_OT_select_all";
1511  ot->description = "Select all text";
1512 
1513  /* api callbacks */
1515  ot->poll = text_edit_poll;
1516 }
1517 
1520 /* -------------------------------------------------------------------- */
1525 {
1526  Text *text = CTX_data_edit_text(C);
1527 
1528  txt_sel_line(text);
1529 
1532 
1533  return OPERATOR_FINISHED;
1534 }
1535 
1537 {
1538  /* identifiers */
1539  ot->name = "Select Line";
1540  ot->idname = "TEXT_OT_select_line";
1541  ot->description = "Select text by line";
1542 
1543  /* api callbacks */
1545  ot->poll = text_edit_poll;
1546 }
1547 
1550 /* -------------------------------------------------------------------- */
1555 {
1556  Text *text = CTX_data_edit_text(C);
1557  /* don't advance cursor before stepping */
1558  const bool use_init_step = false;
1559 
1560  txt_jump_left(text, false, use_init_step);
1561  txt_jump_right(text, true, use_init_step);
1562 
1565 
1566  return OPERATOR_FINISHED;
1567 }
1568 
1570 {
1571  /* identifiers */
1572  ot->name = "Select Word";
1573  ot->idname = "TEXT_OT_select_word";
1574  ot->description = "Select word under cursor";
1575 
1576  /* api callbacks */
1578  ot->poll = text_edit_poll;
1579 }
1580 
1583 /* -------------------------------------------------------------------- */
1588 {
1589  Text *text = CTX_data_edit_text(C);
1590  const int direction = RNA_enum_get(op->ptr, "direction");
1591 
1593 
1594  txt_move_lines(text, direction);
1595 
1598 
1599  /* run the script while editing, evil but useful */
1600  if (CTX_wm_space_text(C)->live_edit) {
1602  }
1603 
1604  return OPERATOR_FINISHED;
1605 }
1606 
1608 {
1609  static const EnumPropertyItem direction_items[] = {
1610  {TXT_MOVE_LINE_UP, "UP", 0, "Up", ""},
1611  {TXT_MOVE_LINE_DOWN, "DOWN", 0, "Down", ""},
1612  {0, NULL, 0, NULL, NULL},
1613  };
1614 
1615  /* identifiers */
1616  ot->name = "Move Lines";
1617  ot->idname = "TEXT_OT_move_lines";
1618  ot->description = "Move the currently selected line(s) up/down";
1619 
1620  /* api callbacks */
1621  ot->exec = move_lines_exec;
1622  ot->poll = text_edit_poll;
1623 
1624  /* flags */
1625  ot->flag = OPTYPE_UNDO;
1626 
1627  /* properties */
1628  RNA_def_enum(ot->srna, "direction", direction_items, 1, "Direction", "");
1629 }
1630 
1633 /* -------------------------------------------------------------------- */
1638  {LINE_BEGIN, "LINE_BEGIN", 0, "Line Begin", ""},
1639  {LINE_END, "LINE_END", 0, "Line End", ""},
1640  {FILE_TOP, "FILE_TOP", 0, "File Top", ""},
1641  {FILE_BOTTOM, "FILE_BOTTOM", 0, "File Bottom", ""},
1642  {PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
1643  {NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
1644  {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
1645  {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
1646  {PREV_LINE, "PREVIOUS_LINE", 0, "Previous Line", ""},
1647  {NEXT_LINE, "NEXT_LINE", 0, "Next Line", ""},
1648  {PREV_PAGE, "PREVIOUS_PAGE", 0, "Previous Page", ""},
1649  {NEXT_PAGE, "NEXT_PAGE", 0, "Next Page", ""},
1650  {0, NULL, 0, NULL, NULL},
1651 };
1652 
1653 /* get cursor position in line by relative wrapped line and column positions */
1655  SpaceText *st, ARegion *region, TextLine *linein, int rell, int relc)
1656 {
1657  int i, j, start, end, max, chop, curs, loop, endj, found, selc;
1658  char ch;
1659 
1660  max = wrap_width(st, region);
1661 
1662  selc = start = endj = curs = found = 0;
1663  end = max;
1664  chop = loop = 1;
1665 
1666  for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe(linein->line + j)) {
1667  int chars;
1668  int columns = BLI_str_utf8_char_width_safe(linein->line + j); /* = 1 for tab */
1669 
1670  /* Mimic replacement of tabs */
1671  ch = linein->line[j];
1672  if (ch == '\t') {
1673  chars = st->tabnumber - i % st->tabnumber;
1674  ch = ' ';
1675  }
1676  else {
1677  chars = 1;
1678  }
1679 
1680  while (chars--) {
1681  if (rell == 0 && i - start <= relc && i + columns - start > relc) {
1682  /* current position could be wrapped to next line */
1683  /* this should be checked when end of current line would be reached */
1684  selc = j;
1685  found = 1;
1686  }
1687  else if (i - end <= relc && i + columns - end > relc) {
1688  curs = j;
1689  }
1690  if (i + columns - start > max) {
1691  end = MIN2(end, i);
1692 
1693  if (found) {
1694  /* exact cursor position was found, check if it's */
1695  /* still on needed line (hasn't been wrapped) */
1696  if (selc > endj && !chop) {
1697  selc = endj;
1698  }
1699  loop = 0;
1700  break;
1701  }
1702 
1703  if (chop) {
1704  endj = j;
1705  }
1706 
1707  start = end;
1708  end += max;
1709  chop = 1;
1710  rell--;
1711 
1712  if (rell == 0 && i + columns - start > relc) {
1713  selc = curs;
1714  loop = 0;
1715  break;
1716  }
1717  }
1718  else if (ch == '\0') {
1719  if (!found) {
1720  selc = linein->len;
1721  }
1722  loop = 0;
1723  break;
1724  }
1725  else if (ELEM(ch, ' ', '-')) {
1726  if (found) {
1727  loop = 0;
1728  break;
1729  }
1730 
1731  if (rell == 0 && i + columns - start > relc) {
1732  selc = curs;
1733  loop = 0;
1734  break;
1735  }
1736  end = i + 1;
1737  endj = j;
1738  chop = 0;
1739  }
1740  i += columns;
1741  }
1742  }
1743 
1744  return selc;
1745 }
1746 
1748  SpaceText *st, ARegion *region, int lines, TextLine **linep, int *charp, int *rell, int *relc)
1749 {
1750  int offl, offc, visible_lines;
1751 
1752  wrap_offset_in_line(st, region, *linep, *charp, &offl, &offc);
1753  *relc = text_get_char_pos(st, (*linep)->line, *charp) + offc;
1754  *rell = lines;
1755 
1756  /* handle current line */
1757  if (lines > 0) {
1758  visible_lines = text_get_visible_lines(st, region, (*linep)->line);
1759 
1760  if (*rell - visible_lines + offl >= 0) {
1761  if (!(*linep)->next) {
1762  if (offl < visible_lines - 1) {
1763  *rell = visible_lines - 1;
1764  return 1;
1765  }
1766 
1767  *charp = (*linep)->len;
1768  return 0;
1769  }
1770 
1771  *rell -= visible_lines - offl;
1772  *linep = (*linep)->next;
1773  }
1774  else {
1775  *rell += offl;
1776  return 1;
1777  }
1778  }
1779  else {
1780  if (*rell + offl <= 0) {
1781  if (!(*linep)->prev) {
1782  if (offl) {
1783  *rell = 0;
1784  return 1;
1785  }
1786 
1787  *charp = 0;
1788  return 0;
1789  }
1790 
1791  *rell += offl;
1792  *linep = (*linep)->prev;
1793  }
1794  else {
1795  *rell += offl;
1796  return 1;
1797  }
1798  }
1799 
1800  /* skip lines and find destination line and offsets */
1801  while (*linep) {
1802  visible_lines = text_get_visible_lines(st, region, (*linep)->line);
1803 
1804  if (lines < 0) { /* moving top */
1805  if (*rell + visible_lines >= 0) {
1806  *rell += visible_lines;
1807  break;
1808  }
1809 
1810  if (!(*linep)->prev) {
1811  *rell = 0;
1812  break;
1813  }
1814 
1815  *rell += visible_lines;
1816  *linep = (*linep)->prev;
1817  }
1818  else { /* moving bottom */
1819  if (*rell - visible_lines < 0) {
1820  break;
1821  }
1822 
1823  if (!(*linep)->next) {
1824  *rell = visible_lines - 1;
1825  break;
1826  }
1827 
1828  *rell -= visible_lines;
1829  *linep = (*linep)->next;
1830  }
1831  }
1832 
1833  return 1;
1834 }
1835 
1836 static void txt_wrap_move_bol(SpaceText *st, ARegion *region, const bool sel)
1837 {
1838  Text *text = st->text;
1839  TextLine **linep;
1840  int *charp;
1841  int oldc, i, j, max, start, end, endj, chop, loop;
1842  char ch;
1843 
1845 
1846  if (sel) {
1847  linep = &text->sell;
1848  charp = &text->selc;
1849  }
1850  else {
1851  linep = &text->curl;
1852  charp = &text->curc;
1853  }
1854 
1855  oldc = *charp;
1856 
1857  max = wrap_width(st, region);
1858 
1859  start = endj = 0;
1860  end = max;
1861  chop = loop = 1;
1862  *charp = 0;
1863 
1864  for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) {
1865  int chars;
1866  int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab */
1867 
1868  /* Mimic replacement of tabs */
1869  ch = (*linep)->line[j];
1870  if (ch == '\t') {
1871  chars = st->tabnumber - i % st->tabnumber;
1872  ch = ' ';
1873  }
1874  else {
1875  chars = 1;
1876  }
1877 
1878  while (chars--) {
1879  if (i + columns - start > max) {
1880  end = MIN2(end, i);
1881 
1882  *charp = endj;
1883 
1884  if (j >= oldc) {
1885  if (ch == '\0') {
1886  *charp = BLI_str_utf8_offset_from_column((*linep)->line, start);
1887  }
1888  loop = 0;
1889  break;
1890  }
1891 
1892  if (chop) {
1893  endj = j;
1894  }
1895 
1896  start = end;
1897  end += max;
1898  chop = 1;
1899  }
1900  else if (ELEM(ch, ' ', '-', '\0')) {
1901  if (j >= oldc) {
1902  *charp = BLI_str_utf8_offset_from_column((*linep)->line, start);
1903  loop = 0;
1904  break;
1905  }
1906 
1907  end = i + 1;
1908  endj = j + 1;
1909  chop = 0;
1910  }
1911  i += columns;
1912  }
1913  }
1914 
1915  if (!sel) {
1916  txt_pop_sel(text);
1917  }
1918 }
1919 
1920 static void txt_wrap_move_eol(SpaceText *st, ARegion *region, const bool sel)
1921 {
1922  Text *text = st->text;
1923  TextLine **linep;
1924  int *charp;
1925  int oldc, i, j, max, start, end, endj, chop, loop;
1926  char ch;
1927 
1929 
1930  if (sel) {
1931  linep = &text->sell;
1932  charp = &text->selc;
1933  }
1934  else {
1935  linep = &text->curl;
1936  charp = &text->curc;
1937  }
1938 
1939  oldc = *charp;
1940 
1941  max = wrap_width(st, region);
1942 
1943  start = endj = 0;
1944  end = max;
1945  chop = loop = 1;
1946  *charp = 0;
1947 
1948  for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) {
1949  int chars;
1950  int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab */
1951 
1952  /* Mimic replacement of tabs */
1953  ch = (*linep)->line[j];
1954  if (ch == '\t') {
1955  chars = st->tabnumber - i % st->tabnumber;
1956  ch = ' ';
1957  }
1958  else {
1959  chars = 1;
1960  }
1961 
1962  while (chars--) {
1963  if (i + columns - start > max) {
1964  end = MIN2(end, i);
1965 
1966  if (chop) {
1967  endj = BLI_str_find_prev_char_utf8((*linep)->line + j, (*linep)->line) - (*linep)->line;
1968  }
1969 
1970  if (endj >= oldc) {
1971  if (ch == '\0') {
1972  *charp = (*linep)->len;
1973  }
1974  else {
1975  *charp = endj;
1976  }
1977  loop = 0;
1978  break;
1979  }
1980 
1981  start = end;
1982  end += max;
1983  chop = 1;
1984  }
1985  else if (ch == '\0') {
1986  *charp = (*linep)->len;
1987  loop = 0;
1988  break;
1989  }
1990  else if (ELEM(ch, ' ', '-')) {
1991  end = i + 1;
1992  endj = j;
1993  chop = 0;
1994  }
1995  i += columns;
1996  }
1997  }
1998 
1999  if (!sel) {
2000  txt_pop_sel(text);
2001  }
2002 }
2003 
2004 static void txt_wrap_move_up(SpaceText *st, ARegion *region, const bool sel)
2005 {
2006  Text *text = st->text;
2007  TextLine **linep;
2008  int *charp;
2009  int offl, offc, col;
2010 
2012 
2013  if (sel) {
2014  linep = &text->sell;
2015  charp = &text->selc;
2016  }
2017  else {
2018  linep = &text->curl;
2019  charp = &text->curc;
2020  }
2021 
2022  wrap_offset_in_line(st, region, *linep, *charp, &offl, &offc);
2023  col = text_get_char_pos(st, (*linep)->line, *charp) + offc;
2024  if (offl) {
2025  *charp = text_get_cursor_rel(st, region, *linep, offl - 1, col);
2026  }
2027  else {
2028  if ((*linep)->prev) {
2029  int visible_lines;
2030 
2031  *linep = (*linep)->prev;
2032  visible_lines = text_get_visible_lines(st, region, (*linep)->line);
2033  *charp = text_get_cursor_rel(st, region, *linep, visible_lines - 1, col);
2034  }
2035  else {
2036  *charp = 0;
2037  }
2038  }
2039 
2040  if (!sel) {
2041  txt_pop_sel(text);
2042  }
2043 }
2044 
2045 static void txt_wrap_move_down(SpaceText *st, ARegion *region, const bool sel)
2046 {
2047  Text *text = st->text;
2048  TextLine **linep;
2049  int *charp;
2050  int offl, offc, col, visible_lines;
2051 
2053 
2054  if (sel) {
2055  linep = &text->sell;
2056  charp = &text->selc;
2057  }
2058  else {
2059  linep = &text->curl;
2060  charp = &text->curc;
2061  }
2062 
2063  wrap_offset_in_line(st, region, *linep, *charp, &offl, &offc);
2064  col = text_get_char_pos(st, (*linep)->line, *charp) + offc;
2065  visible_lines = text_get_visible_lines(st, region, (*linep)->line);
2066  if (offl < visible_lines - 1) {
2067  *charp = text_get_cursor_rel(st, region, *linep, offl + 1, col);
2068  }
2069  else {
2070  if ((*linep)->next) {
2071  *linep = (*linep)->next;
2072  *charp = text_get_cursor_rel(st, region, *linep, 0, col);
2073  }
2074  else {
2075  *charp = (*linep)->len;
2076  }
2077  }
2078 
2079  if (!sel) {
2080  txt_pop_sel(text);
2081  }
2082 }
2083 
2084 /* Moves the cursor vertically by the specified number of lines.
2085  * If the destination line is shorter than the current cursor position, the
2086  * cursor will be positioned at the end of this line.
2087  *
2088  * This is to replace screen_skip for PageUp/Down operations.
2089  */
2090 static void cursor_skip(SpaceText *st, ARegion *region, Text *text, int lines, const bool sel)
2091 {
2092  TextLine **linep;
2093  int *charp;
2094 
2095  if (sel) {
2096  linep = &text->sell;
2097  charp = &text->selc;
2098  }
2099  else {
2100  linep = &text->curl;
2101  charp = &text->curc;
2102  }
2103 
2104  if (st && region && st->wordwrap) {
2105  int rell, relc;
2106 
2107  /* find line and offsets inside it needed to set cursor position */
2108  if (cursor_skip_find_line(st, region, lines, linep, charp, &rell, &relc)) {
2109  *charp = text_get_cursor_rel(st, region, *linep, rell, relc);
2110  }
2111  }
2112  else {
2113  while (lines > 0 && (*linep)->next) {
2114  *linep = (*linep)->next;
2115  lines--;
2116  }
2117  while (lines < 0 && (*linep)->prev) {
2118  *linep = (*linep)->prev;
2119  lines++;
2120  }
2121  }
2122 
2123  if (*charp > (*linep)->len) {
2124  *charp = (*linep)->len;
2125  }
2126 
2127  if (!sel) {
2128  txt_pop_sel(text);
2129  }
2130 }
2131 
2132 static int text_move_cursor(bContext *C, int type, bool select)
2133 {
2135  Text *text = CTX_data_edit_text(C);
2136  ARegion *region = CTX_wm_region(C);
2137 
2138  /* ensure we have the right region, it's optional */
2139  if (region && region->regiontype != RGN_TYPE_WINDOW) {
2140  region = NULL;
2141  }
2142 
2143  switch (type) {
2144  case LINE_BEGIN:
2145  if (!select) {
2146  txt_sel_clear(text);
2147  }
2148  if (st && st->wordwrap && region) {
2149  txt_wrap_move_bol(st, region, select);
2150  }
2151  else {
2152  txt_move_bol(text, select);
2153  }
2154  break;
2155 
2156  case LINE_END:
2157  if (!select) {
2158  txt_sel_clear(text);
2159  }
2160  if (st && st->wordwrap && region) {
2161  txt_wrap_move_eol(st, region, select);
2162  }
2163  else {
2164  txt_move_eol(text, select);
2165  }
2166  break;
2167 
2168  case FILE_TOP:
2169  txt_move_bof(text, select);
2170  break;
2171 
2172  case FILE_BOTTOM:
2173  txt_move_eof(text, select);
2174  break;
2175 
2176  case PREV_WORD:
2177  if (txt_cursor_is_line_start(text)) {
2178  txt_move_left(text, select);
2179  }
2180  txt_jump_left(text, select, true);
2181  break;
2182 
2183  case NEXT_WORD:
2184  if (txt_cursor_is_line_end(text)) {
2185  txt_move_right(text, select);
2186  }
2187  txt_jump_right(text, select, true);
2188  break;
2189 
2190  case PREV_CHAR:
2191  if (txt_has_sel(text) && !select) {
2192  txt_order_cursors(text, false);
2193  txt_pop_sel(text);
2194  }
2195  else {
2196  txt_move_left(text, select);
2197  }
2198  break;
2199 
2200  case NEXT_CHAR:
2201  if (txt_has_sel(text) && !select) {
2202  txt_order_cursors(text, true);
2203  txt_pop_sel(text);
2204  }
2205  else {
2206  txt_move_right(text, select);
2207  }
2208  break;
2209 
2210  case PREV_LINE:
2211  if (st && st->wordwrap && region) {
2212  txt_wrap_move_up(st, region, select);
2213  }
2214  else {
2215  txt_move_up(text, select);
2216  }
2217  break;
2218 
2219  case NEXT_LINE:
2220  if (st && st->wordwrap && region) {
2221  txt_wrap_move_down(st, region, select);
2222  }
2223  else {
2224  txt_move_down(text, select);
2225  }
2226  break;
2227 
2228  case PREV_PAGE:
2229  if (st) {
2230  cursor_skip(st, region, st->text, -st->runtime.viewlines, select);
2231  }
2232  else {
2233  cursor_skip(NULL, NULL, text, -10, select);
2234  }
2235  break;
2236 
2237  case NEXT_PAGE:
2238  if (st) {
2239  cursor_skip(st, region, st->text, st->runtime.viewlines, select);
2240  }
2241  else {
2242  cursor_skip(NULL, NULL, text, 10, select);
2243  }
2244  break;
2245  }
2246 
2249 
2250  return OPERATOR_FINISHED;
2251 }
2252 
2254 {
2255  int type = RNA_enum_get(op->ptr, "type");
2256 
2257  return text_move_cursor(C, type, 0);
2258 }
2259 
2261 {
2262  /* identifiers */
2263  ot->name = "Move Cursor";
2264  ot->idname = "TEXT_OT_move";
2265  ot->description = "Move cursor to position type";
2266 
2267  /* api callbacks */
2268  ot->exec = text_move_exec;
2269  ot->poll = text_edit_poll;
2270 
2271  /* properties */
2272  RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to");
2273 }
2274 
2277 /* -------------------------------------------------------------------- */
2282 {
2283  int type = RNA_enum_get(op->ptr, "type");
2284 
2285  return text_move_cursor(C, type, 1);
2286 }
2287 
2289 {
2290  /* identifiers */
2291  ot->name = "Move Select";
2292  ot->idname = "TEXT_OT_move_select";
2293  ot->description = "Move the cursor while selecting";
2294 
2295  /* api callbacks */
2298 
2299  /* properties */
2300  RNA_def_enum(ot->srna,
2301  "type",
2303  LINE_BEGIN,
2304  "Type",
2305  "Where to move cursor to, to make a selection");
2306 }
2307 
2310 /* -------------------------------------------------------------------- */
2315 {
2316  Text *text = CTX_data_edit_text(C);
2317  int line = RNA_int_get(op->ptr, "line");
2318  short nlines = txt_get_span(text->lines.first, text->lines.last) + 1;
2319 
2320  if (line < 1) {
2321  txt_move_toline(text, 1, 0);
2322  }
2323  else if (line > nlines) {
2324  txt_move_toline(text, nlines - 1, 0);
2325  }
2326  else {
2327  txt_move_toline(text, line - 1, 0);
2328  }
2329 
2332 
2333  return OPERATOR_FINISHED;
2334 }
2335 
2336 static int text_jump_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2337 {
2338  return WM_operator_props_dialog_popup(C, op, 200);
2339 }
2340 
2342 {
2343  PropertyRNA *prop;
2344 
2345  /* identifiers */
2346  ot->name = "Jump";
2347  ot->idname = "TEXT_OT_jump";
2348  ot->description = "Jump cursor to line";
2349 
2350  /* api callbacks */
2352  ot->exec = text_jump_exec;
2353  ot->poll = text_edit_poll;
2354 
2355  /* properties */
2356  prop = RNA_def_int(ot->srna, "line", 1, 1, INT_MAX, "Line", "Line number to jump to", 1, 10000);
2358 }
2359 
2362 /* -------------------------------------------------------------------- */
2367  {DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
2368  {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
2369  {DEL_NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
2370  {DEL_PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
2371  {0, NULL, 0, NULL, NULL},
2372 };
2373 
2375 {
2377  Text *text = CTX_data_edit_text(C);
2378  int type = RNA_enum_get(op->ptr, "type");
2379 
2381 
2382  /* behavior could be changed here,
2383  * but for now just don't jump words when we have a selection */
2384  if (txt_has_sel(text)) {
2385  if (type == DEL_PREV_WORD) {
2386  type = DEL_PREV_CHAR;
2387  }
2388  else if (type == DEL_NEXT_WORD) {
2389  type = DEL_NEXT_CHAR;
2390  }
2391  }
2392 
2394 
2395  if (type == DEL_PREV_WORD) {
2396  if (txt_cursor_is_line_start(text)) {
2397  txt_backspace_char(text);
2398  }
2399  txt_backspace_word(text);
2400  }
2401  else if (type == DEL_PREV_CHAR) {
2402 
2403  if (text->flags & TXT_TABSTOSPACES) {
2404  if (!txt_has_sel(text) && !txt_cursor_is_line_start(text)) {
2405  int tabsize = 0;
2406  tabsize = txt_calc_tab_left(text->curl, text->curc);
2407  if (tabsize) {
2408  text->sell = text->curl;
2409  text->selc = text->curc - tabsize;
2410  txt_order_cursors(text, false);
2411  }
2412  }
2413  }
2414  if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) {
2415  const char *curr = text->curl->line + text->curc;
2416  if (*curr != '\0') {
2417  const char *prev = BLI_str_find_prev_char_utf8(curr, text->curl->line);
2418  if ((curr != prev) && /* When back-spacing from the start of the line. */
2419  (*curr == text_closing_character_pair_get(*prev))) {
2420  txt_move_right(text, false);
2421  txt_backspace_char(text);
2422  }
2423  }
2424  }
2425  txt_backspace_char(text);
2426  }
2427  else if (type == DEL_NEXT_WORD) {
2428  if (txt_cursor_is_line_end(text)) {
2429  txt_delete_char(text);
2430  }
2431  txt_delete_word(text);
2432  }
2433  else if (type == DEL_NEXT_CHAR) {
2434 
2435  if (text->flags & TXT_TABSTOSPACES) {
2436  if (!txt_has_sel(text) && !txt_cursor_is_line_end(text)) {
2437  int tabsize = 0;
2438  tabsize = txt_calc_tab_right(text->curl, text->curc);
2439  if (tabsize) {
2440  text->sell = text->curl;
2441  text->selc = text->curc + tabsize;
2442  txt_order_cursors(text, true);
2443  }
2444  }
2445  }
2446 
2447  txt_delete_char(text);
2448  }
2449 
2451 
2454 
2455  /* run the script while editing, evil but useful */
2456  if (st->live_edit) {
2458  }
2459 
2460  return OPERATOR_FINISHED;
2461 }
2462 
2464 {
2465  /* identifiers */
2466  ot->name = "Delete";
2467  ot->idname = "TEXT_OT_delete";
2468  ot->description = "Delete text by cursor position";
2469 
2470  /* api callbacks */
2472  ot->poll = text_edit_poll;
2473 
2474  /* flags */
2475  ot->flag = OPTYPE_UNDO;
2476 
2477  /* properties */
2478  PropertyRNA *prop;
2479  prop = RNA_def_enum(ot->srna,
2480  "type",
2482  DEL_NEXT_CHAR,
2483  "Type",
2484  "Which part of the text to delete");
2486 }
2487 
2490 /* -------------------------------------------------------------------- */
2495 {
2497 
2498  st->overwrite = !st->overwrite;
2499 
2501 
2502  return OPERATOR_FINISHED;
2503 }
2504 
2506 {
2507  /* identifiers */
2508  ot->name = "Toggle Overwrite";
2509  ot->idname = "TEXT_OT_overwrite_toggle";
2510  ot->description = "Toggle overwrite while typing";
2511 
2512  /* api callbacks */
2515 }
2516 
2519 /* -------------------------------------------------------------------- */
2523 static void txt_screen_clamp(SpaceText *st, ARegion *region)
2524 {
2525  if (st->top <= 0) {
2526  st->top = 0;
2527  }
2528  else {
2529  int last;
2530  last = text_get_total_lines(st, region);
2531  last = last - (st->runtime.viewlines / 2);
2532  if (last > 0 && st->top > last) {
2533  st->top = last;
2534  }
2535  }
2536 }
2537 
2538 /* Moves the view vertically by the specified number of lines */
2539 static void txt_screen_skip(SpaceText *st, ARegion *region, int lines)
2540 {
2541  st->top += lines;
2542  txt_screen_clamp(st, region);
2543 }
2544 
2545 /* quick enum for tsc->zone (scroller handles) */
2551 };
2552 
2553 typedef struct TextScroll {
2554  int mval_prev[2];
2555  int mval_delta[2];
2556 
2557  bool is_first;
2559 
2560  enum eScrollZone zone;
2561 
2562  /* Store the state of the display, cache some constant vars. */
2563  struct {
2564  int ofs_init[2];
2565  int ofs_max[2];
2566  int size_px[2];
2568  int ofs_delta[2];
2571 
2573 {
2574  tsc->state.ofs_init[0] = st->left;
2575  tsc->state.ofs_init[1] = st->top;
2576 
2577  tsc->state.ofs_max[0] = INT_MAX;
2578  tsc->state.ofs_max[1] = max_ii(0,
2579  text_get_total_lines(st, region) - (st->runtime.viewlines / 2));
2580 
2581  tsc->state.size_px[0] = st->runtime.cwidth_px;
2582  tsc->state.size_px[1] = TXT_LINE_HEIGHT(st);
2583 }
2584 
2586 {
2587  /* it should be possible to still scroll linked texts to read them,
2588  * even if they can't be edited... */
2589  return CTX_data_edit_text(C) != NULL;
2590 }
2591 
2593 {
2595  ARegion *region = CTX_wm_region(C);
2596 
2597  int lines = RNA_int_get(op->ptr, "lines");
2598 
2599  if (lines == 0) {
2600  return OPERATOR_CANCELLED;
2601  }
2602 
2603  txt_screen_skip(st, region, lines * 3);
2604 
2606 
2607  return OPERATOR_FINISHED;
2608 }
2609 
2610 static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event)
2611 {
2613  TextScroll *tsc = op->customdata;
2614  const int mval[2] = {event->xy[0], event->xy[1]};
2615 
2617 
2618  /* compute mouse move distance */
2619  if (tsc->is_first) {
2620  copy_v2_v2_int(tsc->mval_prev, mval);
2621  tsc->is_first = false;
2622  }
2623 
2624  if (event->type != MOUSEPAN) {
2625  sub_v2_v2v2_int(tsc->mval_delta, mval, tsc->mval_prev);
2626  }
2627 
2628  /* accumulate scroll, in float values for events that give less than one
2629  * line offset but taken together should still scroll */
2630  if (!tsc->is_scrollbar) {
2631  tsc->ofs_delta_px[0] -= tsc->mval_delta[0];
2632  tsc->ofs_delta_px[1] += tsc->mval_delta[1];
2633  }
2634  else {
2635  tsc->ofs_delta_px[1] -= (tsc->mval_delta[1] * st->runtime.scroll_px_per_line) *
2636  tsc->state.size_px[1];
2637  }
2638 
2639  for (int i = 0; i < 2; i += 1) {
2640  int lines_from_pixels = tsc->ofs_delta_px[i] / tsc->state.size_px[i];
2641  tsc->ofs_delta[i] += lines_from_pixels;
2642  tsc->ofs_delta_px[i] -= lines_from_pixels * tsc->state.size_px[i];
2643  }
2644 
2645  /* The final values need to be calculated from the inputs,
2646  * so clamping and ensuring an unsigned pixel offset doesn't conflict with
2647  * updating the cursor mval_delta. */
2648  int scroll_ofs_new[2] = {
2649  tsc->state.ofs_init[0] + tsc->ofs_delta[0],
2650  tsc->state.ofs_init[1] + tsc->ofs_delta[1],
2651  };
2652  int scroll_ofs_px_new[2] = {
2653  tsc->ofs_delta_px[0],
2654  tsc->ofs_delta_px[1],
2655  };
2656 
2657  for (int i = 0; i < 2; i += 1) {
2658  /* Ensure always unsigned (adjusting line/column accordingly). */
2659  while (scroll_ofs_px_new[i] < 0) {
2660  scroll_ofs_px_new[i] += tsc->state.size_px[i];
2661  scroll_ofs_new[i] -= 1;
2662  }
2663 
2664  /* Clamp within usable region. */
2665  if (scroll_ofs_new[i] < 0) {
2666  scroll_ofs_new[i] = 0;
2667  scroll_ofs_px_new[i] = 0;
2668  }
2669  else if (scroll_ofs_new[i] >= tsc->state.ofs_max[i]) {
2670  scroll_ofs_new[i] = tsc->state.ofs_max[i];
2671  scroll_ofs_px_new[i] = 0;
2672  }
2673  }
2674 
2675  /* Override for word-wrap. */
2676  if (st->wordwrap) {
2677  scroll_ofs_new[0] = 0;
2678  scroll_ofs_px_new[0] = 0;
2679  }
2680 
2681  /* Apply to the screen. */
2682  if (scroll_ofs_new[0] != st->left || scroll_ofs_new[1] != st->top ||
2683  /* Horizontal sub-pixel offset currently isn't used. */
2684  /* scroll_ofs_px_new[0] != st->scroll_ofs_px[0] || */
2685  scroll_ofs_px_new[1] != st->runtime.scroll_ofs_px[1]) {
2686 
2687  st->left = scroll_ofs_new[0];
2688  st->top = scroll_ofs_new[1];
2689  st->runtime.scroll_ofs_px[0] = scroll_ofs_px_new[0];
2690  st->runtime.scroll_ofs_px[1] = scroll_ofs_px_new[1];
2692  }
2693 
2694  tsc->mval_prev[0] = mval[0];
2695  tsc->mval_prev[1] = mval[1];
2696 }
2697 
2698 static void scroll_exit(bContext *C, wmOperator *op)
2699 {
2701  TextScroll *tsc = op->customdata;
2702 
2703  st->flags &= ~ST_SCROLL_SELECT;
2704 
2705  if (st->runtime.scroll_ofs_px[1] > tsc->state.size_px[1] / 2) {
2706  st->top += 1;
2707  }
2708 
2709  st->runtime.scroll_ofs_px[0] = 0;
2710  st->runtime.scroll_ofs_px[1] = 0;
2712 
2713  MEM_freeN(op->customdata);
2714 }
2715 
2716 static int text_scroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
2717 {
2718  TextScroll *tsc = op->customdata;
2720  ARegion *region = CTX_wm_region(C);
2721 
2722  switch (event->type) {
2723  case MOUSEMOVE:
2724  if (tsc->zone == SCROLLHANDLE_BAR) {
2725  text_scroll_apply(C, op, event);
2726  }
2727  break;
2728  case LEFTMOUSE:
2729  case RIGHTMOUSE:
2730  case MIDDLEMOUSE:
2731  if (event->val == KM_RELEASE) {
2734  region,
2735  st->runtime.viewlines *
2736  (tsc->zone == SCROLLHANDLE_MIN_OUTSIDE ? 1 : -1));
2737 
2739  }
2740  scroll_exit(C, op);
2741  return OPERATOR_FINISHED;
2742  }
2743  }
2744 
2745  return OPERATOR_RUNNING_MODAL;
2746 }
2747 
2749 {
2750  scroll_exit(C, op);
2751 }
2752 
2753 static int text_scroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2754 {
2756  ARegion *region = CTX_wm_region(C);
2757 
2758  TextScroll *tsc;
2759 
2760  if (RNA_struct_property_is_set(op->ptr, "lines")) {
2761  return text_scroll_exec(C, op);
2762  }
2763 
2764  tsc = MEM_callocN(sizeof(TextScroll), "TextScroll");
2765  tsc->is_first = true;
2766  tsc->zone = SCROLLHANDLE_BAR;
2767 
2768  text_scroll_state_init(tsc, st, region);
2769 
2770  op->customdata = tsc;
2771 
2772  st->flags |= ST_SCROLL_SELECT;
2773 
2774  if (event->type == MOUSEPAN) {
2776 
2777  copy_v2_v2_int(tsc->mval_prev, event->xy);
2778  /* Sensitivity of scroll set to 4pix per line/char */
2779  tsc->mval_delta[0] = (event->xy[0] - event->prev_xy[0]) * st->runtime.cwidth_px / 4;
2780  tsc->mval_delta[1] = (event->xy[1] - event->prev_xy[1]) * st->runtime.lheight_px / 4;
2781  tsc->is_first = false;
2782  tsc->is_scrollbar = false;
2783  text_scroll_apply(C, op, event);
2784  scroll_exit(C, op);
2785  return OPERATOR_FINISHED;
2786  }
2787 
2789 
2790  return OPERATOR_RUNNING_MODAL;
2791 }
2792 
2794 {
2795  /* identifiers */
2796  ot->name = "Scroll";
2797  /* don't really see the difference between this and
2798  * scroll_bar. Both do basically the same thing (aside from key-maps). */
2799  ot->idname = "TEXT_OT_scroll";
2800 
2801  /* api callbacks */
2807 
2808  /* flags */
2810 
2811  /* properties */
2812  RNA_def_int(
2813  ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
2814 }
2815 
2818 /* -------------------------------------------------------------------- */
2823 {
2824  /* same as text_region_edit_poll except it works on libdata too */
2826  Text *text = CTX_data_edit_text(C);
2827  ARegion *region = CTX_wm_region(C);
2828 
2829  if (!st || !text) {
2830  return 0;
2831  }
2832 
2833  if (!region || region->regiontype != RGN_TYPE_WINDOW) {
2834  return 0;
2835  }
2836 
2837  return 1;
2838 }
2839 
2840 static int text_scroll_bar_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2841 {
2843  ARegion *region = CTX_wm_region(C);
2844  TextScroll *tsc;
2845  const int *mval = event->mval;
2847 
2848  if (RNA_struct_property_is_set(op->ptr, "lines")) {
2849  return text_scroll_exec(C, op);
2850  }
2851 
2852  /* verify we are in the right zone */
2853  if (mval[0] > st->runtime.scroll_region_handle.xmin &&
2854  mval[0] < st->runtime.scroll_region_handle.xmax) {
2855  if (mval[1] >= st->runtime.scroll_region_handle.ymin &&
2856  mval[1] <= st->runtime.scroll_region_handle.ymax) {
2857  /* mouse inside scroll handle */
2858  zone = SCROLLHANDLE_BAR;
2859  }
2860  else if (mval[1] > TXT_SCROLL_SPACE && mval[1] < region->winy - TXT_SCROLL_SPACE) {
2861  if (mval[1] < st->runtime.scroll_region_handle.ymin) {
2862  zone = SCROLLHANDLE_MIN_OUTSIDE;
2863  }
2864  else {
2865  zone = SCROLLHANDLE_MAX_OUTSIDE;
2866  }
2867  }
2868  }
2869 
2870  if (zone == SCROLLHANDLE_INVALID_OUTSIDE) {
2871  /* we are outside slider - nothing to do */
2872  return OPERATOR_PASS_THROUGH;
2873  }
2874 
2875  tsc = MEM_callocN(sizeof(TextScroll), "TextScroll");
2876  tsc->is_first = true;
2877  tsc->is_scrollbar = true;
2878  tsc->zone = zone;
2879  op->customdata = tsc;
2880  st->flags |= ST_SCROLL_SELECT;
2881 
2882  text_scroll_state_init(tsc, st, region);
2883 
2884  /* jump scroll, works in v2d but needs to be added here too :S */
2885  if (event->type == MIDDLEMOUSE) {
2886  tsc->mval_prev[0] = region->winrct.xmin + BLI_rcti_cent_x(&st->runtime.scroll_region_handle);
2887  tsc->mval_prev[1] = region->winrct.ymin + BLI_rcti_cent_y(&st->runtime.scroll_region_handle);
2888 
2889  tsc->is_first = false;
2890  tsc->zone = SCROLLHANDLE_BAR;
2891  text_scroll_apply(C, op, event);
2892  }
2893 
2895 
2896  return OPERATOR_RUNNING_MODAL;
2897 }
2898 
2900 {
2901  /* identifiers */
2902  ot->name = "Scrollbar";
2903  /* don't really see the difference between this and
2904  * scroll. Both do basically the same thing (aside from key-maps). */
2905  ot->idname = "TEXT_OT_scroll_bar";
2906 
2907  /* api callbacks */
2912 
2913  /* flags */
2915 
2916  /* properties */
2917  RNA_def_int(
2918  ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
2919 }
2920 
2923 /* -------------------------------------------------------------------- */
2927 typedef struct SetSelection {
2928  int selc, sell;
2929  short mval_prev[2];
2930  wmTimer *timer; /* needed for scrolling when mouse at region bounds */
2932 
2933 static int flatten_width(SpaceText *st, const char *str)
2934 {
2935  int total = 0;
2936 
2937  for (int i = 0; str[i]; i += BLI_str_utf8_size_safe(str + i)) {
2938  if (str[i] == '\t') {
2939  total += st->tabnumber - total % st->tabnumber;
2940  }
2941  else {
2942  total += BLI_str_utf8_char_width_safe(str + i);
2943  }
2944  }
2945 
2946  return total;
2947 }
2948 
2949 static int flatten_column_to_offset(SpaceText *st, const char *str, int index)
2950 {
2951  int i = 0, j = 0, col;
2952 
2953  while (*(str + j)) {
2954  if (str[j] == '\t') {
2955  col = st->tabnumber - i % st->tabnumber;
2956  }
2957  else {
2959  }
2960 
2961  if (i + col > index) {
2962  break;
2963  }
2964 
2965  i += col;
2966  j += BLI_str_utf8_size_safe(str + j);
2967  }
2968 
2969  return j;
2970 }
2971 
2973 {
2974  TextLine *linep = st->text->lines.first;
2975  int i, lines;
2976 
2977  if (*y < -st->top) {
2978  return NULL; /* We are beyond the first line... */
2979  }
2980 
2981  for (i = -st->top; i <= *y && linep; linep = linep->next, i += lines) {
2982  lines = text_get_visible_lines(st, region, linep->line);
2983 
2984  if (i + lines > *y) {
2985  /* We found the line matching given vertical 'coordinate',
2986  * now set y relative to this line's start. */
2987  *y -= i;
2988  break;
2989  }
2990  }
2991  return linep;
2992 }
2993 
2995  SpaceText *st, ARegion *region, int x, int y, const bool sel)
2996 {
2997  Text *text = st->text;
2998  int max = wrap_width(st, region); /* column */
2999  int charp = -1; /* mem */
3000  bool found = false; /* flags */
3001 
3002  /* Point to line matching given y position, if any. */
3003  TextLine *linep = get_line_pos_wrapped(st, region, &y);
3004 
3005  if (linep) {
3006  int i = 0, start = 0, end = max; /* column */
3007  int j, curs = 0, endj = 0; /* mem */
3008  bool chop = true; /* flags */
3009  char ch;
3010 
3011  for (j = 0; !found && ((ch = linep->line[j]) != '\0');
3012  j += BLI_str_utf8_size_safe(linep->line + j)) {
3013  int chars;
3014  int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */
3015 
3016  /* Mimic replacement of tabs */
3017  if (ch == '\t') {
3018  chars = st->tabnumber - i % st->tabnumber;
3019  ch = ' ';
3020  }
3021  else {
3022  chars = 1;
3023  }
3024 
3025  while (chars--) {
3026  /* Gone too far, go back to last wrap point */
3027  if (y < 0) {
3028  charp = endj;
3029  y = 0;
3030  found = true;
3031  break;
3032  /* Exactly at the cursor */
3033  }
3034  if (y == 0 && i - start <= x && i + columns - start > x) {
3035  /* current position could be wrapped to next line */
3036  /* this should be checked when end of current line would be reached */
3037  charp = curs = j;
3038  found = true;
3039  /* Prepare curs for next wrap */
3040  }
3041  else if (i - end <= x && i + columns - end > x) {
3042  curs = j;
3043  }
3044  if (i + columns - start > max) {
3045  end = MIN2(end, i);
3046 
3047  if (found) {
3048  /* exact cursor position was found, check if it's still on needed line
3049  * (hasn't been wrapped) */
3050  if (charp > endj && !chop && ch != '\0') {
3051  charp = endj;
3052  }
3053  break;
3054  }
3055 
3056  if (chop) {
3057  endj = j;
3058  }
3059  start = end;
3060  end += max;
3061 
3062  if (j < linep->len) {
3063  y--;
3064  }
3065 
3066  chop = true;
3067  if (y == 0 && i + columns - start > x) {
3068  charp = curs;
3069  found = true;
3070  break;
3071  }
3072  }
3073  else if (ELEM(ch, ' ', '-', '\0')) {
3074  if (found) {
3075  break;
3076  }
3077 
3078  if (y == 0 && i + columns - start > x) {
3079  charp = curs;
3080  found = true;
3081  break;
3082  }
3083  end = i + 1;
3084  endj = j;
3085  chop = false;
3086  }
3087  i += columns;
3088  }
3089  }
3090 
3091  BLI_assert(y == 0);
3092 
3093  if (!found) {
3094  /* On correct line but didn't meet cursor, must be at end */
3095  charp = linep->len;
3096  }
3097  }
3098  else if (y < 0) { /* Before start of text. */
3099  linep = st->text->lines.first;
3100  charp = 0;
3101  }
3102  else { /* Beyond end of text */
3103  linep = st->text->lines.last;
3104  charp = linep->len;
3105  }
3106 
3107  BLI_assert(linep && charp != -1);
3108 
3109  if (sel) {
3110  text->sell = linep;
3111  text->selc = charp;
3112  }
3113  else {
3114  text->curl = linep;
3115  text->curc = charp;
3116  }
3117 }
3118 
3119 static void text_cursor_set_to_pos(SpaceText *st, ARegion *region, int x, int y, const bool sel)
3120 {
3121  Text *text = st->text;
3123  y = (region->winy - 2 - y) / TXT_LINE_HEIGHT(st);
3124 
3125  x -= TXT_BODY_LEFT(st);
3126  if (x < 0) {
3127  x = 0;
3128  }
3129  x = text_pixel_x_to_column(st, x) + st->left;
3130 
3131  if (st->wordwrap) {
3132  text_cursor_set_to_pos_wrapped(st, region, x, y, sel);
3133  }
3134  else {
3135  TextLine **linep;
3136  int *charp;
3137  int w;
3138 
3139  if (sel) {
3140  linep = &text->sell;
3141  charp = &text->selc;
3142  }
3143  else {
3144  linep = &text->curl;
3145  charp = &text->curc;
3146  }
3147 
3148  y -= txt_get_span(text->lines.first, *linep) - st->top;
3149 
3150  if (y > 0) {
3151  while (y-- != 0) {
3152  if ((*linep)->next) {
3153  *linep = (*linep)->next;
3154  }
3155  }
3156  }
3157  else if (y < 0) {
3158  while (y++ != 0) {
3159  if ((*linep)->prev) {
3160  *linep = (*linep)->prev;
3161  }
3162  }
3163  }
3164 
3165  w = flatten_width(st, (*linep)->line);
3166  if (x < w) {
3167  *charp = flatten_column_to_offset(st, (*linep)->line, x);
3168  }
3169  else {
3170  *charp = (*linep)->len;
3171  }
3172  }
3173  if (!sel) {
3174  txt_pop_sel(text);
3175  }
3176 }
3177 
3179 {
3180  if (ssel->timer == NULL) {
3182  wmWindow *win = CTX_wm_window(C);
3183 
3184  ssel->timer = WM_event_add_timer(wm, win, TIMER, 0.02f);
3185  }
3186 }
3187 
3189 {
3190  if (ssel->timer) {
3192  wmWindow *win = CTX_wm_window(C);
3193 
3194  WM_event_remove_timer(wm, win, ssel->timer);
3195  }
3196  ssel->timer = NULL;
3197 }
3198 
3199 static void text_cursor_set_apply(bContext *C, wmOperator *op, const wmEvent *event)
3200 {
3202  ARegion *region = CTX_wm_region(C);
3203  SetSelection *ssel = op->customdata;
3204 
3205  if (event->mval[1] < 0 || event->mval[1] > region->winy) {
3206  text_cursor_timer_ensure(C, ssel);
3207 
3208  if (event->type == TIMER) {
3209  text_cursor_set_to_pos(st, region, event->mval[0], event->mval[1], 1);
3210  ED_text_scroll_to_cursor(st, region, false);
3212  }
3213  }
3214  else if (!st->wordwrap && (event->mval[0] < 0 || event->mval[0] > region->winx)) {
3215  text_cursor_timer_ensure(C, ssel);
3216 
3217  if (event->type == TIMER) {
3219  st, region, CLAMPIS(event->mval[0], 0, region->winx), event->mval[1], 1);
3220  ED_text_scroll_to_cursor(st, region, false);
3222  }
3223  }
3224  else {
3225  text_cursor_timer_remove(C, ssel);
3226 
3227  if (event->type != TIMER) {
3228  text_cursor_set_to_pos(st, region, event->mval[0], event->mval[1], 1);
3229  ED_text_scroll_to_cursor(st, region, false);
3231 
3232  ssel->mval_prev[0] = event->mval[0];
3233  ssel->mval_prev[1] = event->mval[1];
3234  }
3235  }
3236 }
3237 
3239 {
3241  Text *text = st->text;
3242  SetSelection *ssel = op->customdata;
3243  char *buffer;
3244 
3245  if (txt_has_sel(text)) {
3246  buffer = txt_sel_to_buf(text, NULL);
3248  MEM_freeN(buffer);
3249  }
3250 
3253 
3254  text_cursor_timer_remove(C, ssel);
3255  MEM_freeN(ssel);
3256 }
3257 
3258 static int text_selection_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3259 {
3261  SetSelection *ssel;
3262 
3263  if (event->mval[0] >= st->runtime.scroll_region_handle.xmin) {
3264  return OPERATOR_PASS_THROUGH;
3265  }
3266 
3267  op->customdata = MEM_callocN(sizeof(SetSelection), "SetCursor");
3268  ssel = op->customdata;
3269 
3270  ssel->mval_prev[0] = event->mval[0];
3271  ssel->mval_prev[1] = event->mval[1];
3272 
3273  ssel->sell = txt_get_span(st->text->lines.first, st->text->sell);
3274  ssel->selc = st->text->selc;
3275 
3277 
3278  text_cursor_set_apply(C, op, event);
3279 
3280  return OPERATOR_RUNNING_MODAL;
3281 }
3282 
3283 static int text_selection_set_modal(bContext *C, wmOperator *op, const wmEvent *event)
3284 {
3285  switch (event->type) {
3286  case LEFTMOUSE:
3287  case MIDDLEMOUSE:
3288  case RIGHTMOUSE:
3289  text_cursor_set_exit(C, op);
3290  return OPERATOR_FINISHED;
3291  case TIMER:
3292  case MOUSEMOVE:
3293  text_cursor_set_apply(C, op, event);
3294  break;
3295  }
3296 
3297  return OPERATOR_RUNNING_MODAL;
3298 }
3299 
3301 {
3302  text_cursor_set_exit(C, op);
3303 }
3304 
3306 {
3307  /* identifiers */
3308  ot->name = "Set Selection";
3309  ot->idname = "TEXT_OT_selection_set";
3310  ot->description = "Set cursor selection";
3311 
3312  /* api callbacks */
3317 }
3318 
3321 /* -------------------------------------------------------------------- */
3326 {
3328  ARegion *region = CTX_wm_region(C);
3329  int x = RNA_int_get(op->ptr, "x");
3330  int y = RNA_int_get(op->ptr, "y");
3331 
3332  text_cursor_set_to_pos(st, region, x, y, 0);
3333 
3336 
3337  return OPERATOR_PASS_THROUGH;
3338 }
3339 
3340 static int text_cursor_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3341 {
3343 
3344  if (event->mval[0] >= st->runtime.scroll_region_handle.xmin) {
3345  return OPERATOR_PASS_THROUGH;
3346  }
3347 
3348  RNA_int_set(op->ptr, "x", event->mval[0]);
3349  RNA_int_set(op->ptr, "y", event->mval[1]);
3350 
3351  return text_cursor_set_exec(C, op);
3352 }
3353 
3355 {
3356  /* identifiers */
3357  ot->name = "Set Cursor";
3358  ot->idname = "TEXT_OT_cursor_set";
3359  ot->description = "Set cursor position";
3360 
3361  /* api callbacks */
3365 
3366  /* properties */
3367  RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
3368  RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
3369 }
3370 
3373 /* -------------------------------------------------------------------- */
3377 static int text_line_number_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
3378 {
3380  Text *text = CTX_data_edit_text(C);
3381  ARegion *region = CTX_wm_region(C);
3382  const int *mval = event->mval;
3383  double time;
3384  static int jump_to = 0;
3385  static double last_jump = 0;
3386 
3388 
3389  if (!st->showlinenrs) {
3390  return OPERATOR_PASS_THROUGH;
3391  }
3392 
3393  if (!(mval[0] > 2 &&
3394  mval[0] < (TXT_NUMCOL_WIDTH(st) + (TXT_BODY_LPAD * st->runtime.cwidth_px)) &&
3395  mval[1] > 2 && mval[1] < region->winy - 2)) {
3396  return OPERATOR_PASS_THROUGH;
3397  }
3398 
3399  const char event_ascii = WM_event_utf8_to_ascii(event);
3400  if (!(event_ascii >= '0' && event_ascii <= '9')) {
3401  return OPERATOR_PASS_THROUGH;
3402  }
3403 
3405  if (last_jump < time - 1) {
3406  jump_to = 0;
3407  }
3408 
3409  jump_to *= 10;
3410  jump_to += (int)(event_ascii - '0');
3411 
3412  txt_move_toline(text, jump_to - 1, 0);
3413  last_jump = time;
3414 
3417 
3418  return OPERATOR_FINISHED;
3419 }
3420 
3422 {
3423  /* identifiers */
3424  ot->name = "Line Number";
3425  ot->idname = "TEXT_OT_line_number";
3426  ot->description = "The current line number";
3427 
3428  /* api callbacks */
3431 }
3432 
3435 /* -------------------------------------------------------------------- */
3440 {
3442  Text *text = CTX_data_edit_text(C);
3443  char *str;
3444  int str_len;
3445  bool done = false;
3446  size_t i = 0;
3447  uint code;
3448 
3450 
3451  str = RNA_string_get_alloc(op->ptr, "text", NULL, 0, &str_len);
3452 
3454 
3455  if (st && st->overwrite) {
3456  while (str[i]) {
3457  code = BLI_str_utf8_as_unicode_step(str, str_len, &i);
3458  done |= txt_replace_char(text, code);
3459  }
3460  }
3461  else {
3462  while (str[i]) {
3463  code = BLI_str_utf8_as_unicode_step(str, str_len, &i);
3464  done |= txt_add_char(text, code);
3465  }
3466  }
3467 
3468  MEM_freeN(str);
3469 
3470  if (!done) {
3471  return OPERATOR_CANCELLED;
3472  }
3473 
3475 
3478 
3479  return OPERATOR_FINISHED;
3480 }
3481 
3482 static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3483 {
3484  uint auto_close_char = 0;
3485  int ret;
3486 
3487  /* NOTE: the "text" property is always set from key-map,
3488  * so we can't use #RNA_struct_property_is_set, check the length instead. */
3489  if (!RNA_string_length(op->ptr, "text")) {
3490  /* if alt/ctrl/super are pressed pass through except for utf8 character event
3491  * (when input method are used for utf8 inputs, the user may assign key event
3492  * including alt/ctrl/super like ctrl+m to commit utf8 string. in such case,
3493  * the modifiers in the utf8 character event make no sense.) */
3494  if ((event->modifier & (KM_CTRL | KM_OSKEY)) && !event->utf8_buf[0]) {
3495  return OPERATOR_PASS_THROUGH;
3496  }
3497 
3498  char str[BLI_UTF8_MAX + 1];
3499  const size_t len = BLI_str_utf8_size_safe(event->utf8_buf);
3500  memcpy(str, event->utf8_buf, len);
3501  str[len] = '\0';
3502  RNA_string_set(op->ptr, "text", str);
3503 
3504  if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) {
3505  auto_close_char = BLI_str_utf8_as_unicode(str);
3506  }
3507  }
3508 
3509  ret = text_insert_exec(C, op);
3510 
3511  if ((ret == OPERATOR_FINISHED) && (auto_close_char != 0)) {
3512  const uint auto_close_match = text_closing_character_pair_get(auto_close_char);
3513  if (auto_close_match != 0) {
3514  Text *text = CTX_data_edit_text(C);
3515  txt_add_char(text, auto_close_match);
3516  txt_move_left(text, false);
3517  }
3518  }
3519 
3520  /* run the script while editing, evil but useful */
3521  if (ret == OPERATOR_FINISHED && CTX_wm_space_text(C)->live_edit) {
3523  }
3524 
3525  return ret;
3526 }
3527 
3529 {
3530  PropertyRNA *prop;
3531 
3532  /* identifiers */
3533  ot->name = "Insert";
3534  ot->idname = "TEXT_OT_insert";
3535  ot->description = "Insert text at cursor position";
3536 
3537  /* api callbacks */
3540  ot->poll = text_edit_poll;
3541 
3542  /* flags */
3543  ot->flag = OPTYPE_UNDO;
3544 
3545  /* properties */
3546  prop = RNA_def_string(
3547  ot->srna, "text", NULL, 0, "Text", "Text to insert at the cursor position");
3549 }
3550 
3553 /* -------------------------------------------------------------------- */
3557 /* mode */
3558 #define TEXT_FIND 0
3559 #define TEXT_REPLACE 1
3560 
3561 static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
3562 {
3563  Main *bmain = CTX_data_main(C);
3565  Text *text = st->text;
3566  int flags;
3567  int found = 0;
3568  char *tmp;
3569 
3570  if (!st->findstr[0]) {
3571  return OPERATOR_CANCELLED;
3572  }
3573 
3574  flags = st->flags;
3575  if (flags & ST_FIND_ALL) {
3576  flags &= ~ST_FIND_WRAP;
3577  }
3578 
3579  /* Replace current */
3580  if (mode != TEXT_FIND && txt_has_sel(text)) {
3581  tmp = txt_sel_to_buf(text, NULL);
3582 
3583  if (flags & ST_MATCH_CASE) {
3584  found = STREQ(st->findstr, tmp);
3585  }
3586  else {
3587  found = BLI_strcasecmp(st->findstr, tmp) == 0;
3588  }
3589 
3590  if (found) {
3591  if (mode == TEXT_REPLACE) {
3593  txt_insert_buf(text, st->replacestr, strlen(st->replacestr));
3594  if (text->curl && text->curl->format) {
3595  MEM_freeN(text->curl->format);
3596  text->curl->format = NULL;
3597  }
3601  }
3602  }
3603  MEM_freeN(tmp);
3604  tmp = NULL;
3605  }
3606 
3607  /* Find next */
3608  if (txt_find_string(text, st->findstr, flags & ST_FIND_WRAP, flags & ST_MATCH_CASE)) {
3611  }
3612  else if (flags & ST_FIND_ALL) {
3613  if (text->id.next) {
3614  text = st->text = text->id.next;
3615  }
3616  else {
3617  text = st->text = bmain->texts.first;
3618  }
3619  txt_move_toline(text, 0, 0);
3622  }
3623  else {
3624  if (!found) {
3625  BKE_reportf(op->reports, RPT_WARNING, "Text not found: %s", st->findstr);
3626  }
3627  }
3628 
3629  return OPERATOR_FINISHED;
3630 }
3631 
3633 {
3634  return text_find_and_replace(C, op, TEXT_FIND);
3635 }
3636 
3638 {
3639  /* identifiers */
3640  ot->name = "Find Next";
3641  ot->idname = "TEXT_OT_find";
3642  ot->description = "Find specified text";
3643 
3644  /* api callbacks */
3645  ot->exec = text_find_exec;
3647 }
3648 
3651 /* -------------------------------------------------------------------- */
3656 {
3658  Text *text = st->text;
3659  const int flags = st->flags;
3660  int found = 0;
3661 
3662  if (!st->findstr[0]) {
3663  return OPERATOR_CANCELLED;
3664  }
3665 
3666  const int orig_curl = BLI_findindex(&text->lines, text->curl);
3667  const int orig_curc = text->curc;
3668  bool has_sel = txt_has_sel(text);
3669 
3670  txt_move_toline(text, 0, false);
3671 
3672  found = txt_find_string(text, st->findstr, 0, flags & ST_MATCH_CASE);
3673  if (found) {
3675 
3676  do {
3677  txt_insert_buf(text, st->replacestr, strlen(st->replacestr));
3678  if (text->curl && text->curl->format) {
3679  MEM_freeN(text->curl->format);
3680  text->curl->format = NULL;
3681  }
3682  found = txt_find_string(text, st->findstr, 0, flags & ST_MATCH_CASE);
3683  } while (found);
3684 
3687  }
3688  else {
3689  /* Restore position */
3690  txt_move_to(text, orig_curl, orig_curc, has_sel);
3691  return OPERATOR_CANCELLED;
3692  }
3693 
3694  return OPERATOR_FINISHED;
3695 }
3696 
3698 {
3699  bool replace_all = RNA_boolean_get(op->ptr, "all");
3700  if (replace_all) {
3701  return text_replace_all(C);
3702  }
3703  return text_find_and_replace(C, op, TEXT_REPLACE);
3704 }
3705 
3707 {
3708  /* identifiers */
3709  ot->name = "Replace";
3710  ot->idname = "TEXT_OT_replace";
3711  ot->description = "Replace text with the specified text";
3712 
3713  /* api callbacks */
3716 
3717  /* flags */
3718  ot->flag = OPTYPE_UNDO;
3719 
3720  /* properties */
3721  PropertyRNA *prop;
3722  prop = RNA_def_boolean(ot->srna, "all", false, "Replace All", "Replace all occurrences");
3724 }
3725 
3728 /* -------------------------------------------------------------------- */
3733 {
3735  Text *text = CTX_data_edit_text(C);
3736  char *tmp;
3737 
3738  tmp = txt_sel_to_buf(text, NULL);
3739  BLI_strncpy(st->findstr, tmp, ST_MAX_FIND_STR);
3740  MEM_freeN(tmp);
3741 
3742  if (!st->findstr[0]) {
3743  return OPERATOR_FINISHED;
3744  }
3745 
3746  return text_find_and_replace(C, op, TEXT_FIND);
3747 }
3748 
3750 {
3751  /* identifiers */
3752  ot->name = "Find & Set Selection";
3753  ot->idname = "TEXT_OT_find_set_selected";
3754  ot->description = "Find specified text and set as selected";
3755 
3756  /* api callbacks */
3759 }
3760 
3763 /* -------------------------------------------------------------------- */
3768 {
3770  Text *text = CTX_data_edit_text(C);
3771  char *tmp;
3772 
3773  tmp = txt_sel_to_buf(text, NULL);
3774  BLI_strncpy(st->replacestr, tmp, ST_MAX_FIND_STR);
3775  MEM_freeN(tmp);
3776 
3777  return OPERATOR_FINISHED;
3778 }
3779 
3781 {
3782  /* identifiers */
3783  ot->name = "Replace & Set Selection";
3784  ot->idname = "TEXT_OT_replace_set_selected";
3785  ot->description = "Replace text with specified text and set as selected";
3786 
3787  /* api callbacks */
3790 
3791  /* flags */
3792  ot->flag = OPTYPE_UNDO;
3793 }
3794 
3797 /* -------------------------------------------------------------------- */
3803  {RESOLVE_IGNORE, "IGNORE", 0, "Ignore", ""},
3804  {RESOLVE_RELOAD, "RELOAD", 0, "Reload", ""},
3805  {RESOLVE_SAVE, "SAVE", 0, "Save", ""},
3806  {RESOLVE_MAKE_INTERNAL, "MAKE_INTERNAL", 0, "Make Internal", ""},
3807  {0, NULL, 0, NULL, NULL},
3808 };
3809 
3811 {
3812  Text *text = CTX_data_edit_text(C);
3813 
3814  if (!text_edit_poll(C)) {
3815  return false;
3816  }
3817 
3818  return ((text->filepath != NULL) && !(text->flags & TXT_ISMEM));
3819 }
3820 
3822 {
3823  Text *text = CTX_data_edit_text(C);
3824  int resolution = RNA_enum_get(op->ptr, "resolution");
3825 
3826  switch (resolution) {
3827  case RESOLVE_RELOAD:
3828  return text_reload_exec(C, op);
3829  case RESOLVE_SAVE:
3830  return text_save_exec(C, op);
3831  case RESOLVE_MAKE_INTERNAL:
3832  return text_make_internal_exec(C, op);
3833  case RESOLVE_IGNORE:
3835  return OPERATOR_FINISHED;
3836  }
3837 
3838  return OPERATOR_CANCELLED;
3839 }
3840 
3842 {
3843  Text *text = CTX_data_edit_text(C);
3844  uiPopupMenu *pup;
3845  uiLayout *layout;
3846 
3847  switch (BKE_text_file_modified_check(text)) {
3848  case 1:
3849  if (text->flags & TXT_ISDIRTY) {
3850  /* Modified locally and externally, ah. offer more possibilities. */
3851  pup = UI_popup_menu_begin(
3852  C, IFACE_("File Modified Outside and Inside Blender"), ICON_NONE);
3853  layout = UI_popup_menu_layout(pup);
3854  uiItemEnumO_ptr(layout,
3855  op->type,
3856  IFACE_("Reload from disk (ignore local changes)"),
3857  0,
3858  "resolution",
3859  RESOLVE_RELOAD);
3860  uiItemEnumO_ptr(layout,
3861  op->type,
3862  IFACE_("Save to disk (ignore outside changes)"),
3863  0,
3864  "resolution",
3865  RESOLVE_SAVE);
3866  uiItemEnumO_ptr(layout,
3867  op->type,
3868  IFACE_("Make text internal (separate copy)"),
3869  0,
3870  "resolution",
3872  UI_popup_menu_end(C, pup);
3873  }
3874  else {
3875  pup = UI_popup_menu_begin(C, IFACE_("File Modified Outside Blender"), ICON_NONE);
3876  layout = UI_popup_menu_layout(pup);
3878  layout, op->type, IFACE_("Reload from disk"), 0, "resolution", RESOLVE_RELOAD);
3879  uiItemEnumO_ptr(layout,
3880  op->type,
3881  IFACE_("Make text internal (separate copy)"),
3882  0,
3883  "resolution",
3885  uiItemEnumO_ptr(layout, op->type, IFACE_("Ignore"), 0, "resolution", RESOLVE_IGNORE);
3886  UI_popup_menu_end(C, pup);
3887  }
3888  break;
3889  case 2:
3890  pup = UI_popup_menu_begin(C, IFACE_("File Deleted Outside Blender"), ICON_NONE);
3891  layout = UI_popup_menu_layout(pup);
3893  layout, op->type, IFACE_("Make text internal"), 0, "resolution", RESOLVE_MAKE_INTERNAL);
3894  uiItemEnumO_ptr(layout, op->type, IFACE_("Recreate file"), 0, "resolution", RESOLVE_SAVE);
3895  UI_popup_menu_end(C, pup);
3896  break;
3897  }
3898 
3899  return OPERATOR_INTERFACE;
3900 }
3901 
3903 {
3904  /* identifiers */
3905  ot->name = "Resolve Conflict";
3906  ot->idname = "TEXT_OT_resolve_conflict";
3907  ot->description = "When external text is out of sync, resolve the conflict";
3908 
3909  /* api callbacks */
3913 
3914  /* properties */
3915  RNA_def_enum(ot->srna,
3916  "resolution",
3919  "Resolution",
3920  "How to solve conflict due to differences in internal and external text");
3921 }
3922 
3925 /* -------------------------------------------------------------------- */
3930 {
3931  const Text *text = CTX_data_edit_text(C);
3932  const bool split_lines = RNA_boolean_get(op->ptr, "split_lines");
3933 
3934  ED_text_to_object(C, text, split_lines);
3935 
3936  return OPERATOR_FINISHED;
3937 }
3938 
3940 {
3941  /* identifiers */
3942  ot->name = "To 3D Object";
3943  ot->idname = "TEXT_OT_to_3d_object";
3944  ot->description = "Create 3D text object from active text data-block";
3945 
3946  /* api callbacks */
3948  ot->poll = text_data_poll;
3949 
3950  /* flags */
3952 
3953  /* properties */
3955  ot->srna, "split_lines", 0, "Split Lines", "Create one object per line in the text");
3956 }
3957 
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct SpaceText * CTX_wm_space_text(const bContext *C)
Definition: context.c:806
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
struct Text * CTX_data_edit_text(const bContext *C)
Definition: context.c:1380
bool BKE_id_is_editable(const struct Main *bmain, const struct ID *id)
void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL()
const char * BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL()
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.c:83
void txt_move_down(struct Text *text, bool sel)
Definition: text.c:794
void void txt_split_curline(struct Text *text)
Definition: text.c:1649
int txt_setcurr_tab_spaces(struct Text *text, int space)
Definition: text.c:2213
bool txt_has_sel(const struct Text *text)
void txt_move_eof(struct Text *text, bool sel)
Definition: text.c:1068
void txt_delete_selected(struct Text *text)
Definition: text.c:1929
void txt_delete_char(struct Text *text)
Definition: text.c:1758
bool txt_cursor_is_line_end(const struct Text *text)
void txt_sel_line(struct Text *text)
Definition: text.c:1263
void txt_move_toline(struct Text *text, unsigned int line, bool sel)
Definition: text.c:1091
bool txt_replace_char(struct Text *text, unsigned int add)
Definition: text.c:1935
void txt_backspace_char(struct Text *text)
Definition: text.c:1806
void txt_sel_clear(struct Text *text)
Definition: text.c:1255
void txt_move_left(struct Text *text, bool sel)
Definition: text.c:865
bool txt_add_char(struct Text *text, unsigned int add)
Definition: text.c:1919
int txt_calc_tab_left(struct TextLine *tl, int ch)
Definition: text.c:824
void txt_delete_word(struct Text *text)
Definition: text.c:1799
char * txt_sel_to_buf(struct Text *text, size_t *r_buf_strlen)
Definition: text.c:1454
struct Text * BKE_text_add(struct Main *bmain, const char *name)
Definition: text.c:282
bool txt_uncomment(struct Text *text)
Definition: text.c:2149
int txt_get_span(struct TextLine *from, struct TextLine *to)
Definition: text.c:676
void int BKE_text_file_modified_check(struct Text *text)
Definition: text.c:530
void txt_move_bof(struct Text *text, bool sel)
Definition: text.c:1045
void txt_move_right(struct Text *text, bool sel)
Definition: text.c:909
int txt_find_string(struct Text *text, const char *findstr, int wrap, int match_case)
Definition: text.c:1591
@ TXT_MOVE_LINE_UP
Definition: BKE_text.h:134
@ TXT_MOVE_LINE_DOWN
Definition: BKE_text.h:135
void txt_move_lines(struct Text *text, int direction)
Definition: text.c:2182
int txt_calc_tab_right(struct TextLine *tl, int ch)
Definition: text.c:844
void txt_jump_left(struct Text *text, bool sel, bool use_init_step)
Definition: text.c:953
void txt_move_eol(struct Text *text, bool sel)
Definition: text.c:1023
void txt_backspace_word(struct Text *text)
Definition: text.c:1854
void txt_jump_right(struct Text *text, bool sel, bool use_init_step)
Definition: text.c:977
void txt_move_up(struct Text *text, bool sel)
Definition: text.c:764
void txt_comment(struct Text *text)
Definition: text.c:2137
void BKE_text_file_modified_ignore(struct Text *text)
Definition: text.c:564
void txt_move_bol(struct Text *text, bool sel)
Definition: text.c:1001
void txt_sel_all(struct Text *text)
Definition: text.c:1246
void txt_order_cursors(struct Text *text, bool reverse)
Definition: text.c:1177
bool txt_unindent(struct Text *text)
Definition: text.c:2171
void txt_indent(struct Text *text)
Definition: text.c:2160
void txt_duplicate_line(struct Text *text)
Definition: text.c:1741
struct Text * BKE_text_load_ex(struct Main *bmain, const char *filepath, const char *relbase, bool is_internal) ATTR_NONNULL(1
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.c:1096
bool txt_cursor_is_line_start(const struct Text *text)
void txt_pop_sel(struct Text *text)
Definition: text.c:1171
bool BKE_text_reload(struct Text *text)
Definition: text.c:420
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:314
bool BLI_file_is_writable(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:167
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:906
int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
struct stat BLI_stat_t
Definition: BLI_fileops.h:73
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
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])
#define FILE_MAX
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL()
Definition: path_util.c:897
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition: BLI_rect.h:173
BLI_INLINE int BLI_rcti_cent_x(const struct rcti *rct)
Definition: BLI_rect.h:169
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:623
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
int BLI_str_utf8_offset_from_column(const char *str, int column) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: string_utf8.c:791
#define BLI_UTF8_MAX
unsigned int BLI_str_utf8_as_unicode(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: string_utf8.c:478
unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p, size_t p_len, size_t *__restrict index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
int BLI_str_utf8_char_width_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: string_utf8.c:388
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
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: string_utf8.c:466
unsigned int uint
Definition: BLI_sys_types.h:67
#define CLAMPIS(a, b, c)
#define UNUSED(x)
#define ELEM(...)
#define MIN2(a, b)
#define STREQ(a, b)
#define BLT_I18NCONTEXT_ID_TEXT
#define TIP_(msgid)
#define IFACE_(msgid)
#define DATA_(msgid)
void BPY_text_free_code(struct Text *text)
void BPY_pyconstraint_update(struct Object *owner, struct bConstraint *con)
bool bool BPY_run_text(struct bContext *C, struct Text *text, struct ReportList *reports, bool do_jump) ATTR_NONNULL(1
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ CONSTRAINT_TYPE_PYTHON
@ OB_ARMATURE
@ 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 ST_MAX_FIND_STR
#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.c:729
struct UndoStep * ED_text_undo_push_init(struct bContext *C)
Definition: text_undo.c:263
void ED_text_scroll_to_cursor(struct SpaceText *st, struct ARegion *region, bool center)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble top
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Platform independent time functions.
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
struct uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop)
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup)
void uiItemEnumO_ptr(uiLayout *layout, struct wmOperatorType *ot, const char *name, int icon, const char *propname, int value)
uiPopupMenu * UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL()
@ WM_FILESEL_FILEPATH
Definition: WM_api.h:755
@ FILE_OPENFILE
Definition: WM_api.h:764
@ FILE_SAVE
Definition: WM_api.h:765
@ KM_RELEASE
Definition: WM_types.h:268
@ OPTYPE_INTERNAL
Definition: WM_types.h:168
@ OPTYPE_BLOCKING
Definition: WM_types.h:150
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_GRAB_CURSOR_XY
Definition: WM_types.h:154
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_WINDOW
Definition: WM_types.h:325
#define ND_CURSOR
Definition: WM_types.h:438
#define NA_ADDED
Definition: WM_types.h:525
#define NA_EDITED
Definition: WM_types.h:523
#define NC_TEXT
Definition: WM_types.h:336
#define NA_REMOVED
Definition: WM_types.h:526
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:201
@ WM_OP_EXEC_DEFAULT
Definition: WM_types.h:208
@ KM_CTRL
Definition: WM_types.h:239
@ KM_OSKEY
Definition: WM_types.h:242
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
#define NEXT_CHAR(fmt)
unsigned int U
Definition: btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
@ NEXT_LINE
Definition: curve_intern.h:38
@ LINE_BEGIN
Definition: curve_intern.h:31
@ PREV_WORD
Definition: curve_intern.h:35
@ PREV_LINE
Definition: curve_intern.h:37
@ PREV_CHAR
Definition: curve_intern.h:33
@ LINE_END
Definition: curve_intern.h:32
@ PREV_PAGE
Definition: curve_intern.h:39
@ NEXT_PAGE
Definition: curve_intern.h:40
@ NEXT_WORD
Definition: curve_intern.h:36
@ DEL_PREV_WORD
Definition: curve_intern.h:24
@ DEL_PREV_CHAR
Definition: curve_intern.h:22
@ DEL_NEXT_WORD
Definition: curve_intern.h:23
@ DEL_NEXT_CHAR
Definition: curve_intern.h:21
double time
SyclQueue void void size_t num_bytes void
int len
Definition: draw_manager.c:108
void ED_text_to_object(bContext *C, const Text *text, const bool split_lines)
Definition: editfont.c:688
#define str(s)
uint col
ccl_global float * buffer
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static ulong * next
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
SymEdge< T > * prev(const SymEdge< T > *se)
Definition: delaunay_2d.cc:105
static std::string replace_all(const StringRefNull str, const StringRefNull from, const StringRefNull to)
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
static void update(bNodeTree *ntree)
return ret
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
Definition: rna_access.c:5155
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:112
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
Definition: rna_access.c:3532
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:4921
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2138
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:5116
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
int RNA_string_length(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5144
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
Definition: rna_access.c:5129
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:5301
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, int maxlen, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3687
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
Definition: rna_define.c:2848
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3597
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
short regiontype
void * prev
Definition: DNA_ID.h:369
void * next
Definition: DNA_ID.h:369
char name[66]
Definition: DNA_ID.h:378
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
ListBase texts
Definition: BKE_main.h:185
ListBase objects
Definition: BKE_main.h:170
ListBase constraints
struct bPose * pose
struct PropertyRNA * prop
Definition: RNA_types.h:43
PointerRNA ptr
Definition: RNA_types.h:42
wmTimer * timer
Definition: text_ops.c:2930
short mval_prev[2]
Definition: text_ops.c:2929
char * format
char * line
struct TextLine * prev
struct TextLine * next
bool is_first
Definition: text_ops.c:2557
int mval_delta[2]
Definition: text_ops.c:2555
bool is_scrollbar
Definition: text_ops.c:2558
int ofs_init[2]
Definition: text_ops.c:2564
enum eScrollZone zone
Definition: text_ops.c:2560
int mval_prev[2]
Definition: text_ops.c:2554
int size_px[2]
Definition: text_ops.c:2566
int ofs_max[2]
Definition: text_ops.c:2565
struct TextScroll::@557 state
int ofs_delta[2]
Definition: text_ops.c:2568
int ofs_delta_px[2]
Definition: text_ops.c:2569
int flags
ListBase lines
TextLine * curl
int selc
double mtime
TextLine * sell
int curc
void * compiled
char * filepath
struct bConstraint * next
ListBase constraints
struct bPoseChannel * next
ListBase chanbase
int ymin
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
short val
Definition: WM_types.h:680
int xy[2]
Definition: WM_types.h:682
char utf8_buf[6]
Definition: WM_types.h:690
int mval[2]
Definition: WM_types.h:684
int prev_xy[2]
Definition: WM_types.h:728
uint8_t modifier
Definition: WM_types.h:693
short type
Definition: WM_types.h:678
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
int flatten_string(const SpaceText *st, FlattenString *fs, const char *in)
Definition: text_format.c:56
void flatten_string_free(FlattenString *fs)
Definition: text_format.c:89
#define TXT_SCROLL_SPACE
Definition: text_intern.h:46
#define TXT_LINE_HEIGHT(st)
Definition: text_intern.h:53
int text_get_total_lines(struct SpaceText *st, struct ARegion *region)
#define TXT_NUMCOL_WIDTH(st)
Definition: text_intern.h:36
void text_update_cursor_moved(struct bContext *C)
void wrap_offset_in_line(const struct SpaceText *st, struct ARegion *region, struct TextLine *linein, int cursin, int *offl, int *offc)
@ FILE_TOP
Definition: text_intern.h:102
@ FILE_BOTTOM
Definition: text_intern.h:103
int wrap_width(const struct SpaceText *st, struct ARegion *region)
#define TXT_BODY_LEFT(st)
Definition: text_intern.h:42
int text_get_visible_lines(const struct SpaceText *st, struct ARegion *region, const char *str)
#define TXT_BODY_LPAD
Definition: text_intern.h:40
void text_drawcache_tag_update(struct SpaceText *st, int full)
int text_get_char_pos(const struct SpaceText *st, const char *line, int cur)
void text_update_character_width(struct SpaceText *st)
static int text_scroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: text_ops.c:2753
static int text_replace_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:3697
void TEXT_OT_replace_set_selected(wmOperatorType *ot)
Definition: text_ops.c:3780
static bool text_edit_poll(bContext *C)
Definition: text_ops.c:182
static int text_replace_all(bContext *C)
Definition: text_ops.c:3655
static int text_convert_whitespace_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:1346
static int text_line_break_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:1215
static bool text_data_poll(bContext *C)
Definition: text_ops.c:173
static int text_to_3d_object_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:3929
struct SetSelection SetSelection
void TEXT_OT_unlink(wmOperatorType *ot)
Definition: text_ops.c:530
static int text_unindent_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:1175
static int text_insert_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:3439
static int text_select_word_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:1554
void TEXT_OT_overwrite_toggle(wmOperatorType *ot)
Definition: text_ops.c:2505
void TEXT_OT_reload(wmOperatorType *ot)
Definition: text_ops.c:479
static void txt_screen_clamp(SpaceText *st, ARegion *region)
Definition: text_ops.c:2523
void TEXT_OT_open(wmOperatorType *ot)
Definition: text_ops.c:400
static int text_save_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: text_ops.c:654
void text_update_edited(Text *text)
Definition: text_ops.c:253
static int text_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: text_ops.c:711
static int text_cut_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:1052
static void text_open_init(bContext *C, wmOperator *op)
Definition: text_ops.c:321
static int text_jump_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: text_ops.c:2336
static int text_resolve_conflict_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:3821
static char * buf_tabs_to_spaces(const char *in_buf, const int tab_size, int *r_out_buf_len)
Definition: text_ops.c:102
void TEXT_OT_replace(wmOperatorType *ot)
Definition: text_ops.c:3706
static int text_copy_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:1025
static const EnumPropertyItem resolution_items[]
Definition: text_ops.c:3802
eScrollZone
Definition: text_ops.c:2546
@ SCROLLHANDLE_BAR
Definition: text_ops.c:2548
@ SCROLLHANDLE_MIN_OUTSIDE
Definition: text_ops.c:2549
@ SCROLLHANDLE_MAX_OUTSIDE
Definition: text_ops.c:2550
@ SCROLLHANDLE_INVALID_OUTSIDE
Definition: text_ops.c:2547
void TEXT_OT_run_script(wmOperatorType *ot)
Definition: text_ops.c:816
static int text_run_script(bContext *C, ReportList *reports)
Definition: text_ops.c:765
static int cursor_skip_find_line(SpaceText *st, ARegion *region, int lines, TextLine **linep, int *charp, int *rell, int *relc)
Definition: text_ops.c:1747
static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event)
Definition: text_ops.c:2610
static void text_scroll_state_init(TextScroll *tsc, SpaceText *st, ARegion *region)
Definition: text_ops.c:2572
static int text_select_all_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:1494
static int text_refresh_pyconstraints_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
Definition: text_ops.c:837
void TEXT_OT_copy(wmOperatorType *ot)
Definition: text_ops.c:1034
static int text_toggle_overwrite_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:2494
static int text_find_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:3632
static int text_selection_set_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition: text_ops.c:3283
void TEXT_OT_select_line(wmOperatorType *ot)
Definition: text_ops.c:1536
static void text_selection_set_cancel(bContext *C, wmOperator *op)
Definition: text_ops.c:3300
static void text_open_cancel(bContext *UNUSED(C), wmOperator *op)
Definition: text_ops.c:329
#define TEXT_FIND
Definition: text_ops.c:3558
static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
Definition: text_ops.c:3561
void TEXT_OT_new(wmOperatorType *ot)
Definition: text_ops.c:300
void TEXT_OT_indent_or_autocomplete(wmOperatorType *ot)
Definition: text_ops.c:1109
void TEXT_OT_scroll(wmOperatorType *ot)
Definition: text_ops.c:2793
static int text_cursor_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: text_ops.c:3340
void TEXT_OT_line_break(wmOperatorType *ot)
Definition: text_ops.c:1251
static int text_selection_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: text_ops.c:3258
static int text_delete_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:2374
static bool text_region_edit_poll(bContext *C)
Definition: text_ops.c:215
void TEXT_OT_save_as(wmOperatorType *ot)
Definition: text_ops.c:737
@ TO_SPACES
Definition: text_ops.c:1339
@ TO_TABS
Definition: text_ops.c:1339
static bool text_region_scroll_poll(bContext *C)
Definition: text_ops.c:2822
static int text_open_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:334
static int move_lines_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:1587
static void text_cursor_set_exit(bContext *C, wmOperator *op)
Definition: text_ops.c:3238
void TEXT_OT_paste(wmOperatorType *ot)
Definition: text_ops.c:942
static int text_save_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:641
void TEXT_OT_make_internal(wmOperatorType *ot)
Definition: text_ops.c:566
void TEXT_OT_to_3d_object(wmOperatorType *ot)
Definition: text_ops.c:3939
void TEXT_OT_indent(wmOperatorType *ot)
Definition: text_ops.c:1154
bool text_space_edit_poll(bContext *C)
Definition: text_ops.c:198
void TEXT_OT_select_all(wmOperatorType *ot)
Definition: text_ops.c:1506
static void txt_wrap_move_eol(SpaceText *st, ARegion *region, const bool sel)
Definition: text_ops.c:1920
void TEXT_OT_select_word(wmOperatorType *ot)
Definition: text_ops.c:1569
void TEXT_OT_save(wmOperatorType *ot)
Definition: text_ops.c:666
static int text_get_cursor_rel(SpaceText *st, ARegion *region, TextLine *linein, int rell, int relc)
Definition: text_ops.c:1654
static int text_scroll_bar_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: text_ops.c:2840
void TEXT_OT_move_lines(wmOperatorType *ot)
Definition: text_ops.c:1607
static int text_scroll_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:2592
void TEXT_OT_cursor_set(wmOperatorType *ot)
Definition: text_ops.c:3354
static int text_move_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:2253
static int text_cursor_set_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:3325
static int text_comment_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:1272
static int text_jump_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:2314
static const EnumPropertyItem delete_type_items[]
Definition: text_ops.c:2366
void TEXT_OT_scroll_bar(wmOperatorType *ot)
Definition: text_ops.c:2899
void TEXT_OT_find(wmOperatorType *ot)
Definition: text_ops.c:3637
static int text_move_cursor(bContext *C, int type, bool select)
Definition: text_ops.c:2132
void TEXT_OT_duplicate_line(wmOperatorType *ot)
Definition: text_ops.c:988
void TEXT_OT_move_select(wmOperatorType *ot)
Definition: text_ops.c:2288
static int flatten_width(SpaceText *st, const char *str)
Definition: text_ops.c:2933
static int text_reload_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:434
static int text_run_script_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:803
static bool text_new_poll(bContext *UNUSED(C))
Definition: text_ops.c:168
BLI_INLINE int text_pixel_x_to_column(SpaceText *st, const int x)
Definition: text_ops.c:156
static void text_cursor_timer_ensure(bContext *C, SetSelection *ssel)
Definition: text_ops.c:3178
static int text_line_number_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
Definition: text_ops.c:3377
static int text_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: text_ops.c:383
void TEXT_OT_jump(wmOperatorType *ot)
Definition: text_ops.c:2341
static int text_scroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition: text_ops.c:2716
static void text_cursor_timer_remove(bContext *C, SetSelection *ssel)
Definition: text_ops.c:3188
static int text_move_select_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:2281
void TEXT_OT_delete(wmOperatorType *ot)
Definition: text_ops.c:2463
void TEXT_OT_selection_set(wmOperatorType *ot)
Definition: text_ops.c:3305
static bool text_scroll_poll(bContext *C)
Definition: text_ops.c:2585
static int flatten_column_to_offset(SpaceText *st, const char *str, int index)
Definition: text_ops.c:2949
void TEXT_OT_find_set_selected(wmOperatorType *ot)
Definition: text_ops.c:3749
static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: text_ops.c:3482
static int text_replace_set_selected_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:3767
static int text_duplicate_line_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:970
static void txt_wrap_move_bol(SpaceText *st, ARegion *region, const bool sel)
Definition: text_ops.c:1836
void TEXT_OT_unindent(wmOperatorType *ot)
Definition: text_ops.c:1194
static void txt_screen_skip(SpaceText *st, ARegion *region, int lines)
Definition: text_ops.c:2539
static int text_resolve_conflict_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: text_ops.c:3841
void TEXT_OT_insert(wmOperatorType *ot)
Definition: text_ops.c:3528
static int text_new_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:268
static const EnumPropertyItem whitespace_type_items[]
Definition: text_ops.c:1340
void TEXT_OT_comment_toggle(wmOperatorType *ot)
Definition: text_ops.c:1307
static char text_closing_character_pair_get(const char character)
Definition: text_ops.c:77
#define TEXT_REPLACE
Definition: text_ops.c:3559
static bool text_unlink_poll(bContext *C)
Definition: text_ops.c:498
static int text_find_set_selected_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:3732
void TEXT_OT_resolve_conflict(wmOperatorType *ot)
Definition: text_ops.c:3902
static int text_make_internal_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:552
void TEXT_OT_move(wmOperatorType *ot)
Definition: text_ops.c:2260
static int text_indent_or_autocomplete_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:1095
void TEXT_OT_line_number(wmOperatorType *ot)
Definition: text_ops.c:3421
void text_update_line_edited(TextLine *line)
Definition: text_ops.c:243
static void test_line_start(char c, bool *r_last_state)
Definition: text_ops.c:62
static int text_save_as_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:685
static bool text_resolve_conflict_poll(bContext *C)
Definition: text_ops.c:3810
void TEXT_OT_convert_whitespace(wmOperatorType *ot)
Definition: text_ops.c:1465
static TextLine * get_line_pos_wrapped(SpaceText *st, ARegion *region, int *y)
Definition: text_ops.c:2972
static void txt_wrap_move_down(SpaceText *st, ARegion *region, const bool sel)
Definition: text_ops.c:2045
void TEXT_OT_cut(wmOperatorType *ot)
Definition: text_ops.c:1074
static int text_select_line_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:1524
void TEXT_OT_refresh_pyconstraints(wmOperatorType *ot)
Definition: text_ops.c:884
static void cursor_skip(SpaceText *st, ARegion *region, Text *text, int lines, const bool sel)
Definition: text_ops.c:2090
static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *region, int x, int y, const bool sel)
Definition: text_ops.c:2994
static void txt_wrap_move_up(SpaceText *st, ARegion *region, const bool sel)
Definition: text_ops.c:2004
static void text_cursor_set_apply(bContext *C, wmOperator *op, const wmEvent *event)
Definition: text_ops.c:3199
static int text_unlink_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:504
static void txt_copy_clipboard(Text *text)
Definition: text_ops.c:1009
static int text_paste_exec(bContext *C, wmOperator *op)
Definition: text_ops.c:902
static void text_scroll_cancel(bContext *C, wmOperator *op)
Definition: text_ops.c:2748
static void scroll_exit(bContext *C, wmOperator *op)
Definition: text_ops.c:2698
struct TextScroll TextScroll
@ RESOLVE_SAVE
Definition: text_ops.c:3801
@ RESOLVE_MAKE_INTERNAL
Definition: text_ops.c:3801
@ RESOLVE_RELOAD
Definition: text_ops.c:3801
@ RESOLVE_IGNORE
Definition: text_ops.c:3801
static void text_cursor_set_to_pos(SpaceText *st, ARegion *region, int x, int y, const bool sel)
Definition: text_ops.c:3119
static int text_indent_exec(bContext *C, wmOperator *UNUSED(op))
Definition: text_ops.c:1130
static const EnumPropertyItem move_type_items[]
Definition: text_ops.c:1637
static void txt_write_file(Main *bmain, Text *text, ReportList *reports)
Definition: text_ops.c:587
double PIL_check_seconds_timer(void)
Definition: time.c:64
float max
char WM_event_utf8_to_ascii(const struct wmEvent *event)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_fileselect(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
@ MOUSEPAN
@ RIGHTMOUSE
@ TIMER
@ MOUSEMOVE
@ LEFTMOUSE
@ MIDDLEMOUSE
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
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)
int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width)
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
Definition: wm_window.c:1682
void WM_clipboard_text_set(const char *buf, bool selection)
Definition: wm_window.c:1780
char * WM_clipboard_text_get(bool selection, int *r_len)
Definition: wm_window.c:1770
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1630