| CARVIEW |
Navigation Menu
-
Notifications
You must be signed in to change notification settings - Fork 913
Description
We are starting to ship type hierarchy for Ruby in the Ruby LSP and we hit a few doubts about the intended experience is on certain cases. I'm going to divide the doubts below so that I can provide a detailed explanation for each.
Re-opening of an existing declaration
In Ruby, it's common to re-open the same namespace in different files, adding more declarations inside of it. For example:
# file1.rb
module Foo
class Bar
end
end
# file2.rb
module Foo
class Bar
end
end
# In this scenario, the declarations of both `Foo` and `Bar` are re-opened in the two filesA TypeHierarchyItem only supports a single document URI attached to it.
What is the expectation in this case? Should the server return the complete type hierarchy information, but pick one of the document URIs? Or should all re-openings be returned in the list?
Is this a limitation and multiple document URIs should be allowed for type hierarchy items?
Returning more than one item in the prepare request
The prepare request mentions the following: ...return a type hierarchy for the language element of given text document positions. However, it seems that only a single position is sent as part of the request parameters, but the response expected is a list of entries.
While trying to understand what to do for the doubt above this one, we attempted to return all re-openings of the same namespace in the prepare request, but noticed that it doesn't work. The only way to make it work is to return only one item inside of the response array.
Is this intentional? And if so, should we document that in the spec?
Show linearized type hierarchy or only direct ancestors
Another doubt that came up regarding the user experience is whether we should display the linearized ancestor chain or show only the direct chain. For example:
module Foo; end
module Bar
# Add Foo as an ancestor of Bar
include Foo
end
class Baz
# Add Bar as an ancestor of Baz
include Bar
endIn this example, the direct ancestor chain of Baz is just [Bar, Bar, Object] (Object is implicitly the parent class of all Ruby classes).
The linearized ancestor chain is [Baz, Bar, Foo, Object, Kernel, BasicObject], which includes the linearized ancestors of each ancestor present in the chain for Baz on top of the class itself.
Is the intention behind the feature to display the linearization or only the direct ancestors of a namespace? Or is it implementors choice?
Singleton classes
Finally, the last doubt is concerning Ruby's singleton class ancestors. In Ruby, every class or module has the regular ancestors and the singleton ancestors.
The regular ancestor chain is where instance methods are defined and searched for. The singleton ancestor chain is where static (class) methods are defined and searched for. For example:
class Foo
end
# Ancestors of Foo
[Foo, Object, Kernel, BasicObject]
# Ancestors of the singleton class of Foo
[<Class:Foo>, <Class:Object>, <Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]The distinction is important because Ruby developers can add ancestors that will only exist in the regular chain or in the singleton chain (through include or extend).
class Foo
include IncludedModule
extend ExtendedModule
end
# Ancestors of Foo
[Foo, IncludedModule, Object, Kernel, BasicObject]
# Ancestors of the singleton class of Foo
[<Class:Foo>, ExtendedModule, <Class:Object>, <Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]I'm not sure this concept exists for other languages, but for Ruby it would make perfect sense to have two actions: show attached type hierarchy (the regular one) and show singleton type hierarchy.
What is the recommendation to handle this case? Do we implement this as a custom menu item for the Ruby extension only? Is there interest in having something generic to handle these multiple hierarchy chains associated with the same namespace? Should we always display both at the same time in the UI?