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