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