Any script can now register a unique key combination as part of its bpy header. For...
[blender-staging.git] / source / blender / src / drawtext.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <math.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef _WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #include "BLI_winstuff.h"
46 #endif   
47 #include "MEM_guardedalloc.h"
48 #include "PIL_time.h"
49
50 #include "BMF_Api.h"
51
52 #include "BLI_blenlib.h"
53 #include "BLI_arithb.h"
54
55 #include "DNA_text_types.h"
56 #include "DNA_space_types.h"
57 #include "DNA_screen_types.h"
58 #include "DNA_userdef_types.h"
59
60 #include "BKE_utildefines.h"
61 #include "BKE_text.h"
62 #include "BKE_global.h"
63 #include "BKE_main.h"
64 #include "BKE_node.h"
65 #include "BKE_suggestions.h"
66
67 #include "BIF_gl.h"
68 #include "BIF_glutil.h"
69 #include "BIF_keyval.h"
70 #include "BIF_interface.h"
71 #include "BIF_drawtext.h"
72 #include "BIF_editfont.h"
73 #include "BIF_spacetypes.h"
74 #include "BIF_usiblender.h"
75 #include "BIF_screen.h"
76 #include "BIF_toolbox.h"
77 #include "BIF_space.h"
78 #include "BIF_mywindow.h"
79 #include "BIF_resources.h"
80
81 #include "BSE_filesel.h"
82
83 #include "BPY_extern.h"
84 #include "BPY_menus.h"
85
86 #include "mydevice.h"
87 #include "blendef.h" 
88 #include "winlay.h"
89
90 #define TEXTXLOC        38
91
92 #define SUGG_LIST_SIZE 7
93 #define SUGG_LIST_WIDTH 20
94
95 /* forward declarations */
96
97 void drawtextspace(ScrArea *sa, void *spacedata);
98 void winqreadtextspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
99 void txt_copy_selectbuffer (Text *text);
100 void do_brackets();
101
102 void get_selection_buffer(Text *text);
103 int check_bracket(char *string);
104 static int check_delim(char *string);
105 static int check_numbers(char *string);
106 static int check_builtinfuncs(char *string);
107 static int check_specialvars(char *string);
108 static int check_identifier(char ch);
109
110 static void get_suggest_prefix(Text *text);
111 static void confirm_suggestion(Text *text);
112
113 static void *last_txt_find_string= NULL;
114 static double last_check_time= 0;
115
116 static BMF_Font *spacetext_get_font(SpaceText *st) {
117         static BMF_Font *scr12= NULL;
118         static BMF_Font *scr15= NULL;
119         
120         switch (st->font_id) {
121         default:
122         case 0:
123                 if (!scr12)
124                         scr12= BMF_GetFont(BMF_kScreen12);
125                 return scr12;
126         case 1:
127                 if (!scr15)
128                         scr15= BMF_GetFont(BMF_kScreen15);
129                 return scr15;
130         }
131 }
132
133 static int spacetext_get_fontwidth(SpaceText *st) {
134         return BMF_GetCharacterWidth(spacetext_get_font(st), ' ');
135 }
136
137 static char *temp_char_buf= NULL;
138 static int *temp_char_accum= NULL;
139 static int temp_char_len= 0;
140 static int temp_char_pos= 0;
141
142 static void temp_char_write(char c, int accum) {
143         if (temp_char_len==0 || temp_char_pos>=temp_char_len) {
144                 char *nbuf; int *naccum;
145                 int olen= temp_char_len;
146                 
147                 if (olen) temp_char_len*= 2;
148                 else temp_char_len= 256;
149                 
150                 nbuf= MEM_mallocN(sizeof(*temp_char_buf)*temp_char_len, "temp_char_buf");
151                 naccum= MEM_mallocN(sizeof(*temp_char_accum)*temp_char_len, "temp_char_accum");
152                 
153                 if (olen) {
154                         memcpy(nbuf, temp_char_buf, olen);
155                         memcpy(naccum, temp_char_accum, olen);
156                         
157                         MEM_freeN(temp_char_buf);
158                         MEM_freeN(temp_char_accum);
159                 }
160                 
161                 temp_char_buf= nbuf;
162                 temp_char_accum= naccum;
163         }
164         
165         temp_char_buf[temp_char_pos]= c;        
166         temp_char_accum[temp_char_pos]= accum;
167         
168         if (c==0) temp_char_pos= 0;
169         else temp_char_pos++;
170 }
171
172 void free_txt_data(void) {
173         txt_free_cut_buffer();
174         
175         if (last_txt_find_string) MEM_freeN(last_txt_find_string);
176         if (temp_char_buf) MEM_freeN(temp_char_buf);
177         if (temp_char_accum) MEM_freeN(temp_char_accum);        
178 }
179
180 static int render_string (SpaceText *st, char *in) {
181         int r = 0, i = 0;
182         
183         while(*in) {
184                 if (*in=='\t') {
185                         if (temp_char_pos && *(in-1)=='\t') i= st->tabnumber;
186                         else if (st->tabnumber > 0) i= st->tabnumber - (temp_char_pos%st->tabnumber);
187                         while(i--) temp_char_write(' ', r);
188                 } else temp_char_write(*in, r);
189
190                 r++;
191                 in++;
192         }
193         r= temp_char_pos;
194         temp_char_write(0, 0);
195                 
196         return r;
197 }
198
199 void get_format_string(SpaceText *st) 
200 {
201         Text *text = st->text;
202         TextLine *tmp;
203         char *in_line;
204         char format[2000], check[200], other[2];
205         unsigned char c;
206         int spot, letter, tabs, mem_amount;
207         size_t a, b, len;
208         
209         if(!text) return;
210         tmp = text->lines.first;
211         
212         while(tmp) {
213                 in_line = tmp->line;
214                 
215                 len = strlen(in_line);
216                 /* weak code... but we dont want crashes (ton) */
217                 if(len>2000-1) {
218                         if (tmp->format) MEM_freeN(tmp->format);
219                         tmp->format= NULL;
220                 }
221                 else {
222                         
223                         spot = 0;
224                         tabs = 0;
225                         //see how many tabs we have
226                         for(a = 0; a <len; a++) {
227                                 c = (unsigned char) in_line[a];
228                                 if(c == '\t') {
229                                         tabs++;
230                                 }
231                         }
232                         //calculate the amount of MEM_mallocN we neen
233                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len; // +2 for good measure
234                         if (tmp->format) MEM_freeN(tmp->format);
235                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
236                         
237                         for (a = 0; a < len; a++) {
238                                 c = (unsigned char) in_line[a];
239
240                                 check[0] = c;
241                                 check[1] = '\0';
242
243                                 if (check_delim(check))
244                                 {
245                                         switch (c) {
246                                                 case '\"':
247                                                         if(in_line[a] == '\"' && in_line[a+1] == '\"' && in_line[a+2] == '\"') { 
248                                                                 format[spot] = format[spot+1] = format[spot+2] = 'l';
249                                                                 spot +=3;
250                                                                 a += 3;
251                                                                 while(in_line[a] != '\"' || in_line[a-1] != '\"' || in_line[a-2] != '\"') {
252                                                                         c = (unsigned char) in_line[a];
253                                                                         if(a >= len) {
254                                                                                 format[spot] = '\0';
255                                                                                 memcpy(tmp->format, format, strlen(format));
256                                                                                 if(!(tmp= tmp->next)) {
257                                                                                         return;
258                                                                                 } else {
259                                                                                         in_line = tmp->line;
260                                                                                         len = strlen(in_line);
261                                                                                         tabs = 0;
262                                                                                         for(b = 0; b <len; b++) {
263                                                                                                 c = (unsigned char) in_line[b];
264                                                                                                 if(c == '\t') {
265                                                                                                         tabs++;
266                                                                                                 }
267                                                                                         }
268                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
269                                                                                         if (tmp->format) MEM_freeN(tmp->format);
270                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
271                                                                                         a = 0; spot = 0;
272                                                                                 }
273                                                                         } else {
274                                                                                 if(c == '\t' || c == ' ') {
275                                                                                         if(c == '\t') {
276                                                                                                 for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
277                                                                                                         format[spot] = ' ';
278                                                                                                         spot++;
279                                                                                                 }
280                                                                                                 a++;
281                                                                                         } else {
282                                                                                                 format[spot] = ' ';
283                                                                                                 a++; spot++;
284                                                                                 }
285                                                                                 } else {
286                                                                                         format[spot] = 'l';
287                                                                                         a++; spot++;
288                                                                                 }
289                                                                         }
290                                                                 }
291                                                                 format[spot] = 'l';
292                                                                 spot++;
293                                                         } else {
294                                                                 format[spot] = 'l';
295                                                                 a++; spot++;
296                                                                 while(in_line[a] != '\"') {
297                                                                         c = (unsigned char) in_line[a];
298                                                                         if(a >= len) {
299                                                                                 format[spot] = '\0';
300                                                                                 memcpy(tmp->format, format, strlen(format));
301                                                                                 if(!(tmp= tmp->next)) {
302                                                                                         return;
303                                                                                 } else {
304                                                                                         in_line = tmp->line;
305                                                                                         len = strlen(in_line);
306                                                                                         for(b = 0; b <len; b++) {
307                                                                                                 c = (unsigned char) in_line[b];
308                                                                                                 if(c == '\t') {
309                                                                                                         tabs++;
310                                                                                                 }
311                                                                                         }
312                                                                                         //calculate the amount of MEM_mallocN we neen
313                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
314                                                                                         if (tmp->format) MEM_freeN(tmp->format);
315                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
316                                                                                         a = 0; spot = 0;
317                                                                                 }
318                                                                         }
319                                                                         if(c == '\t' || c == ' ') {
320                                                                                 if(c == '\t') {
321                                                                                         for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
322                                                                                                 format[spot] = ' ';
323                                                                                                 spot++;
324                                                                                         }
325                                                                                         a++;
326                                                                                 } else {
327                                                                                         format[spot] = ' ';
328                                                                                         a++; spot++;
329                                                                                 }
330                                                                         } else {
331                                                                                 format[spot] = 'l';
332                                                                                 a++; spot++;
333                                                                         }
334                                                                 }
335                                                                 format[spot] = 'l';
336                                                                 spot++;
337                                                         }
338                                                         break;
339                                                 case '\'':
340                                                         if(in_line[a] == '\'' && in_line[a+1] == '\'' && in_line[a+2] == '\'') { 
341                                                                 format[spot] = format[spot+1] = format[spot+2] = 'l';
342                                                                 spot +=3;
343                                                                 a += 3;
344                                                                 while(in_line[a] != '\'' || in_line[a-1] != '\'' || in_line[a-2] != '\'') {
345                                                                         c = (unsigned char) in_line[a];
346                                                                         if(a >= len) {
347                                                                                 format[spot] = '\0';
348                                                                                 memcpy(tmp->format, format, strlen(format));
349                                                                                 if(!(tmp= tmp->next)) {
350                                                                                         return;
351                                                                                 } else {
352                                                                                         in_line = tmp->line;
353                                                                                         len = strlen(in_line);
354                                                                                         tabs = 0;
355                                                                                         for(b = 0; b <len; b++) {
356                                                                                                 c = (unsigned char) in_line[b];
357                                                                                                 if(c == '\t') {
358                                                                                                         tabs++;
359                                                                                                 }
360                                                                                         }
361                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
362                                                                                         if (tmp->format) MEM_freeN(tmp->format);
363                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
364                                                                                         a = 0; spot = 0;
365                                                                                 }
366                                                                         } else {
367                                                                                 if(c == '\t' || c == ' ') {
368                                                                                         if(c == '\t') {
369                                                                                                 for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
370                                                                                                         format[spot] = ' ';
371                                                                                                         spot++;
372                                                                                                 }
373                                                                                                 a++;
374                                                                                         } else {
375                                                                                                 format[spot] = ' ';
376                                                                                                 a++; spot++;
377                                                                                         }
378                                                                                 } else {
379                                                                                         format[spot] = 'l';
380                                                                                         a++; spot++;
381                                                                                 }
382                                                                         }
383                                                                 }
384                                                                 format[spot] = 'l';
385                                                                 spot++;
386                                                         } else {
387                                                                 format[spot] = 'l';
388                                                                 a++; spot++;
389                                                                 while(in_line[a] != '\'') {
390                                                                         c = (unsigned char) in_line[a];
391                                                                         if(a >= len) {
392                                                                                 format[spot] = '\0';
393                                                                                 memcpy(tmp->format, format, strlen(format));
394                                                                                 if(!(tmp= tmp->next)) {
395                                                                                         return;
396                                                                                 } else {
397                                                                                         in_line = tmp->line;
398                                                                                         len = strlen(in_line);
399                                                                                         for(b = 0; b <len; b++) {
400                                                                                                 c = (unsigned char) in_line[b];
401                                                                                                 if(c == '\t') {
402                                                                                                         tabs++;
403                                                                                                 }
404                                                                                         }
405                                                                                         //calculate the amount of MEM_mallocN we neen
406                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
407                                                                                         if (tmp->format) MEM_freeN(tmp->format);
408                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
409                                                                                         a = 0; spot = 0;
410                                                                                 }
411                                                                         }
412                                                                         if(c == '\t' || c == ' ') {
413                                                                                 if(c == '\t') {
414                                                                                         for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
415                                                                                                 format[spot] = ' ';
416                                                                                                 spot++;
417                                                                                         }
418                                                                                         a++;
419                                                                                 } else {
420                                                                                         format[spot] = ' ';
421                                                                                         a++; spot++;
422                                                                                 }
423                                                                         } else {
424                                                                                 format[spot] = 'l';
425                                                                                 a++; spot++;
426                                                                         }
427                                                                 }
428                                                                 format[spot] = 'l';
429                                                                 spot++;
430                                                         }
431                                                         break;
432                                                 case '#':
433                                                         while(a<len) {
434                                                                 c = (unsigned char) in_line[a];
435                                                                 if(c == '\t' || c == ' ') {
436                                                                         if(c == '\t') {
437                                                                                 for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
438                                                                                         format[spot] = '#';
439                                                                                         spot++;
440                                                                                 }
441                                                                                 a++;
442                                                                         } else {
443                                                                                 format[spot] = '#';
444                                                                                 a++; spot++;
445                                                                         }
446                                                                 } else {
447                                                                         format[spot] = '#';
448                                                                         a++; spot++;
449                                                                 }
450                                                         }
451                                                         break;
452                                                 case ' ':
453                                                         format[spot] = ' ';
454                                                         spot++;
455                                                         break;
456                                                 case '\t':
457                                                         for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
458                                                                 format[spot] = ' ';
459                                                                 spot++;
460                                                         }
461                                                         break;
462                                                 default:
463                                                         format[spot] = 'q';
464                                                         spot++;
465                                                          
466                                                         break;
467                                         }
468                                 } else if (check_numbers(check)) {
469                                         while (a < len) {
470                                                 c = (unsigned char) in_line[a];
471                                                 other[0] = c;
472                                                 other[1] = '\0';
473                                                 if (check_delim(other) && c != '.') {
474                                                         a--; break;
475                                                 } else {
476                                                         format[spot] = 'n';
477                                                         a++; spot++;
478                                                 }
479                                         }
480                                 } else {
481                                         letter = 0;
482                                         while (a < len) {
483                                                 c = (unsigned char) in_line[a];
484                                                 other[0] = c;
485                                                 other[1] = '\0';
486                                                 if (check_delim(other)) {
487                                                         a--; 
488                                                         break;
489                                                 } else {
490                                                         check[letter] = (unsigned char) in_line[a];
491                                                         letter++; 
492                                                         a++;
493                                                 }
494                                         }
495                                         check[letter] = '\0';
496                                         if (check_builtinfuncs(check)) {
497                                                 for (b = 0; b < strlen(check); b++) {
498                                                         format[spot] = 'b'; 
499                                                         spot++;
500                                                 }
501                                         } else if (check_specialvars(check)) { /*If TRUE then color and color next word*/
502                                                 for (b = 0; b < strlen(check); b++) {
503                                                         format[spot] = 'b';
504                                                         spot++;
505                                                 }
506                                                 a++;
507                                                 format[spot] = 'q';
508                                                 spot++; a++;
509                                                 letter = 0;
510                                                 while (a < len) {
511                                                         c = (unsigned char) in_line[a];
512                                                         other[0] = c;
513                                                         other[1] = '\0';
514                                                         if (check_delim(other)) {
515                                                                 a--; 
516                                                                 break;
517                                                         } else {
518                                                                 check[letter] = (unsigned char) in_line[a];
519                                                                 letter++; 
520                                                                 a++;
521                                                         }
522                                                 }
523                                                 check[letter] = '\0';
524                                                 for (b = 0; b < strlen(check); b++) {
525                                                         format[spot] = 'v';
526                                                         spot++;
527                                                 }
528                                         }else {
529                                                 for (b = 0; b < strlen(check); b++) {
530                                                         format[spot] = 'q';
531                                                         spot++;
532                                                 }
533                                         }
534                                 }
535                         }
536                         format[spot] = '\0';
537                         memcpy(tmp->format, format, strlen(format));
538                 }
539                 
540                 tmp = tmp->next;
541         }
542 }
543
544 static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int draw, int x, int y, char *format) {
545         int r=0, w= 0;
546         char *in;
547         int *acc;
548
549         w= render_string(st, str);
550         if(w<cshift ) return 0; /* String is shorter than shift */
551         
552         in= temp_char_buf+cshift;
553         acc= temp_char_accum+cshift;
554         w= w-cshift;
555
556         if (draw) {
557                 if(st->showsyntax && format) {
558                         int amount, a;
559                         char out[2];
560                         format = format+cshift;
561                 
562                         amount = strlen(in);
563                         
564                         for(a = 0; a < amount; a++) {
565                                 out[0] = (unsigned char) in[a]; 
566                                 out[1] = '\0';
567                                 switch (format[a]) {
568                                         case 'l':
569                                                 BIF_ThemeColor(TH_SYNTAX_L);
570                                                 break;
571                                         case 'b':
572                                                 BIF_ThemeColor(TH_SYNTAX_B);
573                                                 break;
574                                         case '#':
575                                                 BIF_ThemeColor(TH_SYNTAX_C);
576                                                 break;
577                                         case 'v': 
578                                                 BIF_ThemeColor(TH_SYNTAX_V);
579                                                 break;
580                                         case 'n':
581                                                 BIF_ThemeColor(TH_SYNTAX_N);
582                                                 break;
583                                         case 'q':
584                                                 BIF_ThemeColor(TH_TEXT);
585                                                 break;
586                                         default:
587                                                 BIF_ThemeColor(TH_TEXT);
588                                                 break;
589                                 }
590                                 glRasterPos2i(x, y);
591                                 BMF_DrawString(spacetext_get_font(st), out);
592                                 x = x+BMF_GetStringWidth(spacetext_get_font(st), out);
593                         }
594                 } else {
595                         glRasterPos2i(x, y);
596                         BMF_DrawString(spacetext_get_font(st), in);
597                 }
598         } else {
599                 while (w-- && *acc++ < maxwidth) {
600                         r+= spacetext_get_fontwidth(st);
601                 }
602         }
603
604         if (cshift && r==0) return 0;
605         else if (st->showlinenrs)
606                 return r+TXT_OFFSET+TEXTXLOC;
607         else
608                 return r+TXT_OFFSET;
609 }
610
611 static void set_cursor_to_pos (SpaceText *st, int x, int y, int sel) 
612 {
613         Text *text;
614         TextLine **linep;
615         int *charp;
616         int w;
617         
618         text= st->text;
619
620         if(sel) { linep= &text->sell; charp= &text->selc; } 
621         else { linep= &text->curl; charp= &text->curc; }
622         
623         y= (curarea->winy - y)/st->lheight;
624         
625         y-= txt_get_span(text->lines.first, *linep) - st->top;
626         
627         if (y>0) {
628                 while (y-- != 0) if((*linep)->next) *linep= (*linep)->next;
629         } else if (y<0) {
630                 while (y++ != 0) if((*linep)->prev) *linep= (*linep)->prev;
631         }
632
633         if(st->showlinenrs)
634                 x-= TXT_OFFSET+TEXTXLOC;
635         else
636                 x-= TXT_OFFSET;
637
638         if (x<0) x= 0;
639         x = (x/spacetext_get_fontwidth(st)) + st->left;
640         
641         w= render_string(st, (*linep)->line);
642         if(x<w) *charp= temp_char_accum[x];
643         else *charp= (*linep)->len;
644         
645         if(!sel) txt_pop_sel(text);
646 }
647
648 static void draw_cursor(SpaceText *st) {
649         int h, x, i, w;
650         Text *text= st->text;
651         TextLine *linef, *linel;
652         int charf, charl;
653         char ch[2];
654         
655         if (text->curl==text->sell && text->curc==text->selc) {
656                 x= text_draw(st, text->curl->line, st->left, text->curc, 0, 0, 0, NULL);
657
658                 if (x) {
659                         h= txt_get_span(text->lines.first, text->curl) - st->top;
660
661                         if (st->overwrite) {
662                                 ch[0]= (unsigned char) text->curl->line[text->curc];
663                                 if (ch[0]=='\0') ch[0]=' ';
664                                 ch[1]= '\0';
665                                 w= BMF_GetStringWidth(spacetext_get_font(st), ch);
666                                 BIF_ThemeColor(TH_SHADE2);
667                                 glRecti(x, curarea->winy-st->lheight*(h)-2, x+w, curarea->winy-st->lheight*(h+1)-2);
668                                 BIF_ThemeColor(TH_HILITE);
669                                 glRecti(x, curarea->winy-st->lheight*(h+1)-3, x+w, curarea->winy-st->lheight*(h+1)-1);
670                         } else {
671                                 BIF_ThemeColor(TH_HILITE);
672                                 glRecti(x-1, curarea->winy-st->lheight*(h)-2, x+1, curarea->winy-st->lheight*(h+1)-2);
673                         }
674                 }
675         } else {
676                 int span= txt_get_span(text->curl, text->sell);
677                 
678                 if (span<0) {
679                         linef= text->sell;
680                         charf= text->selc;
681                         
682                         linel= text->curl;
683                         charl= text->curc;
684                 } else if (span>0) {
685                         linef= text->curl;
686                         charf= text->curc;
687         
688                         linel= text->sell;              
689                         charl= text->selc;
690                 } else {
691                         linef= linel= text->curl;
692                         
693                         if (text->curc<text->selc) {
694                                 charf= text->curc;
695                                 charl= text->selc;
696                         } else {
697                                 charf= text->selc;
698                                 charl= text->curc;
699                         }
700                 }
701         
702                         /* Walk to the beginning of visible text */
703                 h= txt_get_span(text->lines.first, linef) - st->top;
704                 while (h++<-1 && linef!=linel) linef= linef->next;
705         
706                 x= text_draw(st, linef->line, st->left, charf, 0, 0, 0, NULL);
707
708                 BIF_ThemeColor(TH_SHADE2);
709
710                 if(st->showlinenrs) {
711                         if (!x) x= TXT_OFFSET + TEXTXLOC -4;
712                 } else {
713                         if (!x) x= TXT_OFFSET - 4;
714                 }
715                 
716                 while (linef && linef != linel) {
717                         h= txt_get_span(text->lines.first, linef) - st->top;
718                         if (h>st->viewlines) break;
719                         
720                         glRecti(x, curarea->winy-st->lheight*(h)-2, curarea->winx, curarea->winy-st->lheight*(h+1)-2);
721                         if(st->showlinenrs)
722                                 glRecti(TXT_OFFSET+TEXTXLOC-4, curarea->winy-st->lheight*(h+1)-2, TXT_OFFSET+TEXTXLOC, curarea->winy-st->lheight*(h+2)-2);
723                         else
724                                 glRecti(TXT_OFFSET-4, curarea->winy-st->lheight*(h+1)-2, TXT_OFFSET, curarea->winy-st->lheight*(h+2)-2);
725
726                         if(st->showlinenrs)
727                                 x= TXT_OFFSET + TEXTXLOC;
728                         else
729                                 x= TXT_OFFSET;
730                         
731                         linef= linef->next;
732                 }
733                 
734                 h= txt_get_span(text->lines.first, linef) - st->top;
735
736                 i= text_draw(st, linel->line, st->left, charl, 0, 0, 0, NULL);
737                 if(i) glRecti(x, curarea->winy-st->lheight*(h)-2, i, curarea->winy-st->lheight*(h+1)-2);
738
739         }
740
741         do_brackets();
742         BIF_ThemeColor(TH_TEXT);
743 }
744
745 static void calc_text_rcts(SpaceText *st)
746 {
747         int lhlstart, lhlend, ltexth;
748         short barheight, barstart, hlstart, hlend, blank_lines;
749         short pix_available, pix_top_margin, pix_bottom_margin, pix_bardiff;
750
751         pix_top_margin = 8;
752         pix_bottom_margin = 4;
753         pix_available = curarea->winy - pix_top_margin - pix_bottom_margin;
754         ltexth= txt_get_span(st->text->lines.first, st->text->lines.last);
755         blank_lines = st->viewlines / 2;
756         
757         /* when resizing a vieport with the bar at the bottom to a greater height more blank lines will be added */
758         if (ltexth + blank_lines < st->top + st->viewlines) {
759                 blank_lines = st->top + st->viewlines - ltexth;
760         }
761         
762         ltexth += blank_lines;
763
764         barheight = (ltexth > 0)? (st->viewlines*pix_available)/ltexth: 0;
765         pix_bardiff = 0;
766         if (barheight < 20) {
767                 pix_bardiff = 20 - barheight; /* take into account the now non-linear sizing of the bar */      
768                 barheight = 20;
769         }
770         barstart = (ltexth > 0)? ((pix_available - pix_bardiff) * st->top)/ltexth: 0;
771
772         st->txtbar.xmin = 5;
773         st->txtbar.xmax = 17;
774         st->txtbar.ymax = curarea->winy - pix_top_margin - barstart;
775         st->txtbar.ymin = st->txtbar.ymax - barheight;
776
777         CLAMP(st->txtbar.ymin, pix_bottom_margin, curarea->winy - pix_top_margin);
778         CLAMP(st->txtbar.ymax, pix_bottom_margin, curarea->winy - pix_top_margin);
779
780         st->pix_per_line= (pix_available > 0)? (float) ltexth/pix_available: 0;
781         if (st->pix_per_line<.1) st->pix_per_line=.1f;
782
783         lhlstart = MIN2(txt_get_span(st->text->lines.first, st->text->curl), 
784                                 txt_get_span(st->text->lines.first, st->text->sell));
785         lhlend = MAX2(txt_get_span(st->text->lines.first, st->text->curl), 
786                                 txt_get_span(st->text->lines.first, st->text->sell));
787
788         if(ltexth > 0) {
789                 hlstart = (lhlstart * pix_available)/ltexth;
790                 hlend = (lhlend * pix_available)/ltexth;
791
792                 /* the scrollbar is non-linear sized */
793                 if (pix_bardiff > 0) {
794                         /* the start of the highlight is in the current viewport */
795                         if (ltexth && st->viewlines && lhlstart >= st->top && lhlstart <= st->top + st->viewlines) { 
796                                 /* speed the progresion of the start of the highlight through the scrollbar */
797                                 hlstart = ( ( (pix_available - pix_bardiff) * lhlstart) / ltexth) + (pix_bardiff * (lhlstart - st->top) / st->viewlines);       
798                         }
799                         else if (lhlstart > st->top + st->viewlines && hlstart < barstart + barheight && hlstart > barstart) {
800                                 /* push hl start down */
801                                 hlstart = barstart + barheight;
802                         }
803                         else if (lhlend > st->top  && lhlstart < st->top && hlstart > barstart) {
804                                 /*fill out start */
805                                 hlstart = barstart;
806                         }
807
808                         if (hlend <= hlstart) { 
809                                 hlend = hlstart + 2;
810                         }
811
812                         /* the end of the highlight is in the current viewport */
813                         if (ltexth && st->viewlines && lhlend >= st->top && lhlend <= st->top + st->viewlines) { 
814                                 /* speed the progresion of the end of the highlight through the scrollbar */
815                                 hlend = (((pix_available - pix_bardiff )*lhlend)/ltexth) + (pix_bardiff * (lhlend - st->top)/st->viewlines);    
816                         }
817                         else if (lhlend < st->top && hlend >= barstart - 2 && hlend < barstart + barheight) {
818                                 /* push hl end up */
819                                 hlend = barstart;
820                         }                                       
821                         else if (lhlend > st->top + st->viewlines && lhlstart < st->top + st->viewlines && hlend < barstart + barheight) {
822                                 /* fill out end */
823                                 hlend = barstart + barheight;
824                         }
825
826                         if (hlend <= hlstart) { 
827                                 hlstart = hlend - 2;
828                         }       
829                 }       
830         }
831         else {
832                 hlstart = 0;
833                 hlend = 0;
834         }
835
836         if (hlend - hlstart < 2) { 
837                 hlend = hlstart + 2;
838         }
839         
840         st->txtscroll.xmin= 5;
841         st->txtscroll.xmax= 17;
842         st->txtscroll.ymax= curarea->winy - pix_top_margin - hlstart;
843         st->txtscroll.ymin= curarea->winy - pix_top_margin - hlend;
844
845         CLAMP(st->txtscroll.ymin, pix_bottom_margin, curarea->winy - pix_top_margin);
846         CLAMP(st->txtscroll.ymax, pix_bottom_margin, curarea->winy - pix_top_margin);
847 }
848
849 static void draw_textscroll(SpaceText *st)
850 {
851         if (!st->text) return;
852
853         calc_text_rcts(st);
854         
855         BIF_ThemeColorShade(TH_SHADE1, -20);
856         glRecti(2, 2, 20, curarea->winy-6);
857         uiEmboss(2, 2, 20, curarea->winy-6, 1);
858
859         BIF_ThemeColor(TH_SHADE1);
860         glRecti(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax);
861
862         BIF_ThemeColor(TH_SHADE2);
863         glRecti(st->txtscroll.xmin, st->txtscroll.ymin, st->txtscroll.xmax, st->txtscroll.ymax);
864
865         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
866 }
867
868 static void screen_skip(SpaceText *st, int lines)
869 {
870         int last;
871         
872         if (!st) return;
873         if (st->spacetype != SPACE_TEXT) return;
874         if (!st->text) return;
875
876         st->top += lines;
877
878         last= txt_get_span(st->text->lines.first, st->text->lines.last);
879         last= last - (st->viewlines/2);
880         
881         if (st->top>last) st->top= last;
882         if (st->top<0) st->top= 0;
883 }
884
885 /* 
886  * mode 1 == view scroll
887  * mode 2 == scrollbar
888  */
889 static void do_textscroll(SpaceText *st, int mode)
890 {
891         short delta[2]= {0, 0};
892         short mval[2], hold[2], old[2];
893         
894         if (!st->text) return;
895         
896         calc_text_rcts(st);
897
898         st->flags|= ST_SCROLL_SELECT;
899
900         glDrawBuffer(GL_FRONT);
901         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
902         bglFlush();
903         glDrawBuffer(GL_BACK);
904
905         getmouseco_areawin(mval);
906         old[0]= hold[0]= mval[0];
907         old[1]= hold[1]= mval[1];
908
909         while(get_mbut()&(L_MOUSE|M_MOUSE)) {
910                 getmouseco_areawin(mval);
911
912                 if(old[0]!=mval[0] || old[1]!=mval[1]) {
913                         if (mode==1) {
914                                 delta[0]= (hold[0]-mval[0])/spacetext_get_fontwidth(st);
915                                 delta[1]= (mval[1]-hold[1])/st->lheight;
916                         }
917                         else delta[1]= (hold[1]-mval[1])*st->pix_per_line;
918                         
919                         if (delta[0] || delta[1]) {
920                                 screen_skip(st, delta[1]);
921                                 st->left+= delta[0];
922                                 if (st->left<0) st->left= 0;
923                                 
924                                 scrarea_do_windraw(curarea);
925                                 screen_swapbuffers();
926                                 
927                                 hold[0]=mval[0];
928                                 hold[1]=mval[1];
929                         }
930                         old[0]=mval[0];
931                         old[1]=mval[1];
932                 } else {
933                         BIF_wait_for_statechange();
934                 }
935         }
936         st->flags^= ST_SCROLL_SELECT;
937
938         glDrawBuffer(GL_FRONT);
939         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
940         bglFlush();
941         glDrawBuffer(GL_BACK);
942 }
943
944 static void do_selection(SpaceText *st, int selecting)
945 {
946         short mval[2], old[2];
947         int sell, selc;
948         int linep2, charp2;
949         int first= 1;
950
951         getmouseco_areawin(mval);
952         old[0]= mval[0];
953         old[1]= mval[1];
954
955         if (!selecting) {
956                 int curl= txt_get_span(st->text->lines.first, st->text->curl);
957                 int curc= st->text->curc;                       
958                 int linep2, charp2;
959                                         
960                 set_cursor_to_pos(st, mval[0], mval[1], 0);
961
962                 linep2= txt_get_span(st->text->lines.first, st->text->curl);
963                 charp2= st->text->selc;
964                                 
965                 if (curl!=linep2 || curc!=charp2)
966                         txt_undo_add_toop(st->text, UNDO_CTO, curl, curc, linep2, charp2);
967         }
968
969         sell= txt_get_span(st->text->lines.first, st->text->sell);
970         selc= st->text->selc;
971
972         while(get_mbut()&L_MOUSE) {
973                 getmouseco_areawin(mval);
974
975                 if (mval[1]<0 || mval[1]>curarea->winy) {
976                         int d= (old[1]-mval[1])*st->pix_per_line;
977                         if (d) screen_skip(st, d);
978
979                         set_cursor_to_pos(st, mval[0], mval[1]<0?0:curarea->winy, 1);
980
981                         scrarea_do_windraw(curarea);
982                         screen_swapbuffers();
983                 } else if (mval[0]<0 || mval[0]>curarea->winx) {
984                         if (mval[0]>curarea->winx) st->left++;
985                         else if (mval[0]<0 && st->left>0) st->left--;
986                         
987                         set_cursor_to_pos(st, mval[0], mval[1], 1);
988                         
989                         scrarea_do_windraw(curarea);
990                         screen_swapbuffers();
991                         
992                         PIL_sleep_ms(10);
993                 } else if (first || old[0]!=mval[0] || old[1]!=mval[1]) {
994                         set_cursor_to_pos(st, mval[0], mval[1], 1);
995
996                         scrarea_do_windraw(curarea);
997                         screen_swapbuffers();
998
999                         old[0]= mval[0];
1000                         old[1]= mval[1];
1001                         first= 1;
1002                 } else {
1003                         BIF_wait_for_statechange();
1004                 }
1005         }
1006
1007         linep2= txt_get_span(st->text->lines.first, st->text->sell);
1008         charp2= st->text->selc;
1009                 
1010         if (sell!=linep2 || selc!=charp2)
1011                 txt_undo_add_toop(st->text, UNDO_STO, sell, selc, linep2, charp2);
1012 }
1013
1014 static int do_suggest_select(SpaceText *st)
1015 {
1016         SuggItem *item, *first, *last, *sel;
1017         short mval[2];
1018         TextLine *tmp;
1019         int l, x, y, w, h, i;
1020         int seli, tgti;
1021         
1022         if (!st || !st->text) return 0;
1023         if (!suggest_is_active(st->text)) return 0;
1024
1025         first = suggest_first();
1026         last = suggest_last();
1027         sel = suggest_get_selected();
1028
1029         if (!sel || !last || !first)
1030                 return 0;
1031
1032         /* Count the visible lines to the cursor */
1033         for (tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
1034         if (l<0) return 0;
1035         
1036         if(st->showlinenrs) {
1037                 x = spacetext_get_fontwidth(st)*(st->text->curc-st->left) + TXT_OFFSET + TEXTXLOC - 4;
1038         } else {
1039                 x = spacetext_get_fontwidth(st)*(st->text->curc-st->left) + TXT_OFFSET - 4;
1040         }
1041         y = curarea->winy - st->lheight*l - 2;
1042
1043         w = SUGG_LIST_WIDTH*spacetext_get_fontwidth(st) + 20;
1044         h = SUGG_LIST_SIZE*st->lheight + 8;
1045
1046         getmouseco_areawin(mval);
1047
1048         if (mval[0]<x || x+w<mval[0] || mval[1]<y-h || y<mval[1])
1049                 return 0;
1050
1051         /* Work out which of the visible SUGG_LIST_SIZE items is selected */
1052         for (seli=0, item=sel; seli<3 && item && item!=first; seli++, item=item->prev);
1053
1054         /* Work out the target item index in the visible list */
1055         tgti = (y-mval[1]-4) / st->lheight;
1056         if (tgti<0 || tgti>SUGG_LIST_SIZE)
1057                 return 1;
1058
1059         if (seli<tgti) {
1060                 for (i=seli; i<tgti && sel && sel!=last; i++, sel=sel->next);
1061                 if (sel)
1062                         suggest_set_selected(sel);
1063         } else {
1064                 for (i=seli; i>tgti && sel && sel!=first; i--, sel=sel->prev);
1065                 if (sel)
1066                         suggest_set_selected(sel);
1067         }
1068         return 1;
1069 }
1070
1071 void draw_suggestion_list(SpaceText *st) {
1072         SuggItem *item, *first, *last, *sel;
1073         TextLine *tmp;
1074         char str[SUGG_LIST_WIDTH+1];
1075         int w, boxw=0, boxh, i, l, x, y, b;
1076         
1077         if (!st || !st->text) return;
1078         if (!suggest_is_active(st->text)) return;
1079
1080         first = suggest_first();
1081         last = suggest_last();
1082         sel = suggest_get_selected();
1083
1084         /* Count the visible lines to the cursor */
1085         for (tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
1086         if (l<0) return;
1087         
1088         if(st->showlinenrs) {
1089                 x = spacetext_get_fontwidth(st)*(st->text->curc-st->left) + TXT_OFFSET + TEXTXLOC - 4;
1090         } else {
1091                 x = spacetext_get_fontwidth(st)*(st->text->curc-st->left) + TXT_OFFSET - 4;
1092         }
1093         y = curarea->winy - st->lheight*l - 2;
1094
1095         boxw = SUGG_LIST_WIDTH*spacetext_get_fontwidth(st) + 20;
1096         boxh = SUGG_LIST_SIZE*st->lheight + 8;
1097         
1098         BIF_ThemeColor(TH_SHADE1);
1099         glRecti(x-1, y+1, x+boxw+1, y-boxh-1);
1100         BIF_ThemeColor(TH_BACK);
1101         glRecti(x, y, x+boxw, y-boxh);
1102
1103         for (i=0, item=sel; i<3 && item && item!=first; i++, item=item->prev);
1104
1105         for (i=0; i<SUGG_LIST_SIZE && item; i++, item=item->next) {
1106
1107                 y -= st->lheight;
1108
1109                 strncpy(str, item->name, SUGG_LIST_WIDTH);
1110                 str[SUGG_LIST_WIDTH] = '\0';
1111
1112                 w = BMF_GetStringWidth(spacetext_get_font(st), str);
1113                 
1114                 if (item == sel) {
1115                         BIF_ThemeColor(TH_SHADE2);
1116                         glRecti(x+16, y-3, x+16+w, y+st->lheight-3);
1117                 }
1118                 b=1; /* b=1 colour block, text is default. b=0 no block, colour text */
1119                 switch (item->type) {
1120                         case 'k': BIF_ThemeColor(TH_SYNTAX_B); b=0; break;
1121                         case 'm': BIF_ThemeColor(TH_TEXT); break;
1122                         case 'f': BIF_ThemeColor(TH_SYNTAX_L); break;
1123                         case 'v': BIF_ThemeColor(TH_SYNTAX_N); break;
1124                 }
1125                 if (b) {
1126                         glRecti(x+8, y+2, x+11, y+5);
1127                         BIF_ThemeColor(TH_TEXT);
1128                 }
1129                 text_draw(st, str, 0, 0, 1, x+16, y-1, NULL);
1130
1131                 if (item == last) break;
1132         }
1133 }
1134
1135 void drawtextspace(ScrArea *sa, void *spacedata)
1136 {
1137         SpaceText *st= curarea->spacedata.first;
1138         Text *text;
1139         int i;
1140         TextLine *tmp;
1141         char linenr[12];
1142         float col[3];
1143         int linecount = 0;
1144
1145         if (st==NULL || st->spacetype != SPACE_TEXT) return;
1146         
1147         BIF_GetThemeColor3fv(TH_BACK, col);
1148         glClearColor(col[0], col[1], col[2], 0.0);
1149         glClear(GL_COLOR_BUFFER_BIT);
1150         myortho2(-0.375, (float)(sa->winx)-0.375, -0.375, (float)(sa->winy)-0.375);
1151
1152         draw_area_emboss(sa);
1153
1154         text= st->text;
1155         if(!text) return;
1156         
1157         /* Make sure all the positional pointers exist */
1158         if (!text->curl || !text->sell || !text->lines.first || !text->lines.last)
1159                 txt_clean_text(text);
1160         
1161         if(st->lheight) st->viewlines= (int) curarea->winy/st->lheight;
1162         else st->viewlines= 0;
1163         
1164         if(st->showlinenrs) {
1165                 cpack(0x8c787c);
1166                 glRecti(23,  0, (st->lheight==15)?63:59,  curarea->winy - 2);
1167         }
1168
1169         BIF_ThemeColor(TH_TEXT);
1170
1171         draw_cursor(st);
1172
1173         tmp= text->lines.first;
1174         for (i= 0; i<st->top && tmp; i++) {
1175                 tmp= tmp->next;
1176                 linecount++;
1177         }
1178         
1179         if(st->showsyntax) {
1180                 if (tmp && !tmp->format) {
1181                         get_format_string(st);
1182                 }
1183         }
1184         
1185         for (i=0; i<st->viewlines && tmp; i++, tmp= tmp->next) {
1186                 if(st->showlinenrs) {
1187                         /*Change the color of the current line the cursor is on*/
1188                         if(tmp == text->curl) { 
1189                                 BIF_ThemeColor(TH_HILITE);
1190                         } else {
1191                                 BIF_ThemeColor(TH_TEXT);
1192                         }
1193                         if(((float)(i + linecount + 1)/10000.0) < 1.0) {
1194                                 sprintf(linenr, "%4d", i + linecount + 1);
1195                                 glRasterPos2i(TXT_OFFSET - 7, curarea->winy-st->lheight*(i+1));
1196                         } else {
1197                                 sprintf(linenr, "%5d", i + linecount + 1);
1198                                 glRasterPos2i(TXT_OFFSET - 11, curarea->winy-st->lheight*(i+1));
1199                         }
1200                         BIF_ThemeColor(TH_TEXT);
1201                         BMF_DrawString(spacetext_get_font(st), linenr);
1202                         text_draw(st, tmp->line, st->left, 0, 1, TXT_OFFSET + TEXTXLOC, curarea->winy-st->lheight*(i+1), tmp->format);
1203                 } else
1204                         text_draw(st, tmp->line, st->left, 0, 1, TXT_OFFSET, curarea->winy-st->lheight*(i+1), tmp->format);
1205         }
1206
1207         draw_textscroll(st);
1208         draw_suggestion_list(st);
1209
1210         curarea->win_swap= WIN_BACK_OK;
1211 }
1212
1213 /* Moves the view to the cursor location,
1214   also used to make sure the view isnt outside the file */
1215 void pop_space_text (SpaceText *st)
1216 {
1217         int i, x;
1218
1219         if(!st) return;
1220         if(!st->text) return;
1221         if(!st->text->curl) return;
1222                 
1223         i= txt_get_span(st->text->lines.first, st->text->curl);
1224         if (st->top+st->viewlines <= i || st->top > i) {
1225                 st->top= i - st->viewlines/2;
1226         }
1227         
1228         x= text_draw(st, st->text->curl->line, st->left, st->text->curc, 0, 0, 0, NULL);
1229
1230         if (x==0 || x>curarea->winx) {
1231                 st->left= st->text->curc-0.5*(curarea->winx)/spacetext_get_fontwidth(st);
1232         }
1233
1234         if (st->top < 0) st->top= 0;
1235         if (st->left <0) st->left= 0;
1236 }
1237
1238 void add_text_fs(char *file) /* bad but cant pass an as arg here */
1239 {
1240         SpaceText *st= curarea->spacedata.first;
1241         Text *text;
1242
1243         if (st==NULL || st->spacetype != SPACE_TEXT) return;
1244
1245         text= add_text(file);
1246
1247         st->text= text;
1248
1249         st->top= 0;
1250
1251         if (st->showsyntax) get_format_string(st);
1252         allqueue(REDRAWTEXT, 0);
1253         allqueue(REDRAWHEADERS, 0);     
1254 }
1255
1256 void free_textspace(SpaceText *st)
1257 {
1258         if (!st) return;
1259
1260         st->text= NULL;
1261 }
1262
1263 /* returns 0 if file on disk is the same or Text is in memory only
1264    returns 1 if file has been modified on disk since last local edit
1265    returns 2 if file on disk has been deleted
1266    -1 is returned if an error occurs
1267 */
1268 int txt_file_modified(Text *text)
1269 {
1270         struct stat st;
1271         int result;
1272
1273         if (!text || !text->name)
1274                 return 0;
1275
1276         if (!BLI_exists(text->name))
1277                 return 2;
1278
1279         result = stat(text->name, &st);
1280         
1281         if(result == -1)
1282                 return -1;
1283
1284         if((st.st_mode & S_IFMT) != S_IFREG)
1285                 return -1;
1286
1287         if (st.st_mtime > text->mtime)
1288                 return 1;
1289
1290         return 0;
1291 }
1292
1293 static void save_mem_text(char *str)
1294 {
1295         SpaceText *st= curarea->spacedata.first;
1296         Text *text;
1297         
1298         if (!str) return;
1299         
1300         if (!st) return;
1301         if (st->spacetype != SPACE_TEXT) return;
1302
1303         text= st->text;
1304         if(!text) return;
1305         
1306         if (text->name) MEM_freeN(text->name);
1307         text->name= MEM_mallocN(strlen(str)+1, "textname");
1308         strcpy(text->name, str);
1309
1310         text->flags ^= TXT_ISMEM;
1311                 
1312         txt_write_file(text);
1313 }
1314
1315 void txt_write_file(Text *text) 
1316 {
1317         FILE *fp;
1318         TextLine *tmp;
1319         int res;
1320         struct stat st;
1321         
1322         /* Do we need to get a filename? */
1323         if (text->flags & TXT_ISMEM) {
1324                 if (text->name)
1325                         activate_fileselect(FILE_SPECIAL, "SAVE TEXT FILE", text->name, save_mem_text);
1326                 else
1327                         activate_fileselect(FILE_SPECIAL, "SAVE TEXT FILE", text->id.name+2, save_mem_text);
1328                 return;
1329         }
1330         
1331         /* Should we ask to save over? */
1332         if (text->flags & TXT_ISTMP) {
1333                 if (BLI_exists(text->name)) {
1334                         if (!okee("Save over")) return;
1335                 } else if (!okee("Create new file")) return;
1336
1337                 text->flags ^= TXT_ISTMP;
1338         }
1339                 
1340         fp= fopen(text->name, "w");
1341         if (fp==NULL) {
1342                 error("Unable to save file");
1343                 return;
1344         }
1345
1346         tmp= text->lines.first;
1347         while (tmp) {
1348                 if (tmp->next) fprintf(fp, "%s\n", tmp->line);
1349                 else fprintf(fp, "%s", tmp->line);
1350                 
1351                 tmp= tmp->next;
1352         }
1353         
1354         fclose (fp);
1355
1356         res= stat(text->name, &st);
1357         text->mtime= st.st_mtime;
1358         
1359         if (text->flags & TXT_ISDIRTY) text->flags ^= TXT_ISDIRTY;
1360 }
1361
1362 void unlink_text(Text *text)
1363 {
1364         bScreen *scr;
1365         ScrArea *area;
1366         SpaceLink *sl;
1367         
1368         /* check if this text was used as script link:
1369          * this check function unsets the pointers and returns how many
1370          * script links used this Text */
1371         if (BPY_check_all_scriptlinks (text)) {
1372                 allqueue(REDRAWBUTSSCRIPT, 0);
1373         }
1374         /* equivalently for pynodes: */
1375         if (nodeDynamicUnlinkText ((ID*)text)) {
1376                 allqueue(REDRAWNODE, 0);
1377         }
1378
1379         for (scr= G.main->screen.first; scr; scr= scr->id.next) {
1380                 for (area= scr->areabase.first; area; area= area->next) {
1381                         for (sl= area->spacedata.first; sl; sl= sl->next) {
1382                                 if (sl->spacetype==SPACE_TEXT) {
1383                                         SpaceText *st= (SpaceText*) sl;
1384                                         
1385                                         if (st->text==text) {
1386                                                 st->text= NULL;
1387                                                 st->top= 0;
1388                                                 
1389                                                 if (st==area->spacedata.first) {
1390                                                         scrarea_queue_redraw(area);
1391                                                 }
1392                                         }
1393                                 }
1394                         }
1395                 }
1396         }
1397 }
1398
1399 int jumptoline_interactive(SpaceText *st) {
1400         short nlines= txt_get_span(st->text->lines.first, st->text->lines.last)+1;
1401         short tmp= txt_get_span(st->text->lines.first, st->text->curl)+1;
1402
1403         if (button(&tmp, 1, nlines, "Jump to line:")) {
1404                 txt_move_toline(st->text, tmp-1, 0);
1405                 pop_space_text(st);
1406                 return 1;
1407         } else {
1408                 return 0;
1409         }
1410 }
1411
1412
1413 int bufferlength;
1414 static char *copybuffer = NULL;
1415
1416 void txt_copy_selectbuffer (Text *text)
1417 {
1418         int length=0;
1419         TextLine *tmp, *linef, *linel;
1420         int charf, charl;
1421         
1422         if (!text) return;
1423         if (!text->curl) return;
1424         if (!text->sell) return;
1425
1426         if (!txt_has_sel(text)) return;
1427         
1428         if (copybuffer) {
1429                 MEM_freeN(copybuffer);
1430                 copybuffer= NULL;
1431         }
1432
1433         if (text->curl==text->sell) {
1434                 linef= linel= text->curl;
1435                 
1436                 if (text->curc < text->selc) {
1437                         charf= text->curc;
1438                         charl= text->selc;
1439                 } else{
1440                         charf= text->selc;
1441                         charl= text->curc;
1442                 }
1443         } else if (txt_get_span(text->curl, text->sell)<0) {
1444                 linef= text->sell;
1445                 linel= text->curl;
1446
1447                 charf= text->selc;              
1448                 charl= text->curc;
1449         } else {
1450                 linef= text->curl;
1451                 linel= text->sell;
1452                 
1453                 charf= text->curc;
1454                 charl= text->selc;
1455         }
1456
1457         if (linef == linel) {
1458                 length= charl-charf;
1459
1460                 copybuffer= MEM_mallocN(length+1, "cut buffera");
1461                 
1462                 BLI_strncpy(copybuffer, linef->line + charf, length+1);
1463         } else {
1464                 length+= linef->len - charf;
1465                 length+= charl;
1466                 length++; /* For the '\n' */
1467                 
1468                 tmp= linef->next;
1469                 while (tmp && tmp!= linel) {
1470                         length+= tmp->len+1;
1471                         tmp= tmp->next;
1472                 }
1473                 
1474                 copybuffer= MEM_mallocN(length+1, "cut bufferb");
1475                 
1476                 strncpy(copybuffer, linef->line+ charf, linef->len-charf);
1477                 length= linef->len-charf;
1478                 
1479                 copybuffer[length++]='\n';
1480                 
1481                 tmp= linef->next;
1482                 while (tmp && tmp!=linel) {
1483                         strncpy(copybuffer+length, tmp->line, tmp->len);
1484                         length+= tmp->len;
1485                         
1486                         copybuffer[length++]='\n';                      
1487                         
1488                         tmp= tmp->next;
1489                 }
1490                 strncpy(copybuffer+length, linel->line, charl);
1491                 length+= charl;
1492                 
1493                 copybuffer[length]=0;
1494         }
1495
1496         bufferlength = length;
1497 }
1498
1499 static char *unixNewLine(char *buffer)
1500 {
1501         char *p, *p2, *output;
1502         
1503         /* we can afford the few extra bytes */
1504         output= MEM_callocN(strlen(buffer)+1, "unixnewline");
1505         for (p= buffer, p2= output; *p; p++)
1506                 if (*p != '\r') *(p2++)= *p;
1507         
1508         *p2= 0;
1509         return(output);
1510 }
1511
1512 static char *winNewLine(char *buffer)
1513 {
1514         char *p, *p2, *output;
1515         int add= 0;
1516         
1517         for (p= buffer; *p; p++)
1518                 if (*p == '\n') add++;
1519                 
1520         bufferlength= p-buffer+add+1;
1521         output= MEM_callocN(bufferlength, "winnewline");
1522         for (p= buffer, p2= output; *p; p++, p2++) {
1523                 if (*p == '\n') { 
1524                         *(p2++)= '\r'; *p2= '\n';
1525                 } else *p2= *p;
1526         }
1527         *p2= 0;
1528         
1529         return(output);
1530 }
1531
1532 void txt_paste_clipboard(Text *text) {
1533
1534         char * buff;
1535         char *temp_buff;
1536         
1537         buff = (char*)getClipboard(0);
1538         if(buff) {
1539                 temp_buff = unixNewLine(buff);
1540                 
1541                 txt_insert_buf(text, temp_buff);
1542                 if(buff){free((void*)buff);}
1543                 if(temp_buff){MEM_freeN(temp_buff);}
1544         }
1545 }
1546
1547 void get_selection_buffer(Text *text)
1548 {
1549         char *buff = getClipboard(1);
1550         txt_insert_buf(text, buff);
1551 }
1552
1553 void txt_copy_clipboard(Text *text) {
1554         char *temp;
1555
1556         txt_copy_selectbuffer(text);
1557
1558         if (copybuffer) {
1559                 copybuffer[bufferlength] = '\0';
1560                 temp = winNewLine(copybuffer);
1561                 
1562                 putClipboard(temp, 0);
1563                 MEM_freeN(temp);
1564                 MEM_freeN(copybuffer);
1565                 copybuffer= NULL;
1566         }
1567 }
1568
1569 /*
1570  * again==0 show find panel or find
1571  * again==1 find text again */
1572 void txt_find_panel(SpaceText *st, int again)
1573 {
1574         Text *text=st->text;
1575         char *findstr= last_txt_find_string;
1576                         
1577         if (again==0) {
1578                 findstr= txt_sel_to_buf(text);
1579         } else if (again==1) {
1580                 char buf[256];
1581
1582         if (findstr && strlen(findstr)<(sizeof(buf)-1))
1583                 strcpy(buf, findstr);
1584         else
1585                 buf[0]= 0;
1586                 
1587         if (sbutton(buf, 0, sizeof(buf)-1, "Find: ") && buf[0])
1588                 findstr= BLI_strdup(buf);
1589         else
1590                 findstr= NULL;
1591         }
1592
1593         if (findstr!=last_txt_find_string) {
1594                 if (last_txt_find_string)
1595                         MEM_freeN(last_txt_find_string);
1596                 last_txt_find_string= findstr;
1597         }
1598                                 
1599         if (findstr) {
1600                 if (txt_find_string(text, findstr))
1601                         pop_space_text(st);
1602                 else
1603                         error("Not found: %s", findstr);
1604         }
1605 }
1606
1607 void run_python_script(SpaceText *st)
1608 {
1609         char *py_filename;
1610         Text *text=st->text;
1611
1612         if (!BPY_txt_do_python_Text(text)) {
1613                 int lineno = BPY_Err_getLinenumber();
1614                 // jump to error if happened in current text:
1615                 py_filename = (char*) BPY_Err_getFilename();
1616
1617                 /* st->text can become NULL: user called Blender.Load(blendfile)
1618                  * before the end of the script. */
1619                 if (!st->text) return;
1620
1621                 if (!strcmp(py_filename, st->text->id.name+2)) {
1622                         error_pyscript(  );
1623                         if (lineno >= 0) {
1624                                 txt_move_toline(text, lineno-1, 0);
1625                                 txt_sel_line(text);
1626                                 pop_space_text(st);
1627                         }       
1628                 } else {
1629                         error("Error in other (possibly external) file, "\
1630                                 "check console");
1631                 }       
1632         }
1633 }
1634
1635 static void set_tabs(Text *text)
1636 {
1637         SpaceText *st = curarea->spacedata.first;
1638         st->currtab_set = setcurr_tab(text);
1639 }
1640
1641 static void get_suggest_prefix(Text *text) {
1642         int i, len;
1643         char *line, tmp[256];
1644
1645         if (!text) return;
1646         if (!suggest_is_active(text)) return;
1647
1648         line= text->curl->line;
1649         for (i=text->curc-1; i>=0; i--)
1650                 if (!check_identifier(line[i]))
1651                         break;
1652         i++;
1653         len= text->curc-i;
1654         if (len > 255) {
1655                 printf("Suggestion prefix too long\n");
1656                 return;
1657         }
1658         strncpy(tmp, line+i, len);
1659         tmp[len]= '\0';
1660         suggest_prefix(tmp);
1661 }
1662
1663 static void confirm_suggestion(Text *text) {
1664         int i, len;
1665         char *line;
1666         SuggItem *sel;
1667
1668         if (!text) return;
1669         if (!suggest_is_active(text)) return;
1670
1671         sel = suggest_get_selected();
1672         if (!sel) return;
1673
1674         line= text->curl->line;
1675         for (i=text->curc-1; i>=0; i--)
1676                 if (!check_identifier(line[i]))
1677                         break;
1678         i++;
1679         len= text->curc-i;
1680         txt_insert_buf(text, sel->name+len);
1681 }
1682
1683 void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1684 {
1685         unsigned short event= evt->event;
1686         short val= evt->val;
1687         char ascii= evt->ascii;
1688         SpaceText *st= curarea->spacedata.first;
1689         Text *text;
1690         int do_draw=0, p;
1691         int suggesting=0, do_suggest=0; /* 0:just redraw, -1:clear, 1:update prefix */
1692         
1693         if (st==NULL || st->spacetype != SPACE_TEXT) return;
1694         
1695         /* smartass code to prevent the CTRL/ALT events below from not working! */
1696         if(G.qual & (LR_ALTKEY|LR_CTRLKEY))
1697                 if(!ispunct(ascii)) 
1698                         ascii= 0;
1699
1700         text= st->text;
1701         
1702         if (!text) {
1703                 if (event==RIGHTMOUSE) {
1704                         switch (pupmenu("File %t|New %x0|Open... %x1")) {
1705                         case 0:
1706                                 st->text= add_empty_text("Text");
1707                                 st->top= 0;
1708                         
1709                                 allqueue(REDRAWTEXT, 0);
1710                                 allqueue(REDRAWHEADERS, 0);
1711                                 break;
1712                         case 1:
1713                                 activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1714                                 break;
1715                         }
1716                 }
1717                 if (val && !ELEM(G.qual, 0, LR_SHIFTKEY)) {
1718                         if (event==FKEY && G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
1719                                 switch (pupmenu("File %t|New %x0|Open... %x1")) {
1720                                 case 0:
1721                                         st->text= add_empty_text("Text");
1722                                         st->top= 0;
1723                                 
1724                                         allqueue(REDRAWTEXT, 0);
1725                                         allqueue(REDRAWHEADERS, 0);
1726                                         break;
1727                                 case 1:
1728                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1729                                         break;
1730                                 }
1731                         } 
1732                         else if (event==QKEY) {
1733                                 if (G.qual & LR_CTRLKEY) {
1734                                         if(okee("Quit Blender")) exit_usiblender();
1735                                 }
1736                         }
1737                         else if (event==NKEY) {
1738                                 if (G.qual & LR_ALTKEY) {
1739                                         st->text= add_empty_text("Text");
1740                                         st->top= 0;
1741                                 
1742                                         allqueue(REDRAWTEXT, 0);
1743                                         allqueue(REDRAWHEADERS, 0);
1744                                 }
1745                         }
1746                         else if (event==OKEY) {
1747                                 if (G.qual & LR_ALTKEY) {
1748                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1749                                 }
1750                         }
1751                 }
1752                 return;
1753         }
1754
1755         suggesting = suggest_is_active(text);
1756         
1757         if (event==LEFTMOUSE) {
1758                 if (val) {
1759                         short mval[2];
1760                         char *buffer;
1761                         set_tabs(text);
1762                         getmouseco_areawin(mval);
1763                         
1764                         if (mval[0]>2 && mval[0]<20 && mval[1]>2 && mval[1]<curarea->winy-2) {
1765                                 do_textscroll(st, 2);
1766                                 do_suggest= -1;
1767                         } else if (do_suggest_select(st)) {
1768                                 do_draw= 1;
1769                                 do_suggest= 0;
1770                         } else {
1771                                 do_selection(st, G.qual&LR_SHIFTKEY);
1772                                 if (txt_has_sel(text)) {
1773                                         buffer = txt_sel_to_buf(text);
1774                                         putClipboard(buffer, 1);
1775                                         MEM_freeN(buffer);
1776                                 }
1777                                 do_draw= 1;
1778                                 do_suggest= -1;
1779                         }
1780                 }
1781         } else if (event==MIDDLEMOUSE) {
1782                 if (val) {
1783                         if (do_suggest_select(st)) {
1784                                 confirm_suggestion(text);
1785                                 do_draw= 1;
1786                                 do_suggest= 0;
1787                         } else if (U.uiflag & USER_MMB_PASTE) {
1788                                 do_selection(st, G.qual&LR_SHIFTKEY);
1789                                 get_selection_buffer(text);
1790                                 do_draw= 1;
1791                         } else {
1792                                 do_textscroll(st, 1);
1793                         }
1794                         do_suggest= -1;
1795                 }
1796         } else if (event==RIGHTMOUSE) {
1797                 if (val) {
1798                         p= pupmenu("File %t|New %x0|Open... %x1|Save %x2|Save As...%x3|Execute Script%x4");
1799
1800                         switch(p) {
1801                                 case 0:
1802                                         st->text= add_empty_text("Text");
1803                                         st->top= 0;
1804                                         
1805                                         allqueue(REDRAWTEXT, 0);
1806                                         allqueue(REDRAWHEADERS, 0);
1807                                         break;
1808
1809                                 case 1:
1810                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1811                                         break;
1812                                         
1813                                 case 3:
1814                                         text->flags |= TXT_ISMEM;
1815                                         
1816                                 case 2:
1817                                         txt_write_file(text);
1818                                         do_draw= 1;
1819                                         break;
1820                                 case 4:
1821                                         run_python_script(st);
1822                                         do_draw= 1;
1823                                         break;
1824                                 default:
1825                                         break;
1826                         }
1827                         do_suggest= -1;
1828                 }
1829         } else if (ascii) {
1830                 if (text && text->id.lib) {
1831                         error_libdata();
1832
1833                 } else if ((st->overwrite && txt_replace_char(text, ascii)) || txt_add_char(text, ascii)) {
1834                         if (st->showsyntax) get_format_string(st);
1835                         pop_space_text(st);
1836                         do_draw= 1;
1837                         if (suggesting && ispunct(ascii)) {
1838                                 confirm_suggestion(text);
1839                                 if (st->showsyntax) get_format_string(st);
1840                                 do_suggest= 0;
1841                         } else {
1842                                 do_suggest= 1;
1843                         }
1844                 }
1845         } else if (val) {
1846                 do_suggest= -1; /* Note that the default label sets this to 0,
1847                                                 so -1 only applies to the explicit cases below */
1848                 switch (event) {
1849                 case AKEY:
1850                         if (G.qual & LR_ALTKEY) {
1851                                 txt_move_bol(text, G.qual & LR_SHIFTKEY);
1852                                 do_draw= 1;
1853                                 pop_space_text(st);
1854                         } else if (G.qual & LR_CTRLKEY) {
1855                                 txt_sel_all(text);
1856                                 do_draw= 1;
1857                         }
1858                         break; /* BREAK A */
1859                 case CKEY:
1860                         if (G.qual & LR_ALTKEY || G.qual & LR_CTRLKEY) {
1861                                 if(G.qual & LR_SHIFTKEY)
1862                                         txt_copy_clipboard(text);
1863                                 else
1864                                         txt_copy_clipboard(text);
1865
1866                                 do_draw= 1;     
1867                         }
1868                         break; /* BREAK C */
1869                 case DKEY:
1870                         if (text && text->id.lib) {
1871                                 error_libdata();
1872                                 break;
1873                         }
1874                         if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
1875                                 //uncommenting
1876                                 txt_order_cursors(text);
1877                                 uncomment(text);
1878                                 do_draw = 1;
1879                                 if (st->showsyntax) get_format_string(st);
1880                                 break;
1881                         } else if (G.qual == LR_CTRLKEY) {
1882                                 txt_delete_char(text);
1883                                 if (st->showsyntax) get_format_string(st);
1884                                 do_draw= 1;
1885                                 pop_space_text(st);
1886                         }
1887                         break; /* BREAK D */
1888                 case EKEY:
1889                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
1890                                 switch(pupmenu("Edit %t|Cut %x0|Copy %x1|Paste %x2|Print Cut Buffer %x3")) {
1891                                 case 0:
1892                                         if (text && text->id.lib) {
1893                                                 error_libdata();
1894                                                 break;
1895                                         }
1896                                         txt_copy_clipboard(text); //First copy to clipboard
1897                                         txt_cut_sel(text);
1898                                         do_draw= 1;
1899                                         break;
1900                                 case 1:
1901                                         txt_copy_clipboard(text);
1902                                         //txt_copy_sel(text);
1903                                         do_draw= 1;
1904                                         break;
1905                                 case 2:
1906                                         if (text && text->id.lib) {
1907                                                 error_libdata();
1908                                                 break;
1909                                         }
1910                                         //txt_paste(text);
1911                                         txt_paste_clipboard(text);
1912                                         if (st->showsyntax) get_format_string(st);
1913                                         do_draw= 1;
1914                                         break;
1915                                 case 3:
1916                                         txt_print_cutbuffer();
1917                                         break;
1918                                 }
1919                         }
1920                         else if (G.qual == LR_CTRLKEY || G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
1921                                 txt_move_eol(text, G.qual & LR_SHIFTKEY);
1922                                 do_draw= 1;
1923                                 pop_space_text(st);
1924                         }
1925                         break; /* BREAK E */
1926                 case FKEY:
1927                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
1928                                 switch(pupmenu("File %t|New %x0|Open... %x1|Save %x2|Save As...%x3")) {
1929                                 case 0:
1930                                         st->text= add_empty_text("Text");
1931                                         st->top= 0;
1932                                         
1933                                         allqueue(REDRAWTEXT, 0);
1934                                         allqueue(REDRAWHEADERS, 0);
1935                                         break;
1936                                 case 1:
1937                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1938                                         break;
1939                                 case 3:
1940                                         text->flags |= TXT_ISMEM;
1941                                 case 2:
1942                                         txt_write_file(text);
1943                                         do_draw= 1;
1944                                         break;
1945                                 }
1946                         }
1947                         else if (G.qual == LR_ALTKEY) {
1948                                 if (txt_has_sel(text)) {
1949                                         txt_find_panel(st,0);
1950                                         do_draw= 1;
1951                                 }
1952                         }
1953                         else if (G.qual == (LR_ALTKEY|LR_CTRLKEY)) {    /* always search button */
1954                                 txt_find_panel(st,1);
1955                                 do_draw= 1;
1956                         }
1957                         break; /* BREAK F */
1958                 case JKEY:
1959                         if (G.qual == LR_ALTKEY) {
1960                                 do_draw= jumptoline_interactive(st);
1961                         }
1962                         break; /* BREAK J */
1963                 case MKEY:
1964                         if (G.qual == LR_ALTKEY) {
1965                                 txt_export_to_object(text);
1966                                 do_draw= 1;     
1967                         }
1968                         break; /* BREAK M */
1969                 case NKEY:
1970                         if (G.qual == LR_ALTKEY) {
1971                                 st->text= add_empty_text("Text");
1972                                 st->top= 0;
1973                         
1974                                 allqueue(REDRAWTEXT, 0);
1975                                 allqueue(REDRAWHEADERS, 0);
1976
1977                         }
1978                         break; /* BREAK N */
1979                 case OKEY:
1980                         if (G.qual == LR_ALTKEY) {
1981                                 activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1982                         }
1983                         break; /* BREAK O */
1984                 case PKEY:
1985                         if (G.qual == LR_ALTKEY) {
1986                                 run_python_script(st);
1987                                 do_draw= 1;
1988                         }
1989                         break; /* BREAK P */
1990                 case QKEY:
1991                         if(okee("Quit Blender")) exit_usiblender();
1992                         break; /* BREAK Q */
1993                 case RKEY:
1994                         if (G.qual == LR_ALTKEY) {
1995                             if (text->compiled) BPY_free_compiled_text(text);
1996                                 text->compiled = NULL;
1997                                 if (okee("Reopen text")) {
1998                                         if (!reopen_text(text))
1999                                                 error("Could not reopen file");
2000                                 if (st->showsyntax) get_format_string(st);
2001                                 }
2002                                 do_draw= 1;     
2003                         }
2004                         break; /* BREAK R */
2005                 case SKEY:
2006                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
2007                                 p= pupmenu("Select %t|"
2008                                                         "Select All %x0|"
2009                                                         "Select Line %x1|"
2010                                                         "Jump to Line %x3");
2011                                 switch(p) {
2012                                 case 0:
2013                                         txt_sel_all(text);
2014                                         do_draw= 1;
2015                                         break;
2016                                         
2017                                 case 1:
2018                                         txt_sel_line(text);
2019                                         do_draw= 1;
2020                                         break;
2021                                                                                 
2022                                 case 3:
2023                                         do_draw= jumptoline_interactive(st);
2024                                         break;
2025                                 }
2026                         }
2027                         else if (G.qual & LR_ALTKEY) {
2028                                 /* Event treatment CANNOT enter this if
2029                                 if (G.qual & LR_SHIFTKEY) 
2030                                         if (text) text->flags |= TXT_ISMEM;
2031                                 */
2032                                 txt_write_file(text);
2033                                 do_draw= 1;
2034                         }
2035                         break; /* BREAK S */
2036                 case UKEY:
2037                         //txt_print_undo(text); //debug buffer in console
2038                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
2039                                 txt_do_redo(text);
2040                                 do_draw= 1;
2041                         }
2042                         if (G.qual == LR_ALTKEY) {
2043                                 txt_do_undo(text);
2044                                 if (st->showsyntax) get_format_string(st);
2045                                 do_draw= 1;
2046                         }
2047                         break; /* BREAK U */
2048                 case VKEY:
2049                         if (G.qual == (LR_ALTKEY| LR_SHIFTKEY)) {
2050                                 switch(pupmenu("View %t|Top of File %x0|Bottom of File %x1|Page Up %x2|Page Down %x3")) {
2051                                 case 0:
2052                                         txt_move_bof(text, 0);
2053                                         do_draw= 1;
2054                                         pop_space_text(st);
2055                                         break;
2056                                 case 1:
2057                                         txt_move_eof(text, 0);
2058                                         do_draw= 1;
2059                                         pop_space_text(st);
2060                                         break;
2061                                 case 2:
2062                                         screen_skip(st, -st->viewlines);
2063                                         do_draw= 1;
2064                                         break;
2065                                 case 3:
2066                                         screen_skip(st, st->viewlines);
2067                                         do_draw= 1;
2068                                         break;
2069                                 }
2070                         }
2071                         /* Support for both Alt-V and Ctrl-V for Paste, for backward compatibility reasons */
2072                         else if (G.qual & LR_ALTKEY || G.qual & LR_CTRLKEY) {
2073                                 if (text && text->id.lib) {
2074                                         error_libdata();
2075                                         break;
2076                                 }
2077                                 /* Throwing in the Shift modifier Paste from the OS clipboard */
2078                                 if (G.qual & LR_SHIFTKEY)
2079                                         txt_paste_clipboard(text);
2080                                 else
2081                                         txt_paste_clipboard(text);
2082                                 if (st->showsyntax) get_format_string(st);
2083                                 do_draw= 1;     
2084                                 pop_space_text(st);
2085                         }
2086                         break; /* BREAK V */
2087                 case XKEY:
2088                         if (G.qual == LR_ALTKEY || G.qual == LR_CTRLKEY) {
2089                                 if (text && text->id.lib) {
2090                                         error_libdata();
2091                                         break;
2092                                 }
2093                                 txt_cut_sel(text);
2094                                 if (st->showsyntax) get_format_string(st);
2095                                 do_draw= 1;     
2096                                 pop_space_text(st);
2097                         }
2098                         break;
2099                 case ZKEY:
2100                         if (G.qual & (LR_ALTKEY|LR_CTRLKEY|LR_COMMANDKEY)) {
2101                                 if (G.qual & LR_SHIFTKEY) {
2102                                         txt_do_redo(text);
2103                                 } else {
2104                                         txt_do_undo(text);
2105                                 }
2106                                 if (st->showsyntax) get_format_string(st);
2107                                 do_draw= 1;
2108                         }
2109                         break;
2110                 case ESCKEY:
2111                         do_suggest= -1;
2112                         break;
2113                 case SPACEKEY:
2114                         if (suggesting) {
2115                                 confirm_suggestion(text);
2116                                 if (st->showsyntax) get_format_string(st);
2117                         }
2118                         break;
2119                 case TABKEY:
2120                         if (text && text->id.lib) {
2121                                 error_libdata();
2122                                 break;
2123                         }
2124                         if (G.qual & LR_SHIFTKEY) {
2125                                 if (txt_has_sel(text)) {
2126                                         txt_order_cursors(text);
2127                                         unindent(text);
2128                                         
2129                                 }
2130                         } else {
2131                                 if ( txt_has_sel(text)) {
2132                                         txt_order_cursors(text);
2133                                         indent(text);
2134                                 } else {
2135                                         txt_add_char(text, '\t');
2136                                 }
2137                         }
2138                         if (st->showsyntax) get_format_string(st);
2139                         pop_space_text(st);
2140                         do_draw= 1;
2141                         st->currtab_set = setcurr_tab(text);
2142                         break;
2143                 case RETKEY:
2144                         if (text && text->id.lib) {
2145                                 error_libdata();
2146                                 break;
2147                         }
2148                         if (suggesting) {
2149                                 confirm_suggestion(text);
2150                                 if (st->showsyntax) get_format_string(st);
2151                                 break;
2152                         }
2153                         //double check tabs before splitting the line
2154                         st->currtab_set = setcurr_tab(text);
2155                         txt_split_curline(text);
2156                         {
2157                                 int a = 0;
2158                                 if (a < st->currtab_set)
2159                                 {
2160                                         while ( a < st->currtab_set) {
2161                                                 txt_add_char(text, '\t');
2162                                                 a++;
2163                                         }
2164                                 }
2165                         }
2166                         if (st->showsyntax) get_format_string(st);
2167                         do_draw= 1;
2168                         pop_space_text(st);
2169                         break;
2170                 case BACKSPACEKEY:
2171                         if (text && text->id.lib) {
2172                                 error_libdata();
2173                                 break;
2174                         }
2175                         if (G.qual & (LR_ALTKEY | LR_CTRLKEY)) {
2176                                 txt_backspace_word(text);
2177                         } else {
2178                                 txt_backspace_char(text);
2179                         }
2180                         set_tabs(text);
2181                         if (st->showsyntax) get_format_string(st);
2182                         do_draw= 1;
2183                         pop_space_text(st);
2184                         do_suggest= 1;
2185                         break;
2186                 case DELKEY:
2187                         if (text && text->id.lib) {
2188                                 error_libdata();
2189                                 break;
2190                         }
2191                         if (G.qual & (LR_ALTKEY | LR_CTRLKEY)) {
2192                                 txt_delete_word(text);
2193                         } else {
2194                                 txt_delete_char(text);
2195                         }
2196                         if (st->showsyntax) get_format_string(st);
2197                         do_draw= 1;
2198                         pop_space_text(st);
2199                         st->currtab_set = setcurr_tab(text);
2200                         break;
2201                 case INSERTKEY:
2202                         st->overwrite= !st->overwrite;
2203                         do_draw= 1;
2204                         do_suggest= 0;
2205                         break;
2206                 case DOWNARROWKEY:
2207                         if (suggesting) {
2208                                 SuggItem *sel = suggest_get_selected();
2209                                 if (sel && sel!=suggest_last() && sel->next)
2210                                         suggest_set_selected(sel->next);
2211                                 do_suggest= 0;
2212                                 break;
2213                         }
2214                         txt_move_down(text, G.qual & LR_SHIFTKEY);
2215                         set_tabs(text);
2216                         do_draw= 1;
2217                         pop_space_text(st);
2218                         break;
2219                 case LEFTARROWKEY:
2220                         if (G.qual & LR_COMMANDKEY)
2221                                 txt_move_bol(text, G.qual & LR_SHIFTKEY);
2222                         else if (G.qual & LR_ALTKEY)
2223                                 txt_jump_left(text, G.qual & LR_SHIFTKEY);
2224                         else
2225                                 txt_move_left(text, G.qual & LR_SHIFTKEY);
2226                         set_tabs(text);
2227                         do_draw= 1;
2228                         pop_space_text(st);
2229                         break;
2230                 case RIGHTARROWKEY:
2231                         if (G.qual & LR_COMMANDKEY)
2232                                 txt_move_eol(text, G.qual & LR_SHIFTKEY);
2233                         else if (G.qual & LR_ALTKEY)
2234                                 txt_jump_right(text, G.qual & LR_SHIFTKEY);
2235                         else
2236                                 txt_move_right(text, G.qual & LR_SHIFTKEY);
2237                         set_tabs(text);
2238                         do_draw= 1;
2239                         pop_space_text(st);
2240                         break;
2241                 case UPARROWKEY:
2242                         if (suggesting) {
2243                                 SuggItem *sel = suggest_get_selected();
2244                                 if (sel && sel!=suggest_first() && sel->prev)
2245                                         suggest_set_selected(sel->prev);
2246                                 do_suggest= 0;
2247                                 break;
2248                         }
2249                         txt_move_up(text, G.qual & LR_SHIFTKEY);
2250                         set_tabs(text);
2251                         do_draw= 1;
2252                         pop_space_text(st);
2253                         break;
2254                 case PAGEDOWNKEY:
2255                         if (suggesting) {
2256                                 int i;
2257                                 SuggItem *sel = suggest_get_selected();
2258                                 for (i=0; i<SUGG_LIST_SIZE-1 && sel && sel!=suggest_last() && sel->next; i++, sel=sel->next)
2259                                         suggest_set_selected(sel->next);
2260                                 do_suggest= 0;
2261                                 break;
2262                         } else {
2263                                 screen_skip(st, st->viewlines);
2264                         }
2265                         do_draw= 1;
2266                         break;
2267                 case PAGEUPKEY:
2268                         if (suggesting) {
2269                                 int i;
2270                                 SuggItem *sel = suggest_get_selected();
2271                                 for (i=0; i<SUGG_LIST_SIZE-1 && sel && sel!=suggest_first() && sel->prev; i++, sel=sel->prev)
2272                                         suggest_set_selected(sel->prev);
2273                                 do_suggest= 0;
2274                                 break;
2275                         } else {
2276                                 screen_skip(st, -st->viewlines);
2277                         }
2278                         do_draw= 1;
2279                         break;
2280                 case HOMEKEY:
2281                         txt_move_bol(text, G.qual & LR_SHIFTKEY);
2282                         do_draw= 1;
2283                         pop_space_text(st);
2284                         break;
2285                 case ENDKEY:
2286                         txt_move_eol(text, G.qual & LR_SHIFTKEY);
2287                         do_draw= 1;
2288                         pop_space_text(st);
2289                         break;
2290                 case WHEELUPMOUSE:
2291                         if (suggesting) {
2292                                 SuggItem *sel = suggest_get_selected();
2293                                 if (sel && sel!=suggest_first() && sel->prev)
2294                                         suggest_set_selected(sel->prev);
2295                                 do_suggest= 0;
2296                         } else {
2297                                 screen_skip(st, -U.wheellinescroll);
2298                         }
2299                         do_draw= 1;
2300                         break;
2301                 case WHEELDOWNMOUSE:
2302                         if (suggesting) {
2303                                 SuggItem *sel = suggest_get_selected();
2304                                 if (sel && sel!=suggest_last() && sel->next)
2305                                         suggest_set_selected(sel->next);
2306                                 do_suggest= 0;
2307                         } else {
2308                                 screen_skip(st, U.wheellinescroll);
2309                         }
2310                         do_draw= 1;
2311                         break;
2312                 default:
2313                         do_suggest= 0;
2314                 }
2315         }
2316
2317         if (event && val) {
2318                 if (BPY_menu_do_shortcut(PYMENU_TEXTPLUGIN, event, G.qual)) {
2319                         do_draw= 1;
2320                 }
2321         }
2322
2323         if (last_check_time < PIL_check_seconds_timer() - 1.0) {
2324                 switch (txt_file_modified(text)) {
2325                 case 1:
2326                         /* Modified locally and externally, ahhh. Offer more possibilites. */
2327                         if (text->flags & TXT_ISDIRTY) {
2328                                 switch (pupmenu("External File Modified with Local Changes %t|Load external changes (overwrite local) %x0|Save local changes (overwrite external) %x1|Make text internal %x2")) {
2329                                 case 0:
2330                                         reopen_text(text);
2331                                         if (st->showsyntax) get_format_string(st);
2332                                         do_draw= 1;
2333                                         break;
2334                                 case 1:
2335                                         txt_write_file(text);
2336                                         do_draw= 1;
2337                                         break;
2338                                 case 2:
2339                                         text->flags |= TXT_ISMEM | TXT_ISDIRTY | TXT_ISTMP;
2340                                         MEM_freeN(text->name);
2341                                         text->name= NULL;
2342                                         do_draw= 1;
2343                                         break;
2344                                 }
2345                         } else {
2346                                 switch (pupmenu("External File Modified %t|Reload from disk %x0|Make text internal %x1")) {
2347                                 case 0:
2348                                         reopen_text(text);
2349                                         if (st->showsyntax) get_format_string(st);
2350                                         do_draw= 1;
2351                                         break;
2352                                 case 1:
2353                                         text->flags |= TXT_ISMEM | TXT_ISDIRTY | TXT_ISTMP;
2354                                         MEM_freeN(text->name);
2355                                         text->name= NULL;
2356                                         do_draw= 1;
2357                                         break;
2358                                 }
2359                         }
2360                         break;
2361                 case 2:
2362                         switch (pupmenu("External File Deleted %t|Make text internal %x0")) {
2363                         case 0:
2364                                 text->flags |= TXT_ISMEM | TXT_ISDIRTY | TXT_ISTMP;
2365                                 MEM_freeN(text->name);
2366                                 text->name= NULL;
2367                                 do_draw= 1;
2368                                 break;
2369                         }
2370                         break;
2371                 default:
2372                         last_check_time = PIL_check_seconds_timer();
2373                 }
2374         }
2375
2376         if (suggesting) {
2377                 if (do_suggest == -1) {
2378                         suggest_clear_text();
2379                 } else if (do_suggest == 1) {
2380                         get_suggest_prefix(text);
2381                 }
2382                 do_draw= 1;
2383         }
2384
2385         if (do_draw) {
2386                 ScrArea *sa;
2387                 
2388                 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
2389                         SpaceText *st= sa->spacedata.first;
2390                         
2391                         if (st && st->spacetype==SPACE_TEXT) {
2392                                 scrarea_queue_redraw(sa);
2393                         }
2394                 }
2395         }
2396 }
2397
2398 void do_brackets(void) 
2399 {
2400         SpaceText *st = curarea->spacedata.first;
2401         Text *text = st->text;
2402         TextLine *tmp, *start;
2403         char test[2];
2404         int d, pos, open, x, y, x2, y2, h=0;
2405         
2406         if(!text) return;
2407         
2408         tmp = text->curl;
2409         start = text->curl;
2410
2411         test[0] = (unsigned char) tmp->line[text->curc];
2412         test[1] = '\0';
2413         
2414         d = check_bracket(test);
2415         if (!d) /*  If not pri char */
2416         {
2417                 test[0] = (unsigned char) tmp->line[text->curc-1];
2418                 test[1] = '\0';
2419                 d = check_bracket(test);
2420                 if(!d) {
2421                         return; /*If the current char or prev is not a bracket then return*/
2422                 } else { /* current char */
2423                         h= txt_get_span(text->lines.first, start) - st->top;
2424                         x = text_draw(st, start->line, st->left, text->curc-1, 0, 0, 0, NULL);
2425                         y = text_draw(st, start->line, st->left, text->curc, 0, 0, 0, NULL);
2426                         if (d < 4) {
2427                                 pos = text->curc;
2428                         } else {
2429                                 pos = text->curc-2;
2430                         }
2431                 }
2432         } else { /* is pri char */
2433                 h= txt_get_span(text->lines.first, start) - st->top;
2434                 x = text_draw(st, start->line, st->left, text->curc, 0, 0, 0, NULL);
2435                 y = text_draw(st, start->line, st->left, text->curc+1, 0, 0, 0, NULL);
2436                 if (d < 4) {
2437                         pos = text->curc+1;
2438                 } else {
2439                         pos = text->curc-1;
2440                 }
2441         }
2442         
2443         if (d < 4) /*reading forward*/
2444         {
2445                 open = 1; 
2446                 while ( tmp ) {
2447                         while (pos <= tmp->len) {
2448                                 test[0] = (unsigned char) tmp->line[pos];
2449                                 test[1] = '\0';
2450                                 if(check_bracket(test) == d) {
2451                                         open++;
2452                                 } else if (check_bracket(test) == d+3) {
2453                                         open--;
2454                                         if (open == 0) {
2455                                                 BIF_ThemeColorBlend(TH_BACK, TH_SHADE2, 0.5);
2456                                                 glRecti(x, curarea->winy-st->lheight*(h)-2, y, curarea->winy-st->lheight*(h+1)-2);
2457
2458                                                 h= txt_get_span(text->lines.first, tmp) - st->top;
2459                                                 x2= text_draw(st, tmp->line, st->left, pos, 0, 0, 0, NULL);
2460                                                 y2= text_draw(st, tmp->line, st->left, pos+1, 0, 0, 0, NULL);
2461                                                 glRecti(x2, curarea->winy-st->lheight*(h)-2, y2, curarea->winy-st->lheight*(h+1)-2);
2462                                                 BIF_ThemeColor(TH_TEXT);
2463                                                 return;
2464                                         }
2465                                 }
2466                                 pos++;
2467                         }
2468                         tmp = tmp->next;
2469                         pos = 0;
2470                 }
2471         } else { /*  reading back */
2472                 open = 1; 
2473                 while ( tmp ) {
2474                         while (pos >= 0) {
2475                                 test[0] = (unsigned char) tmp->line[pos];
2476                                 test[1] = '\0';
2477                                 if(check_bracket(test) == d) {
2478                                         open++;
2479                                 } else if (check_bracket(test) == d-3) {
2480                                         open--;
2481                                         if (open == 0) {
2482                                                 BIF_ThemeColorBlend(TH_BACK, TH_SHADE2, 0.5);
2483                                                 glRecti(x, curarea->winy-st->lheight*(h)-2, y, curarea->winy-st->lheight*(h+1)-2);
2484
2485                                                 h= txt_get_span(text->lines.first, tmp) - st->top;
2486                                                 x2= text_draw(st, tmp->line, st->left, pos, 0, 0, 0, NULL);
2487                                                 y2= text_draw(st, tmp->line, st->left, pos+1, 0, 0, 0, NULL);
2488                                                 glRecti(x2, curarea->winy-st->lheight*(h)-2, y2, curarea->winy-st->lheight*(h+1)-2);
2489                                                 BIF_ThemeColor(TH_TEXT);
2490                                                 return;
2491                                         }
2492                                 }
2493                                 pos--;
2494                         }
2495                         tmp = tmp->prev;
2496                         if (tmp) {
2497                                 pos = tmp->len;
2498                         }
2499                 }
2500         }
2501         
2502 }
2503
2504 int check_bracket(char *string)
2505 {
2506         int number, a = 0;
2507         char other[][3] = {"(", "[", "{", ")", "]", "}"};
2508         
2509         number = 6;
2510         
2511         while(a < number) {
2512                 if(strcmp(other[a], string) == 0)
2513                 {
2514                         return a+1;
2515                 }
2516                 a++;
2517         }
2518         return 0;
2519 }
2520
2521 static int check_builtinfuncs(char *string) 
2522 {
2523         int number = 30, a = 0;
2524         
2525         char builtinfuncs[][11] = {"and", "as", "assert", "break", "class", "continue", "def",
2526                                                                 "del", "elif", "else", "except", "exec", "finally",
2527                                                                 "for", "from", "global", "if", "import", "in",
2528                                                                 "is", "lambda", "not", "or", "pass", "print",
2529                                                                 "raise", "return", "try", "while", "yield"};
2530
2531         for( a = 0; a < number; a++) {
2532                 if(!strcmp(builtinfuncs[a], string))
2533                         return 1;
2534         }
2535         return 0;
2536 }
2537
2538 static int check_specialvars(char *string) 
2539 {
2540         int number = 2, a = 0;
2541         char specialvars[][7] = {"def", "class"};
2542         
2543         for( a = 0; a < number; a++) {
2544                 if(!strcmp(specialvars[a], string))
2545                         return a+1;
2546         }
2547         return 0;
2548 }
2549
2550 static int check_delim(char *string) 
2551 {
2552         int number = 28, a = 0;
2553         char other[][3] = {"(", ")", ":", "\"", "\'", " ", "~", "!", "%", "^", "&", "*", "-", "+", "=", "[", "]", "{", "}", ";", "/", "<", ">", "|", ".", "#", "\t", ","};
2554         
2555         for( a = 0; a < number; a++) {
2556                 if(!strcmp(other[a], string))
2557                         return 1;
2558         }
2559         return 0;
2560 }
2561
2562 static int check_numbers(char *string)
2563 {
2564         int number = 10, a = 0;
2565         char other[][2] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
2566         
2567         for( a = 0; a < number; a++) {
2568                 if(!strcmp(other[a], string))
2569                         return 1;
2570         }
2571         return 0;
2572 }
2573
2574 static int check_identifier(char ch) {
2575         if (ch < '0') return 0;
2576         if (ch <= '9') return 1;
2577         if (ch < 'A') return 0;
2578         if (ch <= 'Z' || ch == '_') return 1;
2579         if (ch < 'a') return 0;
2580         if (ch <= 'z') return 1;
2581         return 0;
2582 }
2583
2584 void convert_tabs (struct SpaceText *st, int tab)
2585 {
2586         Text *text = st->text;
2587         TextLine *tmp;
2588         char *check_line, *new_line, *format;
2589         int extra, number; //unknown for now
2590         size_t a, j;
2591         
2592         if (!text) return;
2593         
2594         tmp = text->lines.first;
2595         
2596         //first convert to all space, this make it alot easier to convert to tabs because there is no mixtures of ' ' && '\t'
2597         while(tmp) {
2598                 check_line = tmp->line;
2599                 new_line = MEM_mallocN(render_string(st, check_line)+1, "Converted_Line");
2600                 format = MEM_mallocN(render_string(st, check_line)+1, "Converted_Syntax_format");
2601                 j = 0;
2602                 for (a=0; a < strlen(check_line); a++) { //foreach char in line
2603                         if(check_line[a] == '\t') { //checking for tabs
2604                                 //get the number of spaces this tabs is showing
2605                                 //i dont like doing it this way but will look into it later
2606                                 new_line[j] = '\0';
2607                                 number = render_string(st, new_line);
2608                                 new_line[j] = '\t';
2609                                 new_line[j+1] = '\0';
2610                                 number = render_string(st, new_line)-number;
2611                                 for(extra = 0; extra < number; extra++) {
2612                                         new_line[j] = ' ';
2613                                         j++;
2614                                 }
2615                         } else {
2616                                 new_line[j] = check_line[a];
2617                                 ++j;
2618                         }
2619                 }
2620                 new_line[j] = '\0';
2621                 // put new_line in the tmp->line spot still need to try and set the curc correctly
2622                 if (tmp->line) MEM_freeN(tmp->line);
2623                 if(tmp->format) MEM_freeN(tmp->format);
2624                 
2625                 tmp->line = new_line;
2626                 tmp->len = strlen(new_line);
2627                 tmp->format = format;
2628                 tmp = tmp->next;
2629         }
2630         
2631         if (tab) // Converting to tabs
2632         {       //start over from the begining
2633                 tmp = text->lines.first;
2634                 
2635                 while(tmp) {
2636                         check_line = tmp->line;
2637                         extra = 0;
2638                         for (a = 0; a < strlen(check_line); a++) {
2639                                 number = 0;
2640                                 for (j = 0; j < (size_t)st->tabnumber; j++) {
2641                                         if ((a+j) <= strlen(check_line)) { //check to make sure we are not pass the end of the line
2642                                                 if(check_line[a+j] != ' ') {
2643                                                         number = 1;
2644                                                 }
2645                                         }
2646                                 }
2647                                 if (!number) { //found all number of space to equal a tab
2648                                         a = a+(st->tabnumber-1);
2649                                         extra = extra+1;
2650                                 }
2651                         }
2652                         
2653                         if ( extra > 0 ) { //got tabs make malloc and do what you have to do
2654                                 new_line = MEM_mallocN(strlen(check_line)-(((st->tabnumber*extra)-extra)-1), "Converted_Line");
2655                                 format = MEM_mallocN(strlen(check_line)-(((st->tabnumber*extra)-extra)-1), "Converted_Syntax_format");
2656                                 extra = 0; //reuse vars
2657                                 for (a = 0; a < strlen(check_line); a++) {
2658                                         number = 0;
2659                                         for (j = 0; j < (size_t)st->tabnumber; j++) {
2660                                                 if ((a+j) <= strlen(check_line)) { //check to make sure we are not pass the end of the line
2661                                                         if(check_line[a+j] != ' ') {
2662                                                                 number = 1;
2663                                                         }
2664                                                 }
2665                                         }
2666                                         if (!number) { //found all number of space to equal a tab
2667                                                 new_line[extra] = '\t';
2668                                                 a = a+(st->tabnumber-1);
2669                                                 ++extra;
2670                                                 
2671                                         } else { //not adding a tab
2672                                                 new_line[extra] = check_line[a];
2673                                                 ++extra;
2674                                         }
2675                                 }
2676                                 new_line[extra] = '\0';
2677                                 // put new_line in the tmp->line spot still need to try and set the curc correctly
2678                                 if (tmp->line) MEM_freeN(tmp->line);
2679                                 if(tmp->format) MEM_freeN(tmp->format);
2680                                 
2681                                 tmp->line = new_line;
2682                                 tmp->len = strlen(new_line);
2683                                 tmp->format = format;
2684                         }
2685                         tmp = tmp->next;
2686                 }
2687         }
2688
2689         if (st->showsyntax)
2690                 get_format_string(st);
2691 }