generalize formatting code so different formatters can be registered and each has...
authorCampbell Barton <ideasman42@gmail.com>
Wed, 19 Dec 2012 04:02:19 +0000 (04:02 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 19 Dec 2012 04:02:19 +0000 (04:02 +0000)
Since we will likely have OSL formatting added soon.

source/blender/editors/space_text/CMakeLists.txt
source/blender/editors/space_text/space_text.c
source/blender/editors/space_text/text_draw.c
source/blender/editors/space_text/text_format.c [new file with mode: 0644]
source/blender/editors/space_text/text_format.h [new file with mode: 0644]
source/blender/editors/space_text/text_format_py.c [new file with mode: 0644]
source/blender/editors/space_text/text_intern.h
source/blender/editors/space_text/text_ops.c

index 9cc407f..6aaf421 100644 (file)
@@ -37,10 +37,13 @@ set(INC_SYS
 set(SRC
        space_text.c
        text_draw.c
+       text_format.c
+       text_format_py.c
        text_header.c
        text_ops.c
        text_python.c
 
+       text_format.h
        text_intern.h
 )
 
index d74e326..b5a3e7b 100644 (file)
@@ -61,7 +61,8 @@
 #include "RNA_access.h"
 
 
-#include "text_intern.h"    // own include
+#include "text_format.h"
+#include "text_intern.h"  /* own include */
 
 /* ******************** default callbacks for text space ***************** */
 
@@ -556,5 +557,8 @@ void ED_spacetype_text(void)
        BLI_addhead(&st->regiontypes, art);
 
        BKE_spacetype_register(st);
+
+       /* register formatters */
+       ED_text_format_register_py();
 }
 
index 24f40db..2066df3 100644 (file)
@@ -58,6 +58,7 @@
 #include "UI_resources.h"
 
 #include "text_intern.h"
+#include "text_format.h"
 
 /******************** text font drawing ******************/
 // XXX, fixme
@@ -105,350 +106,6 @@ static int text_font_draw_character_utf8(SpaceText *st, int x, int y, const char
        return st->cwidth;
 }
 
-/****************** flatten string **********************/
-
-static void flatten_string_append(FlattenString *fs, const char *c, int accum, int len) 
-{
-       int i;
-       
-       if (fs->pos + len > fs->len) {
-               char *nbuf; int *naccum;
-               fs->len *= 2;
-
-               nbuf = MEM_callocN(sizeof(*fs->buf) * fs->len, "fs->buf");
-               naccum = MEM_callocN(sizeof(*fs->accum) * fs->len, "fs->accum");
-
-               memcpy(nbuf, fs->buf, fs->pos * sizeof(*fs->buf));
-               memcpy(naccum, fs->accum, fs->pos * sizeof(*fs->accum));
-               
-               if (fs->buf != fs->fixedbuf) {
-                       MEM_freeN(fs->buf);
-                       MEM_freeN(fs->accum);
-               }
-               
-               fs->buf = nbuf;
-               fs->accum = naccum;
-       }
-       
-       for (i = 0; i < len; i++) {
-               fs->buf[fs->pos + i] = c[i];
-               fs->accum[fs->pos + i] = accum;
-       }
-
-       fs->pos += len;
-}
-
-int flatten_string(SpaceText *st, FlattenString *fs, const char *in)
-{
-       int r, i, total = 0;
-
-       memset(fs, 0, sizeof(FlattenString));
-       fs->buf = fs->fixedbuf;
-       fs->accum = fs->fixedaccum;
-       fs->len = sizeof(fs->fixedbuf);
-
-       for (r = 0, i = 0; *in; r++) {
-               if (*in == '\t') {
-                       i = st->tabnumber - (total % st->tabnumber);
-                       total += i;
-                       
-                       while (i--)
-                               flatten_string_append(fs, " ", r, 1);
-                       
-                       in++;
-               }
-               else {
-                       size_t len = BLI_str_utf8_size_safe(in);
-                       flatten_string_append(fs, in, r, len);
-                       in += len;
-                       total++;
-               }
-       }
-       
-       flatten_string_append(fs, "\0", r, 1);
-
-       return total;
-}
-
-void flatten_string_free(FlattenString *fs)
-{
-       if (fs->buf != fs->fixedbuf)
-               MEM_freeN(fs->buf);
-       if (fs->accum != fs->fixedaccum)
-               MEM_freeN(fs->accum);
-}
-
-/* Checks the specified source string for a Python built-in function name. This
- * name must start at the beginning of the source string and must be followed by
- * a non-identifier (see text_check_identifier(char)) or null character.
- * 
- * If a built-in function is found, the length of the matching name is returned.
- * Otherwise, -1 is returned.
- *
- * See:
- * http://docs.python.org/py3k/reference/lexical_analysis.html#keywords
- */
-
-static int find_builtinfunc(char *string)
-{
-       int a, i;
-       const char *builtinfuncs[] = {
-               /* "False", "None", "True", */ /* see find_bool() */
-               "and", "as", "assert", "break",
-               "class", "continue", "def", "del", "elif", "else", "except",
-               "finally", "for", "from", "global", "if", "import", "in",
-               "is", "lambda", "nonlocal", "not", "or", "pass", "raise",
-               "return", "try", "while", "with", "yield",
-       };
-
-       for (a = 0; a < sizeof(builtinfuncs) / sizeof(builtinfuncs[0]); a++) {
-               i = 0;
-               while (1) {
-                       /* If we hit the end of a keyword... (eg. "def") */
-                       if (builtinfuncs[a][i] == '\0') {
-                               /* If we still have identifier chars in the source (eg. "definate") */
-                               if (text_check_identifier(string[i]))
-                                       i = -1;  /* No match */
-                               break; /* Next keyword if no match, otherwise we're done */
-                               
-                               /* If chars mismatch, move on to next keyword */
-                       }
-                       else if (string[i] != builtinfuncs[a][i]) {
-                               i = -1;
-                               break; /* Break inner loop, start next keyword */
-                       }
-                       i++;
-               }
-               if (i > 0) break;  /* If we have a match, we're done */
-       }
-       return i;
-}
-
-/* Checks the specified source string for a Python special name. This name must
- * start at the beginning of the source string and must be followed by a non-
- * identifier (see text_check_identifier(char)) or null character.
- * 
- * If a special name is found, the length of the matching name is returned.
- * Otherwise, -1 is returned. */
-
-static int find_specialvar(char *string) 
-{
-       int i = 0;
-       /* Check for "def" */
-       if (string[0] == 'd' && string[1] == 'e' && string[2] == 'f')
-               i = 3;
-       /* Check for "class" */
-       else if (string[0] == 'c' && string[1] == 'l' && string[2] == 'a' && string[3] == 's' && string[4] == 's')
-               i = 5;
-       /* If next source char is an identifier (eg. 'i' in "definate") no match */
-       if (i == 0 || text_check_identifier(string[i]))
-               return -1;
-       return i;
-}
-
-static int find_decorator(char *string) 
-{
-       if (string[0] == '@') {
-               int i = 1;
-               while (text_check_identifier(string[i])) {
-                       i++;
-               }
-               return i;
-       }
-       return -1;
-}
-
-static int find_bool(char *string) 
-{
-       int i = 0;
-       /* Check for "False" */
-       if (string[0] == 'F' && string[1] == 'a' && string[2] == 'l' && string[3] == 's' && string[4] == 'e')
-               i = 5;
-       /* Check for "True" */
-       else if (string[0] == 'T' && string[1] == 'r' && string[2] == 'u' && string[3] == 'e')
-               i = 4;
-       /* Check for "None" */
-       else if (string[0] == 'N' && string[1] == 'o' && string[2] == 'n' && string[3] == 'e')
-               i = 4;
-       /* If next source char is an identifier (eg. 'i' in "definate") no match */
-       if (i == 0 || text_check_identifier(string[i]))
-               return -1;
-       return i;
-}
-
-/* Ensures the format string for the given line is long enough, reallocating
- * as needed. Allocation is done here, alone, to ensure consistency. */
-static int text_check_format_len(TextLine *line, unsigned int len)
-{
-       if (line->format) {
-               if (strlen(line->format) < len) {
-                       MEM_freeN(line->format);
-                       line->format = MEM_mallocN(len + 2, "SyntaxFormat");
-                       if (!line->format) return 0;
-               }
-       }
-       else {
-               line->format = MEM_mallocN(len + 2, "SyntaxFormat");
-               if (!line->format) return 0;
-       }
-
-       return 1;
-}
-
-/* Formats the specified line. If do_next is set, the process will move on to
- * the succeeding line if it is affected (eg. multiline strings). Format strings
- * may contain any of the following characters:
- *  '_'  Whitespace
- *  '#'  Comment text
- *  '!'  Punctuation and other symbols
- *  'n'  Numerals
- *  'l'  String letters
- *  'v'  Special variables (class, def)
- *  'b'  Built-in names (print, for, etc.)
- *  'q'  Other text (identifiers, etc.)
- * It is terminated with a null-terminator '\0' followed by a continuation
- * flag indicating whether the line is part of a multi-line string. */
-
-static void txt_format_line(SpaceText *st, TextLine *line, int do_next)
-{
-       FlattenString fs;
-       char *str, *fmt, orig, cont, find, prev = ' ';
-       int len, i;
-
-       /* Get continuation from previous line */
-       if (line->prev && line->prev->format != NULL) {
-               fmt = line->prev->format;
-               cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
-       }
-       else cont = 0;
-
-       /* Get original continuation from this line */
-       if (line->format != NULL) {
-               fmt = line->format;
-               orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
-       }
-       else orig = 0xFF;
-
-       len = flatten_string(st, &fs, line->line);
-       str = fs.buf;
-       if (!text_check_format_len(line, len)) {
-               flatten_string_free(&fs);
-               return;
-       }
-       fmt = line->format;
-
-       while (*str) {
-               /* Handle escape sequences by skipping both \ and next char */
-               if (*str == '\\') {
-                       *fmt = prev; fmt++; str++;
-                       if (*str == '\0') break;
-                       *fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str);
-                       continue;
-               }
-               /* Handle continuations */
-               else if (cont) {
-                       /* Triple strings ("""...""" or '''...''') */
-                       if (cont & TXT_TRISTR) {
-                               find = (cont & TXT_DBLQUOTSTR) ? '"' : '\'';
-                               if (*str == find && *(str + 1) == find && *(str + 2) == find) {
-                                       *fmt = 'l'; fmt++; str++;
-                                       *fmt = 'l'; fmt++; str++;
-                                       cont = 0;
-                               }
-                               /* Handle other strings */
-                       }
-                       else {
-                               find = (cont & TXT_DBLQUOTSTR) ? '"' : '\'';
-                               if (*str == find) cont = 0;
-                       }
-
-                       *fmt = 'l';
-                       str += BLI_str_utf8_size_safe(str) - 1;
-               }
-               /* Not in a string... */
-               else {
-                       /* Deal with comments first */
-                       if (prev == '#' || *str == '#') {
-                               *fmt = '#';
-                               str += BLI_str_utf8_size_safe(str) - 1;
-                       }
-                       else if (*str == '"' || *str == '\'') {
-                               /* Strings */
-                               find = *str;
-                               cont = (*str == '"') ? TXT_DBLQUOTSTR : TXT_SNGQUOTSTR;
-                               if (*(str + 1) == find && *(str + 2) == find) {
-                                       *fmt = 'l'; fmt++; str++;
-                                       *fmt = 'l'; fmt++; str++;
-                                       cont |= TXT_TRISTR;
-                               }
-                               *fmt = 'l';
-                       }
-                       /* Whitespace (all ws. has been converted to spaces) */
-                       else if (*str == ' ')
-                               *fmt = '_';
-                       /* Numbers (digits not part of an identifier and periods followed by digits) */
-                       else if ((prev != 'q' && text_check_digit(*str)) || (*str == '.' && text_check_digit(*(str + 1))))
-                               *fmt = 'n';
-                       /* Booleans */
-                       else if (prev != 'q' && (i = find_bool(str)) != -1)
-                               if (i > 0) {
-                                       while (i > 1) {
-                                               *fmt = 'n'; fmt++; str++;
-                                               i--;
-                                       }
-                                       *fmt = 'n';
-                               }
-                               else {
-                                       str += BLI_str_utf8_size_safe(str) - 1;
-                                       *fmt = 'q';
-                               }
-                       /* Punctuation */
-                       else if (text_check_delim(*str))
-                               *fmt = '!';
-                       /* Identifiers and other text (no previous ws. or delims. so text continues) */
-                       else if (prev == 'q') {
-                               str += BLI_str_utf8_size_safe(str) - 1;
-                               *fmt = 'q';
-                       }
-                       /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
-                       else {
-                               /* Special vars(v) or built-in keywords(b) */
-                               if ((i = find_specialvar(str)) != -1)
-                                       prev = 'v';
-                               else if ((i = find_builtinfunc(str)) != -1)
-                                       prev = 'b';
-                               else if ((i = find_decorator(str)) != -1)
-                                       prev = 'v';  /* could have a new color for this */
-                               if (i > 0) {
-                                       while (i > 1) {
-                                               *fmt = prev; fmt++; str++;
-                                               i--;
-                                       }
-                                       *fmt = prev;
-                               }
-                               else {
-                                       str += BLI_str_utf8_size_safe(str) - 1;
-                                       *fmt = 'q';
-                               }
-                       }
-               }
-               prev = *fmt;
-               fmt++;
-               str++;
-       }
-
-       /* Terminate and add continuation char */
-       *fmt = '\0'; fmt++;
-       *fmt = cont;
-
-       /* If continuation has changed and we're allowed, process the next line */
-       if (cont != orig && do_next && line->next) {
-               txt_format_line(st, line->next, do_next);
-       }
-       
-       flatten_string_free(&fs);
-}
-
 #if 0
 /* Formats every line of the current text */
 static void txt_format_text(SpaceText *st) 
@@ -1620,6 +1277,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar)
 void draw_text_main(SpaceText *st, ARegion *ar)
 {
        Text *text = st->text;
+       TextFormatType *tft = ED_text_format_get(text);
        TextLine *tmp;
        rcti scroll, back;
        char linenr[12];
@@ -1651,7 +1309,7 @@ void draw_text_main(SpaceText *st, ARegion *ar)
        lineno = 0;
        for (i = 0; i < st->top && tmp; i++) {
                if (st->showsyntax && !tmp->format)
-                       txt_format_line(st, tmp, 0);
+                       tft->format_line(st, tmp, 0);
 
                if (st->wordwrap) {
                        int lines = text_get_visible_lines_no(st, lineno);
@@ -1700,7 +1358,7 @@ void draw_text_main(SpaceText *st, ARegion *ar)
 
        for (i = 0; y > 0 && i < st->viewlines && tmp; i++, tmp = tmp->next) {
                if (st->showsyntax && !tmp->format)
-                       txt_format_line(st, tmp, 0);
+                       tft->format_line(st, tmp, 0);
 
                if (st->showlinenrs && !wrap_skip) {
                        /* draw line number */
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
new file mode 100644 (file)
index 0000000..512b512
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_text/text_draw.c
+ *  \ingroup sptext
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLF_api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_text_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_context.h"
+#include "BKE_suggestions.h"
+#include "BKE_text.h"
+
+#include "BIF_gl.h"
+
+#include "ED_datafiles.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "text_intern.h"
+#include "text_format.h"
+
+
+/****************** flatten string **********************/
+
+static void flatten_string_append(FlattenString *fs, const char *c, int accum, int len)
+{
+       int i;
+
+       if (fs->pos + len > fs->len) {
+               char *nbuf; int *naccum;
+               fs->len *= 2;
+
+               nbuf = MEM_callocN(sizeof(*fs->buf) * fs->len, "fs->buf");
+               naccum = MEM_callocN(sizeof(*fs->accum) * fs->len, "fs->accum");
+
+               memcpy(nbuf, fs->buf, fs->pos * sizeof(*fs->buf));
+               memcpy(naccum, fs->accum, fs->pos * sizeof(*fs->accum));
+
+               if (fs->buf != fs->fixedbuf) {
+                       MEM_freeN(fs->buf);
+                       MEM_freeN(fs->accum);
+               }
+
+               fs->buf = nbuf;
+               fs->accum = naccum;
+       }
+
+       for (i = 0; i < len; i++) {
+               fs->buf[fs->pos + i] = c[i];
+               fs->accum[fs->pos + i] = accum;
+       }
+
+       fs->pos += len;
+}
+
+int flatten_string(SpaceText *st, FlattenString *fs, const char *in)
+{
+       int r, i, total = 0;
+
+       memset(fs, 0, sizeof(FlattenString));
+       fs->buf = fs->fixedbuf;
+       fs->accum = fs->fixedaccum;
+       fs->len = sizeof(fs->fixedbuf);
+
+       for (r = 0, i = 0; *in; r++) {
+               if (*in == '\t') {
+                       i = st->tabnumber - (total % st->tabnumber);
+                       total += i;
+
+                       while (i--)
+                               flatten_string_append(fs, " ", r, 1);
+
+                       in++;
+               }
+               else {
+                       size_t len = BLI_str_utf8_size_safe(in);
+                       flatten_string_append(fs, in, r, len);
+                       in += len;
+                       total++;
+               }
+       }
+
+       flatten_string_append(fs, "\0", r, 1);
+
+       return total;
+}
+
+void flatten_string_free(FlattenString *fs)
+{
+       if (fs->buf != fs->fixedbuf)
+               MEM_freeN(fs->buf);
+       if (fs->accum != fs->fixedaccum)
+               MEM_freeN(fs->accum);
+}
+
+/* Ensures the format string for the given line is long enough, reallocating
+ * as needed. Allocation is done here, alone, to ensure consistency. */
+
+/*TODO: rename! flatten_string_len_ensure() */
+int text_check_format_len(TextLine *line, unsigned int len)
+{
+       if (line->format) {
+               if (strlen(line->format) < len) {
+                       MEM_freeN(line->format);
+                       line->format = MEM_mallocN(len + 2, "SyntaxFormat");
+                       if (!line->format) return 0;
+               }
+       }
+       else {
+               line->format = MEM_mallocN(len + 2, "SyntaxFormat");
+               if (!line->format) return 0;
+       }
+
+       return 1;
+}
+
+/* *** Registration *** */
+static ListBase tft_lb = {NULL, NULL};
+void ED_text_format_register(TextFormatType *tft)
+{
+       BLI_addtail(&tft_lb, tft);
+}
+
+TextFormatType *ED_text_format_get(Text *UNUSED(text))
+{
+       /* NOTE: once more types are added we'll need to return some type based on 'text'
+        * for now this function is more of a placeholder */
+
+       return tft_lb.first;
+}
diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h
new file mode 100644 (file)
index 0000000..7b5b326
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * 
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_text/text_format.h
+ *  \ingroup sptext
+ */
+
+#ifndef __TEXT_FORMAT_H__
+#define __TEXT_FORMAT_H__
+
+/* *** Flatten String *** */
+typedef struct FlattenString {
+       char fixedbuf[256];
+       int fixedaccum[256];
+
+       char *buf;
+       int *accum;
+       int pos, len;
+} FlattenString;
+
+int  flatten_string(struct SpaceText *st, FlattenString *fs, const char *in);
+void flatten_string_free(FlattenString *fs);
+int  text_check_format_len(TextLine *line, unsigned int len);
+
+
+/* *** Generalize Formatting *** */
+typedef struct TextFormatType {
+       struct TextFormatType *next, *prev;
+
+       /* Formats the specified line. If do_next is set, the process will move on to
+        * the succeeding line if it is affected (eg. multiline strings). Format strings
+        * may contain any of the following characters:
+        *  '_'  Whitespace
+        *  '#'  Comment text
+        *  '!'  Punctuation and other symbols
+        *  'n'  Numerals
+        *  'l'  String letters
+        *  'v'  Special variables (class, def)
+        *  'b'  Built-in names (print, for, etc.)
+        *  'q'  Other text (identifiers, etc.)
+        * It is terminated with a null-terminator '\0' followed by a continuation
+        * flag indicating whether the line is part of a multi-line string. */
+       void (*format_line)(SpaceText *st, TextLine *line, int do_next);
+
+       const char **ext;  /* NULL terminated extensions */
+} TextFormatType;
+
+TextFormatType *ED_text_format_get(Text *text);
+void            ED_text_format_register(TextFormatType *tft);
+
+/* formatters */
+void ED_text_format_register_py(void);
+
+#endif  /* __TEXT_FORMAT_H__ */
diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c
new file mode 100644 (file)
index 0000000..dfee0e3
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_text/text_format_py.c
+ *  \ingroup sptext
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLF_api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_text_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_context.h"
+#include "BKE_suggestions.h"
+#include "BKE_text.h"
+
+#include "BIF_gl.h"
+
+#include "ED_datafiles.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "text_intern.h"
+#include "text_format.h"
+
+/* *** Local Functions (for format_line) *** */
+
+
+/* Checks the specified source string for a Python built-in function name. This
+ * name must start at the beginning of the source string and must be followed by
+ * a non-identifier (see text_check_identifier(char)) or null character.
+ *
+ * If a built-in function is found, the length of the matching name is returned.
+ * Otherwise, -1 is returned.
+ *
+ * See:
+ * http://docs.python.org/py3k/reference/lexical_analysis.html#keywords
+ */
+
+static int find_builtinfunc(char *string)
+{
+       int a, i;
+       const char *builtinfuncs[] = {
+               /* "False", "None", "True", */ /* see find_bool() */
+               "and", "as", "assert", "break",
+               "class", "continue", "def", "del", "elif", "else", "except",
+               "finally", "for", "from", "global", "if", "import", "in",
+               "is", "lambda", "nonlocal", "not", "or", "pass", "raise",
+               "return", "try", "while", "with", "yield",
+       };
+
+       for (a = 0; a < sizeof(builtinfuncs) / sizeof(builtinfuncs[0]); a++) {
+               i = 0;
+               while (1) {
+                       /* If we hit the end of a keyword... (eg. "def") */
+                       if (builtinfuncs[a][i] == '\0') {
+                               /* If we still have identifier chars in the source (eg. "definate") */
+                               if (text_check_identifier(string[i]))
+                                       i = -1;  /* No match */
+                               break; /* Next keyword if no match, otherwise we're done */
+
+                               /* If chars mismatch, move on to next keyword */
+                       }
+                       else if (string[i] != builtinfuncs[a][i]) {
+                               i = -1;
+                               break; /* Break inner loop, start next keyword */
+                       }
+                       i++;
+               }
+               if (i > 0) break;  /* If we have a match, we're done */
+       }
+       return i;
+}
+
+/* Checks the specified source string for a Python special name. This name must
+ * start at the beginning of the source string and must be followed by a non-
+ * identifier (see text_check_identifier(char)) or null character.
+ *
+ * If a special name is found, the length of the matching name is returned.
+ * Otherwise, -1 is returned. */
+
+static int find_specialvar(char *string)
+{
+       int i = 0;
+       /* Check for "def" */
+       if (string[0] == 'd' && string[1] == 'e' && string[2] == 'f')
+               i = 3;
+       /* Check for "class" */
+       else if (string[0] == 'c' && string[1] == 'l' && string[2] == 'a' && string[3] == 's' && string[4] == 's')
+               i = 5;
+       /* If next source char is an identifier (eg. 'i' in "definate") no match */
+       if (i == 0 || text_check_identifier(string[i]))
+               return -1;
+       return i;
+}
+
+static int find_decorator(char *string)
+{
+       if (string[0] == '@') {
+               int i = 1;
+               while (text_check_identifier(string[i])) {
+                       i++;
+               }
+               return i;
+       }
+       return -1;
+}
+
+static int find_bool(char *string)
+{
+       int i = 0;
+       /* Check for "False" */
+       if (string[0] == 'F' && string[1] == 'a' && string[2] == 'l' && string[3] == 's' && string[4] == 'e')
+               i = 5;
+       /* Check for "True" */
+       else if (string[0] == 'T' && string[1] == 'r' && string[2] == 'u' && string[3] == 'e')
+               i = 4;
+       /* Check for "None" */
+       else if (string[0] == 'N' && string[1] == 'o' && string[2] == 'n' && string[3] == 'e')
+               i = 4;
+       /* If next source char is an identifier (eg. 'i' in "definate") no match */
+       if (i == 0 || text_check_identifier(string[i]))
+               return -1;
+       return i;
+}
+
+static void txt_format_line(SpaceText *st, TextLine *line, int do_next)
+{
+       FlattenString fs;
+       char *str, *fmt, orig, cont, find, prev = ' ';
+       int len, i;
+
+       /* Get continuation from previous line */
+       if (line->prev && line->prev->format != NULL) {
+               fmt = line->prev->format;
+               cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+       }
+       else cont = 0;
+
+       /* Get original continuation from this line */
+       if (line->format != NULL) {
+               fmt = line->format;
+               orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+       }
+       else orig = 0xFF;
+
+       len = flatten_string(st, &fs, line->line);
+       str = fs.buf;
+       if (!text_check_format_len(line, len)) {
+               flatten_string_free(&fs);
+               return;
+       }
+       fmt = line->format;
+
+       while (*str) {
+               /* Handle escape sequences by skipping both \ and next char */
+               if (*str == '\\') {
+                       *fmt = prev; fmt++; str++;
+                       if (*str == '\0') break;
+                       *fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str);
+                       continue;
+               }
+               /* Handle continuations */
+               else if (cont) {
+                       /* Triple strings ("""...""" or '''...''') */
+                       if (cont & TXT_TRISTR) {
+                               find = (cont & TXT_DBLQUOTSTR) ? '"' : '\'';
+                               if (*str == find && *(str + 1) == find && *(str + 2) == find) {
+                                       *fmt = 'l'; fmt++; str++;
+                                       *fmt = 'l'; fmt++; str++;
+                                       cont = 0;
+                               }
+                               /* Handle other strings */
+                       }
+                       else {
+                               find = (cont & TXT_DBLQUOTSTR) ? '"' : '\'';
+                               if (*str == find) cont = 0;
+                       }
+
+                       *fmt = 'l';
+                       str += BLI_str_utf8_size_safe(str) - 1;
+               }
+               /* Not in a string... */
+               else {
+                       /* Deal with comments first */
+                       if (prev == '#' || *str == '#') {
+                               *fmt = '#';
+                               str += BLI_str_utf8_size_safe(str) - 1;
+                       }
+                       else if (*str == '"' || *str == '\'') {
+                               /* Strings */
+                               find = *str;
+                               cont = (*str == '"') ? TXT_DBLQUOTSTR : TXT_SNGQUOTSTR;
+                               if (*(str + 1) == find && *(str + 2) == find) {
+                                       *fmt = 'l'; fmt++; str++;
+                                       *fmt = 'l'; fmt++; str++;
+                                       cont |= TXT_TRISTR;
+                               }
+                               *fmt = 'l';
+                       }
+                       /* Whitespace (all ws. has been converted to spaces) */
+                       else if (*str == ' ')
+                               *fmt = '_';
+                       /* Numbers (digits not part of an identifier and periods followed by digits) */
+                       else if ((prev != 'q' && text_check_digit(*str)) || (*str == '.' && text_check_digit(*(str + 1))))
+                               *fmt = 'n';
+                       /* Booleans */
+                       else if (prev != 'q' && (i = find_bool(str)) != -1)
+                               if (i > 0) {
+                                       while (i > 1) {
+                                               *fmt = 'n'; fmt++; str++;
+                                               i--;
+                                       }
+                                       *fmt = 'n';
+                               }
+                               else {
+                                       str += BLI_str_utf8_size_safe(str) - 1;
+                                       *fmt = 'q';
+                               }
+                       /* Punctuation */
+                       else if (text_check_delim(*str))
+                               *fmt = '!';
+                       /* Identifiers and other text (no previous ws. or delims. so text continues) */
+                       else if (prev == 'q') {
+                               str += BLI_str_utf8_size_safe(str) - 1;
+                               *fmt = 'q';
+                       }
+                       /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+                       else {
+                               /* Special vars(v) or built-in keywords(b) */
+                               if ((i = find_specialvar(str)) != -1)
+                                       prev = 'v';
+                               else if ((i = find_builtinfunc(str)) != -1)
+                                       prev = 'b';
+                               else if ((i = find_decorator(str)) != -1)
+                                       prev = 'v';  /* could have a new color for this */
+                               if (i > 0) {
+                                       while (i > 1) {
+                                               *fmt = prev; fmt++; str++;
+                                               i--;
+                                       }
+                                       *fmt = prev;
+                               }
+                               else {
+                                       str += BLI_str_utf8_size_safe(str) - 1;
+                                       *fmt = 'q';
+                               }
+                       }
+               }
+               prev = *fmt;
+               fmt++;
+               str++;
+       }
+
+       /* Terminate and add continuation char */
+       *fmt = '\0'; fmt++;
+       *fmt = cont;
+
+       /* If continuation has changed and we're allowed, process the next line */
+       if (cont != orig && do_next && line->next) {
+               txt_format_line(st, line->next, do_next);
+       }
+
+       flatten_string_free(&fs);
+}
+
+void ED_text_format_register_py(void)
+{
+       static TextFormatType tft = {0};
+       static const char *ext[] = {"py", NULL};
+
+       tft.format_line = txt_format_line;
+       tft.ext = ext;
+
+       ED_text_format_register(&tft);
+}
index 6d3b184..c7f9512 100644 (file)
@@ -68,18 +68,6 @@ void text_update_cursor_moved(struct bContext *C);
 #define TOOL_SUGG_LIST 0x01
 #define TOOL_DOCUMENT  0x02
 
-typedef struct FlattenString {
-       char fixedbuf[256];
-       int fixedaccum[256];
-
-       char *buf;
-       int *accum;
-       int pos, len;
-} FlattenString;
-
-int flatten_string(struct SpaceText *st, FlattenString *fs, const char *in);
-void flatten_string_free(FlattenString *fs);
-
 int wrap_width(struct SpaceText *st, struct ARegion *ar);
 void wrap_offset(struct SpaceText *st, struct ARegion *ar, struct TextLine *linein, int cursin, int *offl, int *offc);
 void wrap_offset_in_line(struct SpaceText *st, struct ARegion *ar, struct TextLine *linep, int cursin, int *offl, int *offc);
index 7104457..745e994 100644 (file)
@@ -72,6 +72,7 @@
 #endif
 
 #include "text_intern.h"
+#include "text_format.h"
 
 /************************ poll ***************************/