Improve Goto Symbol popup contents
* always filter-out symbol from the current line from the list * when clicked on a symbol on the current line always swap definition/declaration search even if there are more symbols from the current search direction Fixes #950
This commit is contained in:
parent
7798a041b7
commit
65f84df5ca
132
src/symbols.c
132
src/symbols.c
@ -2071,102 +2071,114 @@ static TMTag *find_best_goto_tag(GeanyDocument *doc, GPtrArray *tags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static GPtrArray *filter_tags(GPtrArray *tags, TMTag *current_tag, gboolean definition)
|
||||||
|
{
|
||||||
|
const TMTagType forward_types = tm_tag_prototype_t | tm_tag_externvar_t;
|
||||||
|
TMTag *tmtag, *last_tag = NULL;
|
||||||
|
GPtrArray *filtered_tags = g_ptr_array_new();
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
foreach_ptr_array(tmtag, i, tags)
|
||||||
|
{
|
||||||
|
if (definition && !(tmtag->type & forward_types) ||
|
||||||
|
!definition && (tmtag->type & forward_types))
|
||||||
|
{
|
||||||
|
/* If there are typedefs of e.g. a struct such as
|
||||||
|
* "typedef struct Foo {} Foo;", filter out the typedef unless
|
||||||
|
* cursor is at the struct name. */
|
||||||
|
if (last_tag != NULL && last_tag->file == tmtag->file &&
|
||||||
|
last_tag->type != tm_tag_typedef_t && tmtag->type == tm_tag_typedef_t)
|
||||||
|
{
|
||||||
|
if (last_tag == current_tag)
|
||||||
|
g_ptr_array_add(filtered_tags, tmtag);
|
||||||
|
}
|
||||||
|
else if (tmtag != current_tag)
|
||||||
|
g_ptr_array_add(filtered_tags, tmtag);
|
||||||
|
|
||||||
|
last_tag = tmtag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered_tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean goto_tag(const gchar *name, gboolean definition)
|
static gboolean goto_tag(const gchar *name, gboolean definition)
|
||||||
{
|
{
|
||||||
const TMTagType forward_types = tm_tag_prototype_t | tm_tag_externvar_t;
|
const TMTagType forward_types = tm_tag_prototype_t | tm_tag_externvar_t;
|
||||||
TMTagType type;
|
TMTag *tmtag, *current_tag = NULL;
|
||||||
TMTag *tmtag, *last_tag;
|
|
||||||
GeanyDocument *old_doc = document_get_current();
|
GeanyDocument *old_doc = document_get_current();
|
||||||
gboolean found = FALSE;
|
gboolean found = FALSE;
|
||||||
const GPtrArray *all_tags;
|
const GPtrArray *all_tags;
|
||||||
GPtrArray *workspace_tags, *filtered_tags;
|
GPtrArray *tags, *filtered_tags;
|
||||||
guint i;
|
guint i;
|
||||||
guint current_line = sci_get_current_line(old_doc->editor->sci) + 1;
|
guint current_line = sci_get_current_line(old_doc->editor->sci) + 1;
|
||||||
|
|
||||||
/* goto tag definition: all except prototypes / forward declarations / externs */
|
all_tags = tm_workspace_find(name, NULL, tm_tag_max_t, NULL, old_doc->file_type->lang);
|
||||||
type = (definition) ? tm_tag_max_t - forward_types : forward_types;
|
|
||||||
all_tags = tm_workspace_find(name, NULL, type, NULL, old_doc->file_type->lang);
|
|
||||||
|
|
||||||
/* get rid of global tags */
|
/* get rid of global tags and find tag at current line */
|
||||||
workspace_tags = g_ptr_array_new();
|
tags = g_ptr_array_new();
|
||||||
foreach_ptr_array(tmtag, i, all_tags)
|
foreach_ptr_array(tmtag, i, all_tags)
|
||||||
{
|
{
|
||||||
if (tmtag->file)
|
if (tmtag->file)
|
||||||
g_ptr_array_add(workspace_tags, tmtag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there are typedefs of e.g. a struct such as "typedef struct Foo {} Foo;",
|
|
||||||
* keep just one of the names in the list - when the cursor is on the struct
|
|
||||||
* name, keep the typename, otherwise keep the struct name. */
|
|
||||||
last_tag = NULL;
|
|
||||||
filtered_tags = g_ptr_array_new();
|
|
||||||
foreach_ptr_array(tmtag, i, workspace_tags)
|
|
||||||
{
|
|
||||||
if (last_tag != NULL && last_tag->file == tmtag->file &&
|
|
||||||
last_tag->type != tm_tag_typedef_t && tmtag->type == tm_tag_typedef_t)
|
|
||||||
{
|
{
|
||||||
if (last_tag->line == current_line && filtered_tags->len > 0)
|
g_ptr_array_add(tags, tmtag);
|
||||||
/* if cursor on struct, replace struct with the typedef */
|
if (tmtag->file == old_doc->tm_file && tmtag->line == current_line)
|
||||||
filtered_tags->pdata[filtered_tags->len-1] = tmtag;
|
current_tag = tmtag;
|
||||||
/* if cursor anywhere else, use struct (already added) and discard typedef */
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
g_ptr_array_add(filtered_tags, tmtag);
|
|
||||||
|
|
||||||
last_tag = tmtag;
|
|
||||||
}
|
}
|
||||||
g_ptr_array_free(workspace_tags, TRUE);
|
|
||||||
workspace_tags = filtered_tags;
|
|
||||||
|
|
||||||
if (workspace_tags->len == 1)
|
if (current_tag)
|
||||||
|
/* swap definition/declaration search */
|
||||||
|
definition = current_tag->type & forward_types;
|
||||||
|
|
||||||
|
filtered_tags = filter_tags(tags, current_tag, definition);
|
||||||
|
if (current_tag && filtered_tags->len == 0)
|
||||||
|
{
|
||||||
|
/* if we previously swapped definition/declaration search and didn't
|
||||||
|
* find anything, try again with the opposite type */
|
||||||
|
g_ptr_array_free(filtered_tags, TRUE);
|
||||||
|
filtered_tags = filter_tags(tags, current_tag, !definition);
|
||||||
|
}
|
||||||
|
g_ptr_array_free(tags, TRUE);
|
||||||
|
tags = filtered_tags;
|
||||||
|
|
||||||
|
if (tags->len == 1)
|
||||||
{
|
{
|
||||||
GeanyDocument *new_doc;
|
GeanyDocument *new_doc;
|
||||||
|
|
||||||
tmtag = workspace_tags->pdata[0];
|
tmtag = tags->pdata[0];
|
||||||
new_doc = document_find_by_real_path(
|
new_doc = document_find_by_real_path(tmtag->file->file_name);
|
||||||
tmtag->file->file_name);
|
|
||||||
|
|
||||||
if (new_doc)
|
if (!new_doc)
|
||||||
{
|
|
||||||
/* If we are already on the tag line, swap definition/declaration */
|
|
||||||
if (new_doc == old_doc && tmtag->line == current_line)
|
|
||||||
{
|
|
||||||
if (goto_tag(name, !definition))
|
|
||||||
found = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* not found in opened document, should open */
|
/* not found in opened document, should open */
|
||||||
new_doc = document_open_file(tmtag->file->file_name, FALSE, NULL, NULL);
|
new_doc = document_open_file(tmtag->file->file_name, FALSE, NULL, NULL);
|
||||||
}
|
|
||||||
|
|
||||||
if (!found && navqueue_goto_line(old_doc, new_doc, tmtag->line))
|
navqueue_goto_line(old_doc, new_doc, tmtag->line);
|
||||||
found = TRUE;
|
|
||||||
}
|
}
|
||||||
else if (workspace_tags->len > 1)
|
else if (tags->len > 1)
|
||||||
{
|
{
|
||||||
GPtrArray *tags;
|
GPtrArray *tag_list;
|
||||||
TMTag *tag, *best_tag;
|
TMTag *tag, *best_tag;
|
||||||
|
|
||||||
g_ptr_array_sort(workspace_tags, compare_tags_by_name_line);
|
g_ptr_array_sort(tags, compare_tags_by_name_line);
|
||||||
best_tag = find_best_goto_tag(old_doc, workspace_tags);
|
best_tag = find_best_goto_tag(old_doc, tags);
|
||||||
|
|
||||||
tags = g_ptr_array_new();
|
tag_list = g_ptr_array_new();
|
||||||
if (best_tag)
|
if (best_tag)
|
||||||
g_ptr_array_add(tags, best_tag);
|
g_ptr_array_add(tag_list, best_tag);
|
||||||
foreach_ptr_array(tag, i, workspace_tags)
|
foreach_ptr_array(tag, i, tags)
|
||||||
{
|
{
|
||||||
if (tag != best_tag)
|
if (tag != best_tag)
|
||||||
g_ptr_array_add(tags, tag);
|
g_ptr_array_add(tag_list, tag);
|
||||||
}
|
}
|
||||||
show_goto_popup(old_doc, tags, best_tag != NULL);
|
show_goto_popup(old_doc, tag_list, best_tag != NULL);
|
||||||
|
|
||||||
g_ptr_array_free(tags, TRUE);
|
g_ptr_array_free(tag_list, TRUE);
|
||||||
found = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_ptr_array_free(workspace_tags, TRUE);
|
found = tags->len > 0;
|
||||||
|
g_ptr_array_free(tags, TRUE);
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user