Cleaned up unused variables and functions.
[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                                         BLI_freelinkN(&text->markers, mrk);
2248                                 }
2249                                 return;
2250                         }
2251                         do {
2252                                 if (mrk->start>i) mrk->start--;
2253                                 mrk->end--;
2254                                 mrk= mrk->next;
2255                         } while (mrk && mrk->lineno==lineno);
2256                 }
2257                 
2258                 c= text->curl->line[i];
2259                 while(i< text->curl->len) {
2260                         text->curl->line[i]= text->curl->line[i+1];
2261                         i++;
2262                 }
2263                 text->curl->len--;
2264
2265                 txt_pop_sel(text);
2266         }
2267
2268         txt_make_dirty(text);
2269         txt_clean_text(text);
2270         
2271         if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c);
2272 }
2273
2274 void txt_delete_word (Text *text) 
2275 {
2276         txt_jump_right(text, 1);
2277         txt_delete_sel(text);
2278 }
2279
2280 void txt_backspace_char (Text *text) 
2281 {
2282         char c='\n';
2283         
2284         if (!text) return;
2285         if (!text->curl) return;
2286         
2287         if (txt_has_sel(text)) { /* deleting a selection */
2288                 txt_delete_sel(text);
2289                 txt_make_dirty(text);
2290                 return;
2291         }
2292         else if (text->curc==0) { /* Appending two lines */
2293                 if (!text->curl->prev) return;
2294                 
2295                 text->curl= text->curl->prev;
2296                 text->curc= text->curl->len;
2297                 
2298                 txt_combine_lines(text, text->curl, text->curl->next);
2299                 txt_pop_sel(text);
2300         }
2301         else { /* Just backspacing a char */
2302                 int i= text->curc-1;
2303
2304                 TextMarker *mrk= txt_find_marker_region(text, text->curl, i, text->curl->len, 0, 0);
2305                 if (mrk) {
2306                         int lineno= mrk->lineno;
2307                         if (mrk->start==i+1) {
2308                                 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2309                                         txt_clear_markers(text, mrk->group, TMARK_TEMP);
2310                                 } else {
2311                                         BLI_freelinkN(&text->markers, mrk);
2312                                 }
2313                                 return;
2314                         }
2315                         do {
2316                                 if (mrk->start>i) mrk->start--;
2317                                 mrk->end--;
2318                                 mrk= mrk->next;
2319                         } while (mrk && mrk->lineno==lineno);
2320                 }
2321                 
2322                 c= text->curl->line[i];
2323                 while(i< text->curl->len) {
2324                         text->curl->line[i]= text->curl->line[i+1];
2325                         i++;
2326                 }
2327                 text->curl->len--;
2328                 text->curc--;
2329
2330                 txt_pop_sel(text);
2331         }
2332
2333         txt_make_dirty(text);
2334         txt_clean_text(text);
2335         
2336         if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
2337 }
2338
2339 void txt_backspace_word (Text *text) 
2340 {
2341         txt_jump_left(text, 1);
2342         txt_delete_sel(text);
2343 }
2344
2345 int txt_add_char (Text *text, char add) 
2346 {
2347         int len, lineno;
2348         char *tmp;
2349         TextMarker *mrk;
2350         
2351         if (!text) return 0;
2352         if (!text->curl) return 0;
2353
2354         if (add=='\n') {
2355                 txt_split_curline(text);
2356                 return 1;
2357         }
2358         
2359         txt_delete_sel(text);
2360         
2361         mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0);
2362         if (mrk) {
2363                 lineno= mrk->lineno;
2364                 do {
2365                         if (mrk->start>text->curc) mrk->start++;
2366                         mrk->end++;
2367                         mrk= mrk->next;
2368                 } while (mrk && mrk->lineno==lineno);
2369         }
2370         
2371         tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2372         
2373         if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2374         tmp[text->curc]= add;
2375         
2376         len= text->curl->len - text->curc;
2377         if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2378         tmp[text->curl->len+1]=0;
2379         make_new_line(text->curl, tmp);
2380                 
2381         text->curc++;
2382
2383         txt_pop_sel(text);
2384         
2385         txt_make_dirty(text);
2386         txt_clean_text(text);
2387
2388         if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add);
2389         return 1;
2390 }
2391
2392 int txt_replace_char (Text *text, char add)
2393 {
2394         char del;
2395         
2396         if (!text) return 0;
2397         if (!text->curl) return 0;
2398
2399         /* If text is selected or we're at the end of the line just use txt_add_char */
2400         if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') {
2401                 TextMarker *mrk;
2402                 int i= txt_add_char(text, add);
2403                 mrk= txt_find_marker(text, text->curl, text->curc, 0, 0);
2404                 if (mrk && mrk->end==text->curc) mrk->end--;
2405                 return i;
2406         }
2407         
2408         del= text->curl->line[text->curc];
2409         text->curl->line[text->curc]= (unsigned char) add;
2410         text->curc++;
2411         txt_pop_sel(text);
2412         
2413         txt_make_dirty(text);
2414         txt_clean_text(text);
2415
2416         /* Should probably create a new op for this */
2417         if(!undoing) {
2418                 txt_undo_add_charop(text, UNDO_DEL, del);
2419                 txt_undo_add_charop(text, UNDO_INSERT, add);
2420         }
2421         return 1;
2422 }
2423
2424 void indent(Text *text)
2425 {
2426         int len, num;
2427         char *tmp;
2428         char add = '\t';
2429         
2430         if (!text) return;
2431         if (!text->curl) return;
2432         if (!text->sell) return;
2433
2434         num = 0;
2435         while (TRUE)
2436         {
2437                 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2438                 
2439                 text->curc = 0; 
2440                 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2441                 tmp[text->curc]= add;
2442                 
2443                 len= text->curl->len - text->curc;
2444                 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2445                 tmp[text->curl->len+1]=0;
2446
2447                 make_new_line(text->curl, tmp);
2448                         
2449                 text->curc++;
2450                 
2451                 txt_make_dirty(text);
2452                 txt_clean_text(text);
2453                 
2454                 if(text->curl == text->sell) 
2455                 {
2456                         text->selc = text->sell->len;
2457                         break;
2458                 } else {
2459                         text->curl = text->curl->next;
2460                         num++;
2461                 }
2462         }
2463         text->curc = 0;
2464         while( num > 0 )
2465         {
2466                 text->curl = text->curl->prev;
2467                 num--;
2468         }
2469         
2470         if(!undoing) 
2471         {
2472                 txt_undo_add_toop(text, UNDO_INDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2473         }
2474 }
2475
2476 void unindent(Text *text)
2477 {
2478         int num = 0;
2479         char remove = '\t';
2480         
2481         if (!text) return;
2482         if (!text->curl) return;
2483         if (!text->sell) return;
2484
2485         while(TRUE)
2486         {
2487                 int i = 0;
2488                 
2489                 if (text->curl->line[i] == remove)
2490                 {
2491                         while(i< text->curl->len) {
2492                                 text->curl->line[i]= text->curl->line[i+1];
2493                                 i++;
2494                         }
2495                         text->curl->len--;
2496                 }
2497                          
2498         
2499                 txt_make_dirty(text);
2500                 txt_clean_text(text);
2501                 
2502                 if(text->curl == text->sell) 
2503                 {
2504                         text->selc = text->sell->len;
2505                         break;
2506                 } else {
2507                         text->curl = text->curl->next;
2508                         num++;
2509                 }
2510                 
2511         }
2512         text->curc = 0;
2513         while( num > 0 )
2514         {
2515                 text->curl = text->curl->prev;
2516                 num--;
2517         }
2518         
2519         if(!undoing) 
2520         {
2521                 txt_undo_add_toop(text, UNDO_UNINDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2522         }
2523 }
2524
2525 void comment(Text *text)
2526 {
2527         int len, num;
2528         char *tmp;
2529         char add = '#';
2530         
2531         if (!text) return;
2532         if (!text->curl) return;
2533         if (!text->sell) return;// Need to change this need to check if only one line is selected ot more then one
2534
2535         num = 0;
2536         while (TRUE)
2537         {
2538                 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2539                 
2540                 text->curc = 0; 
2541                 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2542                 tmp[text->curc]= add;
2543                 
2544                 len= text->curl->len - text->curc;
2545                 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2546                 tmp[text->curl->len+1]=0;
2547
2548                 make_new_line(text->curl, tmp);
2549                         
2550                 text->curc++;
2551                 
2552                 txt_make_dirty(text);
2553                 txt_clean_text(text);
2554                 
2555                 if(text->curl == text->sell) 
2556                 {
2557                         text->selc = text->sell->len;
2558                         break;
2559                 } else {
2560                         text->curl = text->curl->next;
2561                         num++;
2562                 }
2563         }
2564         text->curc = 0;
2565         while( num > 0 )
2566         {
2567                 text->curl = text->curl->prev;
2568                 num--;
2569         }
2570         
2571         if(!undoing) 
2572         {
2573                 txt_undo_add_toop(text, UNDO_COMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2574         }
2575 }
2576
2577 void uncomment(Text *text)
2578 {
2579         int num = 0;
2580         char remove = '#';
2581         
2582         if (!text) return;
2583         if (!text->curl) return;
2584         if (!text->sell) return;
2585
2586         while(TRUE)
2587         {
2588                 int i = 0;
2589                 
2590                 if (text->curl->line[i] == remove)
2591                 {
2592                         while(i< text->curl->len) {
2593                                 text->curl->line[i]= text->curl->line[i+1];
2594                                 i++;
2595                         }
2596                         text->curl->len--;
2597                 }
2598                          
2599         
2600                 txt_make_dirty(text);
2601                 txt_clean_text(text);
2602                 
2603                 if(text->curl == text->sell) 
2604                 {
2605                         text->selc = text->sell->len;
2606                         break;
2607                 } else {
2608                         text->curl = text->curl->next;
2609                         num++;
2610                 }
2611                 
2612         }
2613         text->curc = 0;
2614         while( num > 0 )
2615         {
2616                 text->curl = text->curl->prev;
2617                 num--;
2618         }
2619         
2620         if(!undoing) 
2621         {
2622                 txt_undo_add_toop(text, UNDO_UNCOMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2623         }
2624 }
2625
2626 int setcurr_tab (Text *text)
2627 {
2628         int i = 0;
2629         int test = 0;
2630         char *word = ":";
2631         char *comm = "#";
2632         char back_words[4][7] = {"return", "break", "pass", "yield"};
2633         if (!text) return 0;
2634         if (!text->curl) return 0;
2635         
2636         while (text->curl->line[i] == '\t')
2637         {
2638                 //we only count thos tabs that are before any text or before the curs;
2639                 if (i == text->curc)
2640                 {
2641                         return i;
2642                 } else {
2643                         i++;
2644                 }
2645         }
2646         if(strstr(text->curl->line, word))
2647         {
2648                 //if we find a : then add a tab but not if it is in a comment
2649                 int a, indent = 0;
2650                 for(a=0; text->curl->line[a] != '\0'; a++)
2651                 {
2652                         if (text->curl->line[a]=='#') {
2653                                 break;
2654                         } else if (text->curl->line[a]==':') {
2655                                 indent = 1;
2656                         } else if (text->curl->line[a]==']') {
2657                                 indent = 0;
2658                         }
2659                 }
2660                 if (indent) {
2661                         i++;
2662                 }
2663         }
2664
2665         for(test=0; test < 4; test++)
2666         {
2667                 //if there are these 4 key words then remove a tab because we are done with the block
2668                 if(strstr(text->curl->line, back_words[test]) && i > 0)
2669                 {
2670                         if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
2671                         {
2672                                 i--;
2673                         }
2674                 }
2675         }
2676         return i;
2677 }
2678
2679 /*********************************/
2680 /* Text marker utility functions */
2681 /*********************************/
2682
2683 /* Creates and adds a marker to the list maintaining sorted order */
2684 void txt_add_marker(Text *text, TextLine *line, int start, int end, char color[4], int group, int flags) {
2685         TextMarker *tmp, *marker;
2686
2687         marker= MEM_mallocN(sizeof(TextMarker), "text_marker");
2688         
2689         marker->lineno= txt_get_span(text->lines.first, line);
2690         marker->start= MIN2(start, end);
2691         marker->end= MAX2(start, end);
2692         marker->group= group;
2693         marker->flags= flags;
2694
2695         marker->color[0]= color[0];
2696         marker->color[1]= color[1];
2697         marker->color[2]= color[2];
2698         marker->color[3]= color[3];
2699
2700         for (tmp=text->markers.last; tmp; tmp=tmp->prev)
2701                 if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start))
2702                         break;
2703
2704         if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker);
2705         else BLI_addhead(&text->markers, marker);
2706 }
2707
2708 /* Returns the first matching marker on the specified line between two points.
2709    If the group or flags fields are non-zero the returned flag must be in the
2710    specified group and have at least the specified flags set. */
2711 TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2712         TextMarker *marker, *next;
2713         int lineno= txt_get_span(text->lines.first, line);
2714         
2715         for (marker=text->markers.first; marker; marker=next) {
2716                 next= marker->next;
2717
2718                 if (group && marker->group != group) continue;
2719                 else if ((marker->flags & flags) != flags) continue;
2720                 else if (marker->lineno < lineno) continue;
2721                 else if (marker->lineno > lineno) break;
2722
2723                 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2724                                 (marker->start<end && marker->end>start))
2725                         return marker;
2726         }
2727         return NULL;
2728 }
2729
2730 /* Clears all markers on the specified line between two points. If the group or
2731    flags fields are non-zero the returned flag must be in the specified group
2732    and have at least the specified flags set. */
2733 short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2734         TextMarker *marker, *next;
2735         int lineno= txt_get_span(text->lines.first, line);
2736         short cleared= 0;
2737         
2738         for (marker=text->markers.first; marker; marker=next) {
2739                 next= marker->next;
2740
2741                 if (group && marker->group != group) continue;
2742                 else if ((marker->flags & flags) != flags) continue;
2743                 else if (marker->lineno < lineno) continue;
2744                 else if (marker->lineno > lineno) break;
2745
2746                 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2747                         (marker->start<end && marker->end>start)) {
2748                         BLI_freelinkN(&text->markers, marker);
2749                         cleared= 1;
2750                 }
2751         }
2752         return cleared;
2753 }
2754
2755 /* Clears all markers in the specified group (if given) with at least the
2756    specified flags set. Useful for clearing temporary markers (group=0,
2757    flags=TMARK_TEMP) */
2758 short txt_clear_markers(Text *text, int group, int flags) {
2759         TextMarker *marker, *next;
2760         short cleared= 0;
2761         
2762         for (marker=text->markers.first; marker; marker=next) {
2763                 next= marker->next;
2764
2765                 if ((!group || marker->group==group) &&
2766                                 (marker->flags & flags) == flags) {
2767                         BLI_freelinkN(&text->markers, marker);
2768                         cleared= 1;
2769                 }
2770         }
2771         return cleared;
2772 }
2773
2774 /* Finds the marker at the specified line and cursor position with at least the
2775    specified flags set in the given group (if non-zero). */
2776 TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags) {
2777         TextMarker *marker;
2778         int lineno= txt_get_span(text->lines.first, line);
2779         
2780         for (marker=text->markers.first; marker; marker=marker->next) {
2781                 if (group && marker->group != group) continue;
2782                 else if ((marker->flags & flags) != flags) continue;
2783                 else if (marker->lineno < lineno) continue;
2784                 else if (marker->lineno > lineno) break;
2785
2786                 if (marker->start <= curs && curs <= marker->end)
2787                         return marker;
2788         }
2789         return NULL;
2790 }
2791
2792 /* Finds the previous marker in the same group. If no other is found, the same
2793    marker will be returned */
2794 TextMarker *txt_prev_marker(Text *text, TextMarker *marker) {
2795         TextMarker *tmp= marker;
2796         while (tmp) {
2797                 if (tmp->prev) tmp= tmp->prev;
2798                 else tmp= text->markers.last;
2799                 if (tmp->group == marker->group)
2800                         return tmp;
2801         }
2802         return NULL; /* Only if marker==NULL */
2803 }
2804
2805 /* Finds the next marker in the same group. If no other is found, the same
2806    marker will be returned */
2807 TextMarker *txt_next_marker(Text *text, TextMarker *marker) {
2808         TextMarker *tmp= marker;
2809         while (tmp) {
2810                 if (tmp->next) tmp= tmp->next;
2811                 else tmp= text->markers.first;
2812                 if (tmp->group == marker->group)
2813                         return tmp;
2814         }
2815         return NULL; /* Only if marker==NULL */
2816 }