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