From 35f4fb39326ab7d4847c5c8940f4d4185f3d3d24 Mon Sep 17 00:00:00 2001 From: Mark Karpov Date: Tue, 16 Jun 2020 11:40:26 +0200 Subject: [PATCH] Deal with non-zero indentation in region formatting Improved region formatting so that indented fragments can also be processed correctly. --- CHANGELOG.md | 4 ++++ default.nix | 16 ++++++++++------ region-tests/expected-result-17-18.hs | 17 +++++++++++++++++ region-tests/expected-result-6-7.hs | 7 ++++++- region-tests/expected-result-6-8.hs | 7 ++++++- ...d-result-9-13.hs => expected-result-9-12.hs} | 7 ++++++- region-tests/expected-result-all.hs | 6 ++++++ region-tests/src.hs | 7 ++++++- src/Ormolu/Parser.hs | 8 +++++--- src/Ormolu/Parser/Result.hs | 4 +++- src/Ormolu/Printer.hs | 2 +- src/Ormolu/Processing/Postprocess.hs | 12 ++++++++++-- src/Ormolu/Utils.hs | 14 ++++++++++++++ 13 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 region-tests/expected-result-17-18.hs rename region-tests/{expected-result-9-13.hs => expected-result-9-12.hs} (60%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ae2075..5424576 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,10 @@ * Fixed the bug when type applications glued to 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). + ## Ormolu 0.1.0.0 * Fixed rendering of type signatures concerning several identifiers. [Issue diff --git a/default.nix b/default.nix index 21a58d2..754cef9 100644 --- a/default.nix +++ b/default.nix @@ -132,17 +132,19 @@ in { cp src.hs result-all-implicit.hs ormolu --check-idempotence --mode inplace result-all-implicit.hs cp src.hs result-all-explicit.hs - ormolu --check-idempotence --mode inplace --start-line 1 --end-line 13 result-all-explicit.hs + ormolu --check-idempotence --mode inplace --start-line 1 --end-line 18 result-all-explicit.hs cp src.hs result-only-start.hs ormolu --check-idempotence --mode inplace --start-line 1 result-only-start.hs cp src.hs result-only-end.hs - ormolu --check-idempotence --mode inplace --end-line 13 result-only-end.hs + ormolu --check-idempotence --mode inplace --end-line 18 result-only-end.hs cp src.hs result-6-7.hs ormolu --check-idempotence --mode inplace --start-line 6 --end-line 7 result-6-7.hs cp src.hs result-6-8.hs ormolu --check-idempotence --mode inplace --start-line 6 --end-line 8 result-6-8.hs - cp src.hs result-9-13.hs - ormolu --check-idempotence --mode inplace --start-line 9 --end-line 13 result-9-13.hs + cp src.hs result-9-12.hs + ormolu --check-idempotence --mode inplace --start-line 9 --end-line 12 result-9-12.hs + cp src.hs result-17-18.hs + ormolu --check-idempotence --mode inplace --start-line 17 --end-line 18 result-17-18.hs ''; checkPhase = '' echo result-all-implicit.hs @@ -157,8 +159,10 @@ in { diff --color=always expected-result-6-7.hs result-6-7.hs echo result-6-8.hs diff --color=always expected-result-6-8.hs result-6-8.hs - echo result-9-13.hs - diff --color=always expected-result-9-13.hs result-9-13.hs + echo result-9-12.hs + diff --color=always expected-result-9-12.hs result-9-12.hs + echo result-17-18.hs + diff --color=always expected-result-17-18.hs result-17-18.hs ''; installPhase = '' mkdir "$out" diff --git a/region-tests/expected-result-17-18.hs b/region-tests/expected-result-17-18.hs new file mode 100644 index 0000000..a07a660 --- /dev/null +++ b/region-tests/expected-result-17-18.hs @@ -0,0 +1,17 @@ +{-# LANGUAGE LambdaCase #-} + +module Foo ( + foo, bar, baz) where + +foo :: Int +foo = 5 + +bar :: Int -> Int +bar = \case + 0 -> foo + x -> x - foo + +baz :: Int -> Int +baz = gege + where + gege = 1 + 2 diff --git a/region-tests/expected-result-6-7.hs b/region-tests/expected-result-6-7.hs index 2655016..13b09b2 100644 --- a/region-tests/expected-result-6-7.hs +++ b/region-tests/expected-result-6-7.hs @@ -1,7 +1,7 @@ {-# LANGUAGE LambdaCase #-} module Foo ( - foo, bar) where + foo, bar, baz) where foo :: Int foo = 5 @@ -10,3 +10,8 @@ bar :: Int -> Int bar = \case 0 -> foo x -> x - foo + +baz :: Int -> Int +baz = gege + where + gege = 1 + 2 diff --git a/region-tests/expected-result-6-8.hs b/region-tests/expected-result-6-8.hs index 2c81fbc..46f1ebb 100644 --- a/region-tests/expected-result-6-8.hs +++ b/region-tests/expected-result-6-8.hs @@ -1,7 +1,7 @@ {-# LANGUAGE LambdaCase #-} module Foo ( - foo, bar) where + foo, bar, baz) where foo :: Int foo = 5 @@ -9,3 +9,8 @@ bar :: Int -> Int bar = \case 0 -> foo x -> x - foo + +baz :: Int -> Int +baz = gege + where + gege = 1 + 2 diff --git a/region-tests/expected-result-9-13.hs b/region-tests/expected-result-9-12.hs similarity index 60% rename from region-tests/expected-result-9-13.hs rename to region-tests/expected-result-9-12.hs index f2d158a..ad791d8 100644 --- a/region-tests/expected-result-9-13.hs +++ b/region-tests/expected-result-9-12.hs @@ -1,7 +1,7 @@ {-# LANGUAGE LambdaCase #-} module Foo ( - foo, bar) where + foo, bar, baz) where foo :: Int foo = 5 @@ -10,3 +10,8 @@ bar :: Int -> Int bar = \case 0 -> foo x -> x - foo + +baz :: Int -> Int +baz = gege + where + gege = 1 + 2 diff --git a/region-tests/expected-result-all.hs b/region-tests/expected-result-all.hs index 47f2be2..65b2f01 100644 --- a/region-tests/expected-result-all.hs +++ b/region-tests/expected-result-all.hs @@ -3,6 +3,7 @@ module Foo ( foo, bar, + baz, ) where @@ -13,3 +14,8 @@ bar :: Int -> Int bar = \case 0 -> foo x -> x - foo + +baz :: Int -> Int +baz = gege + where + gege = 1 + 2 diff --git a/region-tests/src.hs b/region-tests/src.hs index 5cbd93e..99730ff 100644 --- a/region-tests/src.hs +++ b/region-tests/src.hs @@ -1,7 +1,7 @@ {-# LANGUAGE LambdaCase #-} module Foo ( - foo, bar) where + foo, bar, baz) where foo :: Int foo = 5 @@ -10,3 +10,8 @@ bar :: Int -> Int bar = \case 0 -> foo x -> x - foo + +baz :: Int -> Int +baz = gege + where + gege = 1 + 2 diff --git a/src/Ormolu/Parser.hs b/src/Ormolu/Parser.hs index 1bc3d40..dab8eac 100644 --- a/src/Ormolu/Parser.hs +++ b/src/Ormolu/Parser.hs @@ -32,7 +32,7 @@ import Ormolu.Parser.Anns import Ormolu.Parser.CommentStream import Ormolu.Parser.Result import Ormolu.Processing.Preprocess (preprocess) -import Ormolu.Utils (incSpanLine) +import Ormolu.Utils (incSpanLine, removeIndentation) import qualified Panic as GHC import qualified Parser as GHC import qualified StringBuffer as GHC @@ -51,8 +51,9 @@ parseModule :: Either (SrcSpan, String) ParseResult ) parseModule Config {..} path rawInput = liftIO $ do - let (literalPrefix, input, literalSuffix, extraComments) = + let (literalPrefix, indentedInput, literalSuffix, extraComments) = preprocess path rawInput cfgRegion + (input, indent) = removeIndentation indentedInput -- It's important that 'setDefaultExts' is done before -- 'parsePragmasIntoDynFlags', because otherwise we might enable an -- extension that was explicitly disabled in the file. @@ -110,7 +111,8 @@ parseModule Config {..} path rawInput = liftIO $ do prImportQualifiedPost = GHC.xopt ImportQualifiedPost dynFlags, prLiteralPrefix = T.pack literalPrefix, - prLiteralSuffix = T.pack literalSuffix + prLiteralSuffix = T.pack literalSuffix, + prIndent = indent } return (warnings, r) diff --git a/src/Ormolu/Parser/Result.hs b/src/Ormolu/Parser/Result.hs index 5b16075..3367a2e 100644 --- a/src/Ormolu/Parser/Result.hs +++ b/src/Ormolu/Parser/Result.hs @@ -35,7 +35,9 @@ data ParseResult = ParseResult -- | Literal prefix prLiteralPrefix :: Text, -- | Literal suffix - prLiteralSuffix :: Text + prLiteralSuffix :: Text, + -- | Indentation level, can be non-zero in case of region formatting + prIndent :: Int } -- | Pretty-print a 'ParseResult'. diff --git a/src/Ormolu/Printer.hs b/src/Ormolu/Printer.hs index a062226..25ee6fa 100644 --- a/src/Ormolu/Printer.hs +++ b/src/Ormolu/Printer.hs @@ -23,7 +23,7 @@ printModule ParseResult {..} = prLiteralPrefix <> region <> prLiteralSuffix where region = - postprocess $ + postprocess prIndent $ runR ( p_hsModule prStackHeader diff --git a/src/Ormolu/Processing/Postprocess.hs b/src/Ormolu/Processing/Postprocess.hs index ddc7f31..1e68ab8 100644 --- a/src/Ormolu/Processing/Postprocess.hs +++ b/src/Ormolu/Processing/Postprocess.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ViewPatterns #-} -- | Postprocessing for the results of printing. @@ -12,12 +13,19 @@ import Ormolu.Processing.Common import qualified Ormolu.Processing.Cpp as Cpp -- | Postprocess output of the formatter. -postprocess :: Text -> Text -postprocess = +postprocess :: + -- | Desired indentation level + Int -> + -- | Input to process + Text -> + Text +postprocess indent = T.unlines + . fmap indentLine . fmap Cpp.unmaskLine . filter (not . magicComment) . T.lines where magicComment (T.stripStart -> x) = x == startDisabling || x == endDisabling + indentLine x = T.replicate indent " " <> x diff --git a/src/Ormolu/Utils.hs b/src/Ormolu/Utils.hs index 9f00e5a..ff482c8 100644 --- a/src/Ormolu/Utils.hs +++ b/src/Ormolu/Utils.hs @@ -1,5 +1,6 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ViewPatterns #-} -- | Random utilities used by the code. module Ormolu.Utils @@ -15,9 +16,11 @@ module Ormolu.Utils separatedByBlank, separatedByBlankNE, onTheSameLine, + removeIndentation, ) where +import Data.Char (isSpace) import Data.List (dropWhileEnd) import qualified Data.List.NonEmpty as NE import Data.List.NonEmpty (NonEmpty (..)) @@ -139,3 +142,14 @@ separatedByBlankNE loc a b = separatedByBlank loc (NE.last a) (NE.head b) onTheSameLine :: SrcSpan -> SrcSpan -> Bool onTheSameLine a b = isOneLineSpan (mkSrcSpan (srcSpanEnd a) (srcSpanStart b)) + +-- | Remove indentation from a given 'String'. Return the input with +-- indentation removed and the detected indentation level. +removeIndentation :: String -> (String, Int) +removeIndentation (lines -> xs) = (unlines (drop n <$> xs), n) + where + n = minimum (getIndent <$> xs) + getIndent y = + if all isSpace y + then 0 + else length (takeWhile isSpace y)