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