Their implementation was buggy, use very old Windows APIs and require
double implementation and maintenance efforts for us
The GTK dialogs work well for all other users already, so they probably
will also for Windows users.
Closes#3209.
While the current way of grouping symbols under various categories
like "Functions", "Structures", "Macros" etc. may be useful in some
situations, it doesn't allow true sorting by name or sorting by line
number because this sorting is only valid within the group and not
globally which makes it sometimes hard to find some symbol.
This patch adds the option to switch between two views of the symbol tree
by using a new checkbox called "Group by Type" to the context menu:
- checked - the original view used by Geany
- unchecked - view with a single root element "Symbols" in which
all symbols are rooted and all of them either sorted by line number
or alphabetically
The core of the implementation is rather simple - there's always the
"Symbols" root present at position 0 in tv_iters and when categorized
view is selected, this root is used for all the tags. (We still need
to keep the category roots in this situation to copy the icons for
the tags from them but they are always empty and hidden).
The rest is some UI stuff for creating entries in the context menu, I also
added a config preference so this settings is remembered across Geany
re-launches. I made this option global for all open files because
I would find it annoying to apply this setting manually for every open
file. So the code also checks whether the view type changed for the
given file when switching tabs and re-creates the tree with the new
setting.
This patch enables local variable and function parameter reporting for
Python, GDScript, PHP, and Typescript.
Because these are dynamic languages and Geany scope autocompletion
relies on static type information, scope completion doesn't work for
these languages. However, at least we get non-scope autocompletion
for local variables and function parameters.
Local variables in GDScript were previously mapped to tm_tag_other_t
and were displayed in the sidebar. We don't display these tags for
C/C++ in the sidebar and they should also be mapped to
tm_tag_local_var_t which is why there is a diff in unit tests removing
these variables from the output.
The python parser generates a slightly different output when function
parameter parsing is enabled (whitespace only change) which causes
the change of the output of some python unit tests.
The current code assumes that the whole var_type string consists of the
anonymous type name. This works for simple cases like
struct {} X;
where X is of the type __anonXXXX but not for cases like
struct {} X[2];
where X is of type __anonXXXX[].
For these cases checking for equality of var_tag->var_type, orig_name isn't
sufficient and we have to check whether orig_name is a substring
of var_tag->var_type and replace this substring with the new anon name.
This problem can be seen for instance in the symbol tree tooltip of
the symbols_icons variable inside symbols.c
ctags sets the tag's "local" flag to true for tags whose visibility is
limited to the current file only. These are for instance "static" functions
in C.
We can ignore these tags for autocompletion in other files than the
tag's file which reduces the number of irrelevant tags in the
autocompletion popup.
The tm_workspace_create_global_tags() function generates tags for
two cases:
1. Source files pre-processed by C pre-processor. It first generates
a file combining the parsed header files by creating a temporary
file in which all the header files are included and this file is passed
to the pre-processor. The result of the pre-processed file is then
parsed by the ctags parser.
2. Source files directly parsed by the ctags parser. In this case all
the source files are concatenated to a single file which is then parsed
by the ctags parser.
This patch leaves (1) more or less unchanged; however, the creation of
the temporary file in (2) is unnecessary - the individual files can
be parsed directly, the tags from all the parses can be combined, sorted
and pruned without creating the temporary file.
The temporary file is a problem for unit tests where some languages
use the file name as the name of module in which the tags are defined
and by using a different name, the unit test generates a different tag
file every time it's run.
Note the changed output of the process_order unit test caused by this
change. The test parses two files, one containing
enum {
I1_E1,
I1_E2,
};
the other contining
enum {
I2_E1,
I2_E2,
};
Previously, because the files were concatenated the enums were different
tags and the anonnymous tag renaming function renamed them to anon_enum_1
and anon_enum_2. Because now the files are parsed separately, the
enum from the first file gets renamed to anon_enum_1 and when parsing
the second file, we get the name anon_enum_1 as well for the second enum.
This however isn't a problem - we don't display global tags in the
symbol tree, autocompletion, and they are also ignored in scope completion
so this shouldn't matter much.
To present more relevant results at the top of the list, sort them in
the following order:
local variables
tags from current file
workspace tags
global tags
and alphabetically within a single group.
In addition, we need to remove duplicates from the list of displayed names.
Finally, since the entries are not sorted alphabetically, we need to call
SSM(sci, SCI_AUTOCSETORDER, SC_ORDER_CUSTOM, 0);
so Scintilla knows it shouldn't sort the list alphabetically.
When performing scope completion for
void A::foo() {
bar. // <--
}
we need to determine what 'bar' is. It could be a global variable, in which
case we should look for variable tags, it could however also be a member
of A in which case we should look for member tags.
To determine this, the previous code checked whether there's a tag
named 'bar' with the same scope as the method tag. One drawback of this
approach is that it doesn't take namespace manipulation functions
like 'using namespace' into account so for header
namespace X {
class A {
Baz bar;
};
};
and source
using namespace X;
void A::foo() {
bar. // <--
}
it wouldn't find 'bar' because ctags reports foo() to have scope A
and bar to have scope X::A.
Another drawback of this approach is that it doesn't take inheritance
into account so it wouldn't find 'bar' when defined in a super-class,
such as
class B {
Baz bar;
};
class A : B {
void foo();
}
To avoid these problems, this patch rewrites member_at_method_scope()
(and renames it to member_accessible()) so it gets the class name from
the scope of the method in which we are (A in the above example) and
returns all members of A (including the super-classes members).
Afterwards, it checks if one of the members is really the member tag
we are interested in ('bar' in the above example).
The code simply checks for inherited classes, strips unneeded stuff
like templates, etc. from inherited classes, detects multiple inheritance
by splitting the string using "," and calling tm_workspace_get_parents()
recursively on every parent class and collecting the returned tags.
The code limits the recursion depth to 10 to avoid possible inheritance
cycles and infinite recursion.
Also remove #if 0'd old code from TM implementing inheritance that we
kept for reference as we now have a better implementation.
We are interested in pure type name and ctags returns types including
pointers, references, arrays, template parameters and keywords such as
"const" or "struct". Strip all those.
Also move strip_type() above so it's usable by other functions.
We only want to use local variables within the current function for
the goto. This means we want to filter out local variable tags that:
1. Are from a different file
2. Are declared later in the file than where the current cursor is
3. Have different scope than the current function scope
Fundamentally the same requirements as for (non-scope) autocompletion.
The code removes invalid local variables from other functions and behind
current position. In addition, it sorts the found tags corresponding
to the name in the editor for which we perform scope completion so
local variables are searched first for their members, followed by tags
from the current file, followed by workspace tags and finally using
global tags.
We have to ignore local variables that:
1. Are from a different file
2. Are declared later in the file than where the current cursor is
3. Have different scope than the current function scope
This problem can be seen on
scintilla/src/Document.cxx
where not all anonymous tags are renamed because of macros. Fix that
by not breaking the rename loop for macros for C-like languages.
Enable generating these tags both for local variables and function
parameters - those are more or less identical for what we will be using
local tags for so they can be mapped to the same type.
Local tags aren't interesting for tag files so filter them out when
generating these (but this also means that we cannot create unit tests
for them).
Sometimes right-click to open a the popup menu in the document sidebar
wouldn't change the selection before showing the popup. Then the
popup wasn't related to the document that was clicked.
This was especially bad with middle-click to close. It closed anything
but the clicked document (or folder in case of tree view).
This was caused by some unexpected calls to the "activate" signal handler
for the "openfiles_path_mode" menu items. The handler might re-create
the document list which in turn invalidates the current selection.
Now the signal handler has some protection against unexpected calls and
the selection properly updates upon right-click before spawing the popup.
This script reads Geany binary tags files from stdin and writes
to stdout a file where each of the tags is followed by a line where
the tag is printed in the following human-readable form:
tag_type: return_value scope :: tag_name(arglist) additional_stuff
Especially the tag_type is currently hard to understand when looking at
unit tests and easy to miss if there's a problem.
This adds a tree view mode to the document list in the sidebar and enables it by default.
Based on previous work by Pavel Roschin <roshin@scriptumplus.ru>, see #259
The test program checks if open documents are grouped correctly by
their parent directory. The older modes (plain document list and two-level
tree) also get a distinct test. For this to work some symbols
must become visible from libgeany.
The test uses g_strv_length() which is relatively new.
Autoconf and meson checks are added as needed.