Revert to master - those changes are globally valid, but remain incomplete,
[blender.git] / source / blender / blenkernel / intern / text.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/blenkernel/intern/text.c
29  *  \ingroup bke
30  */
31
32 #include <stdlib.h> /* abort */
33 #include <string.h> /* strstr */
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <wchar.h>
37 #include <wctype.h>
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_utildefines.h"
42 #include "BLI_path_util.h"
43 #include "BLI_string.h"
44 #include "BLI_string_cursor_utf8.h"
45 #include "BLI_string_utf8.h"
46 #include "BLI_listbase.h"
47 #include "BLI_fileops.h"
48
49 #include "DNA_constraint_types.h"
50 #include "DNA_controller_types.h"
51 #include "DNA_actuator_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_screen_types.h"
54 #include "DNA_space_types.h"
55 #include "DNA_text_types.h"
56 #include "DNA_userdef_types.h"
57 #include "DNA_object_types.h"
58 #include "DNA_node_types.h"
59 #include "DNA_material_types.h"
60
61 #include "BKE_depsgraph.h"
62 #include "BKE_global.h"
63 #include "BKE_library.h"
64 #include "BKE_main.h"
65 #include "BKE_text.h"
66 #include "BKE_node.h"
67
68
69 #ifdef WITH_PYTHON
70 #include "BPY_extern.h"
71 #endif
72
73 /*
74  * How Texts should work
75  * --
76  * A text should relate to a file as follows -
77  * (Text *)->name should be the place where the
78  *     file will or has been saved.
79  *
80  * (Text *)->flags has the following bits
81  *     TXT_ISDIRTY - should always be set if the file in mem. differs from
82  *                     the file on disk, or if there is no file on disk.
83  *     TXT_ISMEM - should always be set if the Text has not been mapped to
84  *                     a file, in which case (Text *)->name may be NULL or garbage.
85  *     TXT_ISEXT - should always be set if the Text is not to be written into
86  *                     the .blend
87  *     TXT_ISSCRIPT - should be set if the user has designated the text
88  *                     as a script. (NEW: this was unused, but now it is needed by
89  *                     space handler script links (see header_view3d.c, for example)
90  *
91  * ->>> see also: /makesdna/DNA_text_types.h
92  *
93  * Display
94  * --
95  * The st->top determines at what line the top of the text is displayed.
96  * If the user moves the cursor the st containing that cursor should
97  * be popped ... other st's retain their own top location.
98  *
99  * Undo
100  * --
101  * Undo/Redo works by storing
102  * events in a queue, and a pointer
103  * to the current position in the
104  * queue...
105  *
106  * Events are stored using an
107  * arbitrary op-code system
108  * to keep track of
109  * a) the two cursors (normal and selected)
110  * b) input (visible and control (ie backspace))
111  *
112  * input data is stored as its
113  * ASCII value, the opcodes are
114  * then selected to not conflict.
115  *
116  * opcodes with data in between are
117  * written at the beginning and end
118  * of the data to allow undo and redo
119  * to simply check the code at the current
120  * undo position
121  *
122  */
123
124 /***/
125
126 static void txt_pop_first(Text *text);
127 static void txt_pop_last(Text *text);
128 static void txt_undo_add_blockop(Text *text, int op, const char *buf);
129 static void txt_delete_line(Text *text, TextLine *line);
130 static void txt_delete_sel(Text *text);
131 static void txt_make_dirty(Text *text);
132
133 /***/
134
135 static unsigned char undoing;
136
137 /* allow to switch off undoing externally */
138 void txt_set_undostate(int u)
139 {
140         undoing = u;
141 }
142
143 int txt_get_undostate(void)
144 {
145         return undoing;
146 }
147
148 static void init_undo_text(Text *text)
149 {
150         text->undo_pos = -1;
151         text->undo_len = TXT_INIT_UNDO;
152         text->undo_buf = MEM_mallocN(text->undo_len, "undo buf");
153 }
154
155 void BKE_text_free(Text *text)
156 {
157         TextLine *tmp;
158
159         for (tmp = text->lines.first; tmp; tmp = tmp->next) {
160                 MEM_freeN(tmp->line);
161                 if (tmp->format)
162                         MEM_freeN(tmp->format);
163         }
164         
165         BLI_freelistN(&text->lines);
166
167         if (text->name) MEM_freeN(text->name);
168         MEM_freeN(text->undo_buf);
169 #ifdef WITH_PYTHON
170         if (text->compiled) BPY_text_free_code(text);
171 #endif
172 }
173
174 Text *BKE_text_add(Main *bmain, const char *name) 
175 {
176         Text *ta;
177         TextLine *tmp;
178         
179         ta = BKE_libblock_alloc(bmain, ID_TXT, name);
180         ta->id.us = 1;
181         
182         ta->name = NULL;
183
184         init_undo_text(ta);
185
186         ta->nlines = 1;
187         ta->flags = TXT_ISDIRTY | TXT_ISMEM;
188         if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0)
189                 ta->flags |= TXT_TABSTOSPACES;
190
191         BLI_listbase_clear(&ta->lines);
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 replaces extended ascii characters */
214 /* to a valid utf-8 sequences */
215 int txt_extended_ascii_as_utf8(char **str)
216 {
217         int bad_char, added = 0, i = 0;
218         int length = strlen(*str);
219
220         while ((*str)[i]) {
221                 if ((bad_char = BLI_utf8_invalid_byte(*str + i, length - i)) == -1)
222                         break;
223
224                 added++;
225                 i += bad_char + 1;
226         }
227         
228         if (added != 0) {
229                 char *newstr = MEM_mallocN(length + added + 1, "text_line");
230                 int mi = 0;
231                 i = 0;
232                 
233                 while ((*str)[i]) {
234                         if ((bad_char = BLI_utf8_invalid_byte((*str) + i, length - i)) == -1) {
235                                 memcpy(newstr + mi, (*str) + i, length - i + 1);
236                                 break;
237                         }
238                         
239                         memcpy(newstr + mi, (*str) + i, bad_char);
240
241                         BLI_str_utf8_from_unicode((*str)[i + bad_char], newstr + mi + bad_char);
242                         i += bad_char + 1;
243                         mi += bad_char + 2;
244                 }
245                 newstr[length + added] = '\0';
246                 MEM_freeN(*str);
247                 *str = newstr;
248         }
249         
250         return added;
251 }
252
253 // this function removes any control characters from
254 // a textline and fixes invalid utf-8 sequences
255
256 static void cleanup_textline(TextLine *tl)
257 {
258         int i;
259
260         for (i = 0; i < tl->len; i++) {
261                 if (tl->line[i] < ' ' && tl->line[i] != '\t') {
262                         memmove(tl->line + i, tl->line + i + 1, tl->len - i);
263                         tl->len--;
264                         i--;
265                 }
266         }
267         tl->len += txt_extended_ascii_as_utf8(&tl->line);
268 }
269
270 /**
271  * used for load and reload (unlike txt_insert_buf)
272  * assumes all fields are empty
273  */
274 static void text_from_buf(Text *text, const unsigned char *buffer, const int len)
275 {
276         int i, llen;
277
278         BLI_assert(BLI_listbase_is_empty(&text->lines));
279
280         text->nlines = 0;
281         llen = 0;
282         for (i = 0; i < len; i++) {
283                 if (buffer[i] == '\n') {
284                         TextLine *tmp;
285
286                         tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
287                         tmp->line = (char *) MEM_mallocN(llen + 1, "textline_string");
288                         tmp->format = NULL;
289
290                         if (llen) memcpy(tmp->line, &buffer[i - llen], llen);
291                         tmp->line[llen] = 0;
292                         tmp->len = llen;
293
294                         cleanup_textline(tmp);
295
296                         BLI_addtail(&text->lines, tmp);
297                         text->nlines++;
298
299                         llen = 0;
300                         continue;
301                 }
302                 llen++;
303         }
304
305         /* create new line in cases:
306          * - rest of line (if last line in file hasn't got \n terminator).
307          *   in this case content of such line would be used to fill text line buffer
308          * - file is empty. in this case new line is needed to start editing from.
309          * - last characted in buffer is \n. in this case new line is needed to
310          *   deal with newline at end of file. (see [#28087]) (sergey) */
311         if (llen != 0 || text->nlines == 0 || buffer[len - 1] == '\n') {
312                 TextLine *tmp;
313
314                 tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
315                 tmp->line = (char *) MEM_mallocN(llen + 1, "textline_string");
316                 tmp->format = NULL;
317
318                 if (llen) memcpy(tmp->line, &buffer[i - llen], llen);
319
320                 tmp->line[llen] = 0;
321                 tmp->len = llen;
322
323                 cleanup_textline(tmp);
324
325                 BLI_addtail(&text->lines, tmp);
326                 text->nlines++;
327         }
328
329         text->curl = text->sell = text->lines.first;
330         text->curc = text->selc = 0;
331 }
332
333 bool BKE_text_reload(Text *text)
334 {
335         FILE *fp;
336         int len;
337         unsigned char *buffer;
338         TextLine *tmp;
339         char str[FILE_MAX];
340         BLI_stat_t st;
341
342         if (!text->name) {
343                 return false;
344         }
345
346         BLI_strncpy(str, text->name, FILE_MAX);
347         BLI_path_abs(str, G.main->name);
348         
349         fp = BLI_fopen(str, "r");
350         if (fp == NULL) {
351                 return false;
352         }
353         fseek(fp, 0L, SEEK_END);
354         len = ftell(fp);
355         fseek(fp, 0L, SEEK_SET);
356         if (UNLIKELY(len == -1)) {
357                 fclose(fp);
358                 return false;
359         }
360
361         /* free memory: */
362
363         for (tmp = text->lines.first; tmp; tmp = tmp->next) {
364                 MEM_freeN(tmp->line);
365                 if (tmp->format) MEM_freeN(tmp->format);
366         }
367         
368         BLI_freelistN(&text->lines);
369
370         BLI_listbase_clear(&text->lines);
371         text->curl = text->sell = NULL;
372
373         /* clear undo buffer */
374         MEM_freeN(text->undo_buf);
375         init_undo_text(text);
376
377         buffer = MEM_mallocN(len, "text_buffer");
378         /* under windows fread can return less than len bytes because
379          * of CR stripping */
380         len = fread(buffer, 1, len, fp);
381
382         fclose(fp);
383
384         if (BLI_stat(str, &st) != -1) {
385                 text->mtime = st.st_mtime;
386         }
387         else {
388                 text->mtime = 0;
389         }
390
391         text_from_buf(text, buffer, len);
392
393         MEM_freeN(buffer);
394         return true;
395 }
396
397 Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
398 {
399         FILE *fp;
400         int len;
401         unsigned char *buffer;
402         Text *ta;
403         char str[FILE_MAX];
404         BLI_stat_t st;
405
406         BLI_strncpy(str, file, FILE_MAX);
407         if (relpath) /* can be NULL (bg mode) */
408                 BLI_path_abs(str, relpath);
409         
410         fp = BLI_fopen(str, "r");
411         if (fp == NULL) {
412                 return NULL;
413         }
414
415         fseek(fp, 0L, SEEK_END);
416         len = ftell(fp);
417         fseek(fp, 0L, SEEK_SET);
418         if (UNLIKELY(len == -1)) {
419                 fclose(fp);
420                 return NULL;
421         }
422
423         ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(str));
424         ta->id.us = 1;
425
426         BLI_listbase_clear(&ta->lines);
427         ta->curl = ta->sell = NULL;
428
429         if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0)
430                 ta->flags = TXT_TABSTOSPACES;
431
432         if (is_internal == false) {
433                 ta->name = MEM_mallocN(strlen(file) + 1, "text_name");
434                 strcpy(ta->name, file);
435         }
436         else {
437                 ta->flags |= TXT_ISMEM | TXT_ISDIRTY;
438         }
439
440         /* clear undo buffer */
441         init_undo_text(ta);
442         
443         buffer = MEM_mallocN(len, "text_buffer");
444         /* under windows fread can return less than len bytes because
445          * of CR stripping */
446         len = fread(buffer, 1, len, fp);
447
448         fclose(fp);
449
450         if (BLI_stat(str, &st) != -1) {
451                 ta->mtime = st.st_mtime;
452         }
453         else {
454                 ta->mtime = 0;
455         }
456         
457         text_from_buf(ta, buffer, len);
458         
459         MEM_freeN(buffer);
460
461         return ta;
462 }
463
464 Text *BKE_text_load(Main *bmain, const char *file, const char *relpath)
465 {
466         return BKE_text_load_ex(bmain, file, relpath, false);
467 }
468
469 Text *BKE_text_copy(Main *bmain, Text *ta)
470 {
471         Text *tan;
472         TextLine *line, *tmp;
473         
474         tan = BKE_libblock_copy(&ta->id);
475         
476         /* file name can be NULL */
477         if (ta->name) {
478                 tan->name = BLI_strdup(ta->name);
479         }
480         else {
481                 tan->name = NULL;
482         }
483
484         tan->flags = ta->flags | TXT_ISDIRTY;
485         
486         BLI_listbase_clear(&tan->lines);
487         tan->curl = tan->sell = NULL;
488         tan->compiled = NULL;
489         
490         tan->nlines = ta->nlines;
491
492         line = ta->lines.first;
493         /* Walk down, reconstructing */
494         while (line) {
495                 tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
496                 tmp->line = MEM_mallocN(line->len + 1, "textline_string");
497                 tmp->format = NULL;
498                 
499                 strcpy(tmp->line, line->line);
500
501                 tmp->len = line->len;
502                 
503                 BLI_addtail(&tan->lines, tmp);
504                 
505                 line = line->next;
506         }
507
508         tan->curl = tan->sell = tan->lines.first;
509         tan->curc = tan->selc = 0;
510
511         init_undo_text(tan);
512
513         if (ta->id.lib) {
514                 BKE_id_lib_local_paths(bmain, ta->id.lib, &tan->id);
515         }
516
517         return tan;
518 }
519
520 void BKE_text_unlink(Main *bmain, Text *text)
521 {
522         bScreen *scr;
523         ScrArea *area;
524         SpaceLink *sl;
525         Object *ob;
526         bController *cont;
527         bActuator *act;
528         bConstraint *con;
529         bNodeTree *ntree;
530         bNode *node;
531         Material *mat;
532         Lamp *la;
533         Tex *te;
534         World *wo;
535         FreestyleLineStyle *linestyle;
536         Scene *sce;
537         SceneRenderLayer *srl;
538         FreestyleModuleConfig *module;
539         bool update;
540
541         for (ob = bmain->object.first; ob; ob = ob->id.next) {
542                 /* game controllers */
543                 for (cont = ob->controllers.first; cont; cont = cont->next) {
544                         if (cont->type == CONT_PYTHON) {
545                                 bPythonCont *pc;
546                                 
547                                 pc = cont->data;
548                                 if (pc->text == text) pc->text = NULL;
549                         }
550                 }
551                 /* game actuators */
552                 for (act = ob->actuators.first; act; act = act->next) {
553                         if (act->type == ACT_2DFILTER) {
554                                 bTwoDFilterActuator *tfa;
555                                 
556                                 tfa = act->data;
557                                 if (tfa->text == text) tfa->text = NULL;
558                         }
559                 }
560
561                 /* pyconstraints */
562                 update = 0;
563
564                 if (ob->type == OB_ARMATURE && ob->pose) {
565                         bPoseChannel *pchan;
566                         for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
567                                 for (con = pchan->constraints.first; con; con = con->next) {
568                                         if (con->type == CONSTRAINT_TYPE_PYTHON) {
569                                                 bPythonConstraint *data = con->data;
570                                                 if (data->text == text) data->text = NULL;
571                                                 update = 1;
572                                                 
573                                         }
574                                 }
575                         }
576                 }
577
578                 for (con = ob->constraints.first; con; con = con->next) {
579                         if (con->type == CONSTRAINT_TYPE_PYTHON) {
580                                 bPythonConstraint *data = con->data;
581                                 if (data->text == text) data->text = NULL;
582                                 update = 1;
583                         }
584                 }
585                 
586                 if (update)
587                         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
588         }
589         
590         /* nodes */
591         for (la = bmain->lamp.first; la; la = la->id.next) {
592                 ntree = la->nodetree;
593                 if (!ntree)
594                         continue;
595                 for (node = ntree->nodes.first; node; node = node->next) {
596                         if (node->type == NODE_FRAME) {
597                                 if ((Text *)node->id == text) {
598                                         node->id = NULL;
599                                 }
600                         }
601                 }
602         }
603
604         for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
605                 ntree = linestyle->nodetree;
606                 if (!ntree)
607                         continue;
608                 for (node = ntree->nodes.first; node; node = node->next) {
609                         if (node->type == NODE_FRAME) {
610                                 if ((Text *)node->id == text) {
611                                         node->id = NULL;
612                                 }
613                         }
614                 }
615         }
616
617         for (mat = bmain->mat.first; mat; mat = mat->id.next) {
618                 ntree = mat->nodetree;
619                 if (!ntree)
620                         continue;
621                 for (node = ntree->nodes.first; node; node = node->next) {
622                         if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
623                                 if ((Text *)node->id == text) {
624                                         node->id = NULL;
625                                 }
626                         }
627                 }
628         }
629
630         for (te = bmain->tex.first; te; te = te->id.next) {
631                 ntree = te->nodetree;
632                 if (!ntree)
633                         continue;
634                 for (node = ntree->nodes.first; node; node = node->next) {
635                         if (node->type == NODE_FRAME) {
636                                 if ((Text *)node->id == text) {
637                                         node->id = NULL;
638                                 }
639                         }
640                 }
641         }
642
643         for (wo = bmain->world.first; wo; wo = wo->id.next) {
644                 ntree = wo->nodetree;
645                 if (!ntree)
646                         continue;
647                 for (node = ntree->nodes.first; node; node = node->next) {
648                         if (node->type == NODE_FRAME) {
649                                 if ((Text *)node->id == text) {
650                                         node->id = NULL;
651                                 }
652                         }
653                 }
654         }
655
656         for (sce = bmain->scene.first; sce; sce = sce->id.next) {
657                 ntree = sce->nodetree;
658                 if (!ntree)
659                         continue;
660                 for (node = ntree->nodes.first; node; node = node->next) {
661                         if (node->type == NODE_FRAME) {
662                                 Text *ntext = (Text *)node->id;
663                                 if (ntext == text) node->id = NULL;
664                         }
665                 }
666
667                 /* Freestyle (while looping over the scene) */
668                 for (srl = sce->r.layers.first; srl; srl = srl->next) {
669                         for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
670                                 if (module->script == text)
671                                         module->script = NULL;
672                         }
673                 }
674         }
675
676         for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
677                 for (node = ntree->nodes.first; node; node = node->next) {
678                         if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
679                                 if ((Text *)node->id == text) {
680                                         node->id = NULL;
681                                 }
682                         }
683                 }
684         }
685         
686         /* text space */
687         for (scr = bmain->screen.first; scr; scr = scr->id.next) {
688                 for (area = scr->areabase.first; area; area = area->next) {
689                         for (sl = area->spacedata.first; sl; sl = sl->next) {
690                                 if (sl->spacetype == SPACE_TEXT) {
691                                         SpaceText *st = (SpaceText *) sl;
692
693                                         if (st->text == text) {
694                                                 st->text = NULL;
695                                                 st->top = 0;
696                                         }
697                                 }
698                         }
699                 }
700         }
701
702         text->id.us = 0;
703 }
704
705 void BKE_text_clear(Text *text) /* called directly from rna */
706 {
707         int oldstate;
708
709         oldstate = txt_get_undostate();
710         txt_set_undostate(1);
711         txt_sel_all(text);
712         txt_delete_sel(text);
713         txt_set_undostate(oldstate);
714
715         txt_make_dirty(text);
716 }
717
718 void BKE_text_write(Text *text, const char *str) /* called directly from rna */
719 {
720         int oldstate;
721
722         oldstate = txt_get_undostate();
723         txt_insert_buf(text, str);
724         txt_move_eof(text, 0);
725         txt_set_undostate(oldstate);
726
727         txt_make_dirty(text);
728 }
729
730
731 /* returns 0 if file on disk is the same or Text is in memory only
732  * returns 1 if file has been modified on disk since last local edit
733  * returns 2 if file on disk has been deleted
734  * -1 is returned if an error occurs */
735
736 int BKE_text_file_modified_check(Text *text)
737 {
738         BLI_stat_t st;
739         int result;
740         char file[FILE_MAX];
741
742         if (!text->name)
743                 return 0;
744
745         BLI_strncpy(file, text->name, FILE_MAX);
746         BLI_path_abs(file, G.main->name);
747
748         if (!BLI_exists(file))
749                 return 2;
750
751         result = BLI_stat(file, &st);
752
753         if (result == -1)
754                 return -1;
755
756         if ((st.st_mode & S_IFMT) != S_IFREG)
757                 return -1;
758
759         if (st.st_mtime > text->mtime)
760                 return 1;
761
762         return 0;
763 }
764
765 void BKE_text_file_modified_ignore(Text *text)
766 {
767         BLI_stat_t st;
768         int result;
769         char file[FILE_MAX];
770
771         if (!text->name) return;
772
773         BLI_strncpy(file, text->name, FILE_MAX);
774         BLI_path_abs(file, G.main->name);
775
776         if (!BLI_exists(file)) return;
777
778         result = BLI_stat(file, &st);
779
780         if (result == -1 || (st.st_mode & S_IFMT) != S_IFREG)
781                 return;
782
783         text->mtime = st.st_mtime;
784 }
785
786 /*****************************/
787 /* Editing utility functions */
788 /*****************************/
789
790 static void make_new_line(TextLine *line, char *newline)
791 {
792         if (line->line) MEM_freeN(line->line);
793         if (line->format) MEM_freeN(line->format);
794         
795         line->line = newline;
796         line->len = strlen(newline);
797         line->format = NULL;
798 }
799
800 static TextLine *txt_new_line(const char *str)
801 {
802         TextLine *tmp;
803
804         if (!str) str = "";
805         
806         tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
807         tmp->line = MEM_mallocN(strlen(str) + 1, "textline_string");
808         tmp->format = NULL;
809         
810         strcpy(tmp->line, str);
811         
812         tmp->len = strlen(str);
813         tmp->next = tmp->prev = NULL;
814         
815         return tmp;
816 }
817
818 static TextLine *txt_new_linen(const char *str, int n)
819 {
820         TextLine *tmp;
821
822         tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
823         tmp->line = MEM_mallocN(n + 1, "textline_string");
824         tmp->format = NULL;
825         
826         BLI_strncpy(tmp->line, (str) ? str : "", n + 1);
827         
828         tmp->len = strlen(tmp->line);
829         tmp->next = tmp->prev = NULL;
830         
831         return tmp;
832 }
833
834 void txt_clean_text(Text *text)
835 {       
836         TextLine **top, **bot;
837
838         if (!text->lines.first) {
839                 if (text->lines.last) text->lines.first = text->lines.last;
840                 else text->lines.first = text->lines.last = txt_new_line(NULL);
841         }
842         
843         if (!text->lines.last) text->lines.last = text->lines.first;
844
845         top = (TextLine **) &text->lines.first;
846         bot = (TextLine **) &text->lines.last;
847         
848         while ((*top)->prev) *top = (*top)->prev;
849         while ((*bot)->next) *bot = (*bot)->next;
850
851         if (!text->curl) {
852                 if (text->sell) text->curl = text->sell;
853                 else text->curl = text->lines.first;
854                 text->curc = 0;
855         }
856
857         if (!text->sell) {
858                 text->sell = text->curl;
859                 text->selc = 0;
860         }
861 }
862
863 int txt_get_span(TextLine *from, TextLine *to)
864 {
865         int ret = 0;
866         TextLine *tmp = from;
867
868         if (!to || !from) return 0;
869         if (from == to) return 0;
870
871         /* Look forwards */
872         while (tmp) {
873                 if (tmp == to) return ret;
874                 ret++;
875                 tmp = tmp->next;
876         }
877
878         /* Look backwards */
879         if (!tmp) {
880                 tmp = from;
881                 ret = 0;
882                 while (tmp) {
883                         if (tmp == to) break;
884                         ret--;
885                         tmp = tmp->prev;
886                 }
887                 if (!tmp) ret = 0;
888         }
889
890         return ret;
891 }
892
893 static void txt_make_dirty(Text *text)
894 {
895         text->flags |= TXT_ISDIRTY;
896 #ifdef WITH_PYTHON
897         if (text->compiled) BPY_text_free_code(text);
898 #endif
899 }
900
901 /****************************/
902 /* Cursor utility functions */
903 /****************************/
904
905 static void txt_curs_cur(Text *text, TextLine ***linep, int **charp)
906 {
907         *linep = &text->curl; *charp = &text->curc;
908 }
909
910 static void txt_curs_sel(Text *text, TextLine ***linep, int **charp)
911 {
912         *linep = &text->sell; *charp = &text->selc;
913 }
914
915 bool txt_cursor_is_line_start(Text *text)
916 {
917         return (text->selc == 0);
918 }
919
920 bool txt_cursor_is_line_end(Text *text)
921 {
922         return (text->selc == text->sell->len);
923 }
924
925 /*****************************/
926 /* Cursor movement functions */
927 /*****************************/
928
929 int txt_utf8_offset_to_index(const char *str, int offset)
930 {
931         int index = 0, pos = 0;
932         while (pos != offset) {
933                 pos += BLI_str_utf8_size(str + pos);
934                 index++;
935         }
936         return index;
937 }
938
939 int txt_utf8_index_to_offset(const char *str, int index)
940 {
941         int offset = 0, pos = 0;
942         while (pos != index) {
943                 offset += BLI_str_utf8_size(str + offset);
944                 pos++;
945         }
946         return offset;
947 }
948
949 int txt_utf8_offset_to_column(const char *str, int offset)
950 {
951         int column = 0, pos = 0;
952         while (pos < offset) {
953                 column += BLI_str_utf8_char_width_safe(str + pos);
954                 pos += BLI_str_utf8_size_safe(str + pos);
955         }
956         return column;
957 }
958
959 int txt_utf8_column_to_offset(const char *str, int column)
960 {
961         int offset = 0, pos = 0, col;
962         while (*(str + offset) && pos < column) {
963                 col = BLI_str_utf8_char_width_safe(str + offset);
964                 if (pos + col > column)
965                         break;
966                 offset += BLI_str_utf8_size_safe(str + offset);
967                 pos += col;
968         }
969         return offset;
970 }
971
972 void txt_move_up(Text *text, const bool sel)
973 {
974         TextLine **linep;
975         int *charp;
976
977         if (sel) txt_curs_sel(text, &linep, &charp);
978         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
979         if (!*linep) return;
980
981         if ((*linep)->prev) {
982                 int column = txt_utf8_offset_to_column((*linep)->line, *charp);
983                 *linep = (*linep)->prev;
984                 *charp = txt_utf8_column_to_offset((*linep)->line, column);
985                 
986         }
987         else {
988                 txt_move_bol(text, sel);
989         }
990
991         if (!sel) txt_pop_sel(text);
992 }
993
994 void txt_move_down(Text *text, const bool sel)
995 {
996         TextLine **linep;
997         int *charp;
998
999         if (sel) txt_curs_sel(text, &linep, &charp);
1000         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
1001         if (!*linep) return;
1002
1003         if ((*linep)->next) {
1004                 int column = txt_utf8_offset_to_column((*linep)->line, *charp);
1005                 *linep = (*linep)->next;
1006                 *charp = txt_utf8_column_to_offset((*linep)->line, column);
1007         }
1008         else {
1009                 txt_move_eol(text, sel);
1010         }
1011
1012         if (!sel) txt_pop_sel(text);
1013 }
1014
1015 void txt_move_left(Text *text, const bool sel)
1016 {
1017         TextLine **linep;
1018         int *charp;
1019         int tabsize = 0, i = 0;
1020
1021         if (sel) txt_curs_sel(text, &linep, &charp);
1022         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
1023         if (!*linep) return;
1024
1025         if (*charp == 0) {
1026                 if ((*linep)->prev) {
1027                         txt_move_up(text, sel);
1028                         *charp = (*linep)->len;
1029                 }
1030         }
1031         else {
1032                 // do nice left only if there are only spaces
1033                 // TXT_TABSIZE hardcoded in DNA_text_types.h
1034                 if (text->flags & TXT_TABSTOSPACES) {
1035                         tabsize = (*charp < TXT_TABSIZE) ? *charp : TXT_TABSIZE;
1036                         
1037                         for (i = 0; i < (*charp); i++)
1038                                 if ((*linep)->line[i] != ' ') {
1039                                         tabsize = 0;
1040                                         break;
1041                                 }
1042                         
1043                         // if in the middle of the space-tab
1044                         if (tabsize && (*charp) % TXT_TABSIZE != 0)
1045                                 tabsize = ((*charp) % TXT_TABSIZE);
1046                 }
1047                 
1048                 if (tabsize)
1049                         (*charp) -= tabsize;
1050                 else {
1051                         const char *prev = BLI_str_prev_char_utf8((*linep)->line + *charp);
1052                         *charp = prev - (*linep)->line;
1053                 }
1054         }
1055
1056         if (!sel) txt_pop_sel(text);
1057 }
1058
1059 void txt_move_right(Text *text, const bool sel)
1060 {
1061         TextLine **linep;
1062         int *charp, i;
1063         bool do_tab = false;
1064
1065         if (sel) txt_curs_sel(text, &linep, &charp);
1066         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
1067         if (!*linep) return;
1068
1069         if (*charp == (*linep)->len) {
1070                 if ((*linep)->next) {
1071                         txt_move_down(text, sel);
1072                         *charp = 0;
1073                 }
1074         }
1075         else {
1076                 // do nice right only if there are only spaces
1077                 // spaces hardcoded in DNA_text_types.h
1078                 if (text->flags & TXT_TABSTOSPACES && (*linep)->line[*charp] == ' ') {
1079                         do_tab = true;
1080                         for (i = 0; i < *charp; i++)
1081                                 if ((*linep)->line[i] != ' ') {
1082                                         do_tab = false;
1083                                         break;
1084                                 }
1085                 }
1086                 
1087                 if (do_tab) {
1088                         int tabsize = (*charp) % TXT_TABSIZE + 1;
1089                         for (i = *charp + 1; (*linep)->line[i] == ' ' && tabsize < TXT_TABSIZE; i++)
1090                                 tabsize++;
1091                         (*charp) = i;
1092                 }
1093                 else {
1094                         (*charp) += BLI_str_utf8_size((*linep)->line + *charp);
1095                 }
1096         }
1097         
1098         if (!sel) txt_pop_sel(text);
1099 }
1100
1101 void txt_jump_left(Text *text, const bool sel, const bool use_init_step)
1102 {
1103         TextLine **linep;
1104         int *charp;
1105
1106         if (sel) txt_curs_sel(text, &linep, &charp);
1107         else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
1108         if (!*linep) return;
1109
1110         BLI_str_cursor_step_utf8((*linep)->line, (*linep)->len,
1111                                  charp, STRCUR_DIR_PREV,
1112                                  STRCUR_JUMP_DELIM, use_init_step);
1113         
1114         if (!sel) txt_pop_sel(text);
1115 }
1116
1117 void txt_jump_right(Text *text, const bool sel, const bool use_init_step)
1118 {
1119         TextLine **linep;
1120         int *charp;
1121
1122         if (sel) txt_curs_sel(text, &linep, &charp);
1123         else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
1124         if (!*linep) return;
1125         
1126         BLI_str_cursor_step_utf8((*linep)->line, (*linep)->len,
1127                                  charp, STRCUR_DIR_NEXT,
1128                                  STRCUR_JUMP_DELIM, use_init_step);
1129         
1130         if (!sel) txt_pop_sel(text);
1131 }
1132
1133 void txt_move_bol(Text *text, const bool sel)
1134 {
1135         TextLine **linep;
1136         int *charp;
1137
1138         if (sel) txt_curs_sel(text, &linep, &charp);
1139         else txt_curs_cur(text, &linep, &charp);
1140         if (!*linep) return;
1141         
1142         *charp = 0;
1143
1144         if (!sel) txt_pop_sel(text);
1145 }
1146
1147 void txt_move_eol(Text *text, const bool sel)
1148 {
1149         TextLine **linep;
1150         int *charp;
1151
1152         if (sel) txt_curs_sel(text, &linep, &charp);
1153         else txt_curs_cur(text, &linep, &charp);
1154         if (!*linep) return;
1155
1156         *charp = (*linep)->len;
1157
1158         if (!sel) txt_pop_sel(text);
1159 }
1160
1161 void txt_move_bof(Text *text, const bool sel)
1162 {
1163         TextLine **linep;
1164         int *charp;
1165
1166         if (sel) txt_curs_sel(text, &linep, &charp);
1167         else txt_curs_cur(text, &linep, &charp);
1168         if (!*linep) return;
1169
1170         *linep = text->lines.first;
1171         *charp = 0;
1172
1173         if (!sel) txt_pop_sel(text);
1174 }
1175
1176 void txt_move_eof(Text *text, const bool sel)
1177 {
1178         TextLine **linep;
1179         int *charp;
1180
1181         if (sel) txt_curs_sel(text, &linep, &charp);
1182         else txt_curs_cur(text, &linep, &charp);
1183         if (!*linep) return;
1184
1185         *linep = text->lines.last;
1186         *charp = (*linep)->len;
1187
1188         if (!sel) txt_pop_sel(text);
1189 }
1190
1191 void txt_move_toline(Text *text, unsigned int line, const bool sel)
1192 {
1193         txt_move_to(text, line, 0, sel);
1194 }
1195
1196 /* Moves to a certain byte in a line, not a certain utf8-character! */
1197 void txt_move_to(Text *text, unsigned int line, unsigned int ch, const bool sel)
1198 {
1199         TextLine **linep;
1200         int *charp;
1201         unsigned int i;
1202
1203         if (sel) txt_curs_sel(text, &linep, &charp);
1204         else txt_curs_cur(text, &linep, &charp);
1205         if (!*linep) return;
1206         
1207         *linep = text->lines.first;
1208         for (i = 0; i < line; i++) {
1209                 if ((*linep)->next) *linep = (*linep)->next;
1210                 else break;
1211         }
1212         if (ch > (unsigned int)((*linep)->len))
1213                 ch = (unsigned int)((*linep)->len);
1214         *charp = ch;
1215         
1216         if (!sel) txt_pop_sel(text);
1217 }
1218
1219 /****************************/
1220 /* Text selection functions */
1221 /****************************/
1222
1223 static void txt_curs_swap(Text *text)
1224 {
1225         TextLine *tmpl;
1226         int tmpc;
1227                 
1228         tmpl = text->curl;
1229         text->curl = text->sell;
1230         text->sell = tmpl;
1231
1232         tmpc = text->curc;
1233         text->curc = text->selc;
1234         text->selc = tmpc;
1235 }
1236
1237 static void txt_pop_first(Text *text)
1238 {
1239         if (txt_get_span(text->curl, text->sell) < 0 ||
1240             (text->curl == text->sell && text->curc > text->selc))
1241         {
1242                 txt_curs_swap(text);
1243         }
1244         
1245         txt_pop_sel(text);
1246 }
1247
1248 static void txt_pop_last(Text *text)
1249 {
1250         if (txt_get_span(text->curl, text->sell) > 0 ||
1251             (text->curl == text->sell && text->curc < text->selc))
1252         {
1253                 txt_curs_swap(text);
1254         }
1255         
1256         txt_pop_sel(text);
1257 }
1258
1259 void txt_pop_sel(Text *text)
1260 {
1261         text->sell = text->curl;
1262         text->selc = text->curc;
1263 }
1264
1265 void txt_order_cursors(Text *text, const bool reverse)
1266 {
1267         if (!text->curl) return;
1268         if (!text->sell) return;
1269         
1270         /* Flip so text->curl is before/after text->sell */
1271         if (reverse == false) {
1272                 if ((txt_get_span(text->curl, text->sell) < 0) ||
1273                     (text->curl == text->sell && text->curc > text->selc))
1274                 {
1275                         txt_curs_swap(text);
1276                 }
1277         }
1278         else {
1279                 if ((txt_get_span(text->curl, text->sell) > 0) ||
1280                     (text->curl == text->sell && text->curc < text->selc))
1281                 {
1282                         txt_curs_swap(text);
1283                 }
1284         }
1285 }
1286
1287 bool txt_has_sel(Text *text)
1288 {
1289         return ((text->curl != text->sell) || (text->curc != text->selc));
1290 }
1291
1292 static void txt_delete_sel(Text *text)
1293 {
1294         TextLine *tmpl;
1295         char *buf;
1296
1297         if (!text->curl) return;
1298         if (!text->sell) return;
1299
1300         if (!txt_has_sel(text)) return;
1301         
1302         txt_order_cursors(text, false);
1303
1304         if (!undoing) {
1305                 buf = txt_sel_to_buf(text);
1306                 txt_undo_add_blockop(text, UNDO_DBLOCK, buf);
1307                 MEM_freeN(buf);
1308         }
1309
1310         buf = MEM_mallocN(text->curc + (text->sell->len - text->selc) + 1, "textline_string");
1311
1312         strncpy(buf, text->curl->line, text->curc);
1313         strcpy(buf + text->curc, text->sell->line + text->selc);
1314         buf[text->curc + (text->sell->len - text->selc)] = 0;
1315
1316         make_new_line(text->curl, buf);
1317         
1318         tmpl = text->sell;
1319         while (tmpl != text->curl) {
1320                 tmpl = tmpl->prev;
1321                 if (!tmpl) break;
1322                 
1323                 txt_delete_line(text, tmpl->next);
1324         }
1325         
1326         text->sell = text->curl;
1327         text->selc = text->curc;
1328 }
1329
1330 void txt_sel_all(Text *text)
1331 {
1332         text->curl = text->lines.first;
1333         text->curc = 0;
1334         
1335         text->sell = text->lines.last;
1336         text->selc = text->sell->len;
1337 }
1338
1339 /**
1340  * Reverse of #txt_pop_sel
1341  * Clears the selection and ensures the cursor is located
1342  * at the selection (where the cursor is visually while editing).
1343  */
1344 void txt_sel_clear(Text *text)
1345 {
1346         if (text->sell) {
1347                 text->curl = text->sell;
1348                 text->curc = text->selc;
1349         }
1350 }
1351
1352 void txt_sel_line(Text *text)
1353 {
1354         if (!text->curl) return;
1355         
1356         text->curc = 0;
1357         text->sell = text->curl;
1358         text->selc = text->sell->len;
1359 }
1360
1361 /***************************/
1362 /* Cut and paste functions */
1363 /***************************/
1364
1365 char *txt_to_buf(Text *text)
1366 {
1367         int length;
1368         TextLine *tmp, *linef, *linel;
1369         int charf, charl;
1370         char *buf;
1371
1372         if (!text->curl) return NULL;
1373         if (!text->sell) return NULL;
1374         if (!text->lines.first) return NULL;
1375
1376         linef = text->lines.first;
1377         charf = 0;
1378                 
1379         linel = text->lines.last;
1380         charl = linel->len;
1381
1382         if (linef == text->lines.last) {
1383                 length = charl - charf;
1384
1385                 buf = MEM_mallocN(length + 2, "text buffer");
1386                 
1387                 BLI_strncpy(buf, linef->line + charf, length + 1);
1388                 buf[length] = 0;
1389         }
1390         else {
1391                 length = linef->len - charf;
1392                 length += charl;
1393                 length += 2; /* For the 2 '\n' */
1394                 
1395                 tmp = linef->next;
1396                 while (tmp && tmp != linel) {
1397                         length += tmp->len + 1;
1398                         tmp = tmp->next;
1399                 }
1400                 
1401                 buf = MEM_mallocN(length + 1, "cut buffer");
1402
1403                 strncpy(buf, linef->line + charf, linef->len - charf);
1404                 length = linef->len - charf;
1405                 
1406                 buf[length++] = '\n';
1407                 
1408                 tmp = linef->next;
1409                 while (tmp && tmp != linel) {
1410                         strncpy(buf + length, tmp->line, tmp->len);
1411                         length += tmp->len;
1412                         
1413                         buf[length++] = '\n';
1414                         
1415                         tmp = tmp->next;
1416                 }
1417                 strncpy(buf + length, linel->line, charl);
1418                 length += charl;
1419                 
1420                 /* python compiler wants an empty end line */
1421                 buf[length++] = '\n';
1422                 buf[length] = 0;
1423         }
1424         
1425         return buf;
1426 }
1427
1428 int txt_find_string(Text *text, const char *findstr, int wrap, int match_case)
1429 {
1430         TextLine *tl, *startl;
1431         const char *s = NULL;
1432
1433         if (!text->curl || !text->sell) return 0;
1434         
1435         txt_order_cursors(text, false);
1436
1437         tl = startl = text->sell;
1438         
1439         if (match_case) s = strstr(&tl->line[text->selc], findstr);
1440         else s = BLI_strcasestr(&tl->line[text->selc], findstr);
1441         while (!s) {
1442                 tl = tl->next;
1443                 if (!tl) {
1444                         if (wrap)
1445                                 tl = text->lines.first;
1446                         else
1447                                 break;
1448                 }
1449
1450                 if (match_case) s = strstr(tl->line, findstr);
1451                 else s = BLI_strcasestr(tl->line, findstr);
1452                 if (tl == startl)
1453                         break;
1454         }
1455         
1456         if (s) {
1457                 int newl = txt_get_span(text->lines.first, tl);
1458                 int newc = (int)(s - tl->line);
1459                 txt_move_to(text, newl, newc, 0);
1460                 txt_move_to(text, newl, newc + strlen(findstr), 1);
1461                 return 1;
1462         }
1463         else
1464                 return 0;
1465 }
1466
1467 char *txt_sel_to_buf(Text *text)
1468 {
1469         char *buf;
1470         int length = 0;
1471         TextLine *tmp, *linef, *linel;
1472         int charf, charl;
1473
1474         if (!text->curl) return NULL;
1475         if (!text->sell) return NULL;
1476         
1477         if (text->curl == text->sell) {
1478                 linef = linel = text->curl;
1479                 
1480                 if (text->curc < text->selc) {
1481                         charf = text->curc;
1482                         charl = text->selc;
1483                 }
1484                 else {
1485                         charf = text->selc;
1486                         charl = text->curc;
1487                 }
1488         }
1489         else if (txt_get_span(text->curl, text->sell) < 0) {
1490                 linef = text->sell;
1491                 linel = text->curl;
1492
1493                 charf = text->selc;
1494                 charl = text->curc;
1495         }
1496         else {
1497                 linef = text->curl;
1498                 linel = text->sell;
1499                 
1500                 charf = text->curc;
1501                 charl = text->selc;
1502         }
1503
1504         if (linef == linel) {
1505                 length = charl - charf;
1506
1507                 buf = MEM_mallocN(length + 1, "sel buffer");
1508                 
1509                 BLI_strncpy(buf, linef->line + charf, length + 1);
1510         }
1511         else {
1512                 length += linef->len - charf;
1513                 length += charl;
1514                 length++; /* For the '\n' */
1515                 
1516                 tmp = linef->next;
1517                 while (tmp && tmp != linel) {
1518                         length += tmp->len + 1;
1519                         tmp = tmp->next;
1520                 }
1521                 
1522                 buf = MEM_mallocN(length + 1, "sel buffer");
1523                 
1524                 strncpy(buf, linef->line + charf, linef->len - charf);
1525                 length = linef->len - charf;
1526                 
1527                 buf[length++] = '\n';
1528                 
1529                 tmp = linef->next;
1530                 while (tmp && tmp != linel) {
1531                         strncpy(buf + length, tmp->line, tmp->len);
1532                         length += tmp->len;
1533                         
1534                         buf[length++] = '\n';
1535                         
1536                         tmp = tmp->next;
1537                 }
1538                 strncpy(buf + length, linel->line, charl);
1539                 length += charl;
1540                 
1541                 buf[length] = 0;
1542         }
1543
1544         return buf;
1545 }
1546
1547 void txt_insert_buf(Text *text, const char *in_buffer)
1548 {
1549         int l = 0, u, len;
1550         size_t i = 0, j;
1551         TextLine *add;
1552         char *buffer;
1553
1554         if (!in_buffer) return;
1555
1556         txt_delete_sel(text);
1557         
1558         len = strlen(in_buffer);
1559         buffer = BLI_strdupn(in_buffer, len);
1560         len += txt_extended_ascii_as_utf8(&buffer);
1561         
1562         if (!undoing) txt_undo_add_blockop(text, UNDO_IBLOCK, buffer);
1563
1564         u = undoing;
1565         undoing = 1;
1566
1567         /* Read the first line (or as close as possible */
1568         while (buffer[i] && buffer[i] != '\n')
1569                 txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &i));
1570         
1571         if (buffer[i] == '\n') txt_split_curline(text);
1572         else { undoing = u; MEM_freeN(buffer); return; }
1573         i++;
1574
1575         while (i < len) {
1576                 l = 0;
1577
1578                 while (buffer[i] && buffer[i] != '\n') {
1579                         i++; l++;
1580                 }
1581         
1582                 if (buffer[i] == '\n') {
1583                         add = txt_new_linen(buffer + (i - l), l);
1584                         BLI_insertlinkbefore(&text->lines, text->curl, add);
1585                         i++;
1586                 }
1587                 else {
1588                         for (j = i - l; j < i && j < len; )
1589                                 txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &j));
1590                         break;
1591                 }
1592         }
1593         
1594         MEM_freeN(buffer);
1595
1596         undoing = u;
1597 }
1598
1599 /******************/
1600 /* Undo functions */
1601 /******************/
1602
1603 static bool max_undo_test(Text *text, int x)
1604 {
1605         while (text->undo_pos + x >= text->undo_len) {
1606                 if (text->undo_len * 2 > TXT_MAX_UNDO) {
1607                         /* XXX error("Undo limit reached, buffer cleared\n"); */
1608                         MEM_freeN(text->undo_buf);
1609                         init_undo_text(text);
1610                         return false;
1611                 }
1612                 else {
1613                         void *tmp = text->undo_buf;
1614                         text->undo_buf = MEM_callocN(text->undo_len * 2, "undo buf");
1615                         memcpy(text->undo_buf, tmp, text->undo_len);
1616                         text->undo_len *= 2;
1617                         MEM_freeN(tmp);
1618                 }
1619         }
1620
1621         return true;
1622 }
1623
1624 #if 0  /* UNUSED */
1625 static void dump_buffer(Text *text) 
1626 {
1627         int i = 0;
1628         
1629         while (i++ < text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
1630 }
1631
1632 /* Note: this function is outdated and must be updated if needed for future use */
1633 void txt_print_undo(Text *text)
1634 {
1635         int i = 0;
1636         int op;
1637         const char *ops;
1638         int linep, charp;
1639         
1640         dump_buffer(text);
1641         
1642         printf("---< Undo Buffer >---\n");
1643         
1644         printf("UndoPosition is %d\n", text->undo_pos);
1645         
1646         while (i <= text->undo_pos) {
1647                 op = text->undo_buf[i];
1648                 
1649                 if (op == UNDO_INSERT_1) {
1650                         ops = "Insert ascii ";
1651                 }
1652                 else if (op == UNDO_INSERT_2) {
1653                         ops = "Insert 2 bytes ";
1654                 }
1655                 else if (op == UNDO_INSERT_3) {
1656                         ops = "Insert 3 bytes ";
1657                 }
1658                 else if (op == UNDO_INSERT_4) {
1659                         ops = "Insert unicode ";
1660                 }
1661                 else if (op == UNDO_BS_1) {
1662                         ops = "Backspace for ascii ";
1663                 }
1664                 else if (op == UNDO_BS_2) {
1665                         ops = "Backspace for 2 bytes ";
1666                 }
1667                 else if (op == UNDO_BS_3) {
1668                         ops = "Backspace for 3 bytes ";
1669                 }
1670                 else if (op == UNDO_BS_4) {
1671                         ops = "Backspace for unicode ";
1672                 }
1673                 else if (op == UNDO_DEL_1) {
1674                         ops = "Delete ascii ";
1675                 }
1676                 else if (op == UNDO_DEL_2) {
1677                         ops = "Delete 2 bytes ";
1678                 }
1679                 else if (op == UNDO_DEL_3) {
1680                         ops = "Delete 3 bytes ";
1681                 }
1682                 else if (op == UNDO_DEL_4) {
1683                         ops = "Delete unicode ";
1684                 }
1685                 else if (op == UNDO_DBLOCK) {
1686                         ops = "Delete text block";
1687                 }
1688                 else if (op == UNDO_IBLOCK) {
1689                         ops = "Insert text block";
1690                 }
1691                 else if (op == UNDO_INDENT) {
1692                         ops = "Indent ";
1693                 }
1694                 else if (op == UNDO_UNINDENT) {
1695                         ops = "Unindent ";
1696                 }
1697                 else if (op == UNDO_COMMENT) {
1698                         ops = "Comment ";
1699                 }
1700                 else if (op == UNDO_UNCOMMENT) {
1701                         ops = "Uncomment ";
1702                 }
1703                 else {
1704                         ops = "Unknown";
1705                 }
1706                 
1707                 printf("Op (%o) at %d = %s", op, i, ops);
1708                 if (op >= UNDO_INSERT_1 && op <= UNDO_DEL_4) {
1709                         i++;
1710                         printf(" - Char is ");
1711                         switch (op) {
1712                                 case UNDO_INSERT_1: case UNDO_BS_1: case UNDO_DEL_1:
1713                                         printf("%c", text->undo_buf[i]);
1714                                         i++;
1715                                         break;
1716                                 case UNDO_INSERT_2: case UNDO_BS_2: case UNDO_DEL_2:
1717                                         printf("%c%c", text->undo_buf[i], text->undo_buf[i + 1]);
1718                                         i += 2;
1719                                         break;
1720                                 case UNDO_INSERT_3: case UNDO_BS_3: case UNDO_DEL_3:
1721                                         printf("%c%c%c", text->undo_buf[i], text->undo_buf[i + 1], text->undo_buf[i + 2]);
1722                                         i += 3;
1723                                         break;
1724                                 case UNDO_INSERT_4: case UNDO_BS_4: case UNDO_DEL_4:
1725                                 {
1726                                         unsigned int uc;
1727                                         char c[BLI_UTF8_MAX + 1];
1728                                         size_t c_len;
1729                                         uc = text->undo_buf[i]; i++;
1730                                         uc = uc + (text->undo_buf[i] << 8); i++;
1731                                         uc = uc + (text->undo_buf[i] << 16); i++;
1732                                         uc = uc + (text->undo_buf[i] << 24); i++;
1733                                         c_len = BLI_str_utf8_from_unicode(uc, c);
1734                                         c[c_len] = '\0';
1735                                         puts(c);
1736                                         break;
1737                                 }
1738                         }
1739                 }
1740                 else if (op == UNDO_DBLOCK || op == UNDO_IBLOCK) {
1741                         i++;
1742
1743                         linep = text->undo_buf[i]; i++;
1744                         linep = linep + (text->undo_buf[i] << 8); i++;
1745                         linep = linep + (text->undo_buf[i] << 16); i++;
1746                         linep = linep + (text->undo_buf[i] << 24); i++;
1747                         
1748                         printf(" (length %d) <", linep);
1749                         
1750                         while (linep > 0) {
1751                                 putchar(text->undo_buf[i]);
1752                                 linep--; i++;
1753                         }
1754                         
1755                         linep = text->undo_buf[i]; i++;
1756                         linep = linep + (text->undo_buf[i] << 8); i++;
1757                         linep = linep + (text->undo_buf[i] << 16); i++;
1758                         linep = linep + (text->undo_buf[i] << 24); i++;
1759                         printf("> (%d)", linep);
1760                 }
1761                 else if (op == UNDO_INDENT || op == UNDO_UNINDENT) {
1762                         i++;
1763
1764                         charp = text->undo_buf[i]; i++;
1765                         charp = charp + (text->undo_buf[i] << 8); i++;
1766
1767                         linep = text->undo_buf[i]; i++;
1768                         linep = linep + (text->undo_buf[i] << 8); i++;
1769                         linep = linep + (text->undo_buf[i] << 16); i++;
1770                         linep = linep + (text->undo_buf[i] << 24); i++;
1771                         
1772                         printf("to <%d, %d> ", linep, charp);
1773
1774                         charp = text->undo_buf[i]; i++;
1775                         charp = charp + (text->undo_buf[i] << 8); i++;
1776
1777                         linep = text->undo_buf[i]; i++;
1778                         linep = linep + (text->undo_buf[i] << 8); i++;
1779                         linep = linep + (text->undo_buf[i] << 16); i++;
1780                         linep = linep + (text->undo_buf[i] << 24); i++;
1781                         
1782                         printf("from <%d, %d>", linep, charp);
1783                 }
1784                 
1785                 printf(" %d\n",  i);
1786                 i++;
1787         }
1788 }
1789 #endif
1790
1791 static void txt_undo_store_uint16(char *undo_buf, int *undo_pos, unsigned short value) 
1792 {
1793         undo_buf[*undo_pos] = (value) & 0xff;
1794         (*undo_pos)++;
1795         undo_buf[*undo_pos] = (value >> 8) & 0xff;
1796         (*undo_pos)++;
1797 }
1798
1799 static void txt_undo_store_uint32(char *undo_buf, int *undo_pos, unsigned int value) 
1800 {
1801         undo_buf[*undo_pos] = (value) & 0xff;
1802         (*undo_pos)++;
1803         undo_buf[*undo_pos] = (value >> 8) & 0xff;
1804         (*undo_pos)++;
1805         undo_buf[*undo_pos] = (value >> 16) & 0xff;
1806         (*undo_pos)++;
1807         undo_buf[*undo_pos] = (value >> 24) & 0xff;
1808         (*undo_pos)++;
1809 }
1810
1811 /* store the cur cursor to the undo buffer */
1812 static void txt_undo_store_cur(Text *text)
1813 {
1814         txt_undo_store_uint16(text->undo_buf, &text->undo_pos, text->curc);
1815         txt_undo_store_uint32(text->undo_buf, &text->undo_pos, txt_get_span(text->lines.first, text->curl));
1816 }
1817
1818 /* store the sel cursor to the undo buffer */
1819 static void txt_undo_store_sel(Text *text)
1820 {
1821         txt_undo_store_uint16(text->undo_buf, &text->undo_pos, text->selc);
1822         txt_undo_store_uint32(text->undo_buf, &text->undo_pos, txt_get_span(text->lines.first, text->sell));
1823 }
1824
1825 /* store both cursors to the undo buffer */
1826 static void txt_undo_store_cursors(Text *text)
1827 {
1828         txt_undo_store_cur(text);
1829         txt_undo_store_sel(text);
1830 }
1831
1832 /* store an operator along with a block of data */
1833 static void txt_undo_add_blockop(Text *text, int op, const char *buf)
1834 {
1835         unsigned int length = strlen(buf);
1836         
1837         if (!max_undo_test(text, length + 11 + 12))
1838                 return;
1839
1840         text->undo_pos++;
1841         text->undo_buf[text->undo_pos] = op;
1842         text->undo_pos++;
1843         
1844         txt_undo_store_cursors(text);
1845
1846         txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length);
1847         
1848         strncpy(text->undo_buf + text->undo_pos, buf, length);
1849         text->undo_pos += length;
1850
1851         txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length);
1852         text->undo_buf[text->undo_pos] = op;
1853         
1854         text->undo_buf[text->undo_pos + 1] = 0;
1855 }
1856
1857 /* store a regular operator */
1858 void txt_undo_add_op(Text *text, int op)
1859 {
1860         if (!max_undo_test(text, 15))
1861                 return;
1862
1863         text->undo_pos++;
1864         text->undo_buf[text->undo_pos] = op;
1865
1866         text->undo_pos++;
1867         
1868         txt_undo_store_cursors(text);
1869                 
1870         text->undo_buf[text->undo_pos] = op;
1871         text->undo_buf[text->undo_pos + 1] = 0;
1872 }
1873
1874 /* store an operator for a single character */
1875 static void txt_undo_add_charop(Text *text, int op_start, unsigned int c)
1876 {
1877         char utf8[BLI_UTF8_MAX];
1878         size_t i, utf8_size = BLI_str_utf8_from_unicode(c, utf8);
1879         
1880         if (!max_undo_test(text, 3 + utf8_size + 12))
1881                 return;
1882         
1883         text->undo_pos++;
1884         
1885         if (utf8_size < 4) {
1886                 text->undo_buf[text->undo_pos] = op_start + utf8_size - 1;
1887                 text->undo_pos++;
1888                 
1889                 txt_undo_store_cur(text);
1890
1891                 for (i = 0; i < utf8_size; i++) {
1892                         text->undo_buf[text->undo_pos] = utf8[i];
1893                         text->undo_pos++;
1894                 }
1895                 
1896                 text->undo_buf[text->undo_pos] = op_start + utf8_size - 1;
1897         }
1898         else {
1899                 text->undo_buf[text->undo_pos] = op_start + 3;
1900                 text->undo_pos++;
1901
1902                 txt_undo_store_cursors(text);
1903
1904                 txt_undo_store_uint32(text->undo_buf, &text->undo_pos, c);
1905                 text->undo_buf[text->undo_pos] = op_start + 3;
1906         }
1907         
1908         text->undo_buf[text->undo_pos + 1] = 0;
1909 }
1910
1911 /* extends Link */
1912 struct LinkInt {
1913         struct LinkInt *next, *prev;
1914         int value;
1915 };
1916
1917 /**
1918  * UnindentLines points to a #ListBase composed of #LinkInt elements, listing the numbers
1919  * of the lines that should not be indented back.
1920  */
1921 static void txt_undo_add_unprefix_op(
1922         Text *text, char undo_op,
1923         const ListBase *line_index_mask, const int line_index_mask_len)
1924 {
1925         struct LinkInt *idata;
1926
1927         BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len);
1928
1929         /* OP byte + UInt32 count + counted UInt32 line numbers + UInt32 count + 12-bytes selection + OP byte */
1930         if (!max_undo_test(text, 1 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) {
1931                 return;
1932         }
1933
1934         /* Opening buffer sequence with OP */
1935         text->undo_pos++;
1936         text->undo_buf[text->undo_pos] = undo_op;
1937         text->undo_pos++;
1938         /* Adding number of line numbers to read */
1939         txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len);
1940
1941         /* Adding linenumbers of lines that shall not be indented if undoing */
1942         for (idata = line_index_mask->first; idata; idata = idata->next) {
1943                 txt_undo_store_uint32(text->undo_buf, &text->undo_pos, idata->value);
1944         }
1945
1946         /* Adding number of line numbers to read again */
1947         txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len);
1948         /* Adding current selection */
1949         txt_undo_store_cursors(text);
1950         /* Closing with OP (same as above) */
1951         text->undo_buf[text->undo_pos] = undo_op;
1952         /* Marking as last undo operation */
1953         text->undo_buf[text->undo_pos + 1] = 0;
1954 }
1955
1956 static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos)
1957 {
1958         unsigned short val;
1959         val = undo_buf[*undo_pos]; (*undo_pos)--;
1960         val = (val << 8) + undo_buf[*undo_pos]; (*undo_pos)--;
1961         return val;
1962 }
1963
1964 static unsigned int txt_undo_read_uint32(const char *undo_buf, int *undo_pos)
1965 {
1966         unsigned int val;
1967         val = undo_buf[*undo_pos]; (*undo_pos)--;
1968         val = (val << 8) + undo_buf[*undo_pos]; (*undo_pos)--;
1969         val = (val << 8) + undo_buf[*undo_pos]; (*undo_pos)--;
1970         val = (val << 8) + undo_buf[*undo_pos]; (*undo_pos)--;
1971         return val;
1972 }
1973
1974 /* read the cur cursor from the undo buffer */
1975 static void txt_undo_read_cur(const char *undo_buf, int *undo_pos, unsigned int *curln, unsigned short *curc)
1976 {
1977         *curln = txt_undo_read_uint32(undo_buf, undo_pos);
1978         *curc  = txt_undo_read_uint16(undo_buf, undo_pos);
1979 }
1980
1981 /* read the sel cursor from the undo buffer */
1982 static void txt_undo_read_sel(const char *undo_buf, int *undo_pos, unsigned int *selln, unsigned short *selc)
1983 {
1984         *selln = txt_undo_read_uint32(undo_buf, undo_pos);
1985         *selc  = txt_undo_read_uint16(undo_buf, undo_pos);
1986 }
1987
1988 /* read both cursors from the undo buffer */
1989 static void txt_undo_read_cursors(const char *undo_buf, int *undo_pos,
1990                                   unsigned int *curln, unsigned short *curc,
1991                                   unsigned int *selln, unsigned short *selc)
1992 {
1993         txt_undo_read_sel(undo_buf, undo_pos, selln, selc);
1994         txt_undo_read_cur(undo_buf, undo_pos, curln, curc);
1995 }
1996
1997 static unsigned int txt_undo_read_unicode(const char *undo_buf, int *undo_pos, short bytes)
1998 {
1999         unsigned int unicode;
2000         char utf8[BLI_UTF8_MAX + 1];
2001         
2002         switch (bytes) {
2003                 case 1: /* ascii */
2004                         unicode = undo_buf[*undo_pos]; (*undo_pos)--; 
2005                         break;
2006                 case 2: /* 2-byte symbol */
2007                         utf8[2] = '\0';
2008                         utf8[1] = undo_buf[*undo_pos]; (*undo_pos)--;
2009                         utf8[0] = undo_buf[*undo_pos]; (*undo_pos)--;
2010                         unicode = BLI_str_utf8_as_unicode(utf8);
2011                         break;
2012                 case 3: /* 3-byte symbol */
2013                         utf8[3] = '\0';
2014                         utf8[2] = undo_buf[*undo_pos]; (*undo_pos)--;
2015                         utf8[1] = undo_buf[*undo_pos]; (*undo_pos)--;
2016                         utf8[0] = undo_buf[*undo_pos]; (*undo_pos)--;
2017                         unicode = BLI_str_utf8_as_unicode(utf8);
2018                         break;
2019                 case 4: /* 32-bit unicode symbol */
2020                         unicode = txt_undo_read_uint32(undo_buf, undo_pos);
2021                         break;
2022                 default:
2023                         /* should never happen */
2024                         BLI_assert(0);
2025                         unicode = 0;
2026                         break;
2027         }
2028         
2029         return unicode;
2030 }
2031
2032 static unsigned short txt_redo_read_uint16(const char *undo_buf, int *undo_pos)
2033 {
2034         unsigned short val;
2035         val = undo_buf[*undo_pos]; (*undo_pos)++;
2036         val = val + (undo_buf[*undo_pos] << 8); (*undo_pos)++;
2037         return val;
2038 }
2039
2040 static unsigned int txt_redo_read_uint32(const char *undo_buf, int *undo_pos)
2041 {
2042         unsigned int val;
2043         val = undo_buf[*undo_pos]; (*undo_pos)++;
2044         val = val + (undo_buf[*undo_pos] << 8); (*undo_pos)++;
2045         val = val + (undo_buf[*undo_pos] << 16); (*undo_pos)++;
2046         val = val + (undo_buf[*undo_pos] << 24); (*undo_pos)++;
2047         return val;
2048 }
2049
2050 /* redo read cur cursor from the undo buffer */
2051 static void txt_redo_read_cur(const char *undo_buf, int *undo_pos, unsigned int *curln, unsigned short *curc)
2052 {
2053         *curc  = txt_redo_read_uint16(undo_buf, undo_pos);
2054         *curln = txt_redo_read_uint32(undo_buf, undo_pos);
2055 }
2056
2057 /* redo read sel cursor from the undo buffer */
2058 static void txt_redo_read_sel(const char *undo_buf, int *undo_pos, unsigned int *selln, unsigned short *selc)
2059 {
2060         *selc  = txt_redo_read_uint16(undo_buf, undo_pos);
2061         *selln = txt_redo_read_uint32(undo_buf, undo_pos);
2062 }
2063
2064 /* redo read both cursors from the undo buffer */
2065 static void txt_redo_read_cursors(const char *undo_buf, int *undo_pos,
2066                                   unsigned int *curln, unsigned short *curc,
2067                                   unsigned int *selln, unsigned short *selc)
2068 {
2069         txt_redo_read_cur(undo_buf, undo_pos, curln, curc);
2070         txt_redo_read_sel(undo_buf, undo_pos, selln, selc);
2071 }
2072
2073 static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, short bytes)
2074 {
2075         unsigned int unicode;
2076         char utf8[BLI_UTF8_MAX + 1];
2077         
2078         switch (bytes) {
2079                 case 1: /* ascii */
2080                         unicode = undo_buf[*undo_pos]; (*undo_pos)++; 
2081                         break;
2082                 case 2: /* 2-byte symbol */
2083                         utf8[0] = undo_buf[*undo_pos]; (*undo_pos)++;
2084                         utf8[1] = undo_buf[*undo_pos]; (*undo_pos)++;
2085                         utf8[2] = '\0';
2086                         unicode = BLI_str_utf8_as_unicode(utf8);
2087                         break;
2088                 case 3: /* 3-byte symbol */
2089                         utf8[0] = undo_buf[*undo_pos]; (*undo_pos)++;
2090                         utf8[1] = undo_buf[*undo_pos]; (*undo_pos)++;
2091                         utf8[2] = undo_buf[*undo_pos]; (*undo_pos)++;
2092                         utf8[3] = '\0';
2093                         unicode = BLI_str_utf8_as_unicode(utf8);
2094                         break;
2095                 case 4: /* 32-bit unicode symbol */
2096                         unicode = txt_undo_read_uint32(undo_buf, undo_pos);
2097                         break;
2098                 default:
2099                         /* should never happen */
2100                         BLI_assert(0);
2101                         unicode = 0;
2102                         break;
2103         }
2104         
2105         return unicode;
2106 }
2107
2108 void txt_do_undo(Text *text)
2109 {
2110         int op = text->undo_buf[text->undo_pos];
2111         int prev_flags;
2112         unsigned int linep, i;
2113         unsigned int uchar;
2114         unsigned int curln, selln;
2115         unsigned short curc, selc;
2116         unsigned short charp;
2117         char *buf;
2118         
2119         if (text->undo_pos < 0) {
2120                 return;
2121         }
2122
2123         text->undo_pos--;
2124
2125         undoing = 1;
2126         
2127         switch (op) {
2128                 case UNDO_INSERT_1:
2129                 case UNDO_INSERT_2:
2130                 case UNDO_INSERT_3:
2131                 case UNDO_INSERT_4:
2132                         text->undo_pos -= op - UNDO_INSERT_1 + 1;
2133                         
2134                         /* get and restore the cursors */
2135                         txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
2136                         txt_move_to(text, curln, curc, 0);
2137                         txt_move_to(text, curln, curc, 1);
2138                         
2139                         txt_delete_char(text);
2140                         
2141                         text->undo_pos--;
2142                         break;
2143
2144                 case UNDO_BS_1:
2145                 case UNDO_BS_2:
2146                 case UNDO_BS_3:
2147                 case UNDO_BS_4:
2148                         charp = op - UNDO_BS_1 + 1;
2149                         uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
2150                         
2151                         /* get and restore the cursors */
2152                         txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
2153                         txt_move_to(text, curln, curc, 0);
2154                         txt_move_to(text, curln, curc, 1);
2155                         
2156                         txt_add_char(text, uchar);
2157
2158                         text->undo_pos--;
2159                         break;
2160
2161                 case UNDO_DEL_1:
2162                 case UNDO_DEL_2:
2163                 case UNDO_DEL_3:
2164                 case UNDO_DEL_4:
2165                         charp = op - UNDO_DEL_1 + 1;
2166                         uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
2167
2168                         /* get and restore the cursors */
2169                         txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
2170                         txt_move_to(text, curln, curc, 0);
2171                         txt_move_to(text, curln, curc, 1);
2172
2173                         txt_add_char(text, uchar);
2174
2175                         txt_move_left(text, 0);
2176
2177                         text->undo_pos--;
2178                         break;
2179
2180                 case UNDO_DBLOCK:
2181                         /* length of the string in the buffer */
2182                         linep = txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
2183
2184                         buf = MEM_mallocN(linep + 1, "dblock buffer");
2185                         for (i = 0; i < linep; i++) {
2186                                 buf[(linep - 1) - i] = text->undo_buf[text->undo_pos];
2187                                 text->undo_pos--;
2188                         }
2189                         buf[i] = 0;
2190
2191                         /* skip over the length that was stored again */
2192                         text->undo_pos -= 4;
2193
2194                         /* Get the cursor positions */
2195                         txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
2196
2197                         /* move cur to location that needs buff inserted */
2198                         txt_move_to(text, curln, curc, 0);
2199                         
2200                         txt_insert_buf(text, buf);
2201                         MEM_freeN(buf);
2202
2203                         /* restore the cursors */
2204                         txt_move_to(text, curln, curc, 0);
2205                         txt_move_to(text, selln, selc, 1);
2206
2207                         text->undo_pos--;
2208                         
2209                         break;
2210
2211                 case UNDO_IBLOCK:
2212                         /* length of the string in the buffer */
2213                         linep = txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
2214                         
2215                         /* txt_backspace_char removes utf8-characters, not bytes */
2216                         buf = MEM_mallocN(linep + 1, "iblock buffer");
2217                         for (i = 0; i < linep; i++) {
2218                                 buf[(linep - 1) - i] = text->undo_buf[text->undo_pos];
2219                                 text->undo_pos--;
2220                         }
2221                         buf[i] = 0;
2222                         linep = BLI_strlen_utf8(buf);
2223                         MEM_freeN(buf);
2224                         
2225                         /* skip over the length that was stored again */
2226                         text->undo_pos -= 4;
2227
2228                         /* get and restore the cursors */
2229                         txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
2230                         
2231                         txt_move_to(text, curln, curc, 0);
2232                         txt_move_to(text, selln, selc, 1);
2233                         
2234                         if ((curln == selln) && (curc == selc)) {
2235                                 /* disable tabs to spaces since moving right may involve skipping multiple spaces */
2236                                 prev_flags = text->flags;
2237                                 text->flags &= ~TXT_TABSTOSPACES;
2238                                 
2239                                 for (i = 0; i < linep; i++)
2240                                         txt_move_right(text, 1);
2241                                 
2242                                 text->flags = prev_flags;
2243                         }
2244                         
2245                         txt_delete_selected(text);
2246                         
2247                         text->undo_pos--;
2248                         break;
2249                 case UNDO_INDENT:
2250                 case UNDO_COMMENT:
2251                 case UNDO_DUPLICATE:
2252                 case UNDO_MOVE_LINES_UP:
2253                 case UNDO_MOVE_LINES_DOWN:
2254                         /* get and restore the cursors */
2255                         txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
2256                         txt_move_to(text, curln, curc, 0);
2257                         txt_move_to(text, selln, selc, 1);
2258                         
2259                         if (op == UNDO_INDENT) {
2260                                 txt_unindent(text);
2261                         }
2262                         else if (op == UNDO_COMMENT) {
2263                                 txt_uncomment(text);
2264                         }
2265                         else if (op == UNDO_DUPLICATE) {
2266                                 txt_delete_line(text, text->curl->next);
2267                         }
2268                         else if (op == UNDO_MOVE_LINES_UP) {
2269                                 txt_move_lines(text, TXT_MOVE_LINE_DOWN);
2270                         }
2271                         else if (op == UNDO_MOVE_LINES_DOWN) {
2272                                 txt_move_lines(text, TXT_MOVE_LINE_UP);
2273                         }
2274                         
2275                         text->undo_pos--;
2276                         break;
2277                 case UNDO_UNINDENT:
2278                 case UNDO_UNCOMMENT:
2279                 {
2280                         void (*txt_prefix_fn)(Text *);
2281                         void (*txt_unprefix_fn)(Text *);
2282                         int count;
2283                         int i;
2284                         /* Get and restore the cursors */
2285                         txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
2286                         txt_move_to(text, curln, curc, 0);
2287                         txt_move_to(text, selln, selc, 1);
2288
2289                         /* Un-unindent */
2290                         if (op == UNDO_UNINDENT) {
2291                                 txt_prefix_fn = txt_indent;
2292                                 txt_unprefix_fn = txt_unindent;
2293                         }
2294                         else {
2295                                 txt_prefix_fn = txt_comment;
2296                                 txt_unprefix_fn = txt_uncomment;
2297                         }
2298
2299                         txt_prefix_fn(text);
2300
2301                         /* Get the count */
2302                         count = txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
2303                         /* Iterate! */
2304                         txt_pop_sel(text);
2305
2306                         for (i = 0; i < count; i++) {
2307                                 txt_move_to(text, txt_undo_read_uint32(text->undo_buf, &text->undo_pos), 0, 0);
2308                                 /* Un-un-unindent/comment */
2309                                 txt_unprefix_fn(text);
2310                         }
2311                         /* Restore selection */
2312                         txt_move_to(text, curln, curc, 0);
2313                         txt_move_to(text, selln, selc, 1);
2314                         /* Jumo over count */
2315                         txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
2316                         /* Jump over closing OP byte */
2317                         text->undo_pos--;
2318                         break;
2319                 }
2320                 default:
2321                         //XXX error("Undo buffer error - resetting");
2322                         text->undo_pos = -1;
2323                         
2324                         break;
2325         }
2326         
2327         undoing = 0;
2328 }
2329
2330 void txt_do_redo(Text *text)
2331 {
2332         char op;
2333         char *buf;
2334         unsigned int linep;
2335         unsigned short charp;
2336         unsigned int uchar;
2337         unsigned int curln, selln;
2338         unsigned short curc, selc;
2339         
2340         text->undo_pos++;
2341         op = text->undo_buf[text->undo_pos];
2342         
2343         if (!op) {
2344                 text->undo_pos--;
2345                 return;
2346         }
2347         
2348         undoing = 1;
2349
2350         switch (op) {
2351                 case UNDO_INSERT_1:
2352                 case UNDO_INSERT_2:
2353                 case UNDO_INSERT_3:
2354                 case UNDO_INSERT_4:
2355                         text->undo_pos++;
2356                         
2357                         /* get and restore the cursors */
2358                         txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
2359                         txt_move_to(text, curln, curc, 0);
2360                         txt_move_to(text, curln, curc, 1);
2361                         
2362                         charp = op - UNDO_INSERT_1 + 1;
2363                         uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp);
2364
2365                         txt_add_char(text, uchar);
2366                         break;
2367
2368                 case UNDO_BS_1:
2369                 case UNDO_BS_2:
2370                 case UNDO_BS_3:
2371                 case UNDO_BS_4:
2372                         text->undo_pos++;
2373
2374                         /* get and restore the cursors */
2375                         txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
2376                         txt_move_to(text, curln, curc, 0);
2377                         txt_move_to(text, curln, curc, 1);
2378
2379                         text->undo_pos += op - UNDO_BS_1 + 1;
2380                         
2381                         /* move right so we backspace the correct char */
2382                         txt_move_right(text, 0);
2383                         txt_backspace_char(text);
2384
2385                         break;
2386
2387                 case UNDO_DEL_1:
2388                 case UNDO_DEL_2:
2389                 case UNDO_DEL_3:
2390                 case UNDO_DEL_4:
2391                         text->undo_pos++;
2392
2393                         /* get and restore the cursors */
2394                         txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
2395                         txt_move_to(text, curln, curc, 0);
2396                         txt_move_to(text, curln, curc, 1);
2397                         
2398                         text->undo_pos += op - UNDO_DEL_1 + 1;
2399
2400                         txt_delete_char(text);
2401
2402                         break;
2403
2404                 case UNDO_DBLOCK:
2405                         text->undo_pos++;
2406
2407                         /* get and restore the cursors */
2408                         txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
2409                         txt_move_to(text, curln, curc, 0);
2410                         txt_move_to(text, selln, selc, 1);
2411
2412                         /* length of the block */
2413                         linep = txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
2414                         
2415                         text->undo_pos += linep;
2416
2417                         /* skip over the length that was stored again */
2418                         text->undo_pos += 4;
2419                         
2420                         txt_delete_sel(text);
2421
2422                         break;
2423
2424                 case UNDO_IBLOCK:
2425                         text->undo_pos++;
2426
2427                         /* get and restore the cursors */
2428                         txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
2429                         txt_move_to(text, curln, curc, 0);
2430                         txt_move_to(text, curln, curc, 1);
2431
2432                         /* length of the block */
2433                         linep = txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
2434
2435                         buf = MEM_mallocN(linep + 1, "iblock buffer");
2436                         memcpy(buf, &text->undo_buf[text->undo_pos], linep);
2437                         text->undo_pos += linep;
2438                         buf[linep] = 0;
2439                         
2440                         txt_insert_buf(text, buf);
2441                         MEM_freeN(buf);
2442
2443                         /* skip over the length that was stored again */
2444                         text->undo_pos += 4;
2445
2446                         break;
2447                         
2448                 case UNDO_INDENT:
2449                 case UNDO_COMMENT:
2450                 case UNDO_UNCOMMENT:
2451                 case UNDO_DUPLICATE:
2452                 case UNDO_MOVE_LINES_UP:
2453                 case UNDO_MOVE_LINES_DOWN:
2454                         text->undo_pos++;
2455
2456                         /* get and restore the cursors */
2457                         txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
2458                         txt_move_to(text, curln, curc, 0);
2459                         txt_move_to(text, selln, selc, 1);
2460
2461                         if (op == UNDO_INDENT) {
2462                                 txt_indent(text);
2463                         }
2464                         else if (op == UNDO_COMMENT) {
2465                                 txt_comment(text);
2466                         }
2467                         else if (op == UNDO_UNCOMMENT) {
2468                                 txt_uncomment(text);
2469                         }
2470                         else if (op == UNDO_DUPLICATE) {
2471                                 txt_duplicate_line(text);
2472                         }
2473                         else if (op == UNDO_MOVE_LINES_UP) {
2474                                 /* offset the cursor by + 1 */
2475                                 txt_move_to(text, curln + 1, curc, 0);
2476                                 txt_move_to(text, selln + 1, selc, 1);
2477
2478                                 txt_move_lines(text, TXT_MOVE_LINE_UP);
2479                         }
2480                         else if (op == UNDO_MOVE_LINES_DOWN) {
2481                                 /* offset the cursor by - 1 */
2482                                 txt_move_to(text, curln - 1, curc, 0);
2483                                 txt_move_to(text, selln - 1, selc, 1);
2484
2485                                 txt_move_lines(text, TXT_MOVE_LINE_DOWN);
2486                         }
2487
2488                         /* re-restore the cursors since they got moved when redoing */
2489                         txt_move_to(text, curln, curc, 0);
2490                         txt_move_to(text, selln, selc, 1);
2491
2492                         break;
2493                 case UNDO_UNINDENT:
2494                 {
2495                         int count;
2496                         int i;
2497
2498                         text->undo_pos++;
2499                         /* Scan all the stuff described in txt_undo_add_unindent_op */
2500                         count = txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
2501                         for (i = 0; i < count; i++) {
2502                                 txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
2503                         }
2504                         /* Count again */
2505                         txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
2506                         /* Get the selection and re-unindent */
2507                         txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
2508                         txt_move_to(text, curln, curc, 0);
2509                         txt_move_to(text, selln, selc, 1);
2510                         txt_unindent(text);
2511                         break;
2512                 }
2513                 default:
2514                         //XXX error("Undo buffer error - resetting");
2515                         text->undo_pos = -1;
2516                         
2517                         break;
2518         }
2519         
2520         undoing = 0;
2521 }
2522
2523 /**************************/
2524 /* Line editing functions */ 
2525 /**************************/
2526
2527 void txt_split_curline(Text *text)
2528 {
2529         TextLine *ins;
2530         char *left, *right;
2531
2532         if (!text->curl) return;
2533
2534         txt_delete_sel(text);
2535
2536         if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, '\n');
2537         
2538         /* Make the two half strings */
2539
2540         left = MEM_mallocN(text->curc + 1, "textline_string");
2541         if (text->curc) memcpy(left, text->curl->line, text->curc);
2542         left[text->curc] = 0;
2543         
2544         right = MEM_mallocN(text->curl->len - text->curc + 1, "textline_string");
2545         memcpy(right, text->curl->line + text->curc, text->curl->len - text->curc + 1);
2546
2547         MEM_freeN(text->curl->line);
2548         if (text->curl->format) MEM_freeN(text->curl->format);
2549
2550         /* Make the new TextLine */
2551         
2552         ins = MEM_mallocN(sizeof(TextLine), "textline");
2553         ins->line = left;
2554         ins->format = NULL;
2555         ins->len = text->curc;
2556
2557         text->curl->line = right;
2558         text->curl->format = NULL;
2559         text->curl->len = text->curl->len - text->curc;
2560         
2561         BLI_insertlinkbefore(&text->lines, text->curl, ins);
2562         
2563         text->curc = 0;
2564         
2565         txt_make_dirty(text);
2566         txt_clean_text(text);
2567         
2568         txt_pop_sel(text);
2569 }
2570
2571 static void txt_delete_line(Text *text, TextLine *line)
2572 {
2573         if (!text->curl) return;
2574
2575         BLI_remlink(&text->lines, line);
2576         
2577         if (line->line) MEM_freeN(line->line);
2578         if (line->format) MEM_freeN(line->format);
2579
2580         MEM_freeN(line);
2581
2582         txt_make_dirty(text);
2583         txt_clean_text(text);
2584 }
2585
2586 static void txt_combine_lines(Text *text, TextLine *linea, TextLine *lineb)
2587 {
2588         char *tmp, *s;
2589         
2590         if (!linea || !lineb) return;
2591
2592
2593         tmp = MEM_mallocN(linea->len + lineb->len + 1, "textline_string");
2594         
2595         s = tmp;
2596         s += BLI_strcpy_rlen(s, linea->line);
2597         s += BLI_strcpy_rlen(s, lineb->line);
2598         (void)s;
2599
2600         make_new_line(linea, tmp);
2601         
2602         txt_delete_line(text, lineb);
2603         
2604         txt_make_dirty(text);
2605         txt_clean_text(text);
2606 }
2607
2608 void txt_duplicate_line(Text *text)
2609 {
2610         TextLine *textline;
2611         
2612         if (!text->curl) return;
2613         
2614         if (text->curl == text->sell) {
2615                 textline = txt_new_line(text->curl->line);
2616                 BLI_insertlinkafter(&text->lines, text->curl, textline);
2617                 
2618                 txt_make_dirty(text);
2619                 txt_clean_text(text);
2620                 
2621                 if (!undoing) txt_undo_add_op(text, UNDO_DUPLICATE);
2622         }
2623 }
2624
2625 void txt_delete_char(Text *text) 
2626 {
2627         unsigned int c = '\n';
2628
2629         if (!text->curl) return;
2630
2631         if (txt_has_sel(text)) { /* deleting a selection */
2632                 txt_delete_sel(text);
2633                 txt_make_dirty(text);
2634                 return;
2635         }
2636         else if (text->curc == text->curl->len) { /* Appending two lines */
2637                 if (text->curl->next) {
2638                         txt_combine_lines(text, text->curl, text->curl->next);
2639                         txt_pop_sel(text);
2640                 }
2641                 else
2642                         return;
2643         }
2644         else { /* Just deleting a char */
2645                 size_t c_len = 0;
2646                 c = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &c_len);
2647                 
2648                 memmove(text->curl->line + text->curc, text->curl->line + text->curc + c_len, text->curl->len - text->curc - c_len + 1);
2649
2650                 text->curl->len -= c_len;
2651
2652                 txt_pop_sel(text);
2653         }
2654
2655         txt_make_dirty(text);
2656         txt_clean_text(text);
2657         
2658         if (!undoing) txt_undo_add_charop(text, UNDO_DEL_1, c);
2659 }
2660
2661 void txt_delete_word(Text *text)
2662 {
2663         txt_jump_right(text, true, true);
2664         txt_delete_sel(text);
2665         txt_make_dirty(text);
2666 }
2667
2668 void txt_backspace_char(Text *text)
2669 {
2670         unsigned int c = '\n';
2671         
2672         if (!text->curl) return;
2673         
2674         if (txt_has_sel(text)) { /* deleting a selection */
2675                 txt_delete_sel(text);
2676                 txt_make_dirty(text);
2677                 return;
2678         }
2679         else if (text->curc == 0) { /* Appending two lines */
2680                 if (!text->curl->prev) return;
2681                 
2682                 text->curl = text->curl->prev;
2683                 text->curc = text->curl->len;
2684                 
2685                 txt_combine_lines(text, text->curl, text->curl->next);
2686                 txt_pop_sel(text);
2687         }
2688         else { /* Just backspacing a char */
2689                 size_t c_len = 0;
2690                 const char *prev = BLI_str_prev_char_utf8(text->curl->line + text->curc);
2691                 c = BLI_str_utf8_as_unicode_and_size(prev, &c_len);
2692                 
2693                 /* source and destination overlap, don't use memcpy() */
2694                 memmove(text->curl->line + text->curc - c_len,
2695                         text->curl->line + text->curc,
2696                         text->curl->len  - text->curc + 1);
2697
2698                 text->curl->len -= c_len;
2699                 text->curc -= c_len;
2700
2701                 txt_pop_sel(text);
2702         }
2703
2704         txt_make_dirty(text);
2705         txt_clean_text(text);
2706         
2707         if (!undoing) txt_undo_add_charop(text, UNDO_BS_1, c);
2708 }
2709
2710 void txt_backspace_word(Text *text)
2711 {
2712         txt_jump_left(text, true, true);
2713         txt_delete_sel(text);
2714         txt_make_dirty(text);
2715 }
2716
2717 /* Max spaces to replace a tab with, currently hardcoded to TXT_TABSIZE = 4.
2718  * Used by txt_convert_tab_to_spaces, indent and unindent.
2719  * Remember to change this string according to max tab size */
2720 static char tab_to_spaces[] = "    ";
2721
2722 static void txt_convert_tab_to_spaces(Text *text)
2723 {
2724         /* sb aims to pad adjust the tab-width needed so that the right number of spaces
2725          * is added so that the indention of the line is the right width (i.e. aligned
2726          * to multiples of TXT_TABSIZE)
2727          */
2728         const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
2729         txt_insert_buf(text, sb);
2730 }
2731
2732 static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs)
2733 {
2734         char *tmp, ch[BLI_UTF8_MAX];
2735         size_t add_len;
2736
2737         if (!text->curl) return 0;
2738
2739         if (add == '\n') {
2740                 txt_split_curline(text);
2741                 return true;
2742         }
2743         
2744         /* insert spaces rather than tabs */
2745         if (add == '\t' && replace_tabs) {
2746                 txt_convert_tab_to_spaces(text);
2747                 return true;
2748         }
2749
2750         txt_delete_sel(text);
2751         
2752         if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, add);
2753
2754         add_len = BLI_str_utf8_from_unicode(add, ch);
2755         
2756         tmp = MEM_mallocN(text->curl->len + add_len + 1, "textline_string");
2757         
2758         memcpy(tmp, text->curl->line, text->curc);
2759         memcpy(tmp + text->curc, ch, add_len);
2760         memcpy(tmp + text->curc + add_len, text->curl->line + text->curc, text->curl->len - text->curc + 1);
2761
2762         make_new_line(text->curl, tmp);
2763                 
2764         text->curc += add_len;
2765
2766         txt_pop_sel(text);
2767         
2768         txt_make_dirty(text);
2769         txt_clean_text(text);
2770
2771         return 1;
2772 }
2773
2774 bool txt_add_char(Text *text, unsigned int add)
2775 {
2776         return txt_add_char_intern(text, add, (text->flags & TXT_TABSTOSPACES) != 0);
2777 }
2778
2779 bool txt_add_raw_char(Text *text, unsigned int add)
2780 {
2781         return txt_add_char_intern(text, add, 0);
2782 }
2783
2784 void txt_delete_selected(Text *text)
2785 {
2786         txt_delete_sel(text);
2787         txt_make_dirty(text);
2788 }
2789
2790 bool txt_replace_char(Text *text, unsigned int add)
2791 {
2792         unsigned int del;
2793         size_t del_size = 0, add_size;
2794         char ch[BLI_UTF8_MAX];
2795
2796         if (!text->curl) return false;
2797
2798         /* If text is selected or we're at the end of the line just use txt_add_char */
2799         if (text->curc == text->curl->len || txt_has_sel(text) || add == '\n') {
2800                 return txt_add_char(text, add);
2801         }
2802         
2803         del = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size);
2804         add_size = BLI_str_utf8_from_unicode(add, ch);
2805         
2806         if (add_size > del_size) {
2807                 char *tmp = MEM_mallocN(text->curl->len + add_size - del_size + 1, "textline_string");
2808                 memcpy(tmp, text->curl->line, text->curc);
2809                 memcpy(tmp + text->curc + add_size, text->curl->line + text->curc + del_size, text->curl->len - text->curc - del_size + 1);
2810                 MEM_freeN(text->curl->line);
2811                 text->curl->line = tmp;
2812         }
2813         else if (add_size < del_size) {
2814                 char *tmp = text->curl->line;
2815                 memmove(tmp + text->curc + add_size, tmp + text->curc + del_size, text->curl->len - text->curc - del_size + 1);
2816         }
2817         
2818         memcpy(text->curl->line + text->curc, ch, add_size);
2819         text->curc += add_size;
2820         text->curl->len += add_size - del_size;
2821         
2822         txt_pop_sel(text);
2823         txt_make_dirty(text);
2824         txt_clean_text(text);
2825
2826         /* Should probably create a new op for this */
2827         if (!undoing) {
2828                 txt_undo_add_charop(text, UNDO_INSERT_1, add);
2829                 text->curc -= add_size;
2830                 txt_pop_sel(text);
2831                 txt_undo_add_charop(text, UNDO_DEL_1, del);
2832                 text->curc += add_size;
2833                 txt_pop_sel(text);
2834         }
2835         return true;
2836 }
2837
2838 /**
2839  * Generic prefix operation, use for comment & indent.
2840  *
2841  * \note caller must handle undo.
2842  */
2843 static void txt_select_prefix(Text *text, const char *add)
2844 {
2845         int len, num, curc_old;
2846         char *tmp;
2847
2848         const int indentlen = strlen(add);
2849
2850         BLI_assert(!ELEM(NULL, text->curl, text->sell));
2851
2852         curc_old = text->curc;
2853
2854         num = 0;
2855         while (true) {
2856
2857                 /* don't indent blank lines */
2858                 if (text->curl->len != 0) {
2859                         tmp = MEM_mallocN(text->curl->len + indentlen + 1, "textline_string");
2860
2861                         text->curc = 0;
2862                         if (text->curc) memcpy(tmp, text->curl->line, text->curc);  /* XXX never true, check prev line */
2863                         memcpy(tmp + text->curc, add, indentlen);
2864
2865                         len = text->curl->len - text->curc;
2866                         if (len > 0) memcpy(tmp + text->curc + indentlen, text->curl->line + text->curc, len);
2867                         tmp[text->curl->len + indentlen] = 0;
2868
2869                         make_new_line(text->curl, tmp);
2870
2871                         text->curc += indentlen;
2872
2873                         txt_make_dirty(text);
2874                         txt_clean_text(text);
2875                 }
2876                 
2877                 if (text->curl == text->sell) {
2878                         text->selc += indentlen;
2879                         break;
2880                 }
2881                 else {
2882                         text->curl = text->curl->next;
2883                         num++;
2884                 }
2885         }
2886         if (!curc_old) text->curc = 0;
2887         else text->curc = curc_old + indentlen;
2888
2889         while (num > 0) {
2890                 text->curl = text->curl->prev;
2891                 num--;
2892         }
2893         
2894         /* caller must handle undo */
2895 }
2896
2897 /**
2898  * Generic un-prefix operation, use for comment & indent.
2899  *
2900  * \param r_line_index_mask: List of lines that are already at indent level 0,
2901  * to store them later into the undo buffer.
2902  *
2903  * \note caller must handle undo.
2904  */
2905 static void txt_select_unprefix(
2906         Text *text, const char *remove,
2907         ListBase *r_line_index_mask, int *r_line_index_mask_len)
2908 {
2909         int num = 0;
2910         const int indentlen = strlen(remove);
2911         bool unindented_first = false;
2912
2913         int curl_span_init = 0;
2914
2915         BLI_assert(!ELEM(NULL, text->curl, text->sell));
2916
2917         BLI_listbase_clear(r_line_index_mask);
2918         *r_line_index_mask_len = 0;
2919
2920         if (!undoing) {
2921                 curl_span_init = txt_get_span(text->lines.first, text->curl);
2922         }
2923
2924         while (true) {
2925                 bool changed = false;
2926                 if (STREQLEN(text->curl->line, remove, indentlen)) {
2927                         if (num == 0)
2928                                 unindented_first = true;
2929                         text->curl->len -= indentlen;
2930                         memmove(text->curl->line, text->curl->line + indentlen, text->curl->len + 1);
2931                         changed = true;
2932                 }
2933                 else {
2934                         if (!undoing) {
2935                                 /* Create list element for 0 indent line */
2936                                 struct LinkInt *idata = MEM_mallocN(sizeof(struct LinkInt), __func__);
2937                                 idata->value = curl_span_init + num;
2938                                 BLI_assert(idata->value == txt_get_span(text->lines.first, text->curl));
2939                                 BLI_addtail(r_line_index_mask, idata);
2940                                 (*r_line_index_mask_len) += 1;
2941                         }
2942                 }
2943         
2944                 txt_make_dirty(text);
2945                 txt_clean_text(text);
2946                 
2947                 if (text->curl == text->sell) {
2948                         if (changed)
2949                                 text->selc = MAX2(text->selc - indentlen, 0);
2950                         break;
2951                 }
2952                 else {
2953                         text->curl = text->curl->next;
2954                         num++;
2955
2956                 }
2957                 
2958         }
2959
2960         if (unindented_first)
2961                 text->curc = MAX2(text->curc - indentlen, 0);
2962
2963         while (num > 0) {
2964                 text->curl = text->curl->prev;
2965                 num--;
2966         }
2967
2968         /* caller must handle undo */
2969 }
2970
2971 void txt_comment(Text *text)
2972 {
2973         const char *prefix = "#";
2974
2975         if (ELEM(NULL, text->curl, text->sell)) {
2976                 return;
2977         }
2978
2979         txt_select_prefix(text, prefix);
2980
2981         if (!undoing) {
2982                 txt_undo_add_op(text, UNDO_COMMENT);
2983         }
2984 }
2985
2986 void txt_uncomment(Text *text)
2987 {
2988         const char *prefix = "#";
2989         ListBase line_index_mask;
2990         int line_index_mask_len;
2991
2992         if (ELEM(NULL, text->curl, text->sell)) {
2993                 return;
2994         }
2995
2996         txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len);
2997
2998         if (!undoing) {
2999                 txt_undo_add_unprefix_op(text, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len);
3000         }
3001
3002         BLI_freelistN(&line_index_mask);
3003 }
3004
3005 void txt_indent(Text *text)
3006 {
3007         const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
3008
3009         if (ELEM(NULL, text->curl, text->sell)) {
3010                 return;
3011         }
3012
3013         txt_select_prefix(text, prefix);
3014
3015         if (!undoing) {
3016                 txt_undo_add_op(text, UNDO_INDENT);
3017         }
3018 }
3019
3020 void txt_unindent(Text *text)
3021 {
3022         const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
3023         ListBase line_index_mask;
3024         int line_index_mask_len;
3025         
3026         if (ELEM(NULL, text->curl, text->sell)) {
3027                 return;
3028         }
3029
3030         txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len);
3031
3032         if (!undoing) {
3033                 txt_undo_add_unprefix_op(text, UNDO_UNINDENT, &line_index_mask, line_index_mask_len);
3034         }
3035
3036         BLI_freelistN(&line_index_mask);
3037 }
3038
3039 void txt_move_lines(struct Text *text, const int direction)
3040 {
3041         TextLine *line_other;
3042
3043         BLI_assert(ELEM(direction, TXT_MOVE_LINE_UP, TXT_MOVE_LINE_DOWN));
3044
3045         if (!text->curl || !text->sell) return;
3046         
3047         txt_order_cursors(text, false);
3048
3049         line_other =  (direction == TXT_MOVE_LINE_DOWN) ? text->sell->next : text->curl->prev;
3050         
3051         if (!line_other) return;
3052                 
3053         BLI_remlink(&text->lines, line_other);
3054
3055         if (direction == TXT_MOVE_LINE_DOWN) {
3056                 BLI_insertlinkbefore(&text->lines, text->curl, line_other);
3057         }
3058         else {
3059                 BLI_insertlinkafter(&text->lines, text->sell, line_other);
3060         }
3061
3062         txt_make_dirty(text);
3063         txt_clean_text(text);
3064         
3065         if (!undoing) {
3066                 txt_undo_add_op(text, (direction == TXT_MOVE_LINE_DOWN) ? UNDO_MOVE_LINES_DOWN : UNDO_MOVE_LINES_UP);
3067         }
3068 }
3069
3070 int txt_setcurr_tab_spaces(Text *text, int space)
3071 {
3072         int i = 0;
3073         int test = 0;
3074         const char *word = ":";
3075         const char *comm = "#";
3076         const char indent = (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t';
3077         static const char *back_words[] = {"return", "break", "continue", "pass", "yield", NULL};
3078
3079         if (!text->curl) return 0;
3080
3081         while (text->curl->line[i] == indent) {
3082                 //we only count those tabs/spaces that are before any text or before the curs;
3083                 if (i == text->curc) {
3084                         return i;
3085                 }
3086                 else {
3087                         i++;
3088                 }
3089         }
3090         if (strstr(text->curl->line, word)) {
3091                 /* if we find a ':' on this line, then add a tab but not if it is:
3092                  *  1) in a comment
3093                  *  2) within an identifier
3094                  *      3) after the cursor (text->curc), i.e. when creating space before a function def [#25414] 
3095                  */
3096                 int a;
3097                 bool is_indent = false;
3098                 for (a = 0; (a < text->curc) && (text->curl->line[a] != '\0'); a++) {
3099                         char ch = text->curl->line[a];
3100                         if (ch == '#') {
3101                                 break;
3102                         }
3103                         else if (ch == ':') {
3104                                 is_indent = 1;
3105                         }
3106                         else if (ch != ' ' && ch != '\t') {
3107                                 is_indent = 0;
3108                         }
3109                 }
3110                 if (is_indent) {
3111                         i += space;
3112                 }
3113         }
3114
3115         for (test = 0; back_words[test]; test++) {
3116                 /* if there are these key words then remove a tab because we are done with the block */
3117                 if (strstr(text->curl->line, back_words[test]) && i > 0) {
3118                         if (strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm)) {
3119                                 i -= space;
3120                         }
3121                 }
3122         }
3123         return i;
3124 }
3125
3126 /*******************************/
3127 /* Character utility functions */
3128 /*******************************/
3129
3130 int text_check_bracket(const char ch)
3131 {
3132         int a;
3133         char opens[] = "([{";
3134         char close[] = ")]}";
3135
3136         for (a = 0; a < (sizeof(opens) - 1); a++) {
3137                 if (ch == opens[a])
3138                         return a + 1;
3139                 else if (ch == close[a])
3140                         return -(a + 1);
3141         }
3142         return 0;
3143 }
3144
3145 /* TODO, have a function for operators - http://docs.python.org/py3k/reference/lexical_analysis.html#operators */
3146 bool text_check_delim(const char ch)
3147 {
3148         int a;
3149         char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,@";
3150
3151         for (a = 0; a < (sizeof(delims) - 1); a++) {
3152                 if (ch == delims[a])
3153                         return true;
3154         }
3155         return false;
3156 }
3157
3158 bool text_check_digit(const char ch)
3159 {
3160         if (ch < '0') return false;
3161         if (ch <= '9') return true;
3162         return false;
3163 }
3164
3165 bool text_check_identifier(const char ch)
3166 {
3167         if (ch < '0') return false;
3168         if (ch <= '9') return true;
3169         if (ch < 'A') return false;
3170         if (ch <= 'Z' || ch == '_') return true;
3171         if (ch < 'a') return false;
3172         if (ch <= 'z') return true;
3173         return false;
3174 }
3175
3176 bool text_check_identifier_nodigit(const char ch)
3177 {
3178         if (ch <= '9') return false;
3179         if (ch < 'A') return false;
3180         if (ch <= 'Z' || ch == '_') return true;
3181         if (ch < 'a') return false;
3182         if (ch <= 'z') return true;
3183         return false;
3184 }
3185
3186 #ifndef WITH_PYTHON
3187 int text_check_identifier_unicode(const unsigned int ch)
3188 {
3189         return (ch < 255 && text_check_identifier((unsigned int)ch));
3190 }
3191
3192 int text_check_identifier_nodigit_unicode(const unsigned int ch)
3193 {
3194         return (ch < 255 && text_check_identifier_nodigit((char)ch));
3195 }
3196 #endif  /* WITH_PYTHON */
3197
3198 bool text_check_whitespace(const char ch)
3199 {
3200         if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
3201                 return true;
3202         return false;
3203 }
3204
3205 int text_find_identifier_start(const char *str, int i)
3206 {
3207         if (UNLIKELY(i <= 0)) {
3208                 return 0;
3209         }
3210
3211         while (i--) {
3212                 if (!text_check_identifier(str[i])) {
3213                         break;
3214                 }
3215         }
3216         i++;
3217         return i;
3218 }