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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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_scene_types.h"
41 #include "DNA_text_types.h"
43 #include "BKE_bad_level_calls.h"
44 #include "BKE_utildefines.h"
46 #include "BKE_library.h"
47 #include "BKE_global.h"
50 #include "BPY_extern.h"
60 A text should relate to a file as follows -
61 (Text *)->name should be the place where the
62 file will or has been saved.
64 (Text *)->flags has the following bits
65 TXT_ISDIRTY - should always be set if the file in mem. differs from
66 the file on disk, or if there is no file on disk.
67 TXT_ISTMP - should always be set if the (Text *)->name file has not
68 been written before, and attempts to save should result
70 TXT_ISMEM - should always be set if the Text has not been mapped to
71 a file, in which case (Text *)->name may be NULL or garbage.
72 TXT_ISEXT - should always be set if the Text is not to be written into
74 TXT_ISSCRIPT - should be set if the user has designated the text
75 as a script. (NEW: this was unused, but now it is needed by
76 space handler script links (see header_view3d.c, for example)
78 ->>> see also: /makesdna/DNA_text_types.h
82 The st->top determines at what line the top of the text is displayed.
83 If the user moves the cursor the st containing that cursor should
84 be popped ... other st's retain their own top location.
88 The mrk->flags define the behaviour and relationships between markers. The
89 upper two bytes are used to hold a group ID, the lower two are normal flags. If
90 TMARK_EDITALL is set the group ID defines which other markers should be edited.
92 The mrk->clr field is used to visually group markers where the flags may not
93 match. A template system, for example, may allow editing of repeating tokens
94 (in one group) but include other marked positions (in another group) all in the
95 same template with the same colour.
99 Undo/Redo works by storing
100 events in a queue, and a pointer
101 to the current position in the
104 Events are stored using an
105 arbitrary op-code system
107 a) the two cursors (normal and selected)
108 b) input (visible and control (ie backspace))
110 input data is stored as its
111 ASCII value, the opcodes are
112 then selected to not conflict.
114 opcodes with data in between are
115 written at the beginning and end
116 of the data to allow undo and redo
117 to simply check the code at the current
124 static void txt_pop_first(Text *text);
125 static void txt_pop_last(Text *text);
126 static void txt_undo_add_op(Text *text, int op);
127 static void txt_undo_add_block(Text *text, int op, char *buf);
128 static void txt_delete_line(Text *text, TextLine *line);
132 static char *txt_cut_buffer= NULL;
133 static unsigned char undoing;
135 /* allow to switch off undoing externally */
136 void txt_set_undostate(int u)
141 int txt_get_undostate(void)
146 void free_text(Text *text)
150 for (tmp= text->lines.first; tmp; tmp= tmp->next) {
151 MEM_freeN(tmp->line);
153 MEM_freeN(tmp->format);
156 BLI_freelistN(&text->lines);
157 BLI_freelistN(&text->markers);
159 if(text->name) MEM_freeN(text->name);
160 MEM_freeN(text->undo_buf);
161 if (text->compiled) BPY_free_compiled_text(text);
164 Text *add_empty_text(char *name)
169 ta= alloc_libblock(&G.main->text, ID_TXT, name);
175 ta->undo_len= TXT_INIT_UNDO;
176 ta->undo_buf= MEM_mallocN(ta->undo_len, "undo buf");
179 ta->flags= TXT_ISDIRTY | TXT_ISTMP | TXT_ISMEM;
181 ta->lines.first= ta->lines.last= NULL;
182 ta->markers.first= ta->markers.last= NULL;
184 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
185 tmp->line= (char*) MEM_mallocN(1, "textline_string");
194 BLI_addhead(&ta->lines, tmp);
196 ta->curl= ta->lines.first;
198 ta->sell= ta->lines.first;
204 // this function removes any control characters from
207 static void cleanup_textline(TextLine * tl)
211 for (i = 0; i < tl->len; i++ ) {
212 if (tl->line[i] < ' ' && tl->line[i] != '\t') {
213 memmove(tl->line + i, tl->line + i + 1, tl->len - i);
220 int reopen_text(Text *text)
223 int i, llen, len, res;
224 unsigned char *buffer;
226 char sfile[FILE_MAXFILE];
227 char str[FILE_MAXDIR+FILE_MAXFILE];
230 if (!text || !text->name) return 0;
232 BLI_strncpy(str, text->name, FILE_MAXDIR+FILE_MAXFILE);
233 BLI_convertstringcode(str, G.sce);
234 BLI_split_dirfile_basic(str, NULL, sfile);
237 if(fp==NULL) return 0;
241 for (tmp= text->lines.first; tmp; tmp= tmp->next) {
242 MEM_freeN(tmp->line);
243 if (tmp->format) MEM_freeN(tmp->format);
246 BLI_freelistN(&text->lines);
248 text->lines.first= text->lines.last= NULL;
249 text->curl= text->sell= NULL;
251 /* clear undo buffer */
252 MEM_freeN(text->undo_buf);
254 text->undo_len= TXT_INIT_UNDO;
255 text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
257 text->flags= TXT_ISTMP;
259 fseek(fp, 0L, SEEK_END);
261 fseek(fp, 0L, SEEK_SET);
265 buffer= MEM_mallocN(len, "text_buffer");
266 // under windows fread can return less then len bytes because
268 len = fread(buffer, 1, len, fp);
273 text->mtime= st.st_mtime;
278 for(i=0; i<len; i++) {
279 if (buffer[i]=='\n') {
280 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
281 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
284 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
288 cleanup_textline(tmp);
290 BLI_addtail(&text->lines, tmp);
299 if (llen!=0 || text->nlines==0) {
300 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
301 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
304 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
309 cleanup_textline(tmp);
311 BLI_addtail(&text->lines, tmp);
315 text->curl= text->sell= text->lines.first;
316 text->curc= text->selc= 0;
322 Text *add_text(char *file)
325 int i, llen, len, res;
326 unsigned char *buffer;
329 char sfile[FILE_MAXFILE];
330 char str[FILE_MAXDIR+FILE_MAXFILE];
333 BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE);
334 if (G.scene) /* can be NULL (bg mode) */
335 BLI_convertstringcode(str, G.sce);
336 BLI_split_dirfile_basic(str, NULL, sfile);
339 if(fp==NULL) return NULL;
341 ta= alloc_libblock(&G.main->text, ID_TXT, sfile);
344 ta->lines.first= ta->lines.last= NULL;
345 ta->markers.first= ta->markers.last= NULL;
346 ta->curl= ta->sell= NULL;
348 /* ta->flags= TXT_ISTMP | TXT_ISEXT; */
349 ta->flags= TXT_ISTMP;
351 fseek(fp, 0L, SEEK_END);
353 fseek(fp, 0L, SEEK_SET);
355 ta->name= MEM_mallocN(strlen(file)+1, "text_name");
356 strcpy(ta->name, file);
359 ta->undo_len= TXT_INIT_UNDO;
360 ta->undo_buf= MEM_mallocN(ta->undo_len, "undo buf");
362 buffer= MEM_mallocN(len, "text_buffer");
363 // under windows fread can return less then len bytes because
365 len = fread(buffer, 1, len, fp);
370 ta->mtime= st.st_mtime;
375 for(i=0; i<len; i++) {
376 if (buffer[i]=='\n') {
377 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
378 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
381 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
385 cleanup_textline(tmp);
387 BLI_addtail(&ta->lines, tmp);
396 if (llen!=0 || ta->nlines==0) {
397 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
398 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
401 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
406 cleanup_textline(tmp);
408 BLI_addtail(&ta->lines, tmp);
412 ta->curl= ta->sell= ta->lines.first;
413 ta->curc= ta->selc= 0;
420 Text *copy_text(Text *ta)
423 TextLine *line, *tmp;
425 tan= copy_libblock(ta);
427 tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name");
428 strcpy(tan->name, ta->name);
430 tan->flags = ta->flags | TXT_ISDIRTY | TXT_ISTMP;
432 tan->lines.first= tan->lines.last= NULL;
433 tan->markers.first= tan->markers.last= NULL;
434 tan->curl= tan->sell= NULL;
436 tan->nlines= ta->nlines;
438 line= ta->lines.first;
439 /* Walk down, reconstructing */
441 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
442 tmp->line= MEM_mallocN(line->len+1, "textline_string");
445 strcpy(tmp->line, line->line);
449 BLI_addtail(&tan->lines, tmp);
454 tan->curl= tan->sell= tan->lines.first;
455 tan->curc= tan->selc= 0;
460 /*****************************/
461 /* Editing utility functions */
462 /*****************************/
464 static void make_new_line (TextLine *line, char *newline)
466 if (line->line) MEM_freeN(line->line);
467 if (line->format) MEM_freeN(line->format);
470 line->len= strlen(newline);
474 static TextLine *txt_new_line(char *str)
480 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
481 tmp->line= MEM_mallocN(strlen(str)+1, "textline_string");
484 strcpy(tmp->line, str);
486 tmp->len= strlen(str);
487 tmp->next= tmp->prev= NULL;
492 static TextLine *txt_new_linen(char *str, int n)
498 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
499 tmp->line= MEM_mallocN(n+1, "textline_string");
502 BLI_strncpy(tmp->line, str, n+1);
504 tmp->len= strlen(tmp->line);
505 tmp->next= tmp->prev= NULL;
510 void txt_clean_text (Text *text)
512 TextLine **top, **bot;
516 if (!text->lines.first) {
517 if (text->lines.last) text->lines.first= text->lines.last;
518 else text->lines.first= text->lines.last= txt_new_line(NULL);
521 if (!text->lines.last) text->lines.last= text->lines.first;
523 top= (TextLine **) &text->lines.first;
524 bot= (TextLine **) &text->lines.last;
526 while ((*top)->prev) *top= (*top)->prev;
527 while ((*bot)->next) *bot= (*bot)->next;
530 if(text->sell) text->curl= text->sell;
531 else text->curl= text->lines.first;
536 text->sell= text->curl;
541 int txt_get_span (TextLine *from, TextLine *to)
546 if (!to || !from) return 0;
547 if (from==to) return 0;
551 if (tmp == to) return ret;
561 if (tmp == to) break;
571 static void txt_make_dirty (Text *text)
573 text->flags |= TXT_ISDIRTY;
574 if (text->compiled) BPY_free_compiled_text(text);
577 /* 0:whitespace, 1:punct, 2:alphanumeric */
578 static short txt_char_type (char ch)
580 if (ch <= ' ') return 0; /* 32 */
581 if (ch <= '/') return 1; /* 47 */
582 if (ch <= '9') return 2; /* 57 */
583 if (ch <= '@') return 1; /* 64 */
584 if (ch <= 'Z') return 2; /* 90 */
585 if (ch == '_') return 2; /* 95, dont delimit '_' */
586 if (ch <= '`') return 1; /* 96 */
587 if (ch <= 'z') return 2; /* 122 */
591 /****************************/
592 /* Cursor utility functions */
593 /****************************/
595 static void txt_curs_cur (Text *text, TextLine ***linep, int **charp)
597 *linep= &text->curl; *charp= &text->curc;
600 static void txt_curs_sel (Text *text, TextLine ***linep, int **charp)
602 *linep= &text->sell; *charp= &text->selc;
605 static void txt_curs_first (Text *text, TextLine **linep, int *charp)
607 if (text->curl==text->sell) {
609 if (text->curc<text->selc) *charp= text->curc;
610 else *charp= text->selc;
611 } else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) {
620 /****************************/
621 /* Cursor movement functions */
622 /****************************/
624 void txt_move_up(Text *text, short sel)
630 if(sel) txt_curs_sel(text, &linep, &charp);
631 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
636 *linep= (*linep)->prev;
637 if (*charp > (*linep)->len) {
638 *charp= (*linep)->len;
639 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);
641 if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
644 txt_move_bol(text, sel);
647 if(!sel) txt_pop_sel(text);
650 void txt_move_down(Text *text, short sel)
656 if(sel) txt_curs_sel(text, &linep, &charp);
657 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
662 *linep= (*linep)->next;
663 if (*charp > (*linep)->len) {
664 *charp= (*linep)->len;
665 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);
667 if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
669 txt_move_eol(text, sel);
672 if(!sel) txt_pop_sel(text);
675 void txt_move_left(Text *text, short sel)
678 int *charp, oundoing= undoing;
681 if(sel) txt_curs_sel(text, &linep, &charp);
682 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
687 if ((*linep)->prev) {
688 txt_move_up(text, sel);
689 *charp= (*linep)->len;
695 if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
697 if(!sel) txt_pop_sel(text);
700 void txt_move_right(Text *text, short sel)
703 int *charp, oundoing= undoing;
706 if(sel) txt_curs_sel(text, &linep, &charp);
707 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
711 if (*charp== (*linep)->len) {
712 if ((*linep)->next) {
713 txt_move_down(text, sel);
720 if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
722 if(!sel) txt_pop_sel(text);
725 void txt_jump_left(Text *text, short sel)
727 TextLine **linep, *oldl;
728 int *charp, oldc, count, i;
732 if(sel) txt_curs_sel(text, &linep, &charp);
733 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
739 undoing= 1; /* Don't push individual moves to undo stack */
742 for (i=0; i<3; i++) {
744 while (*charp>0 && txt_char_type((*linep)->line[*charp-1])==i) {
745 txt_move_left(text, sel);
750 if (count==0) txt_move_left(text, sel);
753 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);
756 void txt_jump_right(Text *text, short sel)
758 TextLine **linep, *oldl;
759 int *charp, oldc, count, i;
763 if(sel) txt_curs_sel(text, &linep, &charp);
764 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
770 undoing= 1; /* Don't push individual moves to undo stack */
773 for (i=0; i<3; i++) {
775 while (*charp<(*linep)->len && txt_char_type((*linep)->line[*charp])==i) {
776 txt_move_right(text, sel);
781 if (count==0) txt_move_right(text, sel);
784 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);
787 void txt_move_bol (Text *text, short sel)
793 if(sel) txt_curs_sel(text, &linep, &charp);
794 else txt_curs_cur(text, &linep, &charp);
800 if(!sel) txt_pop_sel(text);
801 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);
804 void txt_move_eol (Text *text, short sel)
810 if(sel) txt_curs_sel(text, &linep, &charp);
811 else txt_curs_cur(text, &linep, &charp);
815 *charp= (*linep)->len;
817 if(!sel) txt_pop_sel(text);
818 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);
821 void txt_move_bof (Text *text, short sel)
827 if(sel) txt_curs_sel(text, &linep, &charp);
828 else txt_curs_cur(text, &linep, &charp);
832 *linep= text->lines.first;
835 if(!sel) txt_pop_sel(text);
836 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);
839 void txt_move_eof (Text *text, short sel)
845 if(sel) txt_curs_sel(text, &linep, &charp);
846 else txt_curs_cur(text, &linep, &charp);
850 *linep= text->lines.last;
851 *charp= (*linep)->len;
853 if(!sel) txt_pop_sel(text);
854 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);
857 void txt_move_toline (Text *text, unsigned int line, short sel)
859 txt_move_to(text, line, 0, sel);
862 void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel)
864 TextLine **linep, *oldl;
869 if(sel) txt_curs_sel(text, &linep, &charp);
870 else txt_curs_cur(text, &linep, &charp);
875 *linep= text->lines.first;
876 for (i=0; i<line; i++) {
877 if ((*linep)->next) *linep= (*linep)->next;
880 if (ch>(*linep)->len)
884 if(!sel) txt_pop_sel(text);
885 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);
888 /****************************/
889 /* Text selection functions */
890 /****************************/
892 static void txt_curs_swap (Text *text)
898 text->curl= text->sell;
902 text->curc= text->selc;
905 if(!undoing) txt_undo_add_op(text, UNDO_SWAP);
908 static void txt_pop_first (Text *text)
911 if (txt_get_span(text->curl, text->sell)<0 ||
912 (text->curl==text->sell && text->curc>text->selc)) {
916 if(!undoing) txt_undo_add_toop(text, UNDO_STO,
917 txt_get_span(text->lines.first, text->sell),
919 txt_get_span(text->lines.first, text->curl),
925 static void txt_pop_last (Text *text)
927 if (txt_get_span(text->curl, text->sell)>0 ||
928 (text->curl==text->sell && text->curc<text->selc)) {
932 if(!undoing) txt_undo_add_toop(text, UNDO_STO,
933 txt_get_span(text->lines.first, text->sell),
935 txt_get_span(text->lines.first, text->curl),
941 /* never used: CVS 1.19 */
942 /* static void txt_pop_selr (Text *text) */
944 void txt_pop_sel (Text *text)
946 text->sell= text->curl;
947 text->selc= text->curc;
950 void txt_order_cursors(Text *text)
953 if (!text->curl) return;
954 if (!text->sell) return;
956 /* Flip so text->curl is before text->sell */
957 if (txt_get_span(text->curl, text->sell)<0 ||
958 (text->curl==text->sell && text->curc>text->selc))
962 int txt_has_sel(Text *text)
964 return ((text->curl!=text->sell) || (text->curc!=text->selc));
967 static void txt_delete_sel (Text *text)
975 if (!text->curl) return;
976 if (!text->sell) return;
978 if (!txt_has_sel(text)) return;
980 txt_order_cursors(text);
983 buf= txt_sel_to_buf(text);
984 txt_undo_add_block(text, UNDO_DBLOCK, buf);
988 buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
990 if (text->curl != text->sell) {
991 txt_clear_marker_region(text, text->curl, text->curc, text->curl->len, 0, 0);
992 move= txt_get_span(text->curl, text->sell);
994 mrk= txt_find_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
995 if (mrk && (mrk->start > text->curc || mrk->end < text->selc))
996 txt_clear_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
1000 mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0);
1002 lineno= mrk->lineno;
1004 mrk->lineno -= move;
1005 if (mrk->start > text->curc) mrk->start -= text->selc - text->curc;
1006 mrk->end -= text->selc - text->curc;
1008 } while (mrk && mrk->lineno==lineno);
1011 strncpy(buf, text->curl->line, text->curc);
1012 strcpy(buf+text->curc, text->sell->line + text->selc);
1013 buf[text->curc+(text->sell->len - text->selc)]=0;
1015 make_new_line(text->curl, buf);
1018 while (tmpl != text->curl) {
1022 txt_delete_line(text, tmpl->next);
1025 text->sell= text->curl;
1026 text->selc= text->curc;
1029 void txt_sel_all (Text *text)
1033 text->curl= text->lines.first;
1036 text->sell= text->lines.last;
1037 text->selc= text->sell->len;
1040 void txt_sel_line (Text *text)
1043 if (!text->curl) return;
1046 text->sell= text->curl;
1047 text->selc= text->sell->len;
1050 /***************************/
1051 /* Cut and paste functions */
1052 /***************************/
1054 void txt_print_cutbuffer (void)
1056 printf ("Cut buffer\n--\n%s\n--\n", txt_cut_buffer);
1059 char *txt_to_buf (Text *text)
1062 TextLine *tmp, *linef, *linel;
1066 if (!text) return NULL;
1067 if (!text->curl) return NULL;
1068 if (!text->sell) return NULL;
1069 if (!text->lines.first) return NULL;
1071 linef= text->lines.first;
1074 linel= text->lines.last;
1077 if (linef == text->lines.last) {
1078 length= charl-charf;
1080 buf= MEM_mallocN(length+2, "text buffer");
1082 BLI_strncpy(buf, linef->line + charf, length+1);
1085 length= linef->len - charf;
1087 length+= 2; /* For the 2 '\n' */
1090 while (tmp && tmp!= linel) {
1091 length+= tmp->len+1;
1095 buf= MEM_mallocN(length+1, "cut buffer");
1097 strncpy(buf, linef->line + charf, linef->len-charf);
1098 length= linef->len - charf;
1103 while (tmp && tmp!=linel) {
1104 strncpy(buf+length, tmp->line, tmp->len);
1111 strncpy(buf+length, linel->line, charl);
1114 /* python compiler wants an empty end line */
1122 int txt_find_string(Text *text, char *findstr, int wrap)
1124 TextLine *tl, *startl;
1126 int oldcl, oldsl, oldcc, oldsc;
1128 if (!text || !text->curl || !text->sell) return 0;
1130 txt_order_cursors(text);
1132 oldcl= txt_get_span(text->lines.first, text->curl);
1133 oldsl= txt_get_span(text->lines.first, text->sell);
1134 tl= startl= text->sell;
1138 s= strstr(&tl->line[text->selc], findstr);
1143 tl= text->lines.first;
1148 s= strstr(tl->line, findstr);
1154 int newl= txt_get_span(text->lines.first, tl);
1155 int newc= (int)(s-tl->line);
1156 txt_move_to(text, newl, newc, 0);
1157 txt_move_to(text, newl, newc + strlen(findstr), 1);
1163 void txt_cut_sel (Text *text)
1165 if (!G.background) /* Python uses txt_cut_sel, which it should not, working around for now */
1166 txt_copy_clipboard(text);
1168 txt_delete_sel(text);
1169 txt_make_dirty(text);
1172 char *txt_sel_to_buf (Text *text)
1176 TextLine *tmp, *linef, *linel;
1179 if (!text) return NULL;
1180 if (!text->curl) return NULL;
1181 if (!text->sell) return NULL;
1183 if (text->curl==text->sell) {
1184 linef= linel= text->curl;
1186 if (text->curc < text->selc) {
1193 } else if (txt_get_span(text->curl, text->sell)<0) {
1207 if (linef == linel) {
1208 length= charl-charf;
1210 buf= MEM_mallocN(length+1, "sel buffer");
1212 BLI_strncpy(buf, linef->line + charf, length+1);
1214 length+= linef->len - charf;
1216 length++; /* For the '\n' */
1219 while (tmp && tmp!= linel) {
1220 length+= tmp->len+1;
1224 buf= MEM_mallocN(length+1, "sel buffer");
1226 strncpy(buf, linef->line+ charf, linef->len-charf);
1227 length= linef->len-charf;
1232 while (tmp && tmp!=linel) {
1233 strncpy(buf+length, tmp->line, tmp->len);
1240 strncpy(buf+length, linel->line, charl);
1249 void txt_copy_sel (Text *text)
1252 TextLine *tmp, *linef, *linel;
1256 if (!text->curl) return;
1257 if (!text->sell) return;
1259 if (!txt_has_sel(text)) return;
1261 if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
1262 txt_cut_buffer= NULL;
1264 if (text->curl==text->sell) {
1265 linef= linel= text->curl;
1267 if (text->curc < text->selc) {
1274 } else if (txt_get_span(text->curl, text->sell)<0) {
1288 if (linef == linel) {
1289 length= charl-charf;
1291 txt_cut_buffer= MEM_mallocN(length+1, "cut buffera");
1293 BLI_strncpy(txt_cut_buffer, linef->line + charf, length+1);
1295 length+= linef->len - charf;
1297 length++; /* For the '\n' */
1300 while (tmp && tmp!= linel) {
1301 length+= tmp->len+1;
1305 txt_cut_buffer= MEM_mallocN(length+1, "cut bufferb");
1307 strncpy(txt_cut_buffer, linef->line+ charf, linef->len-charf);
1308 length= linef->len-charf;
1310 txt_cut_buffer[length++]='\n';
1313 while (tmp && tmp!=linel) {
1314 strncpy(txt_cut_buffer+length, tmp->line, tmp->len);
1317 txt_cut_buffer[length++]='\n';
1321 strncpy(txt_cut_buffer+length, linel->line, charl);
1324 txt_cut_buffer[length]=0;
1328 void txt_insert_buf(Text *text, char *in_buffer)
1330 int i=0, l=0, j, u, len;
1334 if (!in_buffer) return;
1336 txt_delete_sel(text);
1338 if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer);
1343 /* Read the first line (or as close as possible */
1344 while (in_buffer[i] && in_buffer[i]!='\n') {
1345 txt_add_char(text, in_buffer[i]);
1349 if (in_buffer[i]=='\n') txt_split_curline(text);
1350 else { undoing = u; return; }
1353 /* Read as many full lines as we can */
1354 len= strlen(in_buffer);
1359 while (in_buffer[i] && in_buffer[i]!='\n') {
1363 if(in_buffer[i]=='\n') {
1364 add= txt_new_linen(in_buffer +(i-l), l);
1365 BLI_insertlinkbefore(&text->lines, text->curl, add);
1368 for (j= i-l; j<i && j<(int)strlen(in_buffer); j++) {
1369 txt_add_char(text, in_buffer[j]);
1378 void txt_free_cut_buffer(void)
1380 if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
1383 void txt_paste(Text *text)
1385 txt_insert_buf(text, txt_cut_buffer);
1388 /******************/
1389 /* Undo functions */
1390 /******************/
1392 #define MAX_UNDO_TEST(x) \
1393 while (text->undo_pos+x >= text->undo_len) { \
1394 if(text->undo_len*2 > TXT_MAX_UNDO) { \
1395 error("Undo limit reached, buffer cleared\n"); \
1396 MEM_freeN(text->undo_buf); \
1397 text->undo_len= TXT_INIT_UNDO; \
1398 text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); \
1399 text->undo_pos=-1; \
1402 void *tmp= text->undo_buf; \
1403 text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf"); \
1404 memcpy(text->undo_buf, tmp, text->undo_len); \
1405 text->undo_len*=2; \
1410 static void dump_buffer(Text *text)
1414 while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
1417 void txt_print_undo(Text *text)
1426 printf ("---< Undo Buffer >---\n");
1428 printf ("UndoPosition is %d\n", text->undo_pos);
1430 while (i<=text->undo_pos) {
1431 op= text->undo_buf[i];
1433 if (op==UNDO_CLEFT) {
1435 } else if (op==UNDO_CRIGHT) {
1436 ops= "Cursor right";
1437 } else if (op==UNDO_CUP) {
1439 } else if (op==UNDO_CDOWN) {
1441 } else if (op==UNDO_SLEFT) {
1442 ops= "Selection left";
1443 } else if (op==UNDO_SRIGHT) {
1444 ops= "Selection right";
1445 } else if (op==UNDO_SUP) {
1446 ops= "Selection up";
1447 } else if (op==UNDO_SDOWN) {
1448 ops= "Selection down";
1449 } else if (op==UNDO_STO) {
1451 } else if (op==UNDO_CTO) {
1453 } else if (op==UNDO_INSERT) {
1455 } else if (op==UNDO_BS) {
1457 } else if (op==UNDO_DEL) {
1459 } else if (op==UNDO_SWAP) {
1461 } else if (op==UNDO_DBLOCK) {
1462 ops= "Delete text block";
1463 } else if (op==UNDO_IBLOCK) {
1464 ops= "Insert text block";
1465 } else if (op==UNDO_INDENT) {
1467 } else if (op==UNDO_UNINDENT) {
1469 } else if (op==UNDO_COMMENT) {
1471 } else if (op==UNDO_UNCOMMENT) {
1477 printf ("Op (%o) at %d = %s", op, i, ops);
1478 if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) {
1480 printf (" - Char is %c", text->undo_buf[i]);
1482 } else if (op==UNDO_STO || op==UNDO_CTO) {
1485 charp= text->undo_buf[i]; i++;
1486 charp= charp+(text->undo_buf[i]<<8); i++;
1488 linep= text->undo_buf[i]; i++;
1489 linep= linep+(text->undo_buf[i]<<8); i++;
1490 linep= linep+(text->undo_buf[i]<<16); i++;
1491 linep= linep+(text->undo_buf[i]<<24); i++;
1493 printf ("to <%d, %d> ", linep, charp);
1495 charp= text->undo_buf[i]; i++;
1496 charp= charp+(text->undo_buf[i]<<8); i++;
1498 linep= text->undo_buf[i]; i++;
1499 linep= linep+(text->undo_buf[i]<<8); i++;
1500 linep= linep+(text->undo_buf[i]<<16); i++;
1501 linep= linep+(text->undo_buf[i]<<24); i++;
1503 printf ("from <%d, %d>", linep, charp);
1504 } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
1507 linep= text->undo_buf[i]; i++;
1508 linep= linep+(text->undo_buf[i]<<8); i++;
1509 linep= linep+(text->undo_buf[i]<<16); i++;
1510 linep= linep+(text->undo_buf[i]<<24); i++;
1512 printf (" (length %d) <", linep);
1515 putchar(text->undo_buf[i]);
1519 linep= text->undo_buf[i]; i++;
1520 linep= linep+(text->undo_buf[i]<<8); i++;
1521 linep= linep+(text->undo_buf[i]<<16); i++;
1522 linep= linep+(text->undo_buf[i]<<24); i++;
1523 printf ("> (%d)", linep);
1524 } else if (op==UNDO_INDENT || op==UNDO_UNINDENT) {
1527 charp= text->undo_buf[i]; i++;
1528 charp= charp+(text->undo_buf[i]<<8); i++;
1530 linep= text->undo_buf[i]; i++;
1531 linep= linep+(text->undo_buf[i]<<8); i++;
1532 linep= linep+(text->undo_buf[i]<<16); i++;
1533 linep= linep+(text->undo_buf[i]<<24); i++;
1535 printf ("to <%d, %d> ", linep, charp);
1537 charp= text->undo_buf[i]; i++;
1538 charp= charp+(text->undo_buf[i]<<8); i++;
1540 linep= text->undo_buf[i]; i++;
1541 linep= linep+(text->undo_buf[i]<<8); i++;
1542 linep= linep+(text->undo_buf[i]<<16); i++;
1543 linep= linep+(text->undo_buf[i]<<24); i++;
1545 printf ("from <%d, %d>", linep, charp);
1548 printf (" %d\n", i);
1553 static void txt_undo_add_op(Text *text, int op)
1558 text->undo_buf[text->undo_pos]= op;
1559 text->undo_buf[text->undo_pos+1]= 0;
1562 static void txt_undo_add_block(Text *text, int op, char *buf)
1566 length= strlen(buf);
1568 MAX_UNDO_TEST(length+11);
1571 text->undo_buf[text->undo_pos]= op;
1574 text->undo_buf[text->undo_pos]= (length)&0xff;
1576 text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1578 text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1580 text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1583 strncpy(text->undo_buf+text->undo_pos, buf, length);
1584 text->undo_pos+=length;
1586 text->undo_buf[text->undo_pos]= (length)&0xff;
1588 text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1590 text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1592 text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1595 text->undo_buf[text->undo_pos]= op;
1597 text->undo_buf[text->undo_pos+1]= 0;
1600 void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
1604 if (froml==tol && fromc==toc) return;
1607 text->undo_buf[text->undo_pos]= op;
1610 text->undo_buf[text->undo_pos]= (fromc)&0xff;
1612 text->undo_buf[text->undo_pos]= (fromc>>8)&0xff;
1615 text->undo_buf[text->undo_pos]= (froml)&0xff;
1617 text->undo_buf[text->undo_pos]= (froml>>8)&0xff;
1619 text->undo_buf[text->undo_pos]= (froml>>16)&0xff;
1621 text->undo_buf[text->undo_pos]= (froml>>24)&0xff;
1624 text->undo_buf[text->undo_pos]= (toc)&0xff;
1626 text->undo_buf[text->undo_pos]= (toc>>8)&0xff;
1629 text->undo_buf[text->undo_pos]= (tol)&0xff;
1631 text->undo_buf[text->undo_pos]= (tol>>8)&0xff;
1633 text->undo_buf[text->undo_pos]= (tol>>16)&0xff;
1635 text->undo_buf[text->undo_pos]= (tol>>24)&0xff;
1638 text->undo_buf[text->undo_pos]= op;
1640 text->undo_buf[text->undo_pos+1]= 0;
1643 static void txt_undo_add_charop(Text *text, int op, char c)
1648 text->undo_buf[text->undo_pos]= op;
1650 text->undo_buf[text->undo_pos]= c;
1652 text->undo_buf[text->undo_pos]= op;
1653 text->undo_buf[text->undo_pos+1]= 0;
1656 void txt_do_undo(Text *text)
1658 int op= text->undo_buf[text->undo_pos];
1659 unsigned int linep, i;
1660 unsigned short charp;
1665 if (text->undo_pos<0) {
1675 txt_move_right(text, 0);
1679 txt_move_left(text, 0);
1683 txt_move_down(text, 0);
1687 txt_move_up(text, 0);
1691 txt_move_right(text, 1);
1695 txt_move_left(text, 1);
1699 txt_move_down(text, 1);
1703 txt_move_up(text, 1);
1716 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1717 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1718 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1719 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1721 charp= text->undo_buf[text->undo_pos]; text->undo_pos--;
1722 charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1725 txt_move_toline(text, linep, 0);
1729 txt_move_toline(text, linep, 1);
1737 txt_backspace_char(text);
1743 txt_add_char(text, text->undo_buf[text->undo_pos]);
1749 txt_add_char(text, text->undo_buf[text->undo_pos]);
1750 txt_move_left(text, 0);
1756 txt_curs_swap(text);
1760 linep= 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--;
1763 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1765 buf= MEM_mallocN(linep+1, "dblock buffer");
1766 for (i=0; i < linep; i++){
1767 buf[(linep-1)-i]= text->undo_buf[text->undo_pos];
1772 txt_curs_first(text, &holdl, &holdc);
1773 holdln= txt_get_span(text->lines.first, holdl);
1775 txt_insert_buf(text, buf);
1778 text->curl= text->lines.first;
1780 if(text->curl->next)
1781 text->curl= text->curl->next;
1787 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1788 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1789 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1790 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1797 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1798 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1799 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1800 linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1802 txt_delete_sel(text);
1804 txt_backspace_char(text);
1820 case UNDO_UNCOMMENT:
1821 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1822 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1823 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1824 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1825 //linep is now the end line of the selection
1827 charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1828 charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1829 //charp is the last char selected or text->line->len
1830 //set the selcetion for this now
1832 text->sell = text->lines.first;
1833 for (i= 0; i < linep; i++) {
1834 text->sell = text->sell->next;
1837 linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1838 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1839 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1840 linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1841 //first line to be selected
1843 charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1844 charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1845 //first postion to be selected
1847 text->curl = text->lines.first;
1848 for (i = 0; i < linep; i++) {
1849 text->curl = text->curl->next;
1853 if (op==UNDO_INDENT) {
1855 } else if (op== UNDO_UNINDENT) {
1857 } else if (op == UNDO_COMMENT) {
1859 } else if (op == UNDO_UNCOMMENT) {
1866 error("Undo buffer error - resetting");
1872 /* next undo step may need evaluating */
1873 if (text->undo_pos>=0) {
1874 switch (text->undo_buf[text->undo_pos]) {
1877 txt_do_redo(text); /* selections need restoring */
1880 txt_do_undo(text); /* swaps should appear transparent */
1888 void txt_do_redo(Text *text)
1891 unsigned int linep, i;
1892 unsigned short charp;
1896 op= text->undo_buf[text->undo_pos];
1907 txt_move_left(text, 0);
1911 txt_move_right(text, 0);
1915 txt_move_up(text, 0);
1919 txt_move_down(text, 0);
1923 txt_move_left(text, 1);
1927 txt_move_right(text, 1);
1931 txt_move_up(text, 1);
1935 txt_move_down(text, 1);
1940 txt_add_char(text, text->undo_buf[text->undo_pos]);
1946 txt_backspace_char(text);
1952 txt_delete_char(text);
1957 txt_curs_swap(text);
1958 txt_do_redo(text); /* swaps should appear transparent a*/
1973 charp= text->undo_buf[text->undo_pos];
1975 charp= charp+(text->undo_buf[text->undo_pos]<<8);
1978 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1979 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1980 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1981 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
1984 txt_move_toline(text, linep, 0);
1988 txt_move_toline(text, linep, 1);
1996 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1997 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1998 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1999 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2001 txt_delete_sel(text);
2002 text->undo_pos+=linep;
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 buf= MEM_mallocN(linep+1, "iblock buffer");
2019 memcpy (buf, &text->undo_buf[text->undo_pos], linep);
2020 text->undo_pos+= linep;
2023 txt_insert_buf(text, buf);
2026 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2027 linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2028 linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2029 linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2035 case UNDO_UNCOMMENT:
2037 charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2038 charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2039 //charp is the first char selected or 0
2041 linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2042 linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2043 linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2044 linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2045 //linep is now the first line of the selection
2046 //set the selcetion for this now
2048 text->curl = text->lines.first;
2049 for (i= 0; i < linep; i++) {
2050 text->curl = text->curl->next;
2053 charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2054 charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2055 //last postion to be selected
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++;
2060 //Last line to be selected
2063 text->sell = text->lines.first;
2064 for (i = 0; i < linep; i++) {
2065 text->sell = text->sell->next;
2068 if (op==UNDO_INDENT) {
2070 } else if (op== UNDO_UNINDENT) {
2072 } else if (op == UNDO_COMMENT) {
2074 } else if (op == UNDO_UNCOMMENT) {
2079 error("Undo buffer error - resetting");
2088 /**************************/
2089 /* Line editing functions */
2090 /**************************/
2092 void txt_split_curline (Text *text)
2100 if (!text->curl) return;
2102 txt_delete_sel(text);
2106 lineno= txt_get_span(text->lines.first, text->curl);
2107 mrk= text->markers.first;
2109 if (mrk->lineno==lineno && mrk->start>text->curc) {
2111 mrk->start -= text->curc;
2112 mrk->end -= text->curc;
2113 } else if (mrk->lineno > lineno) {
2119 /* Make the two half strings */
2121 left= MEM_mallocN(text->curc+1, "textline_string");
2122 if (text->curc) memcpy(left, text->curl->line, text->curc);
2125 right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
2126 if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc);
2127 right[text->curl->len - text->curc]=0;
2129 MEM_freeN(text->curl->line);
2130 if (text->curl->format) MEM_freeN(text->curl->format);
2132 /* Make the new TextLine */
2134 ins= MEM_mallocN(sizeof(TextLine), "textline");
2137 ins->len= text->curc;
2139 text->curl->line= right;
2140 text->curl->format= NULL;
2141 text->curl->len= text->curl->len - text->curc;
2143 BLI_insertlinkbefore(&text->lines, text->curl, ins);
2147 txt_make_dirty(text);
2148 txt_clean_text(text);
2151 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n');
2154 static void txt_delete_line (Text *text, TextLine *line)
2156 TextMarker *mrk=NULL, *nxt;
2160 if (!text->curl) return;
2162 lineno= txt_get_span(text->lines.first, line);
2163 mrk= text->markers.first;
2166 if (mrk->lineno==lineno)
2167 BLI_freelinkN(&text->markers, mrk);
2168 else if (mrk->lineno > lineno)
2173 BLI_remlink (&text->lines, line);
2175 if (line->line) MEM_freeN(line->line);
2176 if (line->format) MEM_freeN(line->format);
2180 txt_make_dirty(text);
2181 txt_clean_text(text);
2184 static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
2187 TextMarker *mrk= NULL;
2192 if(!linea || !lineb) return;
2194 mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0);
2196 lineno= mrk->lineno;
2199 mrk->start += linea->len;
2200 mrk->end += linea->len;
2202 } while (mrk && mrk->lineno==lineno);
2204 if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb);
2205 if (!mrk) mrk= text->markers.first;
2207 tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
2209 strcpy(tmp, linea->line);
2210 strcat(tmp, lineb->line);
2212 make_new_line(linea, tmp);
2214 txt_delete_line(text, lineb);
2216 txt_make_dirty(text);
2217 txt_clean_text(text);
2220 void txt_delete_char (Text *text)
2225 if (!text->curl) return;
2227 if (txt_has_sel(text)) { /* deleting a selection */
2228 txt_delete_sel(text);
2229 txt_make_dirty(text);
2232 else if (text->curc== text->curl->len) { /* Appending two lines */
2233 if (text->curl->next) {
2234 txt_combine_lines(text, text->curl, text->curl->next);
2237 } else { /* Just deleting a char */
2240 TextMarker *mrk= txt_find_marker_region(text, text->curl, i-1, text->curl->len, 0, 0);
2242 int lineno= mrk->lineno;
2244 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2245 txt_clear_markers(text, mrk->group, TMARK_TEMP);
2247 BLI_freelinkN(&text->markers, mrk);
2252 if (mrk->start>i) mrk->start--;
2255 } while (mrk && mrk->lineno==lineno);
2258 c= text->curl->line[i];
2259 while(i< text->curl->len) {
2260 text->curl->line[i]= text->curl->line[i+1];
2268 txt_make_dirty(text);
2269 txt_clean_text(text);
2271 if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c);
2274 void txt_delete_word (Text *text)
2276 txt_jump_right(text, 1);
2277 txt_delete_sel(text);
2280 void txt_backspace_char (Text *text)
2285 if (!text->curl) return;
2287 if (txt_has_sel(text)) { /* deleting a selection */
2288 txt_delete_sel(text);
2289 txt_make_dirty(text);
2292 else if (text->curc==0) { /* Appending two lines */
2293 if (!text->curl->prev) return;
2295 text->curl= text->curl->prev;
2296 text->curc= text->curl->len;
2298 txt_combine_lines(text, text->curl, text->curl->next);
2301 else { /* Just backspacing a char */
2302 int i= text->curc-1;
2304 TextMarker *mrk= txt_find_marker_region(text, text->curl, i, text->curl->len, 0, 0);
2306 int lineno= mrk->lineno;
2307 if (mrk->start==i+1) {
2308 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2309 txt_clear_markers(text, mrk->group, TMARK_TEMP);
2311 BLI_freelinkN(&text->markers, mrk);
2316 if (mrk->start>i) mrk->start--;
2319 } while (mrk && mrk->lineno==lineno);
2322 c= text->curl->line[i];
2323 while(i< text->curl->len) {
2324 text->curl->line[i]= text->curl->line[i+1];
2333 txt_make_dirty(text);
2334 txt_clean_text(text);
2336 if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
2339 void txt_backspace_word (Text *text)
2341 txt_jump_left(text, 1);
2342 txt_delete_sel(text);
2345 int txt_add_char (Text *text, char add)
2351 if (!text) return 0;
2352 if (!text->curl) return 0;
2355 txt_split_curline(text);
2359 txt_delete_sel(text);
2361 mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0);
2363 lineno= mrk->lineno;
2365 if (mrk->start>text->curc) mrk->start++;
2368 } while (mrk && mrk->lineno==lineno);
2371 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2373 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2374 tmp[text->curc]= add;
2376 len= text->curl->len - text->curc;
2377 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2378 tmp[text->curl->len+1]=0;
2379 make_new_line(text->curl, tmp);
2385 txt_make_dirty(text);
2386 txt_clean_text(text);
2388 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add);
2392 int txt_replace_char (Text *text, char add)
2396 if (!text) return 0;
2397 if (!text->curl) return 0;
2399 /* If text is selected or we're at the end of the line just use txt_add_char */
2400 if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') {
2402 int i= txt_add_char(text, add);
2403 mrk= txt_find_marker(text, text->curl, text->curc, 0, 0);
2404 if (mrk && mrk->end==text->curc) mrk->end--;
2408 del= text->curl->line[text->curc];
2409 text->curl->line[text->curc]= (unsigned char) add;
2413 txt_make_dirty(text);
2414 txt_clean_text(text);
2416 /* Should probably create a new op for this */
2418 txt_undo_add_charop(text, UNDO_DEL, del);
2419 txt_undo_add_charop(text, UNDO_INSERT, add);
2424 void indent(Text *text)
2431 if (!text->curl) return;
2432 if (!text->sell) return;
2437 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2440 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2441 tmp[text->curc]= add;
2443 len= text->curl->len - text->curc;
2444 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2445 tmp[text->curl->len+1]=0;
2447 make_new_line(text->curl, tmp);
2451 txt_make_dirty(text);
2452 txt_clean_text(text);
2454 if(text->curl == text->sell)
2456 text->selc = text->sell->len;
2459 text->curl = text->curl->next;
2466 text->curl = text->curl->prev;
2472 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);
2476 void unindent(Text *text)
2482 if (!text->curl) return;
2483 if (!text->sell) return;
2489 if (text->curl->line[i] == remove)
2491 while(i< text->curl->len) {
2492 text->curl->line[i]= text->curl->line[i+1];
2499 txt_make_dirty(text);
2500 txt_clean_text(text);
2502 if(text->curl == text->sell)
2504 text->selc = text->sell->len;
2507 text->curl = text->curl->next;
2515 text->curl = text->curl->prev;
2521 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);
2525 void comment(Text *text)
2532 if (!text->curl) return;
2533 if (!text->sell) return;// Need to change this need to check if only one line is selected ot more then one
2538 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2541 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2542 tmp[text->curc]= add;
2544 len= text->curl->len - text->curc;
2545 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2546 tmp[text->curl->len+1]=0;
2548 make_new_line(text->curl, tmp);
2552 txt_make_dirty(text);
2553 txt_clean_text(text);
2555 if(text->curl == text->sell)
2557 text->selc = text->sell->len;
2560 text->curl = text->curl->next;
2567 text->curl = text->curl->prev;
2573 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);
2577 void uncomment(Text *text)
2583 if (!text->curl) return;
2584 if (!text->sell) return;
2590 if (text->curl->line[i] == remove)
2592 while(i< text->curl->len) {
2593 text->curl->line[i]= text->curl->line[i+1];
2600 txt_make_dirty(text);
2601 txt_clean_text(text);
2603 if(text->curl == text->sell)
2605 text->selc = text->sell->len;
2608 text->curl = text->curl->next;
2616 text->curl = text->curl->prev;
2622 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);
2626 int setcurr_tab (Text *text)
2632 char back_words[4][7] = {"return", "break", "pass", "yield"};
2633 if (!text) return 0;
2634 if (!text->curl) return 0;
2636 while (text->curl->line[i] == '\t')
2638 //we only count thos tabs that are before any text or before the curs;
2639 if (i == text->curc)
2646 if(strstr(text->curl->line, word))
2648 //if we find a : then add a tab but not if it is in a comment
2650 for(a=0; text->curl->line[a] != '\0'; a++)
2652 if (text->curl->line[a]=='#') {
2654 } else if (text->curl->line[a]==':') {
2656 } else if (text->curl->line[a]==']') {
2665 for(test=0; test < 4; test++)
2667 //if there are these 4 key words then remove a tab because we are done with the block
2668 if(strstr(text->curl->line, back_words[test]) && i > 0)
2670 if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
2679 /*********************************/
2680 /* Text marker utility functions */
2681 /*********************************/
2683 /* Creates and adds a marker to the list maintaining sorted order */
2684 void txt_add_marker(Text *text, TextLine *line, int start, int end, char color[4], int group, int flags) {
2685 TextMarker *tmp, *marker;
2687 marker= MEM_mallocN(sizeof(TextMarker), "text_marker");
2689 marker->lineno= txt_get_span(text->lines.first, line);
2690 marker->start= MIN2(start, end);
2691 marker->end= MAX2(start, end);
2692 marker->group= group;
2693 marker->flags= flags;
2695 marker->color[0]= color[0];
2696 marker->color[1]= color[1];
2697 marker->color[2]= color[2];
2698 marker->color[3]= color[3];
2700 for (tmp=text->markers.last; tmp; tmp=tmp->prev)
2701 if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start))
2704 if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker);
2705 else BLI_addhead(&text->markers, marker);
2708 /* Returns the first matching marker on the specified line between two points.
2709 If the group or flags fields are non-zero the returned flag must be in the
2710 specified group and have at least the specified flags set. */
2711 TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2712 TextMarker *marker, *next;
2713 int lineno= txt_get_span(text->lines.first, line);
2715 for (marker=text->markers.first; marker; marker=next) {
2718 if (group && marker->group != group) continue;
2719 else if ((marker->flags & flags) != flags) continue;
2720 else if (marker->lineno < lineno) continue;
2721 else if (marker->lineno > lineno) break;
2723 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2724 (marker->start<end && marker->end>start))
2730 /* Clears all markers on the specified line between two points. If the group or
2731 flags fields are non-zero the returned flag must be in the specified group
2732 and have at least the specified flags set. */
2733 short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2734 TextMarker *marker, *next;
2735 int lineno= txt_get_span(text->lines.first, line);
2738 for (marker=text->markers.first; marker; marker=next) {
2741 if (group && marker->group != group) continue;
2742 else if ((marker->flags & flags) != flags) continue;
2743 else if (marker->lineno < lineno) continue;
2744 else if (marker->lineno > lineno) break;
2746 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2747 (marker->start<end && marker->end>start)) {
2748 BLI_freelinkN(&text->markers, marker);
2755 /* Clears all markers in the specified group (if given) with at least the
2756 specified flags set. Useful for clearing temporary markers (group=0,
2757 flags=TMARK_TEMP) */
2758 short txt_clear_markers(Text *text, int group, int flags) {
2759 TextMarker *marker, *next;
2762 for (marker=text->markers.first; marker; marker=next) {
2765 if ((!group || marker->group==group) &&
2766 (marker->flags & flags) == flags) {
2767 BLI_freelinkN(&text->markers, marker);
2774 /* Finds the marker at the specified line and cursor position with at least the
2775 specified flags set in the given group (if non-zero). */
2776 TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags) {
2778 int lineno= txt_get_span(text->lines.first, line);
2780 for (marker=text->markers.first; marker; marker=marker->next) {
2781 if (group && marker->group != group) continue;
2782 else if ((marker->flags & flags) != flags) continue;
2783 else if (marker->lineno < lineno) continue;
2784 else if (marker->lineno > lineno) break;
2786 if (marker->start <= curs && curs <= marker->end)
2792 /* Finds the previous marker in the same group. If no other is found, the same
2793 marker will be returned */
2794 TextMarker *txt_prev_marker(Text *text, TextMarker *marker) {
2795 TextMarker *tmp= marker;
2797 if (tmp->prev) tmp= tmp->prev;
2798 else tmp= text->markers.last;
2799 if (tmp->group == marker->group)
2802 return NULL; /* Only if marker==NULL */
2805 /* Finds the next marker in the same group. If no other is found, the same
2806 marker will be returned */
2807 TextMarker *txt_next_marker(Text *text, TextMarker *marker) {
2808 TextMarker *tmp= marker;
2810 if (tmp->next) tmp= tmp->next;
2811 else tmp= text->markers.first;
2812 if (tmp->group == marker->group)
2815 return NULL; /* Only if marker==NULL */