Branch: refs/heads/master Author: Colomban Wendling ban@herbesfolles.org Committer: Colomban Wendling ban@herbesfolles.org Date: Mon, 17 Sep 2012 20:59:52 Commit: b886ac1b2e601248238a5ab85848d78108e3550e https://github.com/geany/geany/commit/b886ac1b2e601248238a5ab85848d78108e355...
Log Message: ----------- Merge branch 'improve-scope-detection'
Modified Paths: -------------- src/callbacks.c src/symbols.c src/symbols.h src/ui_utils.c tagmanager/src/tm_workspace.c tagmanager/src/tm_workspace.h
Modified: src/callbacks.c 2 files changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -1171,7 +1171,7 @@ G_MODULE_EXPORT void on_comments_function_activate(GtkMenuItem *menuitem, gpoint /* symbols_get_current_function returns -1 on failure, so sci_get_position_from_line * returns the current position, so it should be safe */ line = symbols_get_current_function(doc, &cur_tag); - pos = sci_get_position_from_line(doc->editor->sci, line - 1); + pos = sci_get_position_from_line(doc->editor->sci, line);
text = templates_get_template_function(doc, cur_tag);
Modified: src/symbols.c 178 files changed, 115 insertions(+), 63 deletions(-) =================================================================== @@ -1959,20 +1959,22 @@ static gint get_function_fold_number(GeanyDocument *doc) }
-/* Should be used only with symbols_get_current_function. */ -static gboolean current_function_changed(GeanyDocument *doc, gint cur_line, gint fold_level) +/* Should be used only with get_current_tag_cached. + * tag_types caching might trigger recomputation too often but this isn't used differently often + * enough to be an issue for now */ +static gboolean current_tag_changed(GeanyDocument *doc, gint cur_line, gint fold_level, guint tag_types) { static gint old_line = -2; static GeanyDocument *old_doc = NULL; static gint old_fold_num = -1; + static guint old_tag_types = 0; const gint fold_num = fold_level & SC_FOLDLEVELNUMBERMASK; gboolean ret;
/* check if the cached line and file index have changed since last time: */ - if (doc == NULL || doc != old_doc) + if (doc == NULL || doc != old_doc || old_tag_types != tag_types) ret = TRUE; - else - if (cur_line == old_line) + else if (cur_line == old_line) ret = FALSE; else { @@ -1989,6 +1991,7 @@ static gboolean current_function_changed(GeanyDocument *doc, gint cur_line, gint old_line = cur_line; old_doc = doc; old_fold_num = fold_num; + old_tag_types = tag_types; return ret; }
@@ -2069,83 +2072,79 @@ static gchar *parse_cpp_function_at_line(ScintillaObject *sci, gint tag_line) }
-/* Sets *tagname to point at the current function or tag name. - * If doc is NULL, reset the cached current tag data to ensure it will be reparsed on the next - * call to this function. - * Returns: line number of the current tag, or -1 if unknown. */ -gint symbols_get_current_function(GeanyDocument *doc, const gchar **tagname) +static gint get_fold_header_after(ScintillaObject *sci, gint line) { - static gint tag_line = -1; - static gchar *cur_tag = NULL; - gint line; - gint fold_level; - TMWorkObject *tm_file; + gint line_count = sci_get_line_count(sci);
- if (doc == NULL) /* reset current function */ + for (; line < line_count; line++) { - current_function_changed(NULL, -1, -1); - g_free(cur_tag); - cur_tag = g_strdup(_("unknown")); - if (tagname != NULL) - *tagname = cur_tag; - tag_line = -1; - return tag_line; + if (sci_get_fold_level(sci, line) & SC_FOLDLEVELHEADERFLAG) + return line; }
- line = sci_get_current_line(doc->editor->sci); - fold_level = sci_get_fold_level(doc->editor->sci, line); - /* check if the cached line and file index have changed since last time: */ - if (! current_function_changed(doc, line, fold_level)) - { - /* we can assume same current function as before */ - *tagname = cur_tag; - return tag_line; - } - g_free(cur_tag); /* free the old tag, it will be replaced. */ + return -1; +}
- /* if line is at base fold level, we're not in a function */ - if ((fold_level & SC_FOLDLEVELNUMBERMASK) == SC_FOLDLEVELBASE) - { - cur_tag = g_strdup(_("unknown")); - *tagname = cur_tag; - tag_line = -1; - return tag_line; - } - tm_file = doc->tm_file;
- /* if the tags are up-to-date, get the previous function name from TM */ - if (tm_file != NULL && tm_file->tags_array != NULL && +static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, guint tag_types) +{ + gint line; + gint parent; + + line = sci_get_current_line(doc->editor->sci); + parent = sci_get_fold_parent(doc->editor->sci, line); + /* if we're inside a fold level and we have up-to-date tags, get the function from TM */ + if (parent >= 0 && doc->tm_file != NULL && doc->tm_file->tags_array != NULL && (! doc->changed || editor_prefs.autocompletion_update_freq > 0)) { - const TMTag *tag = (const TMTag*) tm_get_current_function(tm_file->tags_array, line); + const TMTag *tag = tm_get_current_tag(doc->tm_file->tags_array, parent + 1, tag_types);
- if (tag != NULL) + if (tag) { - gchar *tmp; - tmp = tag->atts.entry.scope; - cur_tag = tmp ? g_strconcat(tmp, "::", tag->name, NULL) : g_strdup(tag->name); - *tagname = cur_tag; - tag_line = tag->atts.entry.line; - return tag_line; + gint tag_line = tag->atts.entry.line - 1; + gint last_child = line + 1; + + /* if it may be a false positive because we're inside a fold level not inside anything + * we match, e.g. a #if in C or C++, we check we're inside the fold level that start + * right after the tag we got from TM */ + if (abs(tag_line - parent) > 1) + { + gint tag_fold = get_fold_header_after(doc->editor->sci, tag_line); + if (tag_fold >= 0) + last_child = scintilla_send_message(doc->editor->sci, SCI_GETLASTCHILD, tag_fold, -1); + } + + if (line <= last_child) + { + if (tag->atts.entry.scope) + *tagname = g_strconcat(tag->atts.entry.scope, + symbols_get_context_separator(doc->file_type->id), tag->name, NULL); + else + *tagname = g_strdup(tag->name); + + return tag_line; + } } } - - /* parse the current function name here because TM line numbers may have changed, - * and it would take too long to reparse the whole file. */ - if (doc->file_type != NULL && doc->file_type->id != GEANY_FILETYPES_NONE) + /* for the poor guy with a modified document and without real time tag parsing, we fallback + * to dirty and inaccurate hand-parsing */ + else if (parent >= 0 && doc->file_type != NULL && doc->file_type->id != GEANY_FILETYPES_NONE) { const gint fn_fold = get_function_fold_number(doc); + gint tag_line = parent; + gint fold_level = sci_get_fold_level(doc->editor->sci, tag_line);
- tag_line = line; - do /* find the top level fold point */ + /* find the top level fold point */ + while (tag_line >= 0 && (fold_level & SC_FOLDLEVELNUMBERMASK) != fn_fold) { tag_line = sci_get_fold_parent(doc->editor->sci, tag_line); fold_level = sci_get_fold_level(doc->editor->sci, tag_line); - } while (tag_line >= 0 && - (fold_level & SC_FOLDLEVELNUMBERMASK) != fn_fold); + }
if (tag_line >= 0) { + gchar *cur_tag; + if (sci_get_lexer(doc->editor->sci) == SCLEX_CPP) cur_tag = parse_cpp_function_at_line(doc->editor->sci, tag_line); else @@ -2159,13 +2158,66 @@ gint symbols_get_current_function(GeanyDocument *doc, const gchar **tagname) } }
- cur_tag = g_strdup(_("unknown")); - *tagname = cur_tag; - tag_line = -1; + *tagname = g_strdup(_("unknown")); + return -1; +} + + +static gint get_current_tag_name_cached(GeanyDocument *doc, const gchar **tagname, guint tag_types) +{ + static gint tag_line = -1; + static gchar *cur_tag = NULL; + + if (doc == NULL) /* reset current function */ + { + current_tag_changed(NULL, -1, -1, 0); + g_free(cur_tag); + cur_tag = g_strdup(_("unknown")); + if (tagname != NULL) + *tagname = cur_tag; + tag_line = -1; + } + else + { + gint line = sci_get_current_line(doc->editor->sci); + gint fold_level = sci_get_fold_level(doc->editor->sci, line); + + if (current_tag_changed(doc, line, fold_level, tag_types)) + { + g_free(cur_tag); + tag_line = get_current_tag_name(doc, &cur_tag, tag_types); + } + *tagname = cur_tag; + } + return tag_line; }
+/* Sets *tagname to point at the current function or tag name. + * If doc is NULL, reset the cached current tag data to ensure it will be reparsed on the next + * call to this function. + * Returns: line number of the current tag, or -1 if unknown. */ +gint symbols_get_current_function(GeanyDocument *doc, const gchar **tagname) +{ + return get_current_tag_name_cached(doc, tagname, tm_tag_function_t | tm_tag_method_t); +} + + +/* same as symbols_get_current_function() but finds class, namespaces and more */ +gint symbols_get_current_scope(GeanyDocument *doc, const gchar **tagname) +{ + guint tag_types = (tm_tag_function_t | tm_tag_method_t | tm_tag_class_t | + tm_tag_struct_t | tm_tag_enum_t | tm_tag_union_t); + + /* Python parser reports imports as namespaces which confuses the scope detection */ + if (doc && doc->file_type->lang != filetypes[GEANY_FILETYPES_PYTHON]->lang) + tag_types |= tm_tag_namespace_t; + + return get_current_tag_name_cached(doc, tagname, tag_types); +} + + static void on_symbol_tree_sort_clicked(GtkMenuItem *menuitem, gpointer user_data) { gint sort_mode = GPOINTER_TO_INT(user_data);
Modified: src/symbols.h 2 files changed, 2 insertions(+), 0 deletions(-) =================================================================== @@ -61,4 +61,6 @@ enum
gint symbols_get_current_function(GeanyDocument *doc, const gchar **tagname);
+gint symbols_get_current_scope(GeanyDocument *doc, const gchar **tagname); + #endif
Modified: src/ui_utils.c 2 files changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -272,7 +272,7 @@ static void add_statusbar_statistics(GString *stats_str, g_string_append(stats_str, filetypes_get_display_name(doc->file_type)); break; case 'S': - symbols_get_current_function(doc, &cur_tag); + symbols_get_current_scope(doc, &cur_tag); g_string_append(stats_str, cur_tag); break; default:
Modified: tagmanager/src/tm_workspace.c 23 files changed, 15 insertions(+), 8 deletions(-) =================================================================== @@ -733,30 +733,37 @@ static gboolean match_langs(gint lang, const TMTag *tag)
const TMTag * -tm_get_current_function (GPtrArray * file_tags, const gulong line) +tm_get_current_tag (GPtrArray * file_tags, const gulong line, const guint tag_types) { - GPtrArray *const local = tm_tags_extract (file_tags, tm_tag_function_t | tm_tag_method_t); - TMTag *function_tag = NULL; + GPtrArray *const local = tm_tags_extract (file_tags, tag_types); + TMTag *matching_tag = NULL; if (local && local->len) { guint i; - gulong function_line = 0; + gulong matching_line = 0; glong delta;
for (i = 0; (i < local->len); ++i) { TMTag *tag = TM_TAG (local->pdata[i]); delta = line - tag->atts.entry.line; - if (delta >= 0 && (gulong)delta < line - function_line) + if (delta >= 0 && (gulong)delta < line - matching_line) { - function_tag = tag; - function_line = tag->atts.entry.line; + matching_tag = tag; + matching_line = tag->atts.entry.line; } } } if (local) g_ptr_array_free (local, TRUE); - return function_tag; + return matching_tag; +} + + +const TMTag * +tm_get_current_function (GPtrArray * file_tags, const gulong line) +{ + return tm_get_current_tag (file_tags, line, tm_tag_function_t | tm_tag_method_t); }
Modified: tagmanager/src/tm_workspace.h 7 files changed, 7 insertions(+), 0 deletions(-) =================================================================== @@ -152,6 +152,13 @@ const GPtrArray *tm_workspace_find_scope_members(const GPtrArray *file_tags, tm_workspace_find_namespace_members (const GPtrArray * file_tags, const char *name, gboolean search_global);
+/* Returns TMTag which "own" given line + \param line Current line in edited file. + \param file_tags A GPtrArray of edited file TMTag pointers. + \param tag_types the tag types to include in the match + \return TMTag pointers to owner tag. */ +const TMTag *tm_get_current_tag(GPtrArray *file_tags, const gulong line, const guint tag_types); + /* Returns TMTag to function or method which "own" given line \param line Current line in edited file. \param file_tags A GPtrArray of edited file TMTag pointers.
@@ Diff output truncated at 100000 characters. @@
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD).