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

Make complete-prefix smarter about field projection expressions passed as -prefix #1751

Open
ncik-roberts opened this issue Apr 12, 2024 · 0 comments

Comments

@ncik-roberts
Copy link
Contributor

This is a feature request.

Request

complete-prefix -prefix "t." -position $POS -file $FILE should auto-complete to the fields of the record value t, even if $FILE doesn't currently have the text "t." at position POS.

This matches the current behavior of complete-prefix -prefix "M." -position $POS -file $FILE, which is to autocomplete to the bindings of module M, even if $FILE doesn't currently have the text "M." at position $POS.

Example

file.ml:

module M = struct
  type t = { a : int; b : int }
  let y = { a = 3; b = 4 }
end

let module_ = (* module cursor *)
let field (x : M.t) = (* field cursor *)

Current behavior:

$ module_cursor=6:15
$ field_cursor=7:23
$ complete-prefix -prefix "M." -file file.ml -position $module_cursor < file.ml | jq .value.entries[].name
"y"
"t"
"a"
"b"
$ complete-prefix -prefix "x." -file file.ml -position $field_cursor < file.ml | jq .value.entries[].name
"contents"
"CamlinternalAtomic"
# ...more unrelated bindings...

Requested behavior:

$ module_cursor=6:15
$ field_cursor=7:23
$ complete-prefix -prefix "M." -file file.ml -position $module_cursor < file.ml | jq .value.entries[].name
"y"
"t"
"a"
"b"
$ complete-prefix -prefix "x." -file file.ml -position $field_cursor < file.ml | jq .value.entries[].name
"a"
"b"
# I don't care what comes next

Rationale

This can allow for better caching behavior in merlin.

If the file contents remain unchanged from merlin's view while the user is entering a field projection expression like M.foo.bar, then merlin will not have to re-parse and re-typecheck the file after every keypress in order to continue providing completion results.

Concretely, if the user starts with this file:

module M = struct
  module N = struct
    type t = { a : int; b : int }
  
    let y = { a = 3; b = 4 }
  end
end

let go (x : M.N.t) = (* cursor is here *)

If the user types M.N.y. at the point of the cursor, there are two ways you could imagine the editor making successive completion requests for M., M.N., and M.N.y.:

  • Sending updated file contents to merlin for each request (where the (* cursor is here *) is replaced with M., M.N., etc. successively)
  • Sending the same file contents to merlin for each request, and just varying the -prefix argument to complete-prefix.

The second approach enjoys better caching from merlin. The second approach works well for M. and M.N., because merlin tries to understand -prefix as a module path and tries to look up its components in the environment, one at a time. However, it doesn't work for M.N.y. as merlin's special handling of -prefix doesn't currently extend to record field projection.

@catern is working on the editor-side of a change to get better caching behavior out of merlin and so may correct me if I've said something inaccurate. The editor change becomes simpler if merlin handles field projection too.

Technical detail

These two code paths are different right now:

  • Generating field name completion results on a record field projection
  • Generating completion results for a module's binding on a module path

Merlin only tries to generate field name completion results if the original file contents have something that type-checks as a record field projection at the requested position.

Merlin clearly does some name analysis on some -prefix arguments: that's how it handles module paths. You could imagine extending this analysis to work for records.

If any of the components of -prefix that appear prior to a . are in lowercase, that means that the argument could be treated as record field projection, and merlin could look up the type of the lowercase identifiers in the appropriate environments in order to service the request for the appropriate field names. Examples:

  • foo.
  • foo.bar.
  • foo.Bar.
  • foo.bar.Baz.quux.
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

1 participant