Merge symbol-tree branch:

Apply patch (with some reworking) from Conrad Steenberg
(gnocci-man) to show methods as children of classes in the symbol
list, and for other tag types to group children by their parents
(thanks; #2083110).
This works for any filetype that TagManager can parse tag scopes
for.
Fix not allowing a leading underscore when using scope name prefix.
Fix symbol-tree branch bug: missing C++ constructor declaration
tags.
- Code changes:
Use TMTag instead of GeanySymbol so the symbol tree can read the
scope without parsing it.
Free tag list straight after use, instead of next time the list is
generated.
Use TMTag pointer tree model column instead of line number.



git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@3197 ea778897-0a13-0410-b9d1-a72fbfd435f5
This commit is contained in:
Nick Treleaven 2008-11-10 16:57:18 +00:00
commit 1f6a611580
6 changed files with 437 additions and 210 deletions

View File

@ -1,9 +1,31 @@
2008-11-10 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
* src/about.c, src/treeviews.c, src/treeviews.h, src/symbols.c,
THANKS:
Merge symbol-tree branch:
Apply patch (with some reworking) from Conrad Steenberg
(gnocci-man) to show methods as children of classes in the symbol
list, and for other tag types to group children by their parents
(thanks; #2083110).
This works for any filetype that TagManager can parse tag scopes
for.
Fix not allowing a leading underscore when using scope name prefix.
Fix symbol-tree branch bug: missing C++ constructor declaration
tags.
- Code changes:
Use TMTag instead of GeanySymbol so the symbol tree can read the
scope without parsing it.
Free tag list straight after use, instead of next time the list is
generated.
Use TMTag pointer tree model column instead of line number.
2008-11-08 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com> 2008-11-08 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
* src/editor.c, doc/geany.txt, doc/geany.html: * src/editor.c, doc/geany.txt, doc/geany.html:
Make Ctrl-click go to matching brace if there's no current word. Make Ctrl-click go to matching brace if there's no current word.
* plugins/vcdiff.c, src/editor.c, src/plugindata.h, src/plugins.c: * plugins/vcdiff.c, src/editor.c, src/plugindata.h, src/plugins.c:
Make Version Diff plugin set the indent type for diffs based on the Make Version Diff plugin set the indent type for diffs based on the
current file's indent type. current file's indent type.
Add editor_set_indent_type() to the API. Add editor_set_indent_type() to the API.
Note: uses editor.h plugindata.h include. Note: uses editor.h plugindata.h include.

1
THANKS
View File

@ -51,6 +51,7 @@ Jason Oster <parasytic(at)users(dot)sourceforge(dot)net> - various patches
Andrew Rowland <weibullguy(at)charter(dot)net> - R filetype patch Andrew Rowland <weibullguy(at)charter(dot)net> - R filetype patch
Bronisław Białek <after89(at)gmail(dot)com> - CSS parser update Bronisław Białek <after89(at)gmail(dot)com> - CSS parser update
Roland Baudin <roland(dot)baudin(at)thalesaleniaspace(dot)com> - Matlab filetype patch Roland Baudin <roland(dot)baudin(at)thalesaleniaspace(dot)com> - Matlab filetype patch
Conrad Steenberg <gnocci-man(at)users(dot)sourceforge(dot)net> - symbol tree patch
Translators: Translators:
------------ ------------

View File

@ -79,7 +79,7 @@ static const gint prev_translators_len = G_N_ELEMENTS(prev_translators);
static const gchar *contributors = static const gchar *contributors =
"Alexander Rodin, Andrew Rowland, Anh Phạm, blackdog, Bo Lorentsen, Bob Doan, Bronisław Białek, Catalin Marinas, " "Alexander Rodin, Andrew Rowland, Anh Phạm, blackdog, Bo Lorentsen, Bob Doan, Bronisław Białek, Catalin Marinas, "
"Christoph Berg, Daniel Richard G., Dave Moore, Dirk Weber, Felipe Pena, François Cami, " "Christoph Berg, Conrad Steenberg, Daniel Richard G., Dave Moore, Dirk Weber, Felipe Pena, François Cami, "
"Giuseppe Torelli, Guillaume Hoffmann, Jason Oster, Jean-François Wauthy, Jeff Pohlmeyer, " "Giuseppe Torelli, Guillaume Hoffmann, Jason Oster, Jean-François Wauthy, Jeff Pohlmeyer, "
"John Gabriele, Josef Whiter, Kevin Ellwood, Kristoffer A. Tjernås, Marko Peric, Matti Mårds, " "John Gabriele, Josef Whiter, Kevin Ellwood, Kristoffer A. Tjernås, Marko Peric, Matti Mårds, "
"Peter Strand, Pierre Joye, Rob van der Linde, Robert McGinley, S Jagannathan, Saleem Abdulrasool, " "Peter Strand, Pierre Joye, Rob van der Linde, Robert McGinley, S Jagannathan, Saleem Abdulrasool, "

View File

@ -22,9 +22,9 @@
*/ */
/* /*
* Tagmanager related convenience functions. * Symbol Tree and TagManager-related convenience functions.
* Tagmanager parses tags in the current documents, known as the workspace, plus global tags, * TagManager parses tags for each document, and also adds them to the workspace (session).
* which are lists of tags for each filetype. Global tags are loaded when a document with a * Global tags are lists of tags for each filetype, loaded when a document with a
* matching filetype is first loaded. * matching filetype is first loaded.
*/ */
@ -89,6 +89,8 @@ static TagFileInfo tag_file_info[GTF_MAX] =
static gchar *user_tags_dir; static gchar *user_tags_dir;
static GPtrArray *top_level_iter_names = NULL;
static void html_tags_loaded(void); static void html_tags_loaded(void);
static void load_user_tags(filetype_id ft_id); static void load_user_tags(filetype_id ft_id);
@ -370,113 +372,60 @@ void symbols_finalize(void)
} }
/* small struct to track tag name and type together */ /* sort by name, then line */
typedef struct GeanySymbol static gint compare_symbol(const TMTag *tag_a, const TMTag *tag_b)
{
gchar *str;
gint type;
gint line;
} GeanySymbol;
/* sort by name, line */
static gint compare_symbol(const GeanySymbol *a, const GeanySymbol *b)
{ {
gint ret; gint ret;
if (a == NULL || b == NULL) return 0; if (tag_a == NULL || tag_b == NULL)
return 0;
ret = strcmp(a->str, b->str); ret = strcmp(tag_a->name, tag_b->name);
if (ret == 0) if (ret == 0)
{ {
return a->line - b->line; return tag_a->atts.entry.line - tag_b->atts.entry.line;
} }
return ret; return ret;
} }
/* sort by line only */ /* sort by line only */
static gint compare_symbol_lines(const GeanySymbol *a, const GeanySymbol *b) static gint compare_symbol_lines(gconstpointer a, gconstpointer b)
{ {
if (a == NULL || b == NULL) return 0; const TMTag *tag_a = TM_TAG(a);
const TMTag *tag_b = TM_TAG(b);
return a->line - b->line; if (a == NULL || b == NULL)
return 0;
return tag_a->atts.entry.line - tag_b->atts.entry.line;
} }
static const GList *get_tag_list(GeanyDocument *doc, guint tag_types, gint sort_mode) static GList *get_tag_list(GeanyDocument *doc, guint tag_types)
{ {
static GList *tag_names = NULL; GList *tag_names = NULL;
TMTag *tag;
guint i;
if (doc != NULL && doc->tm_file && g_return_val_if_fail(doc, NULL);
doc->tm_file->tags_array)
{
TMTag *tag;
guint i;
GeanySymbol *symbol;
gboolean doc_is_utf8 = FALSE;
gchar *utf8_name;
const gchar *cosep =
symbols_get_context_separator(FILETYPE_ID(doc->file_type));
if (tag_names) if (!doc->tm_file || !doc->tm_file->tags_array)
{
GList *tmp;
for (tmp = tag_names; tmp; tmp = g_list_next(tmp))
{
g_free(((GeanySymbol*)tmp->data)->str);
g_free(tmp->data);
}
g_list_free(tag_names);
tag_names = NULL;
}
/* encodings_convert_to_utf8_from_charset() fails with charset "None", so skip conversion
* for None at this point completely */
if (utils_str_equal(doc->encoding, "UTF-8") ||
utils_str_equal(doc->encoding, "None"))
doc_is_utf8 = TRUE;
for (i = 0; i < (doc->tm_file)->tags_array->len; ++i)
{
tag = TM_TAG((doc->tm_file)->tags_array->pdata[i]);
if (tag == NULL)
return NULL;
if (tag->type & tag_types)
{
if (! doc_is_utf8) utf8_name = encodings_convert_to_utf8_from_charset(tag->name,
(gsize)-1, doc->encoding, TRUE);
else utf8_name = tag->name;
if (utf8_name == NULL)
continue;
symbol = g_new0(GeanySymbol, 1);
if ((tag->atts.entry.scope != NULL) && isalpha(tag->atts.entry.scope[0]))
{
symbol->str = g_strconcat(tag->atts.entry.scope, cosep, utf8_name, NULL);
}
else
{
symbol->str = g_strdup(utf8_name);
}
symbol->type = tag->type;
symbol->line = tag->atts.entry.line;
tag_names = g_list_prepend(tag_names, symbol);
if (! doc_is_utf8) g_free(utf8_name);
}
}
if (sort_mode == SYMBOLS_SORT_BY_NAME)
tag_names = g_list_sort(tag_names, (GCompareFunc) compare_symbol);
else
tag_names = g_list_sort(tag_names, (GCompareFunc) compare_symbol_lines);
return tag_names;
}
else
return NULL; return NULL;
for (i = 0; i < doc->tm_file->tags_array->len; ++i)
{
tag = TM_TAG(doc->tm_file->tags_array->pdata[i]);
if (tag == NULL)
return NULL;
if (tag->type & tag_types)
{
tag_names = g_list_append(tag_names, tag);
}
}
tag_names = g_list_sort(tag_names, compare_symbol_lines);
return tag_names;
} }
@ -513,13 +462,8 @@ static void init_tag_iters(void)
} }
/* Adds symbol list groups in (iter*, title) pairs. static GdkPixbuf *get_tag_icon(const gchar *icon_name)
* The list must be ended with NULL. */
static void G_GNUC_NULL_TERMINATED
tag_list_add_groups(GtkTreeStore *tree_store, ...)
{ {
va_list args;
GtkTreeIter *iter;
static GtkIconTheme *icon_theme = NULL; static GtkIconTheme *icon_theme = NULL;
static gint x, y; static gint x, y;
@ -537,6 +481,19 @@ tag_list_add_groups(GtkTreeStore *tree_store, ...)
g_free(path); g_free(path);
#endif #endif
} }
return gtk_icon_theme_load_icon(icon_theme, icon_name, x, 0, NULL);
}
/* Adds symbol list groups in (iter*, title) pairs.
* The list must be ended with NULL. */
static void G_GNUC_NULL_TERMINATED
tag_list_add_groups(GtkTreeStore *tree_store, ...)
{
va_list args;
GtkTreeIter *iter;
g_return_if_fail(top_level_iter_names);
va_start(args, tree_store); va_start(args, tree_store);
for (; iter = va_arg(args, GtkTreeIter*), iter != NULL;) for (; iter = va_arg(args, GtkTreeIter*), iter != NULL;)
@ -547,30 +504,35 @@ tag_list_add_groups(GtkTreeStore *tree_store, ...)
if (icon_name) if (icon_name)
{ {
icon = gtk_icon_theme_load_icon(icon_theme, icon_name, x, 0, NULL); icon = get_tag_icon(icon_name);
} }
g_assert(title != NULL); g_assert(title != NULL);
g_ptr_array_add(top_level_iter_names, title);
gtk_tree_store_append(tree_store, iter, NULL); gtk_tree_store_append(tree_store, iter, NULL);
if (G_IS_OBJECT(icon)) if (G_IS_OBJECT(icon))
{ {
gtk_tree_store_set(tree_store, iter, SYMBOLS_COLUMN_ICON, icon, gtk_tree_store_set(tree_store, iter, SYMBOLS_COLUMN_ICON, icon, -1);
SYMBOLS_COLUMN_NAME, title, -1);
g_object_unref(icon); g_object_unref(icon);
} }
else gtk_tree_store_set(tree_store, iter, SYMBOLS_COLUMN_NAME, title, -1);
gtk_tree_store_set(tree_store, iter, SYMBOLS_COLUMN_NAME, title, -1);
} }
va_end(args); va_end(args);
} }
static void init_tag_list(GeanyDocument *doc) static void add_top_level_items(GeanyDocument *doc)
{ {
filetype_id ft_id = doc->file_type->id; filetype_id ft_id = doc->file_type->id;
GtkTreeStore *tag_store = doc->priv->tag_store; GtkTreeStore *tag_store = doc->priv->tag_store;
if (top_level_iter_names == NULL)
top_level_iter_names = g_ptr_array_new();
else
g_ptr_array_set_size(top_level_iter_names, 0);
init_tag_iters(); init_tag_iters();
switch (ft_id) switch (ft_id)
@ -857,25 +819,340 @@ static void hide_empty_rows(GtkTreeStore *store)
} }
static const gchar *get_symbol_name(GeanyDocument *doc, const TMTag *tag,
gboolean found_parent)
{
gchar *utf8_name;
const gchar *scope = tag->atts.entry.scope;
static GString *buffer = NULL; /* buffer will be small so we can keep it for reuse */
gboolean doc_is_utf8 = FALSE;
/* encodings_convert_to_utf8_from_charset() fails with charset "None", so skip conversion
* for None at this point completely */
if (utils_str_equal(doc->encoding, "UTF-8") ||
utils_str_equal(doc->encoding, "None"))
doc_is_utf8 = TRUE;
if (! doc_is_utf8)
utf8_name = encodings_convert_to_utf8_from_charset(tag->name,
(gsize)-1, doc->encoding, TRUE);
else
utf8_name = tag->name;
if (utf8_name == NULL)
return NULL;
if (!buffer)
buffer = g_string_new(NULL);
else
g_string_truncate(buffer, 0);
/* check first char of scope is a wordchar */
if (!found_parent && scope &&
strpbrk(scope, GEANY_WORDCHARS) == scope)
{
const gchar *sep = symbols_get_context_separator(FILETYPE_ID(doc->file_type));
g_string_append(buffer, scope);
g_string_append(buffer, sep);
}
g_string_append(buffer, utf8_name);
if (! doc_is_utf8)
g_free(utf8_name);
g_string_append_printf(buffer, " [%lu]", tag->atts.entry.line);
return buffer->str;
}
/* find the last word in "foo::bar::blah", e.g. "blah" */
const gchar *get_parent_name(const TMTag *tag, filetype_id ft_id)
{
const gchar *scope = tag->atts.entry.scope;
const gchar *separator = symbols_get_context_separator(ft_id);
const gchar *str, *ptr;
if (!scope)
return NULL;
str = scope;
while (1)
{
ptr = strstr(str, separator);
if (ptr)
{
str = ptr + strlen(separator);
}
else
break;
}
return NZV(str) ? str : NULL;
}
static GtkTreeIter *get_tag_type_iter(TMTagType tag_type, filetype_id ft_id)
{
GtkTreeIter *iter = NULL;
switch (tag_type)
{
case tm_tag_prototype_t:
case tm_tag_method_t:
case tm_tag_function_t:
{
iter = &tv_iters.tag_function;
break;
}
case tm_tag_macro_t:
case tm_tag_macro_with_arg_t:
{
iter = &tv_iters.tag_macro;
break;
}
case tm_tag_class_t:
{
iter = &tv_iters.tag_class;
break;
}
case tm_tag_member_t:
case tm_tag_field_t:
{
iter = &tv_iters.tag_member;
break;
}
case tm_tag_typedef_t:
case tm_tag_enum_t:
{
/* TODO separate C-like types here also */
if (ft_id == GEANY_FILETYPES_HAXE)
{
iter = &tv_iters.tag_type;
break;
}
/* fall through */
}
case tm_tag_union_t:
case tm_tag_struct_t:
case tm_tag_interface_t:
{
iter = &tv_iters.tag_struct;
break;
}
case tm_tag_variable_t:
{
iter = &tv_iters.tag_variable;
break;
}
case tm_tag_namespace_t:
case tm_tag_package_t:
{
iter = &tv_iters.tag_namespace;
break;
}
default:
{
iter = &tv_iters.tag_other;
}
}
if (iter->stamp != -1)
return iter;
else
return NULL;
}
static void add_tree_tag(GeanyDocument *doc, const TMTag *tag, GHashTable *parent_hash)
{
filetype_id ft_id = FILETYPE_ID(doc->file_type);
GtkTreeStore *tree_store = doc->priv->tag_store;
GtkTreeIter *parent = NULL;
parent = get_tag_type_iter(tag->type, ft_id);
if (parent)
{
const gchar *name;
const gchar *parent_name = get_parent_name(tag, ft_id);
GtkTreeIter iter;
GtkTreeIter *icon_iter = NULL, *child = NULL;
GdkPixbuf *icon = NULL;
child = &iter;
icon_iter = (parent != &tv_iters.tag_other) ? parent : &tv_iters.tag_variable;
gtk_tree_model_get(GTK_TREE_MODEL(tree_store), icon_iter,
SYMBOLS_COLUMN_ICON, &icon, -1);
if (parent_name)
{
GtkTreeIter *parent_search =
(GtkTreeIter *)g_hash_table_lookup(parent_hash, parent_name);
if (parent_search)
parent = parent_search;
else
parent_name = NULL;
}
/* check if the current tag is a parent of other tags */
if (g_hash_table_lookup_extended(parent_hash, tag->name, NULL, NULL) &&
!utils_str_equal(tag->name, parent_name)) /* prevent Foo::Foo from making parent = child */
{
GtkTreeIter *new_iter = g_new0(GtkTreeIter, 1);
/* set an iter value for the hash key */
g_hash_table_insert(parent_hash, tag->name, new_iter);
/* instead of ignoring the appended child iter below, use the one in the hash table */
child = new_iter;
}
gtk_tree_store_append(tree_store, child, parent);
name = get_symbol_name(doc, tag, (parent_name != NULL));
gtk_tree_store_set(tree_store, child,
SYMBOLS_COLUMN_ICON, icon,
SYMBOLS_COLUMN_NAME, name,
SYMBOLS_COLUMN_TAG, tag, -1);
if (G_LIKELY(G_IS_OBJECT(icon)))
g_object_unref(icon);
}
else
geany_debug("Missing symbol-tree parent iter for type %d!", tag->type);
}
static void add_tree_tags(GeanyDocument *doc, const GList *tags)
{
const GList *item;
GHashTable *parent_hash;
/* Create a hash table "parent_tag_name":(GtkTreeIter*) */
parent_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
/* find and store all parent names in the hash table */
for (item = tags; item; item = g_list_next(item))
{
const TMTag *tag = item->data;
const gchar *name = get_parent_name(tag, FILETYPE_ID(doc->file_type));
if (name)
g_hash_table_insert(parent_hash, (gpointer)name, NULL);
}
for (item = tags; item; item = g_list_next(item))
{
const TMTag *tag = item->data;
add_tree_tag(doc, tag, parent_hash);
}
g_hash_table_destroy(parent_hash);
}
/* @param item Must be a (gpointer*) for implementation reasons.
* @example gchar *name = *item; (for when the GPtrArray contains char pointers). */
#define foreach_ptr_array(item, ptr_array) \
for (item = ptr_array->pdata; item < &ptr_array->pdata[ptr_array->len]; item++)
/* we don't want to sort 1st-level nodes, but we can't return 0 because the tree sort
* is not stable, so the order is already lost. */
static gint compare_top_level_names(const gchar *a, const gchar *b)
{
gpointer *item;
foreach_ptr_array(item, top_level_iter_names)
{
const gchar *name = *item;
if (utils_str_equal(name, a))
return -1;
if (utils_str_equal(name, b))
return 1;
}
g_warning("Couldn't find top level node '%s' or '%s'!", a, b);
return 0;
}
static gboolean tag_has_missing_parent(const TMTag *tag, GtkTreeStore *store,
GtkTreeIter *iter)
{
/* if the tag has a parent tag, it should be at depth >= 2 */
return NZV(tag->atts.entry.scope) &&
gtk_tree_store_iter_depth(store, iter) == 1;
}
static gint tree_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
gpointer user_data)
{
gboolean sort_by_name = GPOINTER_TO_INT(user_data);
const TMTag *tag_a, *tag_b;
gtk_tree_model_get(model, a, SYMBOLS_COLUMN_TAG, &tag_a, -1);
gtk_tree_model_get(model, b, SYMBOLS_COLUMN_TAG, &tag_b, -1);
/* Check if the iters can be sorted based on tag name and line, not tree item name.
* Sort by tree name if the scope was prepended, e.g. 'ScopeNameWithNoTag::TagName'. */
if (tag_a && !tag_has_missing_parent(tag_a, GTK_TREE_STORE(model), a) &&
tag_b && !tag_has_missing_parent(tag_b, GTK_TREE_STORE(model), b))
{
return sort_by_name ? compare_symbol(tag_a, tag_b) :
compare_symbol_lines(tag_a, tag_b);
}
else
{
gchar *astr, *bstr;
gint cmp;
gtk_tree_model_get(model, a, SYMBOLS_COLUMN_NAME, &astr, -1);
gtk_tree_model_get(model, b, SYMBOLS_COLUMN_NAME, &bstr, -1);
/* if a is toplevel, b must be also */
if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), a) == 0)
{
cmp = compare_top_level_names(astr, bstr);
}
else
{
cmp = strcmp(astr, bstr);
/* sort duplicate 'ScopeName::OverloadedTagName' items by line as well */
if (tag_a && tag_b)
if (!sort_by_name ||
(utils_str_equal(tag_a->name, tag_b->name) &&
utils_str_equal(tag_a->atts.entry.scope, tag_b->atts.entry.scope)))
cmp = compare_symbol_lines(tag_a, tag_b);
}
g_free(astr);
g_free(bstr);
return cmp;
}
}
static void sort_tree(GtkTreeStore *store, gboolean sort_by_name)
{
gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), 1, tree_sort_func,
GINT_TO_POINTER(sort_by_name), NULL);
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), 1, GTK_SORT_ASCENDING);
}
gboolean symbols_recreate_tag_list(GeanyDocument *doc, gint sort_mode) gboolean symbols_recreate_tag_list(GeanyDocument *doc, gint sort_mode)
{ {
GList *tmp; GList *tags;
const GList *tags;
GtkTreeIter iter;
static gint prev_sort_mode = SYMBOLS_SORT_BY_NAME; static gint prev_sort_mode = SYMBOLS_SORT_BY_NAME;
filetype_id ft_id;
g_return_val_if_fail(doc != NULL, FALSE); g_return_val_if_fail(doc != NULL, FALSE);
ft_id = FILETYPE_ID(doc->file_type); tags = get_tag_list(doc, tm_tag_max_t);
if (tags == NULL)
if (sort_mode == SYMBOLS_SORT_USE_PREVIOUS)
sort_mode = prev_sort_mode;
else
prev_sort_mode = sort_mode;
tags = get_tag_list(doc, tm_tag_max_t, sort_mode);
if (doc->tm_file == NULL || tags == NULL)
return FALSE; return FALSE;
/* Make sure the model stays with us after the tree view unrefs it */ /* Make sure the model stays with us after the tree view unrefs it */
@ -885,100 +1162,21 @@ gboolean symbols_recreate_tag_list(GeanyDocument *doc, gint sort_mode)
/* Clear all contents */ /* Clear all contents */
gtk_tree_store_clear(doc->priv->tag_store); gtk_tree_store_clear(doc->priv->tag_store);
init_tag_list(doc); /* add grandparent type iters */
for (tmp = (GList*)tags; tmp; tmp = g_list_next(tmp)) add_top_level_items(doc);
{
gchar buf[100];
const GeanySymbol *symbol = (GeanySymbol*)tmp->data;
GtkTreeIter *parent = NULL;
GdkPixbuf *icon = NULL;
g_snprintf(buf, sizeof(buf), "%s [%d]", symbol->str, symbol->line); add_tree_tags(doc, tags);
g_list_free(tags);
switch (symbol->type)
{
case tm_tag_prototype_t:
case tm_tag_method_t:
case tm_tag_function_t:
{
if (tv_iters.tag_function.stamp == -1) break;
parent = &(tv_iters.tag_function);
break;
}
case tm_tag_macro_t:
case tm_tag_macro_with_arg_t:
{
if (tv_iters.tag_macro.stamp == -1) break;
parent = &(tv_iters.tag_macro);
break;
}
case tm_tag_class_t:
{
if (tv_iters.tag_class.stamp == -1) break;
parent = &(tv_iters.tag_class);
break;
}
case tm_tag_member_t:
case tm_tag_field_t:
{
if (tv_iters.tag_member.stamp == -1) break;
parent = &(tv_iters.tag_member);
break;
}
case tm_tag_typedef_t:
case tm_tag_enum_t:
{
/** TODO separate C-like types here also */
if (ft_id == GEANY_FILETYPES_HAXE)
{
if (tv_iters.tag_type.stamp == -1) break;
parent = &(tv_iters.tag_type);
break;
}
}
case tm_tag_union_t:
case tm_tag_struct_t:
case tm_tag_interface_t:
{
if (tv_iters.tag_struct.stamp == -1) break;
parent = &(tv_iters.tag_struct);
break;
}
case tm_tag_variable_t:
{
if (tv_iters.tag_variable.stamp == -1) break;
parent = &(tv_iters.tag_variable);
break;
}
case tm_tag_namespace_t:
case tm_tag_package_t:
{
if (tv_iters.tag_namespace.stamp == -1) break;
parent = &(tv_iters.tag_namespace);
break;
}
default:
{
if (tv_iters.tag_other.stamp == -1) break;
parent = &(tv_iters.tag_other);
}
}
if (parent)
{
gtk_tree_model_get(GTK_TREE_MODEL(doc->priv->tag_store), parent,
SYMBOLS_COLUMN_ICON, &icon, -1);
gtk_tree_store_append(doc->priv->tag_store, &iter, parent);
gtk_tree_store_set(doc->priv->tag_store, &iter,
SYMBOLS_COLUMN_ICON, icon,
SYMBOLS_COLUMN_NAME, buf,
SYMBOLS_COLUMN_LINE, symbol->line, -1);
if (G_LIKELY(G_IS_OBJECT(icon)))
g_object_unref(icon);
}
}
hide_empty_rows(doc->priv->tag_store); hide_empty_rows(doc->priv->tag_store);
if (sort_mode == SYMBOLS_SORT_USE_PREVIOUS)
sort_mode = prev_sort_mode;
else
prev_sort_mode = sort_mode;
sort_tree(doc->priv->tag_store, sort_mode == SYMBOLS_SORT_BY_NAME);
/* Re-attach model to view */ /* Re-attach model to view */
gtk_tree_view_set_model(GTK_TREE_VIEW(doc->priv->tag_tree), gtk_tree_view_set_model(GTK_TREE_VIEW(doc->priv->tag_tree),
GTK_TREE_MODEL(doc->priv->tag_store)); GTK_TREE_MODEL(doc->priv->tag_store));

View File

@ -190,7 +190,7 @@ void treeviews_update_tag_list(GeanyDocument *doc, gboolean update)
if (doc->priv->tag_tree == NULL) if (doc->priv->tag_tree == NULL)
{ {
doc->priv->tag_store = gtk_tree_store_new( doc->priv->tag_store = gtk_tree_store_new(
SYMBOLS_N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT); SYMBOLS_N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
doc->priv->tag_tree = gtk_tree_view_new(); doc->priv->tag_tree = gtk_tree_view_new();
prepare_taglist(doc->priv->tag_tree, doc->priv->tag_store); prepare_taglist(doc->priv->tag_tree, doc->priv->tag_store);
gtk_widget_show(doc->priv->tag_tree); gtk_widget_show(doc->priv->tag_tree);
@ -640,7 +640,13 @@ static gboolean on_taglist_tree_selection_changed(GtkTreeSelection *selection)
if (gtk_tree_selection_get_selected(selection, &model, &iter)) if (gtk_tree_selection_get_selected(selection, &model, &iter))
{ {
gtk_tree_model_get(model, &iter, SYMBOLS_COLUMN_LINE, &line, -1); const TMTag *tag;
gtk_tree_model_get(model, &iter, SYMBOLS_COLUMN_TAG, &tag, -1);
if (!tag)
return FALSE;
line = tag->atts.entry.line;
if (line > 0) if (line > 0)
{ {
GeanyDocument *doc = document_get_current(); GeanyDocument *doc = document_get_current();

View File

@ -41,7 +41,7 @@ enum
{ {
SYMBOLS_COLUMN_ICON, SYMBOLS_COLUMN_ICON,
SYMBOLS_COLUMN_NAME, SYMBOLS_COLUMN_NAME,
SYMBOLS_COLUMN_LINE, SYMBOLS_COLUMN_TAG,
SYMBOLS_N_COLUMNS SYMBOLS_N_COLUMNS
}; };