haskell / haskell-language-server

Official haskell ide support via language server (LSP). Successor of ghcide & haskell-ide-engine.
Apache License 2.0
2.72k stars 368 forks source link

Fourmolu plugin formats code differently compared to separate installation of fourmolu #3788

Closed ollimandoliini closed 1 year ago

ollimandoliini commented 1 year ago

Your environment

Which OS do you use? MacOS

Which version of GHC do you use and how did you install it? 9.6.2 from GHCUp

How is your project built (alternative: link to the project)?

Which LSP client (editor/plugin) do you use? VSCode and vscode-haskell

Which version of HLS do you use and how did you install it? 2.2.0.0 from GHCUp

Have you configured HLS in any way (especially: a hie.yaml file)? Whether you have fourmolu.yaml or not doesn't change the behaviour.

Steps to reproduce

Have the HLS configured to use the built-in installation of fourmolu and run the formatting command.

foo :: Maybe Int -> Int
foo = undefined

thing :: Int
thing =
    foo $ Just $
            case undefined of
                True -> 1
                False -> 2

Expected behaviour

The could should be formatted with the following output like a separate installation of fourmolu-0.13.1.0 does.

foo :: Maybe Int -> Int
foo = undefined

thing :: Int
thing =
    foo $
        Just $
            case undefined of
                True -> 1
                False -> 2

Actual behaviour

Running VSCode's formatting command while having HLS use the built-in fourmolu will format the code to the following form:

foo :: Maybe Int -> Int
foo = undefined

thing :: Int
thing =
    foo
        $ Just
        $ case undefined of
            True -> 1
            False -> 2

Debug information

vscode-haskell outputs the following log entry:

2023-09-03T12:47:51.063236Z | Debug | fourmolu: Using compiled in fourmolu-0.13.1.0
michaelpj commented 1 year ago

Sounds like we're somehow using different configuration to what the CLI fourmolu is getting?

fendor commented 1 year ago

Yes, I theorised the fixity of ($) might be known in HLS but not on the cli.

michaelpj commented 1 year ago

That sounds likely. It's unfortunate that using the extra information we have in HLS can let us do better formatting, but make https://github.com/haskell/haskell-language-server/issues/411 worse.

ollimandoliini commented 1 year ago

That makes sense.

I'm also curious why HLS formats it the way that it does? To me the one formatting that separate fourmolu produces looks nicer and more similar to how what's commonly used in Haskell ecosystem in general.

michaelpj commented 1 year ago

I guess that's a question for the fourmolu devs. If our guess is correct, that's just what fourmolu does if it knows the fixity of $.

brandonchinn178 commented 1 year ago

Yes, that's simply the behavior when Fourmolu doesn't know the fixity of an operator. Some follow up questions:

  1. What if you tell HLS to use an external fourmolu (i.e. the CLI version)?
  2. What's the structure of your project? Do you have a cabal file? Is your module mentioned in it?
  3. Are you using NoImplicitPrelude or a custom prelude or otherwise hiding Prelude? Have you configured the reexports configuration correctly?
  4. How are you invoking the fourmolu CLI? How are you specifying the files?
ollimandoliini commented 1 year ago
  1. The formatting is the same as when using the CLI directly.
  2. I created the project using cabal init with cabal version 3.10.1.0. It only has app/Main.hs module and it's mentioned in the cabal file.
  3. No and no.
  4. By calling fourmolu --mode inplace . from the project root.
brandonchinn178 commented 1 year ago

hm I don't use HLS, so I'm not sure how much help I'd be here.

@ollimandoliini it seems like you have a pretty basic set up. Does it work if you're in a completely separate directory (e.g. /tmp/my-project/) with just a single Haskell file without a Cabal file in any parent directories? If it does work, can you provide a full minimal repro?

@georgefst do you have any idea?

georgefst commented 1 year ago

@georgefst do you have any idea?

Not yet, but I'll try to look in to this as soon as I can. I do have a pretty big backlog of Fourmolu stuff that I want to at least comment on, but this might be the highest priority. It's just hit me and it's super annoying. Although for now, I seem to be getting away with switching back to non-CLI mode (EDIT: ah, I misread that OP is already using this mode - I may just be running in to https://github.com/haskell/haskell-language-server/pull/3421). Though this won't necessarily work for people who aren't wanting to use 0.14.

Vlix commented 1 year ago

I can confirm that I also stumbled upon this issue of the HLS Fourmolu plugin formatting very differently than just the executable. I've worked around it by adding most fixities in the fourmolu.yaml, which seems to have made it behave again (and work the same as running the executable separately.

georgefst commented 1 year ago

Yes, I theorised the fixity of ($) might be known in HLS but not on the cli.

Fortunately it's the opposite, which is easier to fix!

I do also intend, in a separate PR, to modify the external Fourmolu mode to (at least have the option to) avoid passing --no-cabal in order to more straightforwardly replicate using the formatter outside HLS.