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