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