RFC: Create `cabal fix` command
- Dominant language
- Haskell
- Stars
- 1.7k
- Forks
- 750
- Avg merge
- 4d 3h
- Merged PRs (30d)
- 28
Description
# Overview
So, it became clear in #5734 that the purpose of `cabal format` is **not**, in fact, to format your cabal files, which I was sad to hear because I was looking for a tool to do that for a while. The main reason appears to be because it operates on a `GenericPackageDescription` which doesn't maintain source file location (or things like `common` stanzas).
I propose that we create a `cabal fix` command with the following behaviour:
- Reformat the cabal files for your project, with sane defaults (but configurable, like indent offset)
- If you have a Haskell code formatter specified in the config, re-format changed files.
**_Don't let great be the enemy of good_**
Yes, it would be possibly to build a full parser like exists for `GPD`, and also store source file locations, how things were populated, etc., but we could get a pretty long way with a much simpler and dumber formatter. Simple things like: remove trailing whitespace, always leave 1 space after the `:`, two blank lines between stanzas, always hang "repeated fields" and put one per line (`build-depends`, `exposed-modules`, etc). Maybe it can't handle everything from the beginning, but if it can successfully format the majority of folks cabal files then I think that's a win.
## High Level Flow
1. Update `cabal check` to return different error code on parse failure vs. warning.
2. Add `cabal fix`, which makes sure the file parses first (via `cabal check`)
- If parsing fails, ask the user to fix the issues first.
- If parsing succeeds, continue on to re-formatting.
3. Save a copy of the current cabal file (.cabal-fix/cabal-file.cabal.bak.n)
4. Re-format the cabal file
- Don’t try to be too smart
- Can use a simplified package description (see below)
5. Verify parsing of re-formatted cabal file succeeds:
- If parsing fails, report failure and request a bug report be filed and revert file.
- If parsing succeeds, then done.
### Simplified Package Description
Since the majority of what we need to do doesn't care what an individual field or stanza represents, all we need to know is if the field is a single values field, a repeated field with optional commas, or a repeated field with required. This means we can use a much simpler package description and keep a list of which fields require different parsers/pretty printers. This should simplify the development greatly.
### Support undo/redo
In case the formatter messes something up, there should be an easy way to revert it. One simple scheme is described below:
`cabal fix --undo`
This will replace cabal-file.cabal with `.cabal-fix/cabal-file.cabal.bak.n` and move the current cabal file to `.cabal-fix/cabal-file.cabal.redo.n`
`cabal fix --redo`
This will replace `cabal-file.cabal` with `.cabal-fix/cabal-file.cabal.redo.n`
## Sample Formatted File
```
cabal-version: 2.4
name: myapp
version: 0.1.0.0
license: BSD-3-Clause
license-file: LICENSE
build-type: Simple
synopsis: My application synopsis. Should be short. One line.
description:
My application description. This is probably kinda long so we hang it
on the next line.
common common-deps
default-language: Haskell2010
ghc-options:
-Wall
-Wincomplete-uni-patterns
-Wincomplete-record-updates
-Wcompat
-Widentities
-Wredundant-constraints
-fhide-source-paths
-Wmissing-export-lists
-Wpartial-fields
build-depends:
base >=4.12 && <4.13,
library
import: common-deps
exposed-modules:
Myapp
hs-source-dirs: src
build-depends:
containers ^>=0.6,
executable myapp
import: common-deps
main-is: Main.hs
hs-source-dirs: app
build-depends:
myapp -any
```
## Prior Art
http://hackage.haskell.org/package/stylish-cabal (just found this, will check it out)
Edit: This looks like a good start, I'm personally not a fan of the indentation style, but I'll start by poking around in the code there and see what I can do.
## Implementation
I've been looking for little side project to write in Haskell for a while so I'd be willing to implement this.
/cc @phadej @vrom911
Contributor guide
Assessment
This issue has not been assessed yet.