I created function read_scope_prefix which is similar to read_current_word. It gets the scope of the word the cursor is on:
if the user types: ScopeA::ScopeB::Function it will return ScopeA::ScopeB
Then I used my read_scope_prefix function in editor_show_calltip where find_calltips is called. To find_calltips I added an argument const gchar *scope to send the value over. find_calltips now passes scope argument to tm_workspace_find function. If no tags are found within the typed scope, find_calltips falls back to its original behavior, which does not account for scope when displaying function calltips.
<img src="http://imgur.com/ucUiyV4.png"></img> You can view, comment on, or merge this pull request online at:
https://github.com/geany/geany/pull/1177
-- Commit Summary --
* added read_scope_prefix and, added scope arguement to find_calltips, and calltips now searches scope for tags
-- File Changes --
M src/editor.c (86)
-- Patch Links --
https://github.com/geany/geany/pull/1177.patch https://github.com/geany/geany/pull/1177.diff
@@ -2045,8 +2114,13 @@ gboolean editor_show_calltip(GeanyEditor *editor, gint pos) editor_find_current_word(editor, pos - 1, word, sizeof word, NULL); if (word[0] == '\0') return FALSE;
- str = find_calltip(word, editor->document->file_type);
- scope[0] = '\0';
- //const gchar *sname;
- //symbols_get_current_scope(editor->document, &sname);
I would have like to use symbols_get_current_scope here, but it kept returning "unknown" if there is a fix so I can remove read_scope_prefix function then please let me know
@@ -2045,8 +2114,13 @@ gboolean editor_show_calltip(GeanyEditor *editor, gint pos) editor_find_current_word(editor, pos - 1, word, sizeof word, NULL); if (word[0] == '\0') return FALSE;
- str = find_calltip(word, editor->document->file_type);
- scope[0] = '\0';
- //const gchar *sname;
- //symbols_get_current_scope(editor->document, &sname);
- //printf("Current scope: %s\n", sname);
- read_scope_prefix(editor, pos - 1, scope, sizeof scope, NULL);
- str = find_calltip(word, scope, editor->document->file_type);
I would have liked to use symbols_get_current_scope here rather than write my own read_scope_prefix function, but symbols_get_current_scope kept returning "unknown" for some reason. if anyone knows how to make that function work please do
@krogank9 pushed 1 commit.
e4f7dff removed unneeded comment
@@ -2045,8 +2114,13 @@ gboolean editor_show_calltip(GeanyEditor *editor, gint pos) editor_find_current_word(editor, pos - 1, word, sizeof word, NULL); if (word[0] == '\0') return FALSE;
- str = find_calltip(word, editor->document->file_type);
- scope[0] = '\0';
- //const gchar *sname;
- //symbols_get_current_scope(editor->document, &sname);
- //printf("Current scope: %s\n", sname);
- read_scope_prefix(editor, pos - 1, scope, sizeof scope, NULL);
- str = find_calltip(word, scope, editor->document->file_type);
`symbols_get_current_scope()` returns a somewhat limited view of the lexical scope IIUC, so its not what you want until you need to resolve the highest level name in your prefix.
@@ -2045,8 +2114,13 @@ gboolean editor_show_calltip(GeanyEditor *editor, gint pos) editor_find_current_word(editor, pos - 1, word, sizeof word, NULL); if (word[0] == '\0') return FALSE;
- str = find_calltip(word, editor->document->file_type);
- scope[0] = '\0';
- //const gchar *sname;
- //symbols_get_current_scope(editor->document, &sname);
- //printf("Current scope: %s\n", sname);
- read_scope_prefix(editor, pos - 1, scope, sizeof scope, NULL);
- str = find_calltip(word, scope, editor->document->file_type);
Yeah I realized that. I removed those comments. Now I know I can't use it
This should be streamlined as much as possible with `autocomplete_scope()`, which does mostly the same as what you're trying to achieve, and can probably share some code.
@techee might be able to help here :)
Yeah, looks similar and probably both cases could share some code. This patch works for namespace prefixes only but it could also be changed to work for variable prefixes too (for strongly-typed languages for which we have varType).
On the other hand this patch supports multiple levels of scopes which we don't have in scope completion right now (the code would probably get quite a bit crazier if we were doing scope completion for multiple levels). But maybe it's not so important and one level could be enough.
But yeah, the idea behind the patch makes sense and brings back the beautiful memories of the implementation of scope completion :-).
Looking at autocomplete_scope I don't see any way this could share its code as this patch stands now. But I find the way that tm_workspace_find returns tags to find_calltips to be satisfactory. For example all of those MeshBuilder and VertexData namespaces are within the namespace BABYLON. I can type BABYLON.MeshBuilder.CreateBox which will have the scope prefix BABYLON.MeshBuilder. tm_workspace_find will return all tags with scopes matching the last part of the scope. So not just matching BABYLON.MeshBuilder scope but also MeshBuilder scoped functions are returned.
but once the calltip is shown it no longer respects the scope so well and it just shows all functions.
Yeah, calltips don't look at context AFAIK, only scope autocomplete does, for named scopes (ie classes, namespaces) only, it doesn't know about lexical scopes. And variable scope auto-completion only works for variables defined at top level, so its isn't very useful for modern C/C++.
The whole area could probably use a re-think instead of piling patches over patches, especially if @techee doubts it.
@krogank9 I'll try to do the necessary changes on the TM side so you can use it for this feature.
What's the problem with TM? I might be missing something obvious, but a quick and dirty patch like http://pastebin.geany.org/ISAQT/ seems to mostly work.
It could possibly be improved to use the current scope to resolve direct methods and some other stuff, but that could be added. I mean like ```C++ class Foo { std::string something(int n) { return nullptr; }
int main() { return something(/* here, show Foo::something() only, not Bar::something() */); } };
class Bar { int something() { return 0; } };
/* But this works:
Foo::something(); Bar::something();
class Z { Foo memb; Z() { memb.something(); } }; */ ```
Ah right, I forgot tm_workspace_find_scope_members() returns functions too which is what I thought would have to be added. Everything there then, no work for me :-P.
@techee yeah, you'll review, and possibly add support for implicitly scoping on `this` :) Although scoping on `this` might be tricky, because you still want to allow global variables and methods. Methods should be fine as the `this` one would have precedence anyway, and we know which it is, but scope completion would have to consider both the `this` scope and the global one in this case.
Ah, and should I PR my quick patch for further discussion/work/whatever, or it's too quick'n dirty do be of any actual use?
Ah, and should I PR my quick patch for further discussion/work/whatever, or it's too quick'n dirty do be of any actual use?
Would be good - I'll review and also @krogank9 can check if it works for his use cases.
@techee Yup I tried it out, it works the same as my patch and also adds support for variables/instances of a class for strongly typed languages, not just for use with namespaces/static methods
add support for implicitly scoping on this :)
And @techee can add support for C++ scoping of class members in member functions where _this_ is implicit, so I have less to complain about "every language is C" :)
add support for C++ scoping of class members in member functions where _this_ is implicit
Mmm, what? Isn't it what I did, that is that it considers the current scope when there's nothing on the left? My second commit doesn't try to handle `this.foo()` (which would be nice, but few languages use `this`), but `foo()` inside a scope. The idea being that if it's inside `Foo::bar`, it has to be part of one of the scopes `Foo::bar`, `Foo`, or none; but e.g. not `Baz`, as it wouldn't be accessible without an explicit prefix (unless inherited somehow, but we don't have that yet anywhere).
@b4n, it looked like you are relying on autocomplete's algorithm by cunningly renaming it, but it doesn't work AFAICT, eg:
```c++
struct Bar { int aaab; };
struct Foo { int aaaa; int f(){ aa // now autocomplete shows both aaaa and aaab }; }; ```
Or is that not what its doing.
it looked like you are relying on autocomplete's algorithm by cunningly renaming it
what does this mean?
Anyway, your example works for me *if there is only one `Foo` in the workspace*. I'm not very sure why I might pick up the wrong `Foo` if there are more even though I pass `editor->document->tm_file`, but well.
it looked like you are relying on autocomplete's algorithm by cunningly renaming it
what does this mean?
I meant this change:
``` -static gboolean autocomplete_scope(GeanyEditor *editor, const gchar *root, gsize rootlen) +static GPtrArray *get_scoped_tags(GeanyEditor *editor, gint pos) ```
Now my turn :), what do you mean by "only one Foo", the symbol `aaab` is in `Bar` not `Foo`, but it shows for autocomplete inside a member function of `Foo`
I mean rename `Foo` to `FooImSureThereIsOnlyOne` and it'll work.
Nope, not in current Geany, still both. Or is it some extra magic you added in the patch as well as making scope completion apply to calltips?
Oooooh, okay, sorry, I assumed you were trying #1188 which does add it.
Oh, havn't even looked at #1188 yet.
github-comments@lists.geany.org