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