Branch: refs/heads/master
Author: Jiří Techet <techet(a)gmail.com>
Committer: Jiří Techet <techet(a)gmail.com>
Date: Mon, 18 Jan 2016 21:56:10 UTC
Commit: 5b4c6f96b20cd309026e42c02133b28d1e0e64df
https://github.com/geany/geany/commit/5b4c6f96b20cd309026e42c02133b28d1e0e6…
Log Message:
-----------
Don't use anon_struct_* and similar members unless we are sure it's the right one
We can only be sure it's the right one if we previously resolved a
typedef to it and the typedef was in the same file.
Modified Paths:
--------------
tagmanager/src/tm_workspace.c
Modified: tagmanager/src/tm_workspace.c
7 lines changed, 6 insertions(+), 1 deletions(-)
===================================================================
@@ -805,6 +805,7 @@ find_scope_members (const GPtrArray *tags_array, const char *name, langType lang
gboolean namespace)
{
gboolean has_members = FALSE;
+ gboolean typedef_struct = FALSE;
GPtrArray *tags = NULL;
TMTag *tag = NULL;
const gchar *type_name;
@@ -839,6 +840,7 @@ find_scope_members (const GPtrArray *tags_array, const char *name, langType lang
* too many (wrong) results. */
fill_find_tags_array(type_tags, tag->file->tags_array, type_name,
NULL, types, FALSE, lang);
+ typedef_struct = type_tags->len > 0;
}
if (type_tags->len == 0)
fill_find_tags_array(type_tags, tags_array, type_name, NULL, types, FALSE, lang);
@@ -870,7 +872,10 @@ find_scope_members (const GPtrArray *tags_array, const char *name, langType lang
}
}
- if (has_members)
+ /* ignore anon_struct_* and similar unless we resolved a typedef to it within
+ * a single file so we can be sure we don't pick a wrong anon_struct_* from
+ * a different file */
+ if (has_members && (typedef_struct || !tm_tag_is_anon(tag)))
/* use the same file as the composite type if file information available */
tags = find_scope_members_tags(tag->file ? tag->file->tags_array : tags_array, tag, namespace);
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Jiří Techet <techet(a)gmail.com>
Committer: Jiří Techet <techet(a)gmail.com>
Date: Mon, 18 Jan 2016 21:55:02 UTC
Commit: 932dc71fe2edc0c58b15aface319d38855c5e612
https://github.com/geany/geany/commit/932dc71fe2edc0c58b15aface319d38855c5e…
Log Message:
-----------
Don't use struct/class/... member types when the edited text isn't a member
For instance, consider
class A {
int a;
int b;
}
class B {
A c;
void foo() {
c. //<---- (3)
}
}
int main() {
c. //<---- (1)
foo.c. //<---- (2)
}
Consider cases (1) and (2) first - in the case (1) scope completion
shouldn't be performed because c isn't a global variable; however,
in case (2) it should be performed because c is a member.
To fix this, we can check whether the typed variable ('c' in this case)
is preceeded by another dot - if it is, use member tags for scope
completion; otherwise don't use them.
There's one exception from this rule - in the case (3) we are accessing
a member variable from a member function at the same scope so the
function should have access to the variable. For this we can use the
scope at the position of the cursor. It should be
B::foo
in this case, more generally ...::class_name::function_name. We need
to check if class_name exists at the given scope and if the member
variable we are trying to access is inside ...::class_name - if so,
scope completion can be performed using member tags (without explicit
invocation on a member).
Modified Paths:
--------------
src/editor.c
tagmanager/src/tm_workspace.c
tagmanager/src/tm_workspace.h
Modified: src/editor.c
14 lines changed, 13 insertions(+), 1 deletions(-)
===================================================================
@@ -708,6 +708,8 @@ static void autocomplete_scope(GeanyEditor *editor)
GeanyFiletype *ft = editor->document->file_type;
GPtrArray *tags;
gboolean function = FALSE;
+ gboolean member;
+ const gchar *current_scope;
if (typed == '.')
pos -= 1;
@@ -751,7 +753,17 @@ static void autocomplete_scope(GeanyEditor *editor)
if (!name)
return;
- tags = tm_workspace_find_scope_members(editor->document->tm_file, name, function);
+ /* check if invoked on member */
+ pos -= strlen(name);
+ while (pos > 0 && isspace(sci_get_char_at(sci, pos - 1)))
+ pos--;
+ member = match_last_chars(sci, pos, ".") || match_last_chars(sci, pos, "::") ||
+ match_last_chars(sci, pos, "->") || match_last_chars(sci, pos, "->*");
+
+ if (symbols_get_current_scope(editor->document, ¤t_scope) == -1)
+ current_scope = "";
+ tags = tm_workspace_find_scope_members(editor->document->tm_file, name, function,
+ member, current_scope);
if (tags)
{
show_tags_list(editor, tags, 0);
Modified: tagmanager/src/tm_workspace.c
88 lines changed, 77 insertions(+), 11 deletions(-)
===================================================================
@@ -877,9 +877,60 @@ find_scope_members (const GPtrArray *tags_array, const char *name, langType lang
}
+/* Checks whether a member tag is directly accessible from method with method_scope */
+static gboolean member_at_method_scope(const GPtrArray *tags, const gchar *method_scope, TMTag *member_tag,
+ langType lang)
+{
+ const gchar *sep = tm_tag_context_separator(lang);
+ gboolean ret = FALSE;
+ gchar **comps;
+ guint len;
+
+ /* method scope is in the form ...::class_name::method_name */
+ comps = g_strsplit (method_scope, sep, 0);
+ len = g_strv_length(comps);
+ if (len > 1)
+ {
+ gchar *method, *member_scope, *cls, *cls_scope;
+
+ /* get method/member scope */
+ method = comps[len - 1];
+ comps[len - 1] = NULL;
+ member_scope = g_strjoinv(sep, comps);
+ comps[len - 1] = method;
+
+ /* get class scope */
+ cls = comps[len - 2];
+ comps[len - 2] = NULL;
+ cls_scope = g_strjoinv(sep, comps);
+ comps[len - 2] = cls;
+
+ /* check whether member inside the class */
+ if (g_strcmp0(member_tag->scope, member_scope) == 0)
+ {
+ const GPtrArray *src = member_tag->file ? member_tag->file->tags_array : tags;
+ GPtrArray *cls_tags = g_ptr_array_new();
+
+ /* check whether the class exists */
+ fill_find_tags_array(cls_tags, src, cls, cls_scope,
+ tm_tag_class_t | tm_tag_struct_t | tm_tag_interface_t, FALSE, lang);
+ ret = cls_tags->len > 0;
+ g_ptr_array_free(cls_tags, TRUE);
+ }
+
+ g_free(cls_scope);
+ g_free(member_scope);
+ }
+
+ g_strfreev(comps);
+ return ret;
+}
+
+
/* For an array of variable/type tags, find members inside the types */
static GPtrArray *
-find_scope_members_all(const GPtrArray *tags, const GPtrArray *searched_array, langType lang)
+find_scope_members_all(const GPtrArray *tags, const GPtrArray *searched_array, langType lang,
+ gboolean member, const gchar *current_scope)
{
GPtrArray *member_tags = NULL;
guint i;
@@ -896,13 +947,22 @@ find_scope_members_all(const GPtrArray *tags, const GPtrArray *searched_array, l
member_tags = find_scope_members(searched_array, tag->name, lang, TRUE);
else if (tag->var_type) /* variable: scope search */
{
- gchar *tag_type = g_strdup(tag->var_type);
+ /* The question now is whether we should use member tags (such as
+ * tm_tag_field_t, tm_tag_member_t) or not. We want them if member==TRUE
+ * (which means user has typed something like foo.bar.) or if we are
+ * inside a method where foo is a class member, we want scope completion
+ * for foo. */
+ if (!(tag->type & (tm_tag_field_t | tm_tag_member_t)) || member ||
+ member_at_method_scope(tags, current_scope, tag, lang))
+ {
+ gchar *tag_type = g_strdup(tag->var_type);
- /* remove pointers in case the type contains them */
- g_strdelimit(tag_type, "*^", ' ');
- g_strstrip(tag_type);
- member_tags = find_scope_members(searched_array, tag_type, lang, FALSE);
- g_free(tag_type);
+ /* remove pointers in case the type contains them */
+ g_strdelimit(tag_type, "*^", ' ');
+ g_strstrip(tag_type);
+ member_tags = find_scope_members(searched_array, tag_type, lang, FALSE);
+ g_free(tag_type);
+ }
}
}
@@ -915,9 +975,12 @@ find_scope_members_all(const GPtrArray *tags, const GPtrArray *searched_array, l
@param source_file TMSourceFile of the edited source file or NULL if not available
@param name Name of the variable/type whose members are searched
@param function TRUE if the name is a name of a function
+ @param member TRUE if invoked on class/struct member (e.g. after the last dot in foo.bar.)
+ @param current_scope The current scope in the editor
@return A GPtrArray of TMTag pointers to struct/union/class members or NULL when not found */
GPtrArray *
-tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name, gboolean function)
+tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name,
+ gboolean function, gboolean member, const gchar *current_scope)
{
langType lang = source_file ? source_file->lang : -1;
GPtrArray *tags, *member_tags = NULL;
@@ -936,11 +999,14 @@ tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name, gb
* end with global tags. This way we find the "closest" tag to the current
* file in case there are more of them. */
if (source_file)
- member_tags = find_scope_members_all(tags, source_file->tags_array, lang);
+ member_tags = find_scope_members_all(tags, source_file->tags_array,
+ lang, member, current_scope);
if (!member_tags)
- member_tags = find_scope_members_all(tags, theWorkspace->tags_array, lang);
+ member_tags = find_scope_members_all(tags, theWorkspace->tags_array, lang,
+ member, current_scope);
if (!member_tags)
- member_tags = find_scope_members_all(tags, theWorkspace->global_tags, lang);
+ member_tags = find_scope_members_all(tags, theWorkspace->global_tags, lang,
+ member, current_scope);
g_ptr_array_free(tags, TRUE);
Modified: tagmanager/src/tm_workspace.h
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -59,7 +59,7 @@ GPtrArray *tm_workspace_find(const char *name, const char *scope, TMTagType type
TMTagAttrType *attrs, gboolean partial, langType lang);
GPtrArray *tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name,
- gboolean function);
+ gboolean function, gboolean member, const gchar *current_scope);
void tm_workspace_add_source_file_noupdate(TMSourceFile *source_file);
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Jiří Techet <techet(a)gmail.com>
Committer: Jiří Techet <techet(a)gmail.com>
Date: Sun, 10 Jan 2016 11:33:40 UTC
Commit: 1281d0c942322d99da626ad00edd6077425f2c8d
https://github.com/geany/geany/commit/1281d0c942322d99da626ad00edd6077425f2…
Log Message:
-----------
Get members from the same file as the type/struct/union
Rethink how to extract members from the struct types. Inspired by
the patch using the same file as the typedef to search for structs,
we can do the same to extract the members only from the file
containing the struct and not the whole workspace. This makes
this operation fast enough so we don't have to keep the extracted
members in a special array (this will become especially useful
for namespace search because for it we would have to extract
all tags and then the extracted array would have the same
size as the workspace so we'd lose the performance gain).
Since the above works only for tags having the file information,
that is, not the global tags, we'll lose some performance
when searching the global tags. I think people don't create
the tag files for complete projects but rather for header files
which contain less tags and still the performance should be
better than before this patch set because we go through the
global tag list only once (was twice before).
On the way, clean up the source a bit, add more comments and move
some code from find_scope_members() to find_scope_members_tags().
Modified Paths:
--------------
tagmanager/src/tm_workspace.c
tagmanager/src/tm_workspace.h
Modified: tagmanager/src/tm_workspace.c
107 lines changed, 42 insertions(+), 65 deletions(-)
===================================================================
@@ -56,11 +56,6 @@ static TMTagAttrType global_tags_sort_attrs[] =
tm_tag_attr_type_t, tm_tag_attr_scope_t, tm_tag_attr_arglist_t, 0
};
-static TMTagType TM_MEMBER_TYPE_MASK =
- tm_tag_function_t | tm_tag_prototype_t |
- tm_tag_member_t | tm_tag_field_t |
- tm_tag_method_t;
-
static TMWorkspace *theWorkspace = NULL;
@@ -73,8 +68,6 @@ static gboolean tm_create_workspace(void)
theWorkspace->source_files = g_ptr_array_new();
theWorkspace->typename_array = g_ptr_array_new();
theWorkspace->global_typename_array = g_ptr_array_new();
- theWorkspace->member_array = g_ptr_array_new();
- theWorkspace->global_member_array = g_ptr_array_new();
return TRUE;
}
@@ -97,8 +90,6 @@ void tm_workspace_free(void)
g_ptr_array_free(theWorkspace->tags_array, TRUE);
g_ptr_array_free(theWorkspace->typename_array, TRUE);
g_ptr_array_free(theWorkspace->global_typename_array, TRUE);
- g_ptr_array_free(theWorkspace->member_array, TRUE);
- g_ptr_array_free(theWorkspace->global_member_array, TRUE);
g_free(theWorkspace);
theWorkspace = NULL;
}
@@ -150,7 +141,6 @@ static void update_source_file(TMSourceFile *source_file, guchar* text_buf,
* workspace while they exist and can be scanned */
tm_tags_remove_file_tags(source_file, theWorkspace->tags_array);
tm_tags_remove_file_tags(source_file, theWorkspace->typename_array);
- tm_tags_remove_file_tags(source_file, theWorkspace->member_array);
}
tm_source_file_parse(source_file, text_buf, buf_size, use_buffer);
tm_tags_sort(source_file->tags_array, file_tags_sort_attrs, FALSE, TRUE);
@@ -162,7 +152,6 @@ static void update_source_file(TMSourceFile *source_file, guchar* text_buf,
tm_workspace_merge_tags(&theWorkspace->tags_array, source_file->tags_array);
merge_extracted_tags(&(theWorkspace->typename_array), source_file->tags_array, TM_GLOBAL_TYPE_MASK);
- merge_extracted_tags(&(theWorkspace->member_array), source_file->tags_array, TM_MEMBER_TYPE_MASK);
}
#ifdef TM_DEBUG
else
@@ -232,7 +221,6 @@ void tm_workspace_remove_source_file(TMSourceFile *source_file)
{
tm_tags_remove_file_tags(source_file, theWorkspace->tags_array);
tm_tags_remove_file_tags(source_file, theWorkspace->typename_array);
- tm_tags_remove_file_tags(source_file, theWorkspace->member_array);
g_ptr_array_remove_index_fast(theWorkspace->source_files, i);
return;
}
@@ -281,7 +269,6 @@ static void tm_workspace_update(void)
g_ptr_array_free(theWorkspace->typename_array, TRUE);
theWorkspace->typename_array = tm_tags_extract(theWorkspace->tags_array, TM_GLOBAL_TYPE_MASK);
- theWorkspace->member_array = tm_tags_extract(theWorkspace->tags_array, TM_MEMBER_TYPE_MASK);
}
@@ -408,8 +395,6 @@ gboolean tm_workspace_load_global_tags(const char *tags_file, gint mode)
g_ptr_array_free(theWorkspace->global_typename_array, TRUE);
theWorkspace->global_typename_array = tm_tags_extract(new_tags, TM_GLOBAL_TYPE_MASK);
- g_ptr_array_free(theWorkspace->global_member_array, TRUE);
- theWorkspace->global_member_array = tm_tags_extract(new_tags, TM_MEMBER_TYPE_MASK);
return TRUE;
}
@@ -761,33 +746,38 @@ GPtrArray *tm_workspace_find(const char *name, const char *scope, TMTagType type
}
+/* Gets all members of type_tag; search them inside the all array */
static GPtrArray *
-find_scope_members_tags (const GPtrArray * all, const char *scope, langType lang,
- TMSourceFile *tag_file)
+find_scope_members_tags (const GPtrArray *all, TMTag *type_tag)
{
+ TMTagType member_types =
+ tm_tag_function_t | tm_tag_prototype_t |
+ tm_tag_member_t | tm_tag_field_t |
+ tm_tag_method_t;
GPtrArray *tags = g_ptr_array_new();
- TMSourceFile *last_file = tag_file;
+ gchar *scope;
guint i;
+ if (type_tag->scope && *(type_tag->scope))
+ scope = g_strconcat(type_tag->scope, tm_tag_context_separator(type_tag->lang), type_tag->name, NULL);
+ else
+ scope = g_strdup(type_tag->name);
+
for (i = 0; i < all->len; ++i)
{
TMTag *tag = TM_TAG (all->pdata[i]);
- if (tag && (tag->file == last_file || last_file == NULL) &&
+ if (tag && (tag->type & member_types) &&
tag->scope && tag->scope[0] != '\0' &&
- langs_compatible(tag->lang, lang) &&
+ langs_compatible(tag->lang, type_tag->lang) &&
strcmp(scope, tag->scope) == 0)
{
g_ptr_array_add (tags, tag);
- /* once set, always the same thanks to the if above
- * add only if it's from the same file - this prevents mixing tags from
- * structs with identical name (typically the anonymous ones) so we
- * only get members from a single one. For workspace tags it adds
- * all members because there's no file associated. */
- last_file = tag->file;
}
}
+ g_free(scope);
+
if (tags->len == 0)
{
g_ptr_array_free(tags, TRUE);
@@ -798,48 +788,48 @@ find_scope_members_tags (const GPtrArray * all, const char *scope, langType lang
}
+/* Gets all members of the type with the given name; search them inside tags_array */
static GPtrArray *
-find_scope_members (const GPtrArray *tags_array, GPtrArray *member_array,
- const char *name, langType lang)
+find_scope_members (const GPtrArray *tags_array, const char *name, langType lang)
{
- TMSourceFile *typedef_file = NULL;
gboolean has_members = FALSE;
GPtrArray *tags = NULL;
- gchar *type_name;
+ TMTag *tag = NULL;
+ const gchar *type_name;
guint i;
g_return_val_if_fail(name && *name, NULL);
- type_name = g_strdup(name);
+ type_name = name;
/* First check if type_name is a type that can possibly contain members.
* Try to resolve intermediate typedefs to get the real type name. Also
* add scope information to the name if applicable. The only result of this
- * part is the updated type_name and boolean has_members.
+ * part is the TMTag tag and boolean has_members.
* The loop below loops only when resolving typedefs - avoid possibly infinite
* loop when typedefs create a cycle by adding some limits. */
for (i = 0; i < 5; i++)
{
guint j;
- TMTag *tag = NULL;
GPtrArray *type_tags;
TMTagType types = (tm_tag_class_t | tm_tag_namespace_t |
tm_tag_struct_t | tm_tag_union_t | tm_tag_typedef_t);
type_tags = g_ptr_array_new();
- if (typedef_file)
+ if (tag && tag->file)
{
- /* If we have typedef_file, which is the file where the typedef was
- * defined, search in the file first. This helps for
+ /* If we have tag, it means it contains the typedef from the previous
+ * iteration; search in its file first. This helps for
* "typedef struct {...}" cases where the typedef resolves to
* anon_struct_* and searching for it in the whole workspace returns
* too many (wrong) results. */
- fill_find_tags_array(type_tags, typedef_file->tags_array, type_name,
+ fill_find_tags_array(type_tags, tag->file->tags_array, type_name,
NULL, types, FALSE, lang);
}
if (type_tags->len == 0)
fill_find_tags_array(type_tags, tags_array, type_name, NULL, types, FALSE, lang);
+ tag = NULL;
for (j = 0; j < type_tags->len; j++)
{
tag = TM_TAG(type_tags->pdata[j]);
@@ -856,37 +846,28 @@ find_scope_members (const GPtrArray *tags_array, GPtrArray *member_array,
/* intermediate typedef - resolve to the real type */
if (tag->type == tm_tag_typedef_t && tag->var_type && tag->var_type[0] != '\0')
{
- g_free(type_name);
- type_name = g_strdup(tag->var_type);
- typedef_file = tag->file;
+ type_name = tag->var_type;
continue;
}
else /* real type with members */
{
has_members = TRUE;
- if (tag->scope && *(tag->scope))
- {
- gchar *tmp_name = type_name;
-
- type_name = g_strconcat(tag->scope, tm_tag_context_separator(lang), type_name, NULL);
- g_free(tmp_name);
- }
break;
}
}
if (has_members)
- tags = find_scope_members_tags(member_array, type_name, lang, typedef_file);
-
- g_free(type_name);
+ /* use the same file as the composite type if file information available */
+ tags = find_scope_members_tags(tag->file ? tag->file->tags_array : tags_array, tag);
return tags;
}
+/* For an array of variable tags var_array, find members inside their types */
static GPtrArray *
find_scope_members_all(const GPtrArray *var_array, const GPtrArray *searched_array,
- GPtrArray *member_array, langType lang)
+ langType lang)
{
GPtrArray *member_tags = NULL;
guint i;
@@ -899,8 +880,7 @@ find_scope_members_all(const GPtrArray *var_array, const GPtrArray *searched_arr
if (tag->var_type)
{
- member_tags = find_scope_members(searched_array, member_array,
- tag->var_type, lang);
+ member_tags = find_scope_members(searched_array, tag->var_type, lang);
if (member_tags)
break;
}
@@ -910,7 +890,8 @@ find_scope_members_all(const GPtrArray *var_array, const GPtrArray *searched_arr
}
-/* Returns all matching members tags found in given struct/union/class name.
+/* Returns all member tags of a struct/union/class if the provided variable name is of such
+ a type.
@param source_file TMSourceFile of the edited source file or NULL if not available
@param name Name of the variable whose members are searched
@return A GPtrArray of TMTag pointers to struct/union/class members or NULL when not found */
@@ -920,22 +901,18 @@ tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name)
langType lang = source_file ? source_file->lang : -1;
GPtrArray *tags, *member_tags = NULL;
+ /* tags corresponding to the variable name */
tags = tm_workspace_find(name, NULL, tm_tag_max_t, NULL, FALSE, lang);
+ /* Start searching inside the source file, continue with workspace tags and
+ * end with global tags. This way we find the "closest" tag to the current
+ * file in case there are more of them. */
if (source_file)
- {
- GPtrArray *file_members = tm_tags_extract(source_file->tags_array, TM_MEMBER_TYPE_MASK);
-
- member_tags = find_scope_members_all(tags, source_file->tags_array,
- file_members, lang);
- g_ptr_array_free(file_members, TRUE);
- }
+ member_tags = find_scope_members_all(tags, source_file->tags_array, lang);
if (!member_tags)
- member_tags = find_scope_members_all(tags, theWorkspace->tags_array,
- theWorkspace->member_array, lang);
+ member_tags = find_scope_members_all(tags, theWorkspace->tags_array, lang);
if (!member_tags)
- member_tags = find_scope_members_all(tags, theWorkspace->global_tags,
- theWorkspace->global_member_array, lang);
+ member_tags = find_scope_members_all(tags, theWorkspace->global_tags, lang);
g_ptr_array_free(tags, TRUE);
Modified: tagmanager/src/tm_workspace.h
2 lines changed, 0 insertions(+), 2 deletions(-)
===================================================================
@@ -34,8 +34,6 @@ typedef struct
(just pointers to source file tags, the tag objects are owned by the source files) */
GPtrArray *typename_array; /* Typename tags for syntax highlighting (pointers owned by source files) */
GPtrArray *global_typename_array; /* Like above for global tags */
- GPtrArray *member_array; /* Typename tags for syntax highlighting (pointers owned by source files) */
- GPtrArray *global_member_array; /* Like above for global tags */
} TMWorkspace;
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Jiří Techet <techet(a)gmail.com>
Committer: Jiří Techet <techet(a)gmail.com>
Date: Sun, 10 Jan 2016 11:36:05 UTC
Commit: c4b1cd49381a777274897ba2613fc89758acbb0a
https://github.com/geany/geany/commit/c4b1cd49381a777274897ba2613fc89758acb…
Log Message:
-----------
Perform "namespace" search (autocomplete for A:: where A is a type)
In principle this is very similar to the normal scope search. If the
provided name belongs to a type that can contain members (contrary to a
variable in scope search), perform the namespace search. With namespace
search show all possible members that are at the given scope.
Since we perform the scope search at file level, don't perform the
namespace search for tags that can span multiple files otherwise we get
incomplete results which could be confusing to users. This involves
namespaces and packages.
Modified Paths:
--------------
tagmanager/src/tm_workspace.c
Modified: tagmanager/src/tm_workspace.c
58 lines changed, 35 insertions(+), 23 deletions(-)
===================================================================
@@ -746,9 +746,15 @@ GPtrArray *tm_workspace_find(const char *name, const char *scope, TMTagType type
}
-/* Gets all members of type_tag; search them inside the all array */
+/* Gets all members of type_tag; search them inside the all array.
+ * The namespace parameter determines whether we are performing the "namespace"
+ * search (user has typed something like "A::" where A is a type) or "scope" search
+ * (user has typed "a." where a is a global struct-like variable). With the
+ * namespace search we return all direct descendants of any type while with the
+ * scope search we return only those which can be invoked on a variable (member,
+ * method, etc.). */
static GPtrArray *
-find_scope_members_tags (const GPtrArray *all, TMTag *type_tag)
+find_scope_members_tags (const GPtrArray *all, TMTag *type_tag, gboolean namespace)
{
TMTagType member_types =
tm_tag_function_t | tm_tag_prototype_t |
@@ -758,6 +764,9 @@ find_scope_members_tags (const GPtrArray *all, TMTag *type_tag)
gchar *scope;
guint i;
+ if (namespace)
+ member_types = tm_tag_max_t;
+
if (type_tag->scope && *(type_tag->scope))
scope = g_strconcat(type_tag->scope, tm_tag_context_separator(type_tag->lang), type_tag->name, NULL);
else
@@ -790,7 +799,8 @@ find_scope_members_tags (const GPtrArray *all, TMTag *type_tag)
/* Gets all members of the type with the given name; search them inside tags_array */
static GPtrArray *
-find_scope_members (const GPtrArray *tags_array, const char *name, langType lang)
+find_scope_members (const GPtrArray *tags_array, const char *name, langType lang,
+ gboolean namespace)
{
gboolean has_members = FALSE;
GPtrArray *tags = NULL;
@@ -812,8 +822,11 @@ find_scope_members (const GPtrArray *tags_array, const char *name, langType lang
{
guint j;
GPtrArray *type_tags;
- TMTagType types = (tm_tag_class_t | tm_tag_namespace_t |
- tm_tag_struct_t | tm_tag_union_t | tm_tag_typedef_t);
+ TMTagType types = (tm_tag_class_t | tm_tag_struct_t |
+ tm_tag_union_t | tm_tag_typedef_t);
+
+ if (namespace)
+ types |= tm_tag_enum_t;
type_tags = g_ptr_array_new();
if (tag && tag->file)
@@ -858,42 +871,41 @@ find_scope_members (const GPtrArray *tags_array, const char *name, langType lang
if (has_members)
/* use the same file as the composite type if file information available */
- tags = find_scope_members_tags(tag->file ? tag->file->tags_array : tags_array, tag);
+ tags = find_scope_members_tags(tag->file ? tag->file->tags_array : tags_array, tag, namespace);
return tags;
}
-/* For an array of variable tags var_array, find members inside their types */
+/* For an array of variable/type tags, find members inside the types */
static GPtrArray *
-find_scope_members_all(const GPtrArray *var_array, const GPtrArray *searched_array,
- langType lang)
+find_scope_members_all(const GPtrArray *tags, const GPtrArray *searched_array, langType lang)
{
GPtrArray *member_tags = NULL;
guint i;
- /* there may be several variables with the same name - try each of them until
+ /* there may be several variables/types with the same name - try each of them until
* we find something */
- for (i = 0; i < var_array->len; i++)
+ for (i = 0; i < tags->len && !member_tags; i++)
{
- TMTag *tag = TM_TAG(var_array->pdata[i]);
-
- if (tag->var_type)
- {
- member_tags = find_scope_members(searched_array, tag->var_type, lang);
- if (member_tags)
- break;
- }
+ TMTag *tag = TM_TAG(tags->pdata[i]);
+ TMTagType types = (tm_tag_class_t | tm_tag_struct_t | tm_tag_union_t |
+ tm_tag_enum_t | tm_tag_typedef_t);
+
+ if (tag->type & types) /* type: namespace search */
+ member_tags = find_scope_members(searched_array, tag->name, lang, TRUE);
+ else if (tag->var_type) /* variable: scope search */
+ member_tags = find_scope_members(searched_array, tag->var_type, lang, FALSE);
}
return member_tags;
}
-/* Returns all member tags of a struct/union/class if the provided variable name is of such
- a type.
+/* Returns all member tags of a struct/union/class if the provided name is a variable
+ of such a type or the name of the type.
@param source_file TMSourceFile of the edited source file or NULL if not available
- @param name Name of the variable whose members are searched
+ @param name Name of the variable/type whose members are searched
@return A GPtrArray of TMTag pointers to struct/union/class members or NULL when not found */
GPtrArray *
tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name)
@@ -901,7 +913,7 @@ tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name)
langType lang = source_file ? source_file->lang : -1;
GPtrArray *tags, *member_tags = NULL;
- /* tags corresponding to the variable name */
+ /* tags corresponding to the variable/type name */
tags = tm_workspace_find(name, NULL, tm_tag_max_t, NULL, FALSE, lang);
/* Start searching inside the source file, continue with workspace tags and
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Jiří Techet <techet(a)gmail.com>
Committer: Jiří Techet <techet(a)gmail.com>
Date: Sun, 10 Jan 2016 11:36:08 UTC
Commit: e0122592d95f8cd5347729c3d15c05c40094edcd
https://github.com/geany/geany/commit/e0122592d95f8cd5347729c3d15c05c40094e…
Log Message:
-----------
Perform scope autocompletion based on function return types
We just need to skip the (...) and perform autocompletion as before.
Shift pos by 1 in the whole function so we don't have to look 2 characters
back (makes the function easier to read).
Functions contain pointers in their return values - remove them before
searching for the type.
Also restrict the searched variable/function/type tags a bit only to
types which make sense for the search.
Modified Paths:
--------------
src/editor.c
tagmanager/src/tm_workspace.c
tagmanager/src/tm_workspace.h
Modified: src/editor.c
38 lines changed, 29 insertions(+), 9 deletions(-)
===================================================================
@@ -707,31 +707,51 @@ static void autocomplete_scope(GeanyEditor *editor)
gchar *name;
GeanyFiletype *ft = editor->document->file_type;
GPtrArray *tags;
+ gboolean function = FALSE;
- if (ft->id == GEANY_FILETYPES_C || ft->id == GEANY_FILETYPES_CPP ||
+ if (typed == '.')
+ pos -= 1;
+ else if (ft->id == GEANY_FILETYPES_C || ft->id == GEANY_FILETYPES_CPP ||
ft->id == GEANY_FILETYPES_PHP || ft->id == GEANY_FILETYPES_RUST)
{
if (match_last_chars(sci, pos, "::"))
- pos--;
+ pos-=2;
else if ((ft->id == GEANY_FILETYPES_C || ft->id == GEANY_FILETYPES_CPP) &&
match_last_chars(sci, pos, "->"))
- pos--;
- else if (ft->id == GEANY_FILETYPES_CPP && match_last_chars(sci, pos, "->*"))
pos-=2;
- else if (typed != '.')
+ else if (ft->id == GEANY_FILETYPES_CPP && match_last_chars(sci, pos, "->*"))
+ pos-=3;
+ else
return;
}
- else if (typed != '.')
+ else
return;
/* allow for a space between word and operator */
- while (pos >= 2 && isspace(sci_get_char_at(sci, pos - 2)))
+ while (pos > 0 && isspace(sci_get_char_at(sci, pos - 1)))
pos--;
- name = editor_get_word_at_pos(editor, pos - 1, NULL);
+
+ /* if function, skip to matching brace */
+ if (pos > 0 && sci_get_char_at(sci, pos - 1) == ')')
+ {
+ gint brace_pos = sci_find_matching_brace(sci, pos - 1);
+
+ if (brace_pos != -1)
+ {
+ pos = brace_pos;
+ function = TRUE;
+ }
+
+ /* allow for a space between opening brace and function name */
+ while (pos > 0 && isspace(sci_get_char_at(sci, pos - 1)))
+ pos--;
+ }
+
+ name = editor_get_word_at_pos(editor, pos, NULL);
if (!name)
return;
- tags = tm_workspace_find_scope_members(editor->document->tm_file, name);
+ tags = tm_workspace_find_scope_members(editor->document->tm_file, name, function);
if (tags)
{
show_tags_list(editor, tags, 0);
Modified: tagmanager/src/tm_workspace.c
22 lines changed, 19 insertions(+), 3 deletions(-)
===================================================================
@@ -895,7 +895,15 @@ find_scope_members_all(const GPtrArray *tags, const GPtrArray *searched_array, l
if (tag->type & types) /* type: namespace search */
member_tags = find_scope_members(searched_array, tag->name, lang, TRUE);
else if (tag->var_type) /* variable: scope search */
- member_tags = find_scope_members(searched_array, tag->var_type, lang, FALSE);
+ {
+ gchar *tag_type = g_strdup(tag->var_type);
+
+ /* remove pointers in case the type contains them */
+ g_strdelimit(tag_type, "*^", ' ');
+ g_strstrip(tag_type);
+ member_tags = find_scope_members(searched_array, tag_type, lang, FALSE);
+ g_free(tag_type);
+ }
}
return member_tags;
@@ -906,15 +914,23 @@ find_scope_members_all(const GPtrArray *tags, const GPtrArray *searched_array, l
of such a type or the name of the type.
@param source_file TMSourceFile of the edited source file or NULL if not available
@param name Name of the variable/type whose members are searched
+ @param function TRUE if the name is a name of a function
@return A GPtrArray of TMTag pointers to struct/union/class members or NULL when not found */
GPtrArray *
-tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name)
+tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name, gboolean function)
{
langType lang = source_file ? source_file->lang : -1;
GPtrArray *tags, *member_tags = NULL;
+ TMTagType tag_type = tm_tag_max_t &
+ ~(tm_tag_enumerator_t | tm_tag_namespace_t | tm_tag_package_t |
+ tm_tag_macro_t | tm_tag_macro_with_arg_t |
+ tm_tag_function_t | tm_tag_method_t);
+
+ if (function)
+ tag_type = tm_tag_function_t | tm_tag_method_t;
/* tags corresponding to the variable/type name */
- tags = tm_workspace_find(name, NULL, tm_tag_max_t, NULL, FALSE, lang);
+ tags = tm_workspace_find(name, NULL, tag_type, NULL, FALSE, lang);
/* Start searching inside the source file, continue with workspace tags and
* end with global tags. This way we find the "closest" tag to the current
Modified: tagmanager/src/tm_workspace.h
3 lines changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -58,7 +58,8 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i
GPtrArray *tm_workspace_find(const char *name, const char *scope, TMTagType type,
TMTagAttrType *attrs, gboolean partial, langType lang);
-GPtrArray *tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name);
+GPtrArray *tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name,
+ gboolean function);
void tm_workspace_add_source_file_noupdate(TMSourceFile *source_file);
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).