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