haskell-language-server icon indicating copy to clipboard operation
haskell-language-server copied to clipboard

Feature Request: Automatic Expansion of uninitialized record fields

Open ProofOfKeags opened this issue 5 years ago • 19 comments

When a warning for "Fields of ‘SomeRecord’ not initialised: a, b, c, d" fires, I'd like a CodeAction that allows it to initialize all of those rows with typed holes.

Flow would look like this:

  1. let thing = SomeRecord{}
  2. Ctrl+'.' (or other code action trigger)
  3. ~~let thing = SomeRecord{}~~ --> let thing = SomeRecord { a = _, b = _, c = _, d = _ }

The reason that this is somewhat of a big deal is that in the presence of long record names with the conventional prefix based row names (someRecordA, someRecordB, ...), the typing for this is nontrivial and also entirely mechanical and so the editor is perfectly capable of doing this for me.

ProofOfKeags avatar Oct 04 '20 19:10 ProofOfKeags

More sophisticated versions of this could infer what fields are already initialized, and only supply the ones that are missing in this way.

ProofOfKeags avatar Oct 04 '20 19:10 ProofOfKeags

Is this something that belongs in ghcide or hls?

ProofOfKeags avatar Oct 04 '20 19:10 ProofOfKeags

Even cooler would be, agda supports straight up introducing the entire record. So 0.

let
  thing :: SomeRecordType 
  thing = _
  1. <introduce-record
let
  thing :: SomeRecordType 
  thing =
    SomeRecordType
      { field1 = _
      , ...
      }

googleson78 avatar Oct 04 '20 20:10 googleson78

I would say that i could be done in a plugin in hls, but not sure.

jneira avatar Oct 04 '20 20:10 jneira

@googleson78 yeah that's also great. That said, when the typedef expands (like many records do over time), I'd still like to be able to introduce the missing fields.

ProofOfKeags avatar Oct 04 '20 21:10 ProofOfKeags

Somewhat related, it would be nice to have a shortcut to convert from using the "normal" constructor to using record syntax.

For example if I have the following:

data Person = Person { firstName :: Text, lastName :: Text }

let p = Person "Robert" "Dupont"

Some shortcut could convert the second line to:

let p = Person { firstName = "Robert", lastName = "Dupont" }

antoine-fl avatar May 11 '21 13:05 antoine-fl

Now tactics has a code action: Wingman: Use constructor Person which converts

person :: Person
person = _

in

person :: Person
person = Person {firstName = _wf, lastName = _wg}

So i think the suggestion of @googleson78 is already covered.

It still misses the other two requests:

  • Person {} to Person {firstName = _wf, lastName = _wg}
  • Person wf wg to Person {firstName = _wf, lastName = _wg}

For the first one there is a dedicated ghc warning usable to add a quick fix:

• Fields of ‘Person’ not initialised: firstName, lastName
• In the expression: Person {}
  In an equation for ‘person’: person = Person {}typecheck(-Wmissing-fields)

So i would say it should not be very much dificult to get

jneira avatar Oct 04 '21 07:10 jneira

Had a look at the codebase and I think this might be a good start for me to start contributing. Can I attempt this issue?

My outline would be to add a code action for the Fields of '<X>' uninitialized warning. Right now, there is a code action for "suppress errors" so I suppose I can add an alternative quick fix as @jneira mentioned.

For suggestion 2 I'd probably have to have a look on how LHS detects if a token is a record constructor invoked using function syntax.

Hoping to spend the week on this 🤞

naufik avatar Oct 18 '21 02:10 naufik

@naufik nice! thanks for willing to contribute, feel free to ask anything here or in the chat channels.

jneira avatar Oct 18 '21 06:10 jneira

Is this still open for contributions?

salmanjnr avatar Mar 08 '22 22:03 salmanjnr

Hey @salman69e27, unfortunately when I picked this up I couldn't get the build env to work at the time and currently have time constraints to contribute. You can pick up

naufik avatar Mar 08 '22 23:03 naufik

Thank you @naufik . I will start working on it in a couple of days

salmanjnr avatar Mar 10 '22 17:03 salmanjnr

Contributions are welcome 🤗 I just want to point out, as it is not mentioned in the thread, that HLS already generates record fields when autocompleting a record constructor.

Is this good enough? Does it just need to be publicised more?

pepeiborra avatar Mar 10 '22 18:03 pepeiborra

The original request is really around having HLS intelligently expand any constructor that had a warning on "uninitialized record fields".

ProofOfKeags avatar Mar 11 '22 00:03 ProofOfKeags

This is, of course, an issue with my setup - but actions were trivially set up for me and I use them extensively, while I still haven't gotten around to making the record field autocomplete, so I would be happy with having this as a code action.

googleson78 avatar Mar 11 '22 10:03 googleson78

I'd like to work on this ticket! :)

dan-blank avatar Jun 10 '23 12:06 dan-blank

I'm working on this during Zurihac 2024.

akshaymankar avatar Jun 09 '24 09:06 akshaymankar

Just an update that my usecase is no longer covered either, since wingman is not maintained since 9.0 afaik

googleson78 avatar Jun 09 '24 09:06 googleson78

Update from me: I have a branch with something that kinda works, just adds some extra new lines (not sure what's going on). I will try to resolve it this weekend, if not I will create a draft for someone more experienced with ghc-exactprint to take a look.

akshaymankar avatar Jun 13 '24 10:06 akshaymankar