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