packages feed

ormolu 0.8.1.1 → 0.8.2.0

raw patch · 68 files changed

+708/−317 lines, 68 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Ormolu.Printer.Combinators: enterLayout :: Layout -> R () -> R ()
+ Ormolu.Printer.Meat.ImportExport: enterMultilineLayoutIfContainsDocEntries :: [LIE GhcPs] -> R () -> R ()
- Ormolu.Imports: normalizeImports :: [LImportDecl GhcPs] -> [LImportDecl GhcPs]
+ Ormolu.Imports: normalizeImports :: Choice "implicitPrelude" -> [LImportDecl GhcPs] -> [LImportDecl GhcPs]
- Ormolu.Printer: printSnippets :: Bool -> [SourceSnippet] -> Text
+ Ormolu.Printer: printSnippets :: Choice "debug" -> [SourceSnippet] -> Text
- Ormolu.Printer.Combinators: runR :: R () -> SpanStream -> CommentStream -> SourceType -> EnumSet Extension -> ModuleFixityMap -> Bool -> Text
+ Ormolu.Printer.Combinators: runR :: R () -> SpanStream -> CommentStream -> SourceType -> EnumSet Extension -> ModuleFixityMap -> Choice "debug" -> Text
- Ormolu.Printer.Internal: runR :: R () -> SpanStream -> CommentStream -> SourceType -> EnumSet Extension -> ModuleFixityMap -> Bool -> Text
+ Ormolu.Printer.Internal: runR :: R () -> SpanStream -> CommentStream -> SourceType -> EnumSet Extension -> ModuleFixityMap -> Choice "debug" -> Text
- Ormolu.Printer.Meat.Common: p_infixDefHelper :: Bool -> Bool -> R () -> [R ()] -> R ()
+ Ormolu.Printer.Meat.Common: p_infixDefHelper :: Choice "infixStyle" -> Choice "indentArgs" -> R () -> [R ()] -> R ()
- Ormolu.Processing.Preprocess: preprocess :: Bool -> RegionDeltas -> Text -> [Either Text RegionDeltas]
+ Ormolu.Processing.Preprocess: preprocess :: Choice "cppEnabled" -> RegionDeltas -> Text -> [Either Text RegionDeltas]

Files

CHANGELOG.md view
@@ -1,3 +1,42 @@+## Ormolu 0.8.2.0++* Overhaul how operator fixity information is collected. In addition to the+  Hoogle database, Ormolu now parses the sources of a curated set of important+  packages directly, which yields more accurate and complete fixity data than+  before. In particular it recovers fixities for operators re-exported through+  umbrella modules (e.g. `Servant.API`, `Control.Lens`) that recent Hoogle+  databases no longer record. As a result, formatting of operator chains is+  improved out of the box, and users should expect some operator-heavy code to+  be laid out differently (and more correctly) than in previous releases.++* Improve the layout of chains of `infixr 0` operators (`$`, `seq`, `?:`, and+  the like). Such operators are only laid out in the trailing "staircase" style+  when it is warranted: either the chain consists of a single operator, or its+  final operand is a hanging construct (a `do` block, lambda, `case`, etc.). A+  chain of several such operators that ends in an ordinary expression is now+  laid out with the operators in the leading position instead of an+  ever-deepening pyramid. [Issue+  1151](https://github.com/tweag/ormolu/issues/1151).++* Do not crash when a parent directory cannot be read due to insufficient+  permissions while searching for configuration files; the search for+  configuration files is stopped at that point instead. [Issue+  1212](https://github.com/tweag/ormolu/issues/1212).++* Preserve blank lines between blocks in layout contexts (`where`, `do`,+  `let`) when the preceding block ends with a trailing comment. [Issue+  1132](https://github.com/tweag/ormolu/issues/1132).++* Fix printing of single line export lists with inlined Haddock comments.+  [Issue 1051](https://github.com/tweag/ormolu/issues/1051).++* Fix preservation of the position of comments around the `where` keyword.+  [Issue 784](https://github.com/tweag/ormolu/issues/784).++* Do not sort `Prelude` to the end of the import list when the+  `NoImplicitPrelude` extension is enabled; instead sort it like any other+  import. [Issue 1189](https://github.com/tweag/ormolu/issues/1189).+ ## Ormolu 0.8.1.1  * Add missing braces for case expressions in single‑line do blocks. [Issue@@ -8,7 +47,7 @@  ## Ormolu 0.8.1.0 -* Fixed printing of guards on pattern binds. [Issue+* Fix printing of guards on pattern binds. [Issue   1178](https://github.com/tweag/ormolu/issues/1178).  * Switched to `ghc-lib-parser-9.14`, with the following new syntactic features:@@ -26,10 +65,10 @@ * Correctly preserve consecutive blank lines in multiline strings. [Issue   1194](https://github.com/tweag/ormolu/issues/1194). -* Fixed printing of multi-line or-patterns inside as-patterns. [Issue+* Fix printing of multi-line or-patterns inside as-patterns. [Issue   1183](https://github.com/tweag/ormolu/issues/1183). -* Fixed an issue where or-patterns would be indented twice. [Issue+* Fix an issue where or-patterns would be indented twice. [Issue   1188](https://github.com/tweag/ormolu/issues/1188).  * Add support for `ExplicitLevelImports`. [Issue@@ -37,7 +76,7 @@  ## Ormolu 0.8.0.2 -* Fixed a performance regression introduced in 0.8.0.0. [Issue+* Fix a performance regression introduced in 0.8.0.0. [Issue   1176](https://github.com/tweag/ormolu/issues/1176).  ## Ormolu 0.8.0.1@@ -305,7 +344,7 @@  ## Ormolu 0.5.0.1 -* Fixed a bug in the diff printing functionality. [Issue+* Fix a bug in the diff printing functionality. [Issue   886](https://github.com/tweag/ormolu/issues/886).  * Indent closing bracket for list comprehensions in `do` blocks.@@ -554,7 +593,7 @@ * Now `--mode check` fails on missing trailing blank lines. [Issue   743](https://github.com/tweag/ormolu/issues/743). -* Fixed indentation of arrow forms in do blocks. [Issue+* Fix indentation of arrow forms in do blocks. [Issue   739](https://github.com/tweag/ormolu/issues/739).  ## Ormolu 0.1.4.1@@ -567,7 +606,7 @@ * Added support for monad comprehensions. [Issue   665](https://github.com/tweag/ormolu/issues/665). -* Fixed a bug when a space was inserted in front of promoted types even when+* Fix a bug when a space was inserted in front of promoted types even when   it wasn't strictly necessary. [Issue   668](https://github.com/tweag/ormolu/issues/668). @@ -577,7 +616,7 @@  ## Ormolu 0.1.3.1 -* Fixed a problem with multiline record updates using the record dot+* Fix a problem with multiline record updates using the record dot   preprocessor. [Issue 658](https://github.com/tweag/ormolu/issues/658).  ## Ormolu 0.1.3.0@@ -593,7 +632,7 @@  ## Ormolu 0.1.2.0 -* Fixed the bug when comments in different styles got glued together after+* Fix the bug when comments in different styles got glued together after   formatting. [Issue 589](https://github.com/tweag/ormolu/issues/589).  * Added `-i` as a shortcut for `--mode inplace`. [Issue@@ -618,48 +657,48 @@ * Improved sorting of operators in imports. [Issue   602](https://github.com/tweag/ormolu/issues/602). -* Fixed a bug related to trailing space in multiline comments in certain+* Fix a bug related to trailing space in multiline comments in certain   cases. [Issue 603](https://github.com/tweag/ormolu/issues/602).  * Added support for formatting linked lists with `(:)` as line terminator.   [Issue 478](https://github.com/tweag/ormolu/issues/478). -* Fixed rendering of function arguments in multiline layout. [Issue+* Fix rendering of function arguments in multiline layout. [Issue   609](https://github.com/tweag/ormolu/issues/609).  * Blank lines between definitions in `let` and `while` bindings are now   preserved. [Issue 554](https://github.com/tweag/ormolu/issues/554). -* Fixed the bug when type applications stuck to the `$` of TH splices that+* Fix the bug when type applications stuck to the `$` of TH splices that   followed them. [Issue 613](https://github.com/tweag/ormolu/issues/613).  * Improved region formatting so that indented fragments—such as definitions   inside of `where` clauses—can be formatted. [Issue   572](https://github.com/tweag/ormolu/issues/572). -* Fixed the bug related to the de-association of pragma comments. [Issue+* Fix the bug related to the de-association of pragma comments. [Issue   619](https://github.com/tweag/ormolu/issues/619).  ## Ormolu 0.1.0.0 -* Fixed rendering of type signatures concerning several identifiers. [Issue+* Fix rendering of type signatures concerning several identifiers. [Issue   566](https://github.com/tweag/ormolu/issues/566). -* Fixed an idempotence issue with inline comments in tuples and parentheses.+* Fix an idempotence issue with inline comments in tuples and parentheses.   [Issue 450](https://github.com/tweag/ormolu/issues/450). -* Fixed an idempotence issue when certain comments were picked up as+* Fix an idempotence issue when certain comments were picked up as   “continuation” of a series of comments [Issue   449](https://github.com/tweag/ormolu/issues/449). -* Fixed an idempotence issue related to different indentation levels in a+* Fix an idempotence issue related to different indentation levels in a   comment series. [Issue 512](https://github.com/tweag/ormolu/issues/512). -* Fixed an idempotence issue related to comments which may happen to be+* Fix an idempotence issue related to comments which may happen to be   separated from the elements they are attached to by the equality sign.   [Issue 340](https://github.com/tweag/ormolu/issues/340). -* Fixed an idempotence issue with type synonym and data declarations where+* Fix an idempotence issue with type synonym and data declarations where   the type has a Haddock. [Issue   578](https://github.com/tweag/ormolu/issues/578). @@ -667,17 +706,17 @@   multiple blank lines in a row. [Issue   518](https://github.com/tweag/ormolu/issues/518). -* Fixed rendering of comments around if expressions. [Issue+* Fix rendering of comments around if expressions. [Issue   458](https://github.com/tweag/ormolu/issues/458).  * Unnamed fields of data constructors are now documented using the `-- ^`   syntax. [Issue 445](https://github.com/tweag/ormolu/issues/445) and [Issue   428](https://github.com/tweag/ormolu/issues/428). -* Fixed non-idempotent transformation of partly documented data definition.+* Fix non-idempotent transformation of partly documented data definition.   [Issue 590](https://github.com/tweag/ormolu/issues/590). -* Fixed an idempotence issue related to operators. [Issue+* Fix an idempotence issue related to operators. [Issue   522](https://github.com/tweag/ormolu/issues/522).  * Renamed the `--check-idempotency` flag to `--check-idempotence`.@@ -704,7 +743,7 @@   select a region to format. [Issue   516](https://github.com/tweag/ormolu/issues/516). -* Fixed rendering of module headers in the presence of preceding comments or+* Fix rendering of module headers in the presence of preceding comments or   Haddocks. [Issue 561](https://github.com/tweag/ormolu/issues/561).  ## Ormolu 0.0.4.0@@ -725,7 +764,7 @@   now put on its own line. [Issue   509](https://github.com/tweag/ormolu/issues/509). -* Fixed the bug pertaining to rendering of arrow notation with multiline+* Fix the bug pertaining to rendering of arrow notation with multiline   expressions. [Issue 513](https://github.com/tweag/ormolu/issues/513).  * Made rendering of data type definitions, value-level applications, and@@ -743,15 +782,15 @@  ## Ormolu 0.0.3.1 -* Fixed rendering of record updates with the record dot preprocessor syntax+* Fix rendering of record updates with the record dot preprocessor syntax   [Issue 498](https://github.com/tweag/ormolu/issues/498).  ## Ormolu 0.0.3.0 -* Fixed an issue related to unnecessary use of curly braces. [Issue+* Fix an issue related to unnecessary use of curly braces. [Issue   473](https://github.com/tweag/ormolu/issues/473). -* Fixed the issue with formatting multi-way if when it happens to be a+* Fix the issue with formatting multi-way if when it happens to be a   function applied to arguments [Issue   488](https://github.com/tweag/ormolu/issues/488). This changed the way   multi-line if is formatted in general.@@ -763,7 +802,7 @@   potentially-hanging consturctions in the presence of comments. [Issue   447](https://github.com/tweag/ormolu/issues/447). -* Fixed indentation in presence of type applications. [Issue+* Fix indentation in presence of type applications. [Issue   493](https://github.com/tweag/ormolu/issues/493).  * Class and instance declarations now do not have a blank line after@@ -781,20 +820,20 @@ * Now unrecognized GHC options passed with `--ghc-opt` cause Ormolu to fail   (exit code 7). -* Fixed formatting of result type in closed type families. See [issue+* Fix formatting of result type in closed type families. See [issue   420](https://github.com/tweag/ormolu/issues/420). -* Fixed a minor inconsistency between formatting of normal and foreign type+* Fix a minor inconsistency between formatting of normal and foreign type   signatures. See [issue 408](https://github.com/tweag/ormolu/issues/408). -* Fixed a bug when comment before module header with Haddock was moved+* Fix a bug when comment before module header with Haddock was moved   inside the export list. See [issue   430](https://github.com/tweag/ormolu/issues/430).  * Empty `forall`s are now correctly preserved. See [issue   429](https://github.com/tweag/ormolu/issues/429). -* Fixed [issue 446](https://github.com/tweag/ormolu/issues/446), which+* Fix [issue 446](https://github.com/tweag/ormolu/issues/446), which   involved braces and operators.  * When there are comments between preceding Haddock (pipe-style) and its@@ -814,7 +853,7 @@ * Sorting language pragmas cannot not change meaning of the input program   anymore. [Issue 404](https://github.com/tweag/ormolu/issues/404). -* Fixed formatting of applications where function is a complex expression.+* Fix formatting of applications where function is a complex expression.   [Issue 444](https://github.com/tweag/ormolu/issues/444).  ## Ormolu 0.0.1.0
CONTRIBUTING.md view
@@ -33,7 +33,7 @@ inspiration.  Please note that we try to keep individual files at most 25 lines long-because otherwise it's hard to figure out want went wrong when a test fails.+because otherwise it's hard to figure out what went wrong when a test fails.  To regenerate outputs that have changed, you can set the `ORMOLU_REGENERATE_EXAMPLES` environment variable before running tests.@@ -49,4 +49,4 @@  If Ormolu is not formatted like this, the CI will fail. -[issues]: https://github.com/tweag/ormolu/issues+[issues]: https://github.com/mrkkrp/ormolu/issues
DESIGN.md view
@@ -19,10 +19,10 @@     * [Why not contribute to/fork Hindent or Brittany?](#why-not-contribute-tofork-hindent-or-brittany) * [Examples](#examples) -This document describes design of a new formatter for Haskell source code.+This document describes the design of a new formatter for Haskell source code. It also includes recommendations for future implementers. -We set for the following goals (mostly taken from+We set the following goals (mostly taken from [brittany](https://github.com/lspitzner/brittany)): * Preserve the meaning of the formatted functions when no CPP is used; * Make reasonable use of screen space;@@ -38,12 +38,12 @@ ### Brittany  [Brittany][brittany] builds on top of [`ghc-exactprint`][ghc-exactprint]—a-library that uses parser of GHC itself for parsing and thus it guarantees-that at least parsing phase is bug-free (which is admittedly the cause of-majority of bugs in other projects, see below).+library that uses the parser of GHC itself for parsing and thus it guarantees+that at least the parsing phase is bug-free (which is admittedly the cause of+the majority of bugs in other projects, see below). -After parsing, Haskell AST and a collection of annotations are available.-The annotations are there because Haskell AST doesn't provide enough+After parsing, the Haskell AST and a collection of annotations are available.+The annotations are there because the Haskell AST doesn't provide enough information to reconstruct source code (for example it doesn't include comments). The AST and the annotations are converted into a `BriDoc` value. A `BriDoc` value is a document representation like the `Doc` from the@@ -71,7 +71,7 @@ ### Hindent  [Hindent][hindent] uses [`haskell-src-exts`][haskell-src-exts] for parsing-like all older projects. `haskell-src-exts` does not use parser of GHC+like all older projects. `haskell-src-exts` does not use the parser of GHC itself, and is a source of endless parsing bugs. `Hindent` is affected by these upstream issues as well as Stylish Haskell and Haskell formatter (see below). This already makes all these projects unusable with some valid@@ -83,13 +83,13 @@ that the 70-80% of what the code does is a printing traversal.  Hindent code is easier to read and debug. Pretty-printing functions are-very straightforward. If there is a bug (in pretty-printer, not in parser+very straightforward. If there is a bug (in the pretty-printer, not in the parser which Hindent cannot control), it's easy to fix AFAIU.  Hindent is also notable for its ability to handle CPP and inputs that do not-constitute complete modules. It splits input stream into so-called “code+constitute complete modules. It splits the input stream into so-called “code blocks” recognizing CPP macros and then only pretty-prints “normal code”-without touching CPP directives. After that CPP is inserted between+without touching CPP directives. After that, CPP is inserted between pretty-printed blocks of source code. The approach fails when CPP breaks code in such a way that separate blocks do not form valid Haskell expressions, see@@ -98,20 +98,20 @@ Looking at the bug tracker there are many bugs. Part of them is because of the use of `haskell-src-exts`, the other part is because the maintainer doesn't care (anymore?) and doesn't fix them. Well it's as simple as that,-with any sort of commercial backing the bugs in pretty printer would be-fixed long time ago.+with any sort of commercial backing the bugs in the pretty printer would+have been fixed a long time ago.  ### Stylish Haskell  [Stylish Haskell][stylish-haskell] also uses `haskell-src-exts` and suffers from the same upstream problems. I haven't studied the transformations it performs, but it looks like it transforms the parsed source code partially-by manipulating AST and partially by manipulating raw text (e.g. to drop-trailing whitespace from each line). CPP Macros are just filtered out+by manipulating the AST and partially by manipulating raw text (e.g. to drop+trailing whitespace from each line). CPP macros are just filtered out silently as a preprocessing step before feeding the code to `haskell-src-exts`. -Stylish Haskell is not so invasive as the other formatters and most reported+Stylish Haskell is not as invasive as the other formatters and most reported bugs are about parsing issues and CPP. As I understand it, people mostly use it to sort their import lists. @@ -147,7 +147,7 @@  There are the following challenges when formatting a module with CPP: -* GHC parser won't accept anything but a valid, complete module. Therefore,+* The GHC parser won't accept anything but a valid, complete module. Therefore,   formatting the Haskell code between CPP directives is not an option.  * Ignoring the CPP directives and formatting the Haskell code can change@@ -226,7 +226,7 @@ code to avoid changing the meaning by reformatting. But this would introduce additional complexity, and the problem would need to be solved repeatedly for every tool out there which wants-to parse Haskell modules. If CPP is replaced with some language+to parse Haskell modules. If CPP is replaced by some language extension or mechanism to do conditional compilation, all tools will benefit from it. @@ -313,7 +313,7 @@ might be used in multiple projects, and we prefer to have it formatted the same in all of them. -See this [this+See [this post][hindent-5-blog] by Chris Done (the author of Hindent) which says that as long as the default style is conventional and good it doesn't really matter how code gets formatted. Consistency is more important.@@ -323,10 +323,10 @@ Some language extensions affect how parsing is done. We are going to deal with those in two ways: -* When language pragmas are present in source file, we must parse them+* When language pragmas are present in the source file, we must parse them   before we run the main parser (I guess) and they should determine how the   main parsing will be done.-* There also should be configuration file that may enable other language+* There should also be a configuration file that may enable other language   extensions to be used on all files. * Later we could try to locate Cabal files and fetch the list of extensions   that are enabled by default from there.@@ -337,11 +337,11 @@ pretty-printing code and new issues are discovered. For each Haskell module that we want to test, we perform the following steps: -1. Given input snippet of source code parse it and pretty print it.-2. Parse the result of pretty-printing again and make sure that AST is the-   same as AST of original snippet module span positions. We could make+1. Given an input snippet of source code, parse it and pretty print it.+2. Parse the result of pretty-printing again and make sure that the AST is the+   same as the AST of the original snippet module span positions. We could make    this part of a self-check in the formatter.-3. Check the output against expected output. Thus all tests should include+3. Check the output against the expected output. Thus all tests should include    two files: input and expected output. 4. Check that running the formatter on the output produces the same output    again (the transformation is idempotent).@@ -387,7 +387,7 @@ `haskell-src-exts` with `ghc` (or `ghc-exact-print`) then we'll have to work with a different AST type and all the code in Hindent will become incompatible and there won't be much code to be reused in that case. It is-also possible that we'll find a nicer way to write pretty-printer.+also possible that we'll find a nicer way to write the pretty-printer.  ## Examples 
LICENSE.md view
@@ -1,4 +1,4 @@-Copyright © 2018–present Tweag I/O+Copyright © 2018–2026 Tweag I/O, 2026–present Mark Karpov  All rights reserved. @@ -12,7 +12,7 @@   notice, this list of conditions and the following disclaimer in the   documentation and/or other materials provided with the distribution. -* Neither the name Tweag I/O nor the names of contributors may be used to+* Neither the names Tweag I/O and Mark Karpov nor the names of contributors may be used to   endorse or promote products derived from this software without specific   prior written permission. 
README.md view
@@ -4,7 +4,7 @@ [![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)-[![CI](https://github.com/tweag/ormolu/actions/workflows/ci.yml/badge.svg)](https://github.com/tweag/ormolu/actions/workflows/ci.yml)+[![CI](https://github.com/mrkkrp/ormolu/actions/workflows/ci.yml/badge.svg)](https://github.com/mrkkrp/ormolu/actions/workflows/ci.yml)  * [Installation](#installation) * [Building from source](#building-from-source)@@ -46,7 +46,7 @@ * Be well-tested and robust so that the formatter can be used in large   projects. -Try it out in your browser at <https://ormolu-live.tweag.io>!+Try it out in your browser at <https://ormolu-live.markkarpov.com>! See [Ormolu Live](#ormolu-live) for more info.  ## Installation@@ -75,9 +75,24 @@ $ nix build ``` -Make sure to accept the offered Nix caches (in particular the IOG cache),-otherwise building may take a very long time.+Make sure to accept the offered Nix binary caches, otherwise building may+take a very long time. The flake declares the relevant caches (the IOG cache+and the project's own `ormolu.cachix.org`, which is populated by CI) via its+`nixConfig`, but Nix only uses them if you allow it to. The simplest way is+to pass `--accept-flake-config`: +```console+$ nix build --accept-flake-config+```++To avoid repeating the flag, add the following to your Nix configuration+(`/etc/nix/nix.conf`, or `nix.settings` on NixOS):++```+extra-substituters = https://cache.iog.io https://ormolu.cachix.org+extra-trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= ormolu.cachix.org-1:0L9Y4A+6dGpvfGtaeaq5w44pgX0AVRivKMfi2fiOzYE=+```+ Alternatively, `stack` could be used as follows:  ```console@@ -89,7 +104,7 @@  ```nix {-  inputs.ormolu.url = "github:tweag/ormolu";+  inputs.ormolu.url = "github:mrkkrp/ormolu";   outputs = { ormolu, ... }: {     # use ormolu.packages.${system}.default here   };@@ -140,8 +155,8 @@ ### Ormolu Live  On every new commit to `master`, [Ormolu Live](./ormolu-live) is deployed to-https://ormolu-live.tweag.io. Older versions are available at-https://COMMITHASH--ormolu-live.netlify.app.+https://ormolu-live.markkarpov.com. Older versions are available at+https://COMMITHASH--ormolu.netlify.app.  ### Editor integration @@ -345,17 +360,17 @@  See [LICENSE.md][license]. -Copyright © 2018–present Tweag I/O+Copyright © 2018–2026 Tweag I/O, 2026–present Mark Karpov  [aur]: https://aur.archlinux.org/packages/ormolu-[design-cpp]: https://github.com/tweag/ormolu/blob/master/DESIGN.md#cpp+[design-cpp]: https://github.com/mrkkrp/ormolu/blob/master/DESIGN.md#cpp [emacs-package]: https://github.com/vyorkin/ormolu.el [haskell-src-exts]: https://hackage.haskell.org/package/haskell-src-exts [neoformat]: https://github.com/sbdchd/neoformat-[releases]: https://github.com/tweag/ormolu/releases+[releases]: https://github.com/mrkkrp/ormolu/releases [run-ormolu]: https://github.com/haskell-actions/run-ormolu [vim-ormolu]: https://github.com/sdiehl/vim-ormolu [vs-code-plugin]: https://marketplace.visualstudio.com/items?itemName=sjurmillidahl.ormolu-vscode [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+[contributing]: https://github.com/mrkkrp/ormolu/blob/master/CONTRIBUTING.md+[license]: https://github.com/mrkkrp/ormolu/blob/master/LICENSE.md
+ data/examples/declaration/value/function/case-with-comment-before-where-out.hs view
@@ -0,0 +1,14 @@+foo =+  case x of+    _ -> 1+  -- comment+  where+    -- comment 2+    x = 1++foo = case x of+  _ -> 1+  -- comment+  where+    -- comment 2+    x = 1
+ data/examples/declaration/value/function/case-with-comment-before-where.hs view
@@ -0,0 +1,14 @@+foo =+  case x of+    _ -> 1+    -- comment+    where+      -- comment 2+      x = 1++foo = case x of+    _ -> 1+    -- comment+    where+      -- comment 2+      x = 1
data/examples/declaration/value/function/infix/dollar-chains-1-out.hs view
@@ -13,9 +13,9 @@     throwIO (OrmoluCppEnabled path)  foo =-  bar $-    baz $-      quux+  bar+    $ baz+    $ quux  x =   case l of { A -> B } $
data/examples/declaration/value/function/infix/dollar-chains-3-out.hs view
@@ -1,11 +1,11 @@ ex1 =-  f1 $-    arg1 $-      arg2 $-        arg3+  f1+    $ arg1+    $ arg2+    $ arg3  ex3 =-  f1 $-    arg1 $-      arg2 $-        1 + 3+  f1+    $ arg1+    $ arg2+    $ 1 + 3
data/examples/declaration/value/function/infix/dollar-chains-4-out.hs view
@@ -1,5 +1,5 @@ ex2 =-  f1 $-    arg1 $-      arg2 $-        f2 arg3+  f1+    $ arg1+    $ arg2+    $ f2 arg3
data/examples/declaration/value/function/infix/lenses-out.hs view
@@ -1,14 +1,14 @@ import Control.Lens  lenses =-  Just $-    M.fromList $-      "type" .= ("user.connection" :: Text)-        # "connection" .= uc-        # "user" .= case name of-          Just n -> Just $ object ["name" .= n]-          Nothing -> Nothing-        # []+  Just+    $ M.fromList+    $ "type" .= ("user.connection" :: Text)+      # "connection" .= uc+      # "user" .= case name of+        Just n -> Just $ object ["name" .= n]+        Nothing -> Nothing+      # []  foo =   a
data/examples/declaration/value/function/infix/op-chain-r-eq-dollar-1-out.hs view
@@ -1,11 +1,11 @@ -- Right chain, $ case, 2 operators with p($) == p(b) n :: Int n =-  1 $-    2 $-      3 $-        4 `seq`-          5 $-            6 $-              7 $-                8+  1+    $ 2+    $ 3+    $ 4+    `seq` 5+    $ 6+    $ 7+    $ 8
data/examples/declaration/value/function/infix/op-chain-r-eq-dollar-2-out.hs view
@@ -1,11 +1,11 @@ -- Right chain, $ case, 2 operators with p(a) == p($) p :: Int p =-  1 `seq`-    2 `seq`-      3 `seq`-        4 $-          5 `seq`-            6 `seq`-              7 `seq`-                8+  1+    `seq` 2+    `seq` 3+    `seq` 4+    $ 5+    `seq` 6+    `seq` 7+    `seq` 8
data/examples/declaration/value/function/infix/op-chain-r-s-dollar-out.hs view
@@ -1,7 +1,7 @@ -- Right chain, $ case, 1 operator type c :: Int c =-  1 $-    2 $-      3 $-        4+  1+    $ 2+    $ 3+    $ 4
data/examples/declaration/value/function/infix/qualified-ops-out.hs view
@@ -1,9 +1,9 @@ lenses =-  Just $-    M.fromList $-      "type" Foo..= ("user.connection" :: Text)-        Bar.# "connection" Foo..= uc-        Bar.# "user" Foo..= case name of-          Just n -> Just $ object ["name" .= n]-          Nothing -> Nothing-        Bar.# []+  Just+    $ M.fromList+    $ "type" Foo..= ("user.connection" :: Text)+      Bar.# "connection" Foo..= uc+      Bar.# "user" Foo..= case name of+        Just n -> Just $ object ["name" .= n]+        Nothing -> Nothing+      Bar.# []
+ data/examples/fixity/megaparsec-alternative-out.hs view
@@ -0,0 +1,8 @@+module MegaparsecExample where++import Text.Megaparsec++pValue =+  Object <$> parseObjectBody+    <|> Array <$> parseArrayBody+    <|> String <$> parseStringBody
+ data/examples/fixity/megaparsec-alternative.hs view
@@ -0,0 +1,8 @@+module MegaparsecExample where++import Text.Megaparsec++pValue =+  Object <$> parseObjectBody+    <|> Array <$> parseArrayBody+    <|> String <$> parseStringBody
+ data/examples/fixity/optics-mixed-out.hs view
@@ -0,0 +1,8 @@+module OpticsExample where++import Optics++updated =+  record+    & fieldLens % subFieldLens .~ someValue+    & otherLens %~ someTransformationFunctionApplied
+ data/examples/fixity/optics-mixed.hs view
@@ -0,0 +1,8 @@+module OpticsExample where++import Optics++updated =+  record+    & fieldLens % subFieldLens .~ someValue+    & otherLens %~ someTransformationFunctionApplied
+ data/examples/fixity/relude-default-operator-chain-out.hs view
@@ -0,0 +1,10 @@+module ReludeChainExample where++import Relude++resolveValue =+  primarySource+    ?: secondarySource+    ?: tertiarySource+    ?: quaternarySource+    ?: finalFallbackValue
+ data/examples/fixity/relude-default-operator-chain.hs view
@@ -0,0 +1,10 @@+module ReludeChainExample where++import Relude++resolveValue =+  primarySource+    ?: secondarySource+    ?: tertiarySource+    ?: quaternarySource+    ?: finalFallbackValue
+ data/examples/fixity/relude-default-operator-out.hs view
@@ -0,0 +1,7 @@+module ReludeExample where++import Relude++config =+  lookupOptionalSetting environment ?:+    defaultConfigurationValue
+ data/examples/fixity/relude-default-operator.hs view
@@ -0,0 +1,7 @@+module ReludeExample where++import Relude++config =+  lookupOptionalSetting environment+    ?: defaultConfigurationValue
+ data/examples/fixity/rio-ampersand-out.hs view
@@ -0,0 +1,7 @@+module RioExample where++import RIO++message =+  greetingText <> userNameText+    & Text.strip
+ data/examples/fixity/rio-ampersand.hs view
@@ -0,0 +1,7 @@+module RioExample where++import RIO++message =+  greetingText <> userNameText+    & Text.strip
+ data/examples/fixity/rio-deepseq-out.hs view
@@ -0,0 +1,7 @@+module RioDeepseqExample where++import RIO++result =+  forceEvaluationOfBigStructure `deepseq`+    continueWithNextStep
+ data/examples/fixity/rio-deepseq.hs view
@@ -0,0 +1,7 @@+module RioDeepseqExample where++import RIO++result =+  forceEvaluationOfBigStructure+    `deepseq` continueWithNextStep
+ data/examples/import/implicit-prelude-package-out.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE PackageImports #-}++import "base" Control.Applicative (Alternative, (<|>))+import "base" Data.Maybe (Maybe (Nothing), maybe)+import "base" System.IO (IO)+import "yaya" Yaya.Fold (ana, cata)+import "base" Prelude ((+))
+ data/examples/import/implicit-prelude-package.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE PackageImports #-}++import "base" System.IO (IO)+import "base" Prelude ((+))+import "yaya" Yaya.Fold (ana, cata)+import "base" Control.Applicative (Alternative, (<|>))+import "base" Data.Maybe (Maybe (Nothing), maybe)
+ data/examples/import/no-implicit-prelude-out.hs view
@@ -0,0 +1,6 @@+{-# LANGUAGE NoImplicitPrelude #-}++import Control.Applicative (Alternative, (<|>))+import Data.Maybe (Maybe (Nothing), maybe)+import Prelude ((+))+import System.IO (IO)
+ data/examples/import/no-implicit-prelude-package-out.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE NoImplicitPrelude #-}++import "base" Control.Applicative (Alternative, (<|>))+import "base" Data.Maybe (Maybe (Nothing), maybe)+import "base" Prelude ((+))+import "base" System.IO (IO)+import "yaya" Yaya.Fold (ana, cata)
+ data/examples/import/no-implicit-prelude-package.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE PackageImports #-}++import "base" System.IO (IO)+import "base" Prelude ((+))+import "yaya" Yaya.Fold (ana, cata)+import "base" Control.Applicative (Alternative, (<|>))+import "base" Data.Maybe (Maybe (Nothing), maybe)
+ data/examples/import/no-implicit-prelude.hs view
@@ -0,0 +1,6 @@+{-# LANGUAGE NoImplicitPrelude #-}++import System.IO (IO)+import Prelude ((+))+import Control.Applicative (Alternative, (<|>))+import Data.Maybe (Maybe (Nothing), maybe)
+ data/examples/module-header/block-haddock-in-export-list-out.hs view
@@ -0,0 +1,5 @@+module Foo+  ( -- | asdf+    foo,+  )+where
+ data/examples/module-header/block-haddock-in-export-list.hs view
@@ -0,0 +1,1 @@+module Foo ({- | asdf -} foo) where
+ data/examples/other/comment-trailing-blank-line-do-out.hs view
@@ -0,0 +1,4 @@+doBlock = do+  a --++  b
+ data/examples/other/comment-trailing-blank-line-do.hs view
@@ -0,0 +1,4 @@+doBlock = do+  a --++  b
+ data/examples/other/comment-trailing-blank-line-let-out.hs view
@@ -0,0 +1,5 @@+letBlock =+  let a = a --++      b = b+   in c
+ data/examples/other/comment-trailing-blank-line-let.hs view
@@ -0,0 +1,5 @@+letBlock =+  let a = a --++      b = b+   in c
+ data/examples/other/comment-trailing-blank-line-variants-out.hs view
@@ -0,0 +1,22 @@+textComment = do+  a -- some text++  b++blockComment = do+  a {- foo -}++  b++twoComments = do+  a --++  --++  bar++adjacentThenBlank = do+  a --+  --++  bar
+ data/examples/other/comment-trailing-blank-line-variants.hs view
@@ -0,0 +1,22 @@+textComment = do+  a -- some text++  b++blockComment = do+  a {- foo -}++  b++twoComments = do+  a --++  --++  bar++adjacentThenBlank = do+  a --+  --++  bar
+ data/examples/other/comment-trailing-blank-line-where-out.hs view
@@ -0,0 +1,5 @@+whereBlock = foo+  where+    a = a --++    b = b
+ data/examples/other/comment-trailing-blank-line-where.hs view
@@ -0,0 +1,5 @@+whereBlock = foo+  where+    a = a --++    b = b
+ data/examples/other/comment-trailing-no-blank-line-out.hs view
@@ -0,0 +1,25 @@+noBlankAfterComment = do+  a --+  b++noBlankTextComment = do+  a -- some text+  b++noBlankBlockComment = do+  a {- foo -}+  b++blockCommentFollowedByExpr = do+  a {- foo -} 1+  b++whereNoBlank = foo+  where+    a = a --+    b = b++letNoBlank =+  let a = a --+      b = b+   in c
+ data/examples/other/comment-trailing-no-blank-line.hs view
@@ -0,0 +1,25 @@+noBlankAfterComment = do+  a --+  b++noBlankTextComment = do+  a -- some text+  b++noBlankBlockComment = do+  a {- foo -}+  b++blockCommentFollowedByExpr = do+  a {- foo -} 1+  b++whereNoBlank = foo+  where+    a = a --+    b = b++letNoBlank =+  let a = a --+      b = b+   in c
extract-hackage-info/hackage-info.bin view

binary file changed (1002933 → 1243493 bytes)

ormolu.cabal view
@@ -1,16 +1,16 @@ cabal-version: 2.4 name: ormolu-version: 0.8.1.1+version: 0.8.2.0 license: BSD-3-Clause license-file: LICENSE.md-maintainer: Mark Karpov <mark.karpov@tweag.io>+maintainer: Mark Karpov <markkarpov92@gmail.com> tested-with:   ghc ==9.10.2   ghc ==9.12.2   ghc ==9.14.1 -homepage: https://github.com/tweag/ormolu-bug-reports: https://github.com/tweag/ormolu/issues+homepage: https://github.com/mrkkrp/ormolu+bug-reports: https://github.com/mrkkrp/ormolu/issues synopsis: A formatter for Haskell source code description: A formatter for Haskell source code. category: Development, Formatting@@ -29,7 +29,7 @@  source-repository head   type: git-  location: https://github.com/tweag/ormolu.git+  location: https://github.com/mrkkrp/ormolu.git  flag dev   description: Turn on development settings.
src/Ormolu.hs view
@@ -40,6 +40,7 @@ import Control.Exception import Control.Monad import Control.Monad.IO.Class (MonadIO (..))+import Data.Choice qualified as Choice import Data.Map.Strict qualified as Map import Data.Maybe (fromMaybe) import Data.Set qualified as Set@@ -112,7 +113,7 @@   -- when we try to parse the rendered code back, inside of GHC monad   -- wrapper which will lead to error messages presenting the exceptions as   -- GHC bugs.-  let !formattedText = printSnippets (cfgDebug cfg) result0+  let !formattedText = printSnippets (Choice.fromBool (cfgDebug cfg)) result0   when (not (cfgUnsafe cfg) || cfgCheckIdempotence cfg) $ do     -- Parse the result of pretty-printing again and make sure that AST     -- is the same as AST of original snippet module span positions.@@ -138,7 +139,7 @@     -- Try re-formatting the formatted result to check if we get exactly     -- the same output.     when (cfgCheckIdempotence cfg) . liftIO $-      let reformattedText = printSnippets (cfgDebug cfg) result1+      let reformattedText = printSnippets (Choice.fromBool (cfgDebug cfg)) result1        in case diffText formattedText reformattedText path of             Nothing -> return ()             Just diff -> throwIO (OrmoluNonIdempotentOutput diff)
src/Ormolu/Fixity/Internal.hs view
@@ -190,7 +190,7 @@ defaultFixityOverrides :: FixityOverrides defaultFixityOverrides = FixityOverrides Map.empty --- | Module re-exports+-- | Module re-exports. newtype ModuleReexports = ModuleReexports   { unModuleReexports :: Map ModuleName (NonEmpty (Maybe PackageName, ModuleName))   }@@ -198,61 +198,7 @@  -- | Module re-exports to apply by default. defaultModuleReexports :: ModuleReexports-defaultModuleReexports =-  ModuleReexports . Map.fromList $-    [ ( "Control.Lens",-        l-          "lens"-          [ "Control.Lens.At",-            "Control.Lens.Cons",-            "Control.Lens.Each",-            "Control.Lens.Empty",-            "Control.Lens.Equality",-            "Control.Lens.Fold",-            "Control.Lens.Getter",-            "Control.Lens.Indexed",-            "Control.Lens.Iso",-            "Control.Lens.Lens",-            "Control.Lens.Level",-            "Control.Lens.Plated",-            "Control.Lens.Prism",-            "Control.Lens.Reified",-            "Control.Lens.Review",-            "Control.Lens.Setter",-            "Control.Lens.TH",-            "Control.Lens.Traversal",-            "Control.Lens.Tuple",-            "Control.Lens.Type",-            "Control.Lens.Wrapped",-            "Control.Lens.Zoom"-          ]-      ),-      ( "Servant",-        l-          "servant"-          [ "Servant.API"-          ]-      ),-      ( "Optics",-        l-          "optics"-          [ "Optics.Fold",-            "Optics.Operators",-            "Optics.IxAffineFold",-            "Optics.IxFold",-            "Optics.IxTraversal",-            "Optics.Traversal"-          ]-      ),-      ( "Test.Hspec",-        l-          "hspec-expectations"-          [ "Test.Hspec.Expectations"-          ]-      )-    ]-  where-    l packageName xs = (Just packageName,) <$> NE.fromList xs+defaultModuleReexports = ModuleReexports Map.empty  -- | Fixity information that is specific to a package being formatted. It -- requires module-specific imports in order to be usable.
src/Ormolu/Imports.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards #-}@@ -12,6 +13,8 @@  import Data.Bifunctor import Data.Char (isAlphaNum)+import Data.Choice (Choice)+import Data.Choice qualified as Choice import Data.Function (on) import Data.List (nubBy, sortBy, sortOn) import Data.Map.Strict (Map)@@ -27,12 +30,15 @@ import Ormolu.Utils (notImplemented, showOutputable)  -- | Sort and normalize imports.-normalizeImports :: [LImportDecl GhcPs] -> [LImportDecl GhcPs]-normalizeImports =+normalizeImports ::+  Choice "implicitPrelude" ->+  [LImportDecl GhcPs] ->+  [LImportDecl GhcPs]+normalizeImports implicitPrelude =   fmap snd     . M.toAscList     . M.fromListWith combineImports-    . fmap (\x -> (importId x, g x))+    . fmap (\x -> (importId implicitPrelude x, g x))   where     g :: LImportDecl GhcPs -> LImportDecl GhcPs     g (L l ImportDecl {..}) =@@ -118,8 +124,8 @@       toBool EverythingBut = True  -- | Obtain an 'ImportId' for a given import.-importId :: LImportDecl GhcPs -> ImportId-importId (L _ ImportDecl {..}) =+importId :: Choice "implicitPrelude" -> LImportDecl GhcPs -> ImportId+importId implicitPrelude (L _ ImportDecl {..}) =   ImportId     { importIsPrelude = isPrelude,       importIdName = moduleName,@@ -135,7 +141,8 @@       importLevel = importLevelOf ideclLevelSpec     }   where-    isPrelude = moduleNameString moduleName == "Prelude"+    isPrelude =+      Choice.isTrue implicitPrelude && moduleNameString moduleName == "Prelude"     moduleName = unLoc ideclName     importLevelOf = \case       LevelStylePre l -> Just (ImportDeclLevelOrd l)
src/Ormolu/Parser.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}@@ -17,6 +18,8 @@ import Control.Monad.Except (ExceptT (..), runExceptT) import Control.Monad.IO.Class import Data.Char (isSpace)+import Data.Choice (Choice)+import Data.Choice qualified as Choice import Data.Functor import Data.Generics hiding (orElse) import Data.List qualified as L@@ -90,8 +93,12 @@     parsePragmasIntoDynFlags baseFlags extraOpts path rawInputStringBuffer >>= \case       Right res -> pure res       Left err -> throwIO (OrmoluParsingFailed beginningLoc err)-  let cppEnabled = EnumSet.member Cpp (GHC.extensionFlags dynFlags)-      implicitPrelude = EnumSet.member ImplicitPrelude (GHC.extensionFlags dynFlags)+  let cppEnabled =+        Choice.fromBool $+          EnumSet.member Cpp (GHC.extensionFlags dynFlags)+      implicitPrelude =+        Choice.fromBool $+          EnumSet.member ImplicitPrelude (GHC.extensionFlags dynFlags)   fixityImports <-     parseImports dynFlags implicitPrelude path rawInputStringBuffer >>= \case       Right res ->@@ -143,12 +150,15 @@       parser = case cfgSourceType of         ModuleSource -> GHC.parseModule         SignatureSource -> GHC.parseSignature+      implicitPrelude =+        Choice.fromBool $+          EnumSet.member ImplicitPrelude (GHC.extensionFlags dynFlags)       r = case runParser parser dynFlags path input of         GHC.PFailed pstate ->           case pStateErrors pstate of             Just err -> Left err             Nothing -> error "PFailed does not have an error"-        GHC.POk pstate (L _ (normalizeModule -> hsModule)) ->+        GHC.POk pstate (L _ (normalizeModule implicitPrelude -> hsModule)) ->           case pStateErrors pstate of             -- Some parse errors (pattern/arrow syntax in expr context)             -- do not cause a parse error, but they are replaced with "_"@@ -173,8 +183,11 @@  -- | Normalize a 'HsModule' by sorting its import\/export lists, dropping -- blank comments, etc.-normalizeModule :: HsModule GhcPs -> HsModule GhcPs-normalizeModule hsmod =+normalizeModule ::+  Choice "implicitPrelude" ->+  HsModule GhcPs ->+  HsModule GhcPs+normalizeModule implicitPrelude hsmod =   everywhere     ( mkT dropBlankTypeHaddocks         `extT` dropBlankDataDeclHaddocks@@ -183,7 +196,7 @@     )     hsmod       { hsmodImports =-          normalizeImports (hsmodImports hsmod),+          normalizeImports implicitPrelude (hsmodImports hsmod),         hsmodDecls =           filter (not . isBlankDocD . unLoc) (hsmodDecls hsmod),         hsmodExt =@@ -326,8 +339,8 @@ parseImports ::   -- | Pre-set 'DynFlags'   DynFlags ->-  -- | Implicit Prelude?-  Bool ->+  -- | Whether the implicit Prelude is in effect+  Choice "implicitPrelude" ->   -- | File name (only for source location annotations)   FilePath ->   -- | Input for the parser@@ -349,7 +362,11 @@                     mod' = mmoduleName `orElse` L (GHC.noAnnSrcSpan main_loc) mAIN_NAME                     explicitImports = hsmodImports hsmod                     implicitImports =-                      GHC.mkPrelImports (unLoc mod') main_loc implicitPrelude explicitImports+                      GHC.mkPrelImports+                        (unLoc mod')+                        main_loc+                        (Choice.toBool implicitPrelude)+                        explicitImports                  in Right (explicitImports ++ implicitImports)   where     popts = initParserOpts flags
src/Ormolu/Printer.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards #-} @@ -7,6 +8,7 @@   ) where +import Data.Choice (Choice) import Data.Text (Text) import Data.Text qualified as T import Ormolu.Parser.Result@@ -18,7 +20,7 @@ -- | Render several source snippets. printSnippets ::   -- | Whether to print out debug information during printing-  Bool ->+  Choice "debug" ->   -- | Result of parsing   [SourceSnippet] ->   -- | Resulting rendition
src/Ormolu/Printer/Combinators.hs view
@@ -31,6 +31,7 @@     encloseLocated,     located',     switchLayout,+    enterLayout,     Layout (..),     vlayout,     getLayout,
src/Ormolu/Printer/Internal.hs view
@@ -62,7 +62,6 @@ import Control.Monad.State.Strict import Data.Bool (bool) import Data.Choice (Choice)-import Data.Choice qualified as Choice import Data.Coerce import Data.Functor ((<&>)) import Data.List (find)@@ -109,7 +108,7 @@     -- | Module fixity map     rcModuleFixityMap :: ModuleFixityMap,     -- | Whether to print out debug information during printing-    rcDebug :: !Bool+    rcDebug :: !(Choice "debug")   }  -- | State context of 'R'.@@ -179,8 +178,9 @@   EnumSet Extension ->   -- | Module fixity map   ModuleFixityMap ->+  -- | Whether to print out debug information during printing+  Choice "debug" ->   -- | Resulting rendition-  Bool ->   Text runR (R m) sstream cstream sourceType extensions moduleFixityMap debug =   TL.toStrict . toLazyText . scBuilder $ execState (runReaderT m rc) sc@@ -411,7 +411,7 @@ -- | Retrieve whether we should print out certain debug information while -- printing. askDebug :: R (Choice "debug")-askDebug = R (asks (Choice.fromBool . rcDebug))+askDebug = R (asks rcDebug)  inciBy :: Int -> R () -> R () inciBy step (R m) = R (local modRC m)
src/Ormolu/Printer/Meat/Common.hs view
@@ -129,16 +129,16 @@ -- | A helper for formatting infix constructions in lhs of definitions. p_infixDefHelper ::   -- | Whether to format in infix style-  Bool ->+  Choice "infixStyle" ->   -- | Whether to bump indentation for arguments-  Bool ->+  Choice "indentArgs" ->   -- | How to print the operator\/name   R () ->   -- | How to print the arguments   [R ()] ->   R () p_infixDefHelper isInfix indentArgs name args =-  case (isInfix, args) of+  case (Choice.toBool isInfix, args) of     (True, p0 : p1 : ps) -> do       let parens' =             if null ps@@ -151,14 +151,15 @@           name           space           p1-      unless (null ps) . inciIf indentArgs $ do+      unless (null ps) . inciIf (Choice.toBool indentArgs) $ do         breakpoint         sitcc (sep breakpoint sitcc ps)     (_, ps) -> do       name       unless (null ps) $ do         breakpoint-        inciIf indentArgs $ sitcc (sep breakpoint sitcc args)+        inciIf (Choice.toBool indentArgs) $+          sitcc (sep breakpoint sitcc args)  -- | Print a Haddock. p_hsDoc ::
src/Ormolu/Printer/Meat/Declaration/Class.hs view
@@ -1,5 +1,8 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-}  -- | Rendering of type class declarations.@@ -10,6 +13,8 @@  import Control.Arrow import Control.Monad+import Data.Choice (pattern Is)+import Data.Choice qualified as Choice import Data.Foldable import Data.Function (on) import Data.List (sortBy)@@ -60,8 +65,8 @@       for_ ctx p_classContext       switchLayout signatureSpans $         p_infixDefHelper-          (isInfix fixity)-          True+          (Choice.fromBool (isInfix fixity))+          (Is #indentArgs)           (p_rdrName name)           (located' p_hsTyVarBndr <$> hsq_explicit)       inci (p_classFundeps fdeps)
src/Ormolu/Printer/Meat/Declaration/Data.hs view
@@ -75,8 +75,8 @@     forM_ dd_ctxt p_lhsContext     switchLayout constructorSpans $       p_infixDefHelper-        (isInfix fixity)-        True+        (Choice.fromBool (isInfix fixity))+        (Is #indentArgs)         (p_rdrName name)         (p_tyVar <$> tyVars)     forM_ dd_kindSig $ \k -> do
src/Ormolu/Printer/Meat/Declaration/OpTree.hs view
@@ -124,9 +124,27 @@           -- place the operator in a trailing position (because it would be           -- read as being part of the do-block)           && not (isDoBlock $ rightMostNode prevExpr)+      -- A staircase of two or more trailing operators is only worthwhile when+      -- the operand at the very end of the chain has a hanging form (a do+      -- block, lambda, case, etc.): the trailing operator then introduces that+      -- block. When such a chain ends in an ordinary expression (a variable,+      -- literal, or plain application) the trailing layout only produces+      -- ever-deepening indentation, so we fall back to the leading-operator+      -- layout. A single hard splitter is exempt: it does not form a pyramid+      -- and trailing is the idiomatic way to introduce its operand.+      chainEndsInHangingForm =+        case rightMostNode t of+          OpNode (L _ n) -> exprPlacement n == Hanging+          _ -> False+      isSingleOperator = case ops of+        [_] -> True+        _ -> False       -- If all operators at the current level match the conditions to be-      -- trailing, then put them in a trailing position-      isTrailing = all couldBeTrailing $ zip (NE.toList exprs) ops+      -- trailing, and the chain is either a single operator or ends in a+      -- hanging form, then put the operators in a trailing position.+      isTrailing =+        (isSingleOperator || chainEndsInHangingForm)+          && all couldBeTrailing (zip (NE.toList exprs) ops)   ub <- if isTrailing then return useBraces else opBranchBraceStyle placement   let p_x = ub $ p_exprOpTree s firstExpr       putOpsExprs prevExpr (opi : ops') (expr : exprs') = do
src/Ormolu/Printer/Meat/Declaration/Type.hs view
@@ -1,4 +1,7 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-}  -- | Rendering of type synonym declarations.@@ -7,6 +10,7 @@   ) where +import Data.Choice (pattern Is, pattern Isn't) import GHC.Hs.Extension import GHC.Hs.Type import GHC.Parser.Annotation@@ -32,8 +36,11 @@   space   switchLayout (getLocA name : map getLocA hsq_explicit) $     p_infixDefHelper-      (case fixity of Infix -> True; _ -> False)-      True+      ( case fixity of+          Infix -> Is #infixStyle+          _ -> Isn't #infixStyle+      )+      (Is #indentArgs)       (p_rdrName name)       (map (located' p_hsTyVarBndr) hsq_explicit)   inci $ do
src/Ormolu/Printer/Meat/Declaration/TypeFamily.hs view
@@ -1,5 +1,8 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-}  -- | Rendering of data\/type families.@@ -10,6 +13,8 @@ where  import Control.Monad+import Data.Choice (pattern Is)+import Data.Choice qualified as Choice import Data.Maybe (isNothing) import GHC.Hs import GHC.Types.Fixity@@ -33,8 +38,8 @@     breakpoint     switchLayout headerSpns $ do       p_infixDefHelper-        (isInfix fdFixity)-        True+        (Choice.fromBool (isInfix fdFixity))+        (Is #indentArgs)         (p_rdrName fdLName)         (located' p_hsTyVarBndr <$> hsq_explicit)     let resultSig = p_familyResultSigL fdResultSig@@ -95,8 +100,8 @@     let famLhsSpn = getLocA feqn_tycon : fmap lhsTypeArgSrcSpan feqn_pats     switchLayout famLhsSpn $       p_infixDefHelper-        (isInfix feqn_fixity)-        True+        (Choice.fromBool (isInfix feqn_fixity))+        (Is #indentArgs)         (p_rdrName feqn_tycon)         (p_lhsTypeArg <$> feqn_pats)     inci $ do
src/Ormolu/Printer/Meat/Declaration/Value.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}@@ -19,6 +20,7 @@  import Control.Monad import Data.Bool (bool)+import Data.Choice qualified as Choice import Data.Data hiding (Infix, Prefix) import Data.Function (on) import Data.Functor ((<&>))@@ -213,8 +215,8 @@         case style of           Function name ->             p_infixDefHelper-              isInfix-              indentBody+              (Choice.fromBool isInfix)+              (Choice.fromBool indentBody)               (p_rdrName name)               (located' p_pat <$> m_pats)           PatternBind -> stdCase@@ -274,10 +276,16 @@           breakpoint           (located' (p_grhs' placement placer render groupStyle))           (NE.toList grhssGRHSs)+      localBindsWhereSpan = case grhssLocalBinds of+        HsValBinds (EpAnn {anns = AnnList {al_rest}}) _ ->+          locA al_rest+        HsIPBinds (EpAnn {anns = AnnList {al_rest}}) _ ->+          locA al_rest+        EmptyLocalBinds _ -> noSrcSpan       p_where = do         unless (eqEmptyLocalBinds grhssLocalBinds) $ do           breakpoint-          txt "where"+          located (L localBindsWhereSpan ()) $ \_ -> txt "where"           breakpoint           inci $ p_hsLocalBinds grhssLocalBinds   inciIf indentBody $ do@@ -399,14 +407,15 @@     UnhelpfulSpan _ -> f x     RealSrcSpan currentSpn _ -> do       getSpanMark >>= \case-        -- Spacing before comments will be handled by the code-        -- that prints comments, so we just have to deal with-        -- blank lines between statements here.-        Just (StatementSpan lastSpn) ->-          if srcSpanStartLine currentSpn > srcSpanEndLine lastSpn + 1-            then newline-            else return ()-        _ -> return ()+        -- We deal with blank lines between statements here. The last mark+        -- may be a 'StatementSpan' (the usual case) or a comment span: the+        -- latter happens when the previous statement ended with a trailing+        -- comment, in which case we still want to preserve a blank line that+        -- followed that comment in the original input.+        Just lastMark ->+          let lastSpn = spanMarkSpan lastMark+           in when (srcSpanStartLine currentSpn > srcSpanEndLine lastSpn + 1) newline+        Nothing -> return ()       f x       -- In some cases the (f x) expression may insert a new mark. We want       -- to be careful not to override comment marks.
src/Ormolu/Printer/Meat/ImportExport.hs view
@@ -8,6 +8,7 @@ module Ormolu.Printer.Meat.ImportExport   ( p_hsmodExports,     p_hsmodImport,+    enterMultilineLayoutIfContainsDocEntries,   ) where @@ -25,12 +26,13 @@  p_hsmodExports :: [LIE GhcPs] -> R () p_hsmodExports xs =-  parens N $ do-    layout <- getLayout-    sep-      breakpoint-      (\(p, l) -> sitcc (located (addDocSrcSpan l) (p_lie layout p)))-      (attachRelativePos xs)+  enterMultilineLayoutIfContainsDocEntries xs $+    parens N $ do+      layout <- getLayout+      sep+        breakpoint+        (\(p, l) -> sitcc (located (addDocSrcSpan l) (p_lie layout p)))+        (attachRelativePos xs)   where     -- In order to correctly set the layout when a doc comment is present.     addDocSrcSpan lie@(L l ie) = case ieExportDoc ie of@@ -172,3 +174,16 @@   IEGroup {} -> Nothing   IEDoc {} -> Nothing   IEDocNamed {} -> Nothing++enterMultilineLayoutIfContainsDocEntries :: [LIE GhcPs] -> R () -> R ()+enterMultilineLayoutIfContainsDocEntries xs =+  if any (isDocEntry . unLoc) xs+    then enterLayout MultiLine+    else id++isDocEntry :: (IE pass) -> Bool+isDocEntry = \case+  IEDoc {} -> True+  IEGroup {} -> True+  IEDocNamed {} -> True+  _ -> False
src/Ormolu/Printer/Meat/Module.hs view
@@ -37,35 +37,36 @@   let XModulePs {..} = hsmodExt       deprecSpan = maybe [] (pure . getLocA) hsmodDeprecMessage       exportSpans = maybe [] (pure . getLocA) hsmodExports-  switchLayout (deprecSpan <> exportSpans) $ do-    forM_ mstackHeader $ \(L spn comment) -> do-      spitCommentNow spn comment+  switchLayout (deprecSpan <> exportSpans) $+    enterMultilineLayoutIfContainsDocEntries (maybe [] unLoc hsmodExports) $ do+      forM_ mstackHeader $ \(L spn comment) -> do+        spitCommentNow spn comment+        newline       newline-    newline-    p_pragmas pragmas-    newline-    case hsmodName of-      Nothing -> return ()-      Just hsmodName' -> do-        located hsmodName' $ \name -> do-          forM_ hsmodHaddockModHeader (p_hsDoc Pipe (With #endNewline))-          p_hsmodName name-        breakpoint-        forM_ hsmodDeprecMessage $ \w -> do-          located' p_warningTxt w+      p_pragmas pragmas+      newline+      case hsmodName of+        Nothing -> return ()+        Just hsmodName' -> do+          located hsmodName' $ \name -> do+            forM_ hsmodHaddockModHeader (p_hsDoc Pipe (With #endNewline))+            p_hsmodName name           breakpoint-        case hsmodExports of-          Nothing -> return ()-          Just l -> do-            encloseLocated l $ \exports -> do-              inci (p_hsmodExports exports)+          forM_ hsmodDeprecMessage $ \w -> do+            located' p_warningTxt w             breakpoint-        txt "where"-        newline-    newline-    forM_ hsmodImports (located' p_hsmodImport)-    newline-    switchLayout (getLocA <$> hsmodDecls) $ do-      p_hsDecls Free hsmodDecls+          case hsmodExports of+            Nothing -> return ()+            Just l -> do+              encloseLocated l $ \exports -> do+                inci (p_hsmodExports exports)+              breakpoint+          txt "where"+          newline       newline-      spitRemainingComments+      forM_ hsmodImports (located' p_hsmodImport)+      newline+      switchLayout (getLocA <$> hsmodDecls) $ do+        p_hsDecls Free hsmodDecls+        newline+        spitRemainingComments
src/Ormolu/Printer/Operators.hs view
@@ -203,9 +203,9 @@       indices -> splitTree noptExprs noptOps indices   where     indicesOfHardSplitter =-      fmap fst $-        filter (isHardSplitterOp . opiFixityApproximation . snd) $-          zip [0 ..] noptOps+      fmap fst+        $ filter (isHardSplitterOp . opiFixityApproximation . snd)+        $ zip [0 ..] noptOps     indexOfMinMaxPrecOps [] = (Nothing, Nothing)     indexOfMinMaxPrecOps (oo : oos) = go oos 1 oo (Just [0]) oo (Just [0])       where
src/Ormolu/Processing/Preprocess.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}@@ -12,6 +13,8 @@ import Data.Array as A import Data.Bifunctor (bimap) import Data.Char (isSpace)+import Data.Choice (Choice)+import Data.Choice qualified as Choice import Data.Function ((&)) import Data.IntMap (IntMap) import Data.IntMap.Strict qualified as IntMap@@ -29,13 +32,14 @@ -- and subregions to be formatted. preprocess ::   -- | Whether CPP is enabled-  Bool ->+  Choice "cppEnabled" ->   RegionDeltas ->   Text ->   [Either Text RegionDeltas] preprocess cppEnabled region rawInput = rawSnippetsAndRegionsToFormat   where-    (linesNotToFormat', replacementLines) = linesNotToFormat cppEnabled region rawInput+    (linesNotToFormat', replacementLines) =+      linesNotToFormat cppEnabled region rawInput     regionsToFormat =       intSetToRegions rawLineLength $         IntSet.fromAscList [1 .. rawLineLength] IntSet.\\ linesNotToFormat'@@ -91,7 +95,7 @@ -- for specific lines. linesNotToFormat ::   -- | Whether CPP is enabled-  Bool ->+  Choice "cppEnabled" ->   RegionDeltas ->   Text ->   (IntSet, IntMap Text)@@ -100,13 +104,16 @@   where     unconsidered =       IntSet.fromAscList $-        [1 .. regionPrefixLength] <> [totalLines - regionSuffixLength + 1 .. totalLines]+        [1 .. regionPrefixLength]+          <> [totalLines - regionSuffixLength + 1 .. totalLines]     totalLines = length (T.lines input)     regionLines = linesInRegion region input     (magicDisabled, lineUpdates) = magicDisabledLines regionLines     otherDisabled = mconcat allLines regionLines       where-        allLines = [shebangLines, linePragmaLines] <> [cppLines | cppEnabled]+        allLines =+          [shebangLines, linePragmaLines]+            <> [cppLines | Choice.isTrue cppEnabled]  -- | Ormolu state. data OrmoluState
src/Ormolu/Utils/IO.hs view
@@ -16,7 +16,7 @@ import Data.Map.Lazy qualified as M import System.Directory import System.FilePath-import System.IO.Error (isDoesNotExistError)+import System.IO.Error (isDoesNotExistError, isPermissionError)  -- | Find the path to the closest file higher in the file hierarchy that -- satisfies a given predicate.@@ -30,25 +30,36 @@   m (Maybe FilePath) findClosestFileSatisfying isRightFile rootOfSearch = liftIO $ do   parentDir <- takeDirectory <$> makeAbsolute rootOfSearch-  dirEntries <--    listDirectory parentDir `catch` \case-      (isDoesNotExistError -> True) -> pure []+  maybeDirEntries <-+    (Just <$> listDirectory parentDir) `catch` \case+      -- The directory does not exist. This is expected: the search may start+      -- from a path that does not exist yet (e.g. a file about to be created),+      -- whose absolute form still lies below existing parent directories.+      -- Treat it as empty and keep searching upwards.+      (isDoesNotExistError -> True) -> pure (Just [])+      -- We lack the permissions to read the directory, e.g. when running in a+      -- sandbox that restricts access to parent directories. Abort the search:+      -- we almost certainly cannot read any parent directory either.+      (isPermissionError -> True) -> pure Nothing       e -> throwIO e-  let searchAtParentDirLevel = \case-        [] -> pure Nothing-        x : xs ->-          if isRightFile x-            then-              doesFileExist (parentDir </> x) >>= \case-                True -> pure (Just x)-                False -> searchAtParentDirLevel xs-            else searchAtParentDirLevel xs-  searchAtParentDirLevel dirEntries >>= \case-    Just foundFile -> pure . Just $ parentDir </> foundFile-    Nothing ->-      if isDrive parentDir-        then pure Nothing-        else findClosestFileSatisfying isRightFile parentDir+  case maybeDirEntries of+    Nothing -> pure Nothing+    Just entries -> do+      let searchAtParentDirLevel = \case+            [] -> pure Nothing+            x : xs ->+              if isRightFile x+                then+                  doesFileExist (parentDir </> x) >>= \case+                    True -> pure (Just x)+                    False -> searchAtParentDirLevel xs+                else searchAtParentDirLevel xs+      searchAtParentDirLevel entries >>= \case+        Just foundFile -> pure . Just $ parentDir </> foundFile+        Nothing ->+          if isDrive parentDir+            then pure Nothing+            else findClosestFileSatisfying isRightFile parentDir  newtype Cache k v = Cache (IORef (Map k v)) 
tests/Ormolu/FixitySpec.hs view
@@ -201,44 +201,32 @@       ["esqueleto"]       [package_ "bob" $ import_ "Database.Esqueleto.Experimental"]       [(unqual "++.", defaultFixityApproximation)]-  it "default module re-exports: Control.Lens brings into scope Control.Lens.Lens" $+  it "re-exports baked into the database: Control.Lens brings <+~ into scope" $     checkFixities       ["lens"]-      ( applyModuleReexports-          defaultModuleReexports-          [import_ "Control.Lens"]-      )+      [import_ "Control.Lens"]       [(unqual "<+~", FixityApproximation (Just InfixR) 4 4)]-  it "default module re-exports: Control.Lens qualified brings into scope Control.Lens.Lens" $+  it "re-exports baked into the database: Control.Lens qualified" $     checkFixities       ["lens"]-      ( applyModuleReexports-          defaultModuleReexports-          [import_ "Control.Lens" & qualified_]-      )+      [import_ "Control.Lens" & qualified_]       [ (unqual "<+~", defaultFixityApproximation),-        (qual "Control.Lens.Lens" "<+~", defaultFixityApproximation),         (qual "Control.Lens" "<+~", FixityApproximation (Just InfixR) 4 4)       ]-  it "default module re-exports: Control.Lens qualified as brings into scope Control.Lens.Lens" $+  it "re-exports baked into the database: Control.Lens qualified as" $     checkFixities       ["lens"]-      ( applyModuleReexports-          defaultModuleReexports-          [import_ "Control.Lens" & qualified_ & as_ "L"]-      )+      [import_ "Control.Lens" & qualified_ & as_ "L"]       [ (unqual "<+~", defaultFixityApproximation),-        (qual "Control.Lens.Lens" "<+~", defaultFixityApproximation),         (qual "Control.Lens" "<+~", defaultFixityApproximation),         (qual "L" "<+~", FixityApproximation (Just InfixR) 4 4)       ]   it "re-export chains: exported module can itself re-export another module" $ do     let reexports =           ModuleReexports $-            Map.insert+            Map.singleton               "Foo"               ((Nothing, "Control.Lens") :| [])-              (unModuleReexports defaultModuleReexports)     checkFixities       ["lens"]       ( applyModuleReexports
tests/Ormolu/PrinterSpec.hs view
@@ -53,6 +53,10 @@                   "esqueleto",                   "hspec",                   "lens",+                  "megaparsec",+                  "optics",+                  "relude",+                  "rio",                   "servant"                 ]           }