Extensible Haskell pretty printer. Both a library and an executable. Currently a work in progress (see FIXME items).
$ stack build --copy-bins
hindent is used in a pipeline style:
$ cat path/to/sourcefile.hs | hindent > outfile.hs
hindent: arguments: --style [fundamental|chris-done|johan-tibell|gibiansky|cramer]
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 standardM-q
.C-M-\
reformats the current region.
To enable it, add the following to your init file:
(add-to-list 'load-path "/path/to/hindent/elisp")
(require 'hindent)
(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"))))
The 'formatprg'
option lets you use an external program (like hindent) to
format your text. Put the following line into ~/.vim/ftplugin/haskell.vim
to set this option for Haskell files:
setlocal formatprg=hindent\ --style\ chris-done
Then you can format with hindent using gq
. Read :help gq
and help 'formatprg'
for more details.
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.
Basic support is provided through atom/hindent.coffee,
which adds hindent to atom menu with each available style. Mode should be installed as package into .atom\packages\${PACKAGE_NAME}
,
here is simple example of atom package.
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.
-
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
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
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
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
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
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
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