hindent: Extensible Haskell pretty printer

[ bsd3, development, library, program ] [ Propose Tags ]

Extensible Haskell pretty printer. Both a library and an executable.

See the Github page for usage/explanation: https://github.com/chrisdone/hindent


[Skip to Readme]

Downloads

Note: This package has metadata revisions in the cabal description newer than included in the tarball. To unpack the package including the revisions, use 'cabal get'.

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.0, 1.0, 2.0, 2.1, 2.2, 2.3, 2.4, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 3.9.1, 4.0, 4.1.0, 4.1.1, 4.2.0, 4.2.1, 4.2.2, 4.2.3, 4.2.4, 4.3.0, 4.3.1, 4.3.2, 4.3.3, 4.3.4, 4.3.5, 4.3.6, 4.3.7, 4.3.8, 4.3.9, 4.3.10, 4.3.11, 4.3.12, 4.4.0, 4.4.1, 4.4.2, 4.5.0, 4.5.1, 4.5.2, 4.5.3, 4.5.4, 4.5.5, 4.5.6, 4.5.7, 4.6.0, 4.6.1, 4.6.2, 4.6.3, 4.6.4, 5.0.0, 5.0.1, 5.1.0, 5.1.1, 5.2.0, 5.2.1, 5.2.2, 5.2.3, 5.2.4, 5.2.4.1, 5.2.5, 5.2.6, 5.2.7, 5.3.0, 5.3.1, 5.3.2, 5.3.3, 5.3.4, 6.0.0, 6.1.0, 6.1.1 (info)
Dependencies base (>=4.8 && <5), containers, descriptive (>=0.7 && <0.10), directory, ghc-prim, haskell-src-exts (>=1.17 && <1.18), hindent, monad-loops, mtl, text, transformers [details]
License BSD-3-Clause
Copyright 2014 Chris Done
Author Chris Done, Andrew Gibiansky, Tobias Pflug, Pierre Radermecker
Maintainer chrisdone@gmail.com
Revised Revision 3 made by HerbertValerioRiedel at 2016-08-26T11:45:17Z
Category Development
Home page http://www.github.com/chrisdone/hindent
Bug tracker https://github.com/chrisdone/hindent/issues
Source repo head: git clone https://github.com/chrisdone/hindent
Uploaded by ChrisDone at 2016-07-15T10:28:13Z
Distributions Debian:5.3.1, LTSHaskell:6.1.1, NixOS:6.1.1, Stackage:6.1.1
Reverse Dependencies 4 direct, 0 indirect [details]
Executables hindent-generate-tests, hindent
Downloads 63683 total (308 in the last 30 days)
Rating 2.25 (votes: 2) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2016-07-15 [all 1 reports]

Readme for hindent-4.6.4

[back to package description]

hindent Hackage Build Status

Extensible Haskell pretty printer. Both a library and an executable. Currently a work in progress (see FIXME items).

Documentation

Install

$ stack build --copy-bins

Usage

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]

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-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"))))

Vim

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.

Atom

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.

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

Enno Cramer

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