From 59e27e4c37976075f2a2fd9bf5de076f01feabd5 Mon Sep 17 00:00:00 2001 From: frederik-labbe Date: Sun, 25 Dec 2016 04:14:41 -0500 Subject: [PATCH 1/7] Sync highlighted symbol with cursor position --- src/editor.c | 9 +++- src/symbols.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ src/symbols.h | 7 +++ src/ui_utils.c | 33 +++++++++++--- src/ui_utils.h | 2 + 5 files changed, 160 insertions(+), 6 deletions(-) diff --git a/src/editor.c b/src/editor.c index 3808d3fa3b..2ad7572976 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 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(tag_line, scope, cursor_line); #if 0 /** experimental code for inverting selections */ diff --git a/src/symbols.c b/src/symbols.c index 5ee8c85140..692f8a7e84 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -72,6 +72,14 @@ 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 */ + const gchar *tag_name; /* input: the tag name to validate (optional, set to NULL to skip) */ + 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 +2471,113 @@ gint symbols_get_current_scope(GeanyDocument *doc, const gchar **tagname) } +/* Gets selected symbol in TreeView. + * Helpful to check weither or not the selection must be updated. */ +#include "dialogs.h" +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; +} + + +/* *GtkTreeModelForeachFunc for finding a match in symbols panel according to a tag line and tag name*/ +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 matching line in tree view */ + if (ptr_user_data_query->tag_line == current_tag->line) + { + /* if tag name is not null, also validate it */ + if (!ptr_user_data_query->tag_name || g_strcmp0(ptr_user_data_query->tag_name, current_tag->name) == 0) + { + ptr_user_data_query->iter = *iter; + ptr_user_data_query->found = TRUE; + return TRUE; + } + } + } + + ptr_user_data_query->found = FALSE; + return FALSE; +} + + +/* Sets selection to a given tagname */ +gboolean symbols_select_tag(gint tag_line, const gchar *tag_name) { + GeanyDocument *doc = document_get_current(); + if (!doc) + return FALSE; + + TagQueryIterData query; + query.tag_line = tag_line; + query.tag_name = tag_name; + + 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; + } + + return FALSE; +} + + +/* Sets selection to the current prototype if detecting any. + * If no prototype is detected the selection is cleared. */ +gboolean symbols_select_symbol_at_cursor(gint cursor_line) +{ + GeanyDocument *doc = document_get_current(); + if (!doc) + return FALSE; + + TagQueryIterData query; + query.tag_line = cursor_line; + query.tag_name = NULL; + + 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; + } + + return FALSE; +} + + +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..e0056c4242 100644 --- a/src/symbols.h +++ b/src/symbols.h @@ -64,6 +64,13 @@ 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(gint tag_line, const gchar *tagname); + +gboolean symbols_select_symbol_at_cursor(gint cursor_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..6ff8cd930d 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,24 @@ void ui_update_fold_items(void) } +void ui_update_symbols_window_selection(gint tag_line, const gchar *tag_name, gint cursor_line) +{ + /* First try to find a symbol exactly at cursor line. */ + if (!symbols_select_symbol_at_cursor(cursor_line + 1)) + { + /* If not resolving the cursor line, maybe we are in scope of something. */ + if (tag_line != -1) + { + TMTag* selection_tag = symbols_get_current_selection_tag(); + if (!selection_tag || selection_tag->line != tag_line + 1) + symbols_select_tag(tag_line + 1, tag_name); + } + 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..806c3a3681 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 tag_line, const gchar *tag_name, gint cursor_line); void ui_create_insert_menu_items(void); From c872c5483a440775823e830e02215c9ab77e6a3e Mon Sep 17 00:00:00 2001 From: frederik-labbe Date: Sun, 25 Dec 2016 04:44:36 -0500 Subject: [PATCH 2/7] Fix broken indentation --- src/editor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editor.c b/src/editor.c index 2ad7572976..7589d07661 100644 --- a/src/editor.c +++ b/src/editor.c @@ -531,7 +531,7 @@ static void on_update_ui(GeanyEditor *editor, G_GNUC_UNUSED SCNotification *nt) ui_update_statusbar_with_scope(editor->document, pos, scope); /* update selection in symbols window */ - gint cursor_line = sci_get_current_line(sci); + gint cursor_line = sci_get_current_line(sci); ui_update_symbols_window_selection(tag_line, scope, cursor_line); #if 0 From dd4a46a106f53f5be8297629e20c49e0e86d5f11 Mon Sep 17 00:00:00 2001 From: frederik-labbe Date: Sun, 25 Dec 2016 05:08:32 -0500 Subject: [PATCH 3/7] Remove debug stuff --- src/symbols.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/symbols.c b/src/symbols.c index 692f8a7e84..5a46d7b0f6 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -2473,7 +2473,6 @@ gint symbols_get_current_scope(GeanyDocument *doc, const gchar **tagname) /* Gets selected symbol in TreeView. * Helpful to check weither or not the selection must be updated. */ -#include "dialogs.h" TMTag* symbols_get_current_selection_tag() { GeanyDocument *doc = document_get_current(); From cb9b8cb004eaed05a8f112f3199a8e0284831f73 Mon Sep 17 00:00:00 2001 From: frederik-labbe Date: Sun, 25 Dec 2016 07:04:20 -0500 Subject: [PATCH 4/7] Tag line all the way to be more flexible with OO languages --- src/editor.c | 4 ++-- src/symbols.c | 40 +++++----------------------------------- src/symbols.h | 4 +--- src/ui_utils.c | 10 +++++----- src/ui_utils.h | 2 +- 5 files changed, 14 insertions(+), 46 deletions(-) diff --git a/src/editor.c b/src/editor.c index 7589d07661..c9f373ec17 100644 --- a/src/editor.c +++ b/src/editor.c @@ -527,12 +527,12 @@ static void on_update_ui(GeanyEditor *editor, G_GNUC_UNUSED SCNotification *nt) /* update status bar */ const gchar *scope = NULL; - const gint tag_line = symbols_get_current_scope(editor->document, &scope); + 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(tag_line, scope, cursor_line); + 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 5a46d7b0f6..383b364c7a 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -75,7 +75,6 @@ typedef struct typedef struct { gint tag_line; /* input: the line to look for */ - const gchar *tag_name; /* input: the tag name to validate (optional, set to NULL to skip) */ GtkTreeIter iter; /* return: the iterator of the symmbol found */ gboolean found; /* return: wheither or not a symbol have been found */ } TagQueryIterData; @@ -2505,13 +2504,9 @@ gboolean search_tag_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *it /* look for matching line in tree view */ if (ptr_user_data_query->tag_line == current_tag->line) { - /* if tag name is not null, also validate it */ - if (!ptr_user_data_query->tag_name || g_strcmp0(ptr_user_data_query->tag_name, current_tag->name) == 0) - { - ptr_user_data_query->iter = *iter; - ptr_user_data_query->found = TRUE; - return TRUE; - } + ptr_user_data_query->iter = *iter; + ptr_user_data_query->found = TRUE; + return TRUE; } } @@ -2521,38 +2516,13 @@ gboolean search_tag_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *it /* Sets selection to a given tagname */ -gboolean symbols_select_tag(gint tag_line, const gchar *tag_name) { - GeanyDocument *doc = document_get_current(); - if (!doc) - return FALSE; - - TagQueryIterData query; - query.tag_line = tag_line; - query.tag_name = tag_name; - - 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; - } - - return FALSE; -} - - -/* Sets selection to the current prototype if detecting any. - * If no prototype is detected the selection is cleared. */ -gboolean symbols_select_symbol_at_cursor(gint cursor_line) -{ +gboolean symbols_select_tag_at_line(gint line) { GeanyDocument *doc = document_get_current(); if (!doc) return FALSE; TagQueryIterData query; - query.tag_line = cursor_line; - query.tag_name = NULL; + query.tag_line = line; gtk_tree_model_foreach(GTK_TREE_MODEL(doc->priv->tag_store), search_tag_func, (gpointer) &query); if (query.found) diff --git a/src/symbols.h b/src/symbols.h index e0056c4242..2401c6de95 100644 --- a/src/symbols.h +++ b/src/symbols.h @@ -66,9 +66,7 @@ gint symbols_get_current_scope(GeanyDocument *doc, const gchar **tagname); TMTag* symbols_get_current_selection_tag(); -gboolean symbols_select_tag(gint tag_line, const gchar *tagname); - -gboolean symbols_select_symbol_at_cursor(gint cursor_line); +gboolean symbols_select_tag_at_line(gint line); void symbols_clear_selection(); #endif /* GEANY_PRIVATE */ diff --git a/src/ui_utils.c b/src/ui_utils.c index 6ff8cd930d..4efb53d216 100644 --- a/src/ui_utils.c +++ b/src/ui_utils.c @@ -567,17 +567,17 @@ void ui_update_fold_items(void) } -void ui_update_symbols_window_selection(gint tag_line, const gchar *tag_name, gint 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_symbol_at_cursor(cursor_line + 1)) + if (!symbols_select_tag_at_line(cursor_line + 1)) { /* If not resolving the cursor line, maybe we are in scope of something. */ - if (tag_line != -1) + if (scope_tag_line != -1) { TMTag* selection_tag = symbols_get_current_selection_tag(); - if (!selection_tag || selection_tag->line != tag_line + 1) - symbols_select_tag(tag_line + 1, tag_name); + if (!selection_tag || selection_tag->line != scope_tag_line + 1) + symbols_select_tag_at_line(scope_tag_line + 1); } else symbols_clear_selection(); diff --git a/src/ui_utils.h b/src/ui_utils.h index 806c3a3681..50624ebf92 100644 --- a/src/ui_utils.h +++ b/src/ui_utils.h @@ -304,7 +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 tag_line, const gchar *tag_name, gint cursor_line); +void ui_update_symbols_window_selection(gint scope_tag_line, gint cursor_line); void ui_create_insert_menu_items(void); From 2d9d199132ade4206c8cd965b9d4ecf66c626a2c Mon Sep 17 00:00:00 2001 From: frederik-labbe Date: Sun, 25 Dec 2016 07:08:05 -0500 Subject: [PATCH 5/7] Fix indentation --- src/symbols.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/symbols.c b/src/symbols.c index 383b364c7a..9946bd859c 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -2504,9 +2504,9 @@ gboolean search_tag_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *it /* look for 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->iter = *iter; + ptr_user_data_query->found = TRUE; + return TRUE; } } From 6c6f8aa6348d91da7ed248c31c3ac97110983dc3 Mon Sep 17 00:00:00 2001 From: frederik-labbe Date: Sun, 25 Dec 2016 07:26:51 -0500 Subject: [PATCH 6/7] Fix incoherent comments and prevent edge case scenario when a scope cannot be found in tree view --- src/symbols.c | 15 +++++++++++---- src/ui_utils.c | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/symbols.c b/src/symbols.c index 9946bd859c..ed0263d8ef 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -2471,7 +2471,7 @@ gint symbols_get_current_scope(GeanyDocument *doc, const gchar **tagname) /* Gets selected symbol in TreeView. - * Helpful to check weither or not the selection must be updated. */ + * Helpful to check whether or not the selection must be updated. */ TMTag* symbols_get_current_selection_tag() { GeanyDocument *doc = document_get_current(); @@ -2491,7 +2491,8 @@ TMTag* symbols_get_current_selection_tag() } -/* *GtkTreeModelForeachFunc for finding a match in symbols panel according to a tag line and tag name*/ +/* 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; @@ -2501,7 +2502,7 @@ gboolean search_tag_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *it if (current_tag) { - /* look for matching line in tree view */ + /* Look for a matching line in tree view */ if (ptr_user_data_query->tag_line == current_tag->line) { ptr_user_data_query->iter = *iter; @@ -2515,7 +2516,8 @@ gboolean search_tag_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *it } -/* Sets selection to a given tagname */ +/* 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) @@ -2531,11 +2533,16 @@ gboolean symbols_select_tag_at_line(gint line) { 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(); diff --git a/src/ui_utils.c b/src/ui_utils.c index 4efb53d216..cc0ed25c7d 100644 --- a/src/ui_utils.c +++ b/src/ui_utils.c @@ -567,6 +567,7 @@ 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. */ From bca44336f60815c743b635cdf88748e5481e1ac4 Mon Sep 17 00:00:00 2001 From: frederik-labbe Date: Sun, 25 Dec 2016 07:35:14 -0500 Subject: [PATCH 7/7] Coding convention --- src/symbols.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/symbols.c b/src/symbols.c index ed0263d8ef..c3467d0b01 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -2518,7 +2518,8 @@ gboolean search_tag_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *it /* 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) { +gboolean symbols_select_tag_at_line(gint line) +{ GeanyDocument *doc = document_get_current(); if (!doc) return FALSE; @@ -2534,9 +2535,7 @@ gboolean symbols_select_tag_at_line(gint line) { return TRUE; } else - { symbols_clear_selection(); - } return FALSE; }