Blender  V2.93
text.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 <stdlib.h> /* abort */
25 #include <string.h> /* strstr */
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <wctype.h>
29 
30 #include "MEM_guardedalloc.h"
31 
32 #include "BLI_fileops.h"
33 #include "BLI_listbase.h"
34 #include "BLI_path_util.h"
35 #include "BLI_string.h"
36 #include "BLI_string_cursor_utf8.h"
37 #include "BLI_string_utf8.h"
38 #include "BLI_utildefines.h"
39 
40 #include "BLT_translation.h"
41 
42 #include "DNA_constraint_types.h"
43 #include "DNA_material_types.h"
44 #include "DNA_node_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_scene_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_space_types.h"
49 #include "DNA_text_types.h"
50 #include "DNA_userdef_types.h"
51 
52 #include "BKE_idtype.h"
53 #include "BKE_lib_id.h"
54 #include "BKE_main.h"
55 #include "BKE_node.h"
56 #include "BKE_text.h"
57 
58 #include "BLO_read_write.h"
59 
60 #ifdef WITH_PYTHON
61 # include "BPY_extern.h"
62 #endif
63 
64 /* -------------------------------------------------------------------- */
68 static void txt_pop_first(Text *text);
69 static void txt_pop_last(Text *text);
70 static void txt_delete_line(Text *text, TextLine *line);
71 static void txt_delete_sel(Text *text);
72 static void txt_make_dirty(Text *text);
73 
76 /* -------------------------------------------------------------------- */
80 static void text_init_data(ID *id)
81 {
82  Text *text = (Text *)id;
83  TextLine *tmp;
84 
86 
87  text->filepath = NULL;
88 
89  text->flags = TXT_ISDIRTY | TXT_ISMEM;
90  if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0) {
91  text->flags |= TXT_TABSTOSPACES;
92  }
93 
94  BLI_listbase_clear(&text->lines);
95 
96  tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline");
97  tmp->line = (char *)MEM_mallocN(1, "textline_string");
98  tmp->format = NULL;
99 
100  tmp->line[0] = 0;
101  tmp->len = 0;
102 
103  tmp->next = NULL;
104  tmp->prev = NULL;
105 
106  BLI_addhead(&text->lines, tmp);
107 
108  text->curl = text->lines.first;
109  text->curc = 0;
110  text->sell = text->lines.first;
111  text->selc = 0;
112 }
113 
124 static void text_copy_data(Main *UNUSED(bmain),
125  ID *id_dst,
126  const ID *id_src,
127  const int UNUSED(flag))
128 {
129  Text *text_dst = (Text *)id_dst;
130  const Text *text_src = (Text *)id_src;
131 
132  /* File name can be NULL. */
133  if (text_src->filepath) {
134  text_dst->filepath = BLI_strdup(text_src->filepath);
135  }
136 
137  text_dst->flags |= TXT_ISDIRTY;
138 
139  BLI_listbase_clear(&text_dst->lines);
140  text_dst->curl = text_dst->sell = NULL;
141  text_dst->compiled = NULL;
142 
143  /* Walk down, reconstructing. */
144  LISTBASE_FOREACH (TextLine *, line_src, &text_src->lines) {
145  TextLine *line_dst = MEM_mallocN(sizeof(*line_dst), __func__);
146 
147  line_dst->line = BLI_strdup(line_src->line);
148  line_dst->format = NULL;
149  line_dst->len = line_src->len;
150 
151  BLI_addtail(&text_dst->lines, line_dst);
152  }
153 
154  text_dst->curl = text_dst->sell = text_dst->lines.first;
155  text_dst->curc = text_dst->selc = 0;
156 }
157 
159 static void text_free_data(ID *id)
160 {
161  /* No animdata here. */
162  Text *text = (Text *)id;
163 
164  BKE_text_free_lines(text);
165 
166  MEM_SAFE_FREE(text->filepath);
167 #ifdef WITH_PYTHON
168  BPY_text_free_code(text);
169 #endif
170 }
171 
172 static void text_blend_write(BlendWriter *writer, ID *id, const void *id_address)
173 {
174  if (id->us < 1 && !BLO_write_is_undo(writer)) {
175  return;
176  }
177  Text *text = (Text *)id;
178 
179  /* Note: we are clearing local temp data here, *not* the flag in the actual 'real' ID. */
180  if ((text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) {
181  text->flags &= ~TXT_ISEXT;
182  }
183 
184  /* Clean up, important in undo case to reduce false detection of changed datablocks. */
185  text->compiled = NULL;
186 
187  /* write LibData */
188  BLO_write_id_struct(writer, Text, id_address, &text->id);
189  BKE_id_blend_write(writer, &text->id);
190 
191  if (text->filepath) {
192  BLO_write_string(writer, text->filepath);
193  }
194 
195  if (!(text->flags & TXT_ISEXT)) {
196  /* now write the text data, in two steps for optimization in the readfunction */
197  LISTBASE_FOREACH (TextLine *, tmp, &text->lines) {
198  BLO_write_struct(writer, TextLine, tmp);
199  }
200 
201  LISTBASE_FOREACH (TextLine *, tmp, &text->lines) {
202  BLO_write_raw(writer, tmp->len + 1, tmp->line);
203  }
204  }
205 }
206 
207 static void text_blend_read_data(BlendDataReader *reader, ID *id)
208 {
209  Text *text = (Text *)id;
210  BLO_read_data_address(reader, &text->filepath);
211 
212  text->compiled = NULL;
213 
214 #if 0
215  if (text->flags & TXT_ISEXT) {
216  BKE_text_reload(text);
217  }
218  /* else { */
219 #endif
220 
221  BLO_read_list(reader, &text->lines);
222 
223  BLO_read_data_address(reader, &text->curl);
224  BLO_read_data_address(reader, &text->sell);
225 
226  LISTBASE_FOREACH (TextLine *, ln, &text->lines) {
227  BLO_read_data_address(reader, &ln->line);
228  ln->format = NULL;
229 
230  if (ln->len != (int)strlen(ln->line)) {
231  printf("Error loading text, line lengths differ\n");
232  ln->len = strlen(ln->line);
233  }
234  }
235 
236  text->flags = (text->flags) & ~TXT_ISEXT;
237 }
238 
240  .id_code = ID_TXT,
241  .id_filter = FILTER_ID_TXT,
242  .main_listbase_index = INDEX_ID_TXT,
243  .struct_size = sizeof(Text),
244  .name = "Text",
245  .name_plural = "texts",
246  .translation_context = BLT_I18NCONTEXT_ID_TEXT,
247  .flags = IDTYPE_FLAGS_NO_ANIMDATA,
248 
250  .copy_data = text_copy_data,
251  .free_data = text_free_data,
252  .make_local = NULL,
253  .foreach_id = NULL,
254  .foreach_cache = NULL,
255  .owner_get = NULL,
256 
257  .blend_write = text_blend_write,
258  .blend_read_data = text_blend_read_data,
259  .blend_read_lib = NULL,
260  .blend_read_expand = NULL,
261 
262  .blend_read_undo_preserve = NULL,
263 
264  .lib_override_apply_post = NULL,
265 };
266 
269 /* -------------------------------------------------------------------- */
277 {
278  for (TextLine *tmp = text->lines.first, *tmp_next; tmp; tmp = tmp_next) {
279  tmp_next = tmp->next;
280  MEM_freeN(tmp->line);
281  if (tmp->format) {
282  MEM_freeN(tmp->format);
283  }
284  MEM_freeN(tmp);
285  }
286 
287  BLI_listbase_clear(&text->lines);
288 
289  text->curl = text->sell = NULL;
290 }
291 
292 Text *BKE_text_add(Main *bmain, const char *name)
293 {
294  Text *ta;
295 
296  ta = BKE_id_new(bmain, ID_TXT, name);
297  /* Texts have no users by default... Set the fake user flag to ensure that this text block
298  * doesn't get deleted by default when cleaning up data blocks. */
299  id_us_min(&ta->id);
300  id_fake_user_set(&ta->id);
301 
302  return ta;
303 }
304 
305 /* this function replaces extended ascii characters */
306 /* to a valid utf-8 sequences */
308 {
309  ptrdiff_t bad_char, i = 0;
310  const ptrdiff_t length = (ptrdiff_t)strlen(*str);
311  int added = 0;
312 
313  while ((*str)[i]) {
314  if ((bad_char = BLI_utf8_invalid_byte(*str + i, length - i)) == -1) {
315  break;
316  }
317 
318  added++;
319  i += bad_char + 1;
320  }
321 
322  if (added != 0) {
323  char *newstr = MEM_mallocN(length + added + 1, "text_line");
324  ptrdiff_t mi = 0;
325  i = 0;
326 
327  while ((*str)[i]) {
328  if ((bad_char = BLI_utf8_invalid_byte((*str) + i, length - i)) == -1) {
329  memcpy(newstr + mi, (*str) + i, length - i + 1);
330  break;
331  }
332 
333  memcpy(newstr + mi, (*str) + i, bad_char);
334 
335  BLI_str_utf8_from_unicode((*str)[i + bad_char], newstr + mi + bad_char);
336  i += bad_char + 1;
337  mi += bad_char + 2;
338  }
339  newstr[length + added] = '\0';
340  MEM_freeN(*str);
341  *str = newstr;
342  }
343 
344  return added;
345 }
346 
347 // this function removes any control characters from
348 // a textline and fixes invalid utf-8 sequences
349 
350 static void cleanup_textline(TextLine *tl)
351 {
352  int i;
353 
354  for (i = 0; i < tl->len; i++) {
355  if (tl->line[i] < ' ' && tl->line[i] != '\t') {
356  memmove(tl->line + i, tl->line + i + 1, tl->len - i);
357  tl->len--;
358  i--;
359  }
360  }
361  tl->len += txt_extended_ascii_as_utf8(&tl->line);
362 }
363 
368 static void text_from_buf(Text *text, const unsigned char *buffer, const int len)
369 {
370  int i, llen, lines_count;
371 
373 
374  llen = 0;
375  lines_count = 0;
376  for (i = 0; i < len; i++) {
377  if (buffer[i] == '\n') {
378  TextLine *tmp;
379 
380  tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline");
381  tmp->line = (char *)MEM_mallocN(llen + 1, "textline_string");
382  tmp->format = NULL;
383 
384  if (llen) {
385  memcpy(tmp->line, &buffer[i - llen], llen);
386  }
387  tmp->line[llen] = 0;
388  tmp->len = llen;
389 
390  cleanup_textline(tmp);
391 
392  BLI_addtail(&text->lines, tmp);
393  lines_count += 1;
394 
395  llen = 0;
396  continue;
397  }
398  llen++;
399  }
400 
401  /* create new line in cases:
402  * - rest of line (if last line in file hasn't got \n terminator).
403  * in this case content of such line would be used to fill text line buffer
404  * - file is empty. in this case new line is needed to start editing from.
405  * - last character in buffer is \n. in this case new line is needed to
406  * deal with newline at end of file. (see T28087) (sergey) */
407  if (llen != 0 || lines_count == 0 || buffer[len - 1] == '\n') {
408  TextLine *tmp;
409 
410  tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline");
411  tmp->line = (char *)MEM_mallocN(llen + 1, "textline_string");
412  tmp->format = NULL;
413 
414  if (llen) {
415  memcpy(tmp->line, &buffer[i - llen], llen);
416  }
417 
418  tmp->line[llen] = 0;
419  tmp->len = llen;
420 
421  cleanup_textline(tmp);
422 
423  BLI_addtail(&text->lines, tmp);
424  /* lines_count += 1; */ /* UNUSED */
425  }
426 
427  text->curl = text->sell = text->lines.first;
428  text->curc = text->selc = 0;
429 }
430 
432 {
433  unsigned char *buffer;
434  size_t buffer_len;
435  char filepath_abs[FILE_MAX];
436  BLI_stat_t st;
437 
438  if (!text->filepath) {
439  return false;
440  }
441 
442  BLI_strncpy(filepath_abs, text->filepath, FILE_MAX);
443  BLI_path_abs(filepath_abs, ID_BLEND_PATH_FROM_GLOBAL(&text->id));
444 
445  buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
446  if (buffer == NULL) {
447  return false;
448  }
449 
450  /* free memory: */
451  BKE_text_free_lines(text);
452  txt_make_dirty(text);
453 
454  /* clear undo buffer */
455  if (BLI_stat(filepath_abs, &st) != -1) {
456  text->mtime = st.st_mtime;
457  }
458  else {
459  text->mtime = 0;
460  }
461 
462  text_from_buf(text, buffer, buffer_len);
463 
464  MEM_freeN(buffer);
465  return true;
466 }
467 
476 Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
477 {
478  unsigned char *buffer;
479  size_t buffer_len;
480  Text *ta;
481  char filepath_abs[FILE_MAX];
482  BLI_stat_t st;
483 
484  BLI_strncpy(filepath_abs, file, FILE_MAX);
485  if (relpath) { /* can be NULL (bg mode) */
486  BLI_path_abs(filepath_abs, relpath);
487  }
488 
489  buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
490  if (buffer == NULL) {
491  return NULL;
492  }
493 
494  ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs), 0);
495  id_us_min(&ta->id);
496  id_fake_user_set(&ta->id);
497 
499  ta->curl = ta->sell = NULL;
500 
501  if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0) {
502  ta->flags = TXT_TABSTOSPACES;
503  }
504 
505  if (is_internal == false) {
506  ta->filepath = MEM_mallocN(strlen(file) + 1, "text_name");
507  strcpy(ta->filepath, file);
508  }
509  else {
510  ta->flags |= TXT_ISMEM | TXT_ISDIRTY;
511  }
512 
513  /* clear undo buffer */
514  if (BLI_stat(filepath_abs, &st) != -1) {
515  ta->mtime = st.st_mtime;
516  }
517  else {
518  ta->mtime = 0;
519  }
520 
521  text_from_buf(ta, buffer, buffer_len);
522 
523  MEM_freeN(buffer);
524 
525  return ta;
526 }
527 
533 Text *BKE_text_load(Main *bmain, const char *file, const char *relpath)
534 {
535  return BKE_text_load_ex(bmain, file, relpath, false);
536 }
537 
538 void BKE_text_clear(Text *text) /* called directly from rna */
539 {
540  txt_sel_all(text);
541  txt_delete_sel(text);
542  txt_make_dirty(text);
543 }
544 
545 void BKE_text_write(Text *text, const char *str) /* called directly from rna */
546 {
547  txt_insert_buf(text, str);
548  txt_move_eof(text, 0);
549  txt_make_dirty(text);
550 }
551 
552 /* returns 0 if file on disk is the same or Text is in memory only
553  * returns 1 if file has been modified on disk since last local edit
554  * returns 2 if file on disk has been deleted
555  * -1 is returned if an error occurs */
556 
558 {
559  BLI_stat_t st;
560  int result;
561  char file[FILE_MAX];
562 
563  if (!text->filepath) {
564  return 0;
565  }
566 
569 
570  if (!BLI_exists(file)) {
571  return 2;
572  }
573 
574  result = BLI_stat(file, &st);
575 
576  if (result == -1) {
577  return -1;
578  }
579 
580  if ((st.st_mode & S_IFMT) != S_IFREG) {
581  return -1;
582  }
583 
584  if (st.st_mtime > text->mtime) {
585  return 1;
586  }
587 
588  return 0;
589 }
590 
592 {
593  BLI_stat_t st;
594  int result;
595  char file[FILE_MAX];
596 
597  if (!text->filepath) {
598  return;
599  }
600 
603 
604  if (!BLI_exists(file)) {
605  return;
606  }
607 
608  result = BLI_stat(file, &st);
609 
610  if (result == -1 || (st.st_mode & S_IFMT) != S_IFREG) {
611  return;
612  }
613 
614  text->mtime = st.st_mtime;
615 }
616 
619 /* -------------------------------------------------------------------- */
623 static void make_new_line(TextLine *line, char *newline)
624 {
625  if (line->line) {
626  MEM_freeN(line->line);
627  }
628  if (line->format) {
629  MEM_freeN(line->format);
630  }
631 
632  line->line = newline;
633  line->len = strlen(newline);
634  line->format = NULL;
635 }
636 
637 static TextLine *txt_new_line(const char *str)
638 {
639  TextLine *tmp;
640 
641  if (!str) {
642  str = "";
643  }
644 
645  tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline");
646  tmp->line = MEM_mallocN(strlen(str) + 1, "textline_string");
647  tmp->format = NULL;
648 
649  strcpy(tmp->line, str);
650 
651  tmp->len = strlen(str);
652  tmp->next = tmp->prev = NULL;
653 
654  return tmp;
655 }
656 
657 static TextLine *txt_new_linen(const char *str, int n)
658 {
659  TextLine *tmp;
660 
661  tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline");
662  tmp->line = MEM_mallocN(n + 1, "textline_string");
663  tmp->format = NULL;
664 
665  BLI_strncpy(tmp->line, (str) ? str : "", n + 1);
666 
667  tmp->len = strlen(tmp->line);
668  tmp->next = tmp->prev = NULL;
669 
670  return tmp;
671 }
672 
673 void txt_clean_text(Text *text)
674 {
675  TextLine **top, **bot;
676 
677  if (!text->lines.first) {
678  if (text->lines.last) {
679  text->lines.first = text->lines.last;
680  }
681  else {
682  text->lines.first = text->lines.last = txt_new_line(NULL);
683  }
684  }
685 
686  if (!text->lines.last) {
687  text->lines.last = text->lines.first;
688  }
689 
690  top = (TextLine **)&text->lines.first;
691  bot = (TextLine **)&text->lines.last;
692 
693  while ((*top)->prev) {
694  *top = (*top)->prev;
695  }
696  while ((*bot)->next) {
697  *bot = (*bot)->next;
698  }
699 
700  if (!text->curl) {
701  if (text->sell) {
702  text->curl = text->sell;
703  }
704  else {
705  text->curl = text->lines.first;
706  }
707  text->curc = 0;
708  }
709 
710  if (!text->sell) {
711  text->sell = text->curl;
712  text->selc = 0;
713  }
714 }
715 
717 {
718  int ret = 0;
719  TextLine *tmp = from;
720 
721  if (!to || !from) {
722  return 0;
723  }
724  if (from == to) {
725  return 0;
726  }
727 
728  /* Look forwards */
729  while (tmp) {
730  if (tmp == to) {
731  return ret;
732  }
733  ret++;
734  tmp = tmp->next;
735  }
736 
737  /* Look backwards */
738  if (!tmp) {
739  tmp = from;
740  ret = 0;
741  while (tmp) {
742  if (tmp == to) {
743  break;
744  }
745  ret--;
746  tmp = tmp->prev;
747  }
748  if (!tmp) {
749  ret = 0;
750  }
751  }
752 
753  return ret;
754 }
755 
756 static void txt_make_dirty(Text *text)
757 {
758  text->flags |= TXT_ISDIRTY;
759 #ifdef WITH_PYTHON
760  if (text->compiled) {
761  BPY_text_free_code(text);
762  }
763 #endif
764 }
765 
768 /* -------------------------------------------------------------------- */
772 static void txt_curs_cur(Text *text, TextLine ***linep, int **charp)
773 {
774  *linep = &text->curl;
775  *charp = &text->curc;
776 }
777 
778 static void txt_curs_sel(Text *text, TextLine ***linep, int **charp)
779 {
780  *linep = &text->sell;
781  *charp = &text->selc;
782 }
783 
785 {
786  return (text->selc == 0);
787 }
788 
790 {
791  return (text->selc == text->sell->len);
792 }
793 
796 /* -------------------------------------------------------------------- */
804 void txt_move_up(Text *text, const bool sel)
805 {
806  TextLine **linep;
807  int *charp;
808 
809  if (sel) {
810  txt_curs_sel(text, &linep, &charp);
811  }
812  else {
813  txt_pop_first(text);
814  txt_curs_cur(text, &linep, &charp);
815  }
816  if (!*linep) {
817  return;
818  }
819 
820  if ((*linep)->prev) {
821  int column = BLI_str_utf8_offset_to_column((*linep)->line, *charp);
822  *linep = (*linep)->prev;
823  *charp = BLI_str_utf8_offset_from_column((*linep)->line, column);
824  }
825  else {
826  txt_move_bol(text, sel);
827  }
828 
829  if (!sel) {
830  txt_pop_sel(text);
831  }
832 }
833 
834 void txt_move_down(Text *text, const bool sel)
835 {
836  TextLine **linep;
837  int *charp;
838 
839  if (sel) {
840  txt_curs_sel(text, &linep, &charp);
841  }
842  else {
843  txt_pop_last(text);
844  txt_curs_cur(text, &linep, &charp);
845  }
846  if (!*linep) {
847  return;
848  }
849 
850  if ((*linep)->next) {
851  int column = BLI_str_utf8_offset_to_column((*linep)->line, *charp);
852  *linep = (*linep)->next;
853  *charp = BLI_str_utf8_offset_from_column((*linep)->line, column);
854  }
855  else {
856  txt_move_eol(text, sel);
857  }
858 
859  if (!sel) {
860  txt_pop_sel(text);
861  }
862 }
863 
864 int txt_calc_tab_left(TextLine *tl, int ch)
865 {
866  /* do nice left only if there are only spaces */
867 
868  int tabsize = (ch < TXT_TABSIZE) ? ch : TXT_TABSIZE;
869 
870  for (int i = 0; i < ch; i++) {
871  if (tl->line[i] != ' ') {
872  tabsize = 0;
873  break;
874  }
875  }
876 
877  /* if in the middle of the space-tab */
878  if (tabsize && ch % TXT_TABSIZE != 0) {
879  tabsize = (ch % TXT_TABSIZE);
880  }
881  return tabsize;
882 }
883 
884 int txt_calc_tab_right(TextLine *tl, int ch)
885 {
886  if (tl->line[ch] == ' ') {
887  int i;
888  for (i = 0; i < ch; i++) {
889  if (tl->line[i] != ' ') {
890  return 0;
891  }
892  }
893 
894  int tabsize = (ch) % TXT_TABSIZE + 1;
895  for (i = ch + 1; tl->line[i] == ' ' && tabsize < TXT_TABSIZE; i++) {
896  tabsize++;
897  }
898 
899  return i - ch;
900  }
901 
902  return 0;
903 }
904 
905 void txt_move_left(Text *text, const bool sel)
906 {
907  TextLine **linep;
908  int *charp;
909  int tabsize = 0;
910 
911  if (sel) {
912  txt_curs_sel(text, &linep, &charp);
913  }
914  else {
915  txt_pop_first(text);
916  txt_curs_cur(text, &linep, &charp);
917  }
918  if (!*linep) {
919  return;
920  }
921 
922  if (*charp == 0) {
923  if ((*linep)->prev) {
924  txt_move_up(text, sel);
925  *charp = (*linep)->len;
926  }
927  }
928  else {
929  /* do nice left only if there are only spaces */
930  /* #TXT_TABSIZE hard-coded in DNA_text_types.h */
931  if (text->flags & TXT_TABSTOSPACES) {
932  tabsize = txt_calc_tab_left(*linep, *charp);
933  }
934 
935  if (tabsize) {
936  (*charp) -= tabsize;
937  }
938  else {
939  const char *prev = BLI_str_prev_char_utf8((*linep)->line + *charp);
940  *charp = prev - (*linep)->line;
941  }
942  }
943 
944  if (!sel) {
945  txt_pop_sel(text);
946  }
947 }
948 
949 void txt_move_right(Text *text, const bool sel)
950 {
951  TextLine **linep;
952  int *charp;
953 
954  if (sel) {
955  txt_curs_sel(text, &linep, &charp);
956  }
957  else {
958  txt_pop_last(text);
959  txt_curs_cur(text, &linep, &charp);
960  }
961  if (!*linep) {
962  return;
963  }
964 
965  if (*charp == (*linep)->len) {
966  if ((*linep)->next) {
967  txt_move_down(text, sel);
968  *charp = 0;
969  }
970  }
971  else {
972  /* do nice right only if there are only spaces */
973  /* spaces hardcoded in DNA_text_types.h */
974  int tabsize = 0;
975 
976  if (text->flags & TXT_TABSTOSPACES) {
977  tabsize = txt_calc_tab_right(*linep, *charp);
978  }
979 
980  if (tabsize) {
981  (*charp) += tabsize;
982  }
983  else {
984  (*charp) += BLI_str_utf8_size((*linep)->line + *charp);
985  }
986  }
987 
988  if (!sel) {
989  txt_pop_sel(text);
990  }
991 }
992 
993 void txt_jump_left(Text *text, const bool sel, const bool use_init_step)
994 {
995  TextLine **linep;
996  int *charp;
997 
998  if (sel) {
999  txt_curs_sel(text, &linep, &charp);
1000  }
1001  else {
1002  txt_pop_first(text);
1003  txt_curs_cur(text, &linep, &charp);
1004  }
1005  if (!*linep) {
1006  return;
1007  }
1008 
1010  (*linep)->line, (*linep)->len, charp, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, use_init_step);
1011 
1012  if (!sel) {
1013  txt_pop_sel(text);
1014  }
1015 }
1016 
1017 void txt_jump_right(Text *text, const bool sel, const bool use_init_step)
1018 {
1019  TextLine **linep;
1020  int *charp;
1021 
1022  if (sel) {
1023  txt_curs_sel(text, &linep, &charp);
1024  }
1025  else {
1026  txt_pop_last(text);
1027  txt_curs_cur(text, &linep, &charp);
1028  }
1029  if (!*linep) {
1030  return;
1031  }
1032 
1034  (*linep)->line, (*linep)->len, charp, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, use_init_step);
1035 
1036  if (!sel) {
1037  txt_pop_sel(text);
1038  }
1039 }
1040 
1041 void txt_move_bol(Text *text, const bool sel)
1042 {
1043  TextLine **linep;
1044  int *charp;
1045 
1046  if (sel) {
1047  txt_curs_sel(text, &linep, &charp);
1048  }
1049  else {
1050  txt_curs_cur(text, &linep, &charp);
1051  }
1052  if (!*linep) {
1053  return;
1054  }
1055 
1056  *charp = 0;
1057 
1058  if (!sel) {
1059  txt_pop_sel(text);
1060  }
1061 }
1062 
1063 void txt_move_eol(Text *text, const bool sel)
1064 {
1065  TextLine **linep;
1066  int *charp;
1067 
1068  if (sel) {
1069  txt_curs_sel(text, &linep, &charp);
1070  }
1071  else {
1072  txt_curs_cur(text, &linep, &charp);
1073  }
1074  if (!*linep) {
1075  return;
1076  }
1077 
1078  *charp = (*linep)->len;
1079 
1080  if (!sel) {
1081  txt_pop_sel(text);
1082  }
1083 }
1084 
1085 void txt_move_bof(Text *text, const bool sel)
1086 {
1087  TextLine **linep;
1088  int *charp;
1089 
1090  if (sel) {
1091  txt_curs_sel(text, &linep, &charp);
1092  }
1093  else {
1094  txt_curs_cur(text, &linep, &charp);
1095  }
1096  if (!*linep) {
1097  return;
1098  }
1099 
1100  *linep = text->lines.first;
1101  *charp = 0;
1102 
1103  if (!sel) {
1104  txt_pop_sel(text);
1105  }
1106 }
1107 
1108 void txt_move_eof(Text *text, const bool sel)
1109 {
1110  TextLine **linep;
1111  int *charp;
1112 
1113  if (sel) {
1114  txt_curs_sel(text, &linep, &charp);
1115  }
1116  else {
1117  txt_curs_cur(text, &linep, &charp);
1118  }
1119  if (!*linep) {
1120  return;
1121  }
1122 
1123  *linep = text->lines.last;
1124  *charp = (*linep)->len;
1125 
1126  if (!sel) {
1127  txt_pop_sel(text);
1128  }
1129 }
1130 
1131 void txt_move_toline(Text *text, unsigned int line, const bool sel)
1132 {
1133  txt_move_to(text, line, 0, sel);
1134 }
1135 
1136 /* Moves to a certain byte in a line, not a certain utf8-character! */
1137 void txt_move_to(Text *text, unsigned int line, unsigned int ch, const bool sel)
1138 {
1139  TextLine **linep;
1140  int *charp;
1141  unsigned int i;
1142 
1143  if (sel) {
1144  txt_curs_sel(text, &linep, &charp);
1145  }
1146  else {
1147  txt_curs_cur(text, &linep, &charp);
1148  }
1149  if (!*linep) {
1150  return;
1151  }
1152 
1153  *linep = text->lines.first;
1154  for (i = 0; i < line; i++) {
1155  if ((*linep)->next) {
1156  *linep = (*linep)->next;
1157  }
1158  else {
1159  break;
1160  }
1161  }
1162  if (ch > (unsigned int)((*linep)->len)) {
1163  ch = (unsigned int)((*linep)->len);
1164  }
1165  *charp = ch;
1166 
1167  if (!sel) {
1168  txt_pop_sel(text);
1169  }
1170 }
1171 
1174 /* -------------------------------------------------------------------- */
1178 static void txt_curs_swap(Text *text)
1179 {
1180  TextLine *tmpl;
1181  int tmpc;
1182 
1183  tmpl = text->curl;
1184  text->curl = text->sell;
1185  text->sell = tmpl;
1186 
1187  tmpc = text->curc;
1188  text->curc = text->selc;
1189  text->selc = tmpc;
1190 }
1191 
1192 static void txt_pop_first(Text *text)
1193 {
1194  if (txt_get_span(text->curl, text->sell) < 0 ||
1195  (text->curl == text->sell && text->curc > text->selc)) {
1196  txt_curs_swap(text);
1197  }
1198 
1199  txt_pop_sel(text);
1200 }
1201 
1202 static void txt_pop_last(Text *text)
1203 {
1204  if (txt_get_span(text->curl, text->sell) > 0 ||
1205  (text->curl == text->sell && text->curc < text->selc)) {
1206  txt_curs_swap(text);
1207  }
1208 
1209  txt_pop_sel(text);
1210 }
1211 
1212 void txt_pop_sel(Text *text)
1213 {
1214  text->sell = text->curl;
1215  text->selc = text->curc;
1216 }
1217 
1218 void txt_order_cursors(Text *text, const bool reverse)
1219 {
1220  if (!text->curl) {
1221  return;
1222  }
1223  if (!text->sell) {
1224  return;
1225  }
1226 
1227  /* Flip so text->curl is before/after text->sell */
1228  if (reverse == false) {
1229  if ((txt_get_span(text->curl, text->sell) < 0) ||
1230  (text->curl == text->sell && text->curc > text->selc)) {
1231  txt_curs_swap(text);
1232  }
1233  }
1234  else {
1235  if ((txt_get_span(text->curl, text->sell) > 0) ||
1236  (text->curl == text->sell && text->curc < text->selc)) {
1237  txt_curs_swap(text);
1238  }
1239  }
1240 }
1241 
1242 bool txt_has_sel(Text *text)
1243 {
1244  return ((text->curl != text->sell) || (text->curc != text->selc));
1245 }
1246 
1247 static void txt_delete_sel(Text *text)
1248 {
1249  TextLine *tmpl;
1250  char *buf;
1251 
1252  if (!text->curl) {
1253  return;
1254  }
1255  if (!text->sell) {
1256  return;
1257  }
1258 
1259  if (!txt_has_sel(text)) {
1260  return;
1261  }
1262 
1263  txt_order_cursors(text, false);
1264 
1265  buf = MEM_mallocN(text->curc + (text->sell->len - text->selc) + 1, "textline_string");
1266 
1267  strncpy(buf, text->curl->line, text->curc);
1268  strcpy(buf + text->curc, text->sell->line + text->selc);
1269  buf[text->curc + (text->sell->len - text->selc)] = 0;
1270 
1271  make_new_line(text->curl, buf);
1272 
1273  tmpl = text->sell;
1274  while (tmpl != text->curl) {
1275  tmpl = tmpl->prev;
1276  if (!tmpl) {
1277  break;
1278  }
1279 
1280  txt_delete_line(text, tmpl->next);
1281  }
1282 
1283  text->sell = text->curl;
1284  text->selc = text->curc;
1285 }
1286 
1287 void txt_sel_all(Text *text)
1288 {
1289  text->curl = text->lines.first;
1290  text->curc = 0;
1291 
1292  text->sell = text->lines.last;
1293  text->selc = text->sell->len;
1294 }
1295 
1301 void txt_sel_clear(Text *text)
1302 {
1303  if (text->sell) {
1304  text->curl = text->sell;
1305  text->curc = text->selc;
1306  }
1307 }
1308 
1309 void txt_sel_line(Text *text)
1310 {
1311  if (!text->curl) {
1312  return;
1313  }
1314 
1315  text->curc = 0;
1316  text->sell = text->curl;
1317  text->selc = text->sell->len;
1318 }
1319 
1320 void txt_sel_set(Text *text, int startl, int startc, int endl, int endc)
1321 {
1322  TextLine *froml, *tol;
1323  int fromllen, tollen;
1324 
1325  /* Support negative indices. */
1326  if (startl < 0 || endl < 0) {
1327  int end = BLI_listbase_count(&text->lines) - 1;
1328  if (startl < 0) {
1329  startl = end + startl + 1;
1330  }
1331  if (endl < 0) {
1332  endl = end + endl + 1;
1333  }
1334  }
1335  CLAMP_MIN(startl, 0);
1336  CLAMP_MIN(endl, 0);
1337 
1338  froml = BLI_findlink(&text->lines, startl);
1339  if (froml == NULL) {
1340  froml = text->lines.last;
1341  }
1342  if (startl == endl) {
1343  tol = froml;
1344  }
1345  else {
1346  tol = BLI_findlink(&text->lines, endl);
1347  if (tol == NULL) {
1348  tol = text->lines.last;
1349  }
1350  }
1351 
1352  fromllen = BLI_strlen_utf8(froml->line);
1353  tollen = BLI_strlen_utf8(tol->line);
1354 
1355  /* Support negative indices. */
1356  if (startc < 0) {
1357  startc = fromllen + startc + 1;
1358  }
1359  if (endc < 0) {
1360  endc = tollen + endc + 1;
1361  }
1362 
1363  CLAMP(startc, 0, fromllen);
1364  CLAMP(endc, 0, tollen);
1365 
1366  text->curl = froml;
1367  text->curc = BLI_str_utf8_offset_from_index(froml->line, startc);
1368  text->sell = tol;
1369  text->selc = BLI_str_utf8_offset_from_index(tol->line, endc);
1370 }
1371 
1374 /* -------------------------------------------------------------------- */
1390 char *txt_to_buf_for_undo(Text *text, int *r_buf_len)
1391 {
1392  int buf_len = 0;
1393  LISTBASE_FOREACH (const TextLine *, l, &text->lines) {
1394  buf_len += l->len + 1;
1395  }
1396  char *buf = MEM_mallocN(buf_len, __func__);
1397  char *buf_step = buf;
1398  LISTBASE_FOREACH (const TextLine *, l, &text->lines) {
1399  memcpy(buf_step, l->line, l->len);
1400  buf_step += l->len;
1401  *buf_step++ = '\n';
1402  }
1403  *r_buf_len = buf_len;
1404  return buf;
1405 }
1406 
1410 void txt_from_buf_for_undo(Text *text, const char *buf, int buf_len)
1411 {
1412  const char *buf_end = buf + buf_len;
1413  const char *buf_step = buf;
1414 
1415  /* First re-use existing lines.
1416  * Good for undo since it means in practice many operations re-use all
1417  * except for the modified line. */
1418  TextLine *l_src = text->lines.first;
1419  BLI_listbase_clear(&text->lines);
1420  while (buf_step != buf_end && l_src) {
1421  /* New lines are ensured by #txt_to_buf_for_undo. */
1422  const char *buf_step_next = strchr(buf_step, '\n');
1423  const int len = buf_step_next - buf_step;
1424 
1425  TextLine *l = l_src;
1426  l_src = l_src->next;
1427  if (l->len != len) {
1428  l->line = MEM_reallocN(l->line, len + 1);
1429  l->len = len;
1430  }
1431  MEM_SAFE_FREE(l->format);
1432 
1433  memcpy(l->line, buf_step, len);
1434  l->line[len] = '\0';
1435  BLI_addtail(&text->lines, l);
1436  buf_step = buf_step_next + 1;
1437  }
1438 
1439  /* If we have extra lines. */
1440  while (l_src != NULL) {
1441  TextLine *l_src_next = l_src->next;
1442  MEM_freeN(l_src->line);
1443  if (l_src->format) {
1444  MEM_freeN(l_src->format);
1445  }
1446  MEM_freeN(l_src);
1447  l_src = l_src_next;
1448  }
1449 
1450  while (buf_step != buf_end) {
1451  /* New lines are ensured by #txt_to_buf_for_undo. */
1452  const char *buf_step_next = strchr(buf_step, '\n');
1453  const int len = buf_step_next - buf_step;
1454 
1455  TextLine *l = MEM_mallocN(sizeof(TextLine), "textline");
1456  l->line = MEM_mallocN(len + 1, "textline_string");
1457  l->len = len;
1458  l->format = NULL;
1459 
1460  memcpy(l->line, buf_step, len);
1461  l->line[len] = '\0';
1462  BLI_addtail(&text->lines, l);
1463  buf_step = buf_step_next + 1;
1464  }
1465 
1466  text->curl = text->sell = text->lines.first;
1467  text->curc = text->selc = 0;
1468 
1469  txt_make_dirty(text);
1470 }
1471 
1474 /* -------------------------------------------------------------------- */
1478 char *txt_to_buf(Text *text, int *r_buf_strlen)
1479 {
1480  int length;
1481  TextLine *tmp, *linef, *linel;
1482  int charf, charl;
1483  char *buf;
1484 
1485  if (r_buf_strlen) {
1486  *r_buf_strlen = 0;
1487  }
1488 
1489  if (!text->curl) {
1490  return NULL;
1491  }
1492  if (!text->sell) {
1493  return NULL;
1494  }
1495  if (!text->lines.first) {
1496  return NULL;
1497  }
1498 
1499  linef = text->lines.first;
1500  charf = 0;
1501 
1502  linel = text->lines.last;
1503  charl = linel->len;
1504 
1505  if (linef == text->lines.last) {
1506  length = charl - charf;
1507 
1508  buf = MEM_mallocN(length + 2, "text buffer");
1509 
1510  BLI_strncpy(buf, linef->line + charf, length + 1);
1511  buf[length] = 0;
1512  }
1513  else {
1514  length = linef->len - charf;
1515  length += charl;
1516  length += 2; /* For the 2 '\n' */
1517 
1518  tmp = linef->next;
1519  while (tmp && tmp != linel) {
1520  length += tmp->len + 1;
1521  tmp = tmp->next;
1522  }
1523 
1524  buf = MEM_mallocN(length + 1, "cut buffer");
1525 
1526  strncpy(buf, linef->line + charf, linef->len - charf);
1527  length = linef->len - charf;
1528 
1529  buf[length++] = '\n';
1530 
1531  tmp = linef->next;
1532  while (tmp && tmp != linel) {
1533  strncpy(buf + length, tmp->line, tmp->len);
1534  length += tmp->len;
1535 
1536  buf[length++] = '\n';
1537 
1538  tmp = tmp->next;
1539  }
1540  strncpy(buf + length, linel->line, charl);
1541  length += charl;
1542 
1543  /* python compiler wants an empty end line */
1544  buf[length++] = '\n';
1545  buf[length] = 0;
1546  }
1547 
1548  if (r_buf_strlen) {
1549  *r_buf_strlen = length;
1550  }
1551 
1552  return buf;
1553 }
1554 
1555 char *txt_sel_to_buf(Text *text, int *r_buf_strlen)
1556 {
1557  char *buf;
1558  int length = 0;
1559  TextLine *tmp, *linef, *linel;
1560  int charf, charl;
1561 
1562  if (r_buf_strlen) {
1563  *r_buf_strlen = 0;
1564  }
1565 
1566  if (!text->curl) {
1567  return NULL;
1568  }
1569  if (!text->sell) {
1570  return NULL;
1571  }
1572 
1573  if (text->curl == text->sell) {
1574  linef = linel = text->curl;
1575 
1576  if (text->curc < text->selc) {
1577  charf = text->curc;
1578  charl = text->selc;
1579  }
1580  else {
1581  charf = text->selc;
1582  charl = text->curc;
1583  }
1584  }
1585  else if (txt_get_span(text->curl, text->sell) < 0) {
1586  linef = text->sell;
1587  linel = text->curl;
1588 
1589  charf = text->selc;
1590  charl = text->curc;
1591  }
1592  else {
1593  linef = text->curl;
1594  linel = text->sell;
1595 
1596  charf = text->curc;
1597  charl = text->selc;
1598  }
1599 
1600  if (linef == linel) {
1601  length = charl - charf;
1602 
1603  buf = MEM_mallocN(length + 1, "sel buffer");
1604 
1605  BLI_strncpy(buf, linef->line + charf, length + 1);
1606  }
1607  else {
1608  length += linef->len - charf;
1609  length += charl;
1610  length++; /* For the '\n' */
1611 
1612  tmp = linef->next;
1613  while (tmp && tmp != linel) {
1614  length += tmp->len + 1;
1615  tmp = tmp->next;
1616  }
1617 
1618  buf = MEM_mallocN(length + 1, "sel buffer");
1619 
1620  strncpy(buf, linef->line + charf, linef->len - charf);
1621  length = linef->len - charf;
1622 
1623  buf[length++] = '\n';
1624 
1625  tmp = linef->next;
1626  while (tmp && tmp != linel) {
1627  strncpy(buf + length, tmp->line, tmp->len);
1628  length += tmp->len;
1629 
1630  buf[length++] = '\n';
1631 
1632  tmp = tmp->next;
1633  }
1634  strncpy(buf + length, linel->line, charl);
1635  length += charl;
1636 
1637  buf[length] = 0;
1638  }
1639 
1640  if (r_buf_strlen) {
1641  *r_buf_strlen = length;
1642  }
1643 
1644  return buf;
1645 }
1646 
1647 void txt_insert_buf(Text *text, const char *in_buffer)
1648 {
1649  int l = 0, len;
1650  size_t i = 0, j;
1651  TextLine *add;
1652  char *buffer;
1653 
1654  if (!in_buffer) {
1655  return;
1656  }
1657 
1658  txt_delete_sel(text);
1659 
1660  len = strlen(in_buffer);
1661  buffer = BLI_strdupn(in_buffer, len);
1663 
1664  /* Read the first line (or as close as possible */
1665  while (buffer[i] && buffer[i] != '\n') {
1667  }
1668 
1669  if (buffer[i] == '\n') {
1670  txt_split_curline(text);
1671  i++;
1672 
1673  while (i < len) {
1674  l = 0;
1675 
1676  while (buffer[i] && buffer[i] != '\n') {
1677  i++;
1678  l++;
1679  }
1680 
1681  if (buffer[i] == '\n') {
1682  add = txt_new_linen(buffer + (i - l), l);
1683  BLI_insertlinkbefore(&text->lines, text->curl, add);
1684  i++;
1685  }
1686  else {
1687  for (j = i - l; j < i && j < len;) {
1689  }
1690  break;
1691  }
1692  }
1693  }
1694 
1695  MEM_freeN(buffer);
1696 }
1697 
1700 /* -------------------------------------------------------------------- */
1704 int txt_find_string(Text *text, const char *findstr, int wrap, int match_case)
1705 {
1706  TextLine *tl, *startl;
1707  const char *s = NULL;
1708 
1709  if (!text->curl || !text->sell) {
1710  return 0;
1711  }
1712 
1713  txt_order_cursors(text, false);
1714 
1715  tl = startl = text->sell;
1716 
1717  if (match_case) {
1718  s = strstr(&tl->line[text->selc], findstr);
1719  }
1720  else {
1721  s = BLI_strcasestr(&tl->line[text->selc], findstr);
1722  }
1723  while (!s) {
1724  tl = tl->next;
1725  if (!tl) {
1726  if (wrap) {
1727  tl = text->lines.first;
1728  }
1729  else {
1730  break;
1731  }
1732  }
1733 
1734  if (match_case) {
1735  s = strstr(tl->line, findstr);
1736  }
1737  else {
1738  s = BLI_strcasestr(tl->line, findstr);
1739  }
1740  if (tl == startl) {
1741  break;
1742  }
1743  }
1744 
1745  if (s) {
1746  int newl = txt_get_span(text->lines.first, tl);
1747  int newc = (int)(s - tl->line);
1748  txt_move_to(text, newl, newc, 0);
1749  txt_move_to(text, newl, newc + strlen(findstr), 1);
1750  return 1;
1751  }
1752 
1753  return 0;
1754 }
1755 
1758 /* -------------------------------------------------------------------- */
1763 {
1764  TextLine *ins;
1765  char *left, *right;
1766 
1767  if (!text->curl) {
1768  return;
1769  }
1770 
1771  txt_delete_sel(text);
1772 
1773  /* Make the two half strings */
1774 
1775  left = MEM_mallocN(text->curc + 1, "textline_string");
1776  if (text->curc) {
1777  memcpy(left, text->curl->line, text->curc);
1778  }
1779  left[text->curc] = 0;
1780 
1781  right = MEM_mallocN(text->curl->len - text->curc + 1, "textline_string");
1782  memcpy(right, text->curl->line + text->curc, text->curl->len - text->curc + 1);
1783 
1784  MEM_freeN(text->curl->line);
1785  if (text->curl->format) {
1786  MEM_freeN(text->curl->format);
1787  }
1788 
1789  /* Make the new TextLine */
1790 
1791  ins = MEM_mallocN(sizeof(TextLine), "textline");
1792  ins->line = left;
1793  ins->format = NULL;
1794  ins->len = text->curc;
1795 
1796  text->curl->line = right;
1797  text->curl->format = NULL;
1798  text->curl->len = text->curl->len - text->curc;
1799 
1800  BLI_insertlinkbefore(&text->lines, text->curl, ins);
1801 
1802  text->curc = 0;
1803 
1804  txt_make_dirty(text);
1805  txt_clean_text(text);
1806 
1807  txt_pop_sel(text);
1808 }
1809 
1810 static void txt_delete_line(Text *text, TextLine *line)
1811 {
1812  if (!text->curl) {
1813  return;
1814  }
1815 
1816  BLI_remlink(&text->lines, line);
1817 
1818  if (line->line) {
1819  MEM_freeN(line->line);
1820  }
1821  if (line->format) {
1822  MEM_freeN(line->format);
1823  }
1824 
1825  MEM_freeN(line);
1826 
1827  txt_make_dirty(text);
1828  txt_clean_text(text);
1829 }
1830 
1831 static void txt_combine_lines(Text *text, TextLine *linea, TextLine *lineb)
1832 {
1833  char *tmp, *s;
1834 
1835  if (!linea || !lineb) {
1836  return;
1837  }
1838 
1839  tmp = MEM_mallocN(linea->len + lineb->len + 1, "textline_string");
1840 
1841  s = tmp;
1842  s += BLI_strcpy_rlen(s, linea->line);
1843  s += BLI_strcpy_rlen(s, lineb->line);
1844  (void)s;
1845 
1846  make_new_line(linea, tmp);
1847 
1848  txt_delete_line(text, lineb);
1849 
1850  txt_make_dirty(text);
1851  txt_clean_text(text);
1852 }
1853 
1855 {
1856  TextLine *textline;
1857 
1858  if (!text->curl) {
1859  return;
1860  }
1861 
1862  if (text->curl == text->sell) {
1863  textline = txt_new_line(text->curl->line);
1864  BLI_insertlinkafter(&text->lines, text->curl, textline);
1865 
1866  txt_make_dirty(text);
1867  txt_clean_text(text);
1868  }
1869 }
1870 
1872 {
1873  unsigned int c = '\n';
1874 
1875  if (!text->curl) {
1876  return;
1877  }
1878 
1879  if (txt_has_sel(text)) { /* deleting a selection */
1880  txt_delete_sel(text);
1881  txt_make_dirty(text);
1882  return;
1883  }
1884  if (text->curc == text->curl->len) { /* Appending two lines */
1885  if (text->curl->next) {
1886  txt_combine_lines(text, text->curl, text->curl->next);
1887  txt_pop_sel(text);
1888  }
1889  else {
1890  return;
1891  }
1892  }
1893  else { /* Just deleting a char */
1894  size_t c_len = 0;
1895  c = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &c_len);
1896  UNUSED_VARS(c);
1897 
1898  memmove(text->curl->line + text->curc,
1899  text->curl->line + text->curc + c_len,
1900  text->curl->len - text->curc - c_len + 1);
1901 
1902  text->curl->len -= c_len;
1903 
1904  txt_pop_sel(text);
1905  }
1906 
1907  txt_make_dirty(text);
1908  txt_clean_text(text);
1909 }
1910 
1912 {
1913  txt_jump_right(text, true, true);
1914  txt_delete_sel(text);
1915  txt_make_dirty(text);
1916 }
1917 
1919 {
1920  unsigned int c = '\n';
1921 
1922  if (!text->curl) {
1923  return;
1924  }
1925 
1926  if (txt_has_sel(text)) { /* deleting a selection */
1927  txt_delete_sel(text);
1928  txt_make_dirty(text);
1929  return;
1930  }
1931  if (text->curc == 0) { /* Appending two lines */
1932  if (!text->curl->prev) {
1933  return;
1934  }
1935 
1936  text->curl = text->curl->prev;
1937  text->curc = text->curl->len;
1938 
1939  txt_combine_lines(text, text->curl, text->curl->next);
1940  txt_pop_sel(text);
1941  }
1942  else { /* Just backspacing a char */
1943  size_t c_len = 0;
1944  const char *prev = BLI_str_prev_char_utf8(text->curl->line + text->curc);
1945  c = BLI_str_utf8_as_unicode_and_size(prev, &c_len);
1946  UNUSED_VARS(c);
1947 
1948  /* source and destination overlap, don't use memcpy() */
1949  memmove(text->curl->line + text->curc - c_len,
1950  text->curl->line + text->curc,
1951  text->curl->len - text->curc + 1);
1952 
1953  text->curl->len -= c_len;
1954  text->curc -= c_len;
1955 
1956  txt_pop_sel(text);
1957  }
1958 
1959  txt_make_dirty(text);
1960  txt_clean_text(text);
1961 }
1962 
1964 {
1965  txt_jump_left(text, true, true);
1966  txt_delete_sel(text);
1967  txt_make_dirty(text);
1968 }
1969 
1970 /* Max spaces to replace a tab with, currently hardcoded to TXT_TABSIZE = 4.
1971  * Used by txt_convert_tab_to_spaces, indent and unindent.
1972  * Remember to change this string according to max tab size */
1973 static char tab_to_spaces[] = " ";
1974 
1976 {
1977  /* sb aims to pad adjust the tab-width needed so that the right number of spaces
1978  * is added so that the indention of the line is the right width (i.e. aligned
1979  * to multiples of TXT_TABSIZE)
1980  */
1981  const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
1982  txt_insert_buf(text, sb);
1983 }
1984 
1985 static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs)
1986 {
1987  char *tmp, ch[BLI_UTF8_MAX];
1988  size_t add_len;
1989 
1990  if (!text->curl) {
1991  return 0;
1992  }
1993 
1994  if (add == '\n') {
1995  txt_split_curline(text);
1996  return true;
1997  }
1998 
1999  /* insert spaces rather than tabs */
2000  if (add == '\t' && replace_tabs) {
2002  return true;
2003  }
2004 
2005  txt_delete_sel(text);
2006 
2007  add_len = BLI_str_utf8_from_unicode(add, ch);
2008 
2009  tmp = MEM_mallocN(text->curl->len + add_len + 1, "textline_string");
2010 
2011  memcpy(tmp, text->curl->line, text->curc);
2012  memcpy(tmp + text->curc, ch, add_len);
2013  memcpy(
2014  tmp + text->curc + add_len, text->curl->line + text->curc, text->curl->len - text->curc + 1);
2015 
2016  make_new_line(text->curl, tmp);
2017 
2018  text->curc += add_len;
2019 
2020  txt_pop_sel(text);
2021 
2022  txt_make_dirty(text);
2023  txt_clean_text(text);
2024 
2025  return 1;
2026 }
2027 
2028 bool txt_add_char(Text *text, unsigned int add)
2029 {
2030  return txt_add_char_intern(text, add, (text->flags & TXT_TABSTOSPACES) != 0);
2031 }
2032 
2033 bool txt_add_raw_char(Text *text, unsigned int add)
2034 {
2035  return txt_add_char_intern(text, add, 0);
2036 }
2037 
2039 {
2040  txt_delete_sel(text);
2041  txt_make_dirty(text);
2042 }
2043 
2044 bool txt_replace_char(Text *text, unsigned int add)
2045 {
2046  unsigned int del;
2047  size_t del_size = 0, add_size;
2048  char ch[BLI_UTF8_MAX];
2049 
2050  if (!text->curl) {
2051  return false;
2052  }
2053 
2054  /* If text is selected or we're at the end of the line just use txt_add_char */
2055  if (text->curc == text->curl->len || txt_has_sel(text) || add == '\n') {
2056  return txt_add_char(text, add);
2057  }
2058 
2059  del = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size);
2060  UNUSED_VARS(del);
2061  add_size = BLI_str_utf8_from_unicode(add, ch);
2062 
2063  if (add_size > del_size) {
2064  char *tmp = MEM_mallocN(text->curl->len + add_size - del_size + 1, "textline_string");
2065  memcpy(tmp, text->curl->line, text->curc);
2066  memcpy(tmp + text->curc + add_size,
2067  text->curl->line + text->curc + del_size,
2068  text->curl->len - text->curc - del_size + 1);
2069  MEM_freeN(text->curl->line);
2070  text->curl->line = tmp;
2071  }
2072  else if (add_size < del_size) {
2073  char *tmp = text->curl->line;
2074  memmove(tmp + text->curc + add_size,
2075  tmp + text->curc + del_size,
2076  text->curl->len - text->curc - del_size + 1);
2077  }
2078 
2079  memcpy(text->curl->line + text->curc, ch, add_size);
2080  text->curc += add_size;
2081  text->curl->len += add_size - del_size;
2082 
2083  txt_pop_sel(text);
2084  txt_make_dirty(text);
2085  txt_clean_text(text);
2086  return true;
2087 }
2088 
2094 static void txt_select_prefix(Text *text, const char *add, bool skip_blank_lines)
2095 {
2096  int len, num, curc_old, selc_old;
2097  char *tmp;
2098 
2099  const int indentlen = strlen(add);
2100 
2101  BLI_assert(!ELEM(NULL, text->curl, text->sell));
2102 
2103  curc_old = text->curc;
2104  selc_old = text->selc;
2105 
2106  num = 0;
2107  while (true) {
2108 
2109  /* don't indent blank lines */
2110  if ((text->curl->len != 0) || (skip_blank_lines == 0)) {
2111  tmp = MEM_mallocN(text->curl->len + indentlen + 1, "textline_string");
2112 
2113  text->curc = 0;
2114  if (text->curc) {
2115  memcpy(tmp, text->curl->line, text->curc); /* XXX never true, check prev line */
2116  }
2117  memcpy(tmp + text->curc, add, indentlen);
2118 
2119  len = text->curl->len - text->curc;
2120  if (len > 0) {
2121  memcpy(tmp + text->curc + indentlen, text->curl->line + text->curc, len);
2122  }
2123  tmp[text->curl->len + indentlen] = 0;
2124 
2125  make_new_line(text->curl, tmp);
2126 
2127  text->curc += indentlen;
2128 
2129  txt_make_dirty(text);
2130  txt_clean_text(text);
2131  }
2132 
2133  if (text->curl == text->sell) {
2134  if (text->curl->len != 0) {
2135  text->selc += indentlen;
2136  }
2137  break;
2138  }
2139 
2140  text->curl = text->curl->next;
2141  num++;
2142  }
2143 
2144  while (num > 0) {
2145  text->curl = text->curl->prev;
2146  num--;
2147  }
2148 
2149  /* Keep the cursor left aligned if we don't have a selection. */
2150  if (curc_old == 0 && !(text->curl == text->sell && curc_old == selc_old)) {
2151  if (text->curl == text->sell) {
2152  if (text->curc == text->selc) {
2153  text->selc = 0;
2154  }
2155  }
2156  text->curc = 0;
2157  }
2158  else {
2159  if (text->curl->len != 0) {
2160  text->curc = curc_old + indentlen;
2161  }
2162  }
2163 }
2164 
2173 static bool txt_select_unprefix(Text *text, const char *remove, const bool require_all)
2174 {
2175  int num = 0;
2176  const int indentlen = strlen(remove);
2177  bool unindented_first = false;
2178  bool changed_any = false;
2179 
2180  BLI_assert(!ELEM(NULL, text->curl, text->sell));
2181 
2182  if (require_all) {
2183  /* Check all non-empty lines use this 'remove',
2184  * so the operation is applied equally or not at all. */
2185  TextLine *l = text->curl;
2186  while (true) {
2187  if (STREQLEN(l->line, remove, indentlen)) {
2188  /* pass */
2189  }
2190  else {
2191  /* Blank lines or whitespace can be skipped. */
2192  for (int i = 0; i < l->len; i++) {
2193  if (!ELEM(l->line[i], '\t', ' ')) {
2194  return false;
2195  }
2196  }
2197  }
2198  if (l == text->sell) {
2199  break;
2200  }
2201  l = l->next;
2202  }
2203  }
2204 
2205  while (true) {
2206  bool changed = false;
2207  if (STREQLEN(text->curl->line, remove, indentlen)) {
2208  if (num == 0) {
2209  unindented_first = true;
2210  }
2211  text->curl->len -= indentlen;
2212  memmove(text->curl->line, text->curl->line + indentlen, text->curl->len + 1);
2213  changed = true;
2214  changed_any = true;
2215  }
2216 
2217  txt_make_dirty(text);
2218  txt_clean_text(text);
2219 
2220  if (text->curl == text->sell) {
2221  if (changed) {
2222  text->selc = MAX2(text->selc - indentlen, 0);
2223  }
2224  break;
2225  }
2226 
2227  text->curl = text->curl->next;
2228  num++;
2229  }
2230 
2231  if (unindented_first) {
2232  text->curc = MAX2(text->curc - indentlen, 0);
2233  }
2234 
2235  while (num > 0) {
2236  text->curl = text->curl->prev;
2237  num--;
2238  }
2239 
2240  /* caller must handle undo */
2241  return changed_any;
2242 }
2243 
2244 void txt_comment(Text *text)
2245 {
2246  const char *prefix = "#";
2247 
2248  if (ELEM(NULL, text->curl, text->sell)) {
2249  return;
2250  }
2251 
2252  const bool skip_blank_lines = txt_has_sel(text);
2253  txt_select_prefix(text, prefix, skip_blank_lines);
2254 }
2255 
2256 bool txt_uncomment(Text *text)
2257 {
2258  const char *prefix = "#";
2259 
2260  if (ELEM(NULL, text->curl, text->sell)) {
2261  return false;
2262  }
2263 
2264  return txt_select_unprefix(text, prefix, true);
2265 }
2266 
2267 void txt_indent(Text *text)
2268 {
2269  const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
2270 
2271  if (ELEM(NULL, text->curl, text->sell)) {
2272  return;
2273  }
2274 
2275  txt_select_prefix(text, prefix, true);
2276 }
2277 
2278 bool txt_unindent(Text *text)
2279 {
2280  const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
2281 
2282  if (ELEM(NULL, text->curl, text->sell)) {
2283  return false;
2284  }
2285 
2286  return txt_select_unprefix(text, prefix, false);
2287 }
2288 
2289 void txt_move_lines(struct Text *text, const int direction)
2290 {
2291  TextLine *line_other;
2292 
2294 
2295  if (!text->curl || !text->sell) {
2296  return;
2297  }
2298 
2299  txt_order_cursors(text, false);
2300 
2301  line_other = (direction == TXT_MOVE_LINE_DOWN) ? text->sell->next : text->curl->prev;
2302 
2303  if (!line_other) {
2304  return;
2305  }
2306 
2307  BLI_remlink(&text->lines, line_other);
2308 
2309  if (direction == TXT_MOVE_LINE_DOWN) {
2310  BLI_insertlinkbefore(&text->lines, text->curl, line_other);
2311  }
2312  else {
2313  BLI_insertlinkafter(&text->lines, text->sell, line_other);
2314  }
2315 
2316  txt_make_dirty(text);
2317  txt_clean_text(text);
2318 }
2319 
2320 int txt_setcurr_tab_spaces(Text *text, int space)
2321 {
2322  int i = 0;
2323  int test = 0;
2324  const char *word = ":";
2325  const char *comm = "#";
2326  const char indent = (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t';
2327  static const char *back_words[] = {"return", "break", "continue", "pass", "yield", NULL};
2328 
2329  if (!text->curl) {
2330  return 0;
2331  }
2332 
2333  while (text->curl->line[i] == indent) {
2334  // we only count those tabs/spaces that are before any text or before the curs;
2335  if (i == text->curc) {
2336  return i;
2337  }
2338 
2339  i++;
2340  }
2341  if (strstr(text->curl->line, word)) {
2342  /* if we find a ':' on this line, then add a tab but not if it is:
2343  * 1) in a comment
2344  * 2) within an identifier
2345  * 3) after the cursor (text->curc), i.e. when creating space before a function def T25414.
2346  */
2347  int a;
2348  bool is_indent = false;
2349  for (a = 0; (a < text->curc) && (text->curl->line[a] != '\0'); a++) {
2350  char ch = text->curl->line[a];
2351  if (ch == '#') {
2352  break;
2353  }
2354  if (ch == ':') {
2355  is_indent = 1;
2356  }
2357  else if (!ELEM(ch, ' ', '\t')) {
2358  is_indent = 0;
2359  }
2360  }
2361  if (is_indent) {
2362  i += space;
2363  }
2364  }
2365 
2366  for (test = 0; back_words[test]; test++) {
2367  /* if there are these key words then remove a tab because we are done with the block */
2368  if (strstr(text->curl->line, back_words[test]) && i > 0) {
2369  if (strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm)) {
2370  i -= space;
2371  }
2372  }
2373  }
2374  return i;
2375 }
2376 
2379 /* -------------------------------------------------------------------- */
2383 int text_check_bracket(const char ch)
2384 {
2385  int a;
2386  char opens[] = "([{";
2387  char close[] = ")]}";
2388 
2389  for (a = 0; a < (sizeof(opens) - 1); a++) {
2390  if (ch == opens[a]) {
2391  return a + 1;
2392  }
2393  if (ch == close[a]) {
2394  return -(a + 1);
2395  }
2396  }
2397  return 0;
2398 }
2399 
2400 /* TODO, have a function for operators -
2401  * http://docs.python.org/py3k/reference/lexical_analysis.html#operators */
2402 bool text_check_delim(const char ch)
2403 {
2404  int a;
2405  char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,@";
2406 
2407  for (a = 0; a < (sizeof(delims) - 1); a++) {
2408  if (ch == delims[a]) {
2409  return true;
2410  }
2411  }
2412  return false;
2413 }
2414 
2415 bool text_check_digit(const char ch)
2416 {
2417  if (ch < '0') {
2418  return false;
2419  }
2420  if (ch <= '9') {
2421  return true;
2422  }
2423  return false;
2424 }
2425 
2426 bool text_check_identifier(const char ch)
2427 {
2428  if (ch < '0') {
2429  return false;
2430  }
2431  if (ch <= '9') {
2432  return true;
2433  }
2434  if (ch < 'A') {
2435  return false;
2436  }
2437  if (ch <= 'Z' || ch == '_') {
2438  return true;
2439  }
2440  if (ch < 'a') {
2441  return false;
2442  }
2443  if (ch <= 'z') {
2444  return true;
2445  }
2446  return false;
2447 }
2448 
2450 {
2451  if (ch <= '9') {
2452  return false;
2453  }
2454  if (ch < 'A') {
2455  return false;
2456  }
2457  if (ch <= 'Z' || ch == '_') {
2458  return true;
2459  }
2460  if (ch < 'a') {
2461  return false;
2462  }
2463  if (ch <= 'z') {
2464  return true;
2465  }
2466  return false;
2467 }
2468 
2469 #ifndef WITH_PYTHON
2470 int text_check_identifier_unicode(const unsigned int ch)
2471 {
2472  return (ch < 255 && text_check_identifier((unsigned int)ch));
2473 }
2474 
2475 int text_check_identifier_nodigit_unicode(const unsigned int ch)
2476 {
2477  return (ch < 255 && text_check_identifier_nodigit((char)ch));
2478 }
2479 #endif /* WITH_PYTHON */
2480 
2481 bool text_check_whitespace(const char ch)
2482 {
2483  if (ELEM(ch, ' ', '\t', '\r', '\n')) {
2484  return true;
2485  }
2486  return false;
2487 }
2488 
2489 int text_find_identifier_start(const char *str, int i)
2490 {
2491  if (UNLIKELY(i <= 0)) {
2492  return 0;
2493  }
2494 
2495  while (i--) {
2496  if (!text_check_identifier(str[i])) {
2497  break;
2498  }
2499  }
2500  i++;
2501  return i;
2502 }
2503 
@ IDTYPE_FLAGS_NO_ANIMDATA
Definition: BKE_idtype.h:51
void id_us_min(struct ID *id)
Definition: lib_id.c:297
void id_fake_user_set(struct ID *id)
Definition: lib_id.c:328
void * BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT
Definition: lib_id.c:1062
void BKE_id_blend_write(struct BlendWriter *writer, struct ID *id)
Definition: lib_id.c:2395
void * BKE_id_new(struct Main *bmain, const short type, const char *name)
Definition: lib_id.c:1177
@ TXT_MOVE_LINE_UP
Definition: BKE_text.h:108
@ TXT_MOVE_LINE_DOWN
Definition: BKE_text.h:109
#define BLI_assert(a)
Definition: BLI_assert.h:58
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:349
void * BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
Definition: storage.c:508
int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
struct stat BLI_stat_t
Definition: BLI_fileops.h:67
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:87
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:352
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:395
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
const char * BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1868
#define FILE_MAX
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL()
Definition: path_util.c:1016
char * BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:578
char * BLI_strdupn(const char *str, const size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:54
size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:201
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
void BLI_str_cursor_step_utf8(const char *str, size_t maxlen, int *pos, eStrCursorJumpDirection direction, eStrCursorJumpType jump, bool use_init_step)
@ STRCUR_DIR_NEXT
@ STRCUR_DIR_PREV
@ STRCUR_JUMP_DELIM
size_t BLI_strlen_utf8(const char *strc) ATTR_NONNULL()
Definition: string_utf8.c:357
#define BLI_UTF8_MAX
int BLI_str_utf8_size(const char *p) ATTR_NONNULL()
Definition: string_utf8.c:495
int BLI_str_utf8_offset_from_column(const char *str, int column)
Definition: string_utf8.c:943
ptrdiff_t BLI_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL()
Definition: string_utf8.c:73
unsigned int BLI_str_utf8_as_unicode_and_size(const char *__restrict p, size_t *__restrict index) ATTR_NONNULL()
Definition: string_utf8.c:550
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
int BLI_str_utf8_offset_to_column(const char *str, int offset)
Definition: string_utf8.c:933
int BLI_str_utf8_offset_from_index(const char *str, int index)
Definition: string_utf8.c:923
#define UNUSED_VARS(...)
#define STREQLEN(a, b, n)
#define UNUSED(x)
#define MAX2(a, b)
#define UNLIKELY(x)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define CLAMP_MIN(a, b)
#define BLO_read_data_address(reader, ptr_p)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_list(BlendDataReader *reader, struct ListBase *list)
Definition: readfile.c:5654
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
Definition: writefile.c:1401
void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_ptr)
Definition: writefile.c:1286
bool BLO_write_is_undo(BlendWriter *writer)
Definition: writefile.c:1412
#define BLT_I18NCONTEXT_ID_TEXT
void BPY_text_free_code(struct Text *text)
#define ID_BLEND_PATH_FROM_GLOBAL(_id)
Definition: DNA_ID.h:421
@ INDEX_ID_TXT
Definition: DNA_ID.h:802
#define FILTER_ID_TXT
Definition: DNA_ID.h:729
@ ID_TXT
Definition: DNA_ID_enums.h:74
Object is a sort of wrapper for general info.
struct Text Text
#define TXT_TABSIZE
@ TXT_TABSTOSPACES
@ TXT_ISDIRTY
@ TXT_ISMEM
@ TXT_ISEXT
@ USER_TXT_TABSTOSPACES_DISABLE
_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 right
_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)
#define MEM_reallocN(vmemh, len)
static void init_data(ModifierData *md)
Group RGB to Bright Vector Camera CLAMP
ATTR_WARN_UNUSED_RESULT const BMLoop * l
unsigned int U
Definition: btGjkEpa3.h:78
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
StackEntry * from
FILE * file
#define str(s)
__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_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static int left
static void add(GHash *messages, MemArena *memarena, const Message *msg)
Definition: msgfmt.c:268
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
static GPUContext * wrap(Context *ctx)
return ret
struct BMLoop * next
Definition: bmesh_class.h:245
short id_code
Definition: BKE_idtype.h:120
Definition: DNA_ID.h:273
int us
Definition: DNA_ID.h:293
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
char * format
char * line
struct TextLine * prev
struct TextLine * next
int flags
ListBase lines
TextLine * curl
int selc
double mtime
TextLine * sell
int curc
void * compiled
char * filepath
Text * BKE_text_add(Main *bmain, const char *name)
Definition: text.c:292
bool txt_uncomment(Text *text)
Definition: text.c:2256
char * txt_sel_to_buf(Text *text, int *r_buf_strlen)
Definition: text.c:1555
static void text_free_data(ID *id)
Definition: text.c:159
int txt_find_string(Text *text, const char *findstr, int wrap, int match_case)
Definition: text.c:1704
Text * BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
Definition: text.c:476
static void txt_curs_swap(Text *text)
Definition: text.c:1178
bool BKE_text_reload(Text *text)
Definition: text.c:431
bool txt_unindent(Text *text)
Definition: text.c:2278
static void txt_make_dirty(Text *text)
Definition: text.c:756
void txt_sel_set(Text *text, int startl, int startc, int endl, int endc)
Definition: text.c:1320
void txt_indent(Text *text)
Definition: text.c:2267
void BKE_text_free_lines(Text *text)
Definition: text.c:276
bool text_check_identifier(const char ch)
Definition: text.c:2426
bool txt_cursor_is_line_start(Text *text)
Definition: text.c:784
void txt_sel_all(Text *text)
Definition: text.c:1287
static void text_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int UNUSED(flag))
Definition: text.c:124
bool txt_cursor_is_line_end(Text *text)
Definition: text.c:789
void txt_clean_text(Text *text)
Definition: text.c:673
void txt_move_toline(Text *text, unsigned int line, const bool sel)
Definition: text.c:1131
static void text_blend_read_data(BlendDataReader *reader, ID *id)
Definition: text.c:207
void txt_pop_sel(Text *text)
Definition: text.c:1212
static void text_from_buf(Text *text, const unsigned char *buffer, const int len)
Definition: text.c:368
static void txt_delete_line(Text *text, TextLine *line)
Definition: text.c:1810
int text_check_identifier_unicode(const unsigned int ch)
Definition: text.c:2470
bool txt_add_char(Text *text, unsigned int add)
Definition: text.c:2028
static TextLine * txt_new_linen(const char *str, int n)
Definition: text.c:657
void txt_move_bof(Text *text, const bool sel)
Definition: text.c:1085
char * txt_to_buf_for_undo(Text *text, int *r_buf_len)
Definition: text.c:1390
void txt_delete_word(Text *text)
Definition: text.c:1911
char * txt_to_buf(Text *text, int *r_buf_strlen)
Definition: text.c:1478
static void txt_curs_cur(Text *text, TextLine ***linep, int **charp)
Definition: text.c:772
int txt_calc_tab_left(TextLine *tl, int ch)
Definition: text.c:864
void txt_split_curline(Text *text)
Definition: text.c:1762
static void text_init_data(ID *id)
Definition: text.c:80
void txt_jump_right(Text *text, const bool sel, const bool use_init_step)
Definition: text.c:1017
void BKE_text_write(Text *text, const char *str)
Definition: text.c:545
void txt_move_right(Text *text, const bool sel)
Definition: text.c:949
bool text_check_digit(const char ch)
Definition: text.c:2415
bool txt_replace_char(Text *text, unsigned int add)
Definition: text.c:2044
Text * BKE_text_load(Main *bmain, const char *file, const char *relpath)
Definition: text.c:533
void txt_backspace_char(Text *text)
Definition: text.c:1918
void txt_move_eol(Text *text, const bool sel)
Definition: text.c:1063
static void make_new_line(TextLine *line, char *newline)
Definition: text.c:623
void txt_from_buf_for_undo(Text *text, const char *buf, int buf_len)
Definition: text.c:1410
void BKE_text_file_modified_ignore(Text *text)
Definition: text.c:591
void txt_move_lines(struct Text *text, const int direction)
Definition: text.c:2289
int BKE_text_file_modified_check(Text *text)
Definition: text.c:557
int txt_setcurr_tab_spaces(Text *text, int space)
Definition: text.c:2320
int text_check_bracket(const char ch)
Definition: text.c:2383
int text_check_identifier_nodigit_unicode(const unsigned int ch)
Definition: text.c:2475
bool text_check_delim(const char ch)
Definition: text.c:2402
void txt_move_bol(Text *text, const bool sel)
Definition: text.c:1041
int txt_get_span(TextLine *from, TextLine *to)
Definition: text.c:716
static bool txt_select_unprefix(Text *text, const char *remove, const bool require_all)
Definition: text.c:2173
void txt_delete_char(Text *text)
Definition: text.c:1871
static void txt_pop_last(Text *text)
Definition: text.c:1202
static void txt_delete_sel(Text *text)
Definition: text.c:1247
bool txt_has_sel(Text *text)
Definition: text.c:1242
void txt_move_eof(Text *text, const bool sel)
Definition: text.c:1108
void txt_move_down(Text *text, const bool sel)
Definition: text.c:834
static void cleanup_textline(TextLine *tl)
Definition: text.c:350
static void text_blend_write(BlendWriter *writer, ID *id, const void *id_address)
Definition: text.c:172
void BKE_text_clear(Text *text)
Definition: text.c:538
void txt_move_to(Text *text, unsigned int line, unsigned int ch, const bool sel)
Definition: text.c:1137
void txt_comment(Text *text)
Definition: text.c:2244
static void txt_pop_first(Text *text)
Definition: text.c:1192
static void txt_convert_tab_to_spaces(Text *text)
Definition: text.c:1975
int txt_calc_tab_right(TextLine *tl, int ch)
Definition: text.c:884
void txt_jump_left(Text *text, const bool sel, const bool use_init_step)
Definition: text.c:993
void txt_move_left(Text *text, const bool sel)
Definition: text.c:905
void txt_duplicate_line(Text *text)
Definition: text.c:1854
bool txt_add_raw_char(Text *text, unsigned int add)
Definition: text.c:2033
static void txt_combine_lines(Text *text, TextLine *linea, TextLine *lineb)
Definition: text.c:1831
void txt_backspace_word(Text *text)
Definition: text.c:1963
static TextLine * txt_new_line(const char *str)
Definition: text.c:637
void txt_order_cursors(Text *text, const bool reverse)
Definition: text.c:1218
void txt_sel_clear(Text *text)
Definition: text.c:1301
static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs)
Definition: text.c:1985
void txt_move_up(Text *text, const bool sel)
Definition: text.c:804
bool text_check_whitespace(const char ch)
Definition: text.c:2481
static void txt_curs_sel(Text *text, TextLine ***linep, int **charp)
Definition: text.c:778
void txt_insert_buf(Text *text, const char *in_buffer)
Definition: text.c:1647
void txt_sel_line(Text *text)
Definition: text.c:1309
int text_find_identifier_start(const char *str, int i)
Definition: text.c:2489
static void txt_select_prefix(Text *text, const char *add, bool skip_blank_lines)
Definition: text.c:2094
void txt_delete_selected(Text *text)
Definition: text.c:2038
IDTypeInfo IDType_ID_TXT
Definition: text.c:239
bool text_check_identifier_nodigit(const char ch)
Definition: text.c:2449
int txt_extended_ascii_as_utf8(char **str)
Definition: text.c:307
static char tab_to_spaces[]
Definition: text.c:1973
uint len