svn merge -r 14676:15409 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[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         if (!text->lines.first) return NULL;
946
947         linef= text->lines.first;
948         charf= 0;
949                 
950         linel= text->lines.last;
951         charl= linel->len;
952
953         if (linef == text->lines.last) {
954                 length= charl-charf;
955
956                 buf= MEM_mallocN(length+2, "text buffer");
957                 
958                 BLI_strncpy(buf, linef->line + charf, length+1);
959                 buf[length]=0;
960         } else {
961                 length= linef->len - charf;
962                 length+= charl;
963                 length+= 2; /* For the 2 '\n' */
964                 
965                 tmp= linef->next;
966                 while (tmp && tmp!= linel) {
967                         length+= tmp->len+1;
968                         tmp= tmp->next;
969                 }
970                 
971                 buf= MEM_mallocN(length+1, "cut buffer");
972
973                 strncpy(buf, linef->line + charf, linef->len-charf);
974                 length= linef->len - charf;
975                 
976                 buf[length++]='\n';
977                 
978                 tmp= linef->next;
979                 while (tmp && tmp!=linel) {
980                         strncpy(buf+length, tmp->line, tmp->len);
981                         length+= tmp->len;
982                         
983                         buf[length++]='\n';                     
984                         
985                         tmp= tmp->next;
986                 }
987                 strncpy(buf+length, linel->line, charl);
988                 length+= charl;
989                 
990                 /* python compiler wants an empty end line */
991                 buf[length++]='\n';                     
992                 buf[length]=0;
993         }
994         
995         return buf;
996 }
997
998 int txt_find_string(Text *text, char *findstr)
999 {
1000         TextLine *tl, *startl;
1001         char *s= NULL;
1002
1003         if (!text || !text->curl || !text->sell) return 0;
1004         
1005         txt_order_cursors(text);
1006
1007         tl= startl= text->sell;
1008         
1009         s= strstr(&tl->line[text->selc], findstr);
1010         while (!s) {
1011                 tl= tl->next;
1012                 if (!tl)
1013                         tl= text->lines.first;
1014
1015                 s= strstr(tl->line, findstr);
1016                 if (tl==startl)
1017                         break;
1018         }
1019         
1020         if (s) {
1021                 text->curl= text->sell= tl;
1022                 text->curc= (int) (s-tl->line);
1023                 text->selc= text->curc + strlen(findstr);
1024                 
1025                 return 1;                               
1026         } else
1027                 return 0;
1028 }
1029
1030 void txt_cut_sel (Text *text)
1031 {
1032         if (!G.background) /* Python uses txt_cut_sel, which it should not, working around for now  */
1033                 txt_copy_clipboard(text);
1034         
1035         txt_delete_sel(text);
1036         txt_make_dirty(text);
1037 }
1038
1039 char *txt_sel_to_buf (Text *text)
1040 {
1041         char *buf;
1042         int length=0;
1043         TextLine *tmp, *linef, *linel;
1044         int charf, charl;
1045         
1046         if (!text) return NULL;
1047         if (!text->curl) return NULL;
1048         if (!text->sell) return NULL;
1049         
1050         if (text->curl==text->sell) {
1051                 linef= linel= text->curl;
1052                 
1053                 if (text->curc < text->selc) {
1054                         charf= text->curc;
1055                         charl= text->selc;
1056                 } else{
1057                         charf= text->selc;
1058                         charl= text->curc;
1059                 }
1060         } else if (txt_get_span(text->curl, text->sell)<0) {
1061                 linef= text->sell;
1062                 linel= text->curl;
1063
1064                 charf= text->selc;              
1065                 charl= text->curc;
1066         } else {
1067                 linef= text->curl;
1068                 linel= text->sell;
1069                 
1070                 charf= text->curc;
1071                 charl= text->selc;
1072         }
1073
1074         if (linef == linel) {
1075                 length= charl-charf;
1076
1077                 buf= MEM_mallocN(length+1, "sel buffer");
1078                 
1079                 BLI_strncpy(buf, linef->line + charf, length+1);
1080         } else {
1081                 length+= linef->len - charf;
1082                 length+= charl;
1083                 length++; /* For the '\n' */
1084                 
1085                 tmp= linef->next;
1086                 while (tmp && tmp!= linel) {
1087                         length+= tmp->len+1;
1088                         tmp= tmp->next;
1089                 }
1090                 
1091                 buf= MEM_mallocN(length+1, "sel buffer");
1092                 
1093                 strncpy(buf, linef->line+ charf, linef->len-charf);
1094                 length= linef->len-charf;
1095                 
1096                 buf[length++]='\n';
1097                 
1098                 tmp= linef->next;
1099                 while (tmp && tmp!=linel) {
1100                         strncpy(buf+length, tmp->line, tmp->len);
1101                         length+= tmp->len;
1102                         
1103                         buf[length++]='\n';                     
1104                         
1105                         tmp= tmp->next;
1106                 }
1107                 strncpy(buf+length, linel->line, charl);
1108                 length+= charl;
1109                 
1110                 buf[length]=0;
1111         }       
1112
1113         return buf;
1114 }
1115
1116 void txt_copy_sel (Text *text)
1117 {
1118         int length=0;
1119         TextLine *tmp, *linef, *linel;
1120         int charf, charl;
1121         
1122         if (!text) return;
1123         if (!text->curl) return;
1124         if (!text->sell) return;
1125
1126         if (!txt_has_sel(text)) return;
1127         
1128         if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
1129         txt_cut_buffer= NULL;
1130         
1131         if (text->curl==text->sell) {
1132                 linef= linel= text->curl;
1133                 
1134                 if (text->curc < text->selc) {
1135                         charf= text->curc;
1136                         charl= text->selc;
1137                 } else{
1138                         charf= text->selc;
1139                         charl= text->curc;
1140                 }
1141         } else if (txt_get_span(text->curl, text->sell)<0) {
1142                 linef= text->sell;
1143                 linel= text->curl;
1144
1145                 charf= text->selc;              
1146                 charl= text->curc;
1147         } else {
1148                 linef= text->curl;
1149                 linel= text->sell;
1150                 
1151                 charf= text->curc;
1152                 charl= text->selc;
1153         }
1154
1155         if (linef == linel) {
1156                 length= charl-charf;
1157
1158                 txt_cut_buffer= MEM_mallocN(length+1, "cut buffera");
1159                 
1160                 BLI_strncpy(txt_cut_buffer, linef->line + charf, length+1);
1161         } else {
1162                 length+= linef->len - charf;
1163                 length+= charl;
1164                 length++; /* For the '\n' */
1165                 
1166                 tmp= linef->next;
1167                 while (tmp && tmp!= linel) {
1168                         length+= tmp->len+1;
1169                         tmp= tmp->next;
1170                 }
1171                 
1172                 txt_cut_buffer= MEM_mallocN(length+1, "cut bufferb");
1173                 
1174                 strncpy(txt_cut_buffer, linef->line+ charf, linef->len-charf);
1175                 length= linef->len-charf;
1176                 
1177                 txt_cut_buffer[length++]='\n';
1178                 
1179                 tmp= linef->next;
1180                 while (tmp && tmp!=linel) {
1181                         strncpy(txt_cut_buffer+length, tmp->line, tmp->len);
1182                         length+= tmp->len;
1183                         
1184                         txt_cut_buffer[length++]='\n';                  
1185                         
1186                         tmp= tmp->next;
1187                 }
1188                 strncpy(txt_cut_buffer+length, linel->line, charl);
1189                 length+= charl;
1190                 
1191                 txt_cut_buffer[length]=0;
1192         }
1193 }
1194
1195 void txt_insert_buf(Text *text, char *in_buffer)
1196 {
1197         int i=0, l=0, j, u, len;
1198         TextLine *add;
1199
1200         if (!text) return;
1201         if (!in_buffer) return;
1202
1203         txt_delete_sel(text);
1204         
1205         if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer);         
1206
1207         u= undoing;
1208         undoing= 1;
1209
1210         /* Read the first line (or as close as possible */
1211         while (in_buffer[i] && in_buffer[i]!='\n') {
1212                 txt_add_char(text, in_buffer[i]);
1213                 i++;
1214         }
1215         
1216         if (in_buffer[i]=='\n') txt_split_curline(text);
1217         else { undoing = u; return; }
1218         i++;
1219
1220         /* Read as many full lines as we can */
1221         len= strlen(in_buffer);
1222
1223         while (i<len) {
1224                 l=0;
1225
1226                 while (in_buffer[i] && in_buffer[i]!='\n') {
1227                         i++; l++;
1228                 }
1229         
1230                 if(in_buffer[i]=='\n') {
1231                         add= txt_new_linen(in_buffer +(i-l), l);
1232                         BLI_insertlinkbefore(&text->lines, text->curl, add);
1233                         i++;
1234                 } else {
1235                         for (j= i-l; j<i && j<(int)strlen(in_buffer); j++) {
1236                                 txt_add_char(text, in_buffer[j]);
1237                         }
1238                         break;
1239                 }
1240         }
1241         
1242         undoing= u;
1243 }
1244
1245 void txt_free_cut_buffer(void) 
1246 {
1247         if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
1248 }
1249
1250 void txt_paste(Text *text)
1251 {
1252         txt_insert_buf(text, txt_cut_buffer);
1253 }
1254
1255 /******************/
1256 /* Undo functions */
1257 /******************/
1258
1259 #define MAX_UNDO_TEST(x) \
1260         while (text->undo_pos+x >= text->undo_len) { \
1261                 if(text->undo_len*2 > TXT_MAX_UNDO) { \
1262                         error("Undo limit reached, buffer cleared\n"); \
1263                         MEM_freeN(text->undo_buf); \
1264                         text->undo_len= TXT_INIT_UNDO; \
1265                         text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); \
1266                         text->undo_pos=-1; \
1267                         return; \
1268                 } else { \
1269                         void *tmp= text->undo_buf; \
1270                         text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf"); \
1271                         memcpy(text->undo_buf, tmp, text->undo_len); \
1272                         text->undo_len*=2; \
1273                         MEM_freeN(tmp); \
1274                 } \
1275         }
1276
1277 static void dump_buffer(Text *text) 
1278 {
1279         int i= 0;
1280         
1281         while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
1282 }
1283
1284 void txt_print_undo(Text *text)
1285 {
1286         int i= 0;
1287         int op;
1288         char *ops;
1289         int linep, charp;
1290         
1291         dump_buffer(text);
1292         
1293         printf ("---< Undo Buffer >---\n");
1294         
1295         printf ("UndoPosition is %d\n", text->undo_pos);
1296         
1297         while (i<=text->undo_pos) {
1298                 op= text->undo_buf[i];
1299                 
1300                 if (op==UNDO_CLEFT) {
1301                         ops= "Cursor left";
1302                 } else if (op==UNDO_CRIGHT) {
1303                         ops= "Cursor right";
1304                 } else if (op==UNDO_CUP) {
1305                         ops= "Cursor up";
1306                 } else if (op==UNDO_CDOWN) {
1307                         ops= "Cursor down";
1308                 } else if (op==UNDO_SLEFT) {
1309                         ops= "Selection left";
1310                 } else if (op==UNDO_SRIGHT) {
1311                         ops= "Selection right";
1312                 } else if (op==UNDO_SUP) {
1313                         ops= "Selection up";
1314                 } else if (op==UNDO_SDOWN) {
1315                         ops= "Selection down";
1316                 } else if (op==UNDO_STO) {
1317                         ops= "Selection ";
1318                 } else if (op==UNDO_CTO) {
1319                         ops= "Cursor ";
1320                 } else if (op==UNDO_INSERT) {
1321                         ops= "Insert";
1322                 } else if (op==UNDO_BS) {
1323                         ops= "Backspace";
1324                 } else if (op==UNDO_DEL) {
1325                         ops= "Delete";
1326                 } else if (op==UNDO_SWAP) {
1327                         ops= "Cursor swap";
1328                 } else if (op==UNDO_DBLOCK) {
1329                         ops= "Delete text block";
1330                 } else if (op==UNDO_IBLOCK) {
1331                         ops= "Insert text block";
1332                 } else if (op==UNDO_INDENT) {
1333                         ops= "Indent ";
1334                 } else if (op==UNDO_UNINDENT) {
1335                         ops= "Unindent ";
1336                 } else if (op==UNDO_COMMENT) {
1337                         ops= "Comment ";
1338                 } else if (op==UNDO_UNCOMMENT) {
1339                         ops= "Uncomment ";
1340                 } else {
1341                         ops= "Unknown";
1342                 }
1343                 
1344                 printf ("Op (%o) at %d = %s", op, i, ops);
1345                 if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) {
1346                         i++;
1347                         printf (" - Char is %c", text->undo_buf[i]);  
1348                         i++;
1349                 } else if (op==UNDO_STO || op==UNDO_CTO) {
1350                         i++;
1351
1352                         charp= text->undo_buf[i]; i++;
1353                         charp= charp+(text->undo_buf[i]<<8); i++;
1354
1355                         linep= text->undo_buf[i]; i++;
1356                         linep= linep+(text->undo_buf[i]<<8); i++;
1357                         linep= linep+(text->undo_buf[i]<<16); i++;
1358                         linep= linep+(text->undo_buf[i]<<24); i++;
1359                         
1360                         printf ("to <%d, %d> ", linep, charp);
1361
1362                         charp= text->undo_buf[i]; i++;
1363                         charp= charp+(text->undo_buf[i]<<8); i++;
1364
1365                         linep= text->undo_buf[i]; i++;
1366                         linep= linep+(text->undo_buf[i]<<8); i++;
1367                         linep= linep+(text->undo_buf[i]<<16); i++;
1368                         linep= linep+(text->undo_buf[i]<<24); i++;
1369                         
1370                         printf ("from <%d, %d>", linep, charp);
1371                 } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
1372                         i++;
1373
1374                         linep= text->undo_buf[i]; i++;
1375                         linep= linep+(text->undo_buf[i]<<8); i++;
1376                         linep= linep+(text->undo_buf[i]<<16); i++;
1377                         linep= linep+(text->undo_buf[i]<<24); i++;
1378                         
1379                         printf (" (length %d) <", linep);
1380                         
1381                         while (linep>0) {
1382                                 putchar(text->undo_buf[i]);
1383                                 linep--; i++;
1384                         }
1385                         
1386                         linep= text->undo_buf[i]; i++;
1387                         linep= linep+(text->undo_buf[i]<<8); i++;
1388                         linep= linep+(text->undo_buf[i]<<16); i++;
1389                         linep= linep+(text->undo_buf[i]<<24); i++;
1390                         printf ("> (%d)", linep);
1391                 } else if (op==UNDO_INDENT || op==UNDO_UNINDENT) {
1392                         i++;
1393
1394                         charp= text->undo_buf[i]; i++;
1395                         charp= charp+(text->undo_buf[i]<<8); i++;
1396
1397                         linep= text->undo_buf[i]; i++;
1398                         linep= linep+(text->undo_buf[i]<<8); i++;
1399                         linep= linep+(text->undo_buf[i]<<16); i++;
1400                         linep= linep+(text->undo_buf[i]<<24); i++;
1401                         
1402                         printf ("to <%d, %d> ", linep, charp);
1403
1404                         charp= text->undo_buf[i]; i++;
1405                         charp= charp+(text->undo_buf[i]<<8); i++;
1406
1407                         linep= text->undo_buf[i]; i++;
1408                         linep= linep+(text->undo_buf[i]<<8); i++;
1409                         linep= linep+(text->undo_buf[i]<<16); i++;
1410                         linep= linep+(text->undo_buf[i]<<24); i++;
1411                         
1412                         printf ("from <%d, %d>", linep, charp);
1413                 }
1414                 
1415                 printf (" %d\n",  i);
1416                 i++;
1417         }
1418 }
1419
1420 static void txt_undo_add_op(Text *text, int op)
1421 {
1422         MAX_UNDO_TEST(2);
1423         
1424         text->undo_pos++;
1425         text->undo_buf[text->undo_pos]= op;
1426         text->undo_buf[text->undo_pos+1]= 0;
1427 }
1428
1429 static void txt_undo_add_block(Text *text, int op, char *buf)
1430 {
1431         int length;
1432         
1433         length= strlen(buf);
1434         
1435         MAX_UNDO_TEST(length+11);
1436
1437         text->undo_pos++;
1438         text->undo_buf[text->undo_pos]= op;
1439         
1440         text->undo_pos++;
1441         text->undo_buf[text->undo_pos]= (length)&0xff;
1442         text->undo_pos++;
1443         text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1444         text->undo_pos++;
1445         text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1446         text->undo_pos++;
1447         text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1448
1449         text->undo_pos++;
1450         strncpy(text->undo_buf+text->undo_pos, buf, length);
1451         text->undo_pos+=length;
1452
1453         text->undo_buf[text->undo_pos]= (length)&0xff;
1454         text->undo_pos++;
1455         text->undo_buf[text->undo_pos]= (length>>8)&0xff;
1456         text->undo_pos++;
1457         text->undo_buf[text->undo_pos]= (length>>16)&0xff;
1458         text->undo_pos++;
1459         text->undo_buf[text->undo_pos]= (length>>24)&0xff;
1460
1461         text->undo_pos++;
1462         text->undo_buf[text->undo_pos]= op;
1463         
1464         text->undo_buf[text->undo_pos+1]= 0;
1465 }
1466
1467 void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
1468 {
1469         MAX_UNDO_TEST(15);
1470
1471         if (froml==tol && fromc==toc) return;
1472
1473         text->undo_pos++;
1474         text->undo_buf[text->undo_pos]= op;
1475
1476         text->undo_pos++;
1477         text->undo_buf[text->undo_pos]= (fromc)&0xff;
1478         text->undo_pos++;
1479         text->undo_buf[text->undo_pos]= (fromc>>8)&0xff;
1480
1481         text->undo_pos++;
1482         text->undo_buf[text->undo_pos]= (froml)&0xff;
1483         text->undo_pos++;
1484         text->undo_buf[text->undo_pos]= (froml>>8)&0xff;
1485         text->undo_pos++;
1486         text->undo_buf[text->undo_pos]= (froml>>16)&0xff;
1487         text->undo_pos++;
1488         text->undo_buf[text->undo_pos]= (froml>>24)&0xff;
1489
1490         text->undo_pos++;
1491         text->undo_buf[text->undo_pos]= (toc)&0xff;
1492         text->undo_pos++;
1493         text->undo_buf[text->undo_pos]= (toc>>8)&0xff;
1494
1495         text->undo_pos++;
1496         text->undo_buf[text->undo_pos]= (tol)&0xff;
1497         text->undo_pos++;
1498         text->undo_buf[text->undo_pos]= (tol>>8)&0xff;
1499         text->undo_pos++;
1500         text->undo_buf[text->undo_pos]= (tol>>16)&0xff;
1501         text->undo_pos++;
1502         text->undo_buf[text->undo_pos]= (tol>>24)&0xff;
1503
1504         text->undo_pos++;
1505         text->undo_buf[text->undo_pos]= op;
1506
1507         text->undo_buf[text->undo_pos+1]= 0;
1508 }
1509
1510 static void txt_undo_add_charop(Text *text, int op, char c)
1511 {
1512         MAX_UNDO_TEST(4);
1513
1514         text->undo_pos++;
1515         text->undo_buf[text->undo_pos]= op;
1516         text->undo_pos++;
1517         text->undo_buf[text->undo_pos]= c;
1518         text->undo_pos++;
1519         text->undo_buf[text->undo_pos]= op;
1520         text->undo_buf[text->undo_pos+1]= 0;
1521 }
1522
1523 void txt_do_undo(Text *text)
1524 {
1525         int op= text->undo_buf[text->undo_pos];
1526         unsigned int linep, i;
1527         unsigned short charp;
1528         TextLine *holdl;
1529         int holdc, holdln;
1530         char *buf;
1531         
1532         if (text->undo_pos<0) {
1533                 return;
1534         }
1535
1536         text->undo_pos--;
1537
1538         undoing= 1;
1539         
1540         switch(op) {
1541                 case UNDO_CLEFT:
1542                         txt_move_right(text, 0);
1543                         break;
1544                         
1545                 case UNDO_CRIGHT:
1546                         txt_move_left(text, 0);
1547                         break;
1548                         
1549                 case UNDO_CUP:
1550                         txt_move_down(text, 0);
1551                         break;
1552                         
1553                 case UNDO_CDOWN:
1554                         txt_move_up(text, 0);
1555                         break;
1556
1557                 case UNDO_SLEFT:
1558                         txt_move_right(text, 1);
1559                         break;
1560
1561                 case UNDO_SRIGHT:
1562                         txt_move_left(text, 1);
1563                         break;
1564
1565                 case UNDO_SUP:
1566                         txt_move_down(text, 1);
1567                         break;
1568
1569                 case UNDO_SDOWN:
1570                         txt_move_up(text, 1);
1571                         break;
1572                 
1573                 case UNDO_CTO:
1574                 case UNDO_STO:
1575                         text->undo_pos--;
1576                         text->undo_pos--;
1577                         text->undo_pos--;
1578                         text->undo_pos--;
1579                 
1580                         text->undo_pos--;
1581                         text->undo_pos--;
1582                 
1583                         linep= 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                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1587
1588                         charp= text->undo_buf[text->undo_pos]; text->undo_pos--;
1589                         charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1590                         
1591                         if (op==UNDO_CTO) {
1592                                 txt_move_toline(text, linep, 0);
1593                                 text->curc= charp;
1594                                 txt_pop_sel(text);
1595                         } else {
1596                                 txt_move_toline(text, linep, 1);
1597                                 text->selc= charp;
1598                         }
1599                         
1600                         text->undo_pos--;
1601                         break;
1602                         
1603                 case UNDO_INSERT:
1604                         txt_backspace_char(text);
1605                         text->undo_pos--;
1606                         text->undo_pos--;
1607                         break;
1608
1609                 case UNDO_BS:
1610                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1611                         text->undo_pos--;
1612                         text->undo_pos--;
1613                         break;
1614
1615                 case UNDO_DEL:
1616                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1617                         txt_move_left(text, 0);
1618                         text->undo_pos--;
1619                         text->undo_pos--;
1620                         break;
1621
1622                 case UNDO_SWAP:
1623                         txt_curs_swap(text);
1624                         txt_do_undo(text); /* swaps should appear transparent */
1625                         break;
1626
1627                 case UNDO_DBLOCK:
1628                         linep= 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                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1632
1633                         buf= MEM_mallocN(linep+1, "dblock buffer");
1634                         for (i=0; i < linep; i++){
1635                                 buf[(linep-1)-i]= text->undo_buf[text->undo_pos]; 
1636                                 text->undo_pos--;
1637                         }
1638                         buf[i]= 0;
1639                         
1640                         txt_curs_first(text, &holdl, &holdc);
1641                         holdln= txt_get_span(text->lines.first, holdl);
1642                         
1643                         txt_insert_buf(text, buf);                      
1644                         MEM_freeN(buf);
1645
1646                         text->curl= text->lines.first;
1647                         while (holdln>0) {
1648                                 if(text->curl->next)
1649                                         text->curl= text->curl->next;
1650                                         
1651                                 holdln--;
1652                         }
1653                         text->curc= holdc;
1654
1655                         linep= 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                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1659
1660                         text->undo_pos--;
1661                         
1662                         break;
1663
1664                 case UNDO_IBLOCK:
1665                         linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
1666                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1667                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1668                         linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1669
1670                         txt_delete_sel(text);
1671                         while (linep>0) {
1672                                 txt_backspace_char(text);
1673                                 text->undo_pos--;
1674                                 linep--;
1675                         }
1676
1677                         text->undo_pos--;
1678                         text->undo_pos--;
1679                         text->undo_pos--; 
1680                         text->undo_pos--;
1681                         
1682                         text->undo_pos--;
1683
1684                         break;
1685                 case UNDO_INDENT:
1686                 case UNDO_UNINDENT:
1687                 case UNDO_COMMENT:
1688                 case UNDO_UNCOMMENT:
1689                         linep= 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 = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1693                         //linep is now the end line of the selection
1694                         
1695                         charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1696                         charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1697                         //charp is the last char selected or text->line->len
1698                         //set the selcetion for this now
1699                         text->selc = charp;
1700                         text->sell = text->lines.first;
1701                         for (i= 0; i < linep; i++) {
1702                                 text->sell = text->sell->next;
1703                         }
1704
1705                         linep= 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                         linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1709                         //first line to be selected
1710                         
1711                         charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
1712                         charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
1713                         //first postion to be selected
1714                         text->curc = charp;
1715                         text->curl = text->lines.first;
1716                         for (i = 0; i < linep; i++) {
1717                                 text->curl = text->curl->next;
1718                         }
1719
1720                         
1721                         if (op==UNDO_INDENT) {
1722                                 unindent(text);
1723                         } else if (op== UNDO_UNINDENT) {
1724                                 indent(text);
1725                         } else if (op == UNDO_COMMENT) {
1726                                 uncomment(text);
1727                         } else if (op == UNDO_UNCOMMENT) {
1728                                 comment(text);
1729                         }
1730
1731                         text->undo_pos--;
1732                         break;
1733                 default:
1734                         error("Undo buffer error - resetting");
1735                         text->undo_pos= -1;
1736                         
1737                         break;
1738         }
1739         
1740         undoing= 0;     
1741 }
1742
1743 void txt_do_redo(Text *text)
1744 {
1745         char op;
1746         unsigned int linep, i;
1747         unsigned short charp;
1748         char *buf;
1749         
1750         text->undo_pos++;       
1751         op= text->undo_buf[text->undo_pos];
1752         
1753         if (!op) {
1754                 text->undo_pos--;
1755                 return;
1756         }
1757         
1758         undoing= 1;
1759
1760         switch(op) {
1761                 case UNDO_CLEFT:
1762                         txt_move_left(text, 0);
1763                         break;
1764                         
1765                 case UNDO_CRIGHT:
1766                         txt_move_right(text, 0);
1767                         break;
1768                         
1769                 case UNDO_CUP:
1770                         txt_move_up(text, 0);
1771                         break;
1772                         
1773                 case UNDO_CDOWN:
1774                         txt_move_down(text, 0);
1775                         break;
1776
1777                 case UNDO_SLEFT:
1778                         txt_move_left(text, 1);
1779                         break;
1780
1781                 case UNDO_SRIGHT:
1782                         txt_move_right(text, 1);
1783                         break;
1784
1785                 case UNDO_SUP:
1786                         txt_move_up(text, 1);
1787                         break;
1788
1789                 case UNDO_SDOWN:
1790                         txt_move_down(text, 1);
1791                         break;
1792                 
1793                 case UNDO_INSERT:
1794                         text->undo_pos++;
1795                         txt_add_char(text, text->undo_buf[text->undo_pos]);
1796                         text->undo_pos++;
1797                         break;
1798
1799                 case UNDO_BS:
1800                         text->undo_pos++;
1801                         txt_backspace_char(text);
1802                         text->undo_pos++;
1803                         break;
1804
1805                 case UNDO_DEL:
1806                         text->undo_pos++;
1807                         txt_delete_char(text);
1808                         text->undo_pos++;
1809                         break;
1810
1811                 case UNDO_SWAP:
1812                         txt_curs_swap(text);
1813                         txt_do_undo(text); /* swaps should appear transparent a*/
1814                         break;
1815                         
1816                 case UNDO_CTO:
1817                 case UNDO_STO:
1818                         text->undo_pos++;
1819                         text->undo_pos++;
1820
1821                         text->undo_pos++;
1822                         text->undo_pos++;
1823                         text->undo_pos++;
1824                         text->undo_pos++;
1825
1826                         text->undo_pos++;
1827
1828                         charp= text->undo_buf[text->undo_pos];
1829                         text->undo_pos++;
1830                         charp= charp+(text->undo_buf[text->undo_pos]<<8);
1831
1832                         text->undo_pos++;
1833                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1834                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1835                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1836                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
1837                         
1838                         if (op==UNDO_CTO) {
1839                                 txt_move_toline(text, linep, 0);
1840                                 text->curc= charp;
1841                                 txt_pop_sel(text);
1842                         } else {
1843                                 txt_move_toline(text, linep, 1);
1844                                 text->selc= charp;
1845                         }
1846
1847                         break;
1848
1849                 case UNDO_DBLOCK:
1850                         text->undo_pos++;
1851                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1852                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1853                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1854                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
1855
1856                         txt_delete_sel(text);
1857                         text->undo_pos+=linep;
1858
1859                         text->undo_pos++;
1860                         text->undo_pos++;
1861                         text->undo_pos++; 
1862                         text->undo_pos++;
1863                         
1864                         break;
1865
1866                 case UNDO_IBLOCK:
1867                         text->undo_pos++;
1868                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1869                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1870                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1871                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
1872
1873                         buf= MEM_mallocN(linep+1, "iblock buffer");
1874                         memcpy (buf, &text->undo_buf[text->undo_pos], linep);
1875                         text->undo_pos+= linep;
1876                         buf[linep]= 0;
1877                         
1878                         txt_insert_buf(text, buf);                      
1879                         MEM_freeN(buf);
1880
1881                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1882                         linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1883                         linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1884                         linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
1885
1886                         break;
1887                 case UNDO_INDENT:
1888                 case UNDO_UNINDENT:
1889                 case UNDO_COMMENT:
1890                 case UNDO_UNCOMMENT:
1891                         text->undo_pos++;
1892                         charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
1893                         charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1894                         //charp is the first char selected or 0
1895                         
1896                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1897                         linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1898                         linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1899                         linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
1900                         //linep is now the first line of the selection                  
1901                         //set the selcetion for this now
1902                         text->curc = charp;
1903                         text->curl = text->lines.first;
1904                         for (i= 0; i < linep; i++) {
1905                                 text->curl = text->curl->next;
1906                         }
1907                         
1908                         charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
1909                         charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1910                         //last postion to be selected
1911                         linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
1912                         linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
1913                         linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
1914                         linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
1915                         //Last line to be selected
1916                         
1917                         text->selc = charp;
1918                         text->sell = text->lines.first;
1919                         for (i = 0; i < linep; i++) {
1920                                 text->sell = text->sell->next;
1921                         }
1922
1923                         if (op==UNDO_INDENT) {
1924                                 indent(text);
1925                         } else if (op== UNDO_UNINDENT) {
1926                                 unindent(text);
1927                         } else if (op == UNDO_COMMENT) {
1928                                 comment(text);
1929                         } else if (op == UNDO_UNCOMMENT) {
1930                                 uncomment(text);
1931                         }
1932                         break;
1933                 default:
1934                         error("Undo buffer error - resetting");
1935                         text->undo_pos= -1;
1936
1937                         break;
1938         }
1939         
1940         undoing= 0;     
1941 }
1942
1943 /**************************/
1944 /* Line editing functions */ 
1945 /**************************/
1946
1947 void txt_split_curline (Text *text) 
1948 {
1949         TextLine *ins;
1950         char *left, *right, *fleft, *fright;
1951         
1952         if (!text) return;
1953         if (!text->curl) return;
1954
1955         txt_delete_sel(text);   
1956
1957         /* Make the two half strings */
1958
1959         left= MEM_mallocN(text->curc+1, "textline_string");
1960         fleft= MEM_mallocN(text->curc+2, "Syntax_format");
1961         if (text->curc) memcpy(left, text->curl->line, text->curc);
1962         left[text->curc]=0;
1963         
1964         right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
1965         fright= MEM_mallocN(text->curl->len - text->curc+2, "Syntax_format");
1966         if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc);
1967         right[text->curl->len - text->curc]=0;
1968
1969         MEM_freeN(text->curl->line);
1970         if (text->curl->format) MEM_freeN(text->curl->format);
1971
1972         /* Make the new TextLine */
1973         
1974         ins= MEM_mallocN(sizeof(TextLine), "textline");
1975         ins->line= left;
1976         ins->format= fleft;
1977         ins->len= text->curc;
1978         
1979         text->curl->line= right;
1980         text->curl->format= fright;
1981         text->curl->len= text->curl->len - text->curc;
1982         
1983         BLI_insertlinkbefore(&text->lines, text->curl, ins);    
1984         
1985         text->curc=0;
1986         
1987         txt_make_dirty(text);
1988         txt_clean_text(text);
1989         
1990         txt_pop_sel(text);
1991         if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n');
1992 }
1993
1994 static void txt_delete_line (Text *text, TextLine *line) 
1995 {
1996         if (!text) return;
1997         if (!text->curl) return;
1998
1999         BLI_remlink (&text->lines, line);
2000         
2001         if (line->line) MEM_freeN(line->line);
2002         if (line->format) MEM_freeN(line->format);
2003
2004         MEM_freeN(line);
2005
2006         txt_make_dirty(text);
2007         txt_clean_text(text);
2008 }
2009
2010 static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
2011 {
2012         char *tmp, *format;
2013         
2014         if (!text) return;
2015         
2016         if(!linea || !lineb) return;
2017         
2018         tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
2019         format= MEM_mallocN(linea->len+lineb->len+1, "Syntax_format");
2020         
2021         strcpy(tmp, linea->line);
2022         strcat(tmp, lineb->line);
2023
2024         make_new_line(linea, tmp, format);
2025         
2026         txt_delete_line(text, lineb); 
2027         
2028         txt_make_dirty(text);
2029         txt_clean_text(text);
2030 }
2031
2032 void txt_delete_char (Text *text) 
2033 {
2034         char c='\n';
2035         
2036         if (!text) return;
2037         if (!text->curl) return;
2038
2039         if (txt_has_sel(text)) { /* deleting a selection */
2040           txt_delete_sel(text);
2041           return;
2042         }
2043         else if (text->curc== text->curl->len) { /* Appending two lines */
2044                 if (text->curl->next) {
2045                         txt_combine_lines(text, text->curl, text->curl->next);
2046                         txt_pop_sel(text);
2047                 }
2048         } else { /* Just deleting a char */
2049                 int i= text->curc;
2050                 
2051                 c= text->curl->line[i];
2052                 while(i< text->curl->len) {
2053                         text->curl->line[i]= text->curl->line[i+1];
2054                         i++;
2055                 }
2056                 text->curl->len--;
2057
2058                 txt_pop_sel(text);
2059         }
2060
2061         txt_make_dirty(text);
2062         txt_clean_text(text);
2063         
2064         if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c);
2065 }
2066
2067 void txt_backspace_char (Text *text) 
2068 {
2069         char c='\n';
2070         
2071         if (!text) return;
2072         if (!text->curl) return;
2073         
2074         if (txt_has_sel(text)) { /* deleting a selection */
2075           txt_delete_sel(text);
2076           return;
2077         }
2078         else if (text->curc==0) { /* Appending two lines */
2079                 if (!text->curl->prev) return;
2080                 
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         else { /* Just backspacing a char */
2088           int i= text->curc-1;
2089                 
2090           c= text->curl->line[i];
2091           while(i< text->curl->len) {
2092             text->curl->line[i]= text->curl->line[i+1];
2093             i++;
2094           }
2095           text->curl->len--;
2096           text->curc--;
2097                 
2098           txt_pop_sel(text);
2099         }
2100
2101         txt_make_dirty(text);
2102         txt_clean_text(text);
2103         
2104         if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
2105 }
2106
2107 int txt_add_char (Text *text, char add) 
2108 {
2109         int len;
2110         char *tmp, *format;
2111         
2112         if (!text) return 0;
2113         if (!text->curl) return 0;
2114
2115         if (add=='\n') {
2116                 txt_split_curline(text);
2117                 return 1;
2118         }
2119         
2120         txt_delete_sel(text);
2121         
2122         tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2123         format= MEM_mallocN(text->curl->len+4, "Syntax_format");
2124         
2125         if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2126         tmp[text->curc]= add;
2127         
2128         len= text->curl->len - text->curc;
2129         if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2130         tmp[text->curl->len+1]=0;
2131         make_new_line(text->curl, tmp, format);
2132                 
2133         text->curc++;
2134
2135         txt_pop_sel(text);
2136         
2137         txt_make_dirty(text);
2138         txt_clean_text(text);
2139
2140         if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add);
2141         return 1;
2142 }
2143
2144 void indent(Text *text)
2145 {
2146         int len, num;
2147         char *tmp, *format;
2148         char add = '\t';
2149         
2150         if (!text) return;
2151         if (!text->curl) return;
2152         if (!text->sell) return;
2153
2154         num = 0;
2155         while (TRUE)
2156         {
2157                 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2158                 format= MEM_mallocN(text->curl->len+3, "Syntax_format");
2159                 
2160                 text->curc = 0; 
2161                 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2162                 tmp[text->curc]= add;
2163                 
2164                 len= text->curl->len - text->curc;
2165                 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2166                 tmp[text->curl->len+1]=0;
2167
2168                 make_new_line(text->curl, tmp, format);
2169                         
2170                 text->curc++;
2171                 
2172                 txt_make_dirty(text);
2173                 txt_clean_text(text);
2174                 
2175                 if(text->curl == text->sell) 
2176                 {
2177                         text->selc = text->sell->len;
2178                         break;
2179                 } else {
2180                         text->curl = text->curl->next;
2181                         num++;
2182                 }
2183         }
2184         text->curc = 0;
2185         while( num > 0 )
2186         {
2187                 text->curl = text->curl->prev;
2188                 num--;
2189         }
2190         
2191         if(!undoing) 
2192         {
2193                 txt_undo_add_toop(text, UNDO_INDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2194         }
2195 }
2196
2197 void unindent(Text *text)
2198 {
2199         int num = 0;
2200         char remove = '\t';
2201         
2202         if (!text) return;
2203         if (!text->curl) return;
2204         if (!text->sell) return;
2205
2206         while(TRUE)
2207         {
2208                 int i = 0;
2209                 
2210                 if (text->curl->line[i] == remove)
2211                 {
2212                         while(i< text->curl->len) {
2213                                 text->curl->line[i]= text->curl->line[i+1];
2214                                 i++;
2215                         }
2216                         text->curl->len--;
2217                 }
2218                          
2219         
2220                 txt_make_dirty(text);
2221                 txt_clean_text(text);
2222                 
2223                 if(text->curl == text->sell) 
2224                 {
2225                         text->selc = text->sell->len;
2226                         break;
2227                 } else {
2228                         text->curl = text->curl->next;
2229                         num++;
2230                 }
2231                 
2232         }
2233         text->curc = 0;
2234         while( num > 0 )
2235         {
2236                 text->curl = text->curl->prev;
2237                 num--;
2238         }
2239         
2240         if(!undoing) 
2241         {
2242                 txt_undo_add_toop(text, UNDO_UNINDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2243         }
2244 }
2245
2246 void comment(Text *text)
2247 {
2248         int len, num;
2249         char *tmp, *format;
2250         char add = '#';
2251         
2252         if (!text) return;
2253         if (!text->curl) return;
2254         if (!text->sell) return;// Need to change this need to check if only one line is selected ot more then one
2255
2256         num = 0;
2257         while (TRUE)
2258         {
2259                 tmp= MEM_mallocN(text->curl->len+2, "textline_string");
2260                 format = MEM_mallocN(text->curl->len+3, "Syntax_format");
2261                 
2262                 text->curc = 0; 
2263                 if(text->curc) memcpy(tmp, text->curl->line, text->curc);
2264                 tmp[text->curc]= add;
2265                 
2266                 len= text->curl->len - text->curc;
2267                 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
2268                 tmp[text->curl->len+1]=0;
2269
2270                 make_new_line(text->curl, tmp, format);
2271                         
2272                 text->curc++;
2273                 
2274                 txt_make_dirty(text);
2275                 txt_clean_text(text);
2276                 
2277                 if(text->curl == text->sell) 
2278                 {
2279                         text->selc = text->sell->len;
2280                         break;
2281                 } else {
2282                         text->curl = text->curl->next;
2283                         num++;
2284                 }
2285         }
2286         text->curc = 0;
2287         while( num > 0 )
2288         {
2289                 text->curl = text->curl->prev;
2290                 num--;
2291         }
2292         
2293         if(!undoing) 
2294         {
2295                 txt_undo_add_toop(text, UNDO_COMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2296         }
2297 }
2298
2299 void uncomment(Text *text)
2300 {
2301         int num = 0;
2302         char remove = '#';
2303         
2304         if (!text) return;
2305         if (!text->curl) return;
2306         if (!text->sell) return;
2307
2308         while(TRUE)
2309         {
2310                 int i = 0;
2311                 
2312                 if (text->curl->line[i] == remove)
2313                 {
2314                         while(i< text->curl->len) {
2315                                 text->curl->line[i]= text->curl->line[i+1];
2316                                 i++;
2317                         }
2318                         text->curl->len--;
2319                 }
2320                          
2321         
2322                 txt_make_dirty(text);
2323                 txt_clean_text(text);
2324                 
2325                 if(text->curl == text->sell) 
2326                 {
2327                         text->selc = text->sell->len;
2328                         break;
2329                 } else {
2330                         text->curl = text->curl->next;
2331                         num++;
2332                 }
2333                 
2334         }
2335         text->curc = 0;
2336         while( num > 0 )
2337         {
2338                 text->curl = text->curl->prev;
2339                 num--;
2340         }
2341         
2342         if(!undoing) 
2343         {
2344                 txt_undo_add_toop(text, UNDO_UNCOMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
2345         }
2346 }
2347
2348 int setcurr_tab (Text *text)
2349 {
2350         int i = 0;
2351         int test = 0;
2352         char *word = ":";
2353         char *comm = "#";
2354         char back_words[4][7] = {"return", "break", "pass", "yield"};
2355         if (!text) return 0;
2356         if (!text->curl) return 0;
2357         
2358         while (text->curl->line[i] == '\t')
2359         {
2360                 //we only count thos tabs that are before any text or before the curs;
2361                 if (i == text->curc)
2362                 {
2363                         return i;
2364                 } else {
2365                         i++;
2366                 }
2367         }
2368         if(strstr(text->curl->line, word))
2369         {
2370                 //if we find a : then add a tab but not if it is in a comment
2371                 int a, indent = 0;
2372                 for(a=0; text->curl->line[a] != '\0'; a++)
2373                 {
2374                         if (text->curl->line[a]=='#') {
2375                                 break;
2376                         } else if (text->curl->line[a]==':') {
2377                                 indent = 1;
2378                         } else if (text->curl->line[a]==']') {
2379                                 indent = 0;
2380                         }
2381                 }
2382                 if (indent) {
2383                         i++;
2384                 }
2385         }
2386
2387         for(test=0; test < 4; test++)
2388         {
2389                 //if there are these 4 key words then remove a tab because we are done with the block
2390                 if(strstr(text->curl->line, back_words[test]) && i > 0)
2391                 {
2392                         if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
2393                         {
2394                                 i--;
2395                         }
2396                 }
2397         }
2398         return i;
2399 }
2400