hindent

Extensible Haskell pretty printer. Both a library and an
executable. Currently a work in progress (see
FIXME items).
Documentation
Install
$ cabal install hindent
You might need to cabal install happy if haskell-src-exts complains.
Usage
$ hindent
hindent: arguments: --style [fundamental|chris-done|johan-tibell|gibiansky]
Emacs
In
elisp/hindent.el
there is hindent-mode, which provides keybindings to reindent parts of the
buffer:
M-q reformats the current declaration. When inside a comment, it fills the
current paragraph instead, like the standard M-q.
C-M-\ reformats the current region.
To enable it, add the following to your init file:
(add-hook 'haskell-mode-hook #'hindent-mode)
By default it uses the style called fundamental, if you want to use
another, johan-tibell, run M-x customize-variable hindent-style. If you want to configure per-project, make a file
called .dir-locals.el in the project root directory like this:
((nil . ((hindent-style . "johan-tibell"))))
Vim
Basic support is provided through vim/hindent.vim,
which sets hindent as the formatter used by gq for haskell files. The formatting style
defaults to fundamental but can be configured by setting g:hindent_style to the desired style.
Note that unlike in emacs you have to take care of selecting a sensible buffer region as input to
hindent yourself. If that is too much trouble you can try vim-textobj-haskell which provides a text object for top level bindings.
Contributing your own printer style
This package comes with a basic fundamental pretty printer, which is
probably not desirable to use.
It comes with other styles implemented on top of this fundamental
printer, in the modules in HIndent.Styles.*.
Make a module HIndent.Styles.YourName in which to place the printer.
To define your own, see
HIndent.Styles.Fundamental
for a starting point. This module defines a blank style, adds no
additional extensions. Customizations are specified via the
styleExtenders property. See
HIndent.Styles.ChrisDone
for an example of a non-trivial style.
Useful combinators can be found in
HIndent.Pretty
for defining printers. When you want to use a fundamental printer, use
prettyNoExt instead of pretty. Comments will still be inserted by
prettyNoExt.
If you want to contribute it to the package, add it to the list of
styles in
HIndent
and export it, and open a pull request. Use
the Erlang git commit guide
for your commits.
Remaining issues
-
Add test suite.
-
Flesh out more obscure parts of the AST.
-
Improve comment re-insertion.
-
Possibly: Support formatting whole modules.
-
Implement some operator-specific layouts: e.g.
Foo <$> foo
<*> bar
<*> mu
Example
Input code:
foo = do print "OK, go"; foo (foo bar) -- Yep.
(if bar then bob else pif) (case mu {- cool -} zot of
Just x -> return (); Nothing -> do putStrLn "yay"; return 1) bill -- Etc
where potato Cakes {} = 2 * x foo * bar / 5
Fundamental
This is an intentionally very dumb style that demands extension.
foo =
do print
"OK, go"
foo
(foo
bar)
(if bar
then bob
else pif)
(case mu {- cool -}
zot of
Just x ->
return
()
Nothing ->
do putStrLn
"yay"
return
1)
bill -- Etc
where potato Cakes{} =
2 * x
foo * bar / 5
Johan Tibell
Documented in
the style guide.
This printer style uses some simple heuristics in deciding when to go
to a new line or not, and custom handling of do, if, case alts, rhs,
etc.
foo = do
print "OK, go"
foo
(foo bar)
(if bar
then bob
else pif)
(case mu {- cool -} zot of
Just x ->
return ()
Nothing -> do
putStrLn "yay"
return 1)
bill -- Etc
where
potato Cakes{} =
2 * x foo * bar / 5
Chris Done
My style is documented in
the style guide.
This printer style uses some simple heuristics in deciding when to go
to a new line or not.
foo =
do print "OK, go"
foo (foo bar)
(if bar
then bob
else pif)
(case mu {- cool -} zot of
Just x -> return ()
Nothing ->
do putStrLn "yay"
return 1)
bill -- Etc
where potato Cakes{} = 2 * x foo * bar / 5
Andrew Gibiansky
foo = do
print "OK, go"
foo (foo bar) -- Yep.
(if bar
then bob
else pif) (case mu {- cool -} zot of
Just x -> return ()
Nothing -> do
putStrLn "yay"
return 1) bill -- Etc
where
potato Cakes{} = 2 * x foo * bar / 5