2018-11-25 16:34:28 +03:00
|
|
|
|
# Ormolu
|
|
|
|
|
|
2019-08-31 21:31:55 +03:00
|
|
|
|
[![License BSD3](https://img.shields.io/badge/license-BSD3-brightgreen.svg)](http://opensource.org/licenses/BSD-3-Clause)
|
|
|
|
|
[![Hackage](https://img.shields.io/hackage/v/ormolu.svg?style=flat)](https://hackage.haskell.org/package/ormolu)
|
|
|
|
|
[![Stackage Nightly](http://stackage.org/package/ormolu/badge/nightly)](http://stackage.org/nightly/package/ormolu)
|
|
|
|
|
[![Stackage LTS](http://stackage.org/package/ormolu/badge/lts)](http://stackage.org/lts/package/ormolu)
|
2023-01-02 20:47:39 +03:00
|
|
|
|
[![CI](https://github.com/tweag/ormolu/actions/workflows/ci.yml/badge.svg)](https://github.com/tweag/ormolu/actions/workflows/ci.yml)
|
2018-11-25 17:09:03 +03:00
|
|
|
|
|
2021-10-12 13:15:45 +03:00
|
|
|
|
* [Installation](#installation)
|
|
|
|
|
* [Building from source](#building-from-source)
|
2020-11-14 18:57:51 +03:00
|
|
|
|
* [Usage](#usage)
|
2021-10-21 19:07:45 +03:00
|
|
|
|
* [Ormolu Live](#ormolu-live)
|
2020-11-14 18:57:51 +03:00
|
|
|
|
* [Editor integration](#editor-integration)
|
2021-10-29 16:10:36 +03:00
|
|
|
|
* [Haskell Language Server](#haskell-language-server)
|
2020-11-16 00:14:25 +03:00
|
|
|
|
* [GitHub actions](#github-actions)
|
2022-05-03 18:00:21 +03:00
|
|
|
|
* [Language extensions, dependencies, and fixities](#language-extensions-dependencies-and-fixities)
|
2020-11-14 18:57:51 +03:00
|
|
|
|
* [Magic comments](#magic-comments)
|
2022-05-03 18:00:21 +03:00
|
|
|
|
* [Regions](#regions)
|
2020-11-14 18:57:51 +03:00
|
|
|
|
* [Exit codes](#exit-codes)
|
|
|
|
|
* [Limitations](#limitations)
|
|
|
|
|
* [Running on Hackage](#running-on-hackage)
|
2022-01-08 12:19:50 +03:00
|
|
|
|
* [Forks and modifications](#forks-and-modifications)
|
2020-11-14 18:57:51 +03:00
|
|
|
|
* [Contributing](#contributing)
|
|
|
|
|
* [License](#license)
|
|
|
|
|
|
2019-07-02 22:29:07 +03:00
|
|
|
|
Ormolu is a formatter for Haskell source code. The project was created with
|
2019-08-04 22:20:30 +03:00
|
|
|
|
the following goals in mind:
|
2019-05-10 17:36:51 +03:00
|
|
|
|
|
|
|
|
|
* Using GHC's own parser to avoid parsing problems caused by
|
|
|
|
|
[`haskell-src-exts`][haskell-src-exts].
|
2019-10-04 12:30:49 +03:00
|
|
|
|
* Let some whitespace be programmable. The layout of the input influences
|
|
|
|
|
the layout choices in the output. This means that the choices between
|
2020-11-14 19:07:01 +03:00
|
|
|
|
single-line/multi-line layouts in certain situations 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-10-04 12:30:49 +03:00
|
|
|
|
* Writing code in such a way so it's easy to modify and maintain.
|
2019-05-10 17:36:51 +03:00
|
|
|
|
* Implementing one “true” formatting style which admits no configuration.
|
2020-11-14 19:07:01 +03:00
|
|
|
|
* The formatting style aims to result in minimal diffs.
|
2019-10-04 12:30:49 +03:00
|
|
|
|
* Choose a style compatible with modern dialects of Haskell. As new Haskell
|
2020-09-04 05:41:23 +03:00
|
|
|
|
extensions enter broad use, we may change the style to accommodate them.
|
2019-10-04 12:30:49 +03:00
|
|
|
|
* Idempotence: formatting already formatted code doesn't change it.
|
2020-11-14 19:07:01 +03:00
|
|
|
|
* Be well-tested and robust so that the formatter can be used in large
|
|
|
|
|
projects.
|
2019-05-10 17:36:51 +03:00
|
|
|
|
|
2021-10-21 19:07:45 +03:00
|
|
|
|
Try it out in your browser at <https://ormolu-live.tweag.io>!
|
|
|
|
|
See [Ormolu Live](#ormolu-live) for more info.
|
|
|
|
|
|
2021-10-12 13:15:45 +03:00
|
|
|
|
## Installation
|
|
|
|
|
|
|
|
|
|
The [release page][releases] has binaries for Linux, macOS and Windows.
|
|
|
|
|
|
|
|
|
|
You can also install using `cabal` or `stack`:
|
|
|
|
|
|
|
|
|
|
```console
|
|
|
|
|
$ cabal install ormolu
|
|
|
|
|
$ stack install ormolu
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Ormolu is also included in several package repositories. E.g., on Arch Linux,
|
|
|
|
|
one can use [the package on AUR][aur]:
|
|
|
|
|
|
|
|
|
|
```console
|
|
|
|
|
$ yay -S ormolu
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Building from source
|
2019-05-30 14:56:42 +03:00
|
|
|
|
|
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
|
2023-01-02 20:47:20 +03:00
|
|
|
|
$ nix build
|
2019-05-31 15:37:41 +03:00
|
|
|
|
```
|
|
|
|
|
|
2023-01-02 20:47:39 +03:00
|
|
|
|
Make sure to accept the offered Nix caches (in particular the IOG cache),
|
|
|
|
|
otherwise building may take a very long time.
|
2021-09-13 13:10:32 +03:00
|
|
|
|
|
2021-09-15 15:26:56 +03:00
|
|
|
|
Alternatively, `stack` could be used as follows:
|
2019-05-31 15:37:41 +03:00
|
|
|
|
|
|
|
|
|
```console
|
2020-06-23 12:56:43 +03:00
|
|
|
|
$ stack build # to build
|
|
|
|
|
$ stack install # to install
|
2019-05-30 14:56:42 +03:00
|
|
|
|
```
|
|
|
|
|
|
2023-01-02 20:47:20 +03:00
|
|
|
|
To use Ormolu directly from GitHub with Nix flakes, this snippet may come in handy:
|
2019-09-11 13:12:32 +03:00
|
|
|
|
|
|
|
|
|
```nix
|
2023-01-02 20:47:20 +03:00
|
|
|
|
{
|
|
|
|
|
inputs.ormolu.url = "github:tweag/ormolu";
|
|
|
|
|
outputs = { ormolu, ... }: {
|
|
|
|
|
# use ormolu.packages.${system}.default here
|
|
|
|
|
};
|
|
|
|
|
}
|
2019-09-11 13:12:32 +03:00
|
|
|
|
```
|
|
|
|
|
|
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
|
|
|
|
|
```
|
|
|
|
|
|
2020-04-26 17:50:49 +03:00
|
|
|
|
Use `find` to format a tree recursively:
|
|
|
|
|
|
|
|
|
|
```console
|
|
|
|
|
$ ormolu --mode inplace $(find . -name '*.hs')
|
|
|
|
|
```
|
|
|
|
|
|
2021-04-12 23:27:33 +03:00
|
|
|
|
Or find all files in a project with `git ls-files`:
|
|
|
|
|
|
|
|
|
|
```console
|
|
|
|
|
$ ormolu --mode inplace $(git ls-files '*.hs')
|
|
|
|
|
```
|
|
|
|
|
|
2020-11-14 19:07:01 +03:00
|
|
|
|
To check if files are are already formatted (useful on CI):
|
|
|
|
|
|
|
|
|
|
```console
|
|
|
|
|
$ ormolu --mode check $(find . -name '*.hs')
|
|
|
|
|
```
|
|
|
|
|
|
2021-09-24 18:38:57 +03:00
|
|
|
|
#### :zap: Beware git's `core.autocrlf` on Windows :zap:
|
|
|
|
|
Ormolu's output always uses LF line endings. In particular,
|
|
|
|
|
`ormolu --mode check` will fail if its input is correctly formatted
|
|
|
|
|
*except* that it has CRLF line endings. This situation can happen on Windows
|
|
|
|
|
when checking out a git repository without having set [`core.autocrlf`](
|
|
|
|
|
https://www.git-scm.com/docs/git-config#Documentation/git-config.txt-coreautocrlf)
|
|
|
|
|
to `false`.
|
|
|
|
|
|
2021-10-21 19:07:45 +03:00
|
|
|
|
### Ormolu Live
|
|
|
|
|
|
|
|
|
|
On every new commit to `master`, [Ormolu Live](./ormolu-live) is deployed to
|
2021-11-01 19:11:41 +03:00
|
|
|
|
https://ormolu-live.tweag.io. Older versions are available at
|
|
|
|
|
https://COMMITHASH--ormolu-live.netlify.app.
|
2021-10-21 19:07:45 +03:00
|
|
|
|
|
2020-11-14 18:57:51 +03:00
|
|
|
|
### Editor integration
|
|
|
|
|
|
|
|
|
|
We know of the following editor integrations:
|
|
|
|
|
|
|
|
|
|
* [Emacs][emacs-package]
|
|
|
|
|
* [VS Code][vs-code-plugin]
|
2020-11-14 19:07:01 +03:00
|
|
|
|
* Vim: [neoformat][neoformat], [vim-ormolu][vim-ormolu]
|
2020-11-14 18:57:51 +03:00
|
|
|
|
|
2021-10-29 16:10:36 +03:00
|
|
|
|
### Haskell Language Server
|
|
|
|
|
|
|
|
|
|
[Haskell Language Server](https://haskell-language-server.readthedocs.io)
|
|
|
|
|
has built-in support for using Ormolu as a formatter.
|
|
|
|
|
|
2020-11-16 00:14:25 +03:00
|
|
|
|
### GitHub actions
|
|
|
|
|
|
|
|
|
|
[`ormolu-action`][ormolu-action] is the recommended way to ensure that a
|
|
|
|
|
project is formatted with Ormolu.
|
|
|
|
|
|
2022-05-03 18:00:21 +03:00
|
|
|
|
### Language extensions, dependencies, and fixities
|
|
|
|
|
|
|
|
|
|
Ormolu automatically locates the Cabal file that corresponds to a given
|
|
|
|
|
source code file. When input comes from stdin, one can pass
|
|
|
|
|
`--stdin-input-file` which will give Ormolu the location of the Haskell
|
|
|
|
|
source file that should be used as the starting point for searching for a
|
|
|
|
|
suitable Cabal file. Cabal files are used to extract both default extensions
|
|
|
|
|
and dependencies. Default extensions directly affect behavior of the GHC
|
|
|
|
|
parser, while dependencies are used to figure out fixities of operators that
|
|
|
|
|
appear in the source code. Fixities can also be overridden if `.ormolu` file
|
|
|
|
|
is found next to the corresponding Cabal file, i.e. they should be siblings
|
|
|
|
|
in the same directory.
|
|
|
|
|
|
|
|
|
|
Here is an example of `.ormolu` file:
|
|
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
|
infixr 9 .
|
|
|
|
|
infixr 5 ++
|
|
|
|
|
infixl 4 <$
|
|
|
|
|
infixl 1 >>, >>=
|
|
|
|
|
infixr 1 =<<
|
|
|
|
|
infixr 0 $, $!
|
|
|
|
|
infixl 4 <*>, <*, *>, <**>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
It uses exactly the same syntax as usual Haskell fixity declarations to make
|
|
|
|
|
it easier for Haskellers to edit and maintain.
|
|
|
|
|
|
|
|
|
|
Besides, all of the above-mentioned parameters can be controlled from the
|
|
|
|
|
command line:
|
|
|
|
|
|
|
|
|
|
* Language extensions can be specified with the `-o` or `--ghc-opt` flag.
|
|
|
|
|
* Dependencies can be specified with the `-p` or `--package` flag.
|
|
|
|
|
* Fixities can be specified with the `-f` or `--fixity` flag.
|
|
|
|
|
|
|
|
|
|
Searching for both `.cabal` and `.ormolu` files can be disabled by passing
|
|
|
|
|
`--no-cabal`.
|
|
|
|
|
|
2020-11-14 18:57:51 +03:00
|
|
|
|
### Magic comments
|
2020-04-20 18:24:42 +03:00
|
|
|
|
|
|
|
|
|
Ormolu understands two magic comments:
|
|
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
|
{- ORMOLU_DISABLE -}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
and
|
|
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
|
{- ORMOLU_ENABLE -}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This allows us to disable formatting selectively for code between these
|
|
|
|
|
markers or disable it for the entire file. To achieve the latter, just put
|
2020-09-17 13:18:08 +03:00
|
|
|
|
`{- ORMOLU_DISABLE -}` at the very top. Note that for Ormolu to work the
|
2021-09-14 12:06:58 +03:00
|
|
|
|
fragments where Ormolu is enabled must be parseable on their own. Because of
|
|
|
|
|
that the magic comments cannot be placed arbitrarily, but rather must
|
|
|
|
|
enclose independent top-level definitions.
|
2020-04-20 18:24:42 +03:00
|
|
|
|
|
2022-05-03 18:00:21 +03:00
|
|
|
|
### Regions
|
2021-08-11 12:57:27 +03:00
|
|
|
|
|
2022-05-03 18:00:21 +03:00
|
|
|
|
One can ask Ormolu to format a region of input and leave the rest
|
|
|
|
|
unformatted. This is accomplished by passing the `--start-line` and
|
|
|
|
|
`--end-line` command line options. `--start-line` defaults to the beginning
|
|
|
|
|
of the file, while `--end-line` defaults to the end.
|
2021-08-11 12:57:27 +03:00
|
|
|
|
|
2020-11-14 18:57:51 +03:00
|
|
|
|
### Exit codes
|
2020-11-14 18:51:34 +03:00
|
|
|
|
|
|
|
|
|
Exit code | Meaning
|
|
|
|
|
----------|-----------------------------------------------
|
|
|
|
|
0 | Success
|
|
|
|
|
1 | General problem
|
|
|
|
|
2 | CPP used (deprecated)
|
|
|
|
|
3 | Parsing of original input failed
|
|
|
|
|
4 | Parsing of formatted code failed
|
|
|
|
|
5 | AST of original and formatted code differs
|
|
|
|
|
6 | Formatting is not idempotent
|
|
|
|
|
7 | Unrecognized GHC options
|
2021-08-11 12:57:27 +03:00
|
|
|
|
8 | Cabal file parsing failed
|
|
|
|
|
9 | Missing input file path when using stdin input and accounting for .cabal files
|
2022-05-03 18:00:21 +03:00
|
|
|
|
10 | Parse error while parsing fixity overrides
|
2020-11-14 18:51:34 +03:00
|
|
|
|
100 | In checking mode: unformatted files
|
2021-10-12 16:12:28 +03:00
|
|
|
|
101 | Inplace mode does not work with stdin
|
2020-11-14 18:51:34 +03:00
|
|
|
|
102 | Other issue (with multiple input files)
|
|
|
|
|
|
2020-11-14 18:57:51 +03:00
|
|
|
|
## Limitations
|
2019-08-28 16:01:58 +03:00
|
|
|
|
|
2020-04-21 15:36:56 +03:00
|
|
|
|
* CPP support is experimental. CPP is virtually impossible to handle
|
|
|
|
|
correctly, so we process them as a sort of unchangeable snippets. This
|
2020-04-24 23:34:08 +03:00
|
|
|
|
works only in simple cases when CPP conditionals surround top-level
|
2020-11-14 19:07:01 +03:00
|
|
|
|
declarations. See the [CPP][design-cpp] section in the design notes for a
|
|
|
|
|
discussion of the dangers.
|
2019-09-17 14:16:47 +03:00
|
|
|
|
* Input modules should be parsable by Haddock, which is a bit stricter
|
2019-10-04 12:30:49 +03:00
|
|
|
|
criterion than just being valid Haskell modules.
|
2019-08-28 16:01:58 +03:00
|
|
|
|
|
2019-07-14 02:01:02 +03:00
|
|
|
|
## Running on Hackage
|
|
|
|
|
|
|
|
|
|
It's possible to try Ormolu on arbitrary packages from Hackage. For that
|
2019-10-04 12:30:49 +03:00
|
|
|
|
execute (from the root of the cloned repo):
|
2019-07-14 02:01:02 +03:00
|
|
|
|
|
|
|
|
|
```console
|
2023-01-02 20:47:20 +03:00
|
|
|
|
$ nix build .#hackage.<package>
|
2019-07-14 02:01:02 +03:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Then inspect `result/log.txt` for possible problems. The derivation will
|
2019-07-14 13:24:35 +03:00
|
|
|
|
also contain formatted `.hs` files for inspection and original inputs with
|
|
|
|
|
`.hs-original` extension (those are with CPP dropped, exactly what is fed
|
|
|
|
|
into Ormolu).
|
2019-07-14 02:01:02 +03:00
|
|
|
|
|
2022-01-08 12:19:50 +03:00
|
|
|
|
## Forks and modifications
|
|
|
|
|
|
|
|
|
|
We know of the following actively maintained forks:
|
|
|
|
|
|
|
|
|
|
* [Fourmolu][fourmolu], which uses 4-space indentation and allows arbitrary
|
|
|
|
|
configuration.
|
|
|
|
|
|
2019-05-31 16:27:42 +03:00
|
|
|
|
## Contributing
|
2019-05-10 17:36:51 +03:00
|
|
|
|
|
2019-10-22 22:58:57 +03:00
|
|
|
|
See [CONTRIBUTING.md][contributing].
|
2018-11-25 16:34:28 +03:00
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
2019-10-22 22:58:57 +03:00
|
|
|
|
See [LICENSE.md][license].
|
2019-05-23 16:58:07 +03:00
|
|
|
|
|
2019-07-02 22:27:45 +03:00
|
|
|
|
Copyright © 2018–present Tweag I/O
|
2019-05-10 17:36:51 +03:00
|
|
|
|
|
2020-11-16 00:14:25 +03:00
|
|
|
|
[aur]: https://aur.archlinux.org/packages/ormolu
|
|
|
|
|
[design-cpp]: https://github.com/tweag/ormolu/blob/master/DESIGN.md#cpp
|
2019-08-17 00:23:58 +03:00
|
|
|
|
[emacs-package]: https://github.com/vyorkin/ormolu.el
|
2020-11-16 00:14:25 +03:00
|
|
|
|
[haskell-src-exts]: https://hackage.haskell.org/package/haskell-src-exts
|
2020-03-26 23:46:33 +03:00
|
|
|
|
[neoformat]: https://github.com/sbdchd/neoformat
|
2021-10-12 13:15:45 +03:00
|
|
|
|
[releases]: https://github.com/tweag/ormolu/releases
|
2020-11-16 00:14:25 +03:00
|
|
|
|
[ormolu-action]: https://github.com/marketplace/actions/ormolu-action
|
|
|
|
|
[vim-ormolu]: https://github.com/sdiehl/vim-ormolu
|
|
|
|
|
[vs-code-plugin]: https://marketplace.visualstudio.com/items?itemName=sjurmillidahl.ormolu-vscode
|
2022-01-08 12:19:50 +03:00
|
|
|
|
[fourmolu]: https://github.com/fourmolu/fourmolu
|
|
|
|
|
[contributing]: https://github.com/tweag/ormolu/blob/master/CONTRIBUTING.md
|
|
|
|
|
[license]: https://github.com/tweag/ormolu/blob/master/LICENSE.md
|