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 /** \file blender/blenkernel/intern/text.c
37 #include <string.h> /* strstr */
38 #include <sys/types.h>
41 #include "MEM_guardedalloc.h"
43 #include "BLI_blenlib.h"
44 #include "BLI_utildefines.h"
46 #include "DNA_constraint_types.h"
47 #include "DNA_controller_types.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_screen_types.h"
50 #include "DNA_space_types.h"
51 #include "DNA_text_types.h"
52 #include "DNA_userdef_types.h"
53 #include "DNA_object_types.h"
55 #include "BKE_depsgraph.h"
56 #include "BKE_global.h"
57 #include "BKE_library.h"
63 #include "BPY_extern.h"
70 A text should relate to a file as follows -
71 (Text *)->name should be the place where the
72 file will or has been saved.
74 (Text *)->flags has the following bits
75 TXT_ISDIRTY - should always be set if the file in mem. differs from
76 the file on disk, or if there is no file on disk.
77 TXT_ISMEM - should always be set if the Text has not been mapped to
78 a file, in which case (Text *)->name may be NULL or garbage.
79 TXT_ISEXT - should always be set if the Text is not to be written into
81 TXT_ISSCRIPT - should be set if the user has designated the text
82 as a script. (NEW: this was unused, but now it is needed by
83 space handler script links (see header_view3d.c, for example)
85 ->>> see also: /makesdna/DNA_text_types.h
89 The st->top determines at what line the top of the text is displayed.
90 If the user moves the cursor the st containing that cursor should
91 be popped ... other st's retain their own top location.
95 The mrk->flags define the behaviour and relationships between markers. The
96 upper two bytes are used to hold a group ID, the lower two are normal flags. If
97 TMARK_EDITALL is set the group ID defines which other markers should be edited.
99 The mrk->clr field is used to visually group markers where the flags may not
100 match. A template system, for example, may allow editing of repeating tokens
101 (in one group) but include other marked positions (in another group) all in the
102 same template with the same color.
106 Undo/Redo works by storing
107 events in a queue, and a pointer
108 to the current position in the
111 Events are stored using an
112 arbitrary op-code system
114 a) the two cursors (normal and selected)
115 b) input (visible and control (ie backspace))
117 input data is stored as its
118 ASCII value, the opcodes are
119 then selected to not conflict.
121 opcodes with data in between are
122 written at the beginning and end
123 of the data to allow undo and redo
124 to simply check the code at the current
131 static void txt_pop_first(Text *text);
132 static void txt_pop_last(Text *text);
133 static void txt_undo_add_op(Text *text, int op);
134 static void txt_undo_add_block(Text *text, int op, const char *buf);
135 static void txt_delete_line(Text *text, TextLine *line);
136 static void txt_delete_sel (Text *text);
137 static void txt_make_dirty (Text *text);
141 static unsigned char undoing;
143 /* allow to switch off undoing externally */
144 void txt_set_undostate(int u)
149 int txt_get_undostate(void)
154 static void init_undo_text(Text *text)
157 text->undo_len= TXT_INIT_UNDO;
158 text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
161 void free_text(Text *text)
165 for (tmp= text->lines.first; tmp; tmp= tmp->next) {
166 MEM_freeN(tmp->line);
168 MEM_freeN(tmp->format);
171 BLI_freelistN(&text->lines);
172 BLI_freelistN(&text->markers);
174 if(text->name) MEM_freeN(text->name);
175 MEM_freeN(text->undo_buf);
177 if (text->compiled) BPY_text_free_code(text);
181 Text *add_empty_text(const char *name)
187 ta= alloc_libblock(&bmain->text, ID_TXT, name);
195 ta->flags= TXT_ISDIRTY | TXT_ISMEM;
196 if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
197 ta->flags |= TXT_TABSTOSPACES;
199 ta->lines.first= ta->lines.last= NULL;
200 ta->markers.first= ta->markers.last= NULL;
202 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
203 tmp->line= (char*) MEM_mallocN(1, "textline_string");
212 BLI_addhead(&ta->lines, tmp);
214 ta->curl= ta->lines.first;
216 ta->sell= ta->lines.first;
222 // this function removes any control characters from
225 static void cleanup_textline(TextLine * tl)
229 for (i = 0; i < tl->len; i++ ) {
230 if (tl->line[i] < ' ' && tl->line[i] != '\t') {
231 memmove(tl->line + i, tl->line + i + 1, tl->len - i);
238 int reopen_text(Text *text)
241 int i, llen, len, res;
242 unsigned char *buffer;
244 char str[FILE_MAXDIR+FILE_MAXFILE];
247 if (!text || !text->name) return 0;
249 BLI_strncpy(str, text->name, FILE_MAXDIR+FILE_MAXFILE);
250 BLI_path_abs(str, G.main->name);
253 if(fp==NULL) return 0;
257 for (tmp= text->lines.first; tmp; tmp= tmp->next) {
258 MEM_freeN(tmp->line);
259 if (tmp->format) MEM_freeN(tmp->format);
262 BLI_freelistN(&text->lines);
264 text->lines.first= text->lines.last= NULL;
265 text->curl= text->sell= NULL;
267 /* clear undo buffer */
268 MEM_freeN(text->undo_buf);
269 init_undo_text(text);
271 fseek(fp, 0L, SEEK_END);
273 fseek(fp, 0L, SEEK_SET);
277 buffer= MEM_mallocN(len, "text_buffer");
278 // under windows fread can return less then len bytes because
280 len = fread(buffer, 1, len, fp);
285 text->mtime= st.st_mtime;
289 for(i=0; i<len; i++) {
290 if (buffer[i]=='\n') {
291 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
292 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
295 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
299 cleanup_textline(tmp);
301 BLI_addtail(&text->lines, tmp);
310 if (llen!=0 || text->nlines==0) {
311 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
312 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
315 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
320 cleanup_textline(tmp);
322 BLI_addtail(&text->lines, tmp);
326 text->curl= text->sell= text->lines.first;
327 text->curc= text->selc= 0;
333 Text *add_text(const char *file, const char *relpath)
337 int i, llen, len, res;
338 unsigned char *buffer;
341 char str[FILE_MAXDIR+FILE_MAXFILE];
344 BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE);
345 if (relpath) /* can be NULL (bg mode) */
346 BLI_path_abs(str, relpath);
349 if(fp==NULL) return NULL;
351 ta= alloc_libblock(&bmain->text, ID_TXT, BLI_path_basename(str));
354 ta->lines.first= ta->lines.last= NULL;
355 ta->markers.first= ta->markers.last= NULL;
356 ta->curl= ta->sell= NULL;
358 if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
359 ta->flags= TXT_TABSTOSPACES;
361 fseek(fp, 0L, SEEK_END);
363 fseek(fp, 0L, SEEK_SET);
365 ta->name= MEM_mallocN(strlen(file)+1, "text_name");
366 strcpy(ta->name, file);
370 buffer= MEM_mallocN(len, "text_buffer");
371 // under windows fread can return less then len bytes because
373 len = fread(buffer, 1, len, fp);
378 ta->mtime= st.st_mtime;
382 for(i=0; i<len; i++) {
383 if (buffer[i]=='\n') {
384 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
385 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
388 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
392 cleanup_textline(tmp);
394 BLI_addtail(&ta->lines, tmp);
403 if (llen!=0 || ta->nlines==0) {
404 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
405 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
408 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
413 cleanup_textline(tmp);
415 BLI_addtail(&ta->lines, tmp);
419 ta->curl= ta->sell= ta->lines.first;
420 ta->curc= ta->selc= 0;
427 Text *copy_text(Text *ta)
430 TextLine *line, *tmp;
432 tan= copy_libblock(ta);
434 /* file name can be NULL */
436 tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name");
437 strcpy(tan->name, ta->name);
443 tan->flags = ta->flags | TXT_ISDIRTY;
445 tan->lines.first= tan->lines.last= NULL;
446 tan->markers.first= tan->markers.last= NULL;
447 tan->curl= tan->sell= NULL;
449 tan->nlines= ta->nlines;
451 line= ta->lines.first;
452 /* Walk down, reconstructing */
454 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
455 tmp->line= MEM_mallocN(line->len+1, "textline_string");
458 strcpy(tmp->line, line->line);
462 BLI_addtail(&tan->lines, tmp);
467 tan->curl= tan->sell= tan->lines.first;
468 tan->curc= tan->selc= 0;
475 void unlink_text(Main *bmain, Text *text)
487 for(scene=bmain->scene.first; scene; scene=scene->id.next)
488 if(scene->r.dometext == text)
489 scene->r.dometext = NULL;
491 for(ob=bmain->object.first; ob; ob=ob->id.next) {
492 /* game controllers */
493 for(cont=ob->controllers.first; cont; cont=cont->next) {
494 if(cont->type==CONT_PYTHON) {
498 if(pc->text==text) pc->text= NULL;
505 if(ob->type==OB_ARMATURE && ob->pose) {
507 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
508 for(con = pchan->constraints.first; con; con=con->next) {
509 if(con->type==CONSTRAINT_TYPE_PYTHON) {
510 bPythonConstraint *data = con->data;
511 if (data->text==text) data->text = NULL;
519 for(con = ob->constraints.first; con; con=con->next) {
520 if(con->type==CONSTRAINT_TYPE_PYTHON) {
521 bPythonConstraint *data = con->data;
522 if (data->text==text) data->text = NULL;
528 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
532 // XXX nodeDynamicUnlinkText(&text->id);
535 for(scr= bmain->screen.first; scr; scr= scr->id.next) {
536 for(area= scr->areabase.first; area; area= area->next) {
537 for(sl= area->spacedata.first; sl; sl= sl->next) {
538 if(sl->spacetype==SPACE_TEXT) {
539 SpaceText *st= (SpaceText*) sl;
553 void clear_text(Text *text) /* called directly from rna */
557 oldstate = txt_get_undostate( );
558 txt_set_undostate( 1 );
560 txt_delete_sel(text);
561 txt_set_undostate( oldstate );
563 txt_make_dirty(text);
566 void write_text(Text *text, const char *str) /* called directly from rna */
570 oldstate = txt_get_undostate( );
571 txt_insert_buf( text, str );
572 txt_move_eof( text, 0 );
573 txt_set_undostate( oldstate );
575 txt_make_dirty(text);
578 /*****************************/
579 /* Editing utility functions */
580 /*****************************/
582 static void make_new_line (TextLine *line, char *newline)
584 if (line->line) MEM_freeN(line->line);
585 if (line->format) MEM_freeN(line->format);
588 line->len= strlen(newline);
592 static TextLine *txt_new_line(const char *str)
598 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
599 tmp->line= MEM_mallocN(strlen(str)+1, "textline_string");
602 strcpy(tmp->line, str);
604 tmp->len= strlen(str);
605 tmp->next= tmp->prev= NULL;
610 static TextLine *txt_new_linen(const char *str, int n)
614 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
615 tmp->line= MEM_mallocN(n+1, "textline_string");
618 BLI_strncpy(tmp->line, (str)? str: "", n+1);
620 tmp->len= strlen(tmp->line);
621 tmp->next= tmp->prev= NULL;
626 void txt_clean_text (Text *text)
628 TextLine **top, **bot;
632 if (!text->lines.first) {
633 if (text->lines.last) text->lines.first= text->lines.last;
634 else text->lines.first= text->lines.last= txt_new_line(NULL);
637 if (!text->lines.last) text->lines.last= text->lines.first;
639 top= (TextLine **) &text->lines.first;
640 bot= (TextLine **) &text->lines.last;
642 while ((*top)->prev) *top= (*top)->prev;
643 while ((*bot)->next) *bot= (*bot)->next;
646 if(text->sell) text->curl= text->sell;
647 else text->curl= text->lines.first;
652 text->sell= text->curl;
657 int txt_get_span (TextLine *from, TextLine *to)
662 if (!to || !from) return 0;
663 if (from==to) return 0;
667 if (tmp == to) return ret;
677 if (tmp == to) break;
687 static void txt_make_dirty (Text *text)
689 text->flags |= TXT_ISDIRTY;
691 if (text->compiled) BPY_text_free_code(text);
695 /* 0:whitespace, 1:punct, 2:alphanumeric */
696 static short txt_char_type (char ch)
698 if (ch <= ' ') return 0; /* 32 */
699 if (ch <= '/') return 1; /* 47 */
700 if (ch <= '9') return 2; /* 57 */
701 if (ch <= '@') return 1; /* 64 */
702 if (ch <= 'Z') return 2; /* 90 */
703 if (ch == '_') return 2; /* 95, dont delimit '_' */
704 if (ch <= '`') return 1; /* 96 */
705 if (ch <= 'z') return 2; /* 122 */
709 /****************************/
710 /* Cursor utility functions */
711 /****************************/
713 static void txt_curs_cur (Text *text, TextLine ***linep, int **charp)
715 *linep= &text->curl; *charp= &text->curc;
718 static void txt_curs_sel (Text *text, TextLine ***linep, int **charp)
720 *linep= &text->sell; *charp= &text->selc;
723 static void txt_curs_first (Text *text, TextLine **linep, int *charp)
725 if (text->curl==text->sell) {
727 if (text->curc<text->selc) *charp= text->curc;
728 else *charp= text->selc;
729 } else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) {
738 /****************************/
739 /* Cursor movement functions */
740 /****************************/
742 void txt_move_up(Text *text, short sel)
748 if(sel) txt_curs_sel(text, &linep, &charp);
749 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
754 *linep= (*linep)->prev;
755 if (*charp > (*linep)->len) {
756 *charp= (*linep)->len;
757 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);
759 if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
762 txt_move_bol(text, sel);
765 if(!sel) txt_pop_sel(text);
768 void txt_move_down(Text *text, short sel)
774 if(sel) txt_curs_sel(text, &linep, &charp);
775 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
780 *linep= (*linep)->next;
781 if (*charp > (*linep)->len) {
782 *charp= (*linep)->len;
783 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);
785 if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
787 txt_move_eol(text, sel);
790 if(!sel) txt_pop_sel(text);
793 void txt_move_left(Text *text, short sel)
796 int *charp, oundoing= undoing;
799 if(sel) txt_curs_sel(text, &linep, &charp);
800 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
805 if ((*linep)->prev) {
806 txt_move_up(text, sel);
807 *charp= (*linep)->len;
813 if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
815 if(!sel) txt_pop_sel(text);
818 void txt_move_right(Text *text, short sel)
821 int *charp, oundoing= undoing;
824 if(sel) txt_curs_sel(text, &linep, &charp);
825 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
829 if (*charp== (*linep)->len) {
830 if ((*linep)->next) {
831 txt_move_down(text, sel);
838 if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
840 if(!sel) txt_pop_sel(text);
843 void txt_jump_left(Text *text, short sel)
845 TextLine **linep, *oldl;
846 int *charp, oldc, count, i;
850 if(sel) txt_curs_sel(text, &linep, &charp);
851 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
857 undoing= 1; /* Don't push individual moves to undo stack */
860 for (i=0; i<3; i++) {
862 while (*charp>0 && txt_char_type((*linep)->line[*charp-1])==i) {
863 txt_move_left(text, sel);
868 if (count==0) txt_move_left(text, sel);
871 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);
874 void txt_jump_right(Text *text, short sel)
876 TextLine **linep, *oldl;
877 int *charp, oldc, count, i;
881 if(sel) txt_curs_sel(text, &linep, &charp);
882 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
888 undoing= 1; /* Don't push individual moves to undo stack */
891 for (i=0; i<3; i++) {
893 while (*charp<(*linep)->len && txt_char_type((*linep)->line[*charp])==i) {
894 txt_move_right(text, sel);
899 if (count==0) txt_move_right(text, sel);
902 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);
905 void txt_move_bol (Text *text, short sel)
911 if(sel) txt_curs_sel(text, &linep, &charp);
912 else txt_curs_cur(text, &linep, &charp);
918 if(!sel) txt_pop_sel(text);
919 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);
922 void txt_move_eol (Text *text, short sel)
928 if(sel) txt_curs_sel(text, &linep, &charp);
929 else txt_curs_cur(text, &linep, &charp);
933 *charp= (*linep)->len;
935 if(!sel) txt_pop_sel(text);
936 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);
939 void txt_move_bof (Text *text, short sel)
945 if(sel) txt_curs_sel(text, &linep, &charp);
946 else txt_curs_cur(text, &linep, &charp);
950 *linep= text->lines.first;
953 if(!sel) txt_pop_sel(text);
954 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);
957 void txt_move_eof (Text *text, short sel)
963 if(sel) txt_curs_sel(text, &linep, &charp);
964 else txt_curs_cur(text, &linep, &charp);
968 *linep= text->lines.last;
969 *charp= (*linep)->len;
971 if(!sel) txt_pop_sel(text);
972 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);
975 void txt_move_toline (Text *text, unsigned int line, short sel)
977 txt_move_to(text, line, 0, sel);
980 void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel)
982 TextLine **linep, *oldl;
987 if(sel) txt_curs_sel(text, &linep, &charp);
988 else txt_curs_cur(text, &linep, &charp);
993 *linep= text->lines.first;
994 for (i=0; i<line; i++) {
995 if ((*linep)->next) *linep= (*linep)->next;
998 if (ch>(unsigned int)((*linep)->len))
999 ch= (unsigned int)((*linep)->len);
1002 if(!sel) txt_pop_sel(text);
1003 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);
1006 /****************************/
1007 /* Text selection functions */
1008 /****************************/
1010 static void txt_curs_swap (Text *text)
1016 text->curl= text->sell;
1020 text->curc= text->selc;
1023 if(!undoing) txt_undo_add_op(text, UNDO_SWAP);
1026 static void txt_pop_first (Text *text)
1029 if (txt_get_span(text->curl, text->sell)<0 ||
1030 (text->curl==text->sell && text->curc>text->selc)) {
1031 txt_curs_swap(text);
1034 if(!undoing) txt_undo_add_toop(text, UNDO_STO,
1035 txt_get_span(text->lines.first, text->sell),
1037 txt_get_span(text->lines.first, text->curl),
1043 static void txt_pop_last (Text *text)
1045 if (txt_get_span(text->curl, text->sell)>0 ||
1046 (text->curl==text->sell && text->curc<text->selc)) {
1047 txt_curs_swap(text);
1050 if(!undoing) txt_undo_add_toop(text, UNDO_STO,
1051 txt_get_span(text->lines.first, text->sell),
1053 txt_get_span(text->lines.first, text->curl),
1059 /* never used: CVS 1.19 */
1060 /* static void txt_pop_selr (Text *text) */
1062 void txt_pop_sel (Text *text)
1064 text->sell= text->curl;
1065 text->selc= text->curc;
1068 void txt_order_cursors(Text *text)
1071 if (!text->curl) return;
1072 if (!text->sell) return;
1074 /* Flip so text->curl is before text->sell */
1075 if (txt_get_span(text->curl, text->sell)<0 ||
1076 (text->curl==text->sell && text->curc>text->selc))
1077 txt_curs_swap(text);
1080 int txt_has_sel(Text *text)
1082 return ((text->curl!=text->sell) || (text->curc!=text->selc));
1085 static void txt_delete_sel (Text *text)
1093 if (!text->curl) return;
1094 if (!text->sell) return;
1096 if (!txt_has_sel(text)) return;
1098 txt_order_cursors(text);
1101 buf= txt_sel_to_buf(text);
1102 txt_undo_add_block(text, UNDO_DBLOCK, buf);
1106 buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
1108 if (text->curl != text->sell) {
1109 txt_clear_marker_region(text, text->curl, text->curc, text->curl->len, 0, 0);
1110 move= txt_get_span(text->curl, text->sell);
1112 mrk= txt_find_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
1113 if (mrk && (mrk->start > text->curc || mrk->end < text->selc))
1114 txt_clear_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
1118 mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0);
1120 lineno= mrk->lineno;
1122 mrk->lineno -= move;
1123 if (mrk->start > text->curc) mrk->start -= text->selc - text->curc;
1124 mrk->end -= text->selc - text->curc;
1126 } while (mrk && mrk->lineno==lineno);
1129 strncpy(buf, text->curl->line, text->curc);
1130 strcpy(buf+text->curc, text->sell->line + text->selc);
1131 buf[text->curc+(text->sell->len - text->selc)]=0;
1133 make_new_line(text->curl, buf);
1136 while (tmpl != text->curl) {
1140 txt_delete_line(text, tmpl->next);
1143 text->sell= text->curl;
1144 text->selc= text->curc;
1147 void txt_sel_all (Text *text)
1151 text->curl= text->lines.first;
1154 text->sell= text->lines.last;
1155 text->selc= text->sell->len;
1158 void txt_sel_line (Text *text)
1161 if (!text->curl) return;
1164 text->sell= text->curl;
1165 text->selc= text->sell->len;
1168 /***************************/
1169 /* Cut and paste functions */
1170 /***************************/
1172 char *txt_to_buf (Text *text)
1175 TextLine *tmp, *linef, *linel;
1179 if (!text) return NULL;
1180 if (!text->curl) return NULL;
1181 if (!text->sell) return NULL;
1182 if (!text->lines.first) return NULL;
1184 linef= text->lines.first;
1187 linel= text->lines.last;
1190 if (linef == text->lines.last) {
1191 length= charl-charf;
1193 buf= MEM_mallocN(length+2, "text buffer");
1195 BLI_strncpy(buf, linef->line + charf, length+1);
1198 length= linef->len - charf;
1200 length+= 2; /* For the 2 '\n' */
1203 while (tmp && tmp!= linel) {
1204 length+= tmp->len+1;
1208 buf= MEM_mallocN(length+1, "cut buffer");
1210 strncpy(buf, linef->line + charf, linef->len-charf);
1211 length= linef->len - charf;
1216 while (tmp && tmp!=linel) {
1217 strncpy(buf+length, tmp->line, tmp->len);
1224 strncpy(buf+length, linel->line, charl);
1227 /* python compiler wants an empty end line */
1235 int txt_find_string(Text *text, char *findstr, int wrap, int match_case)
1237 TextLine *tl, *startl;
1241 if (!text || !text->curl || !text->sell) return 0;
1243 txt_order_cursors(text);
1245 oldcl= txt_get_span(text->lines.first, text->curl);
1246 oldsl= txt_get_span(text->lines.first, text->sell);
1247 tl= startl= text->sell;
1249 if(match_case) s= strstr(&tl->line[text->selc], findstr);
1250 else s= BLI_strcasestr(&tl->line[text->selc], findstr);
1255 tl= text->lines.first;
1260 if(match_case) s= strstr(tl->line, findstr);
1261 else s= BLI_strcasestr(tl->line, findstr);
1267 int newl= txt_get_span(text->lines.first, tl);
1268 int newc= (int)(s-tl->line);
1269 txt_move_to(text, newl, newc, 0);
1270 txt_move_to(text, newl, newc + strlen(findstr), 1);
1276 char *txt_sel_to_buf (Text *text)
1280 TextLine *tmp, *linef, *linel;
1283 if (!text) return NULL;
1284 if (!text->curl) return NULL;
1285 if (!text->sell) return NULL;
1287 if (text->curl==text->sell) {
1288 linef= linel= text->curl;
1290 if (text->curc < text->selc) {
1297 } else if (txt_get_span(text->curl, text->sell)<0) {
1311 if (linef == linel) {
1312 length= charl-charf;
1314 buf= MEM_mallocN(length+1, "sel buffer");
1316 BLI_strncpy(buf, linef->line + charf, length+1);
1318 length+= linef->len - charf;
1320 length++; /* For the '\n' */
1323 while (tmp && tmp!= linel) {
1324 length+= tmp->len+1;
1328 buf= MEM_mallocN(length+1, "sel buffer");
1330 strncpy(buf, linef->line+ charf, linef->len-charf);
1331 length= linef->len-charf;
1336 while (tmp && tmp!=linel) {
1337 strncpy(buf+length, tmp->line, tmp->len);
1344 strncpy(buf+length, linel->line, charl);
1353 static void txt_shift_markers(Text *text, int lineno, int count)
1357 for (marker=text->markers.first; marker; marker= marker->next)
1358 if (marker->lineno>=lineno) {
1359 marker->lineno+= count;
1363 void txt_insert_buf(Text *text, const char *in_buffer)
1365 int i=0, l=0, j, u, len, lineno= -1, count= 0;
1369 if (!in_buffer) return;
1371 txt_delete_sel(text);
1373 if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer);
1378 /* Read the first line (or as close as possible */
1379 while (in_buffer[i] && in_buffer[i]!='\n') {
1380 txt_add_raw_char(text, in_buffer[i]);
1384 if (in_buffer[i]=='\n') txt_split_curline(text);
1385 else { undoing = u; return; }
1388 /* Read as many full lines as we can */
1389 len= strlen(in_buffer);
1390 lineno= txt_get_span(text->lines.first, text->curl);
1395 while (in_buffer[i] && in_buffer[i]!='\n') {
1399 if(in_buffer[i]=='\n') {
1400 add= txt_new_linen(in_buffer +(i-l), l);
1401 BLI_insertlinkbefore(&text->lines, text->curl, add);
1406 txt_shift_markers(text, lineno, count);
1410 for (j= i-l; j<i && j<(int)strlen(in_buffer); j++) {
1411 txt_add_raw_char(text, in_buffer[j]);
1418 txt_shift_markers(text, lineno, count);
1425 /******************/
1426 /* Undo functions */
1427 /******************/
1429 static int max_undo_test(Text *text, int x)
1431 while (text->undo_pos+x >= text->undo_len) {
1432 if(text->undo_len*2 > TXT_MAX_UNDO) {
1433 /* XXX error("Undo limit reached, buffer cleared\n"); */
1434 MEM_freeN(text->undo_buf);
1435 init_undo_text(text);
1438 void *tmp= text->undo_buf;
1439 text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf");
1440 memcpy(text->undo_buf, tmp, text->undo_len);
1449 static void dump_buffer(Text *text)
1453 while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
1456 void txt_print_undo(Text *text)
1465 printf ("---< Undo Buffer >---\n");
1467 printf ("UndoPosition is %d\n", text->undo_pos);
1469 while (i<=text->undo_pos) {
1470 op= text->undo_buf[i];
1472 if (op==UNDO_CLEFT) {
1474 } else if (op==UNDO_CRIGHT) {
1475 ops= "Cursor right";
1476 } else if (op==UNDO_CUP) {
1478 } else if (op==UNDO_CDOWN) {
1480 } else if (op==UNDO_SLEFT) {
1481 ops= "Selection left";
1482 } else if (op==UNDO_SRIGHT) {
1483 ops= "Selection right";
1484 } else if (op==UNDO_SUP) {
1485 ops= "Selection up";
1486 } else if (op==UNDO_SDOWN) {
1487 ops= "Selection down";
1488 } else if (op==UNDO_STO) {
1490 } else if (op==UNDO_CTO) {
1492 } else if (op==UNDO_INSERT) {
1494 } else if (op==UNDO_BS) {
1496 } else if (op==UNDO_DEL) {
1498 } else if (op==UNDO_SWAP) {
1500 } else if (op==UNDO_DBLOCK) {
1501 ops= "Delete text block";
1502 } else if (op==UNDO_IBLOCK) {
1503 ops= "Insert text block";
1504 } else if (op==UNDO_INDENT) {
1506 } else if (op==UNDO_UNINDENT) {
1508 } else if (op==UNDO_COMMENT) {
1510 } else if (op==UNDO_UNCOMMENT) {
1516 printf ("Op (%o) at %d = %s", op, i, ops);
1517 if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) {
1519 printf (" - Char is %c", text->undo_buf[i]);
1521 } else if (op==UNDO_STO || op==UNDO_CTO) {
1524 charp= text->undo_buf[i]; i++;
1525 charp= charp+(text->undo_buf[i]<<8); i++;
1527 linep= text->undo_buf[i]; i++;
1528 linep= linep+(text->undo_buf[i]<<8); i++;
1529 linep= linep+(text->undo_buf[i]<<16); i++;
1530 linep= linep+(text->undo_buf[i]<<24); i++;
1532 printf ("to <%d, %d> ", linep, charp);
1534 charp= text->undo_buf[i]; i++;
1535 charp= charp+(text->undo_buf[i]<<8); i++;
1537 linep= text->undo_buf[i]; i++;
1538 linep= linep+(text->undo_buf[i]<<8); i++;
1539 linep= linep+(text->undo_buf[i]<<16); i++;
1540 linep= linep+(text->undo_buf[i]<<24); i++;
1542 printf ("from <%d, %d>", linep, charp);
1543 } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
1546 linep= text->undo_buf[i]; i++;
1547 linep= linep+(text->undo_buf[i]<<8); i++;
1548 linep= linep+(text->undo_buf[i]<<16); i++;
1549 linep= linep+(text->undo_buf[i]<<24); i++;
1551 printf (" (length %d) <", linep);
1554 putchar(text->undo_buf[i]);
1558 linep= text->undo_buf[i]; i++;
1559 linep= linep+(text->undo_buf[i]<<8); i++;
1560 linep= linep+(text->undo_buf[i]<<16); i++;
1561 linep= linep+(text->undo_buf[i]<<24); i++;
1562 printf ("> (%d)", linep);
1563 } else if (op==UNDO_INDENT || op==UNDO_UNINDENT) {
1566 charp= text->undo_buf[i]; i++;
1567 charp= charp+(text->undo_buf[i]<<8); i++;
1569 linep= text->undo_buf[i]; i++;
1570 linep= linep+(text->undo_buf[i]<<8); i++;
1571 linep= linep+(text->undo_buf[i]<<16); i++;
1572 linep= linep+(text->undo_buf[i]<<24); i++;
1574 printf ("to <%d, %d> ", linep, charp);
1576 charp= text->undo_buf[i]; i++;
1577 charp= charp+(text->undo_buf[i]<<8); i++;
1579 linep= text->undo_buf[i]; i++;
1580 linep= linep+(text->undo_buf[i]<<8); i++;
1581 linep= linep+(text->undo_buf[i]<<16); i++;
1582 linep= linep+(text->undo_buf[i]<<24); i++;
1584 printf ("from <%d, %d>", linep, charp);
1587 printf (" %d\n", i);
1592 static void txt_undo_add_op(Text *text, int op)
1594 if(!max_undo_test(text, 2))
1598 text->undo_buf[text->undo_pos]= op;
1599 text->undo_buf[text->undo_pos+1]= 0;
1602 static void txt_undo_add_block(Text *text, int op, const char *buf)
1606 length= strlen(buf);
1608 if(!max_undo_test(text, length+11))
1612 text->undo_buf[text->undo_pos]= op;
1615 text->undo_buf[text->undo_pos]= (length)&0xff;
1617 text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1619 text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1621 text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1624 strncpy(text->undo_buf+text->undo_pos, buf, length);
1625 text->undo_pos+=length;
1627 text->undo_buf[text->undo_pos]= (length)&0xff;
1629 text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1631 text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1633 text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1636 text->undo_buf[text->undo_pos]= op;
1638 text->undo_buf[text->undo_pos+1]= 0;
1641 void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
1643 if(!max_undo_test(text, 15))
1646 if (froml==tol && fromc==toc) return;
1649 text->undo_buf[text->undo_pos]= op;
1652 text->undo_buf[text->undo_pos]= (fromc)&0xff;
1654 text->undo_buf[text->undo_pos]= (fromc>>8)&0xff;
1657 text->undo_buf[text->undo_pos]= (froml)&0xff;
1659 text->undo_buf[text->undo_pos]= (froml>>8)&0xff;
1661 text->undo_buf[text->undo_pos]= (froml>>16)&0xff;
1663 text->undo_buf[text->undo_pos]= (froml>>24)&0xff;
1666 text->undo_buf[text->undo_pos]= (toc)&0xff;
1668 text->undo_buf[text->undo_pos]= (toc>>8)&0xff;
1671 text->undo_buf[text->undo_pos]= (tol)&0xff;
1673 text->undo_buf[text->undo_pos]= (tol>>8)&0xff;
1675 text->undo_buf[text->undo_pos]= (tol>>16)&0xff;
1677 text->undo_buf[text->undo_pos]= (tol>>24)&0xff;
1680 text->undo_buf[text->undo_pos]= op;
1682 text->undo_buf[text->undo_pos+1]= 0;
1685 static void txt_undo_add_charop(Text *text, int op, char c)
1687 if(!max_undo_test(text, 4))
1691 text->undo_buf[text->undo_pos]= op;
1693 text->undo_buf[text->undo_pos]= c;
1695 text->undo_buf[text->undo_pos]= op;
1696 text->undo_buf[text->undo_pos+1]= 0;
1699 void txt_do_undo(Text *text)
1701 int op= text->undo_buf[text->undo_pos];
1702 unsigned int linep, i;
1703 unsigned short charp;
1708 if (text->undo_pos<0) {
1718 txt_move_right(text, 0);
1722 txt_move_left(text, 0);
1726 txt_move_down(text, 0);
1730 txt_move_up(text, 0);
1734 txt_move_right(text, 1);
1738 txt_move_left(text, 1);
1742 txt_move_down(text, 1);
1746 txt_move_up(text, 1);
1759 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1760 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1761 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1762 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1764 charp= text->undo_buf[text->undo_pos]; text->undo_pos--;
1765 charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1768 txt_move_toline(text, linep, 0);
1772 txt_move_toline(text, linep, 1);
1780 txt_backspace_char(text);
1786 txt_add_char(text, text->undo_buf[text->undo_pos]);
1792 txt_add_char(text, text->undo_buf[text->undo_pos]);
1793 txt_move_left(text, 0);
1799 txt_curs_swap(text);
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--;
1808 buf= MEM_mallocN(linep+1, "dblock buffer");
1809 for (i=0; i < linep; i++){
1810 buf[(linep-1)-i]= text->undo_buf[text->undo_pos];
1815 txt_curs_first(text, &holdl, &holdc);
1816 holdln= txt_get_span(text->lines.first, holdl);
1818 txt_insert_buf(text, buf);
1821 text->curl= text->lines.first;
1823 if(text->curl->next)
1824 text->curl= text->curl->next;
1830 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1831 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1832 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1833 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1840 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1841 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1842 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1843 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1845 txt_delete_sel(text);
1847 txt_backspace_char(text);
1863 case UNDO_UNCOMMENT:
1864 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1865 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1866 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1867 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1868 //linep is now the end line of the selection
1870 charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1871 charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1872 //charp is the last char selected or text->line->len
1873 //set the selcetion for this now
1875 text->sell = text->lines.first;
1876 for (i= 0; i < linep; i++) {
1877 text->sell = text->sell->next;
1880 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1881 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1882 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1883 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1884 //first line to be selected
1886 charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1887 charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1888 //first postion to be selected
1890 text->curl = text->lines.first;
1891 for (i = 0; i < linep; i++) {
1892 text->curl = text->curl->next;
1896 if (op==UNDO_INDENT) {
1898 } else if (op== UNDO_UNINDENT) {
1900 } else if (op == UNDO_COMMENT) {
1901 txt_uncomment(text);
1902 } else if (op == UNDO_UNCOMMENT) {
1909 //XXX error("Undo buffer error - resetting");
1915 /* next undo step may need evaluating */
1916 if (text->undo_pos>=0) {
1917 switch (text->undo_buf[text->undo_pos]) {
1920 txt_do_redo(text); /* selections need restoring */
1923 txt_do_undo(text); /* swaps should appear transparent */
1931 void txt_do_redo(Text *text)
1934 unsigned int linep, i;
1935 unsigned short charp;
1939 op= text->undo_buf[text->undo_pos];
1950 txt_move_left(text, 0);
1954 txt_move_right(text, 0);
1958 txt_move_up(text, 0);
1962 txt_move_down(text, 0);
1966 txt_move_left(text, 1);
1970 txt_move_right(text, 1);
1974 txt_move_up(text, 1);
1978 txt_move_down(text, 1);
1983 txt_add_char(text, text->undo_buf[text->undo_pos]);
1989 txt_backspace_char(text);
1995 txt_delete_char(text);
2000 txt_curs_swap(text);
2001 txt_do_redo(text); /* swaps should appear transparent a*/
2016 charp= text->undo_buf[text->undo_pos];
2018 charp= charp+(text->undo_buf[text->undo_pos]<<8);
2021 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2022 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2023 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2024 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2027 txt_move_toline(text, linep, 0);
2031 txt_move_toline(text, linep, 1);
2039 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2040 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2041 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2042 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2044 txt_delete_sel(text);
2045 text->undo_pos+=linep;
2056 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2057 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2058 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2059 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2061 buf= MEM_mallocN(linep+1, "iblock buffer");
2062 memcpy (buf, &text->undo_buf[text->undo_pos], linep);
2063 text->undo_pos+= linep;
2066 txt_insert_buf(text, buf);
2069 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2070 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2071 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2072 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2079 case UNDO_UNCOMMENT:
2081 charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2082 charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2083 //charp is the first char selected or 0
2085 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2086 linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2087 linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2088 linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2089 //linep is now the first line of the selection
2090 //set the selcetion for this now
2092 text->curl = text->lines.first;
2093 for (i= 0; i < linep; i++) {
2094 text->curl = text->curl->next;
2097 charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2098 charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2099 //last postion to be selected
2100 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2101 linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2102 linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2103 linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2104 //Last line to be selected
2107 text->sell = text->lines.first;
2108 for (i = 0; i < linep; i++) {
2109 text->sell = text->sell->next;
2112 if (op==UNDO_INDENT) {
2114 } else if (op== UNDO_UNINDENT) {
2116 } else if (op == UNDO_COMMENT) {
2118 } else if (op == UNDO_UNCOMMENT) {
2119 txt_uncomment(text);
2123 //XXX error("Undo buffer error - resetting");
2132 /**************************/
2133 /* Line editing functions */
2134 /**************************/
2136 void txt_split_curline (Text *text)
2144 if (!text->curl) return;
2146 txt_delete_sel(text);
2150 lineno= txt_get_span(text->lines.first, text->curl);
2151 mrk= text->markers.first;
2153 if (mrk->lineno==lineno && mrk->start>text->curc) {
2155 mrk->start -= text->curc;
2156 mrk->end -= text->curc;
2157 } else if (mrk->lineno > lineno) {
2163 /* Make the two half strings */
2165 left= MEM_mallocN(text->curc+1, "textline_string");
2166 if (text->curc) memcpy(left, text->curl->line, text->curc);
2169 right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
2170 if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc);
2171 right[text->curl->len - text->curc]=0;
2173 MEM_freeN(text->curl->line);
2174 if (text->curl->format) MEM_freeN(text->curl->format);
2176 /* Make the new TextLine */
2178 ins= MEM_mallocN(sizeof(TextLine), "textline");
2181 ins->len= text->curc;
2183 text->curl->line= right;
2184 text->curl->format= NULL;
2185 text->curl->len= text->curl->len - text->curc;
2187 BLI_insertlinkbefore(&text->lines, text->curl, ins);
2191 txt_make_dirty(text);
2192 txt_clean_text(text);
2195 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n');
2198 static void txt_delete_line (Text *text, TextLine *line)
2200 TextMarker *mrk=NULL, *nxt;
2204 if (!text->curl) return;
2206 lineno= txt_get_span(text->lines.first, line);
2207 mrk= text->markers.first;
2210 if (mrk->lineno==lineno)
2211 BLI_freelinkN(&text->markers, mrk);
2212 else if (mrk->lineno > lineno)
2217 BLI_remlink (&text->lines, line);
2219 if (line->line) MEM_freeN(line->line);
2220 if (line->format) MEM_freeN(line->format);
2224 txt_make_dirty(text);
2225 txt_clean_text(text);
2228 static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
2231 TextMarker *mrk= NULL;
2236 if(!linea || !lineb) return;
2238 mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0);
2240 lineno= mrk->lineno;
2243 mrk->start += linea->len;
2244 mrk->end += linea->len;
2246 } while (mrk && mrk->lineno==lineno);
2248 if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb);
2250 tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
2252 strcpy(tmp, linea->line);
2253 strcat(tmp, lineb->line);
2255 make_new_line(linea, tmp);
2257 txt_delete_line(text, lineb);
2259 txt_make_dirty(text);
2260 txt_clean_text(text);
2263 void txt_delete_char (Text *text)
2268 if (!text->curl) return;
2270 if (txt_has_sel(text)) { /* deleting a selection */
2271 txt_delete_sel(text);
2272 txt_make_dirty(text);
2275 else if (text->curc== text->curl->len) { /* Appending two lines */
2276 if (text->curl->next) {
2277 txt_combine_lines(text, text->curl, text->curl->next);
2280 } else { /* Just deleting a char */
2283 TextMarker *mrk= txt_find_marker_region(text, text->curl, i-1, text->curl->len, 0, 0);
2285 int lineno= mrk->lineno;
2287 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2288 txt_clear_markers(text, mrk->group, TMARK_TEMP);
2290 BLI_freelinkN(&text->markers, mrk);
2295 if (mrk->start>i) mrk->start--;
2298 } while (mrk && mrk->lineno==lineno);
2301 c= text->curl->line[i];
2302 while(i< text->curl->len) {
2303 text->curl->line[i]= text->curl->line[i+1];
2311 txt_make_dirty(text);
2312 txt_clean_text(text);
2314 if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c);
2317 void txt_delete_word (Text *text)
2319 txt_jump_right(text, 1);
2320 txt_delete_sel(text);
2323 void txt_backspace_char (Text *text)
2328 if (!text->curl) return;
2330 if (txt_has_sel(text)) { /* deleting a selection */
2331 txt_delete_sel(text);
2332 txt_make_dirty(text);
2335 else if (text->curc==0) { /* Appending two lines */
2336 if (!text->curl->prev) return;
2338 text->curl= text->curl->prev;
2339 text->curc= text->curl->len;
2341 txt_combine_lines(text, text->curl, text->curl->next);
2344 else { /* Just backspacing a char */
2345 int i= text->curc-1;
2347 TextMarker *mrk= txt_find_marker_region(text, text->curl, i, text->curl->len, 0, 0);
2349 int lineno= mrk->lineno;
2350 if (mrk->start==i+1) {
2351 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2352 txt_clear_markers(text, mrk->group, TMARK_TEMP);
2354 BLI_freelinkN(&text->markers, mrk);
2359 if (mrk->start>i) mrk->start--;
2362 } while (mrk && mrk->lineno==lineno);
2365 c= text->curl->line[i];
2366 while(i< text->curl->len) {
2367 text->curl->line[i]= text->curl->line[i+1];
2376 txt_make_dirty(text);
2377 txt_clean_text(text);
2379 if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
2382 void txt_backspace_word (Text *text)
2384 txt_jump_left(text, 1);
2385 txt_delete_sel(text);
2388 /* Max spaces to replace a tab with, currently hardcoded to TXT_TABSIZE = 4.
2389 * Used by txt_convert_tab_to_spaces, indent and unintent.
2390 * Remember to change this string according to max tab size */
2391 static char tab_to_spaces[] = " ";
2393 static void txt_convert_tab_to_spaces (Text *text)
2395 /* sb aims to pad adjust the tab-width needed so that the right number of spaces
2396 * is added so that the indention of the line is the right width (i.e. aligned
2397 * to multiples of TXT_TABSIZE)
2399 char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
2400 txt_insert_buf(text, sb);
2403 static int txt_add_char_intern (Text *text, char add, int replace_tabs)
2409 if (!text) return 0;
2410 if (!text->curl) return 0;
2413 txt_split_curline(text);
2417 /* insert spaces rather then tabs */
2418 if (add == '\t' && replace_tabs) {
2419 txt_convert_tab_to_spaces(text);
2423 txt_delete_sel(text);
2425 mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0);
2427 lineno= mrk->lineno;
2429 if (mrk->start>text->curc) mrk->start++;
2432 } while (mrk && mrk->lineno==lineno);
2435 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2437 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2438 tmp[text->curc]= add;
2440 len= text->curl->len - text->curc;
2441 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2442 tmp[text->curl->len+1]=0;
2443 make_new_line(text->curl, tmp);
2449 txt_make_dirty(text);
2450 txt_clean_text(text);
2452 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add);
2456 int txt_add_char (Text *text, char add)
2458 return txt_add_char_intern(text, add, text->flags & TXT_TABSTOSPACES);
2461 int txt_add_raw_char (Text *text, char add)
2463 return txt_add_char_intern(text, add, 0);
2466 void txt_delete_selected(Text *text)
2468 txt_delete_sel(text);
2469 txt_make_dirty(text);
2472 int txt_replace_char (Text *text, char add)
2476 if (!text) return 0;
2477 if (!text->curl) return 0;
2479 /* If text is selected or we're at the end of the line just use txt_add_char */
2480 if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') {
2482 int i= txt_add_char(text, add);
2483 mrk= txt_find_marker(text, text->curl, text->curc, 0, 0);
2484 if (mrk && mrk->end==text->curc) mrk->end--;
2488 del= text->curl->line[text->curc];
2489 text->curl->line[text->curc]= (unsigned char) add;
2493 txt_make_dirty(text);
2494 txt_clean_text(text);
2496 /* Should probably create a new op for this */
2498 txt_undo_add_charop(text, UNDO_DEL, del);
2499 txt_undo_add_charop(text, UNDO_INSERT, add);
2504 void txt_indent(Text *text)
2509 const char *add = "\t";
2512 /* hardcoded: TXT_TABSIZE = 4 spaces: */
2513 int spaceslen = TXT_TABSIZE;
2515 /* insert spaces rather then tabs */
2516 if (text->flags & TXT_TABSTOSPACES){
2517 add = tab_to_spaces;
2518 indentlen = spaceslen;
2522 if (!text->curl) return;
2523 if (!text->sell) return;
2528 tmp= MEM_mallocN(text->curl->len+indentlen+1, "textline_string");
2531 if(text->curc) memcpy(tmp, text->curl->line, text->curc); /* XXX never true, check prev line */
2532 memcpy(tmp+text->curc, add, indentlen);
2534 len= text->curl->len - text->curc;
2535 if(len>0) memcpy(tmp+text->curc+indentlen, text->curl->line+text->curc, len);
2536 tmp[text->curl->len+indentlen]= 0;
2538 make_new_line(text->curl, tmp);
2540 text->curc+= indentlen;
2542 txt_make_dirty(text);
2543 txt_clean_text(text);
2545 if(text->curl == text->sell)
2547 text->selc = text->sell->len;
2550 text->curl = text->curl->next;
2557 text->curl = text->curl->prev;
2563 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);
2567 void txt_unindent(Text *text)
2570 const char *remove = "\t";
2573 /* hardcoded: TXT_TABSIZE = 4 spaces: */
2574 int spaceslen = TXT_TABSIZE;
2576 /* insert spaces rather then tabs */
2577 if (text->flags & TXT_TABSTOSPACES){
2578 remove = tab_to_spaces;
2583 if (!text->curl) return;
2584 if (!text->sell) return;
2590 if (BLI_strncasecmp(text->curl->line, remove, indent) == 0)
2592 while(i< text->curl->len) {
2593 text->curl->line[i]= text->curl->line[i+indent];
2596 text->curl->len-= indent;
2599 txt_make_dirty(text);
2600 txt_clean_text(text);
2602 if(text->curl == text->sell)
2604 text->selc = text->sell->len;
2607 text->curl = text->curl->next;
2615 text->curl = text->curl->prev;
2621 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);
2625 void txt_comment(Text *text)
2632 if (!text->curl) return;
2633 if (!text->sell) return;// Need to change this need to check if only one line is selected to more then one
2638 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2641 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2642 tmp[text->curc]= add;
2644 len= text->curl->len - text->curc;
2645 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2646 tmp[text->curl->len+1]=0;
2648 make_new_line(text->curl, tmp);
2652 txt_make_dirty(text);
2653 txt_clean_text(text);
2655 if(text->curl == text->sell)
2657 text->selc = text->sell->len;
2660 text->curl = text->curl->next;
2667 text->curl = text->curl->prev;
2673 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);
2677 void txt_uncomment(Text *text)
2683 if (!text->curl) return;
2684 if (!text->sell) return;
2690 if (text->curl->line[i] == remove)
2692 while(i< text->curl->len) {
2693 text->curl->line[i]= text->curl->line[i+1];
2700 txt_make_dirty(text);
2701 txt_clean_text(text);
2703 if(text->curl == text->sell)
2705 text->selc = text->sell->len;
2708 text->curl = text->curl->next;
2716 text->curl = text->curl->prev;
2722 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);
2726 int setcurr_tab_spaces (Text *text, int space)
2730 const char *word = ":";
2731 const char *comm = "#";
2732 const char indent= (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t';
2733 static const char *back_words[]= {"return", "break", "continue", "pass", "yield", NULL};
2734 if (!text) return 0;
2735 if (!text->curl) return 0;
2737 while (text->curl->line[i] == indent)
2739 //we only count those tabs/spaces that are before any text or before the curs;
2740 if (i == text->curc)
2747 if(strstr(text->curl->line, word))
2749 /* if we find a ':' on this line, then add a tab but not if it is:
2751 * 2) within an identifier
2752 * 3) after the cursor (text->curc), i.e. when creating space before a function def [#25414]
2754 int a, is_indent = 0;
2755 for(a=0; (a < text->curc) && (text->curl->line[a] != '\0'); a++)
2757 char ch= text->curl->line[a];
2760 } else if (ch==':') {
2762 } else if (ch==']' || ch=='}' || ch=='"' || ch=='\'') {
2771 for(test=0; back_words[test]; test++)
2773 /* if there are these key words then remove a tab because we are done with the block */
2774 if(strstr(text->curl->line, back_words[test]) && i > 0)
2776 if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
2785 /*********************************/
2786 /* Text marker utility functions */
2787 /*********************************/
2789 /* Creates and adds a marker to the list maintaining sorted order */
2790 void txt_add_marker(Text *text, TextLine *line, int start, int end, const unsigned char color[4], int group, int flags) {
2791 TextMarker *tmp, *marker;
2793 marker= MEM_mallocN(sizeof(TextMarker), "text_marker");
2795 marker->lineno= txt_get_span(text->lines.first, line);
2796 marker->start= MIN2(start, end);
2797 marker->end= MAX2(start, end);
2798 marker->group= group;
2799 marker->flags= flags;
2801 marker->color[0]= color[0];
2802 marker->color[1]= color[1];
2803 marker->color[2]= color[2];
2804 marker->color[3]= color[3];
2806 for (tmp=text->markers.last; tmp; tmp=tmp->prev)
2807 if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start))
2810 if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker);
2811 else BLI_addhead(&text->markers, marker);
2814 /* Returns the first matching marker on the specified line between two points.
2815 If the group or flags fields are non-zero the returned flag must be in the
2816 specified group and have at least the specified flags set. */
2817 TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2818 TextMarker *marker, *next;
2819 int lineno= txt_get_span(text->lines.first, line);
2821 for (marker=text->markers.first; marker; marker=next) {
2824 if (group && marker->group != group) continue;
2825 else if ((marker->flags & flags) != flags) continue;
2826 else if (marker->lineno < lineno) continue;
2827 else if (marker->lineno > lineno) break;
2829 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2830 (marker->start<end && marker->end>start))
2836 /* Clears all markers on the specified line between two points. If the group or
2837 flags fields are non-zero the returned flag must be in the specified group
2838 and have at least the specified flags set. */
2839 short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2840 TextMarker *marker, *next;
2841 int lineno= txt_get_span(text->lines.first, line);
2844 for (marker=text->markers.first; marker; marker=next) {
2847 if (group && marker->group != group) continue;
2848 else if ((marker->flags & flags) != flags) continue;
2849 else if (marker->lineno < lineno) continue;
2850 else if (marker->lineno > lineno) break;
2852 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2853 (marker->start<end && marker->end>start)) {
2854 BLI_freelinkN(&text->markers, marker);
2861 /* Clears all markers in the specified group (if given) with at least the
2862 specified flags set. Useful for clearing temporary markers (group=0,
2863 flags=TMARK_TEMP) */
2864 short txt_clear_markers(Text *text, int group, int flags) {
2865 TextMarker *marker, *next;
2868 for (marker=text->markers.first; marker; marker=next) {
2871 if ((!group || marker->group==group) &&
2872 (marker->flags & flags) == flags) {
2873 BLI_freelinkN(&text->markers, marker);
2880 /* Finds the marker at the specified line and cursor position with at least the
2881 specified flags set in the given group (if non-zero). */
2882 TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags) {
2884 int lineno= txt_get_span(text->lines.first, line);
2886 for (marker=text->markers.first; marker; marker=marker->next) {
2887 if (group && marker->group != group) continue;
2888 else if ((marker->flags & flags) != flags) continue;
2889 else if (marker->lineno < lineno) continue;
2890 else if (marker->lineno > lineno) break;
2892 if (marker->start <= curs && curs <= marker->end)
2898 /* Finds the previous marker in the same group. If no other is found, the same
2899 marker will be returned */
2900 TextMarker *txt_prev_marker(Text *text, TextMarker *marker) {
2901 TextMarker *tmp= marker;
2903 if (tmp->prev) tmp= tmp->prev;
2904 else tmp= text->markers.last;
2905 if (tmp->group == marker->group)
2908 return NULL; /* Only if marker==NULL */
2911 /* Finds the next marker in the same group. If no other is found, the same
2912 marker will be returned */
2913 TextMarker *txt_next_marker(Text *text, TextMarker *marker) {
2914 TextMarker *tmp= marker;
2916 if (tmp->next) tmp= tmp->next;
2917 else tmp= text->markers.first;
2918 if (tmp->group == marker->group)
2921 return NULL; /* Only if marker==NULL */
2925 /*******************************/
2926 /* Character utility functions */
2927 /*******************************/
2929 int text_check_bracket(char ch)
2932 char opens[] = "([{";
2933 char close[] = ")]}";
2935 for(a=0; a<(sizeof(opens)-1); a++) {
2938 else if(ch==close[a])
2944 int text_check_delim(char ch)
2947 char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,";
2949 for(a=0; a<(sizeof(delims)-1); a++) {
2956 int text_check_digit(char ch)
2958 if(ch < '0') return 0;
2959 if(ch <= '9') return 1;
2963 int text_check_identifier(char ch)
2965 if(ch < '0') return 0;
2966 if(ch <= '9') return 1;
2967 if(ch < 'A') return 0;
2968 if(ch <= 'Z' || ch == '_') return 1;
2969 if(ch < 'a') return 0;
2970 if(ch <= 'z') return 1;
2974 int text_check_whitespace(char ch)
2976 if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')