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

Improving elm-mode's completion #121

Closed
purcell opened this issue Oct 23, 2017 · 6 comments
Closed

Improving elm-mode's completion #121

purcell opened this issue Oct 23, 2017 · 6 comments

Comments

@purcell
Copy link
Collaborator

purcell commented Oct 23, 2017

As discussed in #119 with @mewa and others, elm-mode's completion using elm-oracle isn't yet as great as it could be. For discussion, here's a plan to improve it. I may or may not get time to do this myself.

Firstly, why change anything? The current strategy is calling elm-oracle every time we want to complete a symbol, and caching the results. This can lead to a large cache which is complicated to manage, and there's a specific issue: when a file has import Date exposing Date, elm-oracle File.elm Date returns results including Wed, Thu etc., which are actually not visible in the current file. Pruning those bogus results in order to reliably give good completions requires an understanding of the current imports, which elm-mode has not applied so far. (There are some plans to fix this upstream, with little traction so far: see ElmCast/elm-oracle#13.)


The obvious approach: use the info from elm-imports-list (see acad691) to prune the elm-oracle completion results before returning them as candidates. In this case, the full list should be cached, and only later pruned, because the pruning will be affected by future edits of the imports list.

Pruning would use the (..) or (symA, symB) imports list to restrict the completions. Care would need to be taken with constructors for sum types. When using a qualified import name, special handling will again need to be applied.

The downside of this approach is still that the cache can get quite large: multiple query results can produce the same symbol information, and that must all be either de-duplicated or stored in memory.


Another idea is to move from guessing what query to pass to elm-oracle to instead building an accurate picture in elisp of what symbols are available for completion.

We would call elm-oracle separately for each of the imported modules, using the module's fully-qualified name as a query. This causes elm-oracle to return information about all the symbols in that module. We would cache the candidates in each module (storing them per-buffer or per-project, to account for different library versions). Locally-defined modules will return empty results, which we would also cache.

This gives us a mapping from fully-qualified module name to all the items in that module.

When performing completion, we would handle two distinct cases:

  • When the completion prefix contains one or more ".", we take all but the last chunk to be the module name, and look up candidates for the last (possibly-empty) chunk in the symbols cache. If the module name appears to be an "as" alias, we use the info from elm-imports-list (see acad691) to help us find the canonical module name.
  • When the completion prefix has no ".", we need to merge candidates from all of the imported modules that have been imported explicitly (e.g. with (..) or (map, andThen). This will require extension of elm-imports-list in order to return the unqualified imports list.

In both cases, we should also allow completion of module names listed in the import.

Once cached, this method should be fast and reliable. Feedback appreciated!


Note: given

import Html exposing (..)
import Html.Attributes exposing (..)

then elm-oracle Myfile.elm Html will return all the completions for both modules, so this will perhaps need to be taken into consideration.

@mewa
Copy link
Contributor

mewa commented Oct 23, 2017

First of all, thanks @purcell for formulating the current state.

As it happens, last night I was able to finish working on an update, which largely converges with the last suggested approach (which also seems to be more universal and should have better performance too). I didn't have the time to file a PR though, so I'll do that in a moment, so we can discuss the changes.

Currently it's caching the module results globally and file imports and their aliases on a per file basis. The aliases are turned to their original names and the global cache is queried for results.

@welf
Copy link

welf commented Oct 29, 2017

Another problem with completion is when I try to complete function name or types from imported libraries, and it contains more than two dots, completion doesn't filter completion variants according to what I type.

For example, when I import GraphQL.Client.Http module and want to type GraphQL.Client.Http.Error or GraphQL.Client.Http.sendQuery defined in this module, autocompletion doesn't react on my typing when I type function or type name:

elm-mode-issue

elm-mode-issue-1

The same situation is with other modules where you use more than one dot in a type or function name.

@purcell
Copy link
Collaborator Author

purcell commented Nov 11, 2017

@welf That's just how company works: it's not fuzzy, and only matches prefixes. However, you can hit "C-s" to jump to matching candidates.

@welf
Copy link

welf commented Nov 15, 2017

@purcell After the recent update, the company autocompletion works as expected. Thanks! :)

@purcell
Copy link
Collaborator Author

purcell commented Nov 16, 2017

After the recent update, the company autocompletion works as expected. Thanks! :)

@welf - great news!

@purcell
Copy link
Collaborator Author

purcell commented Mar 15, 2018

Now done, so closing.

@purcell purcell closed this as completed Mar 15, 2018
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

No branches or pull requests

3 participants