-
Notifications
You must be signed in to change notification settings - Fork 31
Conversation
Thanks for posting a gif example 👍 |
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.
works!!! 🥇
it_completes("A", %w(Array Atomic ArgumentError AtExitHandlers)) | ||
it_completes("JSON::P", %w(ParseException Parser PullParser)) | ||
it_completes("JSON::Pa", %w(ParseException Parser)) | ||
it_completes("JSO", %w(JSON JSON::Any JSON::Builder JSON::Error JSON::Lexer JSON::Lexer::IOBased JSON::Lexer::StringBased JSON::ParseException JSON::Parser JSON::PullParser JSON::Token)) |
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.
Can you add a spec for completion after JSON::
?
And after ::
? (if it works)
src/scry/completion/method_db.cr
Outdated
@@ -20,6 +20,10 @@ module Scry::Completion | |||
end.select(&.name.starts_with? text).to_a | |||
end | |||
|
|||
def type_match(text : String) : Array(String) | |||
@db.keys.select(&.starts_with?(text)).reject(&.ends_with?(".class")) |
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.
select!
reject!
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.
@bew Why? are mutable methods faster?
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.
Yeah I think so, they don't allocate a new array each time.
@@ -53,39 +57,54 @@ module Scry::Completion | |||
|
|||
class Visitor < Crystal::Visitor | |||
property classes | |||
property class_name = "" |
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.
I think it's better to use nil
to denote the absence of class_name
, so the compiler can help you instead of doing empty checks.
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.
I think it's easier with an empty string cause we only interpolate stuff, otherwise I'll have to use not_nil! calls
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.
I don't agree, I think it's always better to use the typing system for this kind of case.
For example in visit(node : Crystal::Def)
where you use it, I'd use:
class_name = @class_name || raise CustomError.new
if node.name == "initialize"
name = "new"
method_receiver = "#{@class_queue.last}.class"
return_type = @class_queue.last
method_receiver = "#{class_name}.class"
return_type = class_name
else
name = node.name
method_receiver = node.receiver ? "#{@class_queue.last}.class" : @class_queue.last
method_receiver = node.receiver ? "#{class_name}.class" : class_name
end
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.
@class_name is assigned the value of the generate_classname which will be an empty string if the queues are empty.
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.
property class_name : String?
and
if this_class_name = class_name
# Use this_cass_name here...
end
WDYT?
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.
Although I see no issues with initializing the class_name = ""
@bew Is this a bad practice or something? 😅
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.
I'll simply say:
method_receiver = node.receiver ? "#{@class_name}.class" : @class_name
In this case, does it make sense (allowed) to have @class_name
as an empty string?
I don't think so, so it must be made difficult/impossible to do.
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.
that won't happen cause if class_name is "" then class_queue is empty and in here we opt out
scry/src/scry/completion/method_db.cr
Line 73 in d05348c
return false if @class_queue.empty? || node.visibility != Crystal::Visibility::Public |
he idea of the classname is just to cache the output of generate_class_name which never returns nil, so initialising it as nil doesn't seem like the right way to handle it.
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.
@laginha87 Oh, ok, I think class_name = ""
is not that bad @bew WDYT?
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.
yeah let's not block the PR for a tiny non-straight-forward thing like that, it's ok
@classes[node.name.to_s] = [] of MethodDBEntry | ||
@class_queue << node.name.to_s | ||
@class_queue << node.name | ||
@class_name = generate_name(@module_queue + @class_queue) |
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.
Does this still work if you have a module inside a class inside a module?
Why are you separating module & classes queues?
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.
oh, I didn't even know that could happen
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.
It's seperate cause we only store methods for class, for now.
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.
@bew I tried to change this to use classes and modules in the same queue but started getting some tests failing not really sure why. I cut a new branch to add this and module functions as well.
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.
can you create a new issue to track and not forget this? It's quite important
thanks
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.
Also, include what you tried and your results, it might help find the actual problem ;)
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.
I got a pull request https://github.com/crystal-lang-tools/scry/pull/117/files
Should there be a matching issue ?
…om/crystal-lang-tools/scry into laginha87-add-classname-completion
@@ -136,8 +136,11 @@ module Scry | |||
context "classname completion" do | |||
_kind_ = CompletionItemKind::Class | |||
it_completes("A", %w(Array Atomic ArgumentError AtExitHandlers)) | |||
it_completes(" ::A", %w(Array Atomic ArgumentError AtExitHandlers)) | |||
it_completes(" ::", %w()) |
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 nothing? It should give every top level classes & constants
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.
@bew I think listing all classes would be very slow 😅 , no?
By example on Workspace symbols, if query is empty, you get this:
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.
@faustinoaq you're showing symbols here, not completion.
Slow? I don't know.
So for now it only gives an empty list? Maybe that's ok
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.
I couldn't figure out why it didn't return anything :(
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.
No problem, I think is ok 👍
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.
@laginha87 let's not block this pr as it's not so important, but please open an issue to keep track of ::
completion, and fix it one day, or decide what we do about it
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.
I actually wanna tackle doing a context aware comlpetion for this at some point .
for example:
module A
::
should complete with modules and classes inside A as well
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.
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.
@laginha87 there is no need for contextual completion, ::
completions will ALWAYS be the top level things, that's what it exists for, there is no contextual things going on for types that starts with ::
@crystal-lang-tools/scry Can we get another review here? |
@bew, thanks for reviewing the code, can you approve this or is there something I missed? |
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.
Looks good overall 😃
a.", %w(method) | ||
end | ||
end | ||
|
||
context "classname completion" do |
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.
Note: it can also complete module names (and structs), not only class names, maybe change the spec name?
|
||
context "classname completion" do | ||
_kind_ = CompletionItemKind::Class | ||
it_completes("A", %w(Array Atomic ArgumentError AtExitHandlers)) |
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 means that this spec rely on external code... A change to the stdlib, an addition/removal of a class starting with A
will break this spec...
There are other problems with how the specs currently works, like:
- You can't add a description of what that spec is actually spec-ing
- They rely on external code (see above)
- They are not self-contained: by just reading the spec you don't directly have all the data to understand it (you have to always lookup other files, AND they are shared between many specs)
This should probably go to a new issue though. I'm just too tired right now ^^
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.
- The test will always break with changes to stdlib, we are testing the autocomplete on it I don't think it's something we should worry about.
- What other files do you have to check to understand the specs? My idea for this file was to have tests that almost did an end-to-end test on the completion features and not dependant on the actual implementation.
def find | ||
target_header_index = @target.rindex(":") | ||
@method_db.type_match(@target).map do |label| | ||
label = label[(target_header_index + 1)..-1] if target_header_index |
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.
just a style comment: At first I didn't saw the if
at the end of the line, and was wondering 'how the hell does that compile..."
I think that line is too 'complicated' / 'long' for a suffix if
, and would suggest to make it a multi-line if
.
label: label, | ||
insert_text: label, | ||
kind: CompletionItemKind::Class, | ||
detail: label, |
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 it be better to have the full path (e.g: JSON::Any
, not just Any
) in details? (can someone test this, see how it goes?)
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.
you mean in the CompletionItem class ?
src/scry/completion/method_db.cr
Outdated
@@ -20,6 +20,10 @@ module Scry::Completion | |||
end.select(&.name.starts_with? text).to_a | |||
end | |||
|
|||
def type_match(text : String) : Array(String) | |||
@db.keys.select!(&.starts_with?(text)).reject!(&.ends_with?(".class")) |
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.
@db.keys.select! { |k| k.starts_with?(text) && !k.ends_with?(".class") }
? (less allocations / simpler logic / ...)
0d319ea
to
8e91d84
Compare
@bew thanks for the review 👍 |
Actually it's not important |
@@ -1,6 +1,6 @@ | |||
require "./tree" | |||
|
|||
class A | |||
class B |
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.
By "looking another file to understand the specs" I meant this file!
@laginha87 Thank you! 🎉 |
Hi all
This adds autocomplete for class names and module names.
It doesn't show any documentation for it yet.
Will add a gif to demo.