text editor changes
[blender.git] / source / blender / blenkernel / intern / text.c
1 /* text.c
2  *
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
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.
12  *
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.
17  *
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.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include <string.h> /* strstr */
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39
40 #include "DNA_scene_types.h"
41 #include "DNA_text_types.h"
42
43 #include "BKE_bad_level_calls.h"
44 #include "BKE_utildefines.h"
45 #include "BKE_text.h"
46 #include "BKE_library.h"
47 #include "BKE_global.h"
48 #include "BKE_main.h"
49
50 #include "BPY_extern.h"
51
52 #ifdef HAVE_CONFIG_H
53 #include <config.h>
54 #endif
55
56 /***************/ /*
57
58 How Texts should work
59 --
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.
63         
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
69                                         in "Save over?"
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
73                                         the .blend
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)
77
78 ->>> see also: /makesdna/DNA_text_types.h
79
80 Display
81 --
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.
85
86 Markers
87 --
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.
91
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.
96
97 Undo
98 --
99 Undo/Redo works by storing
100 events in a queue, and a pointer
101 to the current position in the
102 queue...
103
104 Events are stored using an
105 arbitrary op-code system
106 to keep track of
107 a) the two cursors (normal and selected)
108 b) input (visible and control (ie backspace))
109
110 input data is stored as its
111 ASCII value, the opcodes are
112 then selected to not conflict.
113
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
118 undo position
119
120 */ /***************/
121
122 /***/
123
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);
129
130 /***/
131
132 static char *txt_cut_buffer= NULL;
133 static unsigned char undoing;
134
135 /* allow to switch off undoing externally */
136 void txt_set_undostate(int u)
137 {
138         undoing = u;
139 }
140
141 int txt_get_undostate(void)
142 {
143         return undoing;
144 }
145
146 void free_text(Text *text)
147 {
148         TextLine *tmp;
149
150         for (tmp= text->lines.first; tmp; tmp= tmp->next) {
151                 MEM_freeN(tmp->line);
152                 if (tmp->format)
153                   MEM_freeN(tmp->format);
154         }
155         
156         BLI_freelistN(&text->lines);
157         BLI_freelistN(&text->markers);
158
159         if(text->name) MEM_freeN(text->name);
160         MEM_freeN(text->undo_buf);
161         if (text->compiled) BPY_free_compiled_text(text);
162 }
163
164 Text *add_empty_text(char *name) 
165 {
166         Text *ta;
167         TextLine *tmp;
168         
169         ta= alloc_libblock(&G.main->text, ID_TXT, name);
170         ta->id.us= 1;
171         
172         ta->name= NULL;
173
174         ta->undo_pos= -1;
175         ta->undo_len= TXT_INIT_UNDO;
176         ta->undo_buf= MEM_mallocN(ta->undo_len, "undo buf");
177                 
178         ta->nlines=1;
179         ta->flags= TXT_ISDIRTY | TXT_ISTMP | TXT_ISMEM;
180
181         ta->lines.first= ta->lines.last= NULL;
182         ta->markers.first= ta->markers.last= NULL;
183
184         tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
185         tmp->line= (char*) MEM_mallocN(1, "textline_string");
186         tmp->format= NULL;
187         
188         tmp->line[0]=0;
189         tmp->len= 0;
190                                 
191         tmp->next= NULL;
192         tmp->prev= NULL;
193                                 
194         BLI_addhead(&ta->lines, tmp);
195         
196         ta->curl= ta->lines.first;
197         ta->curc= 0;
198         ta->sell= ta->lines.first;
199         ta->selc= 0;
200
201         return ta;
202 }
203
204 // this function removes any control characters from
205 // a textline
206
207 static void cleanup_textline(TextLine * tl)
208 {
209         int i;
210
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);
214                         tl->len--;
215                         i--;
216                 }
217         }
218 }
219
220 int reopen_text(Text *text)
221 {
222         FILE *fp;
223         int i, llen, len, res;
224         unsigned char *buffer;
225         TextLine *tmp;
226         char sfile[FILE_MAXFILE];
227         char str[FILE_MAXDIR+FILE_MAXFILE];
228         struct stat st;
229
230         if (!text || !text->name) return 0;
231         
232         BLI_strncpy(str, text->name, FILE_MAXDIR+FILE_MAXFILE);
233         BLI_convertstringcode(str, G.sce);
234         BLI_split_dirfile_basic(str, NULL, sfile);
235         
236         fp= fopen(str, "r");
237         if(fp==NULL) return 0;
238
239         /* free memory: */
240
241         for (tmp= text->lines.first; tmp; tmp= tmp->next) {
242                 MEM_freeN(tmp->line);
243                 if (tmp->format) MEM_freeN(tmp->format);
244         }
245         
246         BLI_freelistN(&text->lines);
247
248         text->lines.first= text->lines.last= NULL;
249         text->curl= text->sell= NULL;
250
251         /* clear undo buffer */
252         MEM_freeN(text->undo_buf);
253         text->undo_pos= -1;
254         text->undo_len= TXT_INIT_UNDO;
255         text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
256         
257         text->flags= TXT_ISTMP; 
258         
259         fseek(fp, 0L, SEEK_END);
260         len= ftell(fp);
261         fseek(fp, 0L, SEEK_SET);        
262
263         text->undo_pos= -1;
264         
265         buffer= MEM_mallocN(len, "text_buffer");
266         // under windows fread can return less then len bytes because
267         // of CR stripping
268         len = fread(buffer, 1, len, fp);
269
270         fclose(fp);
271
272         res= stat(str, &st);
273         text->mtime= st.st_mtime;
274         
275         text->nlines=0;
276         i=0;
277         llen=0;
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");
282                         tmp->format= NULL;
283                         
284                         if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
285                         tmp->line[llen]=0;
286                         tmp->len= llen;
287                                 
288                         cleanup_textline(tmp);
289
290                         BLI_addtail(&text->lines, tmp);
291                         text->nlines++;
292                                 
293                         llen=0;
294                         continue;
295                 }
296                 llen++;
297         }
298
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");
302                 tmp->format= NULL;
303                 
304                 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
305
306                 tmp->line[llen]=0;
307                 tmp->len= llen;
308                 
309                 cleanup_textline(tmp);
310
311                 BLI_addtail(&text->lines, tmp);
312                 text->nlines++;
313         }
314         
315         text->curl= text->sell= text->lines.first;
316         text->curc= text->selc= 0;
317         
318         MEM_freeN(buffer);      
319         return 1;
320 }
321
322 Text *add_text(char *file) 
323 {
324         FILE *fp;
325         int i, llen, len, res;
326         unsigned char *buffer;
327         TextLine *tmp;
328         Text *ta;
329         char sfile[FILE_MAXFILE];
330         char str[FILE_MAXDIR+FILE_MAXFILE];
331         struct stat st;
332
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);
337         
338         fp= fopen(str, "r");
339         if(fp==NULL) return NULL;
340         
341         ta= alloc_libblock(&G.main->text, ID_TXT, sfile);
342         ta->id.us= 1;
343
344         ta->lines.first= ta->lines.last= NULL;
345         ta->markers.first= ta->markers.last= NULL;
346         ta->curl= ta->sell= NULL;
347
348 /*      ta->flags= TXT_ISTMP | TXT_ISEXT; */
349         ta->flags= TXT_ISTMP;
350         
351         fseek(fp, 0L, SEEK_END);
352         len= ftell(fp);
353         fseek(fp, 0L, SEEK_SET);        
354
355         ta->name= MEM_mallocN(strlen(file)+1, "text_name");
356         strcpy(ta->name, file);
357
358         ta->undo_pos= -1;
359         ta->undo_len= TXT_INIT_UNDO;
360         ta->undo_buf= MEM_mallocN(ta->undo_len, "undo buf");
361         
362         buffer= MEM_mallocN(len, "text_buffer");
363         // under windows fread can return less then len bytes because
364         // of CR stripping
365         len = fread(buffer, 1, len, fp);
366
367         fclose(fp);
368
369         res= stat(str, &st);
370         ta->mtime= st.st_mtime;
371         
372         ta->nlines=0;
373         i=0;
374         llen=0;
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");
379                         tmp->format= NULL;
380                         
381                         if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
382                         tmp->line[llen]=0;
383                         tmp->len= llen;
384                         
385                         cleanup_textline(tmp);
386
387                         BLI_addtail(&ta->lines, tmp);
388                         ta->nlines++;
389                                 
390                         llen=0;
391                         continue;
392                 }
393                 llen++;
394         }
395
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");
399                 tmp->format= NULL;
400                 
401                 if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
402
403                 tmp->line[llen]=0;
404                 tmp->len= llen;
405                 
406                 cleanup_textline(tmp);
407
408                 BLI_addtail(&ta->lines, tmp);
409                 ta->nlines++;
410         }
411         
412         ta->curl= ta->sell= ta->lines.first;
413         ta->curc= ta->selc= 0;
414         
415         MEM_freeN(buffer);      
416
417         return ta;
418 }
419
420 Text *copy_text(Text *ta)
421 {
422         Text *tan;
423         TextLine *line, *tmp;
424         
425         tan= copy_libblock(ta);
426         
427         tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name");
428         strcpy(tan->name, ta->name);
429         
430         tan->flags = ta->flags | TXT_ISDIRTY | TXT_ISTMP;
431         
432         tan->lines.first= tan->lines.last= NULL;
433         tan->markers.first= tan->markers.last= NULL;
434         tan->curl= tan->sell= NULL;
435         
436         tan->nlines= ta->nlines;
437
438         line= ta->lines.first;  
439         /* Walk down, reconstructing */
440         while (line) {
441                 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
442                 tmp->line= MEM_mallocN(line->len+1, "textline_string");
443                 tmp->format= NULL;
444                 
445                 strcpy(tmp->line, line->line);
446
447                 tmp->len= line->len;
448                 
449                 BLI_addtail(&tan->lines, tmp);
450                 
451                 line= line->next;
452         }
453
454         tan->curl= tan->sell= tan->lines.first;
455         tan->curc= tan->selc= 0;
456
457         return tan;
458 }
459
460 /*****************************/
461 /* Editing utility functions */
462 /*****************************/
463
464 static void make_new_line (TextLine *line, char *newline) 
465 {
466         if (line->line) MEM_freeN(line->line);
467         if (line->format) MEM_freeN(line->format);
468         
469         line->line= newline;
470         line->len= strlen(newline);
471         line->format= NULL;
472 }
473
474 static TextLine *txt_new_line(char *str)
475 {
476         TextLine *tmp;
477
478         if(!str) str= "";
479         
480         tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
481         tmp->line= MEM_mallocN(strlen(str)+1, "textline_string");
482         tmp->format= NULL;
483         
484         strcpy(tmp->line, str);
485         
486         tmp->len= strlen(str);
487         tmp->next= tmp->prev= NULL;
488         
489         return tmp;
490 }
491
492 static TextLine *txt_new_linen(char *str, int n)
493 {
494         TextLine *tmp;
495
496         if(!str) str= "";
497         
498         tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
499         tmp->line= MEM_mallocN(n+1, "textline_string");
500         tmp->format= NULL;
501         
502         BLI_strncpy(tmp->line, str, n+1);
503         
504         tmp->len= strlen(tmp->line);
505         tmp->next= tmp->prev= NULL;
506         
507         return tmp;
508 }
509
510 void txt_clean_text (Text *text) 
511 {       
512         TextLine **top, **bot;
513         
514         if (!text) return;
515         
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);
519         } 
520         
521         if (!text->lines.last) text->lines.last= text->lines.first;
522
523         top= (TextLine **) &text->lines.first;
524         bot= (TextLine **) &text->lines.last;
525         
526         while ((*top)->prev) *top= (*top)->prev;
527         while ((*bot)->next) *bot= (*bot)->next;
528
529         if(!text->curl) {
530                 if(text->sell) text->curl= text->sell;
531                 else text->curl= text->lines.first;
532                 text->curc= 0;
533         }
534
535         if(!text->sell) {
536                 text->sell= text->curl;
537                 text->selc= 0;
538         }
539 }
540
541 int txt_get_span (TextLine *from, TextLine *to)
542 {
543         int ret=0;
544         TextLine *tmp= from;
545
546         if (!to || !from) return 0;
547         if (from==to) return 0;
548
549         /* Look forwards */
550         while (tmp) {
551                 if (tmp == to) return ret;
552                 ret++;
553                 tmp= tmp->next;
554         }
555
556         /* Look backwards */
557         if (!tmp) {
558                 tmp= from;
559                 ret=0;
560                 while(tmp) {
561                         if (tmp == to) break;
562                         ret--;
563                         tmp= tmp->prev;
564                 }
565                 if(!tmp) ret=0;
566         }
567
568         return ret;     
569 }
570
571 static void txt_make_dirty (Text *text)
572 {
573         text->flags |= TXT_ISDIRTY;
574         if (text->compiled) BPY_free_compiled_text(text);
575 }
576
577 /* 0:whitespace, 1:punct, 2:alphanumeric */
578 static short txt_char_type (char ch)
579 {
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 */
588         return 1;
589 }
590
591 /****************************/
592 /* Cursor utility functions */
593 /****************************/
594
595 static void txt_curs_cur (Text *text, TextLine ***linep, int **charp)
596 {
597         *linep= &text->curl; *charp= &text->curc;
598 }
599
600 static void txt_curs_sel (Text *text, TextLine ***linep, int **charp)
601 {
602         *linep= &text->sell; *charp= &text->selc;
603 }
604
605 static void txt_curs_first (Text *text, TextLine **linep, int *charp)
606 {
607         if (text->curl==text->sell) {
608                 *linep= text->curl;
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)) {
612                 *linep= text->curl;
613                 *charp= text->curc;
614         } else {
615                 *linep= text->sell;
616                 *charp= text->selc;             
617         }
618 }
619
620 /****************************/
621 /* Cursor movement functions */
622 /****************************/
623
624 void txt_move_up(Text *text, short sel)
625 {
626         TextLine **linep;
627         int *charp, old;
628         
629         if (!text) return;
630         if(sel) txt_curs_sel(text, &linep, &charp);
631         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
632         if (!*linep) return;
633         old= *charp;
634
635         if((*linep)->prev) {
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);
640                 } else {
641                         if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
642                 }
643         } else {
644                 txt_move_bol(text, sel);
645         }
646
647         if(!sel) txt_pop_sel(text);
648 }
649
650 void txt_move_down(Text *text, short sel) 
651 {
652         TextLine **linep;
653         int *charp, old;
654         
655         if (!text) return;
656         if(sel) txt_curs_sel(text, &linep, &charp);
657         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
658         if (!*linep) return;
659         old= *charp;
660
661         if((*linep)->next) {
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);
666                 } else
667                         if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);  
668         } else {
669                 txt_move_eol(text, sel);
670         }
671
672         if(!sel) txt_pop_sel(text);
673 }
674
675 void txt_move_left(Text *text, short sel) 
676 {
677         TextLine **linep;
678         int *charp, oundoing= undoing;
679         
680         if (!text) return;
681         if(sel) txt_curs_sel(text, &linep, &charp);
682         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
683         if (!*linep) return;
684
685         undoing= 1;
686         if (*charp== 0) {
687                 if ((*linep)->prev) {
688                         txt_move_up(text, sel);
689                         *charp= (*linep)->len;
690                 }
691         } else {
692                 (*charp)--;
693         }
694         undoing= oundoing;
695         if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
696         
697         if(!sel) txt_pop_sel(text);
698 }
699
700 void txt_move_right(Text *text, short sel) 
701 {
702         TextLine **linep;
703         int *charp, oundoing= undoing;
704         
705         if (!text) return;
706         if(sel) txt_curs_sel(text, &linep, &charp);
707         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
708         if (!*linep) return;
709
710         undoing= 1;
711         if (*charp== (*linep)->len) {
712                 if ((*linep)->next) {
713                         txt_move_down(text, sel);
714                         *charp= 0;
715                 }
716         } else {
717                 (*charp)++;
718         }
719         undoing= oundoing;
720         if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
721
722         if(!sel) txt_pop_sel(text);
723 }
724
725 void txt_jump_left(Text *text, short sel)
726 {
727         TextLine **linep, *oldl;
728         int *charp, oldc, count, i;
729         unsigned char oldu;
730
731         if (!text) return;
732         if(sel) txt_curs_sel(text, &linep, &charp);
733         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
734         if (!*linep) return;
735
736         oldl= *linep;
737         oldc= *charp;
738         oldu= undoing;
739         undoing= 1; /* Don't push individual moves to undo stack */
740
741         count= 0;
742         for (i=0; i<3; i++) {
743                 if (count < 2) {
744                         while (*charp>0 && txt_char_type((*linep)->line[*charp-1])==i) {
745                                 txt_move_left(text, sel);
746                                 count++;
747                         }
748                 }
749         }
750         if (count==0) txt_move_left(text, sel);
751
752         undoing= oldu;
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);
754 }
755
756 void txt_jump_right(Text *text, short sel)
757 {
758         TextLine **linep, *oldl;
759         int *charp, oldc, count, i;
760         unsigned char oldu;
761
762         if (!text) return;
763         if(sel) txt_curs_sel(text, &linep, &charp);
764         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
765         if (!*linep) return;
766
767         oldl= *linep;
768         oldc= *charp;
769         oldu= undoing;
770         undoing= 1; /* Don't push individual moves to undo stack */
771
772         count= 0;
773         for (i=0; i<3; i++) {
774                 if (count < 2) {
775                         while (*charp<(*linep)->len && txt_char_type((*linep)->line[*charp])==i) {
776                                 txt_move_right(text, sel);
777                                 count++;
778                         }
779                 }
780         }
781         if (count==0) txt_move_right(text, sel);
782
783         undoing= oldu;
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);
785 }
786
787 void txt_move_bol (Text *text, short sel) 
788 {
789         TextLine **linep;
790         int *charp, old;
791         
792         if (!text) return;
793         if(sel) txt_curs_sel(text, &linep, &charp);
794         else txt_curs_cur(text, &linep, &charp);
795         if (!*linep) return;
796         old= *charp;
797         
798         *charp= 0;
799
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);
802 }
803
804 void txt_move_eol (Text *text, short sel) 
805 {
806         TextLine **linep;
807         int *charp, old;
808         
809         if (!text) return;
810         if(sel) txt_curs_sel(text, &linep, &charp);
811         else txt_curs_cur(text, &linep, &charp);
812         if (!*linep) return;
813         old= *charp;
814                 
815         *charp= (*linep)->len;
816
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);
819 }
820
821 void txt_move_bof (Text *text, short sel)
822 {
823         TextLine **linep;
824         int *charp, old;
825         
826         if (!text) return;
827         if(sel) txt_curs_sel(text, &linep, &charp);
828         else txt_curs_cur(text, &linep, &charp);
829         if (!*linep) return;
830         old= *charp;
831
832         *linep= text->lines.first;
833         *charp= 0;
834
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);
837 }
838
839 void txt_move_eof (Text *text, short sel)
840 {
841         TextLine **linep;
842         int *charp, old;
843         
844         if (!text) return;
845         if(sel) txt_curs_sel(text, &linep, &charp);
846         else txt_curs_cur(text, &linep, &charp);
847         if (!*linep) return;
848         old= *charp;
849
850         *linep= text->lines.last;
851         *charp= (*linep)->len;
852
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);     
855 }
856
857 void txt_move_toline (Text *text, unsigned int line, short sel)
858 {
859         txt_move_to(text, line, 0, sel);
860 }
861
862 void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel)
863 {
864         TextLine **linep, *oldl;
865         int *charp, oldc;
866         unsigned int i;
867         
868         if (!text) return;
869         if(sel) txt_curs_sel(text, &linep, &charp);
870         else txt_curs_cur(text, &linep, &charp);
871         if (!*linep) return;
872         oldc= *charp;
873         oldl= *linep;
874         
875         *linep= text->lines.first;
876         for (i=0; i<line; i++) {
877                 if ((*linep)->next) *linep= (*linep)->next;
878                 else break;
879         }
880         if (ch>(*linep)->len)
881                 ch= (*linep)->len;
882         *charp= ch;
883         
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);
886 }
887
888 /****************************/
889 /* Text selection functions */
890 /****************************/
891
892 static void txt_curs_swap (Text *text)
893 {
894         TextLine *tmpl;
895         int tmpc;
896                 
897         tmpl= text->curl;
898         text->curl= text->sell;
899         text->sell= tmpl;
900         
901         tmpc= text->curc;
902         text->curc= text->selc;
903         text->selc= tmpc;
904         
905         if(!undoing) txt_undo_add_op(text, UNDO_SWAP);
906 }
907
908 static void txt_pop_first (Text *text)
909 {
910                         
911         if (txt_get_span(text->curl, text->sell)<0 ||
912                 (text->curl==text->sell && text->curc>text->selc)) {    
913                 txt_curs_swap(text);
914         }
915
916         if(!undoing) txt_undo_add_toop(text, UNDO_STO,
917                 txt_get_span(text->lines.first, text->sell), 
918                 text->selc, 
919                 txt_get_span(text->lines.first, text->curl), 
920                 text->curc);            
921         
922         txt_pop_sel(text);
923 }
924
925 static void txt_pop_last (Text *text)
926 {
927         if (txt_get_span(text->curl, text->sell)>0 ||
928                 (text->curl==text->sell && text->curc<text->selc)) {
929                 txt_curs_swap(text);
930         }
931
932         if(!undoing) txt_undo_add_toop(text, UNDO_STO,
933                 txt_get_span(text->lines.first, text->sell), 
934                 text->selc, 
935                 txt_get_span(text->lines.first, text->curl), 
936                 text->curc);            
937         
938         txt_pop_sel(text);
939 }
940
941 /* never used: CVS 1.19 */
942 /*  static void txt_pop_selr (Text *text) */
943
944 void txt_pop_sel (Text *text)
945 {
946         text->sell= text->curl;
947         text->selc= text->curc; 
948 }
949
950 void txt_order_cursors(Text *text)
951 {
952         if (!text) return;
953         if (!text->curl) return;
954         if (!text->sell) return;
955         
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))
959                 txt_curs_swap(text);
960 }
961
962 int txt_has_sel(Text *text)
963 {
964         return ((text->curl!=text->sell) || (text->curc!=text->selc));
965 }
966
967 static void txt_delete_sel (Text *text)
968 {
969         TextLine *tmpl;
970         TextMarker *mrk;
971         char *buf;
972         int move, lineno;
973         
974         if (!text) return;
975         if (!text->curl) return;
976         if (!text->sell) return;
977
978         if (!txt_has_sel(text)) return;
979         
980         txt_order_cursors(text);
981
982         if(!undoing) {
983                 buf= txt_sel_to_buf(text);
984                 txt_undo_add_block(text, UNDO_DBLOCK, buf);
985                 MEM_freeN(buf);
986         }
987
988         buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
989         
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);
993         } else {
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);
997                 move= 0;
998         }
999
1000         mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0);
1001         if (mrk) {
1002                 lineno= mrk->lineno;
1003                 do {
1004                         mrk->lineno -= move;
1005                         if (mrk->start > text->curc) mrk->start -= text->selc - text->curc;
1006                         mrk->end -= text->selc - text->curc;
1007                         mrk= mrk->next;
1008                 } while (mrk && mrk->lineno==lineno);
1009         }
1010
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;
1014
1015         make_new_line(text->curl, buf);
1016         
1017         tmpl= text->sell;
1018         while (tmpl != text->curl) {
1019                 tmpl= tmpl->prev;
1020                 if (!tmpl) break;
1021                 
1022                 txt_delete_line(text, tmpl->next);
1023         }
1024         
1025         text->sell= text->curl;
1026         text->selc= text->curc;
1027 }
1028
1029 void txt_sel_all (Text *text)
1030 {
1031         if (!text) return;
1032
1033         text->curl= text->lines.first;
1034         text->curc= 0;
1035         
1036         text->sell= text->lines.last;
1037         text->selc= text->sell->len;
1038 }
1039
1040 void txt_sel_line (Text *text)
1041 {
1042         if (!text) return;
1043         if (!text->curl) return;
1044         
1045         text->curc= 0;
1046         text->sell= text->curl;
1047         text->selc= text->sell->len;
1048 }
1049
1050 /***************************/
1051 /* Cut and paste functions */
1052 /***************************/
1053
1054 void txt_print_cutbuffer (void) 
1055 {
1056         printf ("Cut buffer\n--\n%s\n--\n", txt_cut_buffer);    
1057 }
1058
1059 char *txt_to_buf (Text *text)
1060 {
1061         int length;
1062         TextLine *tmp, *linef, *linel;
1063         int charf, charl;
1064         char *buf;
1065         
1066         if (!text) return NULL;
1067         if (!text->curl) return NULL;
1068         if (!text->sell) return NULL;
1069         if (!text->lines.first) return NULL;
1070
1071         linef= text->lines.first;
1072         charf= 0;
1073                 
1074         linel= text->lines.last;
1075         charl= linel->len;
1076
1077         if (linef == text->lines.last) {
1078                 length= charl-charf;
1079
1080                 buf= MEM_mallocN(length+2, "text buffer");
1081                 
1082                 BLI_strncpy(buf, linef->line + charf, length+1);
1083                 buf[length]=0;
1084         } else {
1085                 length= linef->len - charf;
1086                 length+= charl;
1087                 length+= 2; /* For the 2 '\n' */
1088                 
1089                 tmp= linef->next;
1090                 while (tmp && tmp!= linel) {
1091                         length+= tmp->len+1;
1092                         tmp= tmp->next;
1093                 }
1094                 
1095                 buf= MEM_mallocN(length+1, "cut buffer");
1096
1097                 strncpy(buf, linef->line + charf, linef->len-charf);
1098                 length= linef->len - charf;
1099                 
1100                 buf[length++]='\n';
1101                 
1102                 tmp= linef->next;
1103                 while (tmp && tmp!=linel) {
1104                         strncpy(buf+length, tmp->line, tmp->len);
1105                         length+= tmp->len;
1106                         
1107                         buf[length++]='\n';                     
1108                         
1109                         tmp= tmp->next;
1110                 }
1111                 strncpy(buf+length, linel->line, charl);
1112                 length+= charl;
1113                 
1114                 /* python compiler wants an empty end line */
1115                 buf[length++]='\n';                     
1116                 buf[length]=0;
1117         }
1118         
1119         return buf;
1120 }
1121
1122 int txt_find_string(Text *text, char *findstr, int wrap)
1123 {
1124         TextLine *tl, *startl;
1125         char *s= NULL;
1126         int oldcl, oldsl, oldcc, oldsc;
1127
1128         if (!text || !text->curl || !text->sell) return 0;
1129         
1130         txt_order_cursors(text);
1131
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;
1135         oldcc= text->curc;
1136         oldsc= text->selc;
1137         
1138         s= strstr(&tl->line[text->selc], findstr);
1139         while (!s) {
1140                 tl= tl->next;
1141                 if (!tl) {
1142                         if (wrap)
1143                                 tl= text->lines.first;
1144                         else
1145                                 break;
1146                 }
1147
1148                 s= strstr(tl->line, findstr);
1149                 if (tl==startl)
1150                         break;
1151         }
1152         
1153         if (s) {
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);
1158                 return 1;                               
1159         } else
1160                 return 0;
1161 }
1162
1163 void txt_cut_sel (Text *text)
1164 {
1165         if (!G.background) /* Python uses txt_cut_sel, which it should not, working around for now  */
1166                 txt_copy_clipboard(text);
1167         
1168         txt_delete_sel(text);
1169         txt_make_dirty(text);
1170 }
1171
1172 char *txt_sel_to_buf (Text *text)
1173 {
1174         char *buf;
1175         int length=0;
1176         TextLine *tmp, *linef, *linel;
1177         int charf, charl;
1178         
1179         if (!text) return NULL;
1180         if (!text->curl) return NULL;
1181         if (!text->sell) return NULL;
1182         
1183         if (text->curl==text->sell) {
1184                 linef= linel= text->curl;
1185                 
1186                 if (text->curc < text->selc) {
1187                         charf= text->curc;
1188                         charl= text->selc;
1189                 } else{
1190                         charf= text->selc;
1191                         charl= text->curc;
1192                 }
1193         } else if (txt_get_span(text->curl, text->sell)<0) {
1194                 linef= text->sell;
1195                 linel= text->curl;
1196
1197                 charf= text->selc;              
1198                 charl= text->curc;
1199         } else {
1200                 linef= text->curl;
1201                 linel= text->sell;
1202                 
1203                 charf= text->curc;
1204                 charl= text->selc;
1205         }
1206
1207         if (linef == linel) {
1208                 length= charl-charf;
1209
1210                 buf= MEM_mallocN(length+1, "sel buffer");
1211                 
1212                 BLI_strncpy(buf, linef->line + charf, length+1);
1213         } else {
1214                 length+= linef->len - charf;
1215                 length+= charl;
1216                 length++; /* For the '\n' */
1217                 
1218                 tmp= linef->next;
1219                 while (tmp && tmp!= linel) {
1220                         length+= tmp->len+1;
1221                         tmp= tmp->next;
1222                 }
1223                 
1224                 buf= MEM_mallocN(length+1, "sel buffer");
1225                 
1226                 strncpy(buf, linef->line+ charf, linef->len-charf);
1227                 length= linef->len-charf;
1228                 
1229                 buf[length++]='\n';
1230                 
1231                 tmp= linef->next;
1232                 while (tmp && tmp!=linel) {
1233                         strncpy(buf+length, tmp->line, tmp->len);
1234                         length+= tmp->len;
1235                         
1236                         buf[length++]='\n';                     
1237                         
1238                         tmp= tmp->next;
1239                 }
1240                 strncpy(buf+length, linel->line, charl);
1241                 length+= charl;
1242                 
1243                 buf[length]=0;
1244         }       
1245
1246         return buf;
1247 }
1248
1249 void txt_copy_sel (Text *text)
1250 {
1251         int length=0;
1252         TextLine *tmp, *linef, *linel;
1253         int charf, charl;
1254         
1255         if (!text) return;
1256         if (!text->curl) return;
1257         if (!text->sell) return;
1258
1259         if (!txt_has_sel(text)) return;
1260         
1261         if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
1262         txt_cut_buffer= NULL;
1263         
1264         if (text->curl==text->sell) {
1265                 linef= linel= text->curl;
1266                 
1267                 if (text->curc < text->selc) {
1268                         charf= text->curc;
1269                         charl= text->selc;
1270                 } else{
1271                         charf= text->selc;
1272                         charl= text->curc;
1273                 }
1274         } else if (txt_get_span(text->curl, text->sell)<0) {
1275                 linef= text->sell;
1276                 linel= text->curl;
1277
1278                 charf= text->selc;              
1279                 charl= text->curc;
1280         } else {
1281                 linef= text->curl;
1282                 linel= text->sell;
1283                 
1284                 charf= text->curc;
1285                 charl= text->selc;
1286         }
1287
1288         if (linef == linel) {
1289                 length= charl-charf;
1290
1291                 txt_cut_buffer= MEM_mallocN(length+1, "cut buffera");
1292                 
1293                 BLI_strncpy(txt_cut_buffer, linef->line + charf, length+1);
1294         } else {
1295                 length+= linef->len - charf;
1296                 length+= charl;
1297                 length++; /* For the '\n' */
1298                 
1299                 tmp= linef->next;
1300                 while (tmp && tmp!= linel) {
1301                         length+= tmp->len+1;
1302                         tmp= tmp->next;
1303                 }
1304                 
1305                 txt_cut_buffer= MEM_mallocN(length+1, "cut bufferb");
1306                 
1307                 strncpy(txt_cut_buffer, linef->line+ charf, linef->len-charf);
1308                 length= linef->len-charf;
1309                 
1310                 txt_cut_buffer[length++]='\n';
1311                 
1312                 tmp= linef->next;
1313                 while (tmp && tmp!=linel) {
1314                         strncpy(txt_cut_buffer+length, tmp->line, tmp->len);
1315                         length+= tmp->len;
1316                         
1317                         txt_cut_buffer[length++]='\n';                  
1318                         
1319                         tmp= tmp->next;
1320                 }
1321                 strncpy(txt_cut_buffer+length, linel->line, charl);
1322                 length+= charl;
1323                 
1324                 txt_cut_buffer[length]=0;
1325         }
1326 }
1327
1328 void txt_insert_buf(Text *text, char *in_buffer)
1329 {
1330         int i=0, l=0, j, u, len;
1331         TextLine *add;
1332
1333         if (!text) return;
1334         if (!in_buffer) return;
1335
1336         txt_delete_sel(text);
1337         
1338         if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer);         
1339
1340         u= undoing;
1341         undoing= 1;
1342
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]);
1346                 i++;
1347         }
1348         
1349         if (in_buffer[i]=='\n') txt_split_curline(text);
1350         else { undoing = u; return; }
1351         i++;
1352
1353         /* Read as many full lines as we can */
1354         len= strlen(in_buffer);
1355
1356         while (i<len) {
1357                 l=0;
1358
1359                 while (in_buffer[i] && in_buffer[i]!='\n') {
1360                         i++; l++;
1361                 }
1362         
1363                 if(in_buffer[i]=='\n') {
1364                         add= txt_new_linen(in_buffer +(i-l), l);
1365                         BLI_insertlinkbefore(&text->lines, text->curl, add);
1366                         i++;
1367                 } else {
1368                         for (j= i-l; j<i && j<(int)strlen(in_buffer); j++) {
1369                                 txt_add_char(text, in_buffer[j]);
1370                         }
1371                         break;
1372                 }
1373         }
1374         
1375         undoing= u;
1376 }
1377
1378 void txt_free_cut_buffer(void) 
1379 {
1380         if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
1381 }
1382
1383 void txt_paste(Text *text)
1384 {
1385         txt_insert_buf(text, txt_cut_buffer);
1386 }
1387
1388 /******************/
1389 /* Undo functions */
1390 /******************/
1391
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; \
1400                         return; \
1401                 } else { \
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; \
1406                         MEM_freeN(tmp); \
1407                 } \
1408         }
1409
1410 static void dump_buffer(Text *text) 
1411 {
1412         int i= 0;
1413         
1414         while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
1415 }
1416
1417 void txt_print_undo(Text *text)
1418 {
1419         int i= 0;
1420         int op;
1421         char *ops;
1422         int linep, charp;
1423         
1424         dump_buffer(text);
1425         
1426         printf ("---< Undo Buffer >---\n");
1427         
1428         printf ("UndoPosition is %d\n", text->undo_pos);
1429         
1430         while (i<=text->undo_pos) {
1431                 op= text->undo_buf[i];
1432                 
1433                 if (op==UNDO_CLEFT) {
1434                         ops= "Cursor left";
1435                 } else if (op==UNDO_CRIGHT) {
1436                         ops= "Cursor right";
1437                 } else if (op==UNDO_CUP) {
1438                         ops= "Cursor up";
1439                 } else if (op==UNDO_CDOWN) {
1440                         ops= "Cursor down";
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) {
1450                         ops= "Selection ";
1451                 } else if (op==UNDO_CTO) {
1452                         ops= "Cursor ";
1453                 } else if (op==UNDO_INSERT) {
1454                         ops= "Insert";
1455                 } else if (op==UNDO_BS) {
1456                         ops= "Backspace";
1457                 } else if (op==UNDO_DEL) {
1458                         ops= "Delete";
1459                 } else if (op==UNDO_SWAP) {
1460                         ops= "Cursor 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) {
1466                         ops= "Indent ";
1467                 } else if (op==UNDO_UNINDENT) {
1468                         ops= "Unindent ";
1469                 } else if (op==UNDO_COMMENT) {
1470                         ops= "Comment ";
1471                 } else if (op==UNDO_UNCOMMENT) {
1472                         ops= "Uncomment ";
1473                 } else {
1474                         ops= "Unknown";
1475                 }
1476                 
1477                 printf ("Op (%o) at %d = %s", op, i, ops);
1478                 if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) {
1479                         i++;
1480                         printf (" - Char is %c", text->undo_buf[i]);  
1481                         i++;
1482                 } else if (op==UNDO_STO || op==UNDO_CTO) {
1483                         i++;
1484
1485                         charp= text->undo_buf[i]; i++;
1486                         charp= charp+(text->undo_buf[i]<<8); i++;
1487
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++;
1492                         
1493                         printf ("to <%d, %d> ", linep, charp);
1494
1495                         charp= text->undo_buf[i]; i++;
1496                         charp= charp+(text->undo_buf[i]<<8); i++;
1497
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++;
1502                         
1503                         printf ("from <%d, %d>", linep, charp);
1504                 } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
1505                         i++;
1506
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++;
1511                         
1512                         printf (" (length %d) <", linep);
1513                         
1514                         while (linep>0) {
1515                                 putchar(text->undo_buf[i]);
1516                                 linep--; i++;
1517                         }
1518                         
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) {
1525                         i++;
1526
1527                         charp= text->undo_buf[i]; i++;
1528                         charp= charp+(text->undo_buf[i]<<8); i++;
1529
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++;
1534                         
1535                         printf ("to <%d, %d> ", linep, charp);
1536
1537                         charp= text->undo_buf[i]; i++;
1538                         charp= charp+(text->undo_buf[i]<<8); i++;
1539
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++;
1544                         
1545                         printf ("from <%d, %d>", linep, charp);
1546                 }
1547                 
1548                 printf (" %d\n",  i);
1549                 i++;
1550         }
1551 }
1552
1553 static void txt_undo_add_op(Text *text, int op)
1554 {
1555         MAX_UNDO_TEST(2);
1556         
1557         text->undo_pos++;
1558         text->undo_buf[text->undo_pos]= op;
1559         text->undo_buf[text->undo_pos+1]= 0;
1560 }
1561
1562 static void txt_undo_add_block(Text *text, int op, char *buf)
1563 {
1564         int length;
1565         
1566         length= strlen(buf);
1567         
1568         MAX_UNDO_TEST(length+11);
1569
1570         text->undo_pos++;
1571         text->undo_buf[text->undo_pos]= op;
1572         
1573         text->undo_pos++;
1574         text->undo_buf[text->undo_pos]= (length)&0xff;
1575         text->undo_pos++;
1576         text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1577         text->undo_pos++;
1578         text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1579         text->undo_pos++;
1580         text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1581
1582         text->undo_pos++;
1583         strncpy(text->undo_buf+text->undo_pos, buf, length);
1584         text->undo_pos+=length;
1585
1586         text->undo_buf[text->undo_pos]= (length)&0xff;
1587         text->undo_pos++;
1588         text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1589         text->undo_pos++;
1590         text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1591         text->undo_pos++;
1592         text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1593
1594         text->undo_pos++;
1595         text->undo_buf[text->undo_pos]= op;
1596         
1597         text->undo_buf[text->undo_pos+1]= 0;
1598 }
1599
1600 void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
1601 {
1602         MAX_UNDO_TEST(15);
1603
1604         if (froml==tol && fromc==toc) return;
1605
1606         text->undo_pos++;
1607         text->undo_buf[text->undo_pos]= op;
1608
1609         text->undo_pos++;
1610         text->undo_buf[text->undo_pos]= (fromc)&0xff;
1611         text->undo_pos++;
1612         text->undo_buf[text->undo_pos]= (fromc>>8)&0xff;
1613
1614         text->undo_pos++;
1615         text->undo_buf[text->undo_pos]= (froml)&0xff;
1616         text->undo_pos++;
1617         text->undo_buf[text->undo_pos]= (froml>>8)&0xff;
1618         text->undo_pos++;
1619         text->undo_buf[text->undo_pos]= (froml>>16)&0xff;
1620         text->undo_pos++;
1621         text->undo_buf[text->undo_pos]= (froml>>24)&0xff;
1622
1623         text->undo_pos++;
1624         text->undo_buf[text->undo_pos]= (toc)&0xff;
1625         text->undo_pos++;
1626         text->undo_buf[text->undo_pos]= (toc>>8)&0xff;
1627
1628         text->undo_pos++;
1629         text->undo_buf[text->undo_pos]= (tol)&0xff;
1630         text->undo_pos++;
1631         text->undo_buf[text->undo_pos]= (tol>>8)&0xff;
1632         text->undo_pos++;
1633         text->undo_buf[text->undo_pos]= (tol>>16)&0xff;
1634         text->undo_pos++;
1635         text->undo_buf[text->undo_pos]= (tol>>24)&0xff;
1636
1637         text->undo_pos++;
1638         text->undo_buf[text->undo_pos]= op;
1639
1640         text->undo_buf[text->undo_pos+1]= 0;
1641 }
1642
1643 static void txt_undo_add_charop(Text *text, int op, char c)
1644 {
1645         MAX_UNDO_TEST(4);
1646
1647         text->undo_pos++;
1648         text->undo_buf[text->undo_pos]= op;
1649         text->undo_pos++;
1650         text->undo_buf[text->undo_pos]= c;
1651         text->undo_pos++;
1652         text->undo_buf[text->undo_pos]= op;
1653         text->undo_buf[text->undo_pos+1]= 0;
1654 }
1655
1656 void txt_do_undo(Text *text)
1657 {
1658         int op= text->undo_buf[text->undo_pos];
1659         unsigned int linep, i;
1660         unsigned short charp;
1661         TextLine *holdl;
1662         int holdc, holdln;
1663         char *buf;
1664         
1665         if (text->undo_pos<0) {
1666                 return;
1667         }
1668
1669         text->undo_pos--;
1670
1671         undoing= 1;
1672         
1673         switch(op) {
1674                 case UNDO_CLEFT:
1675                         txt_move_right(text, 0);
1676                         break;
1677                         
1678                 case UNDO_CRIGHT:
1679                         txt_move_left(text, 0);
1680                         break;
1681                         
1682                 case UNDO_CUP:
1683                         txt_move_down(text, 0);
1684                         break;
1685                         
1686                 case UNDO_CDOWN:
1687                         txt_move_up(text, 0);
1688                         break;
1689
1690                 case UNDO_SLEFT:
1691                         txt_move_right(text, 1);
1692                         break;
1693
1694                 case UNDO_SRIGHT:
1695                         txt_move_left(text, 1);
1696                         break;
1697
1698                 case UNDO_SUP:
1699                         txt_move_down(text, 1);
1700                         break;
1701
1702                 case UNDO_SDOWN:
1703                         txt_move_up(text, 1);
1704                         break;
1705                 
1706                 case UNDO_CTO:
1707                 case UNDO_STO:
1708                         text->undo_pos--;
1709                         text->undo_pos--;
1710                         text->undo_pos--;
1711                         text->undo_pos--;
1712                 
1713                         text->undo_pos--;
1714                         text->undo_pos--;
1715                 
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--;
1720
1721                         charp= text->undo_buf[text->undo_pos]; text->undo_pos--;
1722                         charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1723                         
1724                         if (op==UNDO_CTO) {
1725                                 txt_move_toline(text, linep, 0);
1726                                 text->curc= charp;
1727                                 txt_pop_sel(text);
1728                         } else {
1729                                 txt_move_toline(text, linep, 1);
1730                                 text->selc= charp;
1731                         }
1732                         
1733                         text->undo_pos--;
1734                         break;
1735                         
1736                 case UNDO_INSERT:
1737                         txt_backspace_char(text);
1738                         text->undo_pos--;
1739                         text->undo_pos--;
1740                         break;
1741
1742                 case UNDO_BS:
1743                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1744                         text->undo_pos--;
1745                         text->undo_pos--;
1746                         break;
1747
1748                 case UNDO_DEL:
1749                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1750                         txt_move_left(text, 0);
1751                         text->undo_pos--;
1752                         text->undo_pos--;
1753                         break;
1754
1755                 case UNDO_SWAP:
1756                         txt_curs_swap(text);
1757                         break;
1758
1759                 case UNDO_DBLOCK:
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--;
1764
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]; 
1768                                 text->undo_pos--;
1769                         }
1770                         buf[i]= 0;
1771                         
1772                         txt_curs_first(text, &holdl, &holdc);
1773                         holdln= txt_get_span(text->lines.first, holdl);
1774                         
1775                         txt_insert_buf(text, buf);                      
1776                         MEM_freeN(buf);
1777
1778                         text->curl= text->lines.first;
1779                         while (holdln>0) {
1780                                 if(text->curl->next)
1781                                         text->curl= text->curl->next;
1782                                         
1783                                 holdln--;
1784                         }
1785                         text->curc= holdc;
1786
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--;
1791
1792                         text->undo_pos--;
1793                         
1794                         break;
1795
1796                 case UNDO_IBLOCK:
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--;
1801
1802                         txt_delete_sel(text);
1803                         while (linep>0) {
1804                                 txt_backspace_char(text);
1805                                 text->undo_pos--;
1806                                 linep--;
1807                         }
1808
1809                         text->undo_pos--;
1810                         text->undo_pos--;
1811                         text->undo_pos--; 
1812                         text->undo_pos--;
1813                         
1814                         text->undo_pos--;
1815
1816                         break;
1817                 case UNDO_INDENT:
1818                 case UNDO_UNINDENT:
1819                 case UNDO_COMMENT:
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
1826                         
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
1831                         text->selc = charp;
1832                         text->sell = text->lines.first;
1833                         for (i= 0; i < linep; i++) {
1834                                 text->sell = text->sell->next;
1835                         }
1836
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
1842                         
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
1846                         text->curc = charp;
1847                         text->curl = text->lines.first;
1848                         for (i = 0; i < linep; i++) {
1849                                 text->curl = text->curl->next;
1850                         }
1851
1852                         
1853                         if (op==UNDO_INDENT) {
1854                                 unindent(text);
1855                         } else if (op== UNDO_UNINDENT) {
1856                                 indent(text);
1857                         } else if (op == UNDO_COMMENT) {
1858                                 uncomment(text);
1859                         } else if (op == UNDO_UNCOMMENT) {
1860                                 comment(text);
1861                         }
1862
1863                         text->undo_pos--;
1864                         break;
1865                 default:
1866                         error("Undo buffer error - resetting");
1867                         text->undo_pos= -1;
1868                         
1869                         break;
1870         }
1871
1872         /* next undo step may need evaluating */
1873         if (text->undo_pos>=0) {
1874                 switch (text->undo_buf[text->undo_pos]) {
1875                         case UNDO_STO:
1876                                 txt_do_undo(text);
1877                                 txt_do_redo(text); /* selections need restoring */
1878                                 break;
1879                         case UNDO_SWAP:
1880                                 txt_do_undo(text); /* swaps should appear transparent */
1881                                 break;
1882                 }
1883         }
1884         
1885         undoing= 0;     
1886 }
1887
1888 void txt_do_redo(Text *text)
1889 {
1890         char op;
1891         unsigned int linep, i;
1892         unsigned short charp;
1893         char *buf;
1894         
1895         text->undo_pos++;       
1896         op= text->undo_buf[text->undo_pos];
1897         
1898         if (!op) {
1899                 text->undo_pos--;
1900                 return;
1901         }
1902         
1903         undoing= 1;
1904
1905         switch(op) {
1906                 case UNDO_CLEFT:
1907                         txt_move_left(text, 0);
1908                         break;
1909                         
1910                 case UNDO_CRIGHT:
1911                         txt_move_right(text, 0);
1912                         break;
1913                         
1914                 case UNDO_CUP:
1915                         txt_move_up(text, 0);
1916                         break;
1917                         
1918                 case UNDO_CDOWN:
1919                         txt_move_down(text, 0);
1920                         break;
1921
1922                 case UNDO_SLEFT:
1923                         txt_move_left(text, 1);
1924                         break;
1925
1926                 case UNDO_SRIGHT:
1927                         txt_move_right(text, 1);
1928                         break;
1929
1930                 case UNDO_SUP:
1931                         txt_move_up(text, 1);
1932                         break;
1933
1934                 case UNDO_SDOWN:
1935                         txt_move_down(text, 1);
1936                         break;
1937                 
1938                 case UNDO_INSERT:
1939                         text->undo_pos++;
1940                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1941                         text->undo_pos++;
1942                         break;
1943
1944                 case UNDO_BS:
1945                         text->undo_pos++;
1946                         txt_backspace_char(text);
1947                         text->undo_pos++;
1948                         break;
1949
1950                 case UNDO_DEL:
1951                         text->undo_pos++;
1952                         txt_delete_char(text);
1953                         text->undo_pos++;
1954                         break;
1955
1956                 case UNDO_SWAP:
1957                         txt_curs_swap(text);
1958                         txt_do_redo(text); /* swaps should appear transparent a*/
1959                         break;
1960                         
1961                 case UNDO_CTO:
1962                 case UNDO_STO:
1963                         text->undo_pos++;
1964                         text->undo_pos++;
1965
1966                         text->undo_pos++;
1967                         text->undo_pos++;
1968                         text->undo_pos++;
1969                         text->undo_pos++;
1970
1971                         text->undo_pos++;
1972
1973                         charp= text->undo_buf[text->undo_pos];
1974                         text->undo_pos++;
1975                         charp= charp+(text->undo_buf[text->undo_pos]<<8);
1976
1977                         text->undo_pos++;
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++;
1982                         
1983                         if (op==UNDO_CTO) {
1984                                 txt_move_toline(text, linep, 0);
1985                                 text->curc= charp;
1986                                 txt_pop_sel(text);
1987                         } else {
1988                                 txt_move_toline(text, linep, 1);
1989                                 text->selc= charp;
1990                         }
1991
1992                         break;
1993
1994                 case UNDO_DBLOCK:
1995                         text->undo_pos++;
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++;
2000
2001                         txt_delete_sel(text);
2002                         text->undo_pos+=linep;
2003
2004                         text->undo_pos++;
2005                         text->undo_pos++;
2006                         text->undo_pos++; 
2007                         text->undo_pos++;
2008                         
2009                         break;
2010
2011                 case UNDO_IBLOCK:
2012                         text->undo_pos++;
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++;
2017
2018                         buf= MEM_mallocN(linep+1, "iblock buffer");
2019                         memcpy (buf, &text->undo_buf[text->undo_pos], linep);
2020                         text->undo_pos+= linep;
2021                         buf[linep]= 0;
2022                         
2023                         txt_insert_buf(text, buf);                      
2024                         MEM_freeN(buf);
2025
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++;
2030
2031                         break;
2032                 case UNDO_INDENT:
2033                 case UNDO_UNINDENT:
2034                 case UNDO_COMMENT:
2035                 case UNDO_UNCOMMENT:
2036                         text->undo_pos++;
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
2040                         
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
2047                         text->curc = charp;
2048                         text->curl = text->lines.first;
2049                         for (i= 0; i < linep; i++) {
2050                                 text->curl = text->curl->next;
2051                         }
2052                         
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
2061                         
2062                         text->selc = charp;
2063                         text->sell = text->lines.first;
2064                         for (i = 0; i < linep; i++) {
2065                                 text->sell = text->sell->next;
2066                         }
2067
2068                         if (op==UNDO_INDENT) {
2069                                 indent(text);
2070                         } else if (op== UNDO_UNINDENT) {
2071                                 unindent(text);
2072                         } else if (op == UNDO_COMMENT) {
2073                                 comment(text);
2074                         } else if (op == UNDO_UNCOMMENT) {
2075                                 uncomment(text);
2076                         }
2077                         break;
2078                 default:
2079                         error("Undo buffer error - resetting");
2080                         text->undo_pos= -1;
2081
2082                         break;
2083         }
2084         
2085         undoing= 0;     
2086 }
2087
2088 /**************************/
2089 /* Line editing functions */ 
2090 /**************************/
2091
2092 void txt_split_curline (Text *text) 
2093 {
2094         TextLine *ins;
2095         TextMarker *mrk;
2096         char *left, *right;
2097         int lineno= -1;
2098         
2099         if (!text) return;
2100         if (!text->curl) return;
2101
2102         txt_delete_sel(text);
2103
2104         /* Move markers */
2105
2106         lineno= txt_get_span(text->lines.first, text->curl);
2107         mrk= text->markers.first;
2108         while (mrk) {
2109                 if (mrk->lineno==lineno && mrk->start>text->curc) {
2110                         mrk->lineno++;
2111                         mrk->start -= text->curc;
2112                         mrk->end -= text->curc;
2113                 } else if (mrk->lineno > lineno) {
2114                         mrk->lineno++;
2115                 }
2116                 mrk= mrk->next;
2117         }
2118
2119         /* Make the two half strings */
2120
2121         left= MEM_mallocN(text->curc+1, "textline_string");
2122         if (text->curc) memcpy(left, text->curl->line, text->curc);
2123         left[text->curc]=0;
2124         
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;
2128
2129         MEM_freeN(text->curl->line);
2130         if (text->curl->format) MEM_freeN(text->curl->format);
2131
2132         /* Make the new TextLine */
2133         
2134         ins= MEM_mallocN(sizeof(TextLine), "textline");
2135         ins->line= left;
2136         ins->format= NULL;
2137         ins->len= text->curc;
2138         
2139         text->curl->line= right;
2140         text->curl->format= NULL;
2141         text->curl->len= text->curl->len - text->curc;
2142         
2143         BLI_insertlinkbefore(&text->lines, text->curl, ins);    
2144         
2145         text->curc=0;
2146         
2147         txt_make_dirty(text);
2148         txt_clean_text(text);
2149         
2150         txt_pop_sel(text);
2151         if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n');
2152 }
2153
2154 static void txt_delete_line (Text *text, TextLine *line) 
2155 {
2156         TextMarker *mrk=NULL, *nxt;
2157         int lineno= -1;
2158
2159         if (!text) return;
2160         if (!text->curl) return;
2161
2162         lineno= txt_get_span(text->lines.first, line);
2163         mrk= text->markers.first;
2164         while (mrk) {
2165                 nxt= mrk->next;
2166                 if (mrk->lineno==lineno)
2167                         BLI_freelinkN(&text->markers, mrk);
2168                 else if (mrk->lineno > lineno)
2169                         mrk->lineno--;
2170                 mrk= nxt;
2171         }
2172
2173         BLI_remlink (&text->lines, line);
2174         
2175         if (line->line) MEM_freeN(line->line);
2176         if (line->format) MEM_freeN(line->format);
2177
2178         MEM_freeN(line);
2179
2180         txt_make_dirty(text);
2181         txt_clean_text(text);
2182 }
2183
2184 static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
2185 {
2186         char *tmp;
2187         TextMarker *mrk= NULL;
2188         int lineno=-1;
2189         
2190         if (!text) return;
2191         
2192         if(!linea || !lineb) return;
2193
2194         mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0);
2195         if (mrk) {
2196                 lineno= mrk->lineno;
2197                 do {
2198                         mrk->lineno--;
2199                         mrk->start += linea->len;
2200                         mrk->end += linea->len;
2201                         mrk= mrk->next;
2202                 } while (mrk && mrk->lineno==lineno);
2203         }
2204         if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb);
2205         if (!mrk) mrk= text->markers.first;
2206         
2207         tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
2208         
2209         strcpy(tmp, linea->line);
2210         strcat(tmp, lineb->line);
2211
2212         make_new_line(linea, tmp);
2213         
2214         txt_delete_line(text, lineb);
2215         
2216         txt_make_dirty(text);
2217         txt_clean_text(text);
2218 }
2219
2220 void txt_delete_char (Text *text) 
2221 {
2222         char c='\n';
2223         
2224         if (!text) return;
2225         if (!text->curl) return;
2226
2227         if (txt_has_sel(text)) { /* deleting a selection */
2228                 txt_delete_sel(text);
2229                 txt_make_dirty(text);
2230                 return;
2231         }
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);
2235                         txt_pop_sel(text);
2236                 }
2237         } else { /* Just deleting a char */
2238                 int i= text->curc;
2239
2240                 TextMarker *mrk= txt_find_marker_region(text, text->curl, i-1, text->curl->len, 0, 0);
2241                 if (mrk) {
2242                         int lineno= mrk->lineno;
2243                         if (mrk->end==i) {
2244                                 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2245                                         txt_clear_markers(text, mrk->group, TMARK_TEMP);
2246                                 } else {
2247                                         //TextMarker *nxt= mrk->next;
2248                                         BLI_freelinkN(&text->markers, mrk);
2249                                 }
2250                                 return;
2251                         }
2252                         do {
2253                                 if (mrk->start>i) mrk->start--;
2254                                 mrk->end--;
2255                                 mrk= mrk->next;
2256                         } while (mrk && mrk->lineno==lineno);
2257                 }
2258                 
2259                 c= text->curl->line[i];
2260                 while(i< text->curl->len) {
2261                         text->curl->line[i]= text->curl->line[i+1];
2262                         i++;
2263                 }
2264                 text->curl->len--;
2265
2266                 txt_pop_sel(text);
2267         }
2268
2269         txt_make_dirty(text);
2270         txt_clean_text(text);
2271         
2272         if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c);
2273 }
2274
2275 void txt_delete_word (Text *text) 
2276 {
2277         txt_jump_right(text, 1);
2278         txt_delete_sel(text);
2279 }
2280
2281 void txt_backspace_char (Text *text) 
2282 {
2283         char c='\n';
2284         
2285         if (!text) return;
2286         if (!text->curl) return;
2287         
2288         if (txt_has_sel(text)) { /* deleting a selection */
2289                 txt_delete_sel(text);
2290                 txt_make_dirty(text);
2291                 return;
2292         }
2293         else if (text->curc==0) { /* Appending two lines */
2294                 if (!text->curl->prev) return;
2295                 
2296                 text->curl= text->curl->prev;
2297                 text->curc= text->curl->len;
2298                 
2299                 txt_combine_lines(text, text->curl, text->curl->next);
2300                 txt_pop_sel(text);
2301         }
2302         else { /* Just backspacing a char */
2303                 int i= text->curc-1;
2304
2305                 TextMarker *mrk= txt_find_marker_region(text, text->curl, i, text->curl->len, 0, 0);
2306                 if (mrk) {
2307                         int lineno= mrk->lineno;
2308                         if (mrk->start==i+1) {
2309                                 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2310                                         txt_clear_markers(text, mrk->group, TMARK_TEMP);
2311                                 } else {
2312                                         //TextMarker *nxt= mrk->next;
2313                                         BLI_freelinkN(&text->markers, mrk);
2314                                 }
2315                                 return;
2316                         }
2317                         do {
2318                                 if (mrk->start>i) mrk->start--;
2319                                 mrk->end--;
2320                                 mrk= mrk->next;
2321                         } while (mrk && mrk->lineno==lineno);
2322                 }
2323                 
2324                 c= text->curl->line[i];
2325                 while(i< text->curl->len) {
2326                         text->curl->line[i]= text->curl->line[i+1];
2327                         i++;
2328                 }
2329                 text->curl->len--;
2330                 text->curc--;
2331
2332                 txt_pop_sel(text);
2333         }
2334
2335         txt_make_dirty(text);
2336         txt_clean_text(text);
2337         
2338         if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
2339 }
2340
2341 void txt_backspace_word (Text *text) 
2342 {
2343         txt_jump_left(text, 1);
2344         txt_delete_sel(text);
2345 }
2346
2347 int txt_add_char (Text *text, char add) 
2348 {
2349         int len, lineno;
2350         char *tmp;
2351         TextMarker *mrk;
2352         
2353         if (!text) return 0;
2354         if (!text->curl) return 0;
2355
2356         if (add=='\n') {
2357                 txt_split_curline(text);
2358                 return 1;
2359         }
2360         
2361         txt_delete_sel(text);
2362         
2363         mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0);
2364         if (mrk) {
2365                 lineno= mrk->lineno;
2366                 do {
2367                         if (mrk->start>text->curc) mrk->start++;
2368                         mrk->end++;
2369                         mrk= mrk->next;
2370                 } while (mrk && mrk->lineno==lineno);
2371         }
2372         
2373         tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2374         
2375         if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2376         tmp[text->curc]= add;
2377         
2378         len= text->curl->len - text->curc;
2379         if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2380         tmp[text->curl->len+1]=0;
2381         make_new_line(text->curl, tmp);
2382                 
2383         text->curc++;
2384
2385         txt_pop_sel(text);
2386         
2387         txt_make_dirty(text);
2388         txt_clean_text(text);
2389
2390         if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add);
2391         return 1;
2392 }
2393
2394 int txt_replace_char (Text *text, char add)
2395 {
2396         char del;
2397         
2398         if (!text) return 0;
2399         if (!text->curl) return 0;
2400
2401         /* If text is selected or we're at the end of the line just use txt_add_char */
2402         if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') {
2403                 TextMarker *mrk;
2404                 int i= txt_add_char(text, add);
2405                 mrk= txt_find_marker(text, text->curl, text->curc, 0, 0);
2406                 if (mrk && mrk->end==text->curc) mrk->end--;
2407                 return i;
2408         }
2409         
2410         del= text->curl->line[text->curc];
2411         text->curl->line[text->curc]= (unsigned char) add;
2412         text->curc++;
2413         txt_pop_sel(text);
2414         
2415         txt_make_dirty(text);
2416         txt_clean_text(text);
2417
2418         /* Should probably create a new op for this */
2419         if(!undoing) {
2420                 txt_undo_add_charop(text, UNDO_DEL, del);
2421                 txt_undo_add_charop(text, UNDO_INSERT, add);
2422         }
2423         return 1;
2424 }
2425
2426 void indent(Text *text)
2427 {
2428         int len, num;
2429         char *tmp;
2430         char add = '\t';
2431         
2432         if (!text) return;
2433         if (!text->curl) return;
2434         if (!text->sell) return;
2435
2436         num = 0;
2437         while (TRUE)
2438         {
2439                 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2440                 
2441                 text->curc = 0; 
2442                 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2443                 tmp[text->curc]= add;
2444                 
2445                 len= text->curl->len - text->curc;
2446                 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2447                 tmp[text->curl->len+1]=0;
2448
2449                 make_new_line(text->curl, tmp);
2450                         
2451                 text->curc++;
2452                 
2453                 txt_make_dirty(text);
2454                 txt_clean_text(text);
2455                 
2456                 if(text->curl == text->sell) 
2457                 {
2458                         text->selc = text->sell->len;
2459                         break;
2460                 } else {
2461                         text->curl = text->curl->next;
2462                         num++;
2463                 }
2464         }
2465         text->curc = 0;
2466         while( num > 0 )
2467         {
2468                 text->curl = text->curl->prev;
2469                 num--;
2470         }
2471         
2472         if(!undoing) 
2473         {
2474                 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);
2475         }
2476 }
2477
2478 void unindent(Text *text)
2479 {
2480         int num = 0;
2481         char remove = '\t';
2482         
2483         if (!text) return;
2484         if (!text->curl) return;
2485         if (!text->sell) return;
2486
2487         while(TRUE)
2488         {
2489                 int i = 0;
2490                 
2491                 if (text->curl->line[i] == remove)
2492                 {
2493                         while(i< text->curl->len) {
2494                                 text->curl->line[i]= text->curl->line[i+1];
2495                                 i++;
2496                         }
2497                         text->curl->len--;
2498                 }
2499                          
2500         
2501                 txt_make_dirty(text);
2502                 txt_clean_text(text);
2503                 
2504                 if(text->curl == text->sell) 
2505                 {
2506                         text->selc = text->sell->len;
2507                         break;
2508                 } else {
2509                         text->curl = text->curl->next;
2510                         num++;
2511                 }
2512                 
2513         }
2514         text->curc = 0;
2515         while( num > 0 )
2516         {
2517                 text->curl = text->curl->prev;
2518                 num--;
2519         }
2520         
2521         if(!undoing) 
2522         {
2523                 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);
2524         }
2525 }
2526
2527 void comment(Text *text)
2528 {
2529         int len, num;
2530         char *tmp;
2531         char add = '#';
2532         
2533         if (!text) return;
2534         if (!text->curl) return;
2535         if (!text->sell) return;// Need to change this need to check if only one line is selected ot more then one
2536
2537         num = 0;
2538         while (TRUE)
2539         {
2540                 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2541                 
2542                 text->curc = 0; 
2543                 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2544                 tmp[text->curc]= add;
2545                 
2546                 len= text->curl->len - text->curc;
2547                 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2548                 tmp[text->curl->len+1]=0;
2549
2550                 make_new_line(text->curl, tmp);
2551                         
2552                 text->curc++;
2553                 
2554                 txt_make_dirty(text);
2555                 txt_clean_text(text);
2556                 
2557                 if(text->curl == text->sell) 
2558                 {
2559                         text->selc = text->sell->len;
2560                         break;
2561                 } else {
2562                         text->curl = text->curl->next;
2563                         num++;
2564                 }
2565         }
2566         text->curc = 0;
2567         while( num > 0 )
2568         {
2569                 text->curl = text->curl->prev;
2570                 num--;
2571         }
2572         
2573         if(!undoing) 
2574         {
2575                 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);
2576         }
2577 }
2578
2579 void uncomment(Text *text)
2580 {
2581         int num = 0;
2582         char remove = '#';
2583         
2584         if (!text) return;
2585         if (!text->curl) return;
2586         if (!text->sell) return;
2587
2588         while(TRUE)
2589         {
2590                 int i = 0;
2591                 
2592                 if (text->curl->line[i] == remove)
2593                 {
2594                         while(i< text->curl->len) {
2595                                 text->curl->line[i]= text->curl->line[i+1];
2596                                 i++;
2597                         }
2598                         text->curl->len--;
2599                 }
2600                          
2601         
2602                 txt_make_dirty(text);
2603                 txt_clean_text(text);
2604                 
2605                 if(text->curl == text->sell) 
2606                 {
2607                         text->selc = text->sell->len;
2608                         break;
2609                 } else {
2610                         text->curl = text->curl->next;
2611                         num++;
2612                 }
2613                 
2614         }
2615         text->curc = 0;
2616         while( num > 0 )
2617         {
2618                 text->curl = text->curl->prev;
2619                 num--;
2620         }
2621         
2622         if(!undoing) 
2623         {
2624                 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);
2625         }
2626 }
2627
2628 int setcurr_tab (Text *text)
2629 {
2630         int i = 0;
2631         int test = 0;
2632         char *word = ":";
2633         char *comm = "#";
2634         char back_words[4][7] = {"return", "break", "pass", "yield"};
2635         if (!text) return 0;
2636         if (!text->curl) return 0;
2637         
2638         while (text->curl->line[i] == '\t')
2639         {
2640                 //we only count thos tabs that are before any text or before the curs;
2641                 if (i == text->curc)
2642                 {
2643                         return i;
2644                 } else {
2645                         i++;
2646                 }
2647         }
2648         if(strstr(text->curl->line, word))
2649         {
2650                 //if we find a : then add a tab but not if it is in a comment
2651                 int a, indent = 0;
2652                 for(a=0; text->curl->line[a] != '\0'; a++)
2653                 {
2654                         if (text->curl->line[a]=='#') {
2655                                 break;
2656                         } else if (text->curl->line[a]==':') {
2657                                 indent = 1;
2658                         } else if (text->curl->line[a]==']') {
2659                                 indent = 0;
2660                         }
2661                 }
2662                 if (indent) {
2663                         i++;
2664                 }
2665         }
2666
2667         for(test=0; test < 4; test++)
2668         {
2669                 //if there are these 4 key words then remove a tab because we are done with the block
2670                 if(strstr(text->curl->line, back_words[test]) && i > 0)
2671                 {
2672                         if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
2673                         {
2674                                 i--;
2675                         }
2676                 }
2677         }
2678         return i;
2679 }
2680
2681 /*********************************/
2682 /* Text marker utility functions */
2683 /*********************************/
2684
2685 static int color_match(TextMarker *a, TextMarker *b) {
2686         return (a->color[0]==b->color[0] &&
2687                         a->color[1]==b->color[1] &&
2688                         a->color[2]==b->color[2] &&
2689                         a->color[3]==b->color[3]);
2690 }
2691
2692 /* Creates and adds a marker to the list maintaining sorted order */
2693 void txt_add_marker(Text *text, TextLine *line, int start, int end, char color[4], int group, int flags) {
2694         TextMarker *tmp, *marker;
2695
2696         marker= MEM_mallocN(sizeof(TextMarker), "text_marker");
2697         
2698         marker->lineno= txt_get_span(text->lines.first, line);
2699         marker->start= MIN2(start, end);
2700         marker->end= MAX2(start, end);
2701         marker->group= group;
2702         marker->flags= flags;
2703
2704         marker->color[0]= color[0];
2705         marker->color[1]= color[1];
2706         marker->color[2]= color[2];
2707         marker->color[3]= color[3];
2708
2709         for (tmp=text->markers.last; tmp; tmp=tmp->prev)
2710                 if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start))
2711                         break;
2712
2713         if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker);
2714         else BLI_addhead(&text->markers, marker);
2715 }
2716
2717 /* Returns the first matching marker on the specified line between two points.
2718    If the group or flags fields are non-zero the returned flag must be in the
2719    specified group and have at least the specified flags set. */
2720 TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2721         TextMarker *marker, *next;
2722         int lineno= txt_get_span(text->lines.first, line);
2723         
2724         for (marker=text->markers.first; marker; marker=next) {
2725                 next= marker->next;
2726
2727                 if (group && marker->group != group) continue;
2728                 else if ((marker->flags & flags) != flags) continue;
2729                 else if (marker->lineno < lineno) continue;
2730                 else if (marker->lineno > lineno) break;
2731
2732                 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2733                                 (marker->start<end && marker->end>start))
2734                         return marker;
2735         }
2736         return NULL;
2737 }
2738
2739 /* Clears all markers on the specified line between two points. If the group or
2740    flags fields are non-zero the returned flag must be in the specified group
2741    and have at least the specified flags set. */
2742 short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2743         TextMarker *marker, *next;
2744         int lineno= txt_get_span(text->lines.first, line);
2745         short cleared= 0;
2746         
2747         for (marker=text->markers.first; marker; marker=next) {
2748                 next= marker->next;
2749
2750                 if (group && marker->group != group) continue;
2751                 else if ((marker->flags & flags) != flags) continue;
2752                 else if (marker->lineno < lineno) continue;
2753                 else if (marker->lineno > lineno) break;
2754
2755                 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2756                         (marker->start<end && marker->end>start)) {
2757                         BLI_freelinkN(&text->markers, marker);
2758                         cleared= 1;
2759                 }
2760         }
2761         return cleared;
2762 }
2763
2764 /* Clears all markers in the specified group (if given) with at least the
2765    specified flags set. Useful for clearing temporary markers (group=0,
2766    flags=TMARK_TEMP) */
2767 short txt_clear_markers(Text *text, int group, int flags) {
2768         TextMarker *marker, *next;
2769         short cleared= 0;
2770         
2771         for (marker=text->markers.first; marker; marker=next) {
2772                 next= marker->next;
2773
2774                 if ((!group || marker->group==group) &&
2775                                 (marker->flags & flags) == flags) {
2776                         BLI_freelinkN(&text->markers, marker);
2777                         cleared= 1;
2778                 }
2779         }
2780         return cleared;
2781 }
2782
2783 /* Finds the marker at the specified line and cursor position with at least the
2784    specified flags set in the given group (if non-zero). */
2785 TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags) {
2786         TextMarker *marker;
2787         int lineno= txt_get_span(text->lines.first, line);
2788         
2789         for (marker=text->markers.first; marker; marker=marker->next) {
2790                 if (group && marker->group != group) continue;
2791                 else if ((marker->flags & flags) != flags) continue;
2792                 else if (marker->lineno < lineno) continue;
2793                 else if (marker->lineno > lineno) break;
2794
2795                 if (marker->start <= curs && curs <= marker->end)
2796                         return marker;
2797         }
2798         return NULL;
2799 }
2800
2801 /* Finds the previous marker in the same group. If no other is found, the same
2802    marker will be returned */
2803 TextMarker *txt_prev_marker(Text *text, TextMarker *marker) {
2804         TextMarker *tmp= marker;
2805         while (tmp) {
2806                 if (tmp->prev) tmp= tmp->prev;
2807                 else tmp= text->markers.last;
2808                 if (tmp->group == marker->group)
2809                         return tmp;
2810         }
2811         return NULL; /* Only if marker==NULL */
2812 }
2813
2814 /* Finds the next marker in the same group. If no other is found, the same
2815    marker will be returned */
2816 TextMarker *txt_next_marker(Text *text, TextMarker *marker) {
2817         TextMarker *tmp= marker;
2818         while (tmp) {
2819                 if (tmp->next) tmp= tmp->next;
2820                 else tmp= text->markers.first;
2821                 if (tmp->group == marker->group)
2822                         return tmp;
2823         }
2824         return NULL; /* Only if marker==NULL */
2825 }