brittany 0.9.0.0 → 0.9.0.1
raw patch · 18 files changed
+306/−105 lines, 18 filesdep ~butcherdep ~ghc-exactprintPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: butcher, ghc-exactprint
API changes (from Hackage documentation)
+ Language.Haskell.Brittany: [_lconfig_hangingTypeSignature] :: CLayoutConfig f -> f (Last Bool)
+ Language.Haskell.Brittany.Internal.Config: [_lconfig_hangingTypeSignature] :: CLayoutConfig f -> f (Last Bool)
+ Language.Haskell.Brittany.Internal.Config.Types: [_lconfig_hangingTypeSignature] :: CLayoutConfig f -> f (Last Bool)
+ Language.Haskell.Brittany.Internal.PreludeUtils: putStrErr :: String -> IO ()
+ Paths_brittany: getDynLibDir :: IO FilePath
- Language.Haskell.Brittany: LayoutConfig :: f (Last Int) -> f (Last IndentPolicy) -> f (Last Int) -> f (Last Bool) -> f (Last Bool) -> f (Last Int) -> f (Last AltChooser) -> f (Last ColumnAlignMode) -> f (Last Int) -> f (Last Bool) -> CLayoutConfig f
+ Language.Haskell.Brittany: LayoutConfig :: f (Last Int) -> f (Last IndentPolicy) -> f (Last Int) -> f (Last Bool) -> f (Last Bool) -> f (Last Int) -> f (Last AltChooser) -> f (Last ColumnAlignMode) -> f (Last Int) -> f (Last Bool) -> f (Last Bool) -> CLayoutConfig f
- Language.Haskell.Brittany.Internal.Config: LayoutConfig :: f (Last Int) -> f (Last IndentPolicy) -> f (Last Int) -> f (Last Bool) -> f (Last Bool) -> f (Last Int) -> f (Last AltChooser) -> f (Last ColumnAlignMode) -> f (Last Int) -> f (Last Bool) -> CLayoutConfig f
+ Language.Haskell.Brittany.Internal.Config: LayoutConfig :: f (Last Int) -> f (Last IndentPolicy) -> f (Last Int) -> f (Last Bool) -> f (Last Bool) -> f (Last Int) -> f (Last AltChooser) -> f (Last ColumnAlignMode) -> f (Last Int) -> f (Last Bool) -> f (Last Bool) -> CLayoutConfig f
- Language.Haskell.Brittany.Internal.Config.Types: LayoutConfig :: f (Last Int) -> f (Last IndentPolicy) -> f (Last Int) -> f (Last Bool) -> f (Last Bool) -> f (Last Int) -> f (Last AltChooser) -> f (Last ColumnAlignMode) -> f (Last Int) -> f (Last Bool) -> CLayoutConfig f
+ Language.Haskell.Brittany.Internal.Config.Types: LayoutConfig :: f (Last Int) -> f (Last IndentPolicy) -> f (Last Int) -> f (Last Bool) -> f (Last Bool) -> f (Last Int) -> f (Last AltChooser) -> f (Last ColumnAlignMode) -> f (Last Int) -> f (Last Bool) -> f (Last Bool) -> CLayoutConfig f
Files
- ChangeLog.md +17/−0
- README.md +47/−11
- brittany.cabal +3/−3
- src-brittany/Main.hs +13/−12
- src-literatetests/10-tests.blt +20/−3
- src-literatetests/15-regressions.blt +15/−3
- src-literatetests/Main.hs +1/−0
- src-literatetests/tests-context-free.blt +10/−5
- src-unittests/TestUtils.hs +1/−0
- src/Language/Haskell/Brittany/Internal.hs +5/−0
- src/Language/Haskell/Brittany/Internal/Backend.hs +5/−1
- src/Language/Haskell/Brittany/Internal/Config.hs +5/−3
- src/Language/Haskell/Brittany/Internal/Config/Types.hs +11/−0
- src/Language/Haskell/Brittany/Internal/ExactPrintUtils.hs +21/−6
- src/Language/Haskell/Brittany/Internal/Layouters/Decl.hs +64/−22
- src/Language/Haskell/Brittany/Internal/Layouters/Expr.hs +32/−33
- src/Language/Haskell/Brittany/Internal/Layouters/Pattern.hs +33/−3
- src/Language/Haskell/Brittany/Internal/PreludeUtils.hs +3/−0
ChangeLog.md view
@@ -1,10 +1,27 @@ # Revision history for brittany +## 0.9.0.1 -- February 2018++* Support `TupleSections` (thanks to Matthew Piziak)+* Bugfixes:+ - Fix Shebang handling with stdin input (#92)+ - Fix bug that effectively deleted strict/lazy matches (BangPatterns) (#116)+ - Fix infix operator whitespace bug (#101, #114)+ - Fix help command output and its layouting (#103)+ - Fix crash when config dir does not exist yet (#115)+* Layouting changes:+ - no space after opening non-tuple parenthesis even for multi-line case+ - use spaces around infix operators (applies to sections and in pattern+ matches)+ - Let-in is layouted more flexibly in fewer lines, if possible+ (thanks to Evan Borden)+ ## 0.9.0.0 -- December 2017 * Change default global config path (use XDG spec) Existing config should still be respected, so this should not break compatibility+* Support per-project config * ! Slight rework of the commandline interface: - Support multiple inputs and outputs - Support inplace-transformation for multiple files via
README.md view
@@ -43,14 +43,21 @@ accidentally quadratic sub-algorithm); noticable for inputs with >1k loc.~~ (fixed in `0.8.0.3`) +## Try without Installing++You can [paste haskell code over here](https://hexagoxel.de/brittany/)+to test how it gets formatted by brittany. (Rg. privacy: the server does+log the size of the input, but _not_ the full requests.)+ # Other usage notes - Supports GHC versions `8.0.*` and `8.2.*`.-- as of November'17, `brittany` is available on stackage nightly.+- included in stackage with lts>=10.0 (or nightlies dating to >=2017-11-15) - config (file) documentation is lacking. - some config values can not be configured via commandline yet.-- uses/creates user config file in `~/.brittany/config.yaml`;- also reads `brittany.yaml` in current dir if present.+- uses/creates user config file in `~/.config/brittany/config.yaml`;+ also reads (the first) `brittany.yaml` found in current or parent+ directories. # Installation @@ -75,23 +82,52 @@ cp `./find dist-newstyle/build/ -type f -name brittany` $HOME/.cabal/bin/ ~~~~ -- via `stack`+- via `stack` using a sufficiently recent stackage snapshot (dated to >= 2017-11-15) ~~~~.sh- git clone https://github.com/lspitzner/brittany.git- cd brittany- stack install+ stack install brittany # --resolver lts-10.0 ~~~~ + (earlier ltss did not include `brittany` yet, but the repo should contain a+ `stack.yaml` that works with ghc-8.0.) +- on ArchLinux via [the britanny AUR package](https://aur.archlinux.org/packages/brittany/)+ using `aura`:+ ~~~~.sh+ aura -A brittany+ ~~~~++# Editor Integration++#### Sublime text+ [In this gist](https://gist.github.com/lspitzner/097c33177248a65e7657f0c6d0d12075)+ I have described a haskell setup that includes a shortcut to run brittany formatting.+#### VSCode+ [This extension](https://marketplace.visualstudio.com/items?itemName=MaxGabriel.brittany)+ connects commandline `brittany` to VSCode formatting API. Thanks to @MaxGarbriel.+#### Via HIE+ [haskell-ide-engine](https://github.com/haskell/haskell-ide-engine)+ includes a `brittany` plugin that directly uses the brittany library.+ Relevant for any editors that properly support the language-server-protocol.+#### Neovim / Vim 8+ The [Neoformat](https://github.com/sbdchd/neoformat) plugin comes with support for+ brittany built in.+ # Usage -- Currently one mode of operation: Transform a single module. By default read- from `stdin` and written to `stdout`, but commandline arguments allow to- read/write from/to files.+- Default mode of operation: Transform a single module, from `stdin` to `stdout`.+ Can pass one or multiple files as input, and there is a flag to override them+ in place instead of using `stdout` (since 0.9.0.0). So:+ + ~~~~ .sh+ brittany # stdin -> stdout+ brittany mysource.hs # ./mysource.hs -> stdout+ brittany --write-mode=inplace *.hs # apply formatting to all ./*.hs inplace+ ~~~~+ - For stdin/stdout usage it makes sense to enable certain syntactic extensions by default, i.e. to add something like this to your- `~/.brittany/config.yaml` (execute `brittany` once to create default):+ `~/.config/brittany/config.yaml` (execute `brittany` once to create default): ~~~~ conf_forward:
brittany.cabal view
@@ -1,5 +1,5 @@ name: brittany-version: 0.9.0.0+version: 0.9.0.1 synopsis: Haskell source code formatter description: { See <https://github.com/lspitzner/brittany/blob/master/README.md the README>.@@ -82,7 +82,7 @@ { base >=4.9 && <4.11 , ghc >=8.0.1 && <8.3 , ghc-paths >=0.1.0.9 && <0.2- , ghc-exactprint >=0.5.3.0 && <0.6+ , ghc-exactprint >=0.5.6.0 && <0.5.7 , transformers >=0.5.2.0 && <0.6 , containers >=0.5.7.1 && <0.6 , mtl >=2.2.1 && <2.3@@ -94,7 +94,7 @@ , pretty >=1.1.3.3 && <1.2 , bytestring >=0.10.8.1 && <0.11 , directory >=1.2.6.2 && <1.4- , butcher >=1.2 && <1.3+ , butcher >=1.3 && <1.4 , yaml >=0.8.18 && <0.9 , aeson >=1.0.1.0 && <1.3 , extra >=1.4.10 && <1.7
src-brittany/Main.hs view
@@ -82,9 +82,10 @@ ] , parDocW [ "This program is written carefully and contains safeguards to ensure"- , "the transformation does not change semantics (or the syntax tree at all)"- , "and that no comments are removed."- , "Nonetheless, this is a young project, and there will always be bugs."+ , "the output is syntactically valid and that no comments are removed."+ , "Nonetheless, this is a young project, and there will always be bugs,"+ , "and ensuring that the transformation never changes semantics of the"+ , "transformed source is currently not possible." , "Please do check the output and do not let brittany override your large" , "codebase without having backups." ]@@ -140,16 +141,16 @@ "" ["write-mode"] "(display|inplace)"- Flag- { _flag_help = Just $ PP.vcat+ ( flagHelp+ ( PP.vcat [ PP.text "display: output for any input(s) goes to stdout" , PP.text "inplace: override respective input file (without backup!)" ]- , _flag_default = Just Display- }- inputParams <- addParamNoFlagStrings "PATH" (paramHelpStr "paths to input haskell source files")+ )+ <> flagDefault Display+ )+ inputParams <- addParamNoFlagStrings "PATH" (paramHelpStr "paths to input/inout haskell source files") reorderStop- desc <- peekCmdDesc addCmdImpl $ void $ do when printLicense $ do print licenseDoc@@ -161,7 +162,7 @@ putStrLn $ "There is NO WARRANTY, to the extent permitted by law." System.Exit.exitSuccess when printHelp $ do- liftIO $ print $ ppHelpShallow desc+ liftIO $ putStrLn $ PP.renderStyle PP.style { PP.ribbonsPerLine = 1.0 } $ ppHelpShallow helpDesc System.Exit.exitSuccess let inputPaths = if null inputParams then [Nothing] else map Just inputParams@@ -281,7 +282,7 @@ putErrorLn $ "Error: detected unprocessed comments." ++ " The transformation output will most likely"- ++ " not contain certain of the comments"+ ++ " not contain some of the comments" ++ " present in the input haskell source file." putErrorLn $ "Affected are the following comments:" unused `forM_` \case@@ -346,7 +347,7 @@ userConfigXdg <- readConfig userConfigPathXdg let userConfig = userConfigSimple <|> userConfigXdg when (Data.Maybe.isNothing userConfig) $ do- liftIO $ Directory.createDirectoryIfMissing False userBritPathXdg+ liftIO $ Directory.createDirectoryIfMissing True userBritPathXdg writeDefaultConfig userConfigPathXdg -- rightmost has highest priority pure $ [userConfig, localConfig]
src-literatetests/10-tests.blt view
@@ -349,13 +349,16 @@ func (A a) = a #test list constructor-func (x:xr) = x+func (x : xr) = x #test some other constructor symbol #pending-func (x:+:xr) = x+func (x :+: xr) = x +#test normal infix constructor+func (x `Foo` xr) = x + ############################################################################### ############################################################################### ###############################################################################@@ -476,8 +479,22 @@ #group tuples ### -#test 1+#test pair func = (abc, def)++#test pair section left+func = (abc, )++#test pair section right+func = (, abc)++#test quintuple section long+myTupleSection =+ ( verylaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaargefirstelement+ ,+ , verylaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaargethirdelement+ ,+ ) #test 2 #pending
src-literatetests/15-regressions.blt view
@@ -123,8 +123,8 @@ #test list comprehension comment placement func = [ (thing, take 10 alts) --TODO: select best ones- | (thing, _got, alts@(_:_)) <- nosuchFooThing- , gast <- award+ | (thing, _got, alts@(_ : _)) <- nosuchFooThing+ , gast <- award ] #test if-then-else comment placement@@ -219,7 +219,7 @@ , entry "Versions installed" installedVersions- ( altText+ (altText null (if hasLib pkginfo then "[ Not installed ]" else "[ Unknown ]") )@@ -513,3 +513,15 @@ #test issue 70 {-# LANGUAGE TemplateHaskell #-} deriveFromJSON (unPrefix "assignPost") ''AssignmentPost++#test issue 116+{-# LANGUAGE BangPatterns #-}+func = do+ let !forced = some+ pure ()++#test let-in-hanging+spanKey p q = case minViewWithKey q of+ Just ((k, _), q') | p k ->+ let (kas, q'') = spanKey p q' in ((k, a) : kas, q'')+ _ -> ([], q)
src-literatetests/Main.hs view
@@ -173,6 +173,7 @@ , _lconfig_columnAlignMode = coerce (ColumnAlignModeMajority 0.7) , _lconfig_alignmentLimit = coerce (30 :: Int) , _lconfig_alignmentBreakOnMultiline = coerce True+ , _lconfig_hangingTypeSignature = coerce False } , _conf_errorHandling = (_conf_errorHandling staticDefaultConfig) { _econf_omit_output_valid_check = coerce True
src-literatetests/tests-context-free.blt view
@@ -366,11 +366,11 @@ func (A a) = a #test list constructor-func (x:xr) = x+func (x : xr) = x #test some other constructor symbol #pending-func (x:+:xr) = x+func (x :+: xr) = x ###############################################################################@@ -510,8 +510,13 @@ func = (lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd , lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd) +#test let in on single line+foo =+ let longIdentifierForShortValue = 1+ in longIdentifierForShortValue + longIdentifierForShortValue + ############################################################################### ############################################################################### ###############################################################################@@ -714,7 +719,7 @@ #test some indentation thingy func =- ( lkjadljasldjalskdjaldjalsdjkalsdjlaksdjlasjdlajsaldskj+ (lkjadljasldjalskdjaldjalsdjkalsdjlaksdjlasjdlajsaldskj $ abc $ def $ ghi@@ -743,7 +748,7 @@ #test list comprehension comment placement func = [ (thing, take 10 alts) --TODO: select best ones- | (thing, _got, alts@(_:_)) <- nosuchFooThing+ | (thing, _got, alts@(_ : _)) <- nosuchFooThing , gast <- award ] @@ -840,7 +845,7 @@ , entry "Versions installed" installedVersions- ( altText+ (altText null (if hasLib pkginfo then "[ Not installed ]" else "[ Unknown ]") )
src-unittests/TestUtils.hs view
@@ -55,6 +55,7 @@ , _lconfig_columnAlignMode = coerce (ColumnAlignModeMajority 0.7) , _lconfig_alignmentLimit = coerce (30 :: Int) , _lconfig_alignmentBreakOnMultiline = coerce True+ , _lconfig_hangingTypeSignature = coerce False } , _conf_errorHandling = (_conf_errorHandling staticDefaultConfig) { _econf_ExactPrintFallback = coerce ExactPrintFallbackModeNever
src/Language/Haskell/Brittany/Internal.hs view
@@ -61,6 +61,11 @@ -- -- Note that this function ignores/resets all config values regarding -- debugging, i.e. it will never use `trace`/write to stderr.+--+-- Note that the ghc parsing function used internally currently is wrapped in+-- `mask_`, so cannot be killed easily. If you don't control the input, you+-- may wish to put some proper upper bound on the input's size as a timeout+-- won't do. parsePrintModule :: Config -> Text -> IO (Either [BrittanyError] Text) parsePrintModule configRaw inputText = runExceptT $ do let config = configRaw { _conf_debug = _conf_debug staticDefaultConfig }
src/Language/Haskell/Brittany/Internal/Backend.hs view
@@ -352,7 +352,11 @@ -- maxZipper xs [] = xs -- maxZipper (x:xr) (y:yr) = max x y : maxZipper xr yr colAggregation :: [Int] -> Int- colAggregation xs = maximum [ x | x <- xs, x < minimum xs + alignMax ]+ colAggregation [] = 0 -- this probably cannot happen the way we call+ -- this function, because _cbs_map only ever+ -- contains nonempty Seqs.+ colAggregation xs = maximum [ x | x <- xs, x <= minimum xs + alignMax' ]+ where alignMax' = max 0 alignMax processedMap :: ColMap2 processedMap =
src/Language/Haskell/Brittany/Internal/Config.hs view
@@ -63,6 +63,7 @@ , _lconfig_columnAlignMode = coerce (ColumnAlignModeMajority 0.7) , _lconfig_alignmentLimit = coerce (30 :: Int) , _lconfig_alignmentBreakOnMultiline = coerce True+ , _lconfig_hangingTypeSignature = coerce False } , _conf_errorHandling = ErrorHandlingConfig { _econf_produceOutputOnErrors = coerce False@@ -104,7 +105,7 @@ cols <- addFlagReadParams "" ["columns"] "AMOUNT" (flagHelpStr "target max columns (80 is an old default for this)") importCol <- addFlagReadParams "" ["import-col"] "N" (flagHelpStr "column to align import lists at") - dumpConfig <- addSimpleBoolFlag "" ["dump-config"] (flagHelp $ parDoc "dump the programs full config (commandline + file + defaults)")+ dumpConfig <- addSimpleBoolFlag "" ["dump-config"] (flagHelp $ parDoc "dump the programs full config (merged commandline + file + defaults)") dumpAnnotations <- addSimpleBoolFlag "" ["dump-annotations"] (flagHelp $ parDoc "dump the full annotations returned by ghc-exactprint") dumpUnknownAST <- addSimpleBoolFlag "" ["dump-ast-unknown"] (flagHelp $ parDoc "dump the ast for any nodes not transformed, but copied as-is by brittany") dumpCompleteAST <- addSimpleBoolFlag "" ["dump-ast-full"] (flagHelp $ parDoc "dump the full ast")@@ -118,9 +119,9 @@ dumpBriDocIndent <- addSimpleBoolFlag "" ["dump-bridoc-indent"] (flagHelp $ parDoc "dump the partially transformed bridoc: after transformation: indent") dumpBriDocFinal <- addSimpleBoolFlag "" ["dump-bridoc-final"] (flagHelp $ parDoc "dump the post-transformation bridoc") - outputOnErrors <- addSimpleBoolFlag "" ["output-on-errors"] (flagHelp $ parDoc "even when there are errors, produce output (or try to to the degree possible")+ outputOnErrors <- addSimpleBoolFlag "" ["output-on-errors"] (flagHelp $ parDoc "even when there are errors, produce output (or try to to the degree possible)") wError <- addSimpleBoolFlag "" ["werror"] (flagHelp $ parDoc "treat warnings as errors")- omitValidCheck <- addSimpleBoolFlag "" ["omit-output-check"] (flagHelp $ parDoc "omit checking if the output is syntactically valid; for dev on brittany")+ omitValidCheck <- addSimpleBoolFlag "" ["omit-output-check"] (flagHelp $ parDoc "omit checking if the output is syntactically valid (debugging)") roundtripOnly <- addSimpleBoolFlag "" ["exactprint-only"] (flagHelp $ parDoc "do not reformat, but exclusively use exactprint to roundtrip (debugging)") @@ -156,6 +157,7 @@ , _lconfig_columnAlignMode = mempty , _lconfig_alignmentLimit = mempty , _lconfig_alignmentBreakOnMultiline = mempty+ , _lconfig_hangingTypeSignature = mempty } , _conf_errorHandling = ErrorHandlingConfig { _econf_produceOutputOnErrors = wrapLast $ falseToNothing outputOnErrors
src/Language/Haskell/Brittany/Internal/Config/Types.hs view
@@ -73,6 +73,17 @@ -- short <- some more stuff -- that requires two lines -- loooooooong <- stuff+ , _lconfig_hangingTypeSignature :: f (Last Bool)+ -- Do not put "::" in a new line, and use hanging indentation for the+ -- signature, i.e.:+ -- func :: SomeLongStuff+ -- -> SomeLongStuff+ -- instead of the usual+ -- func+ -- :: SomeLongStuff+ -- -> SomeLongStuff+ -- As usual for hanging indentation, the result will be+ -- context-sensitive (in the function name). } deriving (Generic)
src/Language/Haskell/Brittany/Internal/ExactPrintUtils.hs view
@@ -24,11 +24,17 @@ import qualified GHC as GHC hiding (parseModule) import qualified Parser as GHC import qualified SrcLoc as GHC+import qualified FastString as GHC+import qualified GHC as GHC hiding (parseModule)+import qualified Lexer as GHC+import qualified StringBuffer as GHC+import qualified Outputable as GHC import RdrName ( RdrName(..) ) import HsSyn import SrcLoc ( SrcSpan, Located ) import RdrName ( RdrName(..) ) + import qualified Language.Haskell.GHC.ExactPrint as ExactPrint import qualified Language.Haskell.GHC.ExactPrint.Annotate as ExactPrint import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint@@ -37,6 +43,8 @@ import qualified Language.Haskell.GHC.ExactPrint.Delta as ExactPrint import qualified Data.Generics as SYB++import Control.Exception -- import Data.Generics.Schemes @@ -85,7 +93,14 @@ -> String -> IO (Either String (ExactPrint.Anns, GHC.ParsedSource, a)) parseModuleFromString args fp dynCheck str =- ExactPrint.ghcWrapper $ ExceptT.runExceptT $ do+ -- We mask here because otherwise using `throwTo` (i.e. for a timeout) will+ -- produce nasty looking errors ("ghc panic"). The `mask_` makes it so we+ -- cannot kill the parsing thread - not very nice. But i'll+ -- optimistically assume that most of the time brittany uses noticable or+ -- longer time, the majority of the time is not spend in parsing, but in+ -- bridoc transformation stuff.+ -- (reminder to update note on `parsePrintModule` if this changes.)+ mask_ $ ExactPrint.ghcWrapper $ ExceptT.runExceptT $ do dflags0 <- lift $ ExactPrint.initDynFlagsPure fp str (dflags1, leftover, warnings) <- lift $ GHC.parseDynamicFlagsCmdLine dflags0 (GHC.noLoc <$> args)@@ -97,12 +112,12 @@ $ ExceptT.throwE $ "when parsing ghc flags: encountered warnings: " ++ show (warnings <&> \(L _ s) -> s)- x <- ExceptT.ExceptT $ liftIO $ dynCheck dflags1- either (\(span, err) -> ExceptT.throwE $ show span ++ ": " ++ err)- (\(a, m) -> pure (a, m, x))- $ ExactPrint.parseWith dflags1 fp GHC.parseModule str+ dynCheckRes <- ExceptT.ExceptT $ liftIO $ dynCheck dflags1+ let res = ExactPrint.parseModuleFromStringInternal dflags1 fp str+ case res of+ Left (span, err) -> ExceptT.throwE $ show span ++ ": " ++ err+ Right (a , m ) -> pure (a, m, dynCheckRes) ------------ commentAnnFixTransformGlob :: SYB.Data ast => ast -> ExactPrint.Transform () commentAnnFixTransformGlob ast = do
src/Language/Haskell/Brittany/Internal/Layouters/Decl.hs view
@@ -52,23 +52,39 @@ let nameStr = Text.intercalate (Text.pack ", ") $ nameStrs typeDoc <- docSharedWrapper layoutType typ hasComments <- hasAnyCommentsBelow lsig- docAlt- $ [ docSeq- [ appSep $ docWrapNodeRest lsig $ docLit nameStr- , appSep $ docLit $ Text.pack "::"- , docForceSingleline typeDoc- ]- | not hasComments- ]- ++ [ docAddBaseY BrIndentRegular $ docPar- (docWrapNodeRest lsig $ docLit nameStr)- ( docCols- ColTyOpPrefix- [ docLit $ Text.pack ":: "- , docAddBaseY (BrIndentSpecial 3) $ typeDoc+ shouldBeHanging <- mAsk+ <&> _conf_layout+ .> _lconfig_hangingTypeSignature+ .> confUnpack+ if shouldBeHanging+ then docSeq+ [ appSep $ docWrapNodeRest lsig $ docLit nameStr+ , docSetBaseY $ docLines+ [ docCols+ ColTyOpPrefix+ [ docLit $ Text.pack ":: "+ , docAddBaseY (BrIndentSpecial 3) $ typeDoc+ ]+ ]+ ]+ else+ docAlt+ $ [ docSeq+ [ appSep $ docWrapNodeRest lsig $ docLit nameStr+ , appSep $ docLit $ Text.pack "::"+ , docForceSingleline typeDoc+ ]+ | not hasComments ]- )- ]+ ++ [ docAddBaseY BrIndentRegular $ docPar+ (docWrapNodeRest lsig $ docLit nameStr)+ ( docCols+ ColTyOpPrefix+ [ docLit $ Text.pack ":: "+ , docAddBaseY (BrIndentSpecial 3) $ typeDoc+ ]+ )+ ] InlineSig name (InlinePragma _ spec _arity phaseAct conlike) -> docWrapNode lsig $ do nameStr <- lrdrNameToTextAnn name@@ -176,16 +192,17 @@ -> BriDocNumbered -> LMatch RdrName (LHsExpr RdrName) -> ToBriDocM BriDocNumbered-layoutPatternBind mIdStr binderDoc lmatch@(L _ match@(Match _ pats _ (GRHSs grhss whereBinds))) = do+layoutPatternBind mIdStr binderDoc lmatch@(L _ match@(Match fixityOrCtx pats _ (GRHSs grhss whereBinds))) = do patDocs <- pats `forM` \p -> fmap return $ colsWrapPat =<< layoutPat p let isInfix = isInfixMatch match- patDoc <- docWrapNodePrior lmatch $ case (mIdStr, patDocs) of- (Just idStr, p1:pr) | isInfix -> docCols+ let mIdStr' = fixPatternBindIdentifier fixityOrCtx <$> mIdStr+ patDoc <- docWrapNodePrior lmatch $ case (mIdStr', patDocs) of+ (Just idStr, p1 : pr) | isInfix -> docCols ColPatternsFuncInfix ( [appSep $ docForceSingleline p1, appSep $ docLit idStr] ++ (spacifyDocs $ docForceSingleline <$> pr) )- (Just idStr, [] ) -> docLit idStr+ (Just idStr, []) -> docLit idStr (Just idStr, ps) -> docCols ColPatternsFuncPrefix $ appSep (docLit $ idStr)@@ -204,6 +221,28 @@ mWhereDocs hasComments +#if MIN_VERSION_ghc(8,2,0) /* ghc-8.2 */+fixPatternBindIdentifier+ :: HsMatchContext (NameOrRdrName RdrName) -> Text -> Text+fixPatternBindIdentifier ctx idStr = case ctx of+ (FunRhs _ _ SrcLazy ) -> Text.cons '~' idStr+ (FunRhs _ _ SrcStrict ) -> Text.cons '!' idStr+ (FunRhs _ _ NoSrcStrict) -> idStr+ (StmtCtxt ctx1 ) -> fixPatternBindIdentifier' ctx1+ _ -> idStr+ where+ -- I have really no idea if this path ever occurs, but better safe than+ -- risking another "drop bangpatterns" bugs.+ fixPatternBindIdentifier' = \case+ (PatGuard ctx1) -> fixPatternBindIdentifier ctx1 idStr+ (ParStmtCtxt ctx1) -> fixPatternBindIdentifier' ctx1+ (TransStmtCtxt ctx1) -> fixPatternBindIdentifier' ctx1+ _ -> idStr+#else /* ghc-8.0 */+fixPatternBindIdentifier :: MatchFixity RdrName -> Text -> Text+fixPatternBindIdentifier _ x = x+#endif+ layoutPatternBindFinal :: Maybe Text -> BriDocNumbered@@ -261,10 +300,13 @@ ] let singleLineGuardsDoc guards = appSep $ case guards of [] -> docEmpty- [g] -> docSeq [appSep $ docLit $ Text.pack "|", return g]+ [g] -> docSeq+ [appSep $ docLit $ Text.pack "|", docForceSingleline $ return g] gs -> docSeq $ [appSep $ docLit $ Text.pack "|"]- ++ List.intersperse docCommaSep (return <$> gs)+ ++ (List.intersperse docCommaSep+ (docForceSingleline . return <$> gs)+ ) indentPolicy <- mAsk <&> _conf_layout
src/Language/Haskell/Brittany/Internal/Layouters/Expr.hs view
@@ -327,7 +327,7 @@ ] , docSetBaseY $ docLines [ docCols ColOpPrefix- [ docParenLSep+ [ docLit $ Text.pack "(" , docAddBaseY (BrIndentSpecial 2) innerExpDoc ] , docLit $ Text.pack ")"@@ -341,9 +341,9 @@ opDoc <- docSharedWrapper layoutExpr op rightDoc <- docSharedWrapper layoutExpr right docSeq [opDoc, docSeparator, rightDoc]- ExplicitTuple args boxity- | Just argExprs <- args `forM` (\case (L _ (Present e)) -> Just e; _ -> Nothing) -> do- argDocs <- docSharedWrapper layoutExpr `mapM` argExprs+ ExplicitTuple args boxity -> do+ let argExprs = fmap (\case (L _ (Present e)) -> Just e; (L _ (Missing PlaceHolder)) -> Nothing) args+ argDocs <- docSharedWrapper (maybe docEmpty layoutExpr) `mapM` argExprs hasComments <- hasAnyCommentsBelow lexpr let (openLit, closeLit) = case boxity of Boxed -> (docLit $ Text.pack "(", docLit $ Text.pack ")")@@ -385,8 +385,6 @@ end = closeLit in docSetBaseY $ docLines $ [start] ++ linesM ++ [lineN] ++ [end] ]- ExplicitTuple{} ->- unknownNodeError "ExplicitTuple|.." lexpr HsCase cExp (MG lmatches@(L _ matches) _ _ _) -> do cExpDoc <- docSharedWrapper layoutExpr cExp binderDoc <- docLit $ Text.pack "->"@@ -533,6 +531,10 @@ HsLet binds exp1 -> do expDoc1 <- docSharedWrapper layoutExpr exp1 mBindDocs <- layoutLocalBinds binds+ let+ ifIndentLeftElse :: a -> a -> a+ ifIndentLeftElse x y =+ if indentPolicy == IndentPolicyLeft then x else y -- this `docSetIndentLevel` might seem out of place, but is here due to -- ghc-exactprint's DP handling of "let" in particular. -- Just pushing another indentation level is a straightforward approach@@ -540,39 +542,36 @@ -- if "let" is moved horizontally as part of the transformation, as the -- comments before the first let item are moved horizontally with it. docSetIndentLevel $ case mBindDocs of- Just [bindDoc] -> docAltFilter- [ ( True- , docSeq+ Just [bindDoc] -> docAlt+ [ docSeq [ appSep $ docLit $ Text.pack "let" , appSep $ docForceSingleline $ return bindDoc , appSep $ docLit $ Text.pack "in" , docForceSingleline $ expDoc1 ]- )- , ( indentPolicy /= IndentPolicyLeft- , docLines- [ docSeq- [ appSep $ docLit $ Text.pack "let"- , docSetBaseAndIndent $ return bindDoc- ]- , docSeq- [ appSep $ docLit $ Text.pack "in "- , docSetBaseY $ expDoc1- ]- ]- )- , ( True- , docLines- [ docAddBaseY BrIndentRegular- $ docPar- (appSep $ docLit $ Text.pack "let")- (docSetBaseAndIndent $ return bindDoc)- , docAddBaseY BrIndentRegular- $ docPar- (appSep $ docLit $ Text.pack "in")- (docSetBaseY $ expDoc1)+ , docLines+ [ docAlt+ [ docSeq+ [ appSep $ docLit $ Text.pack "let"+ , ifIndentLeftElse docForceSingleline docSetBaseAndIndent+ $ return bindDoc+ ]+ , docAddBaseY BrIndentRegular+ $ docPar+ (docLit $ Text.pack "let")+ (docSetBaseAndIndent $ return bindDoc)+ ]+ , docAlt+ [ docSeq+ [ appSep $ docLit $ Text.pack $ ifIndentLeftElse "in" "in "+ , ifIndentLeftElse docForceSingleline docSetBaseAndIndent expDoc1+ ]+ , docAddBaseY BrIndentRegular+ $ docPar+ (docLit $ Text.pack "in")+ (docSetBaseY $ expDoc1)+ ] ]- ) ] Just bindDocs@(_:_) -> docAltFilter --either
src/Language/Haskell/Brittany/Internal/Layouters/Pattern.hs view
@@ -24,12 +24,26 @@ +-- | layouts patterns (inside function bindings, case alternatives, let+-- bindings or do notation). E.g. for input+-- > case computation of+-- > (warnings, Success a b) -> ..+-- This part ^^^^^^^^^^^^^^^^^^^^^^^ of the syntax tree is layouted by+-- 'layoutPat'. Similarly for+-- > func abc True 0 = []+-- ^^^^^^^^^^ this part+-- We will use `case .. of` as the imagined prefix to the examples used in+-- the different cases below. layoutPat :: ToBriDocC (Pat RdrName) (Seq BriDocNumbered) layoutPat lpat@(L _ pat) = docWrapNode lpat $ case pat of WildPat _ -> fmap Seq.singleton $ docLit $ Text.pack "_"+ -- _ -> expr VarPat n -> fmap Seq.singleton $ docLit $ lrdrNameToText n+ -- abc -> expr LitPat lit -> fmap Seq.singleton $ allocateNode $ litBriDoc lit+ -- 0 -> expr ParPat inner -> do+ -- (nestedpat) -> expr left <- docLit $ Text.pack "(" right <- docLit $ Text.pack ")" innerDocs <- colsWrapPat =<< layoutPat inner@@ -49,6 +63,7 @@ -- xN' <- docSeq [return xN, docLit $ Text.pack ")"] -- return $ (x1' Seq.<| middle) Seq.|> xN' ConPatIn lname (PrefixCon args) -> do+ -- Abc a b c -> expr let nameDoc = lrdrNameToText lname argDocs <- layoutPat `mapM` args if null argDocs@@ -61,15 +76,19 @@ $ fmap colsWrapPat argDocs return $ x1 Seq.<| xR ConPatIn lname (InfixCon left right) -> do- let nameDoc = lrdrNameToText lname- leftDoc <- colsWrapPat =<< layoutPat left+ -- a :< b -> expr+ nameDoc <- lrdrNameToTextAnn lname+ leftDoc <- appSep . colsWrapPat =<< layoutPat left rightDoc <- colsWrapPat =<< layoutPat right- middle <- docLit nameDoc+ middle <- appSep $ docLit nameDoc return $ Seq.empty Seq.|> leftDoc Seq.|> middle Seq.|> rightDoc ConPatIn lname (RecCon (HsRecFields [] Nothing)) -> do+ -- Abc{} -> expr let t = lrdrNameToText lname fmap Seq.singleton $ docLit $ t <> Text.pack "{}" ConPatIn lname (RecCon (HsRecFields fs@(_:_) Nothing)) -> do+ -- Abc { a = locA, b = locB, c = locC } -> expr1+ -- Abc { a, b, c } -> expr2 let t = lrdrNameToText lname fds <- fs `forM` \(L _ (HsRecField (L _ (FieldOcc lnameF _)) fPat pun)) -> do fExpDoc <- if pun@@ -91,12 +110,14 @@ , docLit $ Text.pack "}" ] ConPatIn lname (RecCon (HsRecFields [] (Just 0))) -> do+ -- Abc { .. } -> expr let t = lrdrNameToText lname fmap Seq.singleton $ docSeq [ appSep $ docLit t , docLit $ Text.pack "{..}" ] ConPatIn lname (RecCon (HsRecFields fs@(_:_) (Just dotdoti))) | dotdoti == length fs -> do+ -- Abc { a = locA, .. } let t = lrdrNameToText lname fds <- fs `forM` \(L _ (HsRecField (L _ (FieldOcc lnameF _)) fPat pun)) -> do fExpDoc <- if pun@@ -117,16 +138,20 @@ , docLit $ Text.pack "..}" ] TuplePat args boxity _ -> do+ -- (nestedpat1, nestedpat2, nestedpat3) -> expr+ -- (#nestedpat1, nestedpat2, nestedpat3#) -> expr case boxity of Boxed -> wrapPatListy args "(" ")" Unboxed -> wrapPatListy args "(#" "#)" AsPat asName asPat -> do+ -- bind@nestedpat -> expr wrapPatPrepend asPat (docLit $ lrdrNameToText asName <> Text.pack "@") #if MIN_VERSION_ghc(8,2,0) /* ghc-8.2 */ SigPatIn pat1 (HsWC _ (HsIB _ ty1 _)) -> do #else /* ghc-8.0 */ SigPatIn pat1 (HsIB _ (HsWC _ _ ty1)) -> do #endif+ -- i :: Int -> expr patDocs <- layoutPat pat1 tyDoc <- docSharedWrapper layoutType ty1 case Seq.viewr patDocs of@@ -146,12 +171,17 @@ ] return $ xR Seq.|> xN' ListPat elems _ _ ->+ -- [] -> expr1+ -- [nestedpat1, nestedpat2, nestedpat3] -> expr2 wrapPatListy elems "[" "]" BangPat pat1 -> do+ -- !nestedpat -> expr wrapPatPrepend pat1 (docLit $ Text.pack "!") LazyPat pat1 -> do+ -- ~nestedpat -> expr wrapPatPrepend pat1 (docLit $ Text.pack "~") NPat llit@(L _ (OverLit olit _ _ _)) mNegative _ _ -> do+ -- -13 -> expr litDoc <- docWrapNode llit $ allocateNode $ overLitValBriDoc olit negDoc <- docLit $ Text.pack "-" pure $ case mNegative of
src/Language/Haskell/Brittany/Internal/PreludeUtils.hs view
@@ -46,6 +46,9 @@ putStrErrLn :: String -> IO () putStrErrLn s = hPutStrLn stderr s +putStrErr :: String -> IO ()+putStrErr s = hPutStr stderr s+ printErr :: Show a => a -> IO () printErr = putStrErrLn . show