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