-
-
Notifications
You must be signed in to change notification settings - Fork 115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(lsp): Add autocomplete #1900
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some excellent work here @spotandjake and so fantastic to get this into the LSP!
I think we need to go ahead and handle the cases for completion a little better—going ahead and looking for the |
I made that change and improved the way detection is done. |
compiler/src/language_server/doc.re
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we name this file document.re
? I don't want to get it confused with doc.re
in the formatter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Im a fan of that change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made that change
b50da63
to
479b596
Compare
8a6cdca
to
53ef8b5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks pretty reasonable, but we'll need to do some work on how we find completeable states.
); | ||
}; | ||
|
||
let supressed_types = [Builtin_types.path_void, Builtin_types.path_bool]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this not all builtin types?
let source = | ||
Str.global_replace(Str.regexp({|\r\n|}), {|\n|}, source_code); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary? This is extremely expensive.
let source_chars = | ||
List.rev( | ||
String_utils.explode(String_utils.slice(~last=offset, source)), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really expensive too. I imagine it's cheaper just to check string prefixes directly.
root_decl: Types.module_declaration, | ||
path: list(string), | ||
) => { | ||
// Get The Modules Exports |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Get The Modules Exports | |
// Get the module's exports |
Some(build_type_completion(~env, (ident.name, decl))) | ||
| TSigModule(ident, decl, _) => | ||
Some(build_module_completion(~env, (ident.name, decl))) | ||
// Dissabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Dissabled | |
// Disabled |
// Find The Top Level Modules | ||
let completions = | ||
switch (search) { | ||
// User Wrote Nothing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// User Wrote Nothing | |
// User wrote nothing |
switch (search) { | ||
// User Wrote Nothing | ||
| [] | ||
// User Wrote A Single Word, i.e Top Level Search |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// User Wrote A Single Word, i.e Top Level Search | |
// User wrote a single word, i.e top-level search |
| [] | ||
// User Wrote A Single Word, i.e Top Level Search | ||
| [_] => completions | ||
// User Wrote A Path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// User Wrote A Path | |
// User wrote a path |
| [_] => completions | ||
// User Wrote A Path | ||
| [search, ...path] => | ||
// Find Module Root |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Find Module Root | |
// Find module root |
} | ||
}; | ||
// Remove Operators | ||
let operators = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would also be good to have this at the top level.
@ospencer if you get a chance would you be willing to review the new implementation. It needs more work before its good so im going to convert this to a draft. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general the new approach seems really smart!
807a91b
to
443d057
Compare
…e are writing an identifier.
03e2953
to
d93ab92
Compare
mentioned in the grain meeting, but if anyone wants to take over this pr feel free ive gotten a little burnt out from it,My current approach was to run the lexer and get the lexing token and then try to recover the current state from the cursor to get some context for what were working on from there I was using the cached program to get varaibles and stuff this could be combined with sourcetree to get additonal information such as some program scope. Things I was considering: I was trying to leave room in my implementation so that we could look into recovering some parse state from the parser in the future this could be combined with the lexing approach to get a more accurate state of whats going on, addittionally I was trying to make sure adding new states didnt require touching the parsing logic instead it just required defining the state, handling the parsing seperatly from our completion states also would let us fall back to a simple parser like what reasonml does in their autocomplete engine for cases where we lose complete context. If anyone decides to take this up feel free to send me a message here or on discord and I give a better explanation of the technique I was trying to use if needed. |
This pr adds autocomplete to the grain language. I think we may want to expand this in the future. Possibly with a better parser to improve finding the current context of completion. Right now we just treat
=
as indicating you want value completions and:
as indicating you want type completions There are a few issues with this approach though, such as ew do not currently trigger completions1 + <here>
in the position of<here>
and other similar cases. we also mistreattype T =
as value completions currently, so some more consideration may need to be given on parsing rules. Im opening the pr now though as I am hoping to get feedback on parsing rules here.Another possible addition would be to try and use the
sourceTree
to give context, I didnt take this approach as in most casessourceTree
is very far behind where your autocompleting and not very helpful, it would have to be used in addition to the half parser though rather than as an alternative.Another possible future expansion is adding autocompletes to
include
s that scan the directory for.gr
files and suggest them. I think this could come in a later pr though, maybe after we determine the newinclude
syntax.Another possible future expansion would be adding snippet completions to keywords. but i feel this can come in a later pr.
This pr replaces: #1262, Thanks to marcus for the initial implementation from that pr.