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 +previewServer
So 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.2
And 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 */*.cabal
you'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!