Minor tidying and commenting
[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;
581         if (ch <= '/') return 1;
582         if (ch <= '9') return 2;
583         if (ch <= '@') return 1;
584         if (ch <= 'Z') return 2;
585         if (ch <= '`') return 1;
586         if (ch <= 'z') return 2;
587         return 1;
588 }
589
590 /****************************/
591 /* Cursor utility functions */
592 /****************************/
593
594 static void txt_curs_cur (Text *text, TextLine ***linep, int **charp)
595 {
596         *linep= &text->curl; *charp= &text->curc;
597 }
598
599 static void txt_curs_sel (Text *text, TextLine ***linep, int **charp)
600 {
601         *linep= &text->sell; *charp= &text->selc;
602 }
603
604 static void txt_curs_first (Text *text, TextLine **linep, int *charp)
605 {
606         if (text->curl==text->sell) {
607                 *linep= text->curl;
608                 if (text->curc<text->selc) *charp= text->curc;
609                 else *charp= text->selc;
610         } else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) {
611                 *linep= text->curl;
612                 *charp= text->curc;
613         } else {
614                 *linep= text->sell;
615                 *charp= text->selc;             
616         }
617 }
618
619 /****************************/
620 /* Cursor movement functions */
621 /****************************/
622
623 void txt_move_up(Text *text, short sel)
624 {
625         TextLine **linep;
626         int *charp, old;
627         
628         if (!text) return;
629         if(sel) txt_curs_sel(text, &linep, &charp);
630         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
631         if (!*linep) return;
632         old= *charp;
633
634         if((*linep)->prev) {
635                 *linep= (*linep)->prev;
636                 if (*charp > (*linep)->len) {
637                         *charp= (*linep)->len;
638                         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);
639                 } else {
640                         if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
641                 }
642         } else {
643                 txt_move_bol(text, sel);
644         }
645
646         if(!sel) txt_pop_sel(text);
647 }
648
649 void txt_move_down(Text *text, short sel) 
650 {
651         TextLine **linep;
652         int *charp, old;
653         
654         if (!text) return;
655         if(sel) txt_curs_sel(text, &linep, &charp);
656         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
657         if (!*linep) return;
658         old= *charp;
659
660         if((*linep)->next) {
661                 *linep= (*linep)->next;
662                 if (*charp > (*linep)->len) {
663                         *charp= (*linep)->len;
664                         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);
665                 } else
666                         if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);  
667         } else {
668                 txt_move_eol(text, sel);
669         }
670
671         if(!sel) txt_pop_sel(text);
672 }
673
674 void txt_move_left(Text *text, short sel) 
675 {
676         TextLine **linep;
677         int *charp, oundoing= undoing;
678         
679         if (!text) return;
680         if(sel) txt_curs_sel(text, &linep, &charp);
681         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
682         if (!*linep) return;
683
684         undoing= 1;
685         if (*charp== 0) {
686                 if ((*linep)->prev) {
687                         txt_move_up(text, sel);
688                         *charp= (*linep)->len;
689                 }
690         } else {
691                 (*charp)--;
692         }
693         undoing= oundoing;
694         if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
695         
696         if(!sel) txt_pop_sel(text);
697 }
698
699 void txt_move_right(Text *text, short sel) 
700 {
701         TextLine **linep;
702         int *charp, oundoing= undoing;
703         
704         if (!text) return;
705         if(sel) txt_curs_sel(text, &linep, &charp);
706         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
707         if (!*linep) return;
708
709         undoing= 1;
710         if (*charp== (*linep)->len) {
711                 if ((*linep)->next) {
712                         txt_move_down(text, sel);
713                         *charp= 0;
714                 }
715         } else {
716                 (*charp)++;
717         }
718         undoing= oundoing;
719         if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
720
721         if(!sel) txt_pop_sel(text);
722 }
723
724 void txt_jump_left(Text *text, short sel)
725 {
726         TextLine **linep, *oldl;
727         int *charp, oldc, count, i;
728         unsigned char oldu;
729
730         if (!text) return;
731         if(sel) txt_curs_sel(text, &linep, &charp);
732         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
733         if (!*linep) return;
734
735         oldl= *linep;
736         oldc= *charp;
737         oldu= undoing;
738         undoing= 1; /* Don't push individual moves to undo stack */
739
740         count= 0;
741         for (i=0; i<3; i++) {
742                 if (count < 2) {
743                         while (*charp>0 && txt_char_type((*linep)->line[*charp-1])==i) {
744                                 txt_move_left(text, sel);
745                                 count++;
746                         }
747                 }
748         }
749         if (count==0) txt_move_left(text, sel);
750
751         undoing= oldu;
752         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);
753 }
754
755 void txt_jump_right(Text *text, short sel)
756 {
757         TextLine **linep, *oldl;
758         int *charp, oldc, count, i;
759         unsigned char oldu;
760
761         if (!text) return;
762         if(sel) txt_curs_sel(text, &linep, &charp);
763         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
764         if (!*linep) return;
765
766         oldl= *linep;
767         oldc= *charp;
768         oldu= undoing;
769         undoing= 1; /* Don't push individual moves to undo stack */
770
771         count= 0;
772         for (i=0; i<3; i++) {
773                 if (count < 2) {
774                         while (*charp<(*linep)->len && txt_char_type((*linep)->line[*charp])==i) {
775                                 txt_move_right(text, sel);
776                                 count++;
777                         }
778                 }
779         }
780         if (count==0) txt_move_right(text, sel);
781
782         undoing= oldu;
783         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);
784 }
785
786 void txt_move_bol (Text *text, short sel) 
787 {
788         TextLine **linep;
789         int *charp, old;
790         
791         if (!text) return;
792         if(sel) txt_curs_sel(text, &linep, &charp);
793         else txt_curs_cur(text, &linep, &charp);
794         if (!*linep) return;
795         old= *charp;
796         
797         *charp= 0;
798
799         if(!sel) txt_pop_sel(text);
800         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);
801 }
802
803 void txt_move_eol (Text *text, short sel) 
804 {
805         TextLine **linep;
806         int *charp, old;
807         
808         if (!text) return;
809         if(sel) txt_curs_sel(text, &linep, &charp);
810         else txt_curs_cur(text, &linep, &charp);
811         if (!*linep) return;
812         old= *charp;
813                 
814         *charp= (*linep)->len;
815
816         if(!sel) txt_pop_sel(text);
817         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);
818 }
819
820 void txt_move_bof (Text *text, short sel)
821 {
822         TextLine **linep;
823         int *charp, old;
824         
825         if (!text) return;
826         if(sel) txt_curs_sel(text, &linep, &charp);
827         else txt_curs_cur(text, &linep, &charp);
828         if (!*linep) return;
829         old= *charp;
830
831         *linep= text->lines.first;
832         *charp= 0;
833
834         if(!sel) txt_pop_sel(text);
835         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);
836 }
837
838 void txt_move_eof (Text *text, short sel)
839 {
840         TextLine **linep;
841         int *charp, old;
842         
843         if (!text) return;
844         if(sel) txt_curs_sel(text, &linep, &charp);
845         else txt_curs_cur(text, &linep, &charp);
846         if (!*linep) return;
847         old= *charp;
848
849         *linep= text->lines.last;
850         *charp= (*linep)->len;
851
852         if(!sel) txt_pop_sel(text);
853         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);     
854 }
855
856 void txt_move_toline (Text *text, unsigned int line, short sel)
857 {
858         txt_move_to(text, line, 0, sel);
859 }
860
861 void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel)
862 {
863         TextLine **linep, *oldl;
864         int *charp, oldc;
865         unsigned int i;
866         
867         if (!text) return;
868         if(sel) txt_curs_sel(text, &linep, &charp);
869         else txt_curs_cur(text, &linep, &charp);
870         if (!*linep) return;
871         oldc= *charp;
872         oldl= *linep;
873         
874         *linep= text->lines.first;
875         for (i=0; i<line; i++) {
876                 if ((*linep)->next) *linep= (*linep)->next;
877                 else break;
878         }
879         if (ch>(*linep)->len)
880                 ch= (*linep)->len;
881         *charp= ch;
882         
883         if(!sel) txt_pop_sel(text);
884         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);
885 }
886
887 /****************************/
888 /* Text selection functions */
889 /****************************/
890
891 static void txt_curs_swap (Text *text)
892 {
893         TextLine *tmpl;
894         int tmpc;
895                 
896         tmpl= text->curl;
897         text->curl= text->sell;
898         text->sell= tmpl;
899         
900         tmpc= text->curc;
901         text->curc= text->selc;
902         text->selc= tmpc;
903         
904         if(!undoing) txt_undo_add_op(text, UNDO_SWAP);
905 }
906
907 static void txt_pop_first (Text *text)
908 {
909                         
910         if (txt_get_span(text->curl, text->sell)<0 ||
911                 (text->curl==text->sell && text->curc>text->selc)) {    
912                 txt_curs_swap(text);
913         }
914
915         if(!undoing) txt_undo_add_toop(text, UNDO_STO,
916                 txt_get_span(text->lines.first, text->sell), 
917                 text->selc, 
918                 txt_get_span(text->lines.first, text->curl), 
919                 text->curc);            
920         
921         txt_pop_sel(text);
922 }
923
924 static void txt_pop_last (Text *text)
925 {
926         if (txt_get_span(text->curl, text->sell)>0 ||
927                 (text->curl==text->sell && text->curc<text->selc)) {
928                 txt_curs_swap(text);
929         }
930
931         if(!undoing) txt_undo_add_toop(text, UNDO_STO,
932                 txt_get_span(text->lines.first, text->sell), 
933                 text->selc, 
934                 txt_get_span(text->lines.first, text->curl), 
935                 text->curc);            
936         
937         txt_pop_sel(text);
938 }
939
940 /* never used: CVS 1.19 */
941 /*  static void txt_pop_selr (Text *text) */
942
943 void txt_pop_sel (Text *text)
944 {
945         text->sell= text->curl;
946         text->selc= text->curc; 
947 }
948
949 void txt_order_cursors(Text *text)
950 {
951         if (!text) return;
952         if (!text->curl) return;
953         if (!text->sell) return;
954         
955                 /* Flip so text->curl is before text->sell */
956         if (txt_get_span(text->curl, text->sell)<0 ||
957                         (text->curl==text->sell && text->curc>text->selc))
958                 txt_curs_swap(text);
959 }
960
961 int txt_has_sel(Text *text)
962 {
963         return ((text->curl!=text->sell) || (text->curc!=text->selc));
964 }
965
966 static void txt_delete_sel (Text *text)
967 {
968         TextLine *tmpl;
969         TextMarker *mrk;
970         char *buf;
971         int move, lineno;
972         
973         if (!text) return;
974         if (!text->curl) return;
975         if (!text->sell) return;
976
977         if (!txt_has_sel(text)) return;
978         
979         txt_order_cursors(text);
980
981         if(!undoing) {
982                 buf= txt_sel_to_buf(text);
983                 txt_undo_add_block(text, UNDO_DBLOCK, buf);
984                 MEM_freeN(buf);
985         }
986
987         buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
988         
989         if (text->curl != text->sell) {
990                 txt_clear_marker_region(text, text->curl, text->curc, text->curl->len, 0, 0);
991                 move= txt_get_span(text->curl, text->sell);
992         } else {
993                 mrk= txt_find_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
994                 if (mrk && (mrk->start > text->curc || mrk->end < text->selc))
995                         txt_clear_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
996                 move= 0;
997         }
998
999         mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0);
1000         if (mrk) {
1001                 lineno= mrk->lineno;
1002                 do {
1003                         mrk->lineno -= move;
1004                         if (mrk->start > text->curc) mrk->start -= text->selc - text->curc;
1005                         mrk->end -= text->selc - text->curc;
1006                         mrk= mrk->next;
1007                 } while (mrk && mrk->lineno==lineno);
1008         }
1009
1010         strncpy(buf, text->curl->line, text->curc);
1011         strcpy(buf+text->curc, text->sell->line + text->selc);
1012         buf[text->curc+(text->sell->len - text->selc)]=0;
1013
1014         make_new_line(text->curl, buf);
1015         
1016         tmpl= text->sell;
1017         while (tmpl != text->curl) {
1018                 tmpl= tmpl->prev;
1019                 if (!tmpl) break;
1020                 
1021                 txt_delete_line(text, tmpl->next);
1022         }
1023         
1024         text->sell= text->curl;
1025         text->selc= text->curc;
1026 }
1027
1028 void txt_sel_all (Text *text)
1029 {
1030         if (!text) return;
1031
1032         text->curl= text->lines.first;
1033         text->curc= 0;
1034         
1035         text->sell= text->lines.last;
1036         text->selc= text->sell->len;
1037 }
1038
1039 void txt_sel_line (Text *text)
1040 {
1041         if (!text) return;
1042         if (!text->curl) return;
1043         
1044         text->curc= 0;
1045         text->sell= text->curl;
1046         text->selc= text->sell->len;
1047 }
1048
1049 /***************************/
1050 /* Cut and paste functions */
1051 /***************************/
1052
1053 void txt_print_cutbuffer (void) 
1054 {
1055         printf ("Cut buffer\n--\n%s\n--\n", txt_cut_buffer);    
1056 }
1057
1058 char *txt_to_buf (Text *text)
1059 {
1060         int length;
1061         TextLine *tmp, *linef, *linel;
1062         int charf, charl;
1063         char *buf;
1064         
1065         if (!text) return NULL;
1066         if (!text->curl) return NULL;
1067         if (!text->sell) return NULL;
1068         if (!text->lines.first) return NULL;
1069
1070         linef= text->lines.first;
1071         charf= 0;
1072                 
1073         linel= text->lines.last;
1074         charl= linel->len;
1075
1076         if (linef == text->lines.last) {
1077                 length= charl-charf;
1078
1079                 buf= MEM_mallocN(length+2, "text buffer");
1080                 
1081                 BLI_strncpy(buf, linef->line + charf, length+1);
1082                 buf[length]=0;
1083         } else {
1084                 length= linef->len - charf;
1085                 length+= charl;
1086                 length+= 2; /* For the 2 '\n' */
1087                 
1088                 tmp= linef->next;
1089                 while (tmp && tmp!= linel) {
1090                         length+= tmp->len+1;
1091                         tmp= tmp->next;
1092                 }
1093                 
1094                 buf= MEM_mallocN(length+1, "cut buffer");
1095
1096                 strncpy(buf, linef->line + charf, linef->len-charf);
1097                 length= linef->len - charf;
1098                 
1099                 buf[length++]='\n';
1100                 
1101                 tmp= linef->next;
1102                 while (tmp && tmp!=linel) {
1103                         strncpy(buf+length, tmp->line, tmp->len);
1104                         length+= tmp->len;
1105                         
1106                         buf[length++]='\n';                     
1107                         
1108                         tmp= tmp->next;
1109                 }
1110                 strncpy(buf+length, linel->line, charl);
1111                 length+= charl;
1112                 
1113                 /* python compiler wants an empty end line */
1114                 buf[length++]='\n';                     
1115                 buf[length]=0;
1116         }
1117         
1118         return buf;
1119 }
1120
1121 int txt_find_string(Text *text, char *findstr, int wrap)
1122 {
1123         TextLine *tl, *startl;
1124         char *s= NULL;
1125         int oldcl, oldsl, oldcc, oldsc;
1126
1127         if (!text || !text->curl || !text->sell) return 0;
1128         
1129         txt_order_cursors(text);
1130
1131         oldcl= txt_get_span(text->lines.first, text->curl);
1132         oldsl= txt_get_span(text->lines.first, text->sell);
1133         tl= startl= text->sell;
1134         oldcc= text->curc;
1135         oldsc= text->selc;
1136         
1137         s= strstr(&tl->line[text->selc], findstr);
1138         while (!s) {
1139                 tl= tl->next;
1140                 if (!tl) {
1141                         if (wrap)
1142                                 tl= text->lines.first;
1143                         else
1144                                 break;
1145                 }
1146
1147                 s= strstr(tl->line, findstr);
1148                 if (tl==startl)
1149                         break;
1150         }
1151         
1152         if (s) {
1153                 int newl= txt_get_span(text->lines.first, tl);
1154                 int newc= (int)(s-tl->line);
1155                 txt_move_to(text, newl, newc, 0);
1156                 txt_move_to(text, newl, newc + strlen(findstr), 1);
1157                 return 1;                               
1158         } else
1159                 return 0;
1160 }
1161
1162 void txt_cut_sel (Text *text)
1163 {
1164         if (!G.background) /* Python uses txt_cut_sel, which it should not, working around for now  */
1165                 txt_copy_clipboard(text);
1166         
1167         txt_delete_sel(text);
1168         txt_make_dirty(text);
1169 }
1170
1171 char *txt_sel_to_buf (Text *text)
1172 {
1173         char *buf;
1174         int length=0;
1175         TextLine *tmp, *linef, *linel;
1176         int charf, charl;
1177         
1178         if (!text) return NULL;
1179         if (!text->curl) return NULL;
1180         if (!text->sell) return NULL;
1181         
1182         if (text->curl==text->sell) {
1183                 linef= linel= text->curl;
1184                 
1185                 if (text->curc < text->selc) {
1186                         charf= text->curc;
1187                         charl= text->selc;
1188                 } else{
1189                         charf= text->selc;
1190                         charl= text->curc;
1191                 }
1192         } else if (txt_get_span(text->curl, text->sell)<0) {
1193                 linef= text->sell;
1194                 linel= text->curl;
1195
1196                 charf= text->selc;              
1197                 charl= text->curc;
1198         } else {
1199                 linef= text->curl;
1200                 linel= text->sell;
1201                 
1202                 charf= text->curc;
1203                 charl= text->selc;
1204         }
1205
1206         if (linef == linel) {
1207                 length= charl-charf;
1208
1209                 buf= MEM_mallocN(length+1, "sel buffer");
1210                 
1211                 BLI_strncpy(buf, linef->line + charf, length+1);
1212         } else {
1213                 length+= linef->len - charf;
1214                 length+= charl;
1215                 length++; /* For the '\n' */
1216                 
1217                 tmp= linef->next;
1218                 while (tmp && tmp!= linel) {
1219                         length+= tmp->len+1;
1220                         tmp= tmp->next;
1221                 }
1222                 
1223                 buf= MEM_mallocN(length+1, "sel buffer");
1224                 
1225                 strncpy(buf, linef->line+ charf, linef->len-charf);
1226                 length= linef->len-charf;
1227                 
1228                 buf[length++]='\n';
1229                 
1230                 tmp= linef->next;
1231                 while (tmp && tmp!=linel) {
1232                         strncpy(buf+length, tmp->line, tmp->len);
1233                         length+= tmp->len;
1234                         
1235                         buf[length++]='\n';                     
1236                         
1237                         tmp= tmp->next;
1238                 }
1239                 strncpy(buf+length, linel->line, charl);
1240                 length+= charl;
1241                 
1242                 buf[length]=0;
1243         }       
1244
1245         return buf;
1246 }
1247
1248 void txt_copy_sel (Text *text)
1249 {
1250         int length=0;
1251         TextLine *tmp, *linef, *linel;
1252         int charf, charl;
1253         
1254         if (!text) return;
1255         if (!text->curl) return;
1256         if (!text->sell) return;
1257
1258         if (!txt_has_sel(text)) return;
1259         
1260         if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
1261         txt_cut_buffer= NULL;
1262         
1263         if (text->curl==text->sell) {
1264                 linef= linel= text->curl;
1265                 
1266                 if (text->curc < text->selc) {
1267                         charf= text->curc;
1268                         charl= text->selc;
1269                 } else{
1270                         charf= text->selc;
1271                         charl= text->curc;
1272                 }
1273         } else if (txt_get_span(text->curl, text->sell)<0) {
1274                 linef= text->sell;
1275                 linel= text->curl;
1276
1277                 charf= text->selc;              
1278                 charl= text->curc;
1279         } else {
1280                 linef= text->curl;
1281                 linel= text->sell;
1282                 
1283                 charf= text->curc;
1284                 charl= text->selc;
1285         }
1286
1287         if (linef == linel) {
1288                 length= charl-charf;
1289
1290                 txt_cut_buffer= MEM_mallocN(length+1, "cut buffera");
1291                 
1292                 BLI_strncpy(txt_cut_buffer, linef->line + charf, length+1);
1293         } else {
1294                 length+= linef->len - charf;
1295                 length+= charl;
1296                 length++; /* For the '\n' */
1297                 
1298                 tmp= linef->next;
1299                 while (tmp && tmp!= linel) {
1300                         length+= tmp->len+1;
1301                         tmp= tmp->next;
1302                 }
1303                 
1304                 txt_cut_buffer= MEM_mallocN(length+1, "cut bufferb");
1305                 
1306                 strncpy(txt_cut_buffer, linef->line+ charf, linef->len-charf);
1307                 length= linef->len-charf;
1308                 
1309                 txt_cut_buffer[length++]='\n';
1310                 
1311                 tmp= linef->next;
1312                 while (tmp && tmp!=linel) {
1313                         strncpy(txt_cut_buffer+length, tmp->line, tmp->len);
1314                         length+= tmp->len;
1315                         
1316                         txt_cut_buffer[length++]='\n';                  
1317                         
1318                         tmp= tmp->next;
1319                 }
1320                 strncpy(txt_cut_buffer+length, linel->line, charl);
1321                 length+= charl;
1322                 
1323                 txt_cut_buffer[length]=0;
1324         }
1325 }
1326
1327 void txt_insert_buf(Text *text, char *in_buffer)
1328 {
1329         int i=0, l=0, j, u, len;
1330         TextLine *add;
1331
1332         if (!text) return;
1333         if (!in_buffer) return;
1334
1335         txt_delete_sel(text);
1336         
1337         if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer);         
1338
1339         u= undoing;
1340         undoing= 1;
1341
1342         /* Read the first line (or as close as possible */
1343         while (in_buffer[i] && in_buffer[i]!='\n') {
1344                 txt_add_char(text, in_buffer[i]);
1345                 i++;
1346         }
1347         
1348         if (in_buffer[i]=='\n') txt_split_curline(text);
1349         else { undoing = u; return; }
1350         i++;
1351
1352         /* Read as many full lines as we can */
1353         len= strlen(in_buffer);
1354
1355         while (i<len) {
1356                 l=0;
1357
1358                 while (in_buffer[i] && in_buffer[i]!='\n') {
1359                         i++; l++;
1360                 }
1361         
1362                 if(in_buffer[i]=='\n') {
1363                         add= txt_new_linen(in_buffer +(i-l), l);
1364                         BLI_insertlinkbefore(&text->lines, text->curl, add);
1365                         i++;
1366                 } else {
1367                         for (j= i-l; j<i && j<(int)strlen(in_buffer); j++) {
1368                                 txt_add_char(text, in_buffer[j]);
1369                         }
1370                         break;
1371                 }
1372         }
1373         
1374         undoing= u;
1375 }
1376
1377 void txt_free_cut_buffer(void) 
1378 {
1379         if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
1380 }
1381
1382 void txt_paste(Text *text)
1383 {
1384         txt_insert_buf(text, txt_cut_buffer);
1385 }
1386
1387 /******************/
1388 /* Undo functions */
1389 /******************/
1390
1391 #define MAX_UNDO_TEST(x) \
1392         while (text->undo_pos+x >= text->undo_len) { \
1393                 if(text->undo_len*2 > TXT_MAX_UNDO) { \
1394                         error("Undo limit reached, buffer cleared\n"); \
1395                         MEM_freeN(text->undo_buf); \
1396                         text->undo_len= TXT_INIT_UNDO; \
1397                         text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); \
1398                         text->undo_pos=-1; \
1399                         return; \
1400                 } else { \
1401                         void *tmp= text->undo_buf; \
1402                         text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf"); \
1403                         memcpy(text->undo_buf, tmp, text->undo_len); \
1404                         text->undo_len*=2; \
1405                         MEM_freeN(tmp); \
1406                 } \
1407         }
1408
1409 static void dump_buffer(Text *text) 
1410 {
1411         int i= 0;
1412         
1413         while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
1414 }
1415
1416 void txt_print_undo(Text *text)
1417 {
1418         int i= 0;
1419         int op;
1420         char *ops;
1421         int linep, charp;
1422         
1423         dump_buffer(text);
1424         
1425         printf ("---< Undo Buffer >---\n");
1426         
1427         printf ("UndoPosition is %d\n", text->undo_pos);
1428         
1429         while (i<=text->undo_pos) {
1430                 op= text->undo_buf[i];
1431                 
1432                 if (op==UNDO_CLEFT) {
1433                         ops= "Cursor left";
1434                 } else if (op==UNDO_CRIGHT) {
1435                         ops= "Cursor right";
1436                 } else if (op==UNDO_CUP) {
1437                         ops= "Cursor up";
1438                 } else if (op==UNDO_CDOWN) {
1439                         ops= "Cursor down";
1440                 } else if (op==UNDO_SLEFT) {
1441                         ops= "Selection left";
1442                 } else if (op==UNDO_SRIGHT) {
1443                         ops= "Selection right";
1444                 } else if (op==UNDO_SUP) {
1445                         ops= "Selection up";
1446                 } else if (op==UNDO_SDOWN) {
1447                         ops= "Selection down";
1448                 } else if (op==UNDO_STO) {
1449                         ops= "Selection ";
1450                 } else if (op==UNDO_CTO) {
1451                         ops= "Cursor ";
1452                 } else if (op==UNDO_INSERT) {
1453                         ops= "Insert";
1454                 } else if (op==UNDO_BS) {
1455                         ops= "Backspace";
1456                 } else if (op==UNDO_DEL) {
1457                         ops= "Delete";
1458                 } else if (op==UNDO_SWAP) {
1459                         ops= "Cursor swap";
1460                 } else if (op==UNDO_DBLOCK) {
1461                         ops= "Delete text block";
1462                 } else if (op==UNDO_IBLOCK) {
1463                         ops= "Insert text block";
1464                 } else if (op==UNDO_INDENT) {
1465                         ops= "Indent ";
1466                 } else if (op==UNDO_UNINDENT) {
1467                         ops= "Unindent ";
1468                 } else if (op==UNDO_COMMENT) {
1469                         ops= "Comment ";
1470                 } else if (op==UNDO_UNCOMMENT) {
1471                         ops= "Uncomment ";
1472                 } else {
1473                         ops= "Unknown";
1474                 }
1475                 
1476                 printf ("Op (%o) at %d = %s", op, i, ops);
1477                 if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) {
1478                         i++;
1479                         printf (" - Char is %c", text->undo_buf[i]);  
1480                         i++;
1481                 } else if (op==UNDO_STO || op==UNDO_CTO) {
1482                         i++;
1483
1484                         charp= text->undo_buf[i]; i++;
1485                         charp= charp+(text->undo_buf[i]<<8); i++;
1486
1487                         linep= text->undo_buf[i]; i++;
1488                         linep= linep+(text->undo_buf[i]<<8); i++;
1489                         linep= linep+(text->undo_buf[i]<<16); i++;
1490                         linep= linep+(text->undo_buf[i]<<24); i++;
1491                         
1492                         printf ("to <%d, %d> ", linep, charp);
1493
1494                         charp= text->undo_buf[i]; i++;
1495                         charp= charp+(text->undo_buf[i]<<8); i++;
1496
1497                         linep= text->undo_buf[i]; i++;
1498                         linep= linep+(text->undo_buf[i]<<8); i++;
1499                         linep= linep+(text->undo_buf[i]<<16); i++;
1500                         linep= linep+(text->undo_buf[i]<<24); i++;
1501                         
1502                         printf ("from <%d, %d>", linep, charp);
1503                 } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
1504                         i++;
1505
1506                         linep= text->undo_buf[i]; i++;
1507                         linep= linep+(text->undo_buf[i]<<8); i++;
1508                         linep= linep+(text->undo_buf[i]<<16); i++;
1509                         linep= linep+(text->undo_buf[i]<<24); i++;
1510                         
1511                         printf (" (length %d) <", linep);
1512                         
1513                         while (linep>0) {
1514                                 putchar(text->undo_buf[i]);
1515                                 linep--; i++;
1516                         }
1517                         
1518                         linep= text->undo_buf[i]; i++;
1519                         linep= linep+(text->undo_buf[i]<<8); i++;
1520                         linep= linep+(text->undo_buf[i]<<16); i++;
1521                         linep= linep+(text->undo_buf[i]<<24); i++;
1522                         printf ("> (%d)", linep);
1523                 } else if (op==UNDO_INDENT || op==UNDO_UNINDENT) {
1524                         i++;
1525
1526                         charp= text->undo_buf[i]; i++;
1527                         charp= charp+(text->undo_buf[i]<<8); i++;
1528
1529                         linep= text->undo_buf[i]; i++;
1530                         linep= linep+(text->undo_buf[i]<<8); i++;
1531                         linep= linep+(text->undo_buf[i]<<16); i++;
1532                         linep= linep+(text->undo_buf[i]<<24); i++;
1533                         
1534                         printf ("to <%d, %d> ", linep, charp);
1535
1536                         charp= text->undo_buf[i]; i++;
1537                         charp= charp+(text->undo_buf[i]<<8); i++;
1538
1539                         linep= text->undo_buf[i]; i++;
1540                         linep= linep+(text->undo_buf[i]<<8); i++;
1541                         linep= linep+(text->undo_buf[i]<<16); i++;
1542                         linep= linep+(text->undo_buf[i]<<24); i++;
1543                         
1544                         printf ("from <%d, %d>", linep, charp);
1545                 }
1546                 
1547                 printf (" %d\n",  i);
1548                 i++;
1549         }
1550 }
1551
1552 static void txt_undo_add_op(Text *text, int op)
1553 {
1554         MAX_UNDO_TEST(2);
1555         
1556         text->undo_pos++;
1557         text->undo_buf[text->undo_pos]= op;
1558         text->undo_buf[text->undo_pos+1]= 0;
1559 }
1560
1561 static void txt_undo_add_block(Text *text, int op, char *buf)
1562 {
1563         int length;
1564         
1565         length= strlen(buf);
1566         
1567         MAX_UNDO_TEST(length+11);
1568
1569         text->undo_pos++;
1570         text->undo_buf[text->undo_pos]= op;
1571         
1572         text->undo_pos++;
1573         text->undo_buf[text->undo_pos]= (length)&0xff;
1574         text->undo_pos++;
1575         text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1576         text->undo_pos++;
1577         text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1578         text->undo_pos++;
1579         text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1580
1581         text->undo_pos++;
1582         strncpy(text->undo_buf+text->undo_pos, buf, length);
1583         text->undo_pos+=length;
1584
1585         text->undo_buf[text->undo_pos]= (length)&0xff;
1586         text->undo_pos++;
1587         text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1588         text->undo_pos++;
1589         text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1590         text->undo_pos++;
1591         text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1592
1593         text->undo_pos++;
1594         text->undo_buf[text->undo_pos]= op;
1595         
1596         text->undo_buf[text->undo_pos+1]= 0;
1597 }
1598
1599 void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
1600 {
1601         MAX_UNDO_TEST(15);
1602
1603         if (froml==tol && fromc==toc) return;
1604
1605         text->undo_pos++;
1606         text->undo_buf[text->undo_pos]= op;
1607
1608         text->undo_pos++;
1609         text->undo_buf[text->undo_pos]= (fromc)&0xff;
1610         text->undo_pos++;
1611         text->undo_buf[text->undo_pos]= (fromc>>8)&0xff;
1612
1613         text->undo_pos++;
1614         text->undo_buf[text->undo_pos]= (froml)&0xff;
1615         text->undo_pos++;
1616         text->undo_buf[text->undo_pos]= (froml>>8)&0xff;
1617         text->undo_pos++;
1618         text->undo_buf[text->undo_pos]= (froml>>16)&0xff;
1619         text->undo_pos++;
1620         text->undo_buf[text->undo_pos]= (froml>>24)&0xff;
1621
1622         text->undo_pos++;
1623         text->undo_buf[text->undo_pos]= (toc)&0xff;
1624         text->undo_pos++;
1625         text->undo_buf[text->undo_pos]= (toc>>8)&0xff;
1626
1627         text->undo_pos++;
1628         text->undo_buf[text->undo_pos]= (tol)&0xff;
1629         text->undo_pos++;
1630         text->undo_buf[text->undo_pos]= (tol>>8)&0xff;
1631         text->undo_pos++;
1632         text->undo_buf[text->undo_pos]= (tol>>16)&0xff;
1633         text->undo_pos++;
1634         text->undo_buf[text->undo_pos]= (tol>>24)&0xff;
1635
1636         text->undo_pos++;
1637         text->undo_buf[text->undo_pos]= op;
1638
1639         text->undo_buf[text->undo_pos+1]= 0;
1640 }
1641
1642 static void txt_undo_add_charop(Text *text, int op, char c)
1643 {
1644         MAX_UNDO_TEST(4);
1645
1646         text->undo_pos++;
1647         text->undo_buf[text->undo_pos]= op;
1648         text->undo_pos++;
1649         text->undo_buf[text->undo_pos]= c;
1650         text->undo_pos++;
1651         text->undo_buf[text->undo_pos]= op;
1652         text->undo_buf[text->undo_pos+1]= 0;
1653 }
1654
1655 void txt_do_undo(Text *text)
1656 {
1657         int op= text->undo_buf[text->undo_pos];
1658         unsigned int linep, i;
1659         unsigned short charp;
1660         TextLine *holdl;
1661         int holdc, holdln;
1662         char *buf;
1663         
1664         if (text->undo_pos<0) {
1665                 return;
1666         }
1667
1668         text->undo_pos--;
1669
1670         undoing= 1;
1671         
1672         switch(op) {
1673                 case UNDO_CLEFT:
1674                         txt_move_right(text, 0);
1675                         break;
1676                         
1677                 case UNDO_CRIGHT:
1678                         txt_move_left(text, 0);
1679                         break;
1680                         
1681                 case UNDO_CUP:
1682                         txt_move_down(text, 0);
1683                         break;
1684                         
1685                 case UNDO_CDOWN:
1686                         txt_move_up(text, 0);
1687                         break;
1688
1689                 case UNDO_SLEFT:
1690                         txt_move_right(text, 1);
1691                         break;
1692
1693                 case UNDO_SRIGHT:
1694                         txt_move_left(text, 1);
1695                         break;
1696
1697                 case UNDO_SUP:
1698                         txt_move_down(text, 1);
1699                         break;
1700
1701                 case UNDO_SDOWN:
1702                         txt_move_up(text, 1);
1703                         break;
1704                 
1705                 case UNDO_CTO:
1706                 case UNDO_STO:
1707                         text->undo_pos--;
1708                         text->undo_pos--;
1709                         text->undo_pos--;
1710                         text->undo_pos--;
1711                 
1712                         text->undo_pos--;
1713                         text->undo_pos--;
1714                 
1715                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1716                         linep= (linep<<8)+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
1720                         charp= text->undo_buf[text->undo_pos]; text->undo_pos--;
1721                         charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1722                         
1723                         if (op==UNDO_CTO) {
1724                                 txt_move_toline(text, linep, 0);
1725                                 text->curc= charp;
1726                                 txt_pop_sel(text);
1727                         } else {
1728                                 txt_move_toline(text, linep, 1);
1729                                 text->selc= charp;
1730                         }
1731                         
1732                         text->undo_pos--;
1733                         break;
1734                         
1735                 case UNDO_INSERT:
1736                         txt_backspace_char(text);
1737                         text->undo_pos--;
1738                         text->undo_pos--;
1739                         break;
1740
1741                 case UNDO_BS:
1742                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1743                         text->undo_pos--;
1744                         text->undo_pos--;
1745                         break;
1746
1747                 case UNDO_DEL:
1748                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1749                         txt_move_left(text, 0);
1750                         text->undo_pos--;
1751                         text->undo_pos--;
1752                         break;
1753
1754                 case UNDO_SWAP:
1755                         txt_curs_swap(text);
1756                         break;
1757
1758                 case UNDO_DBLOCK:
1759                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1760                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1761                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1762                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1763
1764                         buf= MEM_mallocN(linep+1, "dblock buffer");
1765                         for (i=0; i < linep; i++){
1766                                 buf[(linep-1)-i]= text->undo_buf[text->undo_pos]; 
1767                                 text->undo_pos--;
1768                         }
1769                         buf[i]= 0;
1770                         
1771                         txt_curs_first(text, &holdl, &holdc);
1772                         holdln= txt_get_span(text->lines.first, holdl);
1773                         
1774                         txt_insert_buf(text, buf);                      
1775                         MEM_freeN(buf);
1776
1777                         text->curl= text->lines.first;
1778                         while (holdln>0) {
1779                                 if(text->curl->next)
1780                                         text->curl= text->curl->next;
1781                                         
1782                                 holdln--;
1783                         }
1784                         text->curc= holdc;
1785
1786                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1787                         linep= (linep<<8)+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
1791                         text->undo_pos--;
1792                         
1793                         break;
1794
1795                 case UNDO_IBLOCK:
1796                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1797                         linep= (linep<<8)+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
1801                         txt_delete_sel(text);
1802                         while (linep>0) {
1803                                 txt_backspace_char(text);
1804                                 text->undo_pos--;
1805                                 linep--;
1806                         }
1807
1808                         text->undo_pos--;
1809                         text->undo_pos--;
1810                         text->undo_pos--; 
1811                         text->undo_pos--;
1812                         
1813                         text->undo_pos--;
1814
1815                         break;
1816                 case UNDO_INDENT:
1817                 case UNDO_UNINDENT:
1818                 case UNDO_COMMENT:
1819                 case UNDO_UNCOMMENT:
1820                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1821                         linep = (linep<<8)+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 is now the end line of the selection
1825                         
1826                         charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1827                         charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1828                         //charp is the last char selected or text->line->len
1829                         //set the selcetion for this now
1830                         text->selc = charp;
1831                         text->sell = text->lines.first;
1832                         for (i= 0; i < linep; i++) {
1833                                 text->sell = text->sell->next;
1834                         }
1835
1836                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1837                         linep = (linep<<8)+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                         //first line to be selected
1841                         
1842                         charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1843                         charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1844                         //first postion to be selected
1845                         text->curc = charp;
1846                         text->curl = text->lines.first;
1847                         for (i = 0; i < linep; i++) {
1848                                 text->curl = text->curl->next;
1849                         }
1850
1851                         
1852                         if (op==UNDO_INDENT) {
1853                                 unindent(text);
1854                         } else if (op== UNDO_UNINDENT) {
1855                                 indent(text);
1856                         } else if (op == UNDO_COMMENT) {
1857                                 uncomment(text);
1858                         } else if (op == UNDO_UNCOMMENT) {
1859                                 comment(text);
1860                         }
1861
1862                         text->undo_pos--;
1863                         break;
1864                 default:
1865                         error("Undo buffer error - resetting");
1866                         text->undo_pos= -1;
1867                         
1868                         break;
1869         }
1870
1871         /* next undo step may need evaluating */
1872         if (text->undo_pos>=0) {
1873                 switch (text->undo_buf[text->undo_pos]) {
1874                         case UNDO_STO:
1875                                 txt_do_undo(text);
1876                                 txt_do_redo(text); /* selections need restoring */
1877                                 break;
1878                         case UNDO_SWAP:
1879                                 txt_do_undo(text); /* swaps should appear transparent */
1880                                 break;
1881                 }
1882         }
1883         
1884         undoing= 0;     
1885 }
1886
1887 void txt_do_redo(Text *text)
1888 {
1889         char op;
1890         unsigned int linep, i;
1891         unsigned short charp;
1892         char *buf;
1893         
1894         text->undo_pos++;       
1895         op= text->undo_buf[text->undo_pos];
1896         
1897         if (!op) {
1898                 text->undo_pos--;
1899                 return;
1900         }
1901         
1902         undoing= 1;
1903
1904         switch(op) {
1905                 case UNDO_CLEFT:
1906                         txt_move_left(text, 0);
1907                         break;
1908                         
1909                 case UNDO_CRIGHT:
1910                         txt_move_right(text, 0);
1911                         break;
1912                         
1913                 case UNDO_CUP:
1914                         txt_move_up(text, 0);
1915                         break;
1916                         
1917                 case UNDO_CDOWN:
1918                         txt_move_down(text, 0);
1919                         break;
1920
1921                 case UNDO_SLEFT:
1922                         txt_move_left(text, 1);
1923                         break;
1924
1925                 case UNDO_SRIGHT:
1926                         txt_move_right(text, 1);
1927                         break;
1928
1929                 case UNDO_SUP:
1930                         txt_move_up(text, 1);
1931                         break;
1932
1933                 case UNDO_SDOWN:
1934                         txt_move_down(text, 1);
1935                         break;
1936                 
1937                 case UNDO_INSERT:
1938                         text->undo_pos++;
1939                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1940                         text->undo_pos++;
1941                         break;
1942
1943                 case UNDO_BS:
1944                         text->undo_pos++;
1945                         txt_backspace_char(text);
1946                         text->undo_pos++;
1947                         break;
1948
1949                 case UNDO_DEL:
1950                         text->undo_pos++;
1951                         txt_delete_char(text);
1952                         text->undo_pos++;
1953                         break;
1954
1955                 case UNDO_SWAP:
1956                         txt_curs_swap(text);
1957                         txt_do_redo(text); /* swaps should appear transparent a*/
1958                         break;
1959                         
1960                 case UNDO_CTO:
1961                 case UNDO_STO:
1962                         text->undo_pos++;
1963                         text->undo_pos++;
1964
1965                         text->undo_pos++;
1966                         text->undo_pos++;
1967                         text->undo_pos++;
1968                         text->undo_pos++;
1969
1970                         text->undo_pos++;
1971
1972                         charp= text->undo_buf[text->undo_pos];
1973                         text->undo_pos++;
1974                         charp= charp+(text->undo_buf[text->undo_pos]<<8);
1975
1976                         text->undo_pos++;
1977                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1978                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1979                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1980                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
1981                         
1982                         if (op==UNDO_CTO) {
1983                                 txt_move_toline(text, linep, 0);
1984                                 text->curc= charp;
1985                                 txt_pop_sel(text);
1986                         } else {
1987                                 txt_move_toline(text, linep, 1);
1988                                 text->selc= charp;
1989                         }
1990
1991                         break;
1992
1993                 case UNDO_DBLOCK:
1994                         text->undo_pos++;
1995                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1996                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1997                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1998                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
1999
2000                         txt_delete_sel(text);
2001                         text->undo_pos+=linep;
2002
2003                         text->undo_pos++;
2004                         text->undo_pos++;
2005                         text->undo_pos++; 
2006                         text->undo_pos++;
2007                         
2008                         break;
2009
2010                 case UNDO_IBLOCK:
2011                         text->undo_pos++;
2012                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2013                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2014                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2015                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2016
2017                         buf= MEM_mallocN(linep+1, "iblock buffer");
2018                         memcpy (buf, &text->undo_buf[text->undo_pos], linep);
2019                         text->undo_pos+= linep;
2020                         buf[linep]= 0;
2021                         
2022                         txt_insert_buf(text, buf);                      
2023                         MEM_freeN(buf);
2024
2025                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2026                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2027                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2028                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2029
2030                         break;
2031                 case UNDO_INDENT:
2032                 case UNDO_UNINDENT:
2033                 case UNDO_COMMENT:
2034                 case UNDO_UNCOMMENT:
2035                         text->undo_pos++;
2036                         charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2037                         charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2038                         //charp is the first char selected or 0
2039                         
2040                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2041                         linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2042                         linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2043                         linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2044                         //linep is now the first line of the selection                  
2045                         //set the selcetion for this now
2046                         text->curc = charp;
2047                         text->curl = text->lines.first;
2048                         for (i= 0; i < linep; i++) {
2049                                 text->curl = text->curl->next;
2050                         }
2051                         
2052                         charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
2053                         charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2054                         //last postion to be selected
2055                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
2056                         linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
2057                         linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
2058                         linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
2059                         //Last line to be selected
2060                         
2061                         text->selc = charp;
2062                         text->sell = text->lines.first;
2063                         for (i = 0; i < linep; i++) {
2064                                 text->sell = text->sell->next;
2065                         }
2066
2067                         if (op==UNDO_INDENT) {
2068                                 indent(text);
2069                         } else if (op== UNDO_UNINDENT) {
2070                                 unindent(text);
2071                         } else if (op == UNDO_COMMENT) {
2072                                 comment(text);
2073                         } else if (op == UNDO_UNCOMMENT) {
2074                                 uncomment(text);
2075                         }
2076                         break;
2077                 default:
2078                         error("Undo buffer error - resetting");
2079                         text->undo_pos= -1;
2080
2081                         break;
2082         }
2083         
2084         undoing= 0;     
2085 }
2086
2087 /**************************/
2088 /* Line editing functions */ 
2089 /**************************/
2090
2091 void txt_split_curline (Text *text) 
2092 {
2093         TextLine *ins;
2094         TextMarker *mrk;
2095         char *left, *right;
2096         int lineno= -1;
2097         
2098         if (!text) return;
2099         if (!text->curl) return;
2100
2101         txt_delete_sel(text);
2102
2103         /* Move markers */
2104
2105         lineno= txt_get_span(text->lines.first, text->curl);
2106         mrk= text->markers.first;
2107         while (mrk) {
2108                 if (mrk->lineno==lineno && mrk->start>text->curc) {
2109                         mrk->lineno++;
2110                         mrk->start -= text->curc;
2111                         mrk->end -= text->curc;
2112                 } else if (mrk->lineno > lineno) {
2113                         mrk->lineno++;
2114                 }
2115                 mrk= mrk->next;
2116         }
2117
2118         /* Make the two half strings */
2119
2120         left= MEM_mallocN(text->curc+1, "textline_string");
2121         if (text->curc) memcpy(left, text->curl->line, text->curc);
2122         left[text->curc]=0;
2123         
2124         right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
2125         if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc);
2126         right[text->curl->len - text->curc]=0;
2127
2128         MEM_freeN(text->curl->line);
2129         if (text->curl->format) MEM_freeN(text->curl->format);
2130
2131         /* Make the new TextLine */
2132         
2133         ins= MEM_mallocN(sizeof(TextLine), "textline");
2134         ins->line= left;
2135         ins->format= NULL;
2136         ins->len= text->curc;
2137         
2138         text->curl->line= right;
2139         text->curl->format= NULL;
2140         text->curl->len= text->curl->len - text->curc;
2141         
2142         BLI_insertlinkbefore(&text->lines, text->curl, ins);    
2143         
2144         text->curc=0;
2145         
2146         txt_make_dirty(text);
2147         txt_clean_text(text);
2148         
2149         txt_pop_sel(text);
2150         if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n');
2151 }
2152
2153 static void txt_delete_line (Text *text, TextLine *line) 
2154 {
2155         TextMarker *mrk=NULL, *nxt;
2156         int lineno= -1;
2157
2158         if (!text) return;
2159         if (!text->curl) return;
2160
2161         lineno= txt_get_span(text->lines.first, line);
2162         mrk= text->markers.first;
2163         while (mrk) {
2164                 nxt= mrk->next;
2165                 if (mrk->lineno==lineno)
2166                         BLI_freelinkN(&text->markers, mrk);
2167                 else if (mrk->lineno > lineno)
2168                         mrk->lineno--;
2169                 mrk= nxt;
2170         }
2171
2172         BLI_remlink (&text->lines, line);
2173         
2174         if (line->line) MEM_freeN(line->line);
2175         if (line->format) MEM_freeN(line->format);
2176
2177         MEM_freeN(line);
2178
2179         txt_make_dirty(text);
2180         txt_clean_text(text);
2181 }
2182
2183 static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
2184 {
2185         char *tmp;
2186         TextMarker *mrk= NULL;
2187         int lineno=-1;
2188         
2189         if (!text) return;
2190         
2191         if(!linea || !lineb) return;
2192
2193         mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0);
2194         if (mrk) {
2195                 lineno= mrk->lineno;
2196                 do {
2197                         mrk->lineno--;
2198                         mrk->start += linea->len;
2199                         mrk->end += linea->len;
2200                         mrk= mrk->next;
2201                 } while (mrk && mrk->lineno==lineno);
2202         }
2203         if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb);
2204         if (!mrk) mrk= text->markers.first;
2205         
2206         tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
2207         
2208         strcpy(tmp, linea->line);
2209         strcat(tmp, lineb->line);
2210
2211         make_new_line(linea, tmp);
2212         
2213         txt_delete_line(text, lineb);
2214         
2215         txt_make_dirty(text);
2216         txt_clean_text(text);
2217 }
2218
2219 void txt_delete_char (Text *text) 
2220 {
2221         char c='\n';
2222         
2223         if (!text) return;
2224         if (!text->curl) return;
2225
2226         if (txt_has_sel(text)) { /* deleting a selection */
2227                 txt_delete_sel(text);
2228                 txt_make_dirty(text);
2229                 return;
2230         }
2231         else if (text->curc== text->curl->len) { /* Appending two lines */
2232                 if (text->curl->next) {
2233                         txt_combine_lines(text, text->curl, text->curl->next);
2234                         txt_pop_sel(text);
2235                 }
2236         } else { /* Just deleting a char */
2237                 int i= text->curc;
2238
2239                 TextMarker *mrk= txt_find_marker_region(text, text->curl, i-1, text->curl->len, 0, 0);
2240                 if (mrk) {
2241                         int lineno= mrk->lineno;
2242                         if (mrk->end==i) {
2243                                 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
2244                                         txt_clear_markers(text, mrk->group, TMARK_TEMP);
2245                                 } else {
2246                                         TextMarker *nxt= mrk->next;
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                                         TextMarker *nxt= mrk->next;
2312                                         BLI_freelinkN(&text->markers, mrk);
2313                                 }
2314                                 return;
2315                         }
2316                         do {
2317                                 if (mrk->start>i) mrk->start--;
2318                                 mrk->end--;
2319                                 mrk= mrk->next;
2320                         } while (mrk && mrk->lineno==lineno);
2321                 }
2322                 
2323                 c= text->curl->line[i];
2324                 while(i< text->curl->len) {
2325                         text->curl->line[i]= text->curl->line[i+1];
2326                         i++;
2327                 }
2328                 text->curl->len--;
2329                 text->curc--;
2330
2331                 txt_pop_sel(text);
2332         }
2333
2334         txt_make_dirty(text);
2335         txt_clean_text(text);
2336         
2337         if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
2338 }
2339
2340 void txt_backspace_word (Text *text) 
2341 {
2342         txt_jump_left(text, 1);
2343         txt_delete_sel(text);
2344 }
2345
2346 int txt_add_char (Text *text, char add) 
2347 {
2348         int len, lineno;
2349         char *tmp;
2350         TextMarker *mrk;
2351         
2352         if (!text) return 0;
2353         if (!text->curl) return 0;
2354
2355         if (add=='\n') {
2356                 txt_split_curline(text);
2357                 return 1;
2358         }
2359         
2360         txt_delete_sel(text);
2361         
2362         mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0);
2363         if (mrk) {
2364                 lineno= mrk->lineno;
2365                 do {
2366                         if (mrk->start>text->curc) mrk->start++;
2367                         mrk->end++;
2368                         mrk= mrk->next;
2369                 } while (mrk && mrk->lineno==lineno);
2370         }
2371         
2372         tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2373         
2374         if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2375         tmp[text->curc]= add;
2376         
2377         len= text->curl->len - text->curc;
2378         if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2379         tmp[text->curl->len+1]=0;
2380         make_new_line(text->curl, tmp);
2381                 
2382         text->curc++;
2383
2384         txt_pop_sel(text);
2385         
2386         txt_make_dirty(text);
2387         txt_clean_text(text);
2388
2389         if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add);
2390         return 1;
2391 }
2392
2393 int txt_replace_char (Text *text, char add)
2394 {
2395         char del;
2396         
2397         if (!text) return 0;
2398         if (!text->curl) return 0;
2399
2400         /* If text is selected or we're at the end of the line just use txt_add_char */
2401         if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') {
2402                 TextMarker *mrk;
2403                 int i= txt_add_char(text, add);
2404                 mrk= txt_find_marker(text, text->curl, text->curc, 0, 0);
2405                 if (mrk && mrk->end==text->curc) mrk->end--;
2406                 return i;
2407         }
2408         
2409         del= text->curl->line[text->curc];
2410         text->curl->line[text->curc]= (unsigned char) add;
2411         text->curc++;
2412         txt_pop_sel(text);
2413         
2414         txt_make_dirty(text);
2415         txt_clean_text(text);
2416
2417         /* Should probably create a new op for this */
2418         if(!undoing) {
2419                 txt_undo_add_charop(text, UNDO_DEL, del);
2420                 txt_undo_add_charop(text, UNDO_INSERT, add);
2421         }
2422         return 1;
2423 }
2424
2425 void indent(Text *text)
2426 {
2427         int len, num;
2428         char *tmp;
2429         char add = '\t';
2430         
2431         if (!text) return;
2432         if (!text->curl) return;
2433         if (!text->sell) return;
2434
2435         num = 0;
2436         while (TRUE)
2437         {
2438                 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2439                 
2440                 text->curc = 0; 
2441                 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2442                 tmp[text->curc]= add;
2443                 
2444                 len= text->curl->len - text->curc;
2445                 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2446                 tmp[text->curl->len+1]=0;
2447
2448                 make_new_line(text->curl, tmp);
2449                         
2450                 text->curc++;
2451                 
2452                 txt_make_dirty(text);
2453                 txt_clean_text(text);
2454                 
2455                 if(text->curl == text->sell) 
2456                 {
2457                         text->selc = text->sell->len;
2458                         break;
2459                 } else {
2460                         text->curl = text->curl->next;
2461                         num++;
2462                 }
2463         }
2464         text->curc = 0;
2465         while( num > 0 )
2466         {
2467                 text->curl = text->curl->prev;
2468                 num--;
2469         }
2470         
2471         if(!undoing) 
2472         {
2473                 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);
2474         }
2475 }
2476
2477 void unindent(Text *text)
2478 {
2479         int num = 0;
2480         char remove = '\t';
2481         
2482         if (!text) return;
2483         if (!text->curl) return;
2484         if (!text->sell) return;
2485
2486         while(TRUE)
2487         {
2488                 int i = 0;
2489                 
2490                 if (text->curl->line[i] == remove)
2491                 {
2492                         while(i< text->curl->len) {
2493                                 text->curl->line[i]= text->curl->line[i+1];
2494                                 i++;
2495                         }
2496                         text->curl->len--;
2497                 }
2498                          
2499         
2500                 txt_make_dirty(text);
2501                 txt_clean_text(text);
2502                 
2503                 if(text->curl == text->sell) 
2504                 {
2505                         text->selc = text->sell->len;
2506                         break;
2507                 } else {
2508                         text->curl = text->curl->next;
2509                         num++;
2510                 }
2511                 
2512         }
2513         text->curc = 0;
2514         while( num > 0 )
2515         {
2516                 text->curl = text->curl->prev;
2517                 num--;
2518         }
2519         
2520         if(!undoing) 
2521         {
2522                 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);
2523         }
2524 }
2525
2526 void comment(Text *text)
2527 {
2528         int len, num;
2529         char *tmp;
2530         char add = '#';
2531         
2532         if (!text) return;
2533         if (!text->curl) return;
2534         if (!text->sell) return;// Need to change this need to check if only one line is selected ot more then one
2535
2536         num = 0;
2537         while (TRUE)
2538         {
2539                 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2540                 
2541                 text->curc = 0; 
2542                 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2543                 tmp[text->curc]= add;
2544                 
2545                 len= text->curl->len - text->curc;
2546                 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2547                 tmp[text->curl->len+1]=0;
2548
2549                 make_new_line(text->curl, tmp);
2550                         
2551                 text->curc++;
2552                 
2553                 txt_make_dirty(text);
2554                 txt_clean_text(text);
2555                 
2556                 if(text->curl == text->sell) 
2557                 {
2558                         text->selc = text->sell->len;
2559                         break;
2560                 } else {
2561                         text->curl = text->curl->next;
2562                         num++;
2563                 }
2564         }
2565         text->curc = 0;
2566         while( num > 0 )
2567         {
2568                 text->curl = text->curl->prev;
2569                 num--;
2570         }
2571         
2572         if(!undoing) 
2573         {
2574                 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);
2575         }
2576 }
2577
2578 void uncomment(Text *text)
2579 {
2580         int num = 0;
2581         char remove = '#';
2582         
2583         if (!text) return;
2584         if (!text->curl) return;
2585         if (!text->sell) return;
2586
2587         while(TRUE)
2588         {
2589                 int i = 0;
2590                 
2591                 if (text->curl->line[i] == remove)
2592                 {
2593                         while(i< text->curl->len) {
2594                                 text->curl->line[i]= text->curl->line[i+1];
2595                                 i++;
2596                         }
2597                         text->curl->len--;
2598                 }
2599                          
2600         
2601                 txt_make_dirty(text);
2602                 txt_clean_text(text);
2603                 
2604                 if(text->curl == text->sell) 
2605                 {
2606                         text->selc = text->sell->len;
2607                         break;
2608                 } else {
2609                         text->curl = text->curl->next;
2610                         num++;
2611                 }
2612                 
2613         }
2614         text->curc = 0;
2615         while( num > 0 )
2616         {
2617                 text->curl = text->curl->prev;
2618                 num--;
2619         }
2620         
2621         if(!undoing) 
2622         {
2623                 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);
2624         }
2625 }
2626
2627 int setcurr_tab (Text *text)
2628 {
2629         int i = 0;
2630         int test = 0;
2631         char *word = ":";
2632         char *comm = "#";
2633         char back_words[4][7] = {"return", "break", "pass", "yield"};
2634         if (!text) return 0;
2635         if (!text->curl) return 0;
2636         
2637         while (text->curl->line[i] == '\t')
2638         {
2639                 //we only count thos tabs that are before any text or before the curs;
2640                 if (i == text->curc)
2641                 {
2642                         return i;
2643                 } else {
2644                         i++;
2645                 }
2646         }
2647         if(strstr(text->curl->line, word))
2648         {
2649                 //if we find a : then add a tab but not if it is in a comment
2650                 int a, indent = 0;
2651                 for(a=0; text->curl->line[a] != '\0'; a++)
2652                 {
2653                         if (text->curl->line[a]=='#') {
2654                                 break;
2655                         } else if (text->curl->line[a]==':') {
2656                                 indent = 1;
2657                         } else if (text->curl->line[a]==']') {
2658                                 indent = 0;
2659                         }
2660                 }
2661                 if (indent) {
2662                         i++;
2663                 }
2664         }
2665
2666         for(test=0; test < 4; test++)
2667         {
2668                 //if there are these 4 key words then remove a tab because we are done with the block
2669                 if(strstr(text->curl->line, back_words[test]) && i > 0)
2670                 {
2671                         if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
2672                         {
2673                                 i--;
2674                         }
2675                 }
2676         }
2677         return i;
2678 }
2679
2680 /*********************************/
2681 /* Text marker utility functions */
2682 /*********************************/
2683
2684 static int color_match(TextMarker *a, TextMarker *b) {
2685         return (a->color[0]==b->color[0] &&
2686                         a->color[1]==b->color[1] &&
2687                         a->color[2]==b->color[2] &&
2688                         a->color[3]==b->color[3]);
2689 }
2690
2691 /* Creates and adds a marker to the list maintaining sorted order */
2692 void txt_add_marker(Text *text, TextLine *line, int start, int end, char color[4], int group, int flags) {
2693         TextMarker *tmp, *marker;
2694
2695         marker= MEM_mallocN(sizeof(TextMarker), "text_marker");
2696         
2697         marker->lineno= txt_get_span(text->lines.first, line);
2698         marker->start= MIN2(start, end);
2699         marker->end= MAX2(start, end);
2700         marker->group= group;
2701         marker->flags= flags;
2702
2703         marker->color[0]= color[0];
2704         marker->color[1]= color[1];
2705         marker->color[2]= color[2];
2706         marker->color[3]= color[3];
2707
2708         for (tmp=text->markers.last; tmp; tmp=tmp->prev)
2709                 if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start))
2710                         break;
2711
2712         if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker);
2713         else BLI_addhead(&text->markers, marker);
2714 }
2715
2716 /* Returns the first matching marker on the specified line between two points.
2717    If the group or flags fields are non-zero the returned flag must be in the
2718    specified group and have at least the specified flags set. */
2719 TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2720         TextMarker *marker, *next;
2721         int lineno= txt_get_span(text->lines.first, line);
2722         
2723         for (marker=text->markers.first; marker; marker=next) {
2724                 next= marker->next;
2725
2726                 if (group && marker->group != group) continue;
2727                 else if ((marker->flags & flags) != flags) continue;
2728                 else if (marker->lineno < lineno) continue;
2729                 else if (marker->lineno > lineno) break;
2730
2731                 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2732                                 (marker->start<end && marker->end>start))
2733                         return marker;
2734         }
2735         return NULL;
2736 }
2737
2738 /* Clears all markers on the specified line between two points. If the group or
2739    flags fields are non-zero the returned flag must be in the specified group
2740    and have at least the specified flags set. */
2741 short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
2742         TextMarker *marker, *next;
2743         int lineno= txt_get_span(text->lines.first, line);
2744         short cleared= 0;
2745         
2746         for (marker=text->markers.first; marker; marker=next) {
2747                 next= marker->next;
2748
2749                 if (group && marker->group != group) continue;
2750                 else if ((marker->flags & flags) != flags) continue;
2751                 else if (marker->lineno < lineno) continue;
2752                 else if (marker->lineno > lineno) break;
2753
2754                 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
2755                         (marker->start<end && marker->end>start)) {
2756                         BLI_freelinkN(&text->markers, marker);
2757                         cleared= 1;
2758                 }
2759         }
2760         return cleared;
2761 }
2762
2763 /* Clears all markers in the specified group (if given) with at least the
2764    specified flags set. Useful for clearing temporary markers (group=0,
2765    flags=TMARK_TEMP) */
2766 short txt_clear_markers(Text *text, int group, int flags) {
2767         TextMarker *marker, *next;
2768         short cleared= 0;
2769         
2770         for (marker=text->markers.first; marker; marker=next) {
2771                 next= marker->next;
2772
2773                 if ((!group || marker->group==group) &&
2774                                 (marker->flags & flags) == flags) {
2775                         BLI_freelinkN(&text->markers, marker);
2776                         cleared= 1;
2777                 }
2778         }
2779         return cleared;
2780 }
2781
2782 /* Finds the marker at the specified line and cursor position with at least the
2783    specified flags set in the given group (if non-zero). */
2784 TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags) {
2785         TextMarker *marker;
2786         int lineno= txt_get_span(text->lines.first, line);
2787         
2788         for (marker=text->markers.first; marker; marker=marker->next) {
2789                 if (group && marker->group != group) continue;
2790                 else if ((marker->flags & flags) != flags) continue;
2791                 else if (marker->lineno < lineno) continue;
2792                 else if (marker->lineno > lineno) break;
2793
2794                 if (marker->start <= curs && curs <= marker->end)
2795                         return marker;
2796         }
2797         return NULL;
2798 }
2799
2800 /* Finds the previous marker in the same group. If no other is found, the same
2801    marker will be returned */
2802 TextMarker *txt_prev_marker(Text *text, TextMarker *marker) {
2803         TextMarker *tmp= marker;
2804         while (tmp) {
2805                 if (tmp->prev) tmp= tmp->prev;
2806                 else tmp= text->markers.last;
2807                 if (tmp->group == marker->group)
2808                         return tmp;
2809         }
2810         return NULL; /* Only if marker==NULL */
2811 }
2812
2813 /* Finds the next marker in the same group. If no other is found, the same
2814    marker will be returned */
2815 TextMarker *txt_next_marker(Text *text, TextMarker *marker) {
2816         TextMarker *tmp= marker;
2817         while (tmp) {
2818                 if (tmp->next) tmp= tmp->next;
2819                 else tmp= text->markers.first;
2820                 if (tmp->group == marker->group)
2821                         return tmp;
2822         }
2823         return NULL; /* Only if marker==NULL */
2824 }