fourmolu 0.0.6.0 → 0.1.0.0
raw patch · 27 files changed
+265/−102 lines, 27 filesdep +aesondep +directorydep +yamldep ~filepathnew-uploaderPVP ok
version bump matches the API change (PVP)
Dependencies added: aeson, directory, yaml
Dependency ranges changed: filepath
API changes (from Hackage documentation)
+ Ormolu: PrinterOpts :: Int -> PrinterOpts
+ Ormolu: [cfgPrinterOpts] :: Config region -> PrinterOpts
+ Ormolu: [poIndentStep] :: PrinterOpts -> Int
+ Ormolu: data PrinterOpts
+ Ormolu: defaultPrinterOpts :: PrinterOpts
+ Ormolu: loadConfigFile :: Bool -> Maybe FilePath -> PrinterOpts -> IO PrinterOpts
+ Ormolu.Config: PrinterOpts :: Int -> PrinterOpts
+ Ormolu.Config: [cfgPrinterOpts] :: Config region -> PrinterOpts
+ Ormolu.Config: [poIndentStep] :: PrinterOpts -> Int
+ Ormolu.Config: data PrinterOpts
+ Ormolu.Config: defaultPrinterOpts :: PrinterOpts
+ Ormolu.Config: instance Data.Aeson.Types.FromJSON.FromJSON Ormolu.Config.PrinterOptsPartial
+ Ormolu.Config: instance GHC.Classes.Eq Ormolu.Config.PrinterOpts
+ Ormolu.Config: instance GHC.Classes.Eq Ormolu.Config.PrinterOptsPartial
+ Ormolu.Config: instance GHC.Generics.Generic Ormolu.Config.PrinterOptsPartial
+ Ormolu.Config: instance GHC.Show.Show Ormolu.Config.PrinterOpts
+ Ormolu.Config: instance GHC.Show.Show Ormolu.Config.PrinterOptsPartial
+ Ormolu.Config: loadConfigFile :: Bool -> Maybe FilePath -> PrinterOpts -> IO PrinterOpts
+ Ormolu.Printer: PrinterOpts :: Int -> PrinterOpts
+ Ormolu.Printer: [poIndentStep] :: PrinterOpts -> Int
+ Ormolu.Printer: data PrinterOpts
+ Ormolu.Printer.Operators: instance GHC.Classes.Eq Ormolu.Printer.Operators.Score
+ Ormolu.Printer.Operators: instance GHC.Classes.Ord Ormolu.Printer.Operators.Score
- Ormolu: Config :: ![DynOption] -> !Bool -> !Bool -> !Bool -> !region -> Config region
+ Ormolu: Config :: ![DynOption] -> !Bool -> !Bool -> !Bool -> !region -> PrinterOpts -> Config region
- Ormolu.Config: Config :: ![DynOption] -> !Bool -> !Bool -> !Bool -> !region -> Config region
+ Ormolu.Config: Config :: ![DynOption] -> !Bool -> !Bool -> !Bool -> !region -> PrinterOpts -> Config region
- Ormolu.Printer: printModule :: ParseResult -> Text
+ Ormolu.Printer: printModule :: ParseResult -> PrinterOpts -> Text
- Ormolu.Printer.Combinators: runR :: R () -> SpanStream -> CommentStream -> Anns -> Bool -> Text
+ Ormolu.Printer.Combinators: runR :: R () -> SpanStream -> CommentStream -> Anns -> PrinterOpts -> Bool -> Text
- Ormolu.Printer.Internal: runR :: R () -> SpanStream -> CommentStream -> Anns -> Bool -> Text
+ Ormolu.Printer.Internal: runR :: R () -> SpanStream -> CommentStream -> Anns -> PrinterOpts -> Bool -> Text
Files
- CHANGELOG.md +15/−4
- app/Main.hs +5/−1
- data/examples/declaration/value/function/infix/do-out.hs +2/−2
- data/examples/declaration/value/function/operators-0-out.hs +5/−0
- data/examples/declaration/value/function/operators-0.hs +4/−0
- data/examples/declaration/value/function/operators-1-out.hs +4/−0
- data/examples/declaration/value/function/operators-1.hs +3/−0
- data/examples/declaration/value/function/operators-2-out.hs +4/−0
- data/examples/declaration/value/function/operators-2.hs +4/−0
- data/examples/declaration/value/function/operators-3-out.hs +3/−0
- data/examples/declaration/value/function/operators-3.hs +3/−0
- data/examples/declaration/value/function/operators-4-out.hs +3/−0
- data/examples/declaration/value/function/operators-4.hs +3/−0
- data/examples/declaration/value/function/operators-5-out.hs +5/−0
- data/examples/declaration/value/function/operators-5.hs +4/−0
- data/examples/declaration/value/function/operators-6-out.hs +9/−0
- data/examples/declaration/value/function/operators-6.hs +7/−0
- data/examples/declaration/value/function/operators-out.hs +0/−5
- data/examples/declaration/value/function/operators.hs +0/−4
- fourmolu.cabal +7/−3
- src/Ormolu.hs +5/−2
- src/Ormolu/Config.hs +93/−2
- src/Ormolu/Printer.hs +5/−1
- src/Ormolu/Printer/Internal.hs +14/−16
- src/Ormolu/Printer/Meat/Declaration/Value.hs +12/−4
- src/Ormolu/Printer/Operators.hs +43/−56
- tests/Ormolu/PrinterSpec.hs +3/−2
CHANGELOG.md view
@@ -1,14 +1,18 @@-## Fourmolu 0.0.6.0+## Fourmolu 0.1.0.0 -* The project was fourked to provide four space indent.+* Allow configuration of indentation size via `fourmolu.yaml` config files. +* An operator on a new line is no longer indented when its left operand is a do-block. This prevents the AST from potentially changing when indenting by more than two spaces.++Upstream changes:+ * Fixed 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. [Issue 450](https://github.com/tweag/ormolu/issues/450). -* Fixed an idempotence issue when certain comments where picked up as+* Fixed 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). @@ -27,7 +31,7 @@ multiple blank lines in a row. [Issue 518](https://github.com/tweag/ormolu/issues/518). -* Fixed rendering of comment around if expressions. [Issue+* Fixed 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 `-- ^`@@ -37,8 +41,15 @@ * Fixed 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+ 522](https://github.com/tweag/ormolu/issues/522).+ * Renamed the `--check-idempotency` flag to `--check-idempotence`. Apparently only the latter is correct.++## Fourmolu 0.0.6.0++* The project was fourked to provide four space indent. ## Ormolu 0.0.5.0
app/Main.hs view
@@ -25,7 +25,10 @@ main :: IO () main = withPrettyOrmoluExceptions $ do Opts {..} <- execParser optsParserInfo- let formatOne' = formatOne optMode optConfig+ let formatOne' path = do+ printerOpts <-+ loadConfigFile (cfgDebug optConfig) path $ cfgPrinterOpts optConfig+ formatOne optMode optConfig {cfgPrinterOpts = printerOpts} path case optInputFiles of [] -> formatOne' Nothing ["-"] -> formatOne' Nothing@@ -183,6 +186,7 @@ help "End line of the region to format (inclusive)" ] )+ <*> pure defaultPrinterOpts ---------------------------------------------------------------------------- -- Helpers
data/examples/declaration/value/function/infix/do-out.hs view
@@ -1,7 +1,7 @@ main = do stuff- `finally` do- recover+ `finally` do+ recover main = do stuff `finally` recover
+ data/examples/declaration/value/function/operators-0-out.hs view
@@ -0,0 +1,5 @@+a =+ b & c .~ d+ & e+ %~ f+ g
+ data/examples/declaration/value/function/operators-0.hs view
@@ -0,0 +1,4 @@+a =+ b & c .~ d+ & e %~ f+ g
+ data/examples/declaration/value/function/operators-1-out.hs view
@@ -0,0 +1,4 @@+foo =+ f+ . g+ =<< h . i
+ data/examples/declaration/value/function/operators-1.hs view
@@ -0,0 +1,3 @@+foo = f+ . g+ =<< h . i
+ data/examples/declaration/value/function/operators-2-out.hs view
@@ -0,0 +1,4 @@+foo n+ | x || y && z || n ** x+ || x && n =+ 42
+ data/examples/declaration/value/function/operators-2.hs view
@@ -0,0 +1,4 @@+foo n+ | x || y && z || n ** x+ || x && n =+ 42
+ data/examples/declaration/value/function/operators-3-out.hs view
@@ -0,0 +1,3 @@+foo =+ op <> n <+> colon <+> prettySe <+> text "="+ <+> prettySe <> text sc
+ data/examples/declaration/value/function/operators-3.hs view
@@ -0,0 +1,3 @@+foo =+ op <> n <+> colon <+> prettySe <+> text "=" <+>+ prettySe <> text sc
+ data/examples/declaration/value/function/operators-4-out.hs view
@@ -0,0 +1,3 @@+foo =+ line <> bindingOf <+> text "=" <+> tPretty <+> colon+ <+> align <> prettyPs
+ data/examples/declaration/value/function/operators-4.hs view
@@ -0,0 +1,3 @@+foo =+ line <> bindingOf <+> text "=" <+> tPretty <+> colon <+>+ align <> prettyPs
+ data/examples/declaration/value/function/operators-5-out.hs view
@@ -0,0 +1,5 @@+foo =+ map bar $+ [ baz+ ]+ ++ quux
+ data/examples/declaration/value/function/operators-5.hs view
@@ -0,0 +1,4 @@+foo =+ map bar $+ [ baz+ ] ++ quux
+ data/examples/declaration/value/function/operators-6-out.hs view
@@ -0,0 +1,9 @@+type PermuteRef =+ "a"+ :> ( "b" :> "c" :> End+ :<|> "c" :> "b" :> End+ )+ :<|> "b"+ :> ( "a" :> "c" :> End+ :<|> "c" :> "a" :> End+ )
+ data/examples/declaration/value/function/operators-6.hs view
@@ -0,0 +1,7 @@+type PermuteRef =+ "a" :> ( "b" :> "c" :> End+ :<|> "c" :> "b" :> End+ )+ :<|> "b" :> ( "a" :> "c" :> End+ :<|> "c" :> "a" :> End+ )
− data/examples/declaration/value/function/operators-out.hs
@@ -1,5 +0,0 @@-a =- b & c .~ d- & e- %~ f- g
− data/examples/declaration/value/function/operators.hs
@@ -1,4 +0,0 @@-a =- b & c .~ d- & e %~ f- g
fourmolu.cabal view
@@ -1,9 +1,9 @@ cabal-version: 1.18 name: fourmolu-version: 0.0.6.0+version: 0.1.0.0 license: BSD3 license-file: LICENSE.md-maintainer: Matt Parsons <parsonsmatt@gmail.com>+maintainer: Matt Parsons <parsonsmatt@gmail.com>, George Thomas <georgefsthomas@gmail.com> tested-with: ghc ==8.6.5 ghc ==8.8.3 ghc ==8.10.1 homepage: https://github.com/parsonsmatt/fourmolu bug-reports: https://github.com/parsonsmatt/fourmolu/issues@@ -116,15 +116,19 @@ default-language: Haskell2010 build-depends:+ aeson >=1.5.2 && <1.6, base >=4.12 && <5.0, bytestring >=0.2 && <0.11, containers >=0.5 && <0.7,+ directory >= 1.3.5 && <1.4, dlist >=0.8 && <0.9, exceptions >=0.6 && <0.11,+ filepath >=1.4.2.1 && <1.5, ghc-lib-parser >=8.10 && <8.11, mtl >=2.0 && <3.0, syb >=0.7 && <0.8,- text >=0.2 && <1.3+ text >=0.2 && <1.3,+ yaml >=0.11.2 && <0.12 if flag(dev) ghc-options:
src/Ormolu.hs view
@@ -9,6 +9,9 @@ RegionIndices (..), defaultConfig, DynOption (..),+ PrinterOpts (..),+ defaultPrinterOpts,+ loadConfigFile, OrmoluException (..), withPrettyOrmoluExceptions, )@@ -62,7 +65,7 @@ -- about not-yet-supported functionality) will be thrown later 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 !txt = printModule result0+ let !txt = printModule result0 $ cfgPrinterOpts cfgWithIndices when (not (cfgUnsafe cfg) || cfgCheckIdempotence cfg) $ do let pathRendered = path ++ "<rendered>" -- Parse the result of pretty-printing again and make sure that AST@@ -80,7 +83,7 @@ -- Try re-formatting the formatted result to check if we get exactly -- the same output. when (cfgCheckIdempotence cfg) $- let txt2 = printModule result1+ let txt2 = printModule result1 $ cfgPrinterOpts cfgWithIndices in case diffText txt txt2 pathRendered of Nothing -> return () Just (loc, l, r) ->
src/Ormolu/Config.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards #-} -- | Configuration options used by the tool.@@ -7,13 +9,38 @@ RegionIndices (..), RegionDeltas (..), defaultConfig,+ PrinterOpts (..),+ defaultPrinterOpts,+ loadConfigFile, regionIndicesToDeltas, DynOption (..), dynOptionToLocatedStr, ) where +import Control.Monad (when)+import Data.Aeson+ ( FromJSON (..),+ camelTo2,+ defaultOptions,+ fieldLabelModifier,+ genericParseJSON,+ rejectUnknownFields,+ )+import Data.List (stripPrefix)+import Data.Maybe (fromMaybe)+import Data.Yaml (decodeFileEither, prettyPrintParseException)+import GHC.Generics (Generic) import qualified SrcLoc as GHC+import System.Directory+ ( XdgDirectory (XdgConfig),+ findFile,+ getCurrentDirectory,+ getXdgDirectory,+ makeAbsolute,+ )+import System.FilePath ((</>), splitPath)+import System.IO (hPutStrLn, stderr) -- | Ormolu configuration. data Config region = Config@@ -26,7 +53,8 @@ -- | Checks if re-formatting the result is idempotent cfgCheckIdempotence :: !Bool, -- | Region selection- cfgRegion :: !region+ cfgRegion :: !region,+ cfgPrinterOpts :: PrinterOpts } deriving (Eq, Show, Functor) @@ -61,9 +89,20 @@ RegionIndices { regionStartLine = Nothing, regionEndLine = Nothing- }+ },+ cfgPrinterOpts = defaultPrinterOpts } +-- | Options controlling formatting output+data PrinterOpts = PrinterOpts+ { -- | Number of spaces to use for indentation+ poIndentStep :: Int+ }+ deriving (Eq, Show)++defaultPrinterOpts :: PrinterOpts+defaultPrinterOpts = PrinterOpts {poIndentStep = 4}+ -- | Convert 'RegionIndices' into 'RegionDeltas'. regionIndicesToDeltas :: -- | Total number of lines in the input@@ -87,3 +126,55 @@ -- | Convert 'DynOption' to @'GHC.Located' 'String'@. dynOptionToLocatedStr :: DynOption -> GHC.Located String dynOptionToLocatedStr (DynOption o) = GHC.L GHC.noSrcSpan o++-- | A version of 'PrinterOpts' where any field can be empty.+-- This corresponds to the information in a config file.+data PrinterOptsPartial = PrinterOptsPartial+ { popIndentation :: Maybe Int+ }+ deriving (Eq, Show, Generic)++instance FromJSON PrinterOptsPartial where+ parseJSON =+ genericParseJSON+ defaultOptions+ { rejectUnknownFields = True,+ fieldLabelModifier = camelTo2 '_' . fromMaybe "" . stripPrefix "pop"+ }++-- | Replace fields with those from a config file, if found.+-- Looks recursively in parent folders, then in 'XdgConfig',+-- for a file matching /fourmolu.yaml/'.+loadConfigFile :: Bool -> Maybe FilePath -> PrinterOpts -> IO PrinterOpts+loadConfigFile debug maybePath PrinterOpts {..} = do+ root <- maybe getCurrentDirectory makeAbsolute maybePath+ xdg <- getXdgDirectory XdgConfig ""+ PrinterOptsPartial {..} <-+ optsFromFile debug $ reverse $ xdg : scanl1 (</>) (splitPath root)+ return $+ PrinterOpts+ { poIndentStep = fromMaybe poIndentStep popIndentation+ }++-- | Search the directories, in order, for a config file.+optsFromFile :: Bool -> [FilePath] -> IO PrinterOptsPartial+optsFromFile debug dirs =+ findFile dirs configFileName >>= \case+ Nothing -> do+ printDebug $+ "No " ++ show configFileName ++ " found in any of:\n"+ ++ unlines (map (" " ++) dirs)+ return def+ Just file -> do+ printDebug $ "Found " ++ show file ++ ""+ decodeFileEither file >>= \case+ Left e -> do+ printDebug $ prettyPrintParseException e+ return def+ Right x -> return x+ where+ def = PrinterOptsPartial Nothing+ printDebug = when debug . hPutStrLn stderr++configFileName :: FilePath+configFileName = "fourmolu.yaml"
src/Ormolu/Printer.hs view
@@ -3,10 +3,12 @@ -- | Pretty-printer for Haskell AST. module Ormolu.Printer ( printModule,+ PrinterOpts (..), ) where import Data.Text (Text)+import Ormolu.Config import Ormolu.Parser.Result import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Module@@ -17,9 +19,10 @@ printModule :: -- | Result of parsing ParseResult ->+ PrinterOpts -> -- | Resulting rendition Text-printModule ParseResult {..} =+printModule ParseResult {..} printerOpts = prLiteralPrefix <> region <> prLiteralSuffix where region =@@ -35,4 +38,5 @@ (mkSpanStream prParsedSource) prCommentStream prAnns+ printerOpts prUseRecordDot
src/Ormolu/Printer/Internal.hs view
@@ -63,6 +63,7 @@ import qualified Data.Text.Lazy as TL import Data.Text.Lazy.Builder import GHC+import Ormolu.Config import Ormolu.Parser.Anns import Ormolu.Parser.CommentStream import Ormolu.Printer.SpanStream@@ -92,7 +93,8 @@ -- | Whether the last expression in the layout can use braces rcCanUseBraces :: Bool, -- | Whether the source could have used the record dot preprocessor- rcUseRecDot :: Bool+ rcUseRecDot :: Bool,+ rcPrinterOpts :: PrinterOpts } -- | State context of 'R'.@@ -158,11 +160,12 @@ CommentStream -> -- | Annotations Anns ->+ PrinterOpts -> -- | Use Record Dot Syntax Bool -> -- | Resulting rendition Text-runR (R m) sstream cstream anns recDot =+runR (R m) sstream cstream anns printerOpts recDot = TL.toStrict . toLazyText . scBuilder $ execState (runReaderT m rc) sc where rc =@@ -172,7 +175,8 @@ rcEnclosingSpans = [], rcAnns = anns, rcCanUseBraces = False,- rcUseRecDot = recDot+ rcUseRecDot = recDot,+ rcPrinterOpts = printerOpts } sc = SC@@ -373,12 +377,13 @@ -- to be valid Haskell. When layout is single-line there is no obvious -- effect, but with multi-line layout correct indentation levels matter. inci :: R () -> R ()-inci (R m) = R (local modRC m)- where- modRC rc =- rc- { rcIndent = rcIndent rc + indentStep- }+inci (R m) = do+ indentStep <- R (asks (poIndentStep . rcPrinterOpts))+ let modRC rc =+ rc+ { rcIndent = rcIndent rc + indentStep+ }+ R (local modRC m) -- | Set indentation level for the inner computation equal to current -- column. This makes sure that the entire inner block is uniformly@@ -566,10 +571,3 @@ -- | Return 'True' if we can use braces in this context. canUseBraces :: R Bool canUseBraces = R (asks rcCanUseBraces)--------------------------------------------------------------------------------- Constants---- | Indentation step.-indentStep :: Int-indentStep = 4
src/Ormolu/Printer/Meat/Declaration/Value.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ViewPatterns #-} module Ormolu.Printer.Meat.Declaration.Value ( p_valDecl,@@ -1324,10 +1325,17 @@ inci p_y else do ub lhs- placeHanging placement $ do- p_op- space- p_y+ let opAndRhs = do+ p_op+ space+ p_y+ case x of+ -- This case prevents an operator from being indented past the start of a `do` block+ -- constituting its left operand, thus altering the AST.+ -- This is only relevant when the `do` block is on one line, as otherwise we will+ -- insert a newline after `do` anyway.+ OpNode (unLoc -> HsDo _ _ _) | isOneLineSpan (opTreeLoc x) -> breakpoint >> opAndRhs+ _ -> placeHanging placement opAndRhs -- | Return 'True' if given expression is a record-dot operator expression. isRecordDot ::
src/Ormolu/Printer/Operators.hs view
@@ -12,8 +12,9 @@ import Data.Function (on) import qualified Data.List as L+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as M import Data.Maybe (fromMaybe, mapMaybe)-import Data.Ord (Down (Down), comparing) import GHC import OccName (mkVarOcc) import Ormolu.Utils (unSrcSpan)@@ -56,7 +57,7 @@ reassociateOpTreeWith :: forall ty op. -- | Fixity map for operators- [(RdrName, Fixity)] ->+ Map RdrName Fixity -> -- | How to get the name of an operator (op -> Maybe RdrName) -> -- | Original 'OpTree'@@ -68,12 +69,12 @@ fixityOf :: op -> Fixity fixityOf op = fromMaybe defaultFixity $ do opName <- getOpName op- lookup opName fixityMap+ M.lookup opName fixityMap -- Here, left branch is already associated and the root alongside with -- the right branch is right-associated. This function picks up one item -- from the right and inserts it correctly to the left. --- -- Also, we are using the 'compareFixity' function which returns if the+ -- Also, we are using the 'compareFixity' function which tells if the -- expression should associate to right. go :: OpTree ty op -> OpTree ty op -- base cases@@ -93,6 +94,16 @@ then go $ OpBranch (OpBranch l op (go $ OpBranch r op' l')) op'' r' else go $ OpBranch (OpBranch (OpBranch l op r) op' l') op'' r' +-- | A score assigned to an operator.+data Score+ = -- | The operator was placed at the beginning of a line+ AtBeginning Int+ | -- | The operator was placed at the end of a line+ AtEnd+ | -- | The operator was placed in between arguments on a single line+ InBetween+ deriving (Eq, Ord)+ -- | Build a map of inferred 'Fixity's from an 'OpTree'. buildFixityMap :: forall ty op.@@ -101,23 +112,26 @@ -- | Operator tree OpTree (Located ty) (Located op) -> -- | Fixity map- [(RdrName, Fixity)]+ Map RdrName Fixity buildFixityMap getOpName opTree =- concatMap (\(i, ns) -> map (\(n, _) -> (n, fixity i InfixL)) ns)- . zip [0 ..]- . L.groupBy (doubleWithinEps 0.00001 `on` snd)- . (overrides ++)- . modeScores+ addOverrides+ . M.fromList+ . concatMap (\(i, ns) -> map (\(n, _) -> (n, fixity i InfixL)) ns)+ . zip [1 ..]+ . L.groupBy ((==) `on` snd)+ . selectScores $ score opTree where- -- Add a special case for ($), since it is pretty unlikely for someone- -- to override it.- overrides :: [(RdrName, Double)]- overrides =- [ (mkRdrUnqual $ mkVarOcc "$", -1)- ]- -- Assign scores to operators based on their location in the source.- score :: OpTree (Located ty) (Located op) -> [(RdrName, Double)]+ addOverrides :: Map RdrName Fixity -> Map RdrName Fixity+ addOverrides m =+ let mk k v = (mkRdrUnqual (mkVarOcc k), fixity v InfixL)+ in M.fromList+ [ mk "$" 0,+ mk "." 9+ ]+ `M.union` m+ fixity = Fixity NoSourceText+ score :: OpTree (Located ty) (Located op) -> [(RdrName, Score)] score (OpNode _) = [] score (OpBranch l o r) = fromMaybe (score r) $ do -- If we fail to get any of these, 'defaultFixity' will be used by@@ -129,46 +143,25 @@ oc <- srcSpanStartCol <$> unSrcSpan (getLoc o) -- operator column opName <- getOpName (unLoc o) let s- | le < ob =- -- if the operator is in the beginning of a line, assign- -- a score relative to its column within range [0, 1).- fromIntegral oc / fromIntegral (maxCol + 1)- | oe < rb =- -- if the operator is in the end of the line, assign the- -- score 1.- 1- | otherwise =- 2 -- otherwise, assign a high score.+ | le < ob = AtBeginning oc+ | oe < rb = AtEnd+ | otherwise = InBetween return $ (opName, s) : score r- -- Pick the most common score per 'RdrName'.- modeScores :: [(RdrName, Double)] -> [(RdrName, Double)]- modeScores =+ selectScores :: [(RdrName, Score)] -> [(RdrName, Score)]+ selectScores = L.sortOn snd . mapMaybe ( \case [] -> Nothing- xs@((n, _) : _) -> Just (n, mode $ map snd xs)+ xs@((n, _) : _) -> Just (n, selectScore $ map snd xs) ) . L.groupBy ((==) `on` fst) . L.sort- -- Return the most common number, leaning to the smaller- -- one in case of a tie.- mode :: [Double] -> Double- mode =- head- . L.minimumBy (comparing (Down . length))- . L.groupBy (doubleWithinEps 0.0001)- . L.sort- -- The start column of the rightmost operator.- maxCol = go opTree- where- go (OpNode (L _ _)) = 0- go (OpBranch l (L o _) r) =- maximum- [ go l,- maybe 0 srcSpanStartCol (unSrcSpan o),- go r- ]+ selectScore :: [Score] -> Score+ selectScore xs =+ case filter (/= InBetween) xs of+ [] -> InBetween+ xs' -> maximum xs' ---------------------------------------------------------------------------- -- Helpers@@ -182,9 +175,3 @@ OpBranch (OpNode l) lop (normalizeOpTree r) normalizeOpTree (OpBranch (OpBranch l' lop' r') lop r) = normalizeOpTree (OpBranch l' lop' (OpBranch r' lop r))--fixity :: Int -> FixityDirection -> Fixity-fixity = Fixity NoSourceText--doubleWithinEps :: Double -> Double -> Double -> Bool-doubleWithinEps eps a b = abs (a - b) < eps
tests/Ormolu/PrinterSpec.hs view
@@ -24,12 +24,13 @@ checkExample :: Path Rel File -> Spec checkExample srcPath' = it (fromRelFile srcPath' ++ " works") . withNiceExceptions $ do let srcPath = examplesDir </> srcPath'+ cfg = defaultConfig {cfgPrinterOpts = PrinterOpts {poIndentStep = 2}} expectedOutputPath <- deriveOutput srcPath -- 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 the original snippet. (This happens in -- 'ormoluFile' automatically.)- formatted0 <- ormoluFile defaultConfig (fromRelFile srcPath)+ formatted0 <- ormoluFile cfg (fromRelFile srcPath) -- 3. Check the output against expected output. Thus all tests should -- include two files: input and expected output. -- T.writeFile (fromRelFile expectedOutputPath) formatted0@@ -37,7 +38,7 @@ shouldMatch False formatted0 expected -- 4. Check that running the formatter on the output produces the same -- output again (the transformation is idempotent).- formatted1 <- ormolu defaultConfig "<formatted>" (T.unpack formatted0)+ formatted1 <- ormolu cfg "<formatted>" (T.unpack formatted0) shouldMatch True formatted1 formatted0 -- | Build list of examples for testing.