Pop up scope completion dialog for namespaces too; e.g. for
boost::
show all symbols defined in the namespace. Determine whether the namespace
scope completion should be used based on whether user typed a scope
separator. If so, perform completion for namespaces before normal scope
completion - this seems to work better e.g. for Scintilla where
Scintilla::
would otherwise pop up the varible sci instead of showing everything
in the namespace (might be more questionable for languages where
the scope separator is identical to the dereference operator like
Java's "." but we have to make some choice anyway).
The performance seems to be reasonable - for the completion all tags
have to be walked but after testing with big C++ projects like
boost and Mozilla, the completion takes only something like 0.2s
which is acceptable as the delay happens only on typing the scope
completion separator and feels kind of expected.
Also tested with linux kernel sources which normally lack any scope
information by hacking TM a bit and injecting 10-character scope for
each tag - then the completion takes something over 0.5s.
The x coordinate is now taken from the scintilla caret position. However,
when performing ctrl+click, we have to distinguish two cases:
1. the click happens in the second half of a letter - in this case the caret
is placed behind the letter and the popup appears behind it - no problem
2. the click happens in the first part of a letter - caret is placed before
the letter and the popup appears before the position where the click
happened - this means that the mouse cursor is above the popup which causes
that the mouse cursor highlights the item at the position of the cursor
instead of having the first item in the menu highlighted.
The patch calculates offset between caret and the mouse click event
position and uses this value to adjust the popup positioning so it's
outside the mouse cursor.
Even when the user Ctrl+clicks to perform goto tag definition, it should
be possible to select the item from the list using keyboard (and have
the first item automatically selected so ctrl+click plus enter afterwards
always gets you somewhere).
If only a single tag is found, just perform the goto. If more tags are found,
show them in a popup. Try to help the user find the right file by
putting the "best" tag at the first position and emphasizing it.
Thanks to Colomban Wendling for various improvements of this patch.
For users a tag is <this> so the naming can be confusing.
The only exception where we probably shouldn't use the word symbol is the
"tags file" (*.tags) containing global tags - this has already the "tags"
extension and is more related to ctags and using "symbols file" is a bit
strange in this case.
As a result, the only places where this patch leaves the word "tag" are:
* phrase "tags file(s)"
* phrase "tags parser(s)"
* documentation mentioning the "tags" directory
* documentation mentioning the *.tags extension
and of course where it means the HTML/XML markup <thing>. The rest of the
uses of the word "tag" is replaced with "symbol".
Documentation is updated accordingly.
Fixes#579.
Because the stash_group_new() is an exported API, it has to be at least a boxed
type to be usable for gobject introspection. The boxed type uses reference
counting as opposed to memory duplication.
The obligatory stash_group_dup() is not exported (doesn't have to).
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.
When scope autocompletion list shows, start filtering it when
when the user types some more characters. As long as the list
is non-empty, don't switch to normal autocompletion and show
only the scope autocompletion results.
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).
This helps g-ir-scanner recognizing the data parameter as context storage,
allowing object methods to be used as callback (via wrappers). It goes even
so far that g_object_unref is propery passed as destroy func to
keybindings_set_item_full() and plugin_set_key_group_full().
Both sorting by name and appearance makes sense for most languages. Some
users may prefer sorting by appearance so make it configurable in
preferences (the possibility to override the settings for specific
filetypes is preserved).
Thanks to Colomban Wendling for lots of improvements of this patch.
Fixes#313.
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.
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.