671 Commits

Author SHA1 Message Date
Jiří Techet
c653741a3c Fix member scope completion with nested members
First, the search for existing type with the given scope should be done
also for namespaces.

Second, with the string operations we get no scope as empty string ""
but the rest of TM functions expect scope to be set to NULL in such
case. Fix that.
2016-01-19 00:40:06 +01:00
Jiří Techet
f10747ae5a Remove duplicate names from scope search popup
There may be duplicate tag names in the list e.g. when performing namespace
search and overloaded methods are found.
2016-01-18 23:00:19 +01:00
Jiří Techet
cd1a58f0a5 Use language-specific context separator instead of hard-coded "::"
This makes it possible to popup scope completion dialog for more languages.
2016-01-18 22:56:10 +01:00
Jiří Techet
f38068f04e Skip typedef resolution in namespace search if not needed
When we already have a struct-like type in namespace search,
we don't need any extra resolution - we already have the
right type. Skip the whole typedef resolution in this case.
2016-01-18 22:56:10 +01:00
Jiří Techet
5801844d7e Improve anonymous type handling
Make sure the anonymous types are from the same file as the
variable of that type (or, when performing typedef resolution, from
the same file as the typedef).

On the way, simplify find_scope_members() a bit and fix some minor
problems.
2016-01-18 22:56:10 +01:00
Jiří Techet
5cd5734642 Minor cleanup
Make the unused code compile and remove unused tm_get_current_function()
(we have similar symbols_get_current_function() and there's no reason
to keep it)
2016-01-18 22:56:10 +01:00
Jiří Techet
ad77ee15da Add a "prefix" search for non-scope autocompletion
The main reason for separating m_workspace_find() into two parts is the
fact that when matching only the prefix, the result may contain too
many results and we need to go through all of them, return them and at the
end discard most of them.

For instance, when considering the linux kernel project with 2300000 tags
and when autocompletion is set to be invoked after typing a single character,
we get on average something like 100000 results (tag_num/alphabet_size).
But from these 100000 results, we get only the first 30 which we display
in the popup and discard the rest which means going through the list of
the 100000 tags and comparing them for no reason.

Thanks to using binary search for the start and the end of the sequence of
matching tags (added in a separate patch), we can get the start of the
sequence and the length of the sequence very quickly without going through
it.

For the prefix search we can limit the number of tags we are interested
in and go through at most this number of returned tags (to be precise,
times two, because we need to go both through the workspace array and
global tags array and remove the extras only after sorting the two).

It would be possible to combine both tm_workspace_find() and
tm_workspace_find_prefix() into a single function but the result is a bit
hard to read because some of the logic is used only in tm_workspace_find()
and some only in tm_workspace_find_prefix() so even though there is some
code duplication, I believe it's easier to understand this way.
2016-01-18 22:56:10 +01:00
Jiří Techet
5b4c6f96b2 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.
2016-01-18 22:56:10 +01:00
Jiří Techet
02105d77d7 Simplify tag type specifications in scope search
Consider types with members to have the same properties everywhere (this
might differ language to language but this assumption should behave
reasonably for any language).

Don't check member type in find_scope_members_tags() - we already check
scope which should be sufficient and will work even if some language
uses function/variable instead of method/member/field.
2016-01-18 22:56:10 +01:00
Jiří Techet
67916dc403 Use only binary search to find first/last element in a row of equal tags
The linear part may become expensive when there are many equal tags
which can happen when partial search, used for non-scope completion,
is used.
2016-01-18 22:56:10 +01:00
Jiří Techet
2682d7973f Remove anon_* elements when performing namespace search
These correspond to anonymous structs, enums, etc. but they don't have
any name so the name shouldn't be listed.
2016-01-18 22:56:10 +01:00
Jiří Techet
932dc71fe2 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).
2016-01-18 22:55:02 +01:00
Jiří Techet
e0122592d9 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.
2016-01-10 12:36:08 +01:00
Jiří Techet
c4b1cd4938 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.
2016-01-10 12:36:05 +01:00
Jiří Techet
1281d0c942 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().
2016-01-10 12:33:40 +01:00
Jiří Techet
30fa28bac7 Don't use enums for scoped search
Even though enums contain members, their members are accessed in a
different way than members of classes and structs. E.g. consider:

typedef enum {A, B, C, D} MyEnum;

Variable of this type is declared as

MyEnum myVar;

myVar can be assigned a value from MyEnum; however, we don't access myVar
over the dot operator so we don't need the list of all members after
typing

myVar.

This patch eliminates some false positives after typing .
2016-01-10 12:31:47 +01:00
Jiří Techet
bf17c90bd6 Improve tag searching for "typedef struct {...}" cases
When resolving typedef, search for the subsequent type in the file where
the typedef was defined. For more info see the comment in the patch.
2016-01-10 12:31:47 +01:00
Jiří Techet
13755122f2 Move symbols_get_context_separator() implementation to TM
This way we can use it inside TM.
2016-01-10 12:31:47 +01:00
Jiří Techet
e13aac0dea Remove unused tm_workspace_find_namespace_members()
The implementation of this function is almost the same like the original
m_workspace_find_scoped_members() and there's nothing interesting here
we wouldn't be able to recreate trivially.
2016-01-10 12:31:46 +01:00
Jiří Techet
809a9a7ea5 Merge add_member() and find_scope_members_tags()
By comparing the file pointer in the loop we can speed it up a bit
because we can avoid the strcmp() (this function is the slowest part of
the scope completion based on profiling).

Also move the pointer array creation to this function and return it which
is a bit cleaner.
2016-01-10 12:31:46 +01:00
Jiří Techet
8ff8cbc3a3 Sane implementation of find_scope_members_tags()
Disclaimer: I have absolutely no idea how the original function works.
After gazing into the code for one hour, I just gave up and wrote my own
version of it based on what I think the function should do
but maybe I'm just missing something what justifies the original
implementation's insanity.
2016-01-10 12:31:46 +01:00
Jiří Techet
140a7b6617 When extracting members, get them from single file only
The previous commit fixed the situation when e.g. anon_struct_0 was in the
current file by checking the current file first.

In the case the struct type definition isn't found in the current file,
at the moment we get all members from all anon_struct_0 which can be a
really long list. This list isn't very helpful to users because all the
members from all the structs are mixed. Moreover, not all possible members
are in the list because there are e.g. just members from anon_struct_0 but
not from anon_struct_1 etc. which from the point of view of this function
is a different type.

Instead, restrict the returned members to just a single file (anonymous
structs have unique name per file so it means there will be just one
from the file). Of course the picked file can be wrong and the returned
members might be from a different struct the user wanted but at least
the list will make more sense to users.
2016-01-10 12:31:46 +01:00
Jiří Techet
b6b93036f6 Get scope members only from corresponding tag arrays
At the moment it can happen that even though a member is found in the
currently edited file, the search at the end of the function finds
the type inside another file. This typically happens for anonymous
structs so e.g. for anon_struct_0{...} from the current file we get
members from anon_struct_0{...} from all open documents plus gloabl tags.

Search in an increasing "circle" - start with current file only (trying
all possible types of the variable), continue with workspace array and
finally, if not found, search in the global tags.
2016-01-10 12:31:02 +01:00
Jiří Techet
2328f84e37 Disallow the possibility to use tm_tags_find() on unsorted array
This function won't work correctly on unsorted array because the second
part of the function (after the tags search) expects the array is sorted
by name. The only user of this is tm_source_file_set_tag_arglist() in which
we can go through the tags manually by ourselves (it needs only a single
value so the original behavior of tm_tags_find() wasn't a problem).
Eliminate the tags_search() function as it isn't needed any more.

Just cleanup, not functional change.
2015-07-14 09:46:59 +02:00
Jiří Techet
99e222ea37 Eliminate calls of slow tm_tags_extract() on big arrays
Do the same with struct/class/union... member tags as we do with
typenames - extract them from the edited file and merge them with
the array containing all of them so while editing, there should
be no slowdowns because one file usually doesn't contain so many
tags. This eliminates about 2s freeze when typing "." on a linux
kernel project with 2300000 tags.

Extract typename and member tags also for global tags in case someone
creates a giant tags file - this needs to be done just once when
loading the tag files.

All the remaining tm_tags_extract() in Geany are called on
file tag array only so there shouldn't be any performance problems.
2015-07-14 09:44:33 +02:00
Jiří Techet
5c18b3d132 Improve scoped search
This patch contains a bit too many things which are however related.

It started by the part in editor.c (where we previously used only the
first type we found to perform scoped search) by going through all the
possible variable types until the scoped search returns some result
(this is useful if variable foo is used once as int and once as struct
and if the int is the first type found, we won't get the struct's members).

This didn't work. After an hour of debugging, it turned out that
because tm_workspace_find_scope_members() calls internally
tm_workspace_find() and this function returns static array, this
invalidates the array returned by the tm_workspace_find() used
previously to get all the possible variable types.

Since this is really dangerous and hard to notice, I tried to eliminate
the static returns from both tm_workspace_find() and
tm_workspace_find_scoped_members().

The tm_workspace_find_scoped_members() function is where I got
stuck because as I started to understand what it's doing, I found
many problems there. This patch does the following in this function:

1. Eliminates search_global and no_definitions parameters because
we always search the whole workspace and this simplifies the slightly
strange logic at the end of the function.
2. Returns members from global tags even when something found in
workspace tags - previously global tags were skipped when something
was found from workspace tags but I don't see a reason why.
3. Adds the lang parameter to restrict tags by language (we do this
with normal search and the same should be done here).
4. Previously when searching for types with members the function
returned NULL when more than one such type was found (there should
have been >=1 instead of ==1 at line 906). This patch improves the
logic a bit and if multiple types are found, it tries to use the one
which is other than typedef because it probably has some members (the
typedef can resolve to e.g. int).
5. Previously the function prevented only direct typedef loops like

typedef A B;
typedef B A;

but a loop like A->B->C->A would lead to an infinite cycle. This patch
restricts the number how many times the typedef can be resolved by
using for loop with limited number of repetitions and giving up when
nothing useful is resolved.
6. Finally the patch tries to simplify the function a bit, make it
easier to read and adds some comments to make it clearer what the
function does.
2015-07-14 09:44:33 +02:00
Jiří Techet
ee3eeeb758 Merge tm_workspace_find() and tm_workspace_find_scoped()
They are basically identical except:

1. _scoped() compares scope in addition
2. _scoped() is missing the C/CPP tag compatibility part
3. _scoped() allows returning just single result (unused)
4. _scoped() allows not searching in global tags (unused)

Since we now always put lang also under tag->lang, the match_langs()
function is not necessary.

Extend the add_filtered_tags() (and rename it to fill_find_tags_array()) to
perform the tm_tags_find(), compare the scope and add scope
as parameter of tm_workspace_find() and eliminate tm_workspace_find_scoped()
completely.
2015-07-14 09:44:33 +02:00
Jiří Techet
5c6b423f70 Clean up tm_workspace_find()
1. Factor-out the part common to tags_array and global_tags
2. Get both C/CPP tags when either of the languages is specified (both
for global_tags and tags_array)
3. Remove unnecessary strcmp()s (tm_tags_find() should return only tags
with the specified name)
4. Various minor cleanups
2015-07-14 09:44:33 +02:00
Colomban Wendling
96d5eec50f Merge pull request #544 from b4n/cxx11-override
c++: Properly parse C++11 overrides, finals and noexcepts
2015-07-08 18:04:05 +02:00
Enrico Tröger
4017442f86 Merge pull request #477 from eht16/ctags_powershell
Add PowerShell tag parser
2015-07-04 12:52:46 +02:00
Colomban Wendling
f60b31385e c++: Handle C++11 noexcept 2015-07-01 12:55:52 +02:00
Colomban Wendling
95a0d4db7e c++: Properly parse C++11 override and final members
As `override` and `final` aren't real keywords, handle them manually
not to break identifiers of those names.
2015-07-01 12:55:29 +02:00
Colomban Wendling
641863c264 c++: Fix handling of the final contextual keyword
`final` is not a normal keyword, as it only have a special meaning in
some specific context.  So, use a special case instead of a keyword not
to break identifiers of that name.
2015-06-30 23:22:08 +02:00
Jiří Techet
89f7a2eec9 Fix leaking typename_array in tag manager 2015-06-30 13:23:02 +02:00
Enrico Tröger
8a6fbd9786 Add PowerShell tag parser 2015-06-28 15:46:23 +02:00
Colomban Wendling
46a123d6fe python: Fix handling of inline comments
If there was two hashes (#) in an inline comment, only the content
between the two was considered a comment.

X-Universal-CTags-Commit-ID: ee93f5b9f393e76a850cf8c894cc748a62981156
2015-06-25 22:47:32 +02:00
Jiří Techet
6781ab30c5 python: optimize skipEverything()
Most of the time there's no start of a string which means all the 10
strcmp()s are done for every character of the input. This is very expensive:
before this patch this function alone takes 55% of the parser time.
When comparing by character (and avoiding further comparison if the first
character doesn't match), this function takes only 11% of the parser time
so the performance of the parser nearly doubles.

In addition check for the "rb" prefix which is possible in Python 3.

Ported from universal-ctags.
2015-06-25 22:10:32 +02:00
Colomban Wendling
6f60de3656 Merge pull request #514 from techee/linear_tag_remove
Add linear tag remove path for cases where not many files are open
2015-06-15 14:56:07 +02:00
Colomban Wendling
882687ec37 C#: Don't ignore the character following an '@'
The character following an '@' was dropped if it didn't start a string
literal.

This could lead to unexpected problems if '@' was valid in other
situations.

X-Universal-CTags-Commit-ID: 2e62f475af1db08850447de46f56db14ce99d2eb
2015-06-14 18:27:17 +02:00
Colomban Wendling
dbbc042786 c family: Add support for digraphs
See http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf 6.4.6§3.

Note: This is not exactly the upstream Universal CTags commit because
it depends on another change for adding the `enter` label, which was
then included here.

X-Universal-CTags-Commit-ID: 3b3b60c7664a321a31ec87de336fc6bda90c405e
2015-06-14 18:25:38 +02:00
Colomban Wendling
b737f031ca c family: Fix trigraph handling
X-Universal-CTags-Commit-ID: d6d1a0f2b90a600bdec9cd6ba964ee69382743e4
2015-06-14 18:23:29 +02:00
Colomban Wendling
b975c2652d read: Allow to unget up to 3 characters
Some parsers need to unget more than one characters, so add support for
this.

X-Universal-CTags-Commit-ID: 956af0555d3a8ef33304c5ae6ed873f22b4e4284
2015-06-14 17:57:18 +02:00
Jiří Techet
e26c9ba2ce Add linear tag remove path for cases where not many files are open
When tested with 200000 LOC python file (created by making many copies
of scripts/create_py_tags.py), the tm_tags_remove_file_tags() function
takes about 50% of the CPU time when only this file is open. After adding
the linear path to tm_tags_remove_file_tags() it takes just about 2%. See
the comment in the patch for more details.
2015-06-14 17:52:24 +02:00
Colomban Wendling
944bffb967 json: Fix handling of tags containing a dot
X-Universal-CTags-Commit-ID: 7ae28a3d8a7ad5f8a9d6399a4e357fcf19ad2b2e
2015-06-14 17:29:04 +02:00
Colomban Wendling
f30b72d91e vstring: Add vStringTruncate()
Add API to truncate a vString to a certain length. This doesn't support
growing the string, only shrinking it.

X-Universal-CTags-Commit-ID: 4e3d9edf2e7a8a476ff97bc678e71c3919b960f9
2015-06-14 17:25:33 +02:00
Colomban Wendling
d75598cc48 python: Fix resetting scope on anonymous blocks
The previous fix, coming from [CTags bug #1988026], was incorrect if
the parent was not a root-level element, as it checked the level name
(unqualified) against the parent name (qualified).

However, there is no need to check the level name, all what counts is
the indentation level itself: if it's smaller than an existing level,
it ends it.

This fixes [CTags bug #356].

[CTags bug #1988026]: https://sourceforge.net/p/ctags/bugs/227/
[CTags bug #356]: https://sourceforge.net/p/ctags/bugs/356/

X-Universal-CTags-Commit-ID: ab91e6e1ae84b80870a1e8712fc7f3133e4b5542
2015-06-14 17:13:46 +02:00
Jiří Techet
206379a272 Parse return value of go functions
Unfortunately varType is Geany-only so this patch cannot be ported to ctags.

The removal of the extra { read is not the most elegant thing but making
skipType() aware of the argList collection complicates things too much.
2015-05-28 16:27:23 +02:00
Jiří Techet
e433490672 Sync go parser with fishman-ctags
New features include:
* struct/interface detection
* struct member parsing
* function prototype parsing
2015-05-28 16:22:54 +02:00
Jiří Techet
81fb120f50 Fix language check in tm_workspace_find()
The tags_lang variable is set from the first tag in the found array but
the array may actually contain tags from several languages. This may
lead to two things:

1. Goto tag definition goes to a tag from a different filetype
2. Worse, the first tag is from a different language than the current file
and we get a message that no tag was found

Get lang for every tag in the array and rename tags_lang to tag_lang.
2015-05-06 18:37:46 +02:00
Jiří Techet
35bde6c5ad Reload a tag in the sidebar only when it differs from the existing tag
gtk_tree_store_set() becomes very slow when the tree gets bigger
because internally it calls gtk_tree_store_get_path() which counts
all the entries in a linked list of elements at the same tree level
to get the tree path.

Avoid the call of this function when not needed.
2015-05-03 19:36:26 +02:00