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