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