Skip to content
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

Refactor symbol and completion item kinds #2000

Merged
merged 6 commits into from
Jul 24, 2022

Conversation

jwortmann
Copy link
Member

  • This defines sublime.Kind tuples, so that they can be reused for LSP's SymbolKinds and CompletionItemKinds, which have a lot of overlap and even had a few inconsistencies before.
  • Also they could easily be used for sublime.QuickPanelItem now.
  • No more awkward indexing with kind - 1
  • Moved the small lookup dicts for DocumentHighlightKind to core/views.py as well, because that seems to be the place where most of such things are defined.
  • Fixes a bug in views.py#format_completion, which would use an int instead of a kind tuple for the kind in sublime.CompletionItem.command_completion, in case there is a kind id in the language server response, which is out of range for LSP's CompletionItemKind.

Changes:

  • Removed "readwrite" from "variable.other.readwrite" scope of SymbolKind.Variable (dubious scope only used in JavaScript syntax - https://github.com/sublimehq/Packages/issues/1336).
  • Adjusted scope of SymbolKind.Boolean from "constant.language" to "constant.language.boolean" (used in various syntaxes).
  • Adjusted scope of SymbolKind.Null from "constant.language" to "constant.language.null" (used in various syntaxes).
  • Changed scope of SymbolKind.Event from "storage.modifier" to "entity.name.function" and kind id from sublime.KIND_ID_TYPE to sublime.KIND_ID_FUNCTION (I'm not entirely sure, but I think "Event" is meant to be things like onclick or onchange).
  • Changed scope of SymbolKind.TypeParameter from "storage.type" to "variable.parameter.type" (but keep the kind id as sublime.KIND_ID_TYPE). Ass far as I understand, the following is a type parameter (Java example):
    class ClassWithGenericType<T> {}
    //                         ^ Type parameter
  • Changed kind id of CompletionItemKind.Folder from sublime.KIND_ID_NAMESPACE to sublime.KIND_ID_NAVIGATION, so that it is consistent with CompletionItemKind.File
  • Changed kind id of SymbolKind.Interface from sublime.KIND_ID_VARIABLE to sublime.KIND_ID_TYPE, so that it is consistent with CompletionItemKind.Interface.
  • Changed kind id of SymbolKind.Operator from sublime.KIND_ID_FUNCTION to sublime.KIND_ID_KEYWORD, so that it is consistent with CompletionItemKind.Operator.
  • Changed kind id of SymbolKind.String from sublime.KIND_ID_MARKUP to sublime.KIND_ID_VARIABLE, so that it is consistent with SymbolKind.Number, SymbolKind.Boolean, SymbolKind.Null.

Copy link
Member

@rwols rwols left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. I do think we can optimize to use 1 dict lookup everywhere instead of 2.



def _enum_like_class_to_list(c: Type[object]) -> List[str]:
def _enum_like_class_to_list(c: Type[object]) -> List[Union[int, str]]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type should be Union[List[str], List[int]], or am I misunderstanding the use case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently that isn't possible, because mypy can't infer which one of the list types the return value is, when it is used later. See https://github.com/sublimelsp/LSP/runs/7490372297

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I guess I can add a type hint in this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can run mypy locally by running tox by the way

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, seems that Pyright and mypy disagree what to do with the type hint comment in f95c500.

So I guess I could revert to the initial return type List[Union[int, str]], or use # type: ignore for the failing line. Or do you see a better solution?

Thanks I will try to figure out how to run mypy locally.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, eventually it goes into some json anyway. For now it’s okay to use List[Union] :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, might not work with inheritance...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's postpone this to another PR and use List[Union] for now ;-)

Alternatively, there is also the enum module / IntEnum which could be used via https://github.com/packagecontrol/enum dependency.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EnumLike(Generic[T]) looks sweet, but like jwortmann I imagined something like https://docs.python.org/3/library/enum.html. Maybe postpone that until python 3.8 because I don't like more dependencies. Or use the EnumLike(Generic[T]) approach.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That more concise solution using EnumLike didn't really work as it wouldn't be possible to access class method without instantiating an object. And @staticmethod doesn't have access to cls. So it would have to be either the more repetitive solution or some other smart approach.

KIND_VALUE = (sublime.KIND_ID_VARIABLE, "v", "Value")
KIND_VARIABLE = (sublime.KIND_ID_VARIABLE, "v", "Variable")

COMPLETION_KINDS = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the reason for using a List was performance :) a list item lookup is an offset into a contiguous array. But, I guess the performance doesn't matter much. Maybe the dict is even faster, who knows? From what I understand dicts are implemented as hash maps. So a number is run through a hash function before doing an array offset index.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. As an alternative to the dict, I could use lists and add the fallback KIND_UNSPECIFIED = (sublime.KIND_ID_AMBIGUOUS, "?", "???") as a first entry in the list, then indexing with kind - 1 could also be avoided. But I guess the performance difference (if any) indeed shouldn't matter here and is orders of magnitude smaller than the display refresh time. So it probably doesn't have any impact and would only be a matter of style/preference. And for the lists, there was an additional check if 1 <= kind <= len(SYMBOL_KINDS), which might be even more overhead...

plugin/core/views.py Outdated Show resolved Hide resolved
plugin/symbols.py Outdated Show resolved Hide resolved
plugin/symbols.py Outdated Show resolved Hide resolved
plugin/symbols.py Outdated Show resolved Hide resolved
@rwols rwols merged commit 2be06be into sublimelsp:main Jul 24, 2022
@jwortmann jwortmann deleted the refactor-kinds branch July 24, 2022 21:44
rchl added a commit that referenced this pull request Jul 25, 2022
* main:
  Prevent failing to load all configs when one fails
  Refactor symbol and completion item kinds (#2000)
  Add Godot (GDScript) LSP instructions
  Add preview for resource files in LocationPicker
rchl added a commit that referenced this pull request Jul 25, 2022
* main:
  Prevent failing to load all configs when one fails
  Refactor symbol and completion item kinds (#2000)
  Add Godot (GDScript) LSP instructions
  Add preview for resource files in LocationPicker
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants