Branch: refs/heads/master Author: Colomban Wendling ban@herbesfolles.org Committer: Colomban Wendling ban@herbesfolles.org Date: Mon, 17 Sep 2012 20:50:32 Commit: 491a45f614bc1c4633168e97a06734eff6886601 https://github.com/geany/geany/commit/491a45f614bc1c4633168e97a06734eff68866...
Log Message: ----------- Improve symbols_get_current_function() a lot and make it more flexible
Finding the current function now better handles the case the current line is after a function but outside its scope, and many other issues the scope reporting had.
Modified Paths: -------------- src/symbols.c
Modified: src/symbols.c 164 files changed, 101 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 + 1); + 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 - 1; - 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,52 @@ 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); +} + + static void on_symbol_tree_sort_clicked(GtkMenuItem *menuitem, gpointer user_data) { gint sort_mode = GPOINTER_TO_INT(user_data);
@@ Diff output truncated at 100000 characters. @@
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD).