2018-11-25 16:34:28 +03:00
|
|
|
|
# Ormolu
|
|
|
|
|
|
2018-11-25 17:09:03 +03:00
|
|
|
|
[![CircleCI](https://circleci.com/gh/tweag/ormolu/tree/master.svg?style=svg&circle-token=cfd37a39265561eb44e608f97cf953cb2a394c03)](https://circleci.com/gh/tweag/ormolu/tree/master)
|
|
|
|
|
|
2019-05-10 17:36:51 +03:00
|
|
|
|
Ormolu is a formatter for Haskell source code. The projects was created with
|
|
|
|
|
the following features in mind:
|
|
|
|
|
|
|
|
|
|
* Using GHC's own parser to avoid parsing problems caused by
|
|
|
|
|
[`haskell-src-exts`][haskell-src-exts].
|
2019-05-23 16:58:07 +03:00
|
|
|
|
* Let some whitespace be programmable. The layout of the input
|
|
|
|
|
influence the layout choices in the output. This means that the
|
|
|
|
|
choices between single-line/multi-line layouts in each particular
|
|
|
|
|
situation are made by the user, not by an algorithm. This makes the
|
|
|
|
|
implementation simpler and leaves some control to the user while
|
|
|
|
|
still guaranteeing that the formatted code is stylistically
|
|
|
|
|
consistent.
|
2019-05-16 19:45:45 +03:00
|
|
|
|
* Writing code in such a way so it's easy to modify and maintain. Roughly,
|
2019-05-10 17:36:51 +03:00
|
|
|
|
it means that the project follows the path of [`hindent`][hindent] and is
|
|
|
|
|
very much about printing AST in a particular way.
|
|
|
|
|
* Implementing one “true” formatting style which admits no configuration.
|
2019-05-17 13:18:01 +03:00
|
|
|
|
* That formatting style aims to result in minimal diffs while still
|
|
|
|
|
remaining very close to “conventional” Haskell formatting people use.
|
2019-05-10 17:36:51 +03:00
|
|
|
|
* Idempotency: formatting already formatted code doesn't change it.
|
|
|
|
|
* Be well-tested and robust to the point that it can be used in large
|
|
|
|
|
projects without exposing unfortunate, disappointing bugs here and there.
|
|
|
|
|
|
2019-05-30 14:56:42 +03:00
|
|
|
|
## Building
|
|
|
|
|
|
2019-05-31 15:37:41 +03:00
|
|
|
|
The easiest way to build the project is with Nix:
|
2019-05-30 14:56:42 +03:00
|
|
|
|
|
2019-05-31 15:37:41 +03:00
|
|
|
|
```console
|
|
|
|
|
$ nix-build
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Or with `cabal-install` from the Nix shell:
|
|
|
|
|
|
|
|
|
|
```console
|
|
|
|
|
$ nix-shell --run "cabal new-build"
|
2019-05-30 14:56:42 +03:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Alternatively, `stack` could be used with a `stack.yaml` file as follows.
|
2019-05-31 15:37:41 +03:00
|
|
|
|
|
|
|
|
|
```console
|
2019-05-30 14:56:42 +03:00
|
|
|
|
$ cat stack.yaml
|
2019-05-31 15:37:41 +03:00
|
|
|
|
resolver: lts-13.19
|
2019-05-30 14:56:42 +03:00
|
|
|
|
packages:
|
|
|
|
|
- '.'
|
2019-05-30 15:19:03 +03:00
|
|
|
|
|
|
|
|
|
$ stack build
|
2019-05-30 14:56:42 +03:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
|
|
The following will print the formatted output to the standard output.
|
2019-05-31 15:37:41 +03:00
|
|
|
|
|
|
|
|
|
```console
|
2019-05-30 14:56:42 +03:00
|
|
|
|
$ ormolu Module.hs
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Add `--mode inplace` to replace the contents of the input file with the
|
|
|
|
|
formatted output.
|
2019-05-31 15:37:41 +03:00
|
|
|
|
|
|
|
|
|
```console
|
2019-05-30 14:56:42 +03:00
|
|
|
|
$ ormolu --mode inplace Module.hs
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
A configuration file can specify the language extensions to use by default.
|
2019-05-31 15:37:41 +03:00
|
|
|
|
|
|
|
|
|
```console
|
2019-05-30 14:56:42 +03:00
|
|
|
|
$ cat ormolu.yaml
|
|
|
|
|
ghc-opts:
|
|
|
|
|
- -XLambdaCase
|
|
|
|
|
unsafe: False
|
|
|
|
|
debug: False
|
|
|
|
|
|
|
|
|
|
$ ormolu -c ormolu.yaml Module.hs
|
|
|
|
|
```
|
|
|
|
|
|
2019-05-10 17:36:51 +03:00
|
|
|
|
## Contribution
|
|
|
|
|
|
|
|
|
|
Issues (bugs, feature requests or otherwise feedback) may be reported in
|
|
|
|
|
[the GitHub issue tracker for this
|
|
|
|
|
project](https://github.com/tweag/ormolu/issues). Pull requests are also
|
|
|
|
|
welcome.
|
|
|
|
|
|
|
|
|
|
### What to hack on?
|
|
|
|
|
|
|
|
|
|
Right now there are two options for people who want to contribute:
|
|
|
|
|
|
2019-05-31 15:37:41 +03:00
|
|
|
|
* [Implementing rendering of AST][cover-ast]. This is the main focus right
|
|
|
|
|
now because we want to have a MVP which can render all syntactical
|
|
|
|
|
constructions found in Haskell source code. Once that is achieved we'll
|
|
|
|
|
polish the tool iteratively.
|
2019-05-10 17:36:51 +03:00
|
|
|
|
* [Fixing bugs][bugs]. If this seems more interesting than implementing
|
|
|
|
|
rendering of AST, you are welcome to do this as well.
|
|
|
|
|
|
|
|
|
|
### Implementing rendering of AST
|
|
|
|
|
|
|
|
|
|
The `Ormolu.Printer.Combinators` module provides a DSL for rendering of GHC
|
|
|
|
|
AST. You'll probably only need this one module for writing new rendering
|
|
|
|
|
functions. The module documents how to use the printing combinators it
|
2019-05-10 19:53:16 +03:00
|
|
|
|
provides. Consult the Haddocks to learn more about them.
|
2019-05-10 17:36:51 +03:00
|
|
|
|
|
|
|
|
|
Create new modules corresponding to the things you want to render under
|
|
|
|
|
`Ormolu.Printer.Meat`. For example, there are `Ormolu.Printer.Meat.Type` and
|
|
|
|
|
`Ormolu.Printer.Meat.Declaration.Data`.
|
|
|
|
|
|
2019-05-10 19:53:16 +03:00
|
|
|
|
Concrete rendering functions get their names by appending `p_` to the name
|
|
|
|
|
of the type which describes a particular part of AST. For example, the
|
|
|
|
|
function for rendering types is correspondingly:
|
2019-05-10 17:36:51 +03:00
|
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
|
p_hsType :: HsType GhcPs -> R ()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In general rendering functions like this take 1 or more arguments and
|
|
|
|
|
produce `R ()` which is a rendering action.
|
|
|
|
|
|
|
|
|
|
### Testing
|
|
|
|
|
|
|
|
|
|
Testing has been taken good care of and now it amounts to just adding
|
|
|
|
|
examples under `data/examples`. Each example is a pair of files:
|
|
|
|
|
`<example-name>.hs` for input and `<example-name>-out.hs` for corresponding
|
|
|
|
|
expected output.
|
|
|
|
|
|
|
|
|
|
Testing is performed as following:
|
|
|
|
|
|
|
|
|
|
* Given snippet of source code is parsed and pretty-printed.
|
|
|
|
|
* The result of printing is parsed back again and the AST is compared to the
|
|
|
|
|
AST obtained from the original file. They should match.
|
|
|
|
|
* The output of printer is checked against the expected output.
|
|
|
|
|
* Idempotency property is verified: formatting already formatted code
|
|
|
|
|
results in exactly the same output.
|
|
|
|
|
|
|
|
|
|
Examples can be organized in sub-directories, see the existing ones for
|
|
|
|
|
inspiration.
|
2018-11-25 16:34:28 +03:00
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
2019-05-23 20:57:32 +03:00
|
|
|
|
See [LICENSE](./LICENSE.md).
|
2019-05-23 16:58:07 +03:00
|
|
|
|
|
2019-03-21 17:43:58 +03:00
|
|
|
|
Copyright © 2018–2019 Tweag I/O
|
2019-05-10 17:36:51 +03:00
|
|
|
|
|
|
|
|
|
[haskell-src-exts]: https://hackage.haskell.org/package/haskell-src-exts
|
|
|
|
|
[hindent]: https://hackage.haskell.org/package/hindent
|
2019-05-31 15:37:41 +03:00
|
|
|
|
[cover-ast]: https://github.com/tweag/ormolu/issues?q=is%3Aissue+is%3Aopen+label%3Acovering-ghc-ast
|
2019-05-10 17:36:51 +03:00
|
|
|
|
[bugs]: https://github.com/tweag/ormolu/issues?q=is%3Aissue+is%3Aopen+label%3Abug
|