6 * ***** BEGIN GPL LICENSE BLOCK *****
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23 * All rights reserved.
25 * The Original Code is: all of this file.
27 * Contributor(s): none yet.
29 * ***** END GPL LICENSE BLOCK *****
32 #include <string.h> /* strstr */
33 #include <sys/types.h>
36 #include "MEM_guardedalloc.h"
38 #include "BLI_blenlib.h"
39 #include "BLI_utildefines.h"
41 #include "DNA_constraint_types.h"
42 #include "DNA_controller_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_space_types.h"
46 #include "DNA_text_types.h"
47 #include "DNA_userdef_types.h"
48 #include "DNA_object_types.h"
50 #include "BKE_depsgraph.h"
51 #include "BKE_global.h"
52 #include "BKE_library.h"
58 #include "BPY_extern.h"
65 A text should relate to a file as follows -
66 (Text *)->name should be the place where the
67 file will or has been saved.
69 (Text *)->flags has the following bits
70 TXT_ISDIRTY - should always be set if the file in mem. differs from
71 the file on disk, or if there is no file on disk.
72 TXT_ISMEM - should always be set if the Text has not been mapped to
73 a file, in which case (Text *)->name may be NULL or garbage.
74 TXT_ISEXT - should always be set if the Text is not to be written into
76 TXT_ISSCRIPT - should be set if the user has designated the text
77 as a script. (NEW: this was unused, but now it is needed by
78 space handler script links (see header_view3d.c, for example)
80 ->>> see also: /makesdna/DNA_text_types.h
84 The st->top determines at what line the top of the text is displayed.
85 If the user moves the cursor the st containing that cursor should
86 be popped ... other st's retain their own top location.
90 The mrk->flags define the behaviour and relationships between markers. The
91 upper two bytes are used to hold a group ID, the lower two are normal flags. If
92 TMARK_EDITALL is set the group ID defines which other markers should be edited.
94 The mrk->clr field is used to visually group markers where the flags may not
95 match. A template system, for example, may allow editing of repeating tokens
96 (in one group) but include other marked positions (in another group) all in the
97 same template with the same color.
101 Undo/Redo works by storing
102 events in a queue, and a pointer
103 to the current position in the
106 Events are stored using an
107 arbitrary op-code system
109 a) the two cursors (normal and selected)
110 b) input (visible and control (ie backspace))
112 input data is stored as its
113 ASCII value, the opcodes are
114 then selected to not conflict.
116 opcodes with data in between are
117 written at the beginning and end
118 of the data to allow undo and redo
119 to simply check the code at the current
126 static void txt_pop_first(Text *text);
127 static void txt_pop_last(Text *text);
128 static void txt_undo_add_op(Text *text, int op);
129 static void txt_undo_add_block(Text *text, int op, const char *buf);
130 static void txt_delete_line(Text *text, TextLine *line);
131 static void txt_delete_sel (Text *text);
132 static void txt_make_dirty (Text *text);
136 static unsigned char undoing;
138 /* allow to switch off undoing externally */
139 void txt_set_undostate(int u)
144 int txt_get_undostate(void)
149 static void init_undo_text(Text *text)
152 text->undo_len= TXT_INIT_UNDO;
153 text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
156 void free_text(Text *text)
160 for (tmp= text->lines.first; tmp; tmp= tmp->next) {
161 MEM_freeN(tmp->line);
163 MEM_freeN(tmp->format);
166 BLI_freelistN(&text->lines);
167 BLI_freelistN(&text->markers);
169 if(text->name) MEM_freeN(text->name);
170 MEM_freeN(text->undo_buf);
172 if (text->compiled) BPY_text_free_code(text);
176 Text *add_empty_text(const char *name)
182 ta= alloc_libblock(&bmain->text, ID_TXT, name);
190 ta->flags= TXT_ISDIRTY | TXT_ISMEM;
191 if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
192 ta->flags |= TXT_TABSTOSPACES;
194 ta->lines.first= ta->lines.last= NULL;
195 ta->markers.first= ta->markers.last= NULL;
197 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
198 tmp->line= (char*) MEM_mallocN(1, "textline_string");
207 BLI_addhead(&ta->lines, tmp);
209 ta->curl= ta->lines.first;
211 ta->sell= ta->lines.first;
217 // this function removes any control characters from
220 static void cleanup_textline(TextLine * tl)
224 for (i = 0; i < tl->len; i++ ) {
225 if (tl->line[i] < ' ' && tl->line[i] != '\t') {
226 memmove(tl->line + i, tl->line + i + 1, tl->len - i);
233 int reopen_text(Text *text)
236 int i, llen, len, res;
237 unsigned char *buffer;
239 char str[FILE_MAXDIR+FILE_MAXFILE];
242 if (!text || !text->name) return 0;
244 BLI_strncpy(str, text->name, FILE_MAXDIR+FILE_MAXFILE);
245 BLI_path_abs(str, G.main->name);
248 if(fp==NULL) return 0;
252 for (tmp= text->lines.first; tmp; tmp= tmp->next) {
253 MEM_freeN(tmp->line);
254 if (tmp->format) MEM_freeN(tmp->format);
257 BLI_freelistN(&text->lines);
259 text->lines.first= text->lines.last= NULL;
260 text->curl= text->sell= NULL;
262 /* clear undo buffer */
263 MEM_freeN(text->undo_buf);
264 init_undo_text(text);
266 fseek(fp, 0L, SEEK_END);
268 fseek(fp, 0L, SEEK_SET);
272 buffer= MEM_mallocN(len, "text_buffer");
273 // under windows fread can return less then len bytes because
275 len = fread(buffer, 1, len, fp);
280 text->mtime= st.st_mtime;
285 for(i=0; i<len; i++) {
286 if (buffer[i]=='\n') {
287 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
288 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
291 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
295 cleanup_textline(tmp);
297 BLI_addtail(&text->lines, tmp);
306 if (llen!=0 || text->nlines==0) {
307 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
308 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
311 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
316 cleanup_textline(tmp);
318 BLI_addtail(&text->lines, tmp);
322 text->curl= text->sell= text->lines.first;
323 text->curc= text->selc= 0;
329 Text *add_text(const char *file, const char *relpath)
333 int i, llen, len, res;
334 unsigned char *buffer;
337 char str[FILE_MAXDIR+FILE_MAXFILE];
340 BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE);
341 if (relpath) /* can be NULL (bg mode) */
342 BLI_path_abs(str, relpath);
345 if(fp==NULL) return NULL;
347 ta= alloc_libblock(&bmain->text, ID_TXT, BLI_path_basename(str));
350 ta->lines.first= ta->lines.last= NULL;
351 ta->markers.first= ta->markers.last= NULL;
352 ta->curl= ta->sell= NULL;
354 if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
355 ta->flags= TXT_TABSTOSPACES;
357 fseek(fp, 0L, SEEK_END);
359 fseek(fp, 0L, SEEK_SET);
361 ta->name= MEM_mallocN(strlen(file)+1, "text_name");
362 strcpy(ta->name, file);
366 buffer= MEM_mallocN(len, "text_buffer");
367 // under windows fread can return less then len bytes because
369 len = fread(buffer, 1, len, fp);
374 ta->mtime= st.st_mtime;
379 for(i=0; i<len; i++) {
380 if (buffer[i]=='\n') {
381 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
382 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
385 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
389 cleanup_textline(tmp);
391 BLI_addtail(&ta->lines, tmp);
400 if (llen!=0 || ta->nlines==0) {
401 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
402 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
405 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
410 cleanup_textline(tmp);
412 BLI_addtail(&ta->lines, tmp);
416 ta->curl= ta->sell= ta->lines.first;
417 ta->curc= ta->selc= 0;
424 Text *copy_text(Text *ta)
427 TextLine *line, *tmp;
429 tan= copy_libblock(ta);
431 /* file name can be NULL */
433 tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name");
434 strcpy(tan->name, ta->name);
440 tan->flags = ta->flags | TXT_ISDIRTY;
442 tan->lines.first= tan->lines.last= NULL;
443 tan->markers.first= tan->markers.last= NULL;
444 tan->curl= tan->sell= NULL;
446 tan->nlines= ta->nlines;
448 line= ta->lines.first;
449 /* Walk down, reconstructing */
451 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
452 tmp->line= MEM_mallocN(line->len+1, "textline_string");
455 strcpy(tmp->line, line->line);
459 BLI_addtail(&tan->lines, tmp);
464 tan->curl= tan->sell= tan->lines.first;
465 tan->curc= tan->selc= 0;
472 void unlink_text(Main *bmain, Text *text)
484 for(scene=bmain->scene.first; scene; scene=scene->id.next)
485 if(scene->r.dometext == text)
486 scene->r.dometext = NULL;
488 for(ob=bmain->object.first; ob; ob=ob->id.next) {
489 /* game controllers */
490 for(cont=ob->controllers.first; cont; cont=cont->next) {
491 if(cont->type==CONT_PYTHON) {
495 if(pc->text==text) pc->text= NULL;
502 if(ob->type==OB_ARMATURE && ob->pose) {
504 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
505 for(con = pchan->constraints.first; con; con=con->next) {
506 if(con->type==CONSTRAINT_TYPE_PYTHON) {
507 bPythonConstraint *data = con->data;
508 if (data->text==text) data->text = NULL;
516 for(con = ob->constraints.first; con; con=con->next) {
517 if(con->type==CONSTRAINT_TYPE_PYTHON) {
518 bPythonConstraint *data = con->data;
519 if (data->text==text) data->text = NULL;
525 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
529 // XXX nodeDynamicUnlinkText(&text->id);
532 for(scr= bmain->screen.first; scr; scr= scr->id.next) {
533 for(area= scr->areabase.first; area; area= area->next) {
534 for(sl= area->spacedata.first; sl; sl= sl->next) {
535 if(sl->spacetype==SPACE_TEXT) {
536 SpaceText *st= (SpaceText*) sl;
550 void clear_text(Text *text) /* called directly from rna */
554 oldstate = txt_get_undostate( );
555 txt_set_undostate( 1 );
557 txt_delete_sel(text);
558 txt_set_undostate( oldstate );
560 txt_make_dirty(text);
563 void write_text(Text *text, const char *str) /* called directly from rna */
567 oldstate = txt_get_undostate( );
568 txt_insert_buf( text, str );
569 txt_move_eof( text, 0 );
570 txt_set_undostate( oldstate );
572 txt_make_dirty(text);
575 /*****************************/
576 /* Editing utility functions */
577 /*****************************/
579 static void make_new_line (TextLine *line, char *newline)
581 if (line->line) MEM_freeN(line->line);
582 if (line->format) MEM_freeN(line->format);
585 line->len= strlen(newline);
589 static TextLine *txt_new_line(const char *str)
595 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
596 tmp->line= MEM_mallocN(strlen(str)+1, "textline_string");
599 strcpy(tmp->line, str);
601 tmp->len= strlen(str);
602 tmp->next= tmp->prev= NULL;
607 static TextLine *txt_new_linen(const char *str, int n)
611 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
612 tmp->line= MEM_mallocN(n+1, "textline_string");
615 BLI_strncpy(tmp->line, (str)? str: "", n+1);
617 tmp->len= strlen(tmp->line);
618 tmp->next= tmp->prev= NULL;
623 void txt_clean_text (Text *text)
625 TextLine **top, **bot;
629 if (!text->lines.first) {
630 if (text->lines.last) text->lines.first= text->lines.last;
631 else text->lines.first= text->lines.last= txt_new_line(NULL);
634 if (!text->lines.last) text->lines.last= text->lines.first;
636 top= (TextLine **) &text->lines.first;
637 bot= (TextLine **) &text->lines.last;
639 while ((*top)->prev) *top= (*top)->prev;
640 while ((*bot)->next) *bot= (*bot)->next;
643 if(text->sell) text->curl= text->sell;
644 else text->curl= text->lines.first;
649 text->sell= text->curl;
654 int txt_get_span (TextLine *from, TextLine *to)
659 if (!to || !from) return 0;
660 if (from==to) return 0;
664 if (tmp == to) return ret;
674 if (tmp == to) break;
684 static void txt_make_dirty (Text *text)
686 text->flags |= TXT_ISDIRTY;
688 if (text->compiled) BPY_text_free_code(text);
692 /* 0:whitespace, 1:punct, 2:alphanumeric */
693 static short txt_char_type (char ch)
695 if (ch <= ' ') return 0; /* 32 */
696 if (ch <= '/') return 1; /* 47 */
697 if (ch <= '9') return 2; /* 57 */
698 if (ch <= '@') return 1; /* 64 */
699 if (ch <= 'Z') return 2; /* 90 */
700 if (ch == '_') return 2; /* 95, dont delimit '_' */
701 if (ch <= '`') return 1; /* 96 */
702 if (ch <= 'z') return 2; /* 122 */
706 /****************************/
707 /* Cursor utility functions */
708 /****************************/
710 static void txt_curs_cur (Text *text, TextLine ***linep, int **charp)
712 *linep= &text->curl; *charp= &text->curc;
715 static void txt_curs_sel (Text *text, TextLine ***linep, int **charp)
717 *linep= &text->sell; *charp= &text->selc;
720 static void txt_curs_first (Text *text, TextLine **linep, int *charp)
722 if (text->curl==text->sell) {
724 if (text->curc<text->selc) *charp= text->curc;
725 else *charp= text->selc;
726 } else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) {
735 /****************************/
736 /* Cursor movement functions */
737 /****************************/
739 void txt_move_up(Text *text, short sel)
745 if(sel) txt_curs_sel(text, &linep, &charp);
746 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
751 *linep= (*linep)->prev;
752 if (*charp > (*linep)->len) {
753 *charp= (*linep)->len;
754 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, (*linep)->next), old, txt_get_span(text->lines.first, *linep), (unsigned short) *charp);
756 if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
759 txt_move_bol(text, sel);
762 if(!sel) txt_pop_sel(text);
765 void txt_move_down(Text *text, short sel)
771 if(sel) txt_curs_sel(text, &linep, &charp);
772 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
777 *linep= (*linep)->next;
778 if (*charp > (*linep)->len) {
779 *charp= (*linep)->len;
780 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, (*linep)->prev), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
782 if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
784 txt_move_eol(text, sel);
787 if(!sel) txt_pop_sel(text);
790 void txt_move_left(Text *text, short sel)
793 int *charp, oundoing= undoing;
796 if(sel) txt_curs_sel(text, &linep, &charp);
797 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
802 if ((*linep)->prev) {
803 txt_move_up(text, sel);
804 *charp= (*linep)->len;
810 if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
812 if(!sel) txt_pop_sel(text);
815 void txt_move_right(Text *text, short sel)
818 int *charp, oundoing= undoing;
821 if(sel) txt_curs_sel(text, &linep, &charp);
822 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
826 if (*charp== (*linep)->len) {
827 if ((*linep)->next) {
828 txt_move_down(text, sel);
835 if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
837 if(!sel) txt_pop_sel(text);
840 void txt_jump_left(Text *text, short sel)
842 TextLine **linep, *oldl;
843 int *charp, oldc, count, i;
847 if(sel) txt_curs_sel(text, &linep, &charp);
848 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
854 undoing= 1; /* Don't push individual moves to undo stack */
857 for (i=0; i<3; i++) {
859 while (*charp>0 && txt_char_type((*linep)->line[*charp-1])==i) {
860 txt_move_left(text, sel);
865 if (count==0) txt_move_left(text, sel);
868 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
871 void txt_jump_right(Text *text, short sel)
873 TextLine **linep, *oldl;
874 int *charp, oldc, count, i;
878 if(sel) txt_curs_sel(text, &linep, &charp);
879 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
885 undoing= 1; /* Don't push individual moves to undo stack */
888 for (i=0; i<3; i++) {
890 while (*charp<(*linep)->len && txt_char_type((*linep)->line[*charp])==i) {
891 txt_move_right(text, sel);
896 if (count==0) txt_move_right(text, sel);
899 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
902 void txt_move_bol (Text *text, short sel)
908 if(sel) txt_curs_sel(text, &linep, &charp);
909 else txt_curs_cur(text, &linep, &charp);
915 if(!sel) txt_pop_sel(text);
916 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
919 void txt_move_eol (Text *text, short sel)
925 if(sel) txt_curs_sel(text, &linep, &charp);
926 else txt_curs_cur(text, &linep, &charp);
930 *charp= (*linep)->len;
932 if(!sel) txt_pop_sel(text);
933 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
936 void txt_move_bof (Text *text, short sel)
942 if(sel) txt_curs_sel(text, &linep, &charp);
943 else txt_curs_cur(text, &linep, &charp);
947 *linep= text->lines.first;
950 if(!sel) txt_pop_sel(text);
951 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
954 void txt_move_eof (Text *text, short sel)
960 if(sel) txt_curs_sel(text, &linep, &charp);
961 else txt_curs_cur(text, &linep, &charp);
965 *linep= text->lines.last;
966 *charp= (*linep)->len;
968 if(!sel) txt_pop_sel(text);
969 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
972 void txt_move_toline (Text *text, unsigned int line, short sel)
974 txt_move_to(text, line, 0, sel);
977 void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel)
979 TextLine **linep, *oldl;
984 if(sel) txt_curs_sel(text, &linep, &charp);
985 else txt_curs_cur(text, &linep, &charp);
990 *linep= text->lines.first;
991 for (i=0; i<line; i++) {
992 if ((*linep)->next) *linep= (*linep)->next;
995 if (ch>(unsigned int)((*linep)->len))
996 ch= (unsigned int)((*linep)->len);
999 if(!sel) txt_pop_sel(text);
1000 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
1003 /****************************/
1004 /* Text selection functions */
1005 /****************************/
1007 static void txt_curs_swap (Text *text)
1013 text->curl= text->sell;
1017 text->curc= text->selc;
1020 if(!undoing) txt_undo_add_op(text, UNDO_SWAP);
1023 static void txt_pop_first (Text *text)
1026 if (txt_get_span(text->curl, text->sell)<0 ||
1027 (text->curl==text->sell && text->curc>text->selc)) {
1028 txt_curs_swap(text);
1031 if(!undoing) txt_undo_add_toop(text, UNDO_STO,
1032 txt_get_span(text->lines.first, text->sell),
1034 txt_get_span(text->lines.first, text->curl),
1040 static void txt_pop_last (Text *text)
1042 if (txt_get_span(text->curl, text->sell)>0 ||
1043 (text->curl==text->sell && text->curc<text->selc)) {
1044 txt_curs_swap(text);
1047 if(!undoing) txt_undo_add_toop(text, UNDO_STO,
1048 txt_get_span(text->lines.first, text->sell),
1050 txt_get_span(text->lines.first, text->curl),
1056 /* never used: CVS 1.19 */
1057 /* static void txt_pop_selr (Text *text) */
1059 void txt_pop_sel (Text *text)
1061 text->sell= text->curl;
1062 text->selc= text->curc;
1065 void txt_order_cursors(Text *text)
1068 if (!text->curl) return;
1069 if (!text->sell) return;
1071 /* Flip so text->curl is before text->sell */
1072 if (txt_get_span(text->curl, text->sell)<0 ||
1073 (text->curl==text->sell && text->curc>text->selc))
1074 txt_curs_swap(text);
1077 int txt_has_sel(Text *text)
1079 return ((text->curl!=text->sell) || (text->curc!=text->selc));
1082 static void txt_delete_sel (Text *text)
1090 if (!text->curl) return;
1091 if (!text->sell) return;
1093 if (!txt_has_sel(text)) return;
1095 txt_order_cursors(text);
1098 buf= txt_sel_to_buf(text);
1099 txt_undo_add_block(text, UNDO_DBLOCK, buf);
1103 buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
1105 if (text->curl != text->sell) {
1106 txt_clear_marker_region(text, text->curl, text->curc, text->curl->len, 0, 0);
1107 move= txt_get_span(text->curl, text->sell);
1109 mrk= txt_find_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
1110 if (mrk && (mrk->start > text->curc || mrk->end < text->selc))
1111 txt_clear_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
1115 mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0);
1117 lineno= mrk->lineno;
1119 mrk->lineno -= move;
1120 if (mrk->start > text->curc) mrk->start -= text->selc - text->curc;
1121 mrk->end -= text->selc - text->curc;
1123 } while (mrk && mrk->lineno==lineno);
1126 strncpy(buf, text->curl->line, text->curc);
1127 strcpy(buf+text->curc, text->sell->line + text->selc);
1128 buf[text->curc+(text->sell->len - text->selc)]=0;
1130 make_new_line(text->curl, buf);
1133 while (tmpl != text->curl) {
1137 txt_delete_line(text, tmpl->next);
1140 text->sell= text->curl;
1141 text->selc= text->curc;
1144 void txt_sel_all (Text *text)
1148 text->curl= text->lines.first;
1151 text->sell= text->lines.last;
1152 text->selc= text->sell->len;
1155 void txt_sel_line (Text *text)
1158 if (!text->curl) return;
1161 text->sell= text->curl;
1162 text->selc= text->sell->len;
1165 /***************************/
1166 /* Cut and paste functions */
1167 /***************************/
1169 char *txt_to_buf (Text *text)
1172 TextLine *tmp, *linef, *linel;
1176 if (!text) return NULL;
1177 if (!text->curl) return NULL;
1178 if (!text->sell) return NULL;
1179 if (!text->lines.first) return NULL;
1181 linef= text->lines.first;
1184 linel= text->lines.last;
1187 if (linef == text->lines.last) {
1188 length= charl-charf;
1190 buf= MEM_mallocN(length+2, "text buffer");
1192 BLI_strncpy(buf, linef->line + charf, length+1);
1195 length= linef->len - charf;
1197 length+= 2; /* For the 2 '\n' */
1200 while (tmp && tmp!= linel) {
1201 length+= tmp->len+1;
1205 buf= MEM_mallocN(length+1, "cut buffer");
1207 strncpy(buf, linef->line + charf, linef->len-charf);
1208 length= linef->len - charf;
1213 while (tmp && tmp!=linel) {
1214 strncpy(buf+length, tmp->line, tmp->len);
1221 strncpy(buf+length, linel->line, charl);
1224 /* python compiler wants an empty end line */
1232 int txt_find_string(Text *text, char *findstr, int wrap)
1234 TextLine *tl, *startl;
1238 if (!text || !text->curl || !text->sell) return 0;
1240 txt_order_cursors(text);
1242 oldcl= txt_get_span(text->lines.first, text->curl);
1243 oldsl= txt_get_span(text->lines.first, text->sell);
1244 tl= startl= text->sell;
1246 s= strstr(&tl->line[text->selc], findstr);
1251 tl= text->lines.first;
1256 s= strstr(tl->line, findstr);
1262 int newl= txt_get_span(text->lines.first, tl);
1263 int newc= (int)(s-tl->line);
1264 txt_move_to(text, newl, newc, 0);
1265 txt_move_to(text, newl, newc + strlen(findstr), 1);
1271 char *txt_sel_to_buf (Text *text)
1275 TextLine *tmp, *linef, *linel;
1278 if (!text) return NULL;
1279 if (!text->curl) return NULL;
1280 if (!text->sell) return NULL;
1282 if (text->curl==text->sell) {
1283 linef= linel= text->curl;
1285 if (text->curc < text->selc) {
1292 } else if (txt_get_span(text->curl, text->sell)<0) {
1306 if (linef == linel) {
1307 length= charl-charf;
1309 buf= MEM_mallocN(length+1, "sel buffer");
1311 BLI_strncpy(buf, linef->line + charf, length+1);
1313 length+= linef->len - charf;
1315 length++; /* For the '\n' */
1318 while (tmp && tmp!= linel) {
1319 length+= tmp->len+1;
1323 buf= MEM_mallocN(length+1, "sel buffer");
1325 strncpy(buf, linef->line+ charf, linef->len-charf);
1326 length= linef->len-charf;
1331 while (tmp && tmp!=linel) {
1332 strncpy(buf+length, tmp->line, tmp->len);
1339 strncpy(buf+length, linel->line, charl);
1348 void txt_insert_buf(Text *text, const char *in_buffer)
1350 int i=0, l=0, j, u, len;
1354 if (!in_buffer) return;
1356 txt_delete_sel(text);
1358 if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer);
1363 /* Read the first line (or as close as possible */
1364 while (in_buffer[i] && in_buffer[i]!='\n') {
1365 txt_add_char(text, in_buffer[i]);
1369 if (in_buffer[i]=='\n') txt_split_curline(text);
1370 else { undoing = u; return; }
1373 /* Read as many full lines as we can */
1374 len= strlen(in_buffer);
1379 while (in_buffer[i] && in_buffer[i]!='\n') {
1383 if(in_buffer[i]=='\n') {
1384 add= txt_new_linen(in_buffer +(i-l), l);
1385 BLI_insertlinkbefore(&text->lines, text->curl, add);
1388 for (j= i-l; j<i && j<(int)strlen(in_buffer); j++) {
1389 txt_add_char(text, in_buffer[j]);
1398 /******************/
1399 /* Undo functions */
1400 /******************/
1402 static int max_undo_test(Text *text, int x)
1404 while (text->undo_pos+x >= text->undo_len) {
1405 if(text->undo_len*2 > TXT_MAX_UNDO) {
1406 /* XXX error("Undo limit reached, buffer cleared\n"); */
1407 MEM_freeN(text->undo_buf);
1408 init_undo_text(text);
1411 void *tmp= text->undo_buf;
1412 text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf");
1413 memcpy(text->undo_buf, tmp, text->undo_len);
1422 static void dump_buffer(Text *text)
1426 while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
1429 void txt_print_undo(Text *text)
1438 printf ("---< Undo Buffer >---\n");
1440 printf ("UndoPosition is %d\n", text->undo_pos);
1442 while (i<=text->undo_pos) {
1443 op= text->undo_buf[i];
1445 if (op==UNDO_CLEFT) {
1447 } else if (op==UNDO_CRIGHT) {
1448 ops= "Cursor right";
1449 } else if (op==UNDO_CUP) {
1451 } else if (op==UNDO_CDOWN) {
1453 } else if (op==UNDO_SLEFT) {
1454 ops= "Selection left";
1455 } else if (op==UNDO_SRIGHT) {
1456 ops= "Selection right";
1457 } else if (op==UNDO_SUP) {
1458 ops= "Selection up";
1459 } else if (op==UNDO_SDOWN) {
1460 ops= "Selection down";
1461 } else if (op==UNDO_STO) {
1463 } else if (op==UNDO_CTO) {
1465 } else if (op==UNDO_INSERT) {
1467 } else if (op==UNDO_BS) {
1469 } else if (op==UNDO_DEL) {
1471 } else if (op==UNDO_SWAP) {
1473 } else if (op==UNDO_DBLOCK) {
1474 ops= "Delete text block";
1475 } else if (op==UNDO_IBLOCK) {
1476 ops= "Insert text block";
1477 } else if (op==UNDO_INDENT) {
1479 } else if (op==UNDO_UNINDENT) {
1481 } else if (op==UNDO_COMMENT) {
1483 } else if (op==UNDO_UNCOMMENT) {
1489 printf ("Op (%o) at %d = %s", op, i, ops);
1490 if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) {
1492 printf (" - Char is %c", text->undo_buf[i]);
1494 } else if (op==UNDO_STO || op==UNDO_CTO) {
1497 charp= text->undo_buf[i]; i++;
1498 charp= charp+(text->undo_buf[i]<<8); i++;
1500 linep= text->undo_buf[i]; i++;
1501 linep= linep+(text->undo_buf[i]<<8); i++;
1502 linep= linep+(text->undo_buf[i]<<16); i++;
1503 linep= linep+(text->undo_buf[i]<<24); i++;
1505 printf ("to <%d, %d> ", linep, charp);
1507 charp= text->undo_buf[i]; i++;
1508 charp= charp+(text->undo_buf[i]<<8); i++;
1510 linep= text->undo_buf[i]; i++;
1511 linep= linep+(text->undo_buf[i]<<8); i++;
1512 linep= linep+(text->undo_buf[i]<<16); i++;
1513 linep= linep+(text->undo_buf[i]<<24); i++;
1515 printf ("from <%d, %d>", linep, charp);
1516 } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
1519 linep= text->undo_buf[i]; i++;
1520 linep= linep+(text->undo_buf[i]<<8); i++;
1521 linep= linep+(text->undo_buf[i]<<16); i++;
1522 linep= linep+(text->undo_buf[i]<<24); i++;
1524 printf (" (length %d) <", linep);
1527 putchar(text->undo_buf[i]);
1531 linep= text->undo_buf[i]; i++;
1532 linep= linep+(text->undo_buf[i]<<8); i++;
1533 linep= linep+(text->undo_buf[i]<<16); i++;
1534 linep= linep+(text->undo_buf[i]<<24); i++;
1535 printf ("> (%d)", linep);
1536 } else if (op==UNDO_INDENT || op==UNDO_UNINDENT) {
1539 charp= text->undo_buf[i]; i++;
1540 charp= charp+(text->undo_buf[i]<<8); i++;
1542 linep= text->undo_buf[i]; i++;
1543 linep= linep+(text->undo_buf[i]<<8); i++;
1544 linep= linep+(text->undo_buf[i]<<16); i++;
1545 linep= linep+(text->undo_buf[i]<<24); i++;
1547 printf ("to <%d, %d> ", linep, charp);
1549 charp= text->undo_buf[i]; i++;
1550 charp= charp+(text->undo_buf[i]<<8); i++;
1552 linep= text->undo_buf[i]; i++;
1553 linep= linep+(text->undo_buf[i]<<8); i++;
1554 linep= linep+(text->undo_buf[i]<<16); i++;
1555 linep= linep+(text->undo_buf[i]<<24); i++;
1557 printf ("from <%d, %d>", linep, charp);
1560 printf (" %d\n", i);
1565 static void txt_undo_add_op(Text *text, int op)
1567 if(!max_undo_test(text, 2))
1571 text->undo_buf[text->undo_pos]= op;
1572 text->undo_buf[text->undo_pos+1]= 0;
1575 static void txt_undo_add_block(Text *text, int op, const char *buf)
1579 length= strlen(buf);
1581 if(!max_undo_test(text, length+11))
1585 text->undo_buf[text->undo_pos]= op;
1588 text->undo_buf[text->undo_pos]= (length)&0xff;
1590 text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1592 text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1594 text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1597 strncpy(text->undo_buf+text->undo_pos, buf, length);
1598 text->undo_pos+=length;
1600 text->undo_buf[text->undo_pos]= (length)&0xff;
1602 text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1604 text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1606 text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1609 text->undo_buf[text->undo_pos]= op;
1611 text->undo_buf[text->undo_pos+1]= 0;
1614 void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
1616 if(!max_undo_test(text, 15))
1619 if (froml==tol && fromc==toc) return;
1622 text->undo_buf[text->undo_pos]= op;
1625 text->undo_buf[text->undo_pos]= (fromc)&0xff;
1627 text->undo_buf[text->undo_pos]= (fromc>>8)&0xff;
1630 text->undo_buf[text->undo_pos]= (froml)&0xff;
1632 text->undo_buf[text->undo_pos]= (froml>>8)&0xff;
1634 text->undo_buf[text->undo_pos]= (froml>>16)&0xff;
1636 text->undo_buf[text->undo_pos]= (froml>>24)&0xff;
1639 text->undo_buf[text->undo_pos]= (toc)&0xff;
1641 text->undo_buf[text->undo_pos]= (toc>>8)&0xff;
1644 text->undo_buf[text->undo_pos]= (tol)&0xff;
1646 text->undo_buf[text->undo_pos]= (tol>>8)&0xff;
1648 text->undo_buf[text->undo_pos]= (tol>>16)&0xff;
1650 text->undo_buf[text->undo_pos]= (tol>>24)&0xff;
1653 text->undo_buf[text->undo_pos]= op;
1655 text->undo_buf[text->undo_pos+1]= 0;
1658 static void txt_undo_add_charop(Text *text, int op, char c)
1660 if(!max_undo_test(text, 4))
1664 text->undo_buf[text->undo_pos]= op;
1666 text->undo_buf[text->undo_pos]= c;
1668 text->undo_buf[text->undo_pos]= op;
1669 text->undo_buf[text->undo_pos+1]= 0;
1672 void txt_do_undo(Text *text)
1674 int op= text->undo_buf[text->undo_pos];
1675 unsigned int linep, i;
1676 unsigned short charp;
1681 if (text->undo_pos<0) {
1691 txt_move_right(text, 0);
1695 txt_move_left(text, 0);
1699 txt_move_down(text, 0);
1703 txt_move_up(text, 0);
1707 txt_move_right(text, 1);
1711 txt_move_left(text, 1);
1715 txt_move_down(text, 1);
1719 txt_move_up(text, 1);
1732 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1733 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1734 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1735 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1737 charp= text->undo_buf[text->undo_pos]; text->undo_pos--;
1738 charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1741 txt_move_toline(text, linep, 0);
1745 txt_move_toline(text, linep, 1);
1753 txt_backspace_char(text);
1759 txt_add_char(text, text->undo_buf[text->undo_pos]);
1765 txt_add_char(text, text->undo_buf[text->undo_pos]);
1766 txt_move_left(text, 0);
1772 txt_curs_swap(text);
1776 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1777 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1778 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1779 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1781 buf= MEM_mallocN(linep+1, "dblock buffer");
1782 for (i=0; i < linep; i++){
1783 buf[(linep-1)-i]= text->undo_buf[text->undo_pos];
1788 txt_curs_first(text, &holdl, &holdc);
1789 holdln= txt_get_span(text->lines.first, holdl);
1791 txt_insert_buf(text, buf);
1794 text->curl= text->lines.first;
1796 if(text->curl->next)
1797 text->curl= text->curl->next;
1803 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1804 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1805 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1806 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1813 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1814 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1815 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1816 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1818 txt_delete_sel(text);
1820 txt_backspace_char(text);
1836 case UNDO_UNCOMMENT:
1837 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1838 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1839 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1840 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1841 //linep is now the end line of the selection
1843 charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1844 charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1845 //charp is the last char selected or text->line->len
1846 //set the selcetion for this now
1848 text->sell = text->lines.first;
1849 for (i= 0; i < linep; i++) {
1850 text->sell = text->sell->next;
1853 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1854 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1855 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1856 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1857 //first line to be selected
1859 charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1860 charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1861 //first postion to be selected
1863 text->curl = text->lines.first;
1864 for (i = 0; i < linep; i++) {
1865 text->curl = text->curl->next;
1869 if (op==UNDO_INDENT) {
1871 } else if (op== UNDO_UNINDENT) {
1873 } else if (op == UNDO_COMMENT) {
1875 } else if (op == UNDO_UNCOMMENT) {
1882 //XXX error("Undo buffer error - resetting");
1888 /* next undo step may need evaluating */
1889 if (text->undo_pos>=0) {
1890 switch (text->undo_buf[text->undo_pos]) {
1893 txt_do_redo(text); /* selections need restoring */
1896 txt_do_undo(text); /* swaps should appear transparent */
1904 void txt_do_redo(Text *text)
1907 unsigned int linep, i;
1908 unsigned short charp;
1912 op= text->undo_buf[text->undo_pos];
1923 txt_move_left(text, 0);
1927 txt_move_right(text, 0);
1931 txt_move_up(text, 0);
1935 txt_move_down(text, 0);
1939 txt_move_left(text, 1);
1943 txt_move_right(text, 1);
1947 txt_move_up(text, 1);
1951 txt_move_down(text, 1);
1956 txt_add_char(text, text->undo_buf[text->undo_pos]);
1962 txt_backspace_char(text);
1968 txt_delete_char(text);
1973 txt_curs_swap(text);
1974 txt_do_redo(text); /* swaps should appear transparent a*/
1989 charp= text->undo_buf[text->undo_pos];
1991 charp= charp+(text->undo_buf[text->undo_pos]<<8);
1994 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1995 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1996 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1997 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2000 txt_move_toline(text, linep, 0);
2004 txt_move_toline(text, linep, 1);
2012 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2013 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2014 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2015 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2017 txt_delete_sel(text);
2018 text->undo_pos+=linep;
2029 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2030 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2031 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2032 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2034 buf= MEM_mallocN(linep+1, "iblock buffer");
2035 memcpy (buf, &text->undo_buf[text->undo_pos], linep);
2036 text->undo_pos+= linep;
2039 txt_insert_buf(text, buf);
2042 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2043 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2044 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2045 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2051 case UNDO_UNCOMMENT:
2053 charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2054 charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2055 //charp is the first char selected or 0
2057 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2058 linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2059 linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2060 linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2061 //linep is now the first line of the selection
2062 //set the selcetion for this now
2064 text->curl = text->lines.first;
2065 for (i= 0; i < linep; i++) {
2066 text->curl = text->curl->next;
2069 charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2070 charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2071 //last postion to be selected
2072 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2073 linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2074 linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2075 linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2076 //Last line to be selected
2079 text->sell = text->lines.first;
2080 for (i = 0; i < linep; i++) {
2081 text->sell = text->sell->next;
2084 if (op==UNDO_INDENT) {
2086 } else if (op== UNDO_UNINDENT) {
2088 } else if (op == UNDO_COMMENT) {
2090 } else if (op == UNDO_UNCOMMENT) {
2095 //XXX error("Undo buffer error - resetting");
2104 /**************************/
2105 /* Line editing functions */
2106 /**************************/
2108 void txt_split_curline (Text *text)
2116 if (!text->curl) return;
2118 txt_delete_sel(text);
2122 lineno= txt_get_span(text->lines.first, text->curl);
2123 mrk= text->markers.first;
2125 if (mrk->lineno==lineno && mrk->start>text->curc) {
2127 mrk->start -= text->curc;
2128 mrk->end -= text->curc;
2129 } else if (mrk->lineno > lineno) {
2135 /* Make the two half strings */
2137 left= MEM_mallocN(text->curc+1, "textline_string");
2138 if (text->curc) memcpy(left, text->curl->line, text->curc);
2141 right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
2142 if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc);
2143 right[text->curl->len - text->curc]=0;
2145 MEM_freeN(text->curl->line);
2146 if (text->curl->format) MEM_freeN(text->curl->format);
2148 /* Make the new TextLine */
2150 ins= MEM_mallocN(sizeof(TextLine), "textline");
2153 ins->len= text->curc;
2155 text->curl->line= right;
2156 text->curl->format= NULL;
2157 text->curl->len= text->curl->len - text->curc;
2159 BLI_insertlinkbefore(&text->lines, text->curl, ins);
2163 txt_make_dirty(text);
2164 txt_clean_text(text);
2167 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n');
2170 static void txt_delete_line (Text *text, TextLine *line)
2172 TextMarker *mrk=NULL, *nxt;
2176 if (!text->curl) return;
2178 lineno= txt_get_span(text->lines.first, line);
2179 mrk= text->markers.first;
2182 if (mrk->lineno==lineno)
2183 BLI_freelinkN(&text->markers, mrk);
2184 else if (mrk->lineno > lineno)
2189 BLI_remlink (&text->lines, line);
2191 if (line->line) MEM_freeN(line->line);
2192 if (line->format) MEM_freeN(line->format);
2196 txt_make_dirty(text);
2197 txt_clean_text(text);
2200 static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
2203 TextMarker *mrk= NULL;
2208 if(!linea || !lineb) return;
2210 mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0);
2212 lineno= mrk->lineno;
2215 mrk->start += linea->len;
2216 mrk->end += linea->len;
2218 } while (mrk && mrk->lineno==lineno);
2220 if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb);
2221 if (!mrk) mrk= text->markers.first;
2223 tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
2225 strcpy(tmp, linea->line);
2226 strcat(tmp, lineb->line);
2228 make_new_line(linea, tmp);
2230 txt_delete_line(text, lineb);
2232 txt_make_dirty(text);
2233 txt_clean_text(text);
2236 void txt_delete_char (Text *text)
2241 if (!text->curl) return;
2243 if (txt_has_sel(text)) { /* deleting a selection */
2244 txt_delete_sel(text);
2245 txt_make_dirty(text);
2248 else if (text->curc== text->curl->len) { /* Appending two lines */
2249 if (text->curl->next) {
2250 txt_combine_lines(text, text->curl, text->curl->next);
2253 } else { /* Just deleting a char */
2256 TextMarker *mrk= txt_find_marker_region(text, text->curl, i-1, text->curl->len, 0, 0);
2258 int lineno= mrk->lineno;
2260 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2261 txt_clear_markers(text, mrk->group, TMARK_TEMP);
2263 BLI_freelinkN(&text->markers, mrk);
2268 if (mrk->start>i) mrk->start--;
2271 } while (mrk && mrk->lineno==lineno);
2274 c= text->curl->line[i];
2275 while(i< text->curl->len) {
2276 text->curl->line[i]= text->curl->line[i+1];
2284 txt_make_dirty(text);
2285 txt_clean_text(text);
2287 if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c);
2290 void txt_delete_word (Text *text)
2292 txt_jump_right(text, 1);
2293 txt_delete_sel(text);
2296 void txt_backspace_char (Text *text)
2301 if (!text->curl) return;
2303 if (txt_has_sel(text)) { /* deleting a selection */
2304 txt_delete_sel(text);
2305 txt_make_dirty(text);
2308 else if (text->curc==0) { /* Appending two lines */
2309 if (!text->curl->prev) return;
2311 text->curl= text->curl->prev;
2312 text->curc= text->curl->len;
2314 txt_combine_lines(text, text->curl, text->curl->next);
2317 else { /* Just backspacing a char */
2318 int i= text->curc-1;
2320 TextMarker *mrk= txt_find_marker_region(text, text->curl, i, text->curl->len, 0, 0);
2322 int lineno= mrk->lineno;
2323 if (mrk->start==i+1) {
2324 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2325 txt_clear_markers(text, mrk->group, TMARK_TEMP);
2327 BLI_freelinkN(&text->markers, mrk);
2332 if (mrk->start>i) mrk->start--;
2335 } while (mrk && mrk->lineno==lineno);
2338 c= text->curl->line[i];
2339 while(i< text->curl->len) {
2340 text->curl->line[i]= text->curl->line[i+1];
2349 txt_make_dirty(text);
2350 txt_clean_text(text);
2352 if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
2355 void txt_backspace_word (Text *text)
2357 txt_jump_left(text, 1);
2358 txt_delete_sel(text);
2361 /* Max spaces to replace a tab with, currently hardcoded to TXT_TABSIZE = 4.
2362 * Used by txt_convert_tab_to_spaces, indent and unintent.
2363 * Remember to change this string according to max tab size */
2364 static char tab_to_spaces[] = " ";
2366 static void txt_convert_tab_to_spaces (Text *text)
2368 /* sb aims to pad adjust the tab-width needed so that the right number of spaces
2369 * is added so that the indention of the line is the right width (i.e. aligned
2370 * to multiples of TXT_TABSIZE)
2372 char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
2373 txt_insert_buf(text, sb);
2376 int txt_add_char (Text *text, char add)
2382 if (!text) return 0;
2383 if (!text->curl) return 0;
2386 txt_split_curline(text);
2390 /* insert spaces rather then tabs */
2391 if (add == '\t' && text->flags & TXT_TABSTOSPACES) {
2392 txt_convert_tab_to_spaces(text);
2396 txt_delete_sel(text);
2398 mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0);
2400 lineno= mrk->lineno;
2402 if (mrk->start>text->curc) mrk->start++;
2405 } while (mrk && mrk->lineno==lineno);
2408 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2410 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2411 tmp[text->curc]= add;
2413 len= text->curl->len - text->curc;
2414 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2415 tmp[text->curl->len+1]=0;
2416 make_new_line(text->curl, tmp);
2422 txt_make_dirty(text);
2423 txt_clean_text(text);
2425 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add);
2429 void txt_delete_selected(Text *text)
2431 txt_delete_sel(text);
2432 txt_make_dirty(text);
2435 int txt_replace_char (Text *text, char add)
2439 if (!text) return 0;
2440 if (!text->curl) return 0;
2442 /* If text is selected or we're at the end of the line just use txt_add_char */
2443 if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') {
2445 int i= txt_add_char(text, add);
2446 mrk= txt_find_marker(text, text->curl, text->curc, 0, 0);
2447 if (mrk && mrk->end==text->curc) mrk->end--;
2451 del= text->curl->line[text->curc];
2452 text->curl->line[text->curc]= (unsigned char) add;
2456 txt_make_dirty(text);
2457 txt_clean_text(text);
2459 /* Should probably create a new op for this */
2461 txt_undo_add_charop(text, UNDO_DEL, del);
2462 txt_undo_add_charop(text, UNDO_INSERT, add);
2467 void indent(Text *text)
2472 const char *add = "\t";
2475 /* hardcoded: TXT_TABSIZE = 4 spaces: */
2476 int spaceslen = TXT_TABSIZE;
2478 /* insert spaces rather then tabs */
2479 if (text->flags & TXT_TABSTOSPACES){
2480 add = tab_to_spaces;
2481 indentlen = spaceslen;
2485 if (!text->curl) return;
2486 if (!text->sell) return;
2491 tmp= MEM_mallocN(text->curl->len+indentlen+1, "textline_string");
2494 if(text->curc) memcpy(tmp, text->curl->line, text->curc); /* XXX never true, check prev line */
2495 memcpy(tmp+text->curc, add, indentlen);
2497 len= text->curl->len - text->curc;
2498 if(len>0) memcpy(tmp+text->curc+indentlen, text->curl->line+text->curc, len);
2499 tmp[text->curl->len+indentlen]= 0;
2501 make_new_line(text->curl, tmp);
2503 text->curc+= indentlen;
2505 txt_make_dirty(text);
2506 txt_clean_text(text);
2508 if(text->curl == text->sell)
2510 text->selc = text->sell->len;
2513 text->curl = text->curl->next;
2520 text->curl = text->curl->prev;
2526 txt_undo_add_toop(text, UNDO_INDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2530 void unindent(Text *text)
2533 const char *remove = "\t";
2536 /* hardcoded: TXT_TABSIZE = 4 spaces: */
2537 int spaceslen = TXT_TABSIZE;
2539 /* insert spaces rather then tabs */
2540 if (text->flags & TXT_TABSTOSPACES){
2541 remove = tab_to_spaces;
2546 if (!text->curl) return;
2547 if (!text->sell) return;
2553 if (BLI_strncasecmp(text->curl->line, remove, indent) == 0)
2555 while(i< text->curl->len) {
2556 text->curl->line[i]= text->curl->line[i+indent];
2559 text->curl->len-= indent;
2562 txt_make_dirty(text);
2563 txt_clean_text(text);
2565 if(text->curl == text->sell)
2567 text->selc = text->sell->len;
2570 text->curl = text->curl->next;
2578 text->curl = text->curl->prev;
2584 txt_undo_add_toop(text, UNDO_UNINDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2588 void comment(Text *text)
2595 if (!text->curl) return;
2596 if (!text->sell) return;// Need to change this need to check if only one line is selected ot more then one
2601 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2604 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2605 tmp[text->curc]= add;
2607 len= text->curl->len - text->curc;
2608 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2609 tmp[text->curl->len+1]=0;
2611 make_new_line(text->curl, tmp);
2615 txt_make_dirty(text);
2616 txt_clean_text(text);
2618 if(text->curl == text->sell)
2620 text->selc = text->sell->len;
2623 text->curl = text->curl->next;
2630 text->curl = text->curl->prev;
2636 txt_undo_add_toop(text, UNDO_COMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2640 void uncomment(Text *text)
2646 if (!text->curl) return;
2647 if (!text->sell) return;
2653 if (text->curl->line[i] == remove)
2655 while(i< text->curl->len) {
2656 text->curl->line[i]= text->curl->line[i+1];
2663 txt_make_dirty(text);
2664 txt_clean_text(text);
2666 if(text->curl == text->sell)
2668 text->selc = text->sell->len;
2671 text->curl = text->curl->next;
2679 text->curl = text->curl->prev;
2685 txt_undo_add_toop(text, UNDO_UNCOMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2689 int setcurr_tab_spaces (Text *text, int space)
2693 const char *word = ":";
2694 const char *comm = "#";
2695 const char indent= (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t';
2696 static const char *back_words[]= {"return", "break", "continue", "pass", "yield", NULL};
2697 if (!text) return 0;
2698 if (!text->curl) return 0;
2700 while (text->curl->line[i] == indent)
2702 //we only count those tabs/spaces that are before any text or before the curs;
2703 if (i == text->curc)
2710 if(strstr(text->curl->line, word))
2712 /* if we find a ':' on this line, then add a tab but not if it is:
2714 * 2) within an identifier
2715 * 3) after the cursor (text->curc), i.e. when creating space before a function def [#25414]
2718 for(a=0; (a < text->curc) && (text->curl->line[a] != '\0'); a++)
2720 if (text->curl->line[a]=='#') {
2722 } else if (text->curl->line[a]==':') {
2724 } else if (text->curl->line[a]==']') {
2733 for(test=0; back_words[test]; test++)
2735 /* if there are these key words then remove a tab because we are done with the block */
2736 if(strstr(text->curl->line, back_words[test]) && i > 0)
2738 if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
2747 /*********************************/
2748 /* Text marker utility functions */
2749 /*********************************/
2751 /* Creates and adds a marker to the list maintaining sorted order */
2752 void txt_add_marker(Text *text, TextLine *line, int start, int end, const unsigned char color[4], int group, int flags) {
2753 TextMarker *tmp, *marker;
2755 marker= MEM_mallocN(sizeof(TextMarker), "text_marker");
2757 marker->lineno= txt_get_span(text->lines.first, line);
2758 marker->start= MIN2(start, end);
2759 marker->end= MAX2(start, end);
2760 marker->group= group;
2761 marker->flags= flags;
2763 marker->color[0]= color[0];
2764 marker->color[1]= color[1];
2765 marker->color[2]= color[2];
2766 marker->color[3]= color[3];
2768 for (tmp=text->markers.last; tmp; tmp=tmp->prev)
2769 if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start))
2772 if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker);
2773 else BLI_addhead(&text->markers, marker);
2776 /* Returns the first matching marker on the specified line between two points.
2777 If the group or flags fields are non-zero the returned flag must be in the
2778 specified group and have at least the specified flags set. */
2779 TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2780 TextMarker *marker, *next;
2781 int lineno= txt_get_span(text->lines.first, line);
2783 for (marker=text->markers.first; marker; marker=next) {
2786 if (group && marker->group != group) continue;
2787 else if ((marker->flags & flags) != flags) continue;
2788 else if (marker->lineno < lineno) continue;
2789 else if (marker->lineno > lineno) break;
2791 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2792 (marker->start<end && marker->end>start))
2798 /* Clears all markers on the specified line between two points. If the group or
2799 flags fields are non-zero the returned flag must be in the specified group
2800 and have at least the specified flags set. */
2801 short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2802 TextMarker *marker, *next;
2803 int lineno= txt_get_span(text->lines.first, line);
2806 for (marker=text->markers.first; marker; marker=next) {
2809 if (group && marker->group != group) continue;
2810 else if ((marker->flags & flags) != flags) continue;
2811 else if (marker->lineno < lineno) continue;
2812 else if (marker->lineno > lineno) break;
2814 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2815 (marker->start<end && marker->end>start)) {
2816 BLI_freelinkN(&text->markers, marker);
2823 /* Clears all markers in the specified group (if given) with at least the
2824 specified flags set. Useful for clearing temporary markers (group=0,
2825 flags=TMARK_TEMP) */
2826 short txt_clear_markers(Text *text, int group, int flags) {
2827 TextMarker *marker, *next;
2830 for (marker=text->markers.first; marker; marker=next) {
2833 if ((!group || marker->group==group) &&
2834 (marker->flags & flags) == flags) {
2835 BLI_freelinkN(&text->markers, marker);
2842 /* Finds the marker at the specified line and cursor position with at least the
2843 specified flags set in the given group (if non-zero). */
2844 TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags) {
2846 int lineno= txt_get_span(text->lines.first, line);
2848 for (marker=text->markers.first; marker; marker=marker->next) {
2849 if (group && marker->group != group) continue;
2850 else if ((marker->flags & flags) != flags) continue;
2851 else if (marker->lineno < lineno) continue;
2852 else if (marker->lineno > lineno) break;
2854 if (marker->start <= curs && curs <= marker->end)
2860 /* Finds the previous marker in the same group. If no other is found, the same
2861 marker will be returned */
2862 TextMarker *txt_prev_marker(Text *text, TextMarker *marker) {
2863 TextMarker *tmp= marker;
2865 if (tmp->prev) tmp= tmp->prev;
2866 else tmp= text->markers.last;
2867 if (tmp->group == marker->group)
2870 return NULL; /* Only if marker==NULL */
2873 /* Finds the next marker in the same group. If no other is found, the same
2874 marker will be returned */
2875 TextMarker *txt_next_marker(Text *text, TextMarker *marker) {
2876 TextMarker *tmp= marker;
2878 if (tmp->next) tmp= tmp->next;
2879 else tmp= text->markers.first;
2880 if (tmp->group == marker->group)
2883 return NULL; /* Only if marker==NULL */
2887 /*******************************/
2888 /* Character utility functions */
2889 /*******************************/
2891 int text_check_bracket(char ch)
2894 char opens[] = "([{";
2895 char close[] = ")]}";
2897 for(a=0; a<(sizeof(opens)-1); a++) {
2900 else if(ch==close[a])
2906 int text_check_delim(char ch)
2909 char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,";
2911 for(a=0; a<(sizeof(delims)-1); a++) {
2918 int text_check_digit(char ch)
2920 if(ch < '0') return 0;
2921 if(ch <= '9') return 1;
2925 int text_check_identifier(char ch)
2927 if(ch < '0') return 0;
2928 if(ch <= '9') return 1;
2929 if(ch < 'A') return 0;
2930 if(ch <= 'Z' || ch == '_') return 1;
2931 if(ch < 'a') return 0;
2932 if(ch <= 'z') return 1;
2936 int text_check_whitespace(char ch)
2938 if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')