Skip to content

Improvements to struct field completion #202

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

Merged
merged 7 commits into from
Apr 25, 2020

Conversation

lukaszsamson
Copy link
Collaborator

With this PR elixir-ls is able to provide completions for map keys and struct fields in following cases

struct = %My{}
struct.f
struct = %My{}
%{struct | f
map = %{key: 123}
%{map | k
map = %{key: 123, nested: %{module: String}}
map.k
map.nested.m
map.nested.module.pri
atom = String
string.pri

@axelson
Copy link
Member

axelson commented Apr 16, 2020

Wow this looks like a really neat change! It would be nice if we could add some tests to go along with this (probably on the provider level instead of the server level).

@axelson
Copy link
Member

axelson commented Apr 16, 2020

Might be nice to add some docs to the Readme as well. That way users can know when to expect completion of struct fields to work.

@lukaszsamson lukaszsamson force-pushed the ls-struct-keys-completion branch from 8e9f869 to d645463 Compare April 18, 2020 07:58
@lukaszsamson
Copy link
Collaborator Author

@axelson I added tests and a doc section in readme. I also fixed a small LSP spec compliance bug in fa69c6c

Copy link
Member

@axelson axelson left a comment

Choose a reason for hiding this comment

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

This is looking great! However, I was able to cause an exception that I think it makes sense to handle.

Given this code:

  def receive_traces(%PrivCheck.Tracer{} = tracer) do
    IO.puts(tracer.
                   ^
  end

But where PrivCheck.Tracer is NOT a struct results in the completion completely failing and the following exception being raised:

06:43:15.012 [error] Process #PID<0.479.0> raised an exception
** (UndefinedFunctionError) function PrivCheck.Tracer.__struct__/0 is undefined or private
    PrivCheck.Tracer.__struct__()
    (elixir 1.10.2) lib/kernel.ex:2182: Kernel.struct/3
    (elixir_sense 1.0.1) lib/elixir_sense/core/struct.ex:20: ElixirSense.Core.Struct.get_fields/2
    (elixir_sense 1.0.1) lib/alchemist/helpers/complete.ex:263: Alchemist.Helpers.Complete.recurse_var/3
    (elixir_sense 1.0.1) lib/alchemist/helpers/complete.ex:220: Alchemist.Helpers.Complete.expand_call/3
    (elixir_sense 1.0.1) lib/alchemist/helpers/complete.ex:61: Alchemist.Helpers.Complete.run/2
    (elixir_sense 1.0.1) lib/elixir_sense/providers/suggestion.ex:485: ElixirSense.Providers.Suggestion.find_hint_mods_funcs/6
    (elixir_sense 1.0.1) lib/elixir_sense/providers/suggestion.ex:205: ElixirSense.Providers.Suggestion.find_all_except_struct_fields/7

Additionally I don't think we should return the __struct__ field as a completion. Maybe we should filter it out on the ElixirLS side?

There's also some minor text adjustments

@lukaszsamson
Copy link
Collaborator Author

Good catch @axelson, fixed in elixir_sense and dep updated.

Additionally I don't think we should return the struct field as a completion. Maybe we should filter it out on the ElixirLS side?

I've got mixed feelings about that. On one hand underscored symbols are meant to be hidden but on the other hand I happen to use them quite often. Similar issue applies to functions, macros, modules and types with @doc false. Should we hide them as well? In my opinion not. It's generally advisable to stick to public APIs while using libraries but when writing libraries you work mostly with your own private APIs.

Maybe we should just deprioritise private API completions and annotate them as such. If you agree, let's do it in another PR.

@axelson
Copy link
Member

axelson commented Apr 22, 2020

I've got mixed feelings about that. On one hand underscored symbols are meant to be hidden but on the other hand I happen to use them quite often. Similar issue applies to functions, macros, modules and types with @doc false. Should we hide them as well? In my opinion not. It's generally advisable to stick to public APIs while using libraries but when writing libraries you work mostly with your own private APIs.

I do have general feelings to you on private/hidden symbols. But for this in particular I'm suggesting to specifically hide __struct__ since I think users will very often be completing struct fields, and almost never want to complete the __struct__ field. i.e. code like a = %MyStruct{}; struct = a.struct. Instead, they could use pattern matching like %struct{} = %MyStruct{}` (but that's also very rarely needed).

Maybe we should just deprioritise private API completions and annotate them as such. If you agree, let's do it in another PR.

Agreed and agreed. Filed as #214

I'm going to run with this locally for a bit longer and see if I encounter any further issues.

Copy link
Member

@axelson axelson left a comment

Choose a reason for hiding this comment

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

This has been working well for me locally. And I'm excited for this change! ❤️

@axelson axelson merged commit a2a1f38 into elixir-lsp:master Apr 25, 2020
axelson added a commit that referenced this pull request Apr 25, 2020
@lukaszsamson lukaszsamson deleted the ls-struct-keys-completion branch April 26, 2020 16:16
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.

2 participants