I spent this Sunday writing two small patches to cabal-fmt.
cabal-fmt reasonably assumes that the file it is formatting is a cabal package definition file. So it parses it as such. That is needed to correctly pretty print the fields, as some syntax, for example leading comma requires somewhat recent cabal-version: 2.2 (see Package Description Format Specification History for details).
However, there are other files using the same markup format, for example cabal.project files or cabal.haskell-ci configuration files used by haskell-ci tool. Wouldn't it be nice if cabal-fmt could format these as well. In cabal-fmt-0.1.4 you can pass -n or --no-cabal-fmt flag, to prevent cabal-fmt from parsing these files as cabal package file.
The downside is that the latest known cabal specification will be used. That shouldn't break cabal.haskell-ci files, but it might break cabal.project files if you are not careful. (Their parsing code is somewhat antique).
An example of reformatting the cabal.project of this blog:
--- a/cabal.project
+++ b/cabal.project
@@ -1,9 +1,7 @@
index-state: 2020-05-10T17:53:22Z
with-compiler: ghc-8.6.5
-
packages:
- "."
- pkg/gists-runnable.cabal
+ "."
+ pkg/gists-runnable.cabal
-constraints:
- hakyll +previewServer
+constraints: hakyll +previewServerSo satisfying.
Another addition are fragments. They are best illustrated by an example. Imagine you have a multi-package project, and you use haskell-ci to generate your .travis.yml. Each .cabal package file must have the same
...
tested-with: GHC ==8.4.4 || ==8.6.5 || ==8.8.3 || ==8.10.1
library
...Then you find out that GHC 8.8.4 and GHC-8.10.2 were recently released, and you want to update your CI configuration. Editing multiple files, with the same change. Busy work.
With cabal-fmt-0.1.4 you can create a fragment file, lets call it tested-with.fragment:
tested-with: GHC ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.2And then edit your package files with a cabal-fmt pragma ( the fragment is probably in the root directory of project, but .cabal files are inside a directory per package):
...
+-- cabal-fmt: fragment ../tested-with.fragment
tested-with: GHC ==8.4.4 || ==8.6.5 || ==8.8.3 || ==8.10.1
library
...Then when you next time run
cabal-fmt --inplace */*.cabalyou'll see the diff
...
-- cabal-fmt: fragment ../tested-with.fragment
-tested-with: GHC ==8.4.4 || ==8.6.5 || ==8.8.3 || ==8.10.1
+tested-with: GHC ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.2
library
...for all libraries. Handy!
Some design comments:
.cabal file and the fragment have to match. (To avoid mistakes).Finally, you can use cabal-fmt --no-cabal-fmt to format fragment files too, even they are reformatted when spliced.
cabal-fmt-0.1.4 is a small release. I made --no-cabal-file to scratch my itch, and fragments partly to highlight that not every feature can exist in Cabal, but is very fine for preprocessors. I do think that fragments could be very useful in bigger projects. Let me know!