Skip to content
Browse files

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.
  • Loading branch information...
1 parent 9d2dab8 commit 491a45f614bc1c4633168e97a06734eff6886601 @b4n b4n committed Sep 17, 2012
Showing with 101 additions and 63 deletions.
  1. +101 −63 src/symbols.c
View
164 src/symbols.c
@@ -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);

0 comments on commit 491a45f

Please sign in to comment.
Something went wrong with that request. Please try again.