Revision: 1773 http://geany.svn.sourceforge.net/geany/?rev=1773&view=rev Author: ntrel Date: 2007-08-07 05:36:03 -0700 (Tue, 07 Aug 2007)
Log Message: ----------- Parse Python global variables and class variables from assignment statements; assignment to a tuple literal ('x, y =') not supported.
Modified Paths: -------------- trunk/ChangeLog trunk/src/symbols.c trunk/tagmanager/python.c
Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2007-08-05 11:29:09 UTC (rev 1772) +++ trunk/ChangeLog 2007-08-07 12:36:03 UTC (rev 1773) @@ -1,3 +1,10 @@ +2007-08-07 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com> + + * src/symbols.c, tagmanager/python.c: + Parse Python global variables and class variables from assignment + statements; assignment to a tuple literal ('x, y =') not supported. + + 2007-08-05 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
* geany.glade, src/geany.h, src/interface.c, src/keyfile.c,
Modified: trunk/src/symbols.c =================================================================== --- trunk/src/symbols.c 2007-08-05 11:29:09 UTC (rev 1772) +++ trunk/src/symbols.c 2007-08-07 12:36:03 UTC (rev 1773) @@ -572,6 +572,7 @@ &(tv_iters.tag_class), _("Classes"), "classviewer-class", &(tv_iters.tag_member), _("Methods"), "classviewer-member", &(tv_iters.tag_function), _("Functions"), "classviewer-method", + &(tv_iters.tag_variable), _("Variables"), "classviewer-var", NULL); //&(tv_iters.tag_macro), _("Mixin"), //&(tv_iters.tag_variable), _("Variables"),
Modified: trunk/tagmanager/python.c =================================================================== --- trunk/tagmanager/python.c 2007-08-05 11:29:09 UTC (rev 1772) +++ trunk/tagmanager/python.c 2007-08-07 12:36:03 UTC (rev 1773) @@ -24,13 +24,14 @@ * DATA DEFINITIONS */ typedef enum { - K_CLASS, K_FUNCTION, K_METHOD + K_CLASS, K_FUNCTION, K_METHOD, K_VARIABLE } pythonKind;
static kindOption PythonKinds [] = { { TRUE, 'c', "class", "classes" }, { TRUE, 'f', "function", "functions" }, - { TRUE, 'm', "member", "methods" } + { TRUE, 'm', "member", "methods" }, + { TRUE, 'v', "variable", "variables" } };
typedef struct _lastClass { @@ -42,7 +43,17 @@ * FUNCTION DEFINITIONS */
+static boolean isIdentifierFirstCharacter (int c) +{ + return (boolean) (isalpha (c) || c == '_'); +}
+static boolean isIdentifierCharacter (int c) +{ + return (boolean) (isalnum (c) || c == '_'); +} + + // remove all previous classes with more indent than the current one static GList *clean_class_list(GList *list, gint indent) { @@ -77,6 +88,9 @@ gint indent; const unsigned char *line; boolean inMultilineString = FALSE; + lastClass *lastclass = NULL; + boolean inFunction = FALSE; + gint fn_indent = 0;
while ((line = fileReadLine ()) != NULL) { @@ -97,15 +111,50 @@ cp += 3; }
+ if (*cp == '\0') + break; // at end of multiline string + + // update indent-sensitive things + if (!inMultilineString && !isspace(*cp)) + { + if (inFunction) + { + if (indent < fn_indent) + inFunction = FALSE; + } + if (lastclass != NULL) + { + if (indent <= lastclass->indent) + { + GList *last; + + parents = clean_class_list(parents, indent); + last = g_list_last(parents); + if (last != NULL) + lastclass = last->data; + else + lastclass = NULL; + } + } + } + if (inMultilineString) ++cp; else if (isspace ((int) *cp)) { - cp++; // count indentation amount of current line // the indentation has to be made with tabs only _or_ spaces only, if they are mixed // the code below gets confused - indent++; + if (cp == line) + { + do + { + indent++; + cp++; + } while (isspace(*cp)); + } + else + cp++; // non-indent whitespace } else if (*cp == '#') break; @@ -114,12 +163,8 @@ cp += 5; if (isspace ((int) *cp)) { - GList *last = g_list_last(parents); - lastClass *lastclass = NULL; lastClass *newclass = g_new(lastClass, 1);
- if (last != NULL) lastclass = last->data; - while (isspace ((int) *cp)) ++cp; while (isalnum ((int) *cp) || *cp == '_') @@ -129,13 +174,14 @@ } vStringTerminate (name);
- parents = clean_class_list(parents, indent); - newclass->name = g_strdup(vStringValue(name)); newclass->indent = indent; parents = g_list_append(parents, newclass); makeSimpleTag (name, PythonKinds, K_CLASS); vStringClear (name); + + lastclass = newclass; + break; // ignore rest of line so that lastclass is not reset immediately } } else if (strncmp ((const char*) cp, "def", (size_t) 3) == 0) @@ -143,13 +189,6 @@ cp += 3; if (isspace ((int) *cp)) { - GList *last; - lastClass *lastclass = NULL; - - parents = clean_class_list(parents, indent); - last = g_list_last(parents); - if (last != NULL) lastclass = last->data; - while (isspace ((int) *cp)) ++cp; while (isalnum ((int) *cp) || *cp == '_') @@ -164,8 +203,62 @@ makeSimpleScopedTag (name, PythonKinds, K_METHOD, PythonKinds[K_CLASS].name, lastclass->name, "public"); vStringClear (name); + + inFunction = TRUE; + fn_indent = indent + 1; + break; // ignore rest of line so inFunction is not cancelled immediately } } + else if (!inFunction && *(const char*)cp == '=') + { + /* Parse global and class variable names (C.x) from assignment statements. + * Object attributes (obj.x) are ignored. + * Assignment to a tuple 'x, y = 2, 3' not supported. + * TODO: ignore duplicate tags from reassignment statements. */ + const guchar *sp, *eq, *start; + + eq = cp + 1; + while (*eq) + { + if (*eq == '=') + goto skipvar; // ignore '==' operator and 'x=5,y=6)' function lines + if (*eq == '(') + break; // allow 'x = func(b=2,y=2,' lines + eq++; + } + // go backwards to the start of the line, checking we have valid chars + start = cp - 1; + while (start >= line && isspace ((int) *start)) + --start; + while (start >= line && isIdentifierCharacter ((int) *start)) + --start; + if (!isIdentifierFirstCharacter(*(start + 1))) + goto skipvar; + sp = start; + while (sp >= line && isspace ((int) *sp)) + --sp; + if ((sp + 1) != line) // the line isn't a simple variable assignment + goto skipvar; + // the line is valid, parse the variable name + ++start; + while (isIdentifierCharacter ((int) *start)) + { + vStringPut (name, (int) *start); + ++start; + } + vStringTerminate (name); + + if (lastclass == NULL) + makeSimpleTag (name, PythonKinds, K_VARIABLE); + else + makeSimpleScopedTag (name, PythonKinds, K_VARIABLE, + PythonKinds[K_CLASS].name, lastclass->name, "public"); // class member variables + + vStringClear (name); + + skipvar: + ++cp; + } else if (*cp != '\0') { do
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.