diff --git a/src/editor.c b/src/editor.c index 3808d3fa3b..c9f373ec17 100644 --- a/src/editor.c +++ b/src/editor.c @@ -525,7 +525,14 @@ static void on_update_ui(GeanyEditor *editor, G_GNUC_UNUSED SCNotification *nt) /* brace highlighting */ editor_highlight_braces(editor, pos); - ui_update_statusbar(editor->document, pos); + /* update status bar */ + const gchar *scope = NULL; + const gint scope_tag_line = symbols_get_current_scope(editor->document, &scope); + ui_update_statusbar_with_scope(editor->document, pos, scope); + + /* update selection in symbols window */ + gint cursor_line = sci_get_current_line(sci); + ui_update_symbols_window_selection(scope_tag_line, cursor_line); #if 0 /** experimental code for inverting selections */ diff --git a/src/symbols.c b/src/symbols.c index 5ee8c85140..c3467d0b01 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -72,6 +72,13 @@ typedef struct gboolean lower /* input: search only for lines with lower number than @line */; } TreeSearchData; +typedef struct +{ + gint tag_line; /* input: the line to look for */ + GtkTreeIter iter; /* return: the iterator of the symmbol found */ + gboolean found; /* return: wheither or not a symbol have been found */ +} TagQueryIterData; + static GPtrArray *top_level_iter_names = NULL; @@ -2463,6 +2470,89 @@ gint symbols_get_current_scope(GeanyDocument *doc, const gchar **tagname) } +/* Gets selected symbol in TreeView. + * Helpful to check whether or not the selection must be updated. */ +TMTag* symbols_get_current_selection_tag() +{ + GeanyDocument *doc = document_get_current(); + if (!doc) + return NULL; + + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(doc->priv->tag_tree)); + GtkTreeModel *model = GTK_TREE_MODEL(doc->priv->tag_store); + GtkTreeIter iter; + + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return NULL; + + TMTag *selection_tag; + gtk_tree_model_get(model, &iter, SYMBOLS_COLUMN_TAG, &selection_tag, -1); + return selection_tag; +} + + +/* Function pointer of type GtkTreeModelForeachFunc. + * This function is called for each items of a tree model and will stop as soon as a match is found. */ +gboolean search_tag_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data_query) +{ + TagQueryIterData *ptr_user_data_query = (TagQueryIterData*) user_data_query; + + TMTag *current_tag; + gtk_tree_model_get(model, iter, SYMBOLS_COLUMN_TAG, ¤t_tag, -1); + + if (current_tag) + { + /* Look for a matching line in tree view */ + if (ptr_user_data_query->tag_line == current_tag->line) + { + ptr_user_data_query->iter = *iter; + ptr_user_data_query->found = TRUE; + return TRUE; + } + } + + ptr_user_data_query->found = FALSE; + return FALSE; +} + + +/* Search for a given tag line in tree model than sets the tree selection it. + * If not found, selection is cleared. */ +gboolean symbols_select_tag_at_line(gint line) +{ + GeanyDocument *doc = document_get_current(); + if (!doc) + return FALSE; + + TagQueryIterData query; + query.tag_line = line; + + gtk_tree_model_foreach(GTK_TREE_MODEL(doc->priv->tag_store), search_tag_func, (gpointer) &query); + if (query.found) + { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(doc->priv->tag_tree)); + gtk_tree_selection_select_iter(selection, &query.iter); + return TRUE; + } + else + symbols_clear_selection(); + + return FALSE; +} + + +/* Clear any selected items in tree selection */ +void symbols_clear_selection() +{ + GeanyDocument *doc = document_get_current(); + if (!doc) + return; + + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(doc->priv->tag_tree)); + gtk_tree_selection_unselect_all(selection); +} + + static void on_symbol_tree_sort_clicked(GtkMenuItem *menuitem, gpointer user_data) { gint sort_mode = GPOINTER_TO_INT(user_data); diff --git a/src/symbols.h b/src/symbols.h index c9e15fd7fd..2401c6de95 100644 --- a/src/symbols.h +++ b/src/symbols.h @@ -64,6 +64,11 @@ gint symbols_get_current_function(GeanyDocument *doc, const gchar **tagname); gint symbols_get_current_scope(GeanyDocument *doc, const gchar **tagname); +TMTag* symbols_get_current_selection_tag(); + +gboolean symbols_select_tag_at_line(gint line); + +void symbols_clear_selection(); #endif /* GEANY_PRIVATE */ G_END_DECLS diff --git a/src/ui_utils.c b/src/ui_utils.c index 702a3453ae..cc0ed25c7d 100644 --- a/src/ui_utils.c +++ b/src/ui_utils.c @@ -188,7 +188,7 @@ void ui_set_statusbar(gboolean log, const gchar *format, ...) /* note: some comments below are for translators */ static gchar *create_statusbar_statistics(GeanyDocument *doc, - guint line, guint vcol, guint pos) + guint line, guint vcol, guint pos, const gchar *scope) { const gchar *cur_tag; const gchar *fmt; @@ -297,8 +297,9 @@ static gchar *create_statusbar_statistics(GeanyDocument *doc, g_string_append(stats_str, filetypes_get_display_name(doc->file_type)); break; case 'S': - symbols_get_current_scope(doc, &cur_tag); - g_string_append(stats_str, cur_tag); + if (!scope) + symbols_get_current_scope(doc, &scope); + g_string_append(stats_str, scope); break; case 'Y': g_string_append_c(stats_str, ' '); @@ -321,9 +322,13 @@ static gchar *create_statusbar_statistics(GeanyDocument *doc, return g_string_free(stats_str, FALSE); } +/* updates the status bar, in case we don't already know the scope */ +void ui_update_statusbar(GeanyDocument *doc, gint pos) { + ui_update_statusbar_with_scope(doc, pos, NULL); +} /* updates the status bar document statistics */ -void ui_update_statusbar(GeanyDocument *doc, gint pos) +void ui_update_statusbar_with_scope(GeanyDocument *doc, gint pos, const gchar *scope) { g_return_if_fail(doc == NULL || doc->is_valid); @@ -351,7 +356,7 @@ void ui_update_statusbar(GeanyDocument *doc, gint pos) vcol = 0; vcol += sci_get_cursor_virtual_space(doc->editor->sci); - stats_str = create_statusbar_statistics(doc, line, vcol, pos); + stats_str = create_statusbar_statistics(doc, line, vcol, pos, scope); /* can be overridden by status messages */ set_statusbar(stats_str, TRUE); @@ -562,6 +567,25 @@ void ui_update_fold_items(void) } +/* Resolve the most accurate symbol of the cursor line */ +void ui_update_symbols_window_selection(gint scope_tag_line, gint cursor_line) +{ + /* First try to find a symbol exactly at cursor line. */ + if (!symbols_select_tag_at_line(cursor_line + 1)) + { + /* If not resolving the cursor line, maybe we are in scope of something. */ + if (scope_tag_line != -1) + { + TMTag* selection_tag = symbols_get_current_selection_tag(); + if (!selection_tag || selection_tag->line != scope_tag_line + 1) + symbols_select_tag_at_line(scope_tag_line + 1); + } + else + symbols_clear_selection(); + } +} + + /* @include include name or NULL for empty with cursor ready for typing it */ static void insert_include(GeanyDocument *doc, gint pos, const gchar *include) { diff --git a/src/ui_utils.h b/src/ui_utils.h index b260d0be37..50624ebf92 100644 --- a/src/ui_utils.h +++ b/src/ui_utils.h @@ -281,6 +281,7 @@ void ui_add_config_file_menu_item(const gchar *real_path, const gchar *label, void ui_update_statusbar(GeanyDocument *doc, gint pos); +void ui_update_statusbar_with_scope(GeanyDocument *doc, gint pos, const gchar *scope); /* This sets the window title according to the current filename. */ void ui_set_window_title(GeanyDocument *doc); @@ -303,6 +304,7 @@ void ui_update_insert_include_item(GeanyDocument *doc, gint item); void ui_update_fold_items(void); +void ui_update_symbols_window_selection(gint scope_tag_line, gint cursor_line); void ui_create_insert_menu_items(void);