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