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"
40 #include "DNA_constraint_types.h"
41 #include "DNA_controller_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_screen_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_text_types.h"
46 #include "DNA_userdef_types.h"
47 #include "DNA_object_types.h"
49 #include "BKE_depsgraph.h"
50 #include "BKE_global.h"
51 #include "BKE_library.h"
54 #include "BKE_utildefines.h"
56 #ifndef DISABLE_PYTHON
57 #include "BPY_extern.h"
64 A text should relate to a file as follows -
65 (Text *)->name should be the place where the
66 file will or has been saved.
68 (Text *)->flags has the following bits
69 TXT_ISDIRTY - should always be set if the file in mem. differs from
70 the file on disk, or if there is no file on disk.
71 TXT_ISMEM - should always be set if the Text has not been mapped to
72 a file, in which case (Text *)->name may be NULL or garbage.
73 TXT_ISEXT - should always be set if the Text is not to be written into
75 TXT_ISSCRIPT - should be set if the user has designated the text
76 as a script. (NEW: this was unused, but now it is needed by
77 space handler script links (see header_view3d.c, for example)
79 ->>> see also: /makesdna/DNA_text_types.h
83 The st->top determines at what line the top of the text is displayed.
84 If the user moves the cursor the st containing that cursor should
85 be popped ... other st's retain their own top location.
89 The mrk->flags define the behaviour and relationships between markers. The
90 upper two bytes are used to hold a group ID, the lower two are normal flags. If
91 TMARK_EDITALL is set the group ID defines which other markers should be edited.
93 The mrk->clr field is used to visually group markers where the flags may not
94 match. A template system, for example, may allow editing of repeating tokens
95 (in one group) but include other marked positions (in another group) all in the
96 same template with the same colour.
100 Undo/Redo works by storing
101 events in a queue, and a pointer
102 to the current position in the
105 Events are stored using an
106 arbitrary op-code system
108 a) the two cursors (normal and selected)
109 b) input (visible and control (ie backspace))
111 input data is stored as its
112 ASCII value, the opcodes are
113 then selected to not conflict.
115 opcodes with data in between are
116 written at the beginning and end
117 of the data to allow undo and redo
118 to simply check the code at the current
125 static void txt_pop_first(Text *text);
126 static void txt_pop_last(Text *text);
127 static void txt_undo_add_op(Text *text, int op);
128 static void txt_undo_add_block(Text *text, int op, const char *buf);
129 static void txt_delete_line(Text *text, TextLine *line);
130 static void txt_delete_sel (Text *text);
131 static void txt_make_dirty (Text *text);
135 static unsigned char undoing;
137 /* allow to switch off undoing externally */
138 void txt_set_undostate(int u)
143 int txt_get_undostate(void)
148 static void init_undo_text(Text *text)
151 text->undo_len= TXT_INIT_UNDO;
152 text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
155 void free_text(Text *text)
159 for (tmp= text->lines.first; tmp; tmp= tmp->next) {
160 MEM_freeN(tmp->line);
162 MEM_freeN(tmp->format);
165 BLI_freelistN(&text->lines);
166 BLI_freelistN(&text->markers);
168 if(text->name) MEM_freeN(text->name);
169 MEM_freeN(text->undo_buf);
170 #ifndef DISABLE_PYTHON
171 if (text->compiled) BPY_free_compiled_text(text);
175 Text *add_empty_text(char *name)
181 ta= alloc_libblock(&bmain->text, ID_TXT, name);
189 ta->flags= TXT_ISDIRTY | TXT_ISMEM;
190 if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
191 ta->flags |= TXT_TABSTOSPACES;
193 ta->lines.first= ta->lines.last= NULL;
194 ta->markers.first= ta->markers.last= NULL;
196 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
197 tmp->line= (char*) MEM_mallocN(1, "textline_string");
206 BLI_addhead(&ta->lines, tmp);
208 ta->curl= ta->lines.first;
210 ta->sell= ta->lines.first;
216 // this function removes any control characters from
219 static void cleanup_textline(TextLine * tl)
223 for (i = 0; i < tl->len; i++ ) {
224 if (tl->line[i] < ' ' && tl->line[i] != '\t') {
225 memmove(tl->line + i, tl->line + i + 1, tl->len - i);
232 int reopen_text(Text *text)
235 int i, llen, len, res;
236 unsigned char *buffer;
238 char str[FILE_MAXDIR+FILE_MAXFILE];
241 if (!text || !text->name) return 0;
243 BLI_strncpy(str, text->name, FILE_MAXDIR+FILE_MAXFILE);
244 BLI_path_abs(str, G.main->name);
247 if(fp==NULL) return 0;
251 for (tmp= text->lines.first; tmp; tmp= tmp->next) {
252 MEM_freeN(tmp->line);
253 if (tmp->format) MEM_freeN(tmp->format);
256 BLI_freelistN(&text->lines);
258 text->lines.first= text->lines.last= NULL;
259 text->curl= text->sell= NULL;
261 /* clear undo buffer */
262 MEM_freeN(text->undo_buf);
263 init_undo_text(text);
265 fseek(fp, 0L, SEEK_END);
267 fseek(fp, 0L, SEEK_SET);
271 buffer= MEM_mallocN(len, "text_buffer");
272 // under windows fread can return less then len bytes because
274 len = fread(buffer, 1, len, fp);
279 text->mtime= st.st_mtime;
284 for(i=0; i<len; i++) {
285 if (buffer[i]=='\n') {
286 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
287 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
290 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
294 cleanup_textline(tmp);
296 BLI_addtail(&text->lines, tmp);
305 if (llen!=0 || text->nlines==0) {
306 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
307 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
310 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
315 cleanup_textline(tmp);
317 BLI_addtail(&text->lines, tmp);
321 text->curl= text->sell= text->lines.first;
322 text->curc= text->selc= 0;
328 Text *add_text(char *file, const char *relpath)
332 int i, llen, len, res;
333 unsigned char *buffer;
336 char str[FILE_MAXDIR+FILE_MAXFILE];
339 BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE);
340 if (relpath) /* can be NULL (bg mode) */
341 BLI_path_abs(str, relpath);
344 if(fp==NULL) return NULL;
346 ta= alloc_libblock(&bmain->text, ID_TXT, BLI_path_basename(str));
349 ta->lines.first= ta->lines.last= NULL;
350 ta->markers.first= ta->markers.last= NULL;
351 ta->curl= ta->sell= NULL;
353 if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
354 ta->flags= TXT_TABSTOSPACES;
356 fseek(fp, 0L, SEEK_END);
358 fseek(fp, 0L, SEEK_SET);
360 ta->name= MEM_mallocN(strlen(file)+1, "text_name");
361 strcpy(ta->name, file);
365 buffer= MEM_mallocN(len, "text_buffer");
366 // under windows fread can return less then len bytes because
368 len = fread(buffer, 1, len, fp);
373 ta->mtime= st.st_mtime;
378 for(i=0; i<len; i++) {
379 if (buffer[i]=='\n') {
380 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
381 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
384 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
388 cleanup_textline(tmp);
390 BLI_addtail(&ta->lines, tmp);
399 if (llen!=0 || ta->nlines==0) {
400 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
401 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
404 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
409 cleanup_textline(tmp);
411 BLI_addtail(&ta->lines, tmp);
415 ta->curl= ta->sell= ta->lines.first;
416 ta->curc= ta->selc= 0;
423 Text *copy_text(Text *ta)
426 TextLine *line, *tmp;
428 tan= copy_libblock(ta);
430 /* file name can be NULL */
432 tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name");
433 strcpy(tan->name, ta->name);
439 tan->flags = ta->flags | TXT_ISDIRTY;
441 tan->lines.first= tan->lines.last= NULL;
442 tan->markers.first= tan->markers.last= NULL;
443 tan->curl= tan->sell= NULL;
445 tan->nlines= ta->nlines;
447 line= ta->lines.first;
448 /* Walk down, reconstructing */
450 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
451 tmp->line= MEM_mallocN(line->len+1, "textline_string");
454 strcpy(tmp->line, line->line);
458 BLI_addtail(&tan->lines, tmp);
463 tan->curl= tan->sell= tan->lines.first;
464 tan->curc= tan->selc= 0;
471 void unlink_text(Main *bmain, Text *text)
483 for(scene=bmain->scene.first; scene; scene=scene->id.next)
484 if(scene->r.dometext == text)
485 scene->r.dometext = NULL;
487 for(ob=bmain->object.first; ob; ob=ob->id.next) {
488 /* game controllers */
489 for(cont=ob->controllers.first; cont; cont=cont->next) {
490 if(cont->type==CONT_PYTHON) {
494 if(pc->text==text) pc->text= NULL;
501 if(ob->type==OB_ARMATURE && ob->pose) {
503 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
504 for(con = pchan->constraints.first; con; con=con->next) {
505 if(con->type==CONSTRAINT_TYPE_PYTHON) {
506 bPythonConstraint *data = con->data;
507 if (data->text==text) data->text = NULL;
515 for(con = ob->constraints.first; con; con=con->next) {
516 if(con->type==CONSTRAINT_TYPE_PYTHON) {
517 bPythonConstraint *data = con->data;
518 if (data->text==text) data->text = NULL;
524 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
528 // XXX nodeDynamicUnlinkText(&text->id);
531 for(scr= bmain->screen.first; scr; scr= scr->id.next) {
532 for(area= scr->areabase.first; area; area= area->next) {
533 for(sl= area->spacedata.first; sl; sl= sl->next) {
534 if(sl->spacetype==SPACE_TEXT) {
535 SpaceText *st= (SpaceText*) sl;
549 void clear_text(Text *text) /* called directly from rna */
553 oldstate = txt_get_undostate( );
554 txt_set_undostate( 1 );
556 txt_delete_sel(text);
557 txt_set_undostate( oldstate );
559 txt_make_dirty(text);
562 void write_text(Text *text, char *str) /* called directly from rna */
566 oldstate = txt_get_undostate( );
567 txt_insert_buf( text, str );
568 txt_move_eof( text, 0 );
569 txt_set_undostate( oldstate );
571 txt_make_dirty(text);
574 /*****************************/
575 /* Editing utility functions */
576 /*****************************/
578 static void make_new_line (TextLine *line, char *newline)
580 if (line->line) MEM_freeN(line->line);
581 if (line->format) MEM_freeN(line->format);
584 line->len= strlen(newline);
588 static TextLine *txt_new_line(char *str)
594 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
595 tmp->line= MEM_mallocN(strlen(str)+1, "textline_string");
598 strcpy(tmp->line, str);
600 tmp->len= strlen(str);
601 tmp->next= tmp->prev= NULL;
606 static TextLine *txt_new_linen(const char *str, int n)
610 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
611 tmp->line= MEM_mallocN(n+1, "textline_string");
614 BLI_strncpy(tmp->line, (str)? str: "", n+1);
616 tmp->len= strlen(tmp->line);
617 tmp->next= tmp->prev= NULL;
622 void txt_clean_text (Text *text)
624 TextLine **top, **bot;
628 if (!text->lines.first) {
629 if (text->lines.last) text->lines.first= text->lines.last;
630 else text->lines.first= text->lines.last= txt_new_line(NULL);
633 if (!text->lines.last) text->lines.last= text->lines.first;
635 top= (TextLine **) &text->lines.first;
636 bot= (TextLine **) &text->lines.last;
638 while ((*top)->prev) *top= (*top)->prev;
639 while ((*bot)->next) *bot= (*bot)->next;
642 if(text->sell) text->curl= text->sell;
643 else text->curl= text->lines.first;
648 text->sell= text->curl;
653 int txt_get_span (TextLine *from, TextLine *to)
658 if (!to || !from) return 0;
659 if (from==to) return 0;
663 if (tmp == to) return ret;
673 if (tmp == to) break;
683 static void txt_make_dirty (Text *text)
685 text->flags |= TXT_ISDIRTY;
686 #ifndef DISABLE_PYTHON
687 if (text->compiled) BPY_free_compiled_text(text);
691 /* 0:whitespace, 1:punct, 2:alphanumeric */
692 static short txt_char_type (char ch)
694 if (ch <= ' ') return 0; /* 32 */
695 if (ch <= '/') return 1; /* 47 */
696 if (ch <= '9') return 2; /* 57 */
697 if (ch <= '@') return 1; /* 64 */
698 if (ch <= 'Z') return 2; /* 90 */
699 if (ch == '_') return 2; /* 95, dont delimit '_' */
700 if (ch <= '`') return 1; /* 96 */
701 if (ch <= 'z') return 2; /* 122 */
705 /****************************/
706 /* Cursor utility functions */
707 /****************************/
709 static void txt_curs_cur (Text *text, TextLine ***linep, int **charp)
711 *linep= &text->curl; *charp= &text->curc;
714 static void txt_curs_sel (Text *text, TextLine ***linep, int **charp)
716 *linep= &text->sell; *charp= &text->selc;
719 static void txt_curs_first (Text *text, TextLine **linep, int *charp)
721 if (text->curl==text->sell) {
723 if (text->curc<text->selc) *charp= text->curc;
724 else *charp= text->selc;
725 } else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) {
734 /****************************/
735 /* Cursor movement functions */
736 /****************************/
738 void txt_move_up(Text *text, short sel)
744 if(sel) txt_curs_sel(text, &linep, &charp);
745 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
750 *linep= (*linep)->prev;
751 if (*charp > (*linep)->len) {
752 *charp= (*linep)->len;
753 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);
755 if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
758 txt_move_bol(text, sel);
761 if(!sel) txt_pop_sel(text);
764 void txt_move_down(Text *text, short sel)
770 if(sel) txt_curs_sel(text, &linep, &charp);
771 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
776 *linep= (*linep)->next;
777 if (*charp > (*linep)->len) {
778 *charp= (*linep)->len;
779 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);
781 if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
783 txt_move_eol(text, sel);
786 if(!sel) txt_pop_sel(text);
789 void txt_move_left(Text *text, short sel)
792 int *charp, oundoing= undoing;
795 if(sel) txt_curs_sel(text, &linep, &charp);
796 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
801 if ((*linep)->prev) {
802 txt_move_up(text, sel);
803 *charp= (*linep)->len;
809 if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
811 if(!sel) txt_pop_sel(text);
814 void txt_move_right(Text *text, short sel)
817 int *charp, oundoing= undoing;
820 if(sel) txt_curs_sel(text, &linep, &charp);
821 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
825 if (*charp== (*linep)->len) {
826 if ((*linep)->next) {
827 txt_move_down(text, sel);
834 if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
836 if(!sel) txt_pop_sel(text);
839 void txt_jump_left(Text *text, short sel)
841 TextLine **linep, *oldl;
842 int *charp, oldc, count, i;
846 if(sel) txt_curs_sel(text, &linep, &charp);
847 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
853 undoing= 1; /* Don't push individual moves to undo stack */
856 for (i=0; i<3; i++) {
858 while (*charp>0 && txt_char_type((*linep)->line[*charp-1])==i) {
859 txt_move_left(text, sel);
864 if (count==0) txt_move_left(text, sel);
867 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);
870 void txt_jump_right(Text *text, short sel)
872 TextLine **linep, *oldl;
873 int *charp, oldc, count, i;
877 if(sel) txt_curs_sel(text, &linep, &charp);
878 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
884 undoing= 1; /* Don't push individual moves to undo stack */
887 for (i=0; i<3; i++) {
889 while (*charp<(*linep)->len && txt_char_type((*linep)->line[*charp])==i) {
890 txt_move_right(text, sel);
895 if (count==0) txt_move_right(text, sel);
898 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);
901 void txt_move_bol (Text *text, short sel)
907 if(sel) txt_curs_sel(text, &linep, &charp);
908 else txt_curs_cur(text, &linep, &charp);
914 if(!sel) txt_pop_sel(text);
915 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);
918 void txt_move_eol (Text *text, short sel)
924 if(sel) txt_curs_sel(text, &linep, &charp);
925 else txt_curs_cur(text, &linep, &charp);
929 *charp= (*linep)->len;
931 if(!sel) txt_pop_sel(text);
932 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);
935 void txt_move_bof (Text *text, short sel)
941 if(sel) txt_curs_sel(text, &linep, &charp);
942 else txt_curs_cur(text, &linep, &charp);
946 *linep= text->lines.first;
949 if(!sel) txt_pop_sel(text);
950 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);
953 void txt_move_eof (Text *text, short sel)
959 if(sel) txt_curs_sel(text, &linep, &charp);
960 else txt_curs_cur(text, &linep, &charp);
964 *linep= text->lines.last;
965 *charp= (*linep)->len;
967 if(!sel) txt_pop_sel(text);
968 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);
971 void txt_move_toline (Text *text, unsigned int line, short sel)
973 txt_move_to(text, line, 0, sel);
976 void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel)
978 TextLine **linep, *oldl;
983 if(sel) txt_curs_sel(text, &linep, &charp);
984 else txt_curs_cur(text, &linep, &charp);
989 *linep= text->lines.first;
990 for (i=0; i<line; i++) {
991 if ((*linep)->next) *linep= (*linep)->next;
994 if (ch>(unsigned int)((*linep)->len))
995 ch= (unsigned int)((*linep)->len);
998 if(!sel) txt_pop_sel(text);
999 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);
1002 /****************************/
1003 /* Text selection functions */
1004 /****************************/
1006 static void txt_curs_swap (Text *text)
1012 text->curl= text->sell;
1016 text->curc= text->selc;
1019 if(!undoing) txt_undo_add_op(text, UNDO_SWAP);
1022 static void txt_pop_first (Text *text)
1025 if (txt_get_span(text->curl, text->sell)<0 ||
1026 (text->curl==text->sell && text->curc>text->selc)) {
1027 txt_curs_swap(text);
1030 if(!undoing) txt_undo_add_toop(text, UNDO_STO,
1031 txt_get_span(text->lines.first, text->sell),
1033 txt_get_span(text->lines.first, text->curl),
1039 static void txt_pop_last (Text *text)
1041 if (txt_get_span(text->curl, text->sell)>0 ||
1042 (text->curl==text->sell && text->curc<text->selc)) {
1043 txt_curs_swap(text);
1046 if(!undoing) txt_undo_add_toop(text, UNDO_STO,
1047 txt_get_span(text->lines.first, text->sell),
1049 txt_get_span(text->lines.first, text->curl),
1055 /* never used: CVS 1.19 */
1056 /* static void txt_pop_selr (Text *text) */
1058 void txt_pop_sel (Text *text)
1060 text->sell= text->curl;
1061 text->selc= text->curc;
1064 void txt_order_cursors(Text *text)
1067 if (!text->curl) return;
1068 if (!text->sell) return;
1070 /* Flip so text->curl is before text->sell */
1071 if (txt_get_span(text->curl, text->sell)<0 ||
1072 (text->curl==text->sell && text->curc>text->selc))
1073 txt_curs_swap(text);
1076 int txt_has_sel(Text *text)
1078 return ((text->curl!=text->sell) || (text->curc!=text->selc));
1081 static void txt_delete_sel (Text *text)
1089 if (!text->curl) return;
1090 if (!text->sell) return;
1092 if (!txt_has_sel(text)) return;
1094 txt_order_cursors(text);
1097 buf= txt_sel_to_buf(text);
1098 txt_undo_add_block(text, UNDO_DBLOCK, buf);
1102 buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
1104 if (text->curl != text->sell) {
1105 txt_clear_marker_region(text, text->curl, text->curc, text->curl->len, 0, 0);
1106 move= txt_get_span(text->curl, text->sell);
1108 mrk= txt_find_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
1109 if (mrk && (mrk->start > text->curc || mrk->end < text->selc))
1110 txt_clear_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
1114 mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0);
1116 lineno= mrk->lineno;
1118 mrk->lineno -= move;
1119 if (mrk->start > text->curc) mrk->start -= text->selc - text->curc;
1120 mrk->end -= text->selc - text->curc;
1122 } while (mrk && mrk->lineno==lineno);
1125 strncpy(buf, text->curl->line, text->curc);
1126 strcpy(buf+text->curc, text->sell->line + text->selc);
1127 buf[text->curc+(text->sell->len - text->selc)]=0;
1129 make_new_line(text->curl, buf);
1132 while (tmpl != text->curl) {
1136 txt_delete_line(text, tmpl->next);
1139 text->sell= text->curl;
1140 text->selc= text->curc;
1143 void txt_sel_all (Text *text)
1147 text->curl= text->lines.first;
1150 text->sell= text->lines.last;
1151 text->selc= text->sell->len;
1154 void txt_sel_line (Text *text)
1157 if (!text->curl) return;
1160 text->sell= text->curl;
1161 text->selc= text->sell->len;
1164 /***************************/
1165 /* Cut and paste functions */
1166 /***************************/
1168 char *txt_to_buf (Text *text)
1171 TextLine *tmp, *linef, *linel;
1175 if (!text) return NULL;
1176 if (!text->curl) return NULL;
1177 if (!text->sell) return NULL;
1178 if (!text->lines.first) return NULL;
1180 linef= text->lines.first;
1183 linel= text->lines.last;
1186 if (linef == text->lines.last) {
1187 length= charl-charf;
1189 buf= MEM_mallocN(length+2, "text buffer");
1191 BLI_strncpy(buf, linef->line + charf, length+1);
1194 length= linef->len - charf;
1196 length+= 2; /* For the 2 '\n' */
1199 while (tmp && tmp!= linel) {
1200 length+= tmp->len+1;
1204 buf= MEM_mallocN(length+1, "cut buffer");
1206 strncpy(buf, linef->line + charf, linef->len-charf);
1207 length= linef->len - charf;
1212 while (tmp && tmp!=linel) {
1213 strncpy(buf+length, tmp->line, tmp->len);
1220 strncpy(buf+length, linel->line, charl);
1223 /* python compiler wants an empty end line */
1231 int txt_find_string(Text *text, char *findstr, int wrap)
1233 TextLine *tl, *startl;
1235 int oldcl, oldsl, oldcc, oldsc;
1237 if (!text || !text->curl || !text->sell) return 0;
1239 txt_order_cursors(text);
1241 oldcl= txt_get_span(text->lines.first, text->curl);
1242 oldsl= txt_get_span(text->lines.first, text->sell);
1243 tl= startl= text->sell;
1247 s= strstr(&tl->line[text->selc], findstr);
1252 tl= text->lines.first;
1257 s= strstr(tl->line, findstr);
1263 int newl= txt_get_span(text->lines.first, tl);
1264 int newc= (int)(s-tl->line);
1265 txt_move_to(text, newl, newc, 0);
1266 txt_move_to(text, newl, newc + strlen(findstr), 1);
1272 char *txt_sel_to_buf (Text *text)
1276 TextLine *tmp, *linef, *linel;
1279 if (!text) return NULL;
1280 if (!text->curl) return NULL;
1281 if (!text->sell) return NULL;
1283 if (text->curl==text->sell) {
1284 linef= linel= text->curl;
1286 if (text->curc < text->selc) {
1293 } else if (txt_get_span(text->curl, text->sell)<0) {
1307 if (linef == linel) {
1308 length= charl-charf;
1310 buf= MEM_mallocN(length+1, "sel buffer");
1312 BLI_strncpy(buf, linef->line + charf, length+1);
1314 length+= linef->len - charf;
1316 length++; /* For the '\n' */
1319 while (tmp && tmp!= linel) {
1320 length+= tmp->len+1;
1324 buf= MEM_mallocN(length+1, "sel buffer");
1326 strncpy(buf, linef->line+ charf, linef->len-charf);
1327 length= linef->len-charf;
1332 while (tmp && tmp!=linel) {
1333 strncpy(buf+length, tmp->line, tmp->len);
1340 strncpy(buf+length, linel->line, charl);
1349 void txt_insert_buf(Text *text, const char *in_buffer)
1351 int i=0, l=0, j, u, len;
1355 if (!in_buffer) return;
1357 txt_delete_sel(text);
1359 if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer);
1364 /* Read the first line (or as close as possible */
1365 while (in_buffer[i] && in_buffer[i]!='\n') {
1366 txt_add_char(text, in_buffer[i]);
1370 if (in_buffer[i]=='\n') txt_split_curline(text);
1371 else { undoing = u; return; }
1374 /* Read as many full lines as we can */
1375 len= strlen(in_buffer);
1380 while (in_buffer[i] && in_buffer[i]!='\n') {
1384 if(in_buffer[i]=='\n') {
1385 add= txt_new_linen(in_buffer +(i-l), l);
1386 BLI_insertlinkbefore(&text->lines, text->curl, add);
1389 for (j= i-l; j<i && j<(int)strlen(in_buffer); j++) {
1390 txt_add_char(text, in_buffer[j]);
1399 /******************/
1400 /* Undo functions */
1401 /******************/
1403 static int max_undo_test(Text *text, int x)
1405 while (text->undo_pos+x >= text->undo_len) {
1406 if(text->undo_len*2 > TXT_MAX_UNDO) {
1407 /* XXX error("Undo limit reached, buffer cleared\n"); */
1408 MEM_freeN(text->undo_buf);
1409 init_undo_text(text);
1412 void *tmp= text->undo_buf;
1413 text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf");
1414 memcpy(text->undo_buf, tmp, text->undo_len);
1423 static void dump_buffer(Text *text)
1427 while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
1430 void txt_print_undo(Text *text)
1439 printf ("---< Undo Buffer >---\n");
1441 printf ("UndoPosition is %d\n", text->undo_pos);
1443 while (i<=text->undo_pos) {
1444 op= text->undo_buf[i];
1446 if (op==UNDO_CLEFT) {
1448 } else if (op==UNDO_CRIGHT) {
1449 ops= "Cursor right";
1450 } else if (op==UNDO_CUP) {
1452 } else if (op==UNDO_CDOWN) {
1454 } else if (op==UNDO_SLEFT) {
1455 ops= "Selection left";
1456 } else if (op==UNDO_SRIGHT) {
1457 ops= "Selection right";
1458 } else if (op==UNDO_SUP) {
1459 ops= "Selection up";
1460 } else if (op==UNDO_SDOWN) {
1461 ops= "Selection down";
1462 } else if (op==UNDO_STO) {
1464 } else if (op==UNDO_CTO) {
1466 } else if (op==UNDO_INSERT) {
1468 } else if (op==UNDO_BS) {
1470 } else if (op==UNDO_DEL) {
1472 } else if (op==UNDO_SWAP) {
1474 } else if (op==UNDO_DBLOCK) {
1475 ops= "Delete text block";
1476 } else if (op==UNDO_IBLOCK) {
1477 ops= "Insert text block";
1478 } else if (op==UNDO_INDENT) {
1480 } else if (op==UNDO_UNINDENT) {
1482 } else if (op==UNDO_COMMENT) {
1484 } else if (op==UNDO_UNCOMMENT) {
1490 printf ("Op (%o) at %d = %s", op, i, ops);
1491 if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) {
1493 printf (" - Char is %c", text->undo_buf[i]);
1495 } else if (op==UNDO_STO || op==UNDO_CTO) {
1498 charp= text->undo_buf[i]; i++;
1499 charp= charp+(text->undo_buf[i]<<8); i++;
1501 linep= text->undo_buf[i]; i++;
1502 linep= linep+(text->undo_buf[i]<<8); i++;
1503 linep= linep+(text->undo_buf[i]<<16); i++;
1504 linep= linep+(text->undo_buf[i]<<24); i++;
1506 printf ("to <%d, %d> ", linep, charp);
1508 charp= text->undo_buf[i]; i++;
1509 charp= charp+(text->undo_buf[i]<<8); i++;
1511 linep= text->undo_buf[i]; i++;
1512 linep= linep+(text->undo_buf[i]<<8); i++;
1513 linep= linep+(text->undo_buf[i]<<16); i++;
1514 linep= linep+(text->undo_buf[i]<<24); i++;
1516 printf ("from <%d, %d>", linep, charp);
1517 } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
1520 linep= text->undo_buf[i]; i++;
1521 linep= linep+(text->undo_buf[i]<<8); i++;
1522 linep= linep+(text->undo_buf[i]<<16); i++;
1523 linep= linep+(text->undo_buf[i]<<24); i++;
1525 printf (" (length %d) <", linep);
1528 putchar(text->undo_buf[i]);
1532 linep= text->undo_buf[i]; i++;
1533 linep= linep+(text->undo_buf[i]<<8); i++;
1534 linep= linep+(text->undo_buf[i]<<16); i++;
1535 linep= linep+(text->undo_buf[i]<<24); i++;
1536 printf ("> (%d)", linep);
1537 } else if (op==UNDO_INDENT || op==UNDO_UNINDENT) {
1540 charp= text->undo_buf[i]; i++;
1541 charp= charp+(text->undo_buf[i]<<8); i++;
1543 linep= text->undo_buf[i]; i++;
1544 linep= linep+(text->undo_buf[i]<<8); i++;
1545 linep= linep+(text->undo_buf[i]<<16); i++;
1546 linep= linep+(text->undo_buf[i]<<24); i++;
1548 printf ("to <%d, %d> ", linep, charp);
1550 charp= text->undo_buf[i]; i++;
1551 charp= charp+(text->undo_buf[i]<<8); i++;
1553 linep= text->undo_buf[i]; i++;
1554 linep= linep+(text->undo_buf[i]<<8); i++;
1555 linep= linep+(text->undo_buf[i]<<16); i++;
1556 linep= linep+(text->undo_buf[i]<<24); i++;
1558 printf ("from <%d, %d>", linep, charp);
1561 printf (" %d\n", i);
1566 static void txt_undo_add_op(Text *text, int op)
1568 if(!max_undo_test(text, 2))
1572 text->undo_buf[text->undo_pos]= op;
1573 text->undo_buf[text->undo_pos+1]= 0;
1576 static void txt_undo_add_block(Text *text, int op, const char *buf)
1580 length= strlen(buf);
1582 if(!max_undo_test(text, length+11))
1586 text->undo_buf[text->undo_pos]= op;
1589 text->undo_buf[text->undo_pos]= (length)&0xff;
1591 text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1593 text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1595 text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1598 strncpy(text->undo_buf+text->undo_pos, buf, length);
1599 text->undo_pos+=length;
1601 text->undo_buf[text->undo_pos]= (length)&0xff;
1603 text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1605 text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1607 text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1610 text->undo_buf[text->undo_pos]= op;
1612 text->undo_buf[text->undo_pos+1]= 0;
1615 void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
1617 if(!max_undo_test(text, 15))
1620 if (froml==tol && fromc==toc) return;
1623 text->undo_buf[text->undo_pos]= op;
1626 text->undo_buf[text->undo_pos]= (fromc)&0xff;
1628 text->undo_buf[text->undo_pos]= (fromc>>8)&0xff;
1631 text->undo_buf[text->undo_pos]= (froml)&0xff;
1633 text->undo_buf[text->undo_pos]= (froml>>8)&0xff;
1635 text->undo_buf[text->undo_pos]= (froml>>16)&0xff;
1637 text->undo_buf[text->undo_pos]= (froml>>24)&0xff;
1640 text->undo_buf[text->undo_pos]= (toc)&0xff;
1642 text->undo_buf[text->undo_pos]= (toc>>8)&0xff;
1645 text->undo_buf[text->undo_pos]= (tol)&0xff;
1647 text->undo_buf[text->undo_pos]= (tol>>8)&0xff;
1649 text->undo_buf[text->undo_pos]= (tol>>16)&0xff;
1651 text->undo_buf[text->undo_pos]= (tol>>24)&0xff;
1654 text->undo_buf[text->undo_pos]= op;
1656 text->undo_buf[text->undo_pos+1]= 0;
1659 static void txt_undo_add_charop(Text *text, int op, char c)
1661 if(!max_undo_test(text, 4))
1665 text->undo_buf[text->undo_pos]= op;
1667 text->undo_buf[text->undo_pos]= c;
1669 text->undo_buf[text->undo_pos]= op;
1670 text->undo_buf[text->undo_pos+1]= 0;
1673 void txt_do_undo(Text *text)
1675 int op= text->undo_buf[text->undo_pos];
1676 unsigned int linep, i;
1677 unsigned short charp;
1682 if (text->undo_pos<0) {
1692 txt_move_right(text, 0);
1696 txt_move_left(text, 0);
1700 txt_move_down(text, 0);
1704 txt_move_up(text, 0);
1708 txt_move_right(text, 1);
1712 txt_move_left(text, 1);
1716 txt_move_down(text, 1);
1720 txt_move_up(text, 1);
1733 linep= 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--;
1736 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1738 charp= text->undo_buf[text->undo_pos]; text->undo_pos--;
1739 charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1742 txt_move_toline(text, linep, 0);
1746 txt_move_toline(text, linep, 1);
1754 txt_backspace_char(text);
1760 txt_add_char(text, text->undo_buf[text->undo_pos]);
1766 txt_add_char(text, text->undo_buf[text->undo_pos]);
1767 txt_move_left(text, 0);
1773 txt_curs_swap(text);
1777 linep= 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--;
1780 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1782 buf= MEM_mallocN(linep+1, "dblock buffer");
1783 for (i=0; i < linep; i++){
1784 buf[(linep-1)-i]= text->undo_buf[text->undo_pos];
1789 txt_curs_first(text, &holdl, &holdc);
1790 holdln= txt_get_span(text->lines.first, holdl);
1792 txt_insert_buf(text, buf);
1795 text->curl= text->lines.first;
1797 if(text->curl->next)
1798 text->curl= text->curl->next;
1804 linep= 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--;
1807 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1814 linep= 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--;
1817 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1819 txt_delete_sel(text);
1821 txt_backspace_char(text);
1837 case UNDO_UNCOMMENT:
1838 linep= 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 = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1842 //linep is now the end line of the selection
1844 charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1845 charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1846 //charp is the last char selected or text->line->len
1847 //set the selcetion for this now
1849 text->sell = text->lines.first;
1850 for (i= 0; i < linep; i++) {
1851 text->sell = text->sell->next;
1854 linep= 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 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1858 //first line to be selected
1860 charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1861 charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1862 //first postion to be selected
1864 text->curl = text->lines.first;
1865 for (i = 0; i < linep; i++) {
1866 text->curl = text->curl->next;
1870 if (op==UNDO_INDENT) {
1872 } else if (op== UNDO_UNINDENT) {
1874 } else if (op == UNDO_COMMENT) {
1876 } else if (op == UNDO_UNCOMMENT) {
1883 //XXX error("Undo buffer error - resetting");
1889 /* next undo step may need evaluating */
1890 if (text->undo_pos>=0) {
1891 switch (text->undo_buf[text->undo_pos]) {
1894 txt_do_redo(text); /* selections need restoring */
1897 txt_do_undo(text); /* swaps should appear transparent */
1905 void txt_do_redo(Text *text)
1908 unsigned int linep, i;
1909 unsigned short charp;
1913 op= text->undo_buf[text->undo_pos];
1924 txt_move_left(text, 0);
1928 txt_move_right(text, 0);
1932 txt_move_up(text, 0);
1936 txt_move_down(text, 0);
1940 txt_move_left(text, 1);
1944 txt_move_right(text, 1);
1948 txt_move_up(text, 1);
1952 txt_move_down(text, 1);
1957 txt_add_char(text, text->undo_buf[text->undo_pos]);
1963 txt_backspace_char(text);
1969 txt_delete_char(text);
1974 txt_curs_swap(text);
1975 txt_do_redo(text); /* swaps should appear transparent a*/
1990 charp= text->undo_buf[text->undo_pos];
1992 charp= charp+(text->undo_buf[text->undo_pos]<<8);
1995 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1996 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1997 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1998 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2001 txt_move_toline(text, linep, 0);
2005 txt_move_toline(text, linep, 1);
2013 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2014 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2015 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2016 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2018 txt_delete_sel(text);
2019 text->undo_pos+=linep;
2030 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2031 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2032 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2033 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2035 buf= MEM_mallocN(linep+1, "iblock buffer");
2036 memcpy (buf, &text->undo_buf[text->undo_pos], linep);
2037 text->undo_pos+= linep;
2040 txt_insert_buf(text, buf);
2043 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2044 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2045 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2046 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2052 case UNDO_UNCOMMENT:
2054 charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2055 charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2056 //charp is the first char selected or 0
2058 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2059 linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2060 linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2061 linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2062 //linep is now the first line of the selection
2063 //set the selcetion for this now
2065 text->curl = text->lines.first;
2066 for (i= 0; i < linep; i++) {
2067 text->curl = text->curl->next;
2070 charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2071 charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2072 //last postion to be selected
2073 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2074 linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2075 linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2076 linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2077 //Last line to be selected
2080 text->sell = text->lines.first;
2081 for (i = 0; i < linep; i++) {
2082 text->sell = text->sell->next;
2085 if (op==UNDO_INDENT) {
2087 } else if (op== UNDO_UNINDENT) {
2089 } else if (op == UNDO_COMMENT) {
2091 } else if (op == UNDO_UNCOMMENT) {
2096 //XXX error("Undo buffer error - resetting");
2105 /**************************/
2106 /* Line editing functions */
2107 /**************************/
2109 void txt_split_curline (Text *text)
2117 if (!text->curl) return;
2119 txt_delete_sel(text);
2123 lineno= txt_get_span(text->lines.first, text->curl);
2124 mrk= text->markers.first;
2126 if (mrk->lineno==lineno && mrk->start>text->curc) {
2128 mrk->start -= text->curc;
2129 mrk->end -= text->curc;
2130 } else if (mrk->lineno > lineno) {
2136 /* Make the two half strings */
2138 left= MEM_mallocN(text->curc+1, "textline_string");
2139 if (text->curc) memcpy(left, text->curl->line, text->curc);
2142 right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
2143 if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc);
2144 right[text->curl->len - text->curc]=0;
2146 MEM_freeN(text->curl->line);
2147 if (text->curl->format) MEM_freeN(text->curl->format);
2149 /* Make the new TextLine */
2151 ins= MEM_mallocN(sizeof(TextLine), "textline");
2154 ins->len= text->curc;
2156 text->curl->line= right;
2157 text->curl->format= NULL;
2158 text->curl->len= text->curl->len - text->curc;
2160 BLI_insertlinkbefore(&text->lines, text->curl, ins);
2164 txt_make_dirty(text);
2165 txt_clean_text(text);
2168 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n');
2171 static void txt_delete_line (Text *text, TextLine *line)
2173 TextMarker *mrk=NULL, *nxt;
2177 if (!text->curl) return;
2179 lineno= txt_get_span(text->lines.first, line);
2180 mrk= text->markers.first;
2183 if (mrk->lineno==lineno)
2184 BLI_freelinkN(&text->markers, mrk);
2185 else if (mrk->lineno > lineno)
2190 BLI_remlink (&text->lines, line);
2192 if (line->line) MEM_freeN(line->line);
2193 if (line->format) MEM_freeN(line->format);
2197 txt_make_dirty(text);
2198 txt_clean_text(text);
2201 static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
2204 TextMarker *mrk= NULL;
2209 if(!linea || !lineb) return;
2211 mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0);
2213 lineno= mrk->lineno;
2216 mrk->start += linea->len;
2217 mrk->end += linea->len;
2219 } while (mrk && mrk->lineno==lineno);
2221 if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb);
2222 if (!mrk) mrk= text->markers.first;
2224 tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
2226 strcpy(tmp, linea->line);
2227 strcat(tmp, lineb->line);
2229 make_new_line(linea, tmp);
2231 txt_delete_line(text, lineb);
2233 txt_make_dirty(text);
2234 txt_clean_text(text);
2237 void txt_delete_char (Text *text)
2242 if (!text->curl) return;
2244 if (txt_has_sel(text)) { /* deleting a selection */
2245 txt_delete_sel(text);
2246 txt_make_dirty(text);
2249 else if (text->curc== text->curl->len) { /* Appending two lines */
2250 if (text->curl->next) {
2251 txt_combine_lines(text, text->curl, text->curl->next);
2254 } else { /* Just deleting a char */
2257 TextMarker *mrk= txt_find_marker_region(text, text->curl, i-1, text->curl->len, 0, 0);
2259 int lineno= mrk->lineno;
2261 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2262 txt_clear_markers(text, mrk->group, TMARK_TEMP);
2264 BLI_freelinkN(&text->markers, mrk);
2269 if (mrk->start>i) mrk->start--;
2272 } while (mrk && mrk->lineno==lineno);
2275 c= text->curl->line[i];
2276 while(i< text->curl->len) {
2277 text->curl->line[i]= text->curl->line[i+1];
2285 txt_make_dirty(text);
2286 txt_clean_text(text);
2288 if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c);
2291 void txt_delete_word (Text *text)
2293 txt_jump_right(text, 1);
2294 txt_delete_sel(text);
2297 void txt_backspace_char (Text *text)
2302 if (!text->curl) return;
2304 if (txt_has_sel(text)) { /* deleting a selection */
2305 txt_delete_sel(text);
2306 txt_make_dirty(text);
2309 else if (text->curc==0) { /* Appending two lines */
2310 if (!text->curl->prev) return;
2312 text->curl= text->curl->prev;
2313 text->curc= text->curl->len;
2315 txt_combine_lines(text, text->curl, text->curl->next);
2318 else { /* Just backspacing a char */
2319 int i= text->curc-1;
2321 TextMarker *mrk= txt_find_marker_region(text, text->curl, i, text->curl->len, 0, 0);
2323 int lineno= mrk->lineno;
2324 if (mrk->start==i+1) {
2325 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2326 txt_clear_markers(text, mrk->group, TMARK_TEMP);
2328 BLI_freelinkN(&text->markers, mrk);
2333 if (mrk->start>i) mrk->start--;
2336 } while (mrk && mrk->lineno==lineno);
2339 c= text->curl->line[i];
2340 while(i< text->curl->len) {
2341 text->curl->line[i]= text->curl->line[i+1];
2350 txt_make_dirty(text);
2351 txt_clean_text(text);
2353 if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
2356 void txt_backspace_word (Text *text)
2358 txt_jump_left(text, 1);
2359 txt_delete_sel(text);
2362 /* Max spaces to replace a tab with, currently hardcoded to TXT_TABSIZE = 4.
2363 * Used by txt_convert_tab_to_spaces, indent and unintent.
2364 * Remember to change this string according to max tab size */
2365 static char tab_to_spaces[] = " ";
2367 static void txt_convert_tab_to_spaces (Text *text)
2369 /* sb aims to pad adjust the tab-width needed so that the right number of spaces
2370 * is added so that the indention of the line is the right width (i.e. aligned
2371 * to multiples of TXT_TABSIZE)
2373 char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
2374 txt_insert_buf(text, sb);
2377 int txt_add_char (Text *text, char add)
2383 if (!text) return 0;
2384 if (!text->curl) return 0;
2387 txt_split_curline(text);
2391 /* insert spaces rather then tabs */
2392 if (add == '\t' && text->flags & TXT_TABSTOSPACES) {
2393 txt_convert_tab_to_spaces(text);
2397 txt_delete_sel(text);
2399 mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0);
2401 lineno= mrk->lineno;
2403 if (mrk->start>text->curc) mrk->start++;
2406 } while (mrk && mrk->lineno==lineno);
2409 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2411 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2412 tmp[text->curc]= add;
2414 len= text->curl->len - text->curc;
2415 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2416 tmp[text->curl->len+1]=0;
2417 make_new_line(text->curl, tmp);
2423 txt_make_dirty(text);
2424 txt_clean_text(text);
2426 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add);
2430 void txt_delete_selected(Text *text)
2432 txt_delete_sel(text);
2433 txt_make_dirty(text);
2436 int txt_replace_char (Text *text, char add)
2440 if (!text) return 0;
2441 if (!text->curl) return 0;
2443 /* If text is selected or we're at the end of the line just use txt_add_char */
2444 if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') {
2446 int i= txt_add_char(text, add);
2447 mrk= txt_find_marker(text, text->curl, text->curc, 0, 0);
2448 if (mrk && mrk->end==text->curc) mrk->end--;
2452 del= text->curl->line[text->curc];
2453 text->curl->line[text->curc]= (unsigned char) add;
2457 txt_make_dirty(text);
2458 txt_clean_text(text);
2460 /* Should probably create a new op for this */
2462 txt_undo_add_charop(text, UNDO_DEL, del);
2463 txt_undo_add_charop(text, UNDO_INSERT, add);
2468 void indent(Text *text)
2476 /* hardcoded: TXT_TABSIZE = 4 spaces: */
2477 int spaceslen = TXT_TABSIZE;
2479 /* insert spaces rather then tabs */
2480 if (text->flags & TXT_TABSTOSPACES){
2481 add = tab_to_spaces;
2482 indentlen = spaceslen;
2486 if (!text->curl) return;
2487 if (!text->sell) return;
2492 tmp= MEM_mallocN(text->curl->len+indentlen+1, "textline_string");
2495 if(text->curc) memcpy(tmp, text->curl->line, text->curc); /* XXX never true, check prev line */
2496 memcpy(tmp+text->curc, add, indentlen);
2498 len= text->curl->len - text->curc;
2499 if(len>0) memcpy(tmp+text->curc+indentlen, text->curl->line+text->curc, len);
2500 tmp[text->curl->len+indentlen]= 0;
2502 make_new_line(text->curl, tmp);
2504 text->curc+= indentlen;
2506 txt_make_dirty(text);
2507 txt_clean_text(text);
2509 if(text->curl == text->sell)
2511 text->selc = text->sell->len;
2514 text->curl = text->curl->next;
2521 text->curl = text->curl->prev;
2527 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);
2531 void unindent(Text *text)
2534 char *remove = "\t";
2537 /* hardcoded: TXT_TABSIZE = 4 spaces: */
2538 int spaceslen = TXT_TABSIZE;
2540 /* insert spaces rather then tabs */
2541 if (text->flags & TXT_TABSTOSPACES){
2542 remove = tab_to_spaces;
2547 if (!text->curl) return;
2548 if (!text->sell) return;
2554 if (BLI_strncasecmp(text->curl->line, remove, indent) == 0)
2556 while(i< text->curl->len) {
2557 text->curl->line[i]= text->curl->line[i+indent];
2560 text->curl->len-= indent;
2563 txt_make_dirty(text);
2564 txt_clean_text(text);
2566 if(text->curl == text->sell)
2568 text->selc = text->sell->len;
2571 text->curl = text->curl->next;
2579 text->curl = text->curl->prev;
2585 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);
2589 void comment(Text *text)
2596 if (!text->curl) return;
2597 if (!text->sell) return;// Need to change this need to check if only one line is selected ot more then one
2602 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2605 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2606 tmp[text->curc]= add;
2608 len= text->curl->len - text->curc;
2609 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2610 tmp[text->curl->len+1]=0;
2612 make_new_line(text->curl, tmp);
2616 txt_make_dirty(text);
2617 txt_clean_text(text);
2619 if(text->curl == text->sell)
2621 text->selc = text->sell->len;
2624 text->curl = text->curl->next;
2631 text->curl = text->curl->prev;
2637 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);
2641 void uncomment(Text *text)
2647 if (!text->curl) return;
2648 if (!text->sell) return;
2654 if (text->curl->line[i] == remove)
2656 while(i< text->curl->len) {
2657 text->curl->line[i]= text->curl->line[i+1];
2664 txt_make_dirty(text);
2665 txt_clean_text(text);
2667 if(text->curl == text->sell)
2669 text->selc = text->sell->len;
2672 text->curl = text->curl->next;
2680 text->curl = text->curl->prev;
2686 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);
2690 int setcurr_tab_spaces (Text *text, int space)
2694 const char *word = ":";
2695 const char *comm = "#";
2696 const char indent= (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t';
2697 static char *back_words[]= {"return", "break", "continue", "pass", "yield", NULL};
2698 if (!text) return 0;
2699 if (!text->curl) return 0;
2701 while (text->curl->line[i] == indent)
2703 //we only count those tabs/spaces that are before any text or before the curs;
2704 if (i == text->curc)
2711 if(strstr(text->curl->line, word))
2713 //if we find a : then add a tab but not if it is in a comment
2715 for(a=0; text->curl->line[a] != '\0'; a++)
2717 if (text->curl->line[a]=='#') {
2719 } else if (text->curl->line[a]==':') {
2721 } else if (text->curl->line[a]==']') {
2730 for(test=0; back_words[test]; test++)
2732 /* if there are these key words then remove a tab because we are done with the block */
2733 if(strstr(text->curl->line, back_words[test]) && i > 0)
2735 if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
2744 /*********************************/
2745 /* Text marker utility functions */
2746 /*********************************/
2748 /* Creates and adds a marker to the list maintaining sorted order */
2749 void txt_add_marker(Text *text, TextLine *line, int start, int end, char color[4], int group, int flags) {
2750 TextMarker *tmp, *marker;
2752 marker= MEM_mallocN(sizeof(TextMarker), "text_marker");
2754 marker->lineno= txt_get_span(text->lines.first, line);
2755 marker->start= MIN2(start, end);
2756 marker->end= MAX2(start, end);
2757 marker->group= group;
2758 marker->flags= flags;
2760 marker->color[0]= color[0];
2761 marker->color[1]= color[1];
2762 marker->color[2]= color[2];
2763 marker->color[3]= color[3];
2765 for (tmp=text->markers.last; tmp; tmp=tmp->prev)
2766 if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start))
2769 if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker);
2770 else BLI_addhead(&text->markers, marker);
2773 /* Returns the first matching marker on the specified line between two points.
2774 If the group or flags fields are non-zero the returned flag must be in the
2775 specified group and have at least the specified flags set. */
2776 TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2777 TextMarker *marker, *next;
2778 int lineno= txt_get_span(text->lines.first, line);
2780 for (marker=text->markers.first; marker; marker=next) {
2783 if (group && marker->group != group) continue;
2784 else if ((marker->flags & flags) != flags) continue;
2785 else if (marker->lineno < lineno) continue;
2786 else if (marker->lineno > lineno) break;
2788 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2789 (marker->start<end && marker->end>start))
2795 /* Clears all markers on the specified line between two points. If the group or
2796 flags fields are non-zero the returned flag must be in the specified group
2797 and have at least the specified flags set. */
2798 short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2799 TextMarker *marker, *next;
2800 int lineno= txt_get_span(text->lines.first, line);
2803 for (marker=text->markers.first; marker; marker=next) {
2806 if (group && marker->group != group) continue;
2807 else if ((marker->flags & flags) != flags) continue;
2808 else if (marker->lineno < lineno) continue;
2809 else if (marker->lineno > lineno) break;
2811 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2812 (marker->start<end && marker->end>start)) {
2813 BLI_freelinkN(&text->markers, marker);
2820 /* Clears all markers in the specified group (if given) with at least the
2821 specified flags set. Useful for clearing temporary markers (group=0,
2822 flags=TMARK_TEMP) */
2823 short txt_clear_markers(Text *text, int group, int flags) {
2824 TextMarker *marker, *next;
2827 for (marker=text->markers.first; marker; marker=next) {
2830 if ((!group || marker->group==group) &&
2831 (marker->flags & flags) == flags) {
2832 BLI_freelinkN(&text->markers, marker);
2839 /* Finds the marker at the specified line and cursor position with at least the
2840 specified flags set in the given group (if non-zero). */
2841 TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags) {
2843 int lineno= txt_get_span(text->lines.first, line);
2845 for (marker=text->markers.first; marker; marker=marker->next) {
2846 if (group && marker->group != group) continue;
2847 else if ((marker->flags & flags) != flags) continue;
2848 else if (marker->lineno < lineno) continue;
2849 else if (marker->lineno > lineno) break;
2851 if (marker->start <= curs && curs <= marker->end)
2857 /* Finds the previous marker in the same group. If no other is found, the same
2858 marker will be returned */
2859 TextMarker *txt_prev_marker(Text *text, TextMarker *marker) {
2860 TextMarker *tmp= marker;
2862 if (tmp->prev) tmp= tmp->prev;
2863 else tmp= text->markers.last;
2864 if (tmp->group == marker->group)
2867 return NULL; /* Only if marker==NULL */
2870 /* Finds the next marker in the same group. If no other is found, the same
2871 marker will be returned */
2872 TextMarker *txt_next_marker(Text *text, TextMarker *marker) {
2873 TextMarker *tmp= marker;
2875 if (tmp->next) tmp= tmp->next;
2876 else tmp= text->markers.first;
2877 if (tmp->group == marker->group)
2880 return NULL; /* Only if marker==NULL */
2884 /*******************************/
2885 /* Character utility functions */
2886 /*******************************/
2888 int text_check_bracket(char ch)
2891 char opens[] = "([{";
2892 char close[] = ")]}";
2894 for(a=0; a<(sizeof(opens)-1); a++) {
2897 else if(ch==close[a])
2903 int text_check_delim(char ch)
2906 char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,";
2908 for(a=0; a<(sizeof(delims)-1); a++) {
2915 int text_check_digit(char ch)
2917 if(ch < '0') return 0;
2918 if(ch <= '9') return 1;
2922 int text_check_identifier(char ch)
2924 if(ch < '0') return 0;
2925 if(ch <= '9') return 1;
2926 if(ch < 'A') return 0;
2927 if(ch <= 'Z' || ch == '_') return 1;
2928 if(ch < 'a') return 0;
2929 if(ch <= 'z') return 1;
2933 int text_check_whitespace(char ch)
2935 if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')