ormolu 0.8.1.0 → 0.8.1.1
raw patch · 20 files changed
+113/−17 lines, 20 filesPVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
API changes (from Hackage documentation)
+ Ormolu.Imports: instance GHC.Classes.Eq Ormolu.Imports.ImportDeclLevelOrd
+ Ormolu.Imports: instance GHC.Classes.Ord Ormolu.Imports.ImportDeclLevelOrd
Files
- CHANGELOG.md +8/−0
- data/examples/declaration/value/function/case-single-line-with-braces-out.hs +2/−0
- data/examples/declaration/value/function/case-single-line-with-braces.hs +2/−0
- data/examples/declaration/value/function/do-multiline-with-case-out.hs +13/−0
- data/examples/declaration/value/function/do-multiline-with-case.hs +13/−0
- data/examples/declaration/value/function/do-single-line-case-guards-out.hs +2/−0
- data/examples/declaration/value/function/do-single-line-case-guards.hs +2/−0
- data/examples/declaration/value/function/do-single-line-lambda-case-out.hs +2/−0
- data/examples/declaration/value/function/do-single-line-lambda-case.hs +2/−0
- data/examples/declaration/value/function/do-single-line-multiple-cases-out.hs +2/−0
- data/examples/declaration/value/function/do-single-line-multiple-cases.hs +2/−0
- data/examples/declaration/value/function/do-single-line-nested-case-out.hs +2/−0
- data/examples/declaration/value/function/do-single-line-nested-case.hs +2/−0
- data/examples/declaration/value/function/do-single-line-with-case-out.hs +2/−0
- data/examples/declaration/value/function/do-single-line-with-case.hs +2/−0
- data/examples/import/explicit-level-imports-out.hs +3/−0
- data/examples/import/explicit-level-imports.hs +4/−0
- ormolu.cabal +1/−1
- src/Ormolu/Imports.hs +20/−2
- src/Ormolu/Printer/Meat/Declaration/Value.hs +27/−14
CHANGELOG.md view
@@ -1,3 +1,11 @@+## Ormolu 0.8.1.1++* Add missing braces for case expressions in single‑line do blocks. [Issue+ 1180](https://github.com/tweag/ormolu/issues/1180).++* Fix the import grouping logic in the presence of imports with explicit+ levels. [Issue 1192](https://github.com/tweag/ormolu/issues/1192).+ ## Ormolu 0.8.1.0 * Fixed printing of guards on pattern binds. [Issue
+ data/examples/declaration/value/function/case-single-line-with-braces-out.hs view
@@ -0,0 +1,2 @@+getValue :: Maybe Int -> Int+getValue x = case x of Just n -> n; Nothing -> 0
+ data/examples/declaration/value/function/case-single-line-with-braces.hs view
@@ -0,0 +1,2 @@+getValue :: Maybe Int -> Int+getValue x = case x of {Just n -> n; Nothing -> 0}
+ data/examples/declaration/value/function/do-multiline-with-case-out.hs view
@@ -0,0 +1,13 @@+handleInput :: IO ()+handleInput = do+ putStrLn "Enter command:"+ cmd <- getLine+ case cmd of+ "quit" -> putStrLn "Goodbye"+ "help" -> do+ putStrLn "Available commands:"+ putStrLn " quit - exit the program"+ putStrLn " help - show this message"+ _ -> do+ putStrLn $ "Unknown command: " ++ cmd+ handleInput
+ data/examples/declaration/value/function/do-multiline-with-case.hs view
@@ -0,0 +1,13 @@+handleInput :: IO ()+handleInput = do+ putStrLn "Enter command:"+ cmd <- getLine+ case cmd of+ "quit" -> putStrLn "Goodbye"+ "help" -> do+ putStrLn "Available commands:"+ putStrLn " quit - exit the program"+ putStrLn " help - show this message"+ _ -> do+ putStrLn $ "Unknown command: " ++ cmd+ handleInput
+ data/examples/declaration/value/function/do-single-line-case-guards-out.hs view
@@ -0,0 +1,2 @@+checkValue :: Int -> IO ()+checkValue n = do putStr "Value is: "; case () of { _ | n < 0 -> putStrLn "negative" | n == 0 -> putStrLn "zero" | otherwise -> putStrLn "positive" }
+ data/examples/declaration/value/function/do-single-line-case-guards.hs view
@@ -0,0 +1,2 @@+checkValue :: Int -> IO ()+checkValue n = do {putStr "Value is: "; case () of {_ | n < 0 -> putStrLn "negative" | n == 0 -> putStrLn "zero" | otherwise -> putStrLn "positive"}}
+ data/examples/declaration/value/function/do-single-line-lambda-case-out.hs view
@@ -0,0 +1,2 @@+processValue :: Maybe Int -> IO ()+processValue x = do putStrLn "Processing:"; \case { Just n -> print n; Nothing -> putStrLn "Empty" } x; putStrLn "Done"
+ data/examples/declaration/value/function/do-single-line-lambda-case.hs view
@@ -0,0 +1,2 @@+processValue :: Maybe Int -> IO ()+processValue x = do {putStrLn "Processing:"; \case {Just n -> print n; Nothing -> putStrLn "Empty"} x; putStrLn "Done"}
+ data/examples/declaration/value/function/do-single-line-multiple-cases-out.hs view
@@ -0,0 +1,2 @@+processPair :: Maybe Int -> Maybe String -> IO ()+processPair x y = do case x of { Just n -> print n; Nothing -> putStrLn "No number" }; case y of { Just s -> putStrLn s; Nothing -> putStrLn "No string" }
+ data/examples/declaration/value/function/do-single-line-multiple-cases.hs view
@@ -0,0 +1,2 @@+processPair :: Maybe Int -> Maybe String -> IO ()+processPair x y = do {case x of {Just n -> print n; Nothing -> putStrLn "No number"}; case y of {Just s -> putStrLn s; Nothing -> putStrLn "No string"}}
+ data/examples/declaration/value/function/do-single-line-nested-case-out.hs view
@@ -0,0 +1,2 @@+nestedDo :: Either String Int -> IO ()+nestedDo e = do putStr "Start: "; case e of { Left s -> do { putStr "Error: "; putStrLn s }; Right n -> do { putStr "Value: "; print n } }; putStrLn "End"
+ data/examples/declaration/value/function/do-single-line-nested-case.hs view
@@ -0,0 +1,2 @@+nestedDo :: Either String Int -> IO ()+nestedDo e = do {putStr "Start: "; case e of {Left s -> do {putStr "Error: "; putStrLn s}; Right n -> do {putStr "Value: "; print n}}; putStrLn "End"}
+ data/examples/declaration/value/function/do-single-line-with-case-out.hs view
@@ -0,0 +1,2 @@+doGuessing :: (Ord t, Read t) => t -> IO ()+doGuessing num = do putStrLn "Enter your guess:"; guess <- getLine; case compare (read guess) num of { LT -> do { putStrLn "Too low!"; doGuessing num }; GT -> do { putStrLn "Too high!"; doGuessing num }; EQ -> putStrLn "You win!" }
+ data/examples/declaration/value/function/do-single-line-with-case.hs view
@@ -0,0 +1,2 @@+doGuessing :: (Ord t, Read t) => t -> IO ()+doGuessing num = do {putStrLn "Enter your guess:"; guess <- getLine; case compare (read guess) num of {LT -> do {putStrLn "Too low!"; doGuessing num}; GT -> do { putStrLn "Too high!"; doGuessing num}; EQ -> putStrLn "You win!"}}
data/examples/import/explicit-level-imports-out.hs view
@@ -8,3 +8,6 @@ import Data.ByteString (e) import Data.ByteString.Lazy quote (d) import splice Data.Text (a, b, c)+import PyF ()+import splice PyF (fmt, tmf)+import quote PyF (abc)
data/examples/import/explicit-level-imports.hs view
@@ -8,3 +8,7 @@ import qualified C splice as SC import A splice import qualified D splice+import quote PyF (abc)+import splice PyF (fmt)+import splice PyF (tmf)+import PyF ()
ormolu.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: ormolu-version: 0.8.1.0+version: 0.8.1.1 license: BSD-3-Clause license-file: LICENSE.md maintainer: Mark Karpov <mark.karpov@tweag.io>
src/Ormolu/Imports.hs view
@@ -71,10 +71,23 @@ importSafe :: Bool, importQualified :: Bool, importAs :: Maybe ModuleName,- importHiding :: Maybe ImportListInterpretationOrd+ importHiding :: Maybe ImportListInterpretationOrd,+ importLevel :: Maybe ImportDeclLevelOrd } deriving (Eq, Ord) +-- | A wrapper for 'ImportDeclLevel' that provides an 'Ord' instance.+newtype ImportDeclLevelOrd = ImportDeclLevelOrd+ { unImportDeclLevelOrd :: ImportDeclLevel+ }+ deriving stock (Eq)++instance Ord ImportDeclLevelOrd where+ compare = compare `on` toBool . unImportDeclLevelOrd+ where+ toBool ImportDeclSplice = False+ toBool ImportDeclQuote = True+ data ImportPkgQual = -- | The import is not qualified by a package name. NoImportPkgQual@@ -118,11 +131,16 @@ QualifiedPost -> True NotQualified -> False, importAs = unLoc <$> ideclAs,- importHiding = ImportListInterpretationOrd . fst <$> ideclImportList+ importHiding = ImportListInterpretationOrd . fst <$> ideclImportList,+ importLevel = importLevelOf ideclLevelSpec } where isPrelude = moduleNameString moduleName == "Prelude" moduleName = unLoc ideclName+ importLevelOf = \case+ LevelStylePre l -> Just (ImportDeclLevelOrd l)+ LevelStylePost l -> Just (ImportDeclLevelOrd l)+ NotLevelled -> Nothing -- | Normalize a collection of import items. normalizeLies :: [LIE GhcPs] -> [LIE GhcPs]
src/Ormolu/Printer/Meat/Declaration/Value.hs view
@@ -94,15 +94,15 @@ MatchGroup GhcPs (LocatedA body) -> R () p_matchGroup' placer render style mg@MG {..} = do- let ob = case style of- Case -> bracesIfEmpty- LambdaCase -> bracesIfEmpty- _ -> dontUseBraces- where- bracesIfEmpty = if isEmptyMatchGroup mg then useBraces else id -- Since we are forcing braces on 'sepSemi' based on 'ob', we have to -- restore the brace state inside the sepsemi. ub <- bool dontUseBraces useBraces <$> canUseBraces+ let ob = case style of+ Case -> bracesIfNecessary+ LambdaCase -> bracesIfNecessary+ _ -> dontUseBraces+ where+ bracesIfNecessary = if isEmptyMatchGroup mg then useBraces else ub ob $ sepSemi (located' (ub . p_Match)) (unLoc mg_alts) where p_Match m@Match {..} =@@ -370,10 +370,10 @@ located cmd (p_hsCmd' Applicand s) breakpoint inci $ located expr p_hsExpr- HsCmdLam _ variant mgroup -> p_lam isApp variant cmdPlacement p_hsCmd mgroup+ HsCmdLam _ variant mgroup -> p_lam isApp s variant cmdPlacement p_hsCmd mgroup HsCmdPar _ c -> parens N (located c p_hsCmd) HsCmdCase _ e mgroup ->- p_case isApp cmdPlacement p_hsCmd e mgroup+ p_case isApp s cmdPlacement p_hsCmd e mgroup HsCmdIf anns _ if' then' else' -> p_if cmdPlacement p_hsCmd anns if' then' else' HsCmdLet _ localBinds c ->@@ -602,6 +602,15 @@ Applicand -> inci . inci NotApplicand -> inci +-- | Adjust bracing as needed for certain cases e.g. involving case+-- expressions and lambdas.+adjustBracing :: IsApplicand -> BracketStyle -> R () -> R ()+adjustBracing isApp s p = do+ layout <- getLayout+ case (s, layout, isApp) of+ (S, SingleLine, NotApplicand) -> useBraces p+ _ -> p+ p_hsExpr' :: IsApplicand -> BracketStyle -> HsExpr GhcPs -> R () p_hsExpr' isApp s = \case HsVar _ name -> p_rdrName name@@ -619,7 +628,7 @@ HsMultilineString (SourceText stxt) _ -> p_stringLit stxt r -> atom r HsLam _ variant mgroup ->- p_lam isApp variant exprPlacement p_hsExpr mgroup+ p_lam isApp s variant exprPlacement p_hsExpr mgroup HsApp _ f x -> do let -- In order to format function applications with multiple parameters -- nicer, traverse the AST to gather the function and all the@@ -728,7 +737,7 @@ ExplicitSum _ tag arity e -> p_unboxedSum N tag arity (located e p_hsExpr) HsCase _ e mgroup ->- p_case isApp exprPlacement p_hsExpr e mgroup+ p_case isApp s exprPlacement p_hsExpr e mgroup HsIf anns if' then' else' -> p_if exprPlacement p_hsExpr anns if' then' else' HsMultiIf _ guards -> do@@ -1045,6 +1054,7 @@ Anno (Match GhcPs (LocatedA body)) ~ SrcSpanAnnA ) => IsApplicand ->+ BracketStyle -> -- | Placer (body -> Placement) -> -- | Render@@ -1054,20 +1064,23 @@ -- | Match group MatchGroup GhcPs (LocatedA body) -> R ()-p_case isApp placer render e mgroup = do+p_case isApp s placer render e mgroup = do txt "case" space located e p_hsExpr space txt "of" breakpoint- inciApplicand isApp (p_matchGroup' placer render Case mgroup)+ adjustBracing isApp s $+ inciApplicand isApp (p_matchGroup' placer render Case mgroup) p_lam :: ( Anno (GRHS GhcPs (LocatedA body)) ~ EpAnnCO, Anno (Match GhcPs (LocatedA body)) ~ SrcSpanAnnA ) => IsApplicand ->+ -- | BracketStyle (S when inside a do block)+ BracketStyle -> -- | Variant (@\\@ or @\\case@ or @\\cases@) HsLamVariant -> -- | Placer@@ -1077,7 +1090,7 @@ -- | Expression MatchGroup GhcPs (LocatedA body) -> R ()-p_lam isApp variant placer render mgroup = do+p_lam isApp s variant placer render mgroup = do let mCaseTxt = case variant of LamSingle -> Nothing LamCase -> Just "\\case"@@ -1089,7 +1102,7 @@ Just caseTxt -> do txt caseTxt breakpoint- inciApplicand isApp pMatchGroup+ adjustBracing isApp s (inciApplicand isApp pMatchGroup) p_if :: -- | Placer