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