floskell 0.10.8 → 0.11.0
raw patch · 22 files changed
+1059/−540 lines, 22 filesdep +ansi-wl-pprintdep +attoparsec-aesondep −utf8-stringdep ~aesondep ~bytestringdep ~deepseqPVP ok
version bump matches the API change (PVP)
Dependencies added: ansi-wl-pprint, attoparsec-aeson
Dependencies removed: utf8-string
Dependency ranges changed: aeson, bytestring, deepseq, hspec, optparse-applicative, text
API changes (from Hackage documentation)
- Floskell.Buffer: toLazyByteString :: Buffer -> ByteString
+ Floskell.Buffer: toLazyText :: Buffer -> Text
+ Floskell.Comments: filterCommentLike :: [Text] -> ([Text], [Comment])
+ Floskell.Comments: instance GHC.Classes.Eq Floskell.Comments.FilterMode
+ Floskell.Comments: instance GHC.Classes.Ord Floskell.Comments.FilterMode
+ Floskell.Comments: instance GHC.Enum.Enum Floskell.Comments.FilterMode
+ Floskell.Comments: instance GHC.Show.Show Floskell.Comments.FilterMode
+ Floskell.Comments: instance GHC.Show.Show Floskell.Comments.FilterState
+ Floskell.Printers: closeEolComment :: Printer ()
+ Floskell.Printers: ensureNewline :: Printer ()
+ Floskell.Printers: suppressOnside :: Printer () -> Printer ()
+ Floskell.Types: IgnoredLine :: CommentType
- Floskell: reformat :: AppConfig -> Maybe FilePath -> ByteString -> Either String ByteString
+ Floskell: reformat :: AppConfig -> Maybe FilePath -> Text -> Either String Text
- Floskell.Buffer: write :: ByteString -> Buffer -> Buffer
+ Floskell.Buffer: write :: Text -> Buffer -> Buffer
- Floskell.Config: ConfigMapKey :: !Maybe ByteString -> !Maybe LayoutContext -> ConfigMapKey
+ Floskell.Config: ConfigMapKey :: !Maybe Text -> !Maybe LayoutContext -> ConfigMapKey
- Floskell.Config: cfgGroupWs :: LayoutContext -> ByteString -> GroupConfig -> Whitespace
+ Floskell.Config: cfgGroupWs :: LayoutContext -> Text -> GroupConfig -> Whitespace
- Floskell.Config: cfgMapFind :: LayoutContext -> ByteString -> ConfigMap a -> a
+ Floskell.Config: cfgMapFind :: LayoutContext -> Text -> ConfigMap a -> a
- Floskell.Config: cfgOpWs :: LayoutContext -> ByteString -> OpConfig -> Whitespace
+ Floskell.Config: cfgOpWs :: LayoutContext -> Text -> OpConfig -> Whitespace
- Floskell.Printers: alignOnOperator :: LayoutContext -> ByteString -> Printer a -> Printer a
+ Floskell.Printers: alignOnOperator :: LayoutContext -> Text -> Printer a -> Printer a
- Floskell.Printers: depend :: ByteString -> Printer a -> Printer a
+ Floskell.Printers: depend :: Text -> Printer a -> Printer a
- Floskell.Printers: group :: LayoutContext -> ByteString -> ByteString -> Printer () -> Printer ()
+ Floskell.Printers: group :: LayoutContext -> Text -> Text -> Printer () -> Printer ()
- Floskell.Printers: groupH :: LayoutContext -> ByteString -> ByteString -> Printer () -> Printer ()
+ Floskell.Printers: groupH :: LayoutContext -> Text -> Text -> Printer () -> Printer ()
- Floskell.Printers: groupV :: LayoutContext -> ByteString -> ByteString -> Printer () -> Printer ()
+ Floskell.Printers: groupV :: LayoutContext -> Text -> Text -> Printer () -> Printer ()
- Floskell.Printers: operator :: LayoutContext -> ByteString -> Printer ()
+ Floskell.Printers: operator :: LayoutContext -> Text -> Printer ()
- Floskell.Printers: operatorH :: LayoutContext -> ByteString -> Printer ()
+ Floskell.Printers: operatorH :: LayoutContext -> Text -> Printer ()
- Floskell.Printers: operatorSectionL :: LayoutContext -> ByteString -> Printer () -> Printer ()
+ Floskell.Printers: operatorSectionL :: LayoutContext -> Text -> Printer () -> Printer ()
- Floskell.Printers: operatorSectionR :: LayoutContext -> ByteString -> Printer () -> Printer ()
+ Floskell.Printers: operatorSectionR :: LayoutContext -> Text -> Printer () -> Printer ()
- Floskell.Printers: operatorV :: LayoutContext -> ByteString -> Printer ()
+ Floskell.Printers: operatorV :: LayoutContext -> Text -> Printer ()
- Floskell.Printers: withOperatorFormatting :: LayoutContext -> ByteString -> Printer () -> (Printer () -> Printer a) -> Printer a
+ Floskell.Printers: withOperatorFormatting :: LayoutContext -> Text -> Printer () -> (Printer () -> Printer a) -> Printer a
- Floskell.Printers: withOperatorFormattingH :: LayoutContext -> ByteString -> Printer () -> (Printer () -> Printer a) -> Printer a
+ Floskell.Printers: withOperatorFormattingH :: LayoutContext -> Text -> Printer () -> (Printer () -> Printer a) -> Printer a
- Floskell.Printers: withOperatorFormattingV :: LayoutContext -> ByteString -> Printer () -> (Printer () -> Printer a) -> Printer a
+ Floskell.Printers: withOperatorFormattingV :: LayoutContext -> Text -> Printer () -> (Printer () -> Printer a) -> Printer a
- Floskell.Printers: write :: ByteString -> Printer ()
+ Floskell.Printers: write :: Text -> Printer ()
Files
- CHANGELOG.md +11/−0
- README.md +12/−0
- TEST.md +74/−0
- floskell.cabal +17/−18
- src/Floskell.hs +42/−88
- src/Floskell/Buffer.hs +17/−16
- src/Floskell/Comments.hs +91/−2
- src/Floskell/Config.hs +67/−68
- src/Floskell/ConfigFile.hs +9/−9
- src/Floskell/Pretty.hs +115/−122
- src/Floskell/Printers.hs +42/−24
- src/Floskell/Styles.hs +92/−92
- src/Floskell/Types.hs +11/−10
- src/main/Benchmark.hs +7/−7
- src/main/Main.hs +24/−23
- src/main/Markdone.hs +25/−28
- src/main/Test.hs +25/−25
- styles/base.md +80/−6
- styles/chris-done.md +74/−0
- styles/cramer.md +74/−0
- styles/gibiansky.md +74/−0
- styles/johan-tibell.md +76/−2
CHANGELOG.md view
@@ -1,3 +1,14 @@+# Floskell 0.11.0 (2023-10-01)++* Fix alignment of non-ASCII identifiers+* Fix extra whitespace generated for preprocessor directives at top/bottom of files+* Fix runtime blow-up with large number of pattern guards+* Add support for manual formatting / hiding regions of code from the formatter+* Add support for multi-line preprocessor directives+* Add support for hsc2hs #enum directives+* Add support for shebang lines+* Add support for building with aeson-2.2.0.0 and optparse-applicative-0.18.1.0+ # Floskell 0.10.8 (2023-08-12) * Add support for building with GHC-9.6.2
README.md view
@@ -224,6 +224,18 @@ #endif ``` +### Manual Formatting and Hiding Code++Floskell can be told to not change the formatting of a section of code+by enclosing the section with `floskell-disable` and `floskell-enable`+comments. The comments must be on a line of their own and can use the+`--` and `{- -}` syntax.++As Floskell will simply copy anything between these comments to the+output and not attempt to parse the contents, this mechanism can also+be used to hide constructs from Floskell that the parser does not+support.+ ## Customization
TEST.md view
@@ -871,6 +871,80 @@ f = () ``` +## Preprocessor Directives++Preprocessor directives are accepted and retained.++``` haskell+ #include <file.h>+ instance Monoid Penalty where+ mempty = 0++ #if !(MIN_VERSION_base(4,11,0))+ mappend = (<>)+ #endif++ #define FOO 1+ #undef FOO++ #warning "WARNING"+ #error "ERROR"+```++Multiline directives++``` haskell+ #define FOO \+ bar++ #if FOO \+ && BAR+ foo = bar+ #endif+```++Support for Hsc2hs #enum++``` haskell+ #enum CInt, \+ , fs = CTL_FS \+ , hw = CTL_HW \+ , kern = CTL_KERN \+ , net = CTL_NET \+ , vfs = CTL_VFS \+ , mem = CTL_VM+```++## Ignored Lines++Ignore lines nested in `floskell-disable` and `floskell-enable`++``` haskell+-- floskell-disable+This is ignored.+-- floskell-enable++{- floskell-disable -}+And so is this.+{- floskell-enable -}+```++Ignore shebang lines++``` haskell+ #! /usr/bin/env nix-shell+ #! nix-shell -p ghcid+ #! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [ shower ])"+ #! nix-shell -i "ghcid -c 'ghci -Wall' -T':!pkill --full ghc\\ .\\*./Main.hs' -T main"++ module Main where++ import Shower++ main :: IO ()+ main = printer "Hello"+```+ ## Indentation and Line Prefixes Preserving indentation and line prefixes so that Floskell can be run
floskell.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: floskell-version: 0.10.8+version: 0.11.0 license: BSD3 license-file: LICENSE.md copyright:@@ -57,9 +57,10 @@ ghc-options: -Wall build-depends: base >=4.9 && <4.19,- aeson >=0.11.3.0 && <2.2,+ aeson >=0.11.3.0 && <2.3, attoparsec >=0.13.1.0 && <0.15,- bytestring >=0.10.8.1 && <0.12,+ attoparsec-aeson >=2.1.0.0 && <2.3,+ bytestring >=0.10.8.1 && <0.13, containers >=0.5.7.1 && <0.7, data-default >=0.7.1.1 && <0.8, directory >=1.2.6.2 && <1.4,@@ -67,10 +68,9 @@ haskell-src-exts >=1.19 && <1.24, monad-dijkstra >=0.1.1 && <0.2, mtl >=2.2.1 && <2.4,- text >=1.2.2.2 && <2.1,+ text >=1.2.2.2 && <2.2, transformers >=0.5.2.0 && <0.7,- unordered-containers >=0.2.8.0 && <0.3,- utf8-string >=1.0.1.1 && <1.1+ unordered-containers >=0.2.8.0 && <0.3 executable floskell main-is: Main.hs@@ -83,12 +83,13 @@ base >=4.9 && <4.19, floskell -any, aeson-pretty >=0.8.2 && <0.9,- bytestring >=0.10.8.1 && <0.12,+ ansi-wl-pprint >=0.6.6 && <1.1,+ bytestring >=0.10.8.1 && <0.13, directory >=1.2.6.2 && <1.4, ghc-prim >=0.5.0.0 && <0.11, haskell-src-exts >=1.19 && <1.24,- optparse-applicative >=0.12.1.0 && <0.18,- text >=1.2.2.2 && <2.1+ optparse-applicative >=0.12.1.0 && <0.19,+ text >=1.2.2.2 && <2.2 test-suite floskell-test type: exitcode-stdio-1.0@@ -100,13 +101,12 @@ build-depends: base >=4.9 && <4.19, floskell -any,- bytestring >=0.10.8.1 && <0.12,- deepseq >=1.4.2.0 && <1.5,+ bytestring >=0.10.8.1 && <0.13,+ deepseq >=1.4.2.0 && <1.6, exceptions >=0.8.3 && <0.12, haskell-src-exts >=1.19 && <1.24,- hspec >=2.2.4 && <2.11,- text >=1.2.2.2 && <2.1,- utf8-string >=1.0.1.1 && <1.1+ hspec >=2.2.4 && <2.12,+ text >=1.2.2.2 && <2.2 benchmark floskell-bench type: exitcode-stdio-1.0@@ -118,11 +118,10 @@ build-depends: base >=4.9 && <4.19, floskell -any,- bytestring >=0.10.8.1 && <0.12,+ bytestring >=0.10.8.1 && <0.13, criterion >=1.1.1.0 && <1.7,- deepseq >=1.4.2.0 && <1.5,+ deepseq >=1.4.2.0 && <1.6, exceptions >=0.8.3 && <0.11, ghc-prim >=0.5.0.0 && <0.11, haskell-src-exts >=1.19 && <1.24,- text >=1.2.2.2 && <2.1,- utf8-string >=1.0.1.1 && <1.1+ text >=1.2.2.2 && <2.2
src/Floskell.hs view
@@ -24,29 +24,28 @@ , defaultExtensions ) where -import Data.ByteString.Lazy ( ByteString )-import qualified Data.ByteString.Lazy.Char8 as L8-import qualified Data.ByteString.Lazy.UTF8 as UTF8 import Data.List import Data.Maybe #if __GLASGOW_HASKELL__ <= 802 import Data.Monoid #endif+import Data.Text.Lazy ( Text )+import qualified Data.Text.Lazy as TL -import qualified Floskell.Buffer as Buffer+import qualified Floskell.Buffer as Buffer import Floskell.Comments import Floskell.Config import Floskell.ConfigFile-import Floskell.Fixities ( builtinFixities )-import Floskell.Pretty ( pretty )-import Floskell.Styles ( Style(..), styles )+import Floskell.Fixities ( builtinFixities )+import Floskell.Pretty ( pretty )+import Floskell.Styles ( Style(..), styles ) import Floskell.Types import Language.Haskell.Exts hiding ( Comment, Pretty, Style, parse, prettyPrint, style )-import qualified Language.Haskell.Exts as Exts+import qualified Language.Haskell.Exts as Exts -data CodeBlock = HaskellSource Int [ByteString] | CPPDirectives [ByteString]+data CodeBlock = HaskellSource Int [Text] | CPPDirectives [Text] deriving ( Show, Eq ) trimBy :: (a -> Bool) -> [a] -> ([a], [a], [a])@@ -60,63 +59,54 @@ suffix = reverse suffix' -findLinePrefix :: (Char -> Bool) -> [ByteString] -> ByteString+findLinePrefix :: (Char -> Bool) -> [Text] -> Text findLinePrefix _ [] = ""-findLinePrefix f (x : xs') = go (L8.takeWhile f x) xs'+findLinePrefix f (x : xs') = go (TL.takeWhile f x) xs' where- go prefix xs = if all (prefix `L8.isPrefixOf`) xs+ go prefix xs = if all (prefix `TL.isPrefixOf`) xs then prefix- else go (L8.take (L8.length prefix - 1) prefix) xs+ else go (TL.take (TL.length prefix - 1) prefix) xs -findIndent :: (Char -> Bool) -> [ByteString] -> ByteString+findIndent :: (Char -> Bool) -> [Text] -> Text findIndent _ [] = ""-findIndent f (x : xs') = go (L8.takeWhile f x) $ filter (not . L8.all f) xs'+findIndent f (x : xs') = go (TL.takeWhile f x) $ filter (not . TL.all f) xs' where- go indent xs = if all (indent `L8.isPrefixOf`) xs+ go indent xs = if all (indent `TL.isPrefixOf`) xs then indent- else go (L8.take (L8.length indent - 1) indent) xs+ else go (TL.take (TL.length indent - 1) indent) xs -preserveVSpace :: Monad m- => ([ByteString] -> m [ByteString])- -> [ByteString]- -> m [ByteString]+preserveVSpace :: Monad m => ([Text] -> m [Text]) -> [Text] -> m [Text] preserveVSpace format input = do output <- format input' return $ prefix ++ output ++ suffix where- (prefix, input', suffix) = trimBy L8.null input+ (prefix, input', suffix) = trimBy TL.null input -preservePrefix :: Monad m- => (Int -> [ByteString] -> m [ByteString])- -> [ByteString]- -> m [ByteString]+preservePrefix :: Monad m => (Int -> [Text] -> m [Text]) -> [Text] -> m [Text] preservePrefix format input = do output <- format (prefixLength prefix) input' return $ map (prefix <>) output where prefix = findLinePrefix allowed input - input' = map (L8.drop $ L8.length prefix) input+ input' = map (TL.drop $ TL.length prefix) input allowed c = c == ' ' || c == '\t' || c == '>' - prefixLength = sum . map (\c -> if c == '\t' then 8 else 1) . L8.unpack+ prefixLength = sum . map (\c -> if c == '\t' then 8 else 1) . TL.unpack -preserveIndent :: Monad m- => (Int -> [ByteString] -> m [ByteString])- -> [ByteString]- -> m [ByteString]+preserveIndent :: Monad m => (Int -> [Text] -> m [Text]) -> [Text] -> m [Text] preserveIndent format input = do output <- format (prefixLength prefix) input'- return $ map (prefix <>) output+ return $ map (\l -> if TL.null l then l else prefix <> l) output where prefix = findIndent allowed input - input' = map (L8.drop $ L8.length prefix) input+ input' = map (TL.drop $ TL.length prefix) input allowed c = c == ' ' || c == '\t' - prefixLength = sum . map (\c -> if c == '\t' then 8 else 1) . L8.unpack+ prefixLength = sum . map (\c -> if c == '\t' then 8 else 1) . TL.unpack withReducedLineLength :: Int -> Config -> Config withReducedLineLength offset config = config { cfgPenalty = penalty }@@ -127,13 +117,12 @@ } -- | Format the given source.-reformat- :: AppConfig -> Maybe FilePath -> ByteString -> Either String ByteString-reformat config mfilepath input = fmap (L8.intercalate "\n")+reformat :: AppConfig -> Maybe FilePath -> Text -> Either String Text+reformat config mfilepath input = fmap (TL.intercalate "\n") . preserveVSpace (preservePrefix (reformatLines mode cfg)) $- L8.split '\n' input+ TL.split (== '\n') input where- mode = case readExtensions $ UTF8.toString input of+ mode = case readExtensions $ TL.unpack input of Nothing -> mode' Just (Nothing, exts') -> mode' { extensions = exts' ++ extensions mode' }@@ -151,38 +140,29 @@ cfg = safeConfig . styleConfig $ appStyle config -reformatLines- :: ParseMode -> Config -> Int -> [ByteString] -> Either String [ByteString]-reformatLines mode config indent = format . filterPreprocessorDirectives+reformatLines :: ParseMode -> Config -> Int -> [Text] -> Either String [Text]+reformatLines mode config indent = preserveVSpace (preserveIndent format) where- config' = withReducedLineLength indent config-- format (code, comments) =- preserveVSpace (preserveIndent (reformatBlock mode config' comments))- code+ format indent' =+ reformatBlock mode (withReducedLineLength (indent + indent') config)+ . filterCommentLike -- | Format a continuous block of code without CPP directives.-reformatBlock :: ParseMode- -> Config- -> [Comment]- -> Int- -> [ByteString]- -> Either String [ByteString]-reformatBlock mode config cpp indent lines =+reformatBlock+ :: ParseMode -> Config -> ([Text], [Comment]) -> Either String [Text]+reformatBlock mode config (lines, cpp) = case parseModuleWithComments mode code of ParseOk (m, comments') -> let comments = map makeComment comments' ast = annotateWithComments m (mergeComments comments cpp) in- case prettyPrint (pretty ast) config' of+ case prettyPrint (pretty ast) config of Nothing -> Left "Printer failed with mzero call."- Just output -> Right $ L8.lines output+ Just output -> Right $ TL.lines output ParseFailed loc e -> Left $ Exts.prettyPrint (loc { srcLine = srcLine loc }) ++ ": " ++ e where- code = UTF8.toString $ L8.intercalate "\n" lines-- config' = withReducedLineLength indent config+ code = TL.unpack $ TL.intercalate "\n" lines makeComment (Exts.Comment inline span text) = Comment (if inline then InlineComment else LineComment) span text@@ -194,34 +174,8 @@ then x : mergeComments xs' ys else y : mergeComments xs ys' --- | Remove CPP directives from input source, retur-filterPreprocessorDirectives :: [ByteString] -> ([ByteString], [Comment])-filterPreprocessorDirectives lines = (code, comments)- where- code = map (\l -> if cppLine l then "" else l) lines-- comments = map makeComment . filter (cppLine . snd) $ zip [ 1 .. ] lines-- makeComment (n, l) =- Comment PreprocessorDirective- (SrcSpan "" n 1 n (fromIntegral $ L8.length l + 1))- (L8.unpack l)-- cppLine src =- any (`L8.isPrefixOf` src)- [ "#if"- , "#end"- , "#else"- , "#define"- , "#undef"- , "#elif"- , "#include"- , "#error"- , "#warning"- ]--prettyPrint :: Printer a -> Config -> Maybe ByteString-prettyPrint printer = fmap (Buffer.toLazyByteString . psBuffer . snd)+prettyPrint :: Printer a -> Config -> Maybe Text+prettyPrint printer = fmap (Buffer.toLazyText . psBuffer . snd) . execPrinter printer . initialPrintState -- | Default extensions.
src/Floskell/Buffer.hs view
@@ -1,5 +1,5 @@--- | An outout buffer for ByteStrings that keeps track of line and--- column numbers.+-- | An outout buffer for Text that keeps track of line and column+-- numbers. module Floskell.Buffer ( Buffer , empty@@ -7,13 +7,14 @@ , write , line , column- , toLazyByteString+ , toLazyText ) where -import qualified Data.ByteString as BS-import Data.ByteString.Builder ( Builder )-import qualified Data.ByteString.Builder as BB-import qualified Data.ByteString.Lazy as BL+import Data.Text ( Text )+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import Data.Text.Lazy.Builder ( Builder )+import qualified Data.Text.Lazy.Builder as TB data Buffer = Buffer { bufferData :: !Builder -- ^ The current output.@@ -30,17 +31,17 @@ , bufferColumn = 0 } --- | Append a ByteString to the output buffer. It is an error for the+-- | Append a Text to the output buffer. It is an error for the -- string to contain newlines.-write :: BS.ByteString -> Buffer -> Buffer+write :: Text -> Buffer -> Buffer write str buf = buf { bufferData = newBufferData , bufferDataNoSpace =- if BS.all (== 32) str then bufferData buf else newBufferData- , bufferColumn = bufferColumn buf + BS.length str+ if T.all (== ' ') str then bufferData buf else newBufferData+ , bufferColumn = bufferColumn buf + T.length str } where- newBufferData = bufferData buf `mappend` BB.byteString str+ newBufferData = bufferData buf `mappend` TB.fromText str -- | Append a newline to the output buffer. newline :: Buffer -> Buffer@@ -50,7 +51,7 @@ , bufferColumn = 0 } where- newBufferData = bufferDataNoSpace buf `mappend` BB.char7 '\n'+ newBufferData = bufferDataNoSpace buf `mappend` TB.singleton '\n' -- | Return the current line number, counting from 0. line :: Buffer -> Int@@ -60,6 +61,6 @@ column :: Buffer -> Int column = bufferColumn --- | Return the contents of the output buffer as a lazy ByteString.-toLazyByteString :: Buffer -> BL.ByteString-toLazyByteString = BB.toLazyByteString . bufferData+-- | Return the contents of the output buffer as a lazy Text.+toLazyText :: Buffer -> TL.Text+toLazyText = TB.toLazyText . bufferData
src/Floskell/Comments.hs view
@@ -1,17 +1,32 @@+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+ -- | Comment handling.-module Floskell.Comments ( annotateWithComments ) where+module Floskell.Comments ( filterCommentLike, annotateWithComments ) where import Control.Arrow ( first, second ) import Control.Monad.State.Strict import Data.Foldable ( traverse_ )-import Data.List ( isPrefixOf )+import Data.List ( foldl', isPrefixOf ) import qualified Data.Map.Strict as M+import Data.Text.Lazy ( Text )+import qualified Data.Text.Lazy as TL import Floskell.Types import Language.Haskell.Exts.SrcLoc ( SrcSpanInfo(..) ) +data FilterMode = Normal | CppContinuation | Unformatted+ deriving ( Eq, Ord, Enum, Show )++data FilterState = FilterState { stMode :: !FilterMode+ , stLines :: [Text]+ , stComments :: [Comment]+ }+ deriving ( Show )+ -- Order by start of span, larger spans before smaller spans. newtype OrderByStart = OrderByStart SrcSpan deriving ( Eq )@@ -33,6 +48,80 @@ `mappend` compare (srcSpanEndColumn l) (srcSpanEndColumn r) `mappend` compare (srcSpanStartLine r) (srcSpanStartLine l) `mappend` compare (srcSpanStartColumn r) (srcSpanStartColumn l)++-- | Remove comment-like blocks from input source, replacing them with+-- blank likes to keep SrcSpan information intact.+filterCommentLike :: [Text] -> ([Text], [Comment])+filterCommentLike = finish . foldl' go start . zip [ 1 .. ]+ where+ start = FilterState Normal [] []++ go s@FilterState{..} (n, l) = case stMode of+ Normal -> if+ | isShebangLine l -> addComment s Normal IgnoredLine n l+ | isCppLine l ->+ let newMode =+ if isCppContinuation l then CppContinuation else Normal+ in+ addComment s newMode PreprocessorDirective n l+ | isBeginIgnore l -> addComment s Unformatted IgnoredLine n l+ | otherwise -> addLine s l++ CppContinuation ->+ let newMode =+ if isCppContinuation l then CppContinuation else Normal+ in+ addComment s newMode PreprocessorDirective n l++ Unformatted ->+ let newMode = if isEndIgnore l then Normal else Unformatted+ in+ addComment s newMode IgnoredLine n l++ finish s = (reverse $ stLines s, reverse $ stComments s)++ addLine s@FilterState{..} l = s { stLines = l : stLines }++ addComment s@FilterState{..} mode t n l =+ s { stMode = mode+ , stLines = "" : stLines+ , stComments = makeComment t n l : stComments+ }++ makeComment t n l =+ Comment t+ (SrcSpan "" n 1 n (fromIntegral $ TL.length l + 1))+ (TL.unpack l)++ isShebangLine = TL.isPrefixOf "#!"++ isCppLine src =+ any (`TL.isPrefixOf` src)+ [ "#define"+ , "#elif"+ , "#else"+ , "#end"+ , "#enum"+ , "#error"+ , "#if"+ , "#include"+ , "#undef"+ , "#warning"+ ]++ isCppContinuation = TL.isSuffixOf "\\"++ isBeginIgnore src = any (`TL.isPrefixOf` src)+ [ "-- floskell-begin-disable-region"+ , "-- floskell-disable"+ , "{- floskell-disable"+ ]++ isEndIgnore src = any (`TL.isPrefixOf` src)+ [ "-- floskell-end-disable-region"+ , "-- floskell-enable"+ , "{- floskell-enable"+ ] onSameLine :: SrcSpan -> SrcSpan -> Bool onSameLine ss ss' = srcSpanEndLine ss == srcSpanStartLine ss'
src/Floskell/Config.hs view
@@ -35,18 +35,17 @@ import Data.Aeson ( FromJSON(..), ToJSON(..), genericParseJSON, genericToJSON )-import qualified Data.Aeson as JSON-import Data.Aeson.Types as JSON+import qualified Data.Aeson as JSON+import Data.Aeson.Types as JSON ( Options(..), camelTo2, typeMismatch )-import Data.ByteString ( ByteString )-import Data.Default ( Default(..) )-import qualified Data.HashMap.Lazy as HashMap-import Data.Map.Strict ( Map )-import qualified Data.Map.Strict as Map-import Data.Set ( Set )-import qualified Data.Set as Set-import qualified Data.Text as T-import qualified Data.Text.Encoding as T ( decodeUtf8, encodeUtf8 )+import Data.Default ( Default(..) )+import qualified Data.HashMap.Lazy as HashMap+import Data.Map.Strict ( Map )+import qualified Data.Map.Strict as Map+import Data.Set ( Set )+import qualified Data.Set as Set+import Data.Text ( Text )+import qualified Data.Text as T import GHC.Generics @@ -71,7 +70,7 @@ data Layout = Flex | Vertical | TryOneline deriving ( Eq, Ord, Bounded, Enum, Show, Generic ) -data ConfigMapKey = ConfigMapKey !(Maybe ByteString) !(Maybe LayoutContext)+data ConfigMapKey = ConfigMapKey !(Maybe Text) !(Maybe LayoutContext) deriving ( Eq, Ord, Show ) data ConfigMap a =@@ -120,71 +119,71 @@ } data IndentConfig =- IndentConfig { cfgIndentOnside :: !Int- , cfgIndentDeriving :: !Int- , cfgIndentWhere :: !Int- , cfgIndentApp :: !Indent- , cfgIndentCase :: !Indent- , cfgIndentClass :: !Indent- , cfgIndentDo :: !Indent+ IndentConfig { cfgIndentOnside :: !Int+ , cfgIndentDeriving :: !Int+ , cfgIndentWhere :: !Int+ , cfgIndentApp :: !Indent+ , cfgIndentCase :: !Indent+ , cfgIndentClass :: !Indent+ , cfgIndentDo :: !Indent , cfgIndentExportSpecList :: !Indent- , cfgIndentIf :: !Indent+ , cfgIndentIf :: !Indent , cfgIndentImportSpecList :: !Indent- , cfgIndentLet :: !Indent- , cfgIndentLetBinds :: !Indent- , cfgIndentLetIn :: !Indent- , cfgIndentMultiIf :: !Indent- , cfgIndentTypesig :: !Indent- , cfgIndentWhereBinds :: !Indent+ , cfgIndentLet :: !Indent+ , cfgIndentLetBinds :: !Indent+ , cfgIndentLetIn :: !Indent+ , cfgIndentMultiIf :: !Indent+ , cfgIndentTypesig :: !Indent+ , cfgIndentWhereBinds :: !Indent } deriving ( Generic ) instance Default IndentConfig where- def = IndentConfig { cfgIndentOnside = 4- , cfgIndentDeriving = 4- , cfgIndentWhere = 2- , cfgIndentApp = IndentBy 4- , cfgIndentCase = IndentBy 4- , cfgIndentClass = IndentBy 4- , cfgIndentDo = IndentBy 4+ def = IndentConfig { cfgIndentOnside = 4+ , cfgIndentDeriving = 4+ , cfgIndentWhere = 2+ , cfgIndentApp = IndentBy 4+ , cfgIndentCase = IndentBy 4+ , cfgIndentClass = IndentBy 4+ , cfgIndentDo = IndentBy 4 , cfgIndentExportSpecList = IndentBy 4- , cfgIndentIf = IndentBy 4+ , cfgIndentIf = IndentBy 4 , cfgIndentImportSpecList = IndentBy 4- , cfgIndentLet = IndentBy 4- , cfgIndentLetBinds = IndentBy 4- , cfgIndentLetIn = IndentBy 4- , cfgIndentMultiIf = IndentBy 4- , cfgIndentTypesig = IndentBy 4- , cfgIndentWhereBinds = IndentBy 2+ , cfgIndentLet = IndentBy 4+ , cfgIndentLetBinds = IndentBy 4+ , cfgIndentLetIn = IndentBy 4+ , cfgIndentMultiIf = IndentBy 4+ , cfgIndentTypesig = IndentBy 4+ , cfgIndentWhereBinds = IndentBy 2 } data LayoutConfig =- LayoutConfig { cfgLayoutApp :: !Layout- , cfgLayoutConDecls :: !Layout- , cfgLayoutDeclaration :: !Layout+ LayoutConfig { cfgLayoutApp :: !Layout+ , cfgLayoutConDecls :: !Layout+ , cfgLayoutDeclaration :: !Layout , cfgLayoutExportSpecList :: !Layout- , cfgLayoutIf :: !Layout+ , cfgLayoutIf :: !Layout , cfgLayoutImportSpecList :: !Layout- , cfgLayoutInfixApp :: !Layout- , cfgLayoutLet :: !Layout- , cfgLayoutListComp :: !Layout- , cfgLayoutRecord :: !Layout- , cfgLayoutType :: !Layout+ , cfgLayoutInfixApp :: !Layout+ , cfgLayoutLet :: !Layout+ , cfgLayoutListComp :: !Layout+ , cfgLayoutRecord :: !Layout+ , cfgLayoutType :: !Layout } deriving ( Generic ) instance Default LayoutConfig where- def = LayoutConfig { cfgLayoutApp = Flex- , cfgLayoutConDecls = Flex- , cfgLayoutDeclaration = Flex+ def = LayoutConfig { cfgLayoutApp = Flex+ , cfgLayoutConDecls = Flex+ , cfgLayoutDeclaration = Flex , cfgLayoutExportSpecList = Flex- , cfgLayoutIf = Flex+ , cfgLayoutIf = Flex , cfgLayoutImportSpecList = Flex- , cfgLayoutInfixApp = Flex- , cfgLayoutLet = Flex- , cfgLayoutListComp = Flex- , cfgLayoutRecord = Flex- , cfgLayoutType = Flex+ , cfgLayoutInfixApp = Flex+ , cfgLayoutLet = Flex+ , cfgLayoutListComp = Flex+ , cfgLayoutRecord = Flex+ , cfgLayoutType = Flex } newtype OpConfig = OpConfig { unOpConfig :: ConfigMap Whitespace }@@ -228,7 +227,8 @@ , cfgOptionAlignSumTypeDecl :: !Bool , cfgOptionFlexibleOneline :: !Bool , cfgOptionPreserveVerticalSpace :: !Bool- , cfgOptionDeclNoBlankLines :: !(Set DeclarationConstruct)+ , cfgOptionDeclNoBlankLines+ :: !(Set DeclarationConstruct) , cfgOptionAlignLetBindsAndInExpr :: !Bool } deriving ( Generic )@@ -310,7 +310,7 @@ (cfgMapFind ctx key config) { wsSpaces = ws } m -cfgMapFind :: LayoutContext -> ByteString -> ConfigMap a -> a+cfgMapFind :: LayoutContext -> Text -> ConfigMap a -> a cfgMapFind ctx key ConfigMap{..} = let value = cfgMapDefault value' = Map.findWithDefault value@@ -325,10 +325,10 @@ in value''' -cfgOpWs :: LayoutContext -> ByteString -> OpConfig -> Whitespace+cfgOpWs :: LayoutContext -> Text -> OpConfig -> Whitespace cfgOpWs ctx op = cfgMapFind ctx op . unOpConfig -cfgGroupWs :: LayoutContext -> ByteString -> GroupConfig -> Whitespace+cfgGroupWs :: LayoutContext -> Text -> GroupConfig -> Whitespace cfgGroupWs ctx op = cfgMapFind ctx op . unGroupConfig inWs :: Location -> WsLoc -> Bool@@ -418,20 +418,19 @@ keyToText :: ConfigMapKey -> T.Text keyToText (ConfigMapKey Nothing Nothing) = "default"-keyToText (ConfigMapKey (Just n) Nothing) = T.decodeUtf8 n+keyToText (ConfigMapKey (Just n) Nothing) = n keyToText (ConfigMapKey Nothing (Just l)) = "* in " `T.append` layoutToText l keyToText (ConfigMapKey (Just n) (Just l)) =- T.decodeUtf8 n `T.append` " in " `T.append` layoutToText l+ n `T.append` " in " `T.append` layoutToText l textToKey :: T.Text -> Maybe ConfigMapKey textToKey t = case T.splitOn " in " t of [ "default" ] -> Just (ConfigMapKey Nothing Nothing) [ "*", "*" ] -> Just (ConfigMapKey Nothing Nothing)- [ name ] -> Just (ConfigMapKey (Just (T.encodeUtf8 name)) Nothing)- [ name, "*" ] -> Just (ConfigMapKey (Just (T.encodeUtf8 name)) Nothing)+ [ name ] -> Just (ConfigMapKey (Just name) Nothing)+ [ name, "*" ] -> Just (ConfigMapKey (Just name) Nothing) [ "*", layout ] -> ConfigMapKey Nothing . Just <$> textToLayout layout- [ name, layout ] -> ConfigMapKey (Just (T.encodeUtf8 name)) . Just- <$> textToLayout layout+ [ name, layout ] -> ConfigMapKey (Just name) . Just <$> textToLayout layout _ -> Nothing instance ToJSON a => ToJSON (ConfigMap a) where
src/Floskell/ConfigFile.hs view
@@ -2,7 +2,6 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE CPP #-} module Floskell.ConfigFile ( AppConfig(..)@@ -29,18 +28,11 @@ import Data.Aeson ( (.:?), (.=), FromJSON(..), ToJSON(..) ) import qualified Data.Aeson as JSON+import qualified Data.Aeson.Parser as JSON ( json' ) import qualified Data.Aeson.Types as JSON ( typeMismatch ) import qualified Data.Attoparsec.ByteString as AP import qualified Data.ByteString as BS import Data.Char ( isLetter, isSpace )--#if MIN_VERSION_aeson(2,0,0)-import qualified Data.Aeson.KeyMap as Map-#else-import qualified Data.Aeson.Parser as JSON ( json' )-import qualified Data.HashMap.Lazy as Map-#endif- import Data.List ( inits ) import qualified Data.Text as T @@ -60,6 +52,14 @@ , getHomeDirectory, getXdgDirectory ) import System.FilePath ( joinPath, splitDirectories, takeDirectory )++{- floskell-disable -}+#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.KeyMap as Map+#else+import qualified Data.HashMap.Lazy as Map+#endif+{- floskell-enable -} data AppConfig = AppConfig { appStyle :: Style , appLanguage :: Language
src/Floskell/Pretty.hs view
@@ -12,13 +12,12 @@ import Control.Monad.State.Strict ( get, gets, modify ) import Data.Bool ( bool )-import Data.ByteString ( ByteString )-import qualified Data.ByteString as BS-import qualified Data.ByteString.Char8 as BS8-import qualified Data.ByteString.Lazy as BL import Data.List ( groupBy, sortBy, sortOn ) import Data.Maybe ( catMaybes, fromMaybe ) import qualified Data.Set as Set+import Data.Text ( Text )+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL import qualified Floskell.Buffer as Buffer import Floskell.Config@@ -101,20 +100,19 @@ -- | Pretty print a syntax tree with annotated comments pretty :: (Annotated ast, Pretty ast) => ast NodeInfo -> Printer () pretty ast = do- printComments Before ast+ printCommentsBefore True ast prettyPrint ast- printComments After ast+ printCommentsAfter ast prettyOnside :: (Annotated ast, Pretty ast) => ast NodeInfo -> Printer () prettyOnside ast = do- eol <- gets psEolComment- when eol newline+ closeEolComment nl <- gets psNewline if nl then do- printComments Before ast+ printCommentsBefore True ast onside $ prettyPrint ast- printComments After ast+ printCommentsAfter ast else onside $ pretty ast -- | Compare two AST nodes ignoring the annotation@@ -143,75 +141,73 @@ to -- | Pretty print a comment.-printComment :: Int -> (Comment, SrcSpan) -> Printer ()-printComment correction (Comment{..}, nextSpan) = do+printComment :: Int -> Comment -> Printer ()+printComment correction Comment{..} = do col <- getNextColumn let padding = max 0 $ srcSpanStartColumn commentSpan + correction - col - 1 case commentType of PreprocessorDirective -> do- nl <- gets psNewline- unless nl newline+ ensureNewline column 0 $ string commentText modify (\s -> s { psEolComment = True }) InlineComment -> do- write $ BS.replicate padding 32+ write $ T.replicate padding " " write "{-" string commentText write "-}"- when (srcSpanEndLine commentSpan /= srcSpanStartLine nextSpan) $- modify (\s -> s { psEolComment = True }) LineComment -> do- write $ BS.replicate padding 32+ write $ T.replicate padding " " write "--" string commentText modify (\s -> s { psEolComment = True })---- | Print comments of a node.-printComments :: Annotated ast => Location -> ast NodeInfo -> Printer ()-printComments = printCommentsInternal True---- | Print comments of a node, but do not force newline before leading comments.-printComments' :: Annotated ast => Location -> ast NodeInfo -> Printer ()-printComments' = printCommentsInternal False--printCommentsInternal- :: Annotated ast => Bool -> Location -> ast NodeInfo -> Printer ()-printCommentsInternal nlBefore loc ast = unless (null comments) $ do- let firstComment = head comments- -- Preceeding comments must have a newline before them, but not break onside indent.- nl <- gets psNewline- onside' <- gets psOnside- when nl $ modify $ \s -> s { psOnside = 0 }- when (loc == Before && not nl && nlBefore) newline- when (loc == After && not nl && notSameLine firstComment) newline+ IgnoredLine -> do+ ensureNewline+ column 0 $ string commentText+ modify (\s -> s { psEolComment = True }) +printCommentsBefore :: Annotated ast => Bool -> ast NodeInfo -> Printer ()+printCommentsBefore nlBefore ast = unless (null comments) $ suppressOnside $ do+ when nlBefore ensureNewline col <- getNextColumn- let correction = case loc of- Before -> col - srcSpanStartColumn ssi + 1- After -> col - srcSpanEndColumn ssi + 1- forM_ (zip comments (tail (map commentSpan comments ++ [ ssi ]))) $- printComment correction-- -- Write newline before restoring onside indent.- eol <- gets psEolComment- when (loc == Before && eol && onside' > 0) newline- when nl $ modify $ \s -> s { psOnside = onside' }+ printCommentsInternal (col - srcSpanStartColumn (nodeSpan ast) + 1)+ comments+ let distance = srcSpanStartLine (nodeSpan ast)+ - srcSpanEndLine (commentSpan (last comments))+ when (distance > 0) $ do+ ensureNewline+ replicateM_ (distance - 1) newline where- ssi = nodeSpan ast+ comments = nodeInfoLeadingComments $ ann ast - comments = filterComments loc ast+printCommentsAfter :: Annotated ast => ast NodeInfo -> Printer ()+printCommentsAfter ast = unless (null comments) $ suppressOnside $ do+ let distance = srcSpanStartLine (commentSpan (head comments))+ - srcSpanEndLine (nodeSpan ast)+ when (distance > 0) $ do+ ensureNewline+ replicateM_ (distance - 1) newline+ col <- getNextColumn+ printCommentsInternal (col - srcSpanEndColumn (nodeSpan ast) + 1) comments+ where+ comments = nodeInfoTrailingComments $ ann ast - notSameLine comment = srcSpanEndLine ssi- < srcSpanStartLine (commentSpan comment)+printCommentsInternal :: Int -> [Comment] -> Printer ()+printCommentsInternal correction comments = do+ printComment correction (head comments)+ forM_ (zip (tail comments) (map (srcSpanEndLine . commentSpan) comments)) $+ \(comment, prevLine) -> do+ let nextLine = srcSpanStartLine $ commentSpan comment+ replicateM_ (nextLine - prevLine) newline+ printComment correction comment -- | Return the configuration name of an operator-opName :: QOp a -> ByteString+opName :: QOp a -> Text opName op = case op of (QVarOp _ qname) -> opName' qname (QConOp _ qname) -> opName' qname -- | Return the configuration name of an operator-opName' :: QName a -> ByteString+opName' :: QName a -> Text opName' (Qual _ _ name) = opName'' name opName' (UnQual _ name) = opName'' name opName' (Special _ (FunCon _)) = "->"@@ -219,9 +215,9 @@ opName' (Special _ _) = "" -- | Return the configuration name of an operator-opName'' :: Name a -> ByteString+opName'' :: Name a -> Text opName'' (Ident _ _) = "``"-opName'' (Symbol _ str) = BS8.pack str+opName'' (Symbol _ str) = T.pack str lineDelta :: Annotated ast => ast NodeInfo -> ast NodeInfo -> Int lineDelta prev next = nextLine - prevLine@@ -262,16 +258,16 @@ linedOnside :: (Annotated ast, Pretty ast) => [ast NodeInfo] -> Printer () linedOnside = linedFn prettyOnside -listVOpLen :: LayoutContext -> ByteString -> Printer Int+listVOpLen :: LayoutContext -> Text -> Printer Int listVOpLen ctx sep = do ws <- getConfig (cfgOpWs ctx sep . cfgOp) return $ if wsLinebreak After ws then 0- else BS.length sep + if wsSpace After ws then 1 else 0+ else T.length sep + if wsSpace After ws then 1 else 0 listVinternal :: (Annotated ast, Pretty ast) => LayoutContext- -> ByteString+ -> Text -> [ast NodeInfo] -> Printer () listVinternal ctx sep xs = case xs of@@ -283,22 +279,22 @@ let itemCol = if nl && length xs > 1 then col + delta else col sepCol = itemCol - delta column itemCol $ do- printComments' Before x+ printCommentsBefore False x cut $ prettyPrint x- printComments After x+ printCommentsAfter x -- `column sepCol` must not be within `column itemCol`, or the -- former can suppress onside for the latter. forM_ xs' $ \x' -> do- column itemCol $ printComments Before x'+ column itemCol $ printCommentsBefore True x' column sepCol $ operatorV ctx sep column itemCol $ cut $ prettyPrint x'- column itemCol $ printComments After x'+ column itemCol $ printCommentsAfter x' listH :: (Annotated ast, Pretty ast) => LayoutContext- -> ByteString- -> ByteString- -> ByteString+ -> Text+ -> Text+ -> Text -> [ast NodeInfo] -> Printer () listH _ open close _ [] = do@@ -310,9 +306,9 @@ listV :: (Annotated ast, Pretty ast) => LayoutContext- -> ByteString- -> ByteString- -> ByteString+ -> Text+ -> Text+ -> Text -> [ast NodeInfo] -> Printer () listV ctx open close sep xs = groupV ctx open close $ do@@ -325,9 +321,9 @@ list :: (Annotated ast, Pretty ast) => LayoutContext- -> ByteString- -> ByteString- -> ByteString+ -> Text+ -> Text+ -> Text -> [ast NodeInfo] -> Printer () list ctx open close sep xs = oneline hor <|> ver@@ -338,14 +334,14 @@ listH' :: (Annotated ast, Pretty ast) => LayoutContext- -> ByteString+ -> Text -> [ast NodeInfo] -> Printer () listH' ctx sep = inter (operatorH ctx sep) . map pretty listV' :: (Annotated ast, Pretty ast) => LayoutContext- -> ByteString+ -> Text -> [ast NodeInfo] -> Printer () listV' ctx sep xs =@@ -353,7 +349,7 @@ list' :: (Annotated ast, Pretty ast) => LayoutContext- -> ByteString+ -> Text -> [ast NodeInfo] -> Printer () list' ctx sep xs = oneline hor <|> ver@@ -364,9 +360,9 @@ listAutoWrap :: (Annotated ast, Pretty ast) => LayoutContext- -> ByteString- -> ByteString- -> ByteString+ -> Text+ -> Text+ -> Text -> [ast NodeInfo] -> Printer () listAutoWrap _ open close _ [] = do@@ -378,7 +374,7 @@ listAutoWrap' :: (Annotated ast, Pretty ast) => LayoutContext- -> ByteString+ -> Text -> [ast NodeInfo] -> Printer () listAutoWrap' _ _ [] = return ()@@ -386,23 +382,23 @@ ws <- getConfig (cfgOpWs ctx sep . cfgOp) let correction = if wsLinebreak After ws then 0- else BS.length sep + if wsSpace After ws then 1 else 0+ else T.length sep + if wsSpace After ws then 1 else 0 col <- getNextColumn pretty x go (col - correction) xs where go _ [] = return () go col [ x' ] = do- printComments Before x'+ printCommentsBefore True x' column col $ operator ctx sep prettyPrint x'- printComments After x'+ printCommentsAfter x' go col (x' : xs') = do- printComments Before x'+ printCommentsBefore True x' cut $ do column col $ operator ctx sep prettyPrint x'- printComments After x'+ printCommentsAfter x' go col xs' measure :: Printer a -> Printer (Maybe Int)@@ -412,7 +408,7 @@ return $ case execPrinter (oneline p) s' of Nothing -> Nothing Just (_, s'') -> Just . (\x -> x - psIndentLevel s) . fromIntegral- . BL.length . Buffer.toLazyByteString $ psBuffer s''+ . TL.length . Buffer.toLazyText $ psBuffer s'' measure' :: Printer a -> Printer (Maybe [Int]) measure' p = fmap (: []) <$> measure p@@ -554,7 +550,7 @@ prettySimpleDecl :: (Annotated ast1, Pretty ast1, Annotated ast2, Pretty ast2) => ast1 NodeInfo- -> ByteString+ -> Text -> ast2 NodeInfo -> Printer () prettySimpleDecl lhs op rhs = withLayout cfgLayoutDeclaration flex vertical@@ -614,7 +610,7 @@ -> Type NodeInfo -> Printer () prettyTypesig ctx names ty = do- inter comma $ map pretty names+ listAutoWrap' ctx "," names atTabStop stopRecordField withIndentConfig cfgIndentTypesig align indentby where@@ -625,7 +621,7 @@ nl <- gets psNewline when nl $ do delta <- listVOpLen ctx "->"- write $ BS.replicate delta 32+ write $ T.replicate delta " " pretty ty prettyApp :: (Annotated ast1, Annotated ast2, Pretty ast1, Pretty ast2)@@ -646,7 +642,7 @@ prettyInfixApp :: (Annotated ast, Pretty ast, Annotated op, HSE.Pretty (op NodeInfo))- => (op NodeInfo -> ByteString)+ => (op NodeInfo -> Text) -> LayoutContext -> (ast NodeInfo, [(op NodeInfo, ast NodeInfo)]) -> Printer ()@@ -666,9 +662,9 @@ pretty arg prettyOp op = do- printComments Before op+ printCommentsBefore True op prettyHSE op- printComments After op+ printCommentsAfter op prettyRecord :: (Annotated ast1, Pretty ast1, Annotated ast2, Pretty ast2) => (ast2 NodeInfo -> Printer (Maybe Int))@@ -693,8 +689,7 @@ -> Printer () prettyRecordFields len ctx fields = withLayout cfgLayoutRecord flex vertical where- flex = groupH ctx "{" "}" $ inter (operatorH ctx ",") $- map prettyOnside fields+ flex = groupH ctx "{" "}" $ listAutoWrap' ctx "," fields vertical = groupV ctx "{" "}" $ withComputedTabStop stopRecordField@@ -702,10 +697,10 @@ (fmap (fmap pure) . len) fields $ listVinternal ctx "," fields -prettyPragma :: ByteString -> Printer () -> Printer ()+prettyPragma :: Text -> Printer () -> Printer () prettyPragma name = prettyPragma' name . Just -prettyPragma' :: ByteString -> Maybe (Printer ()) -> Printer ()+prettyPragma' :: Text -> Maybe (Printer ()) -> Printer () prettyPragma' name mp = do write "{-# " write name@@ -930,7 +925,7 @@ mtyvarbinds' mcontext' ty) = depend "pattern" $ do- inter comma $ map pretty names+ listAutoWrap' Declaration "," names operator Declaration "::" mapM_ prettyForall mtyvarbinds mayM_ mcontext pretty@@ -940,7 +935,7 @@ #elif MIN_VERSION_haskell_src_exts(1,20,0) prettyPrint (PatSynSig _ names mtyvarbinds mcontext mcontext' ty) = depend "pattern" $ do- inter comma $ map pretty names+ listAutoWrap' Declaration "," names operator Declaration "::" mapM_ prettyForall mtyvarbinds mayM_ mcontext pretty@@ -1006,7 +1001,7 @@ else prettyPragma "DEPRECATED" $ forM_ deprecations $ \(names, str) -> do unless (null names) $ do- inter comma $ map pretty names+ listAutoWrap' Other "," names space string (show str) @@ -1015,7 +1010,7 @@ then prettyPragma' "WARNING" Nothing else prettyPragma "WARNING" $ forM_ warnings $ \(names, str) -> do unless (null names) $ do- inter comma $ map pretty names+ listAutoWrap' Other "," names space string (show str) @@ -1035,14 +1030,14 @@ mayM_ mactivation $ withPostfix space pretty pretty qname operator Declaration "::"- inter comma $ map pretty types+ listAutoWrap' Declaration "," types prettyPrint (SpecInlineSig _ inline mactivation qname types) = prettyPragma name $ do mayM_ mactivation $ withPostfix space pretty pretty qname operator Declaration "::"- inter comma $ map pretty types+ listAutoWrap' Declaration "," types where name = if inline then "SPECIALISE INLINE" else "SPECIALISE NOINLINE" @@ -1273,7 +1268,7 @@ (opName'' name) (prettyHSE $ VarOp noNodeInfo name) id- inter spaceOrNewline $ map pretty pats+ inter spaceOrNewline $ map (cut . pretty) pats vertical = do pretty pat@@ -1304,13 +1299,13 @@ where flex = do operatorSectionR Pattern "|" $ write "|"- inter comma $ map pretty stmts+ listAutoWrap' Pattern "," stmts operator Declaration "=" pretty expr vertical = do operatorSectionR Pattern "|" $ write "|"- inter comma $ map pretty stmts+ list' Pattern "," stmts operatorV Declaration "=" pretty expr @@ -1477,9 +1472,7 @@ prettyV (TyForall _ mtyvarbinds mcontext ty) = do forM_ mtyvarbinds $ \tyvarbinds -> do- write "forall "- inter space $ map pretty tyvarbinds- withOperatorFormattingV Type "." (write "." >> space) id+ prettyForall tyvarbinds forM_ mcontext $ \context -> do case context of (CxSingle _ asst) -> pretty asst@@ -1616,17 +1609,17 @@ write $ if nl && alignP then "in " else "in " prettyOnside expr - vertical = withIndentAfter- cfgIndentLet- (do- write "let"- withIndent cfgIndentLetBinds $- pretty (CompactBinds binds))- (do- newline- alignP <- getOption cfgOptionAlignLetBindsAndInExpr- write $ if alignP then "in " else "in"- withIndent cfgIndentLetIn $ pretty expr)+ vertical =+ withIndentAfter cfgIndentLet+ (do+ write "let"+ withIndent cfgIndentLetBinds $+ pretty (CompactBinds binds))+ (do+ newline+ alignP <- getOption cfgOptionAlignLetBindsAndInExpr+ write $ if alignP then "in " else "in"+ withIndent cfgIndentLetIn $ pretty expr) prettyPrint (If _ expr expr' expr'') = withLayout cfgLayoutIf flex vertical where@@ -2192,13 +2185,13 @@ instance Pretty ModulePragma where prettyPrint (LanguagePragma _ names) =- prettyPragma "LANGUAGE" . inter comma $ map pretty names+ prettyPragma "LANGUAGE" $ listAutoWrap' Other "," names prettyPrint (OptionsPragma _ mtool str) = prettyPragma name $ string (trim str) where name = case mtool of- Just tool -> "OPTIONS_" `mappend` BS8.pack (HSE.prettyPrint tool)+ Just tool -> "OPTIONS_" `mappend` T.pack (HSE.prettyPrint tool) Nothing -> "OPTIONS" trim = reverse . dropWhile (== ' ') . reverse . dropWhile (== ' ')@@ -2249,10 +2242,10 @@ prettyPrint (VarFormula _ name) = pretty name prettyPrint (AndFormula _ booleanformulas) =- inter comma $ map pretty booleanformulas+ listAutoWrap' Expression "," booleanformulas prettyPrint (OrFormula _ booleanformulas) =- inter (operator Expression "|") $ map pretty booleanformulas+ listAutoWrap' Expression "|" booleanformulas prettyPrint (ParenFormula _ booleanformula) = parens $ pretty booleanformula @@ -2292,7 +2285,7 @@ instance Pretty GuardedAlt where prettyPrint (GuardedAlt (GuardedRhs _ stmts expr)) = cut $ do operatorSectionR Pattern "|" $ write "|"- inter comma $ map pretty stmts+ listAutoWrap' Expression "," stmts operator Expression "->" pretty expr
src/Floskell/Printers.hs view
@@ -4,6 +4,7 @@ ( getConfig , getOption , cut+ , closeEolComment , oneline , ignoreOneline -- * Basic printing@@ -12,6 +13,7 @@ , int , space , newline+ , ensureNewline , blankline , spaceOrNewline -- * Tab stops@@ -34,6 +36,7 @@ , aligned , indented , onside+ , suppressOnside , depend , depend' , parens@@ -60,13 +63,11 @@ import Control.Monad.Search ( cost, winner ) import Control.Monad.State.Strict ( get, gets, modify ) -import Data.ByteString ( ByteString )-import qualified Data.ByteString as BS-import qualified Data.ByteString.Builder as BB-import qualified Data.ByteString.Lazy as BL import Data.List ( intersperse ) import qualified Data.Map.Strict as Map import Data.Monoid ( (<>) )+import Data.Text ( Text )+import qualified Data.Text as T import qualified Floskell.Buffer as Buffer import Floskell.Config@@ -124,7 +125,7 @@ ignoreOneline = withOutputRestriction Anything -- | Write out a string, updating the current position information.-write :: ByteString -> Printer ()+write :: Text -> Printer () write x = do closeEolComment write' x@@ -133,10 +134,10 @@ state <- get let indentLevel = psIndentLevel state out = if psNewline state- then BS.replicate indentLevel 32 <> x'+ then T.replicate indentLevel " " <> x' else x' buffer = psBuffer state- newCol = Buffer.column buffer + BS.length out+ newCol = Buffer.column buffer + T.length out guard $ psOutputRestriction state == Anything || newCol < penaltyMaxLineLength (cfgPenalty (psConfig state)) penalty <- linePenalty False newCol@@ -146,7 +147,7 @@ -- | Write a string. string :: String -> Printer ()-string = write . BL.toStrict . BB.toLazyByteString . BB.stringUtf8+string = write . T.pack -- | Write an integral. int :: Int -> Printer ()@@ -171,6 +172,12 @@ , psEolComment = False }) +-- | Output a newline if not at the start of a line+ensureNewline :: Printer ()+ensureNewline = do+ nl <- gets psNewline+ unless nl newline+ blankline :: Printer () blankline = newline >> newline @@ -197,7 +204,7 @@ mayM_ mstop $ \stop -> do col <- getNextColumn let padding = max 0 (stop - col)- write (BS.replicate padding 32)+ write (T.replicate padding " ") mayM_ :: Maybe a -> (a -> Printer ()) -> Printer () mayM_ Nothing _ = return ()@@ -300,7 +307,7 @@ level <- gets psIndentLevel column (level + i) p --- | Increase indentation level b n spaces for the given printer, but+-- | Increase indentation level by n spaces for the given printer, but -- ignore increase when computing further indentations. onside :: Printer a -> Printer a onside p = do@@ -308,7 +315,16 @@ onsideIndent <- getConfig (cfgIndentOnside . cfgIndent) withIndentation (\(l, _) -> (l, onsideIndent)) p -depend :: ByteString -> Printer a -> Printer a+-- | Temporarily ignore any onside identation.+suppressOnside :: Printer () -> Printer ()+suppressOnside printer = do+ nl <- gets psNewline+ onsideIndent <- gets psOnside+ when nl $ modify $ \s -> s { psOnside = 0 }+ printer+ modify $ \s -> s { psOnside = onsideIndent }++depend :: Text -> Printer a -> Printer a depend kw = depend' (write kw) depend' :: Printer () -> Printer a -> Printer a@@ -334,7 +350,7 @@ p write "]" -group :: LayoutContext -> ByteString -> ByteString -> Printer () -> Printer ()+group :: LayoutContext -> Text -> Text -> Printer () -> Printer () group ctx open close p = do force <- getConfig (wsForceLinebreak . cfgGroupWs ctx open . cfgGroup) if force then vert else oneline hor <|> vert@@ -343,7 +359,7 @@ vert = groupV ctx open close p -groupH :: LayoutContext -> ByteString -> ByteString -> Printer () -> Printer ()+groupH :: LayoutContext -> Text -> Text -> Printer () -> Printer () groupH ctx open close p = do ws <- getConfig (cfgGroupWs ctx open . cfgGroup) write open@@ -352,7 +368,7 @@ when (wsSpace After ws) space write close -groupV :: LayoutContext -> ByteString -> ByteString -> Printer () -> Printer ()+groupV :: LayoutContext -> Text -> Text -> Printer () -> Printer () groupV ctx open close p = aligned $ do ws <- getConfig (cfgGroupWs ctx open . cfgGroup) write open@@ -361,21 +377,21 @@ if wsLinebreak After ws then newline else when (wsSpace After ws) space write close -operator :: LayoutContext -> ByteString -> Printer ()+operator :: LayoutContext -> Text -> Printer () operator ctx op = withOperatorFormatting ctx op (write op) id -operatorH :: LayoutContext -> ByteString -> Printer ()+operatorH :: LayoutContext -> Text -> Printer () operatorH ctx op = withOperatorFormattingH ctx op (write op) id -operatorV :: LayoutContext -> ByteString -> Printer ()+operatorV :: LayoutContext -> Text -> Printer () operatorV ctx op = withOperatorFormattingV ctx op (write op) id -alignOnOperator :: LayoutContext -> ByteString -> Printer a -> Printer a+alignOnOperator :: LayoutContext -> Text -> Printer a -> Printer a alignOnOperator ctx op p = withOperatorFormatting ctx op (write op) (aligned . (*> p)) withOperatorFormatting :: LayoutContext- -> ByteString+ -> Text -> Printer () -> (Printer () -> Printer a) -> Printer a@@ -388,7 +404,7 @@ vert = withOperatorFormattingV ctx op opp fn withOperatorFormattingH :: LayoutContext- -> ByteString+ -> Text -> Printer () -> (Printer () -> Printer a) -> Printer a@@ -400,24 +416,26 @@ when (wsSpace After ws) space withOperatorFormattingV :: LayoutContext- -> ByteString+ -> Text -> Printer () -> (Printer () -> Printer a) -> Printer a withOperatorFormattingV ctx op opp fn = do ws <- getConfig (cfgOpWs ctx op . cfgOp)- if wsLinebreak Before ws then newline else when (wsSpace Before ws) space+ if wsLinebreak Before ws+ then ensureNewline+ else when (wsSpace Before ws) space fn $ do opp if wsLinebreak After ws then newline else when (wsSpace After ws) space -operatorSectionL :: LayoutContext -> ByteString -> Printer () -> Printer ()+operatorSectionL :: LayoutContext -> Text -> Printer () -> Printer () operatorSectionL ctx op opp = do ws <- getConfig (cfgOpWs ctx op . cfgOp) when (wsSpace Before ws) space opp -operatorSectionR :: LayoutContext -> ByteString -> Printer () -> Printer ()+operatorSectionR :: LayoutContext -> Text -> Printer () -> Printer () operatorSectionR ctx op opp = do ws <- getConfig (cfgOpWs ctx op . cfgOp) opp
src/Floskell/Styles.hs view
@@ -22,35 +22,35 @@ defaultConfig { cfgIndent, cfgLayout, cfgOp, cfgGroup, cfgOptions } where cfgIndent =- IndentConfig { cfgIndentOnside = 2- , cfgIndentDeriving = 2- , cfgIndentWhere = 2- , cfgIndentApp = Align- , cfgIndentCase = IndentBy 2- , cfgIndentClass = IndentBy 2- , cfgIndentDo = Align- , cfgIndentIf = IndentBy 3- , cfgIndentLet = Align- , cfgIndentLetBinds = Align- , cfgIndentLetIn = Align- , cfgIndentMultiIf = IndentBy 2- , cfgIndentTypesig = Align- , cfgIndentWhereBinds = Align+ IndentConfig { cfgIndentOnside = 2+ , cfgIndentDeriving = 2+ , cfgIndentWhere = 2+ , cfgIndentApp = Align+ , cfgIndentCase = IndentBy 2+ , cfgIndentClass = IndentBy 2+ , cfgIndentDo = Align+ , cfgIndentIf = IndentBy 3+ , cfgIndentLet = Align+ , cfgIndentLetBinds = Align+ , cfgIndentLetIn = Align+ , cfgIndentMultiIf = IndentBy 2+ , cfgIndentTypesig = Align+ , cfgIndentWhereBinds = Align , cfgIndentExportSpecList = IndentBy 2 , cfgIndentImportSpecList = AlignOrIndentBy 7 } - cfgLayout = LayoutConfig { cfgLayoutApp = TryOneline- , cfgLayoutConDecls = Vertical- , cfgLayoutDeclaration = TryOneline+ cfgLayout = LayoutConfig { cfgLayoutApp = TryOneline+ , cfgLayoutConDecls = Vertical+ , cfgLayoutDeclaration = TryOneline , cfgLayoutExportSpecList = TryOneline- , cfgLayoutIf = Vertical+ , cfgLayoutIf = Vertical , cfgLayoutImportSpecList = Flex- , cfgLayoutInfixApp = TryOneline- , cfgLayoutLet = Vertical- , cfgLayoutListComp = Flex- , cfgLayoutRecord = Vertical- , cfgLayoutType = TryOneline+ , cfgLayoutInfixApp = TryOneline+ , cfgLayoutLet = Vertical+ , cfgLayoutListComp = Flex+ , cfgLayoutRecord = Vertical+ , cfgLayoutType = TryOneline } cfgOp =@@ -111,35 +111,35 @@ } cfgIndent =- IndentConfig { cfgIndentOnside = 4- , cfgIndentDeriving = 4- , cfgIndentWhere = 2- , cfgIndentApp = Align- , cfgIndentCase = IndentBy 4- , cfgIndentClass = IndentBy 4- , cfgIndentDo = IndentBy 4- , cfgIndentIf = Align- , cfgIndentLet = Align- , cfgIndentLetBinds = Align- , cfgIndentLetIn = IndentBy 4- , cfgIndentMultiIf = IndentBy 4- , cfgIndentTypesig = Align- , cfgIndentWhereBinds = IndentBy 2+ IndentConfig { cfgIndentOnside = 4+ , cfgIndentDeriving = 4+ , cfgIndentWhere = 2+ , cfgIndentApp = Align+ , cfgIndentCase = IndentBy 4+ , cfgIndentClass = IndentBy 4+ , cfgIndentDo = IndentBy 4+ , cfgIndentIf = Align+ , cfgIndentLet = Align+ , cfgIndentLetBinds = Align+ , cfgIndentLetIn = IndentBy 4+ , cfgIndentMultiIf = IndentBy 4+ , cfgIndentTypesig = Align+ , cfgIndentWhereBinds = IndentBy 2 , cfgIndentExportSpecList = IndentBy 4 , cfgIndentImportSpecList = AlignOrIndentBy 17 } - cfgLayout = LayoutConfig { cfgLayoutApp = TryOneline- , cfgLayoutConDecls = TryOneline- , cfgLayoutDeclaration = Flex+ cfgLayout = LayoutConfig { cfgLayoutApp = TryOneline+ , cfgLayoutConDecls = TryOneline+ , cfgLayoutDeclaration = Flex , cfgLayoutExportSpecList = TryOneline- , cfgLayoutIf = TryOneline+ , cfgLayoutIf = TryOneline , cfgLayoutImportSpecList = Flex- , cfgLayoutInfixApp = Flex- , cfgLayoutLet = TryOneline- , cfgLayoutListComp = TryOneline- , cfgLayoutRecord = TryOneline- , cfgLayoutType = TryOneline+ , cfgLayoutInfixApp = Flex+ , cfgLayoutLet = TryOneline+ , cfgLayoutListComp = TryOneline+ , cfgLayoutRecord = TryOneline+ , cfgLayoutType = TryOneline } cfgOp =@@ -225,35 +225,35 @@ } cfgIndent =- IndentConfig { cfgIndentOnside = 2- , cfgIndentDeriving = 2- , cfgIndentWhere = 2- , cfgIndentApp = IndentBy 2- , cfgIndentCase = IndentBy 2- , cfgIndentClass = IndentBy 2- , cfgIndentDo = IndentBy 2- , cfgIndentIf = Align- , cfgIndentLet = Align- , cfgIndentLetBinds = Align- , cfgIndentLetIn = Align- , cfgIndentMultiIf = IndentBy 2- , cfgIndentTypesig = Align- , cfgIndentWhereBinds = IndentBy 2+ IndentConfig { cfgIndentOnside = 2+ , cfgIndentDeriving = 2+ , cfgIndentWhere = 2+ , cfgIndentApp = IndentBy 2+ , cfgIndentCase = IndentBy 2+ , cfgIndentClass = IndentBy 2+ , cfgIndentDo = IndentBy 2+ , cfgIndentIf = Align+ , cfgIndentLet = Align+ , cfgIndentLetBinds = Align+ , cfgIndentLetIn = Align+ , cfgIndentMultiIf = IndentBy 2+ , cfgIndentTypesig = Align+ , cfgIndentWhereBinds = IndentBy 2 , cfgIndentExportSpecList = IndentBy 4 , cfgIndentImportSpecList = Align } - cfgLayout = LayoutConfig { cfgLayoutApp = TryOneline- , cfgLayoutConDecls = Vertical- , cfgLayoutDeclaration = Flex+ cfgLayout = LayoutConfig { cfgLayoutApp = TryOneline+ , cfgLayoutConDecls = Vertical+ , cfgLayoutDeclaration = Flex , cfgLayoutExportSpecList = TryOneline- , cfgLayoutIf = Vertical+ , cfgLayoutIf = Vertical , cfgLayoutImportSpecList = Flex- , cfgLayoutInfixApp = TryOneline- , cfgLayoutLet = Vertical- , cfgLayoutListComp = TryOneline- , cfgLayoutRecord = TryOneline- , cfgLayoutType = TryOneline+ , cfgLayoutInfixApp = TryOneline+ , cfgLayoutLet = Vertical+ , cfgLayoutListComp = TryOneline+ , cfgLayoutRecord = TryOneline+ , cfgLayoutType = TryOneline } cfgOp =@@ -298,35 +298,35 @@ defaultConfig { cfgIndent, cfgLayout, cfgOp, cfgGroup, cfgOptions } where cfgIndent =- IndentConfig { cfgIndentOnside = 4- , cfgIndentDeriving = 4- , cfgIndentWhere = 2- , cfgIndentApp = IndentBy 4- , cfgIndentCase = IndentBy 4- , cfgIndentClass = IndentBy 4- , cfgIndentDo = IndentBy 4- , cfgIndentIf = IndentBy 4- , cfgIndentLet = Align- , cfgIndentLetBinds = Align- , cfgIndentLetIn = Align- , cfgIndentMultiIf = IndentBy 2- , cfgIndentTypesig = Align- , cfgIndentWhereBinds = IndentBy 2+ IndentConfig { cfgIndentOnside = 4+ , cfgIndentDeriving = 4+ , cfgIndentWhere = 2+ , cfgIndentApp = IndentBy 4+ , cfgIndentCase = IndentBy 4+ , cfgIndentClass = IndentBy 4+ , cfgIndentDo = IndentBy 4+ , cfgIndentIf = IndentBy 4+ , cfgIndentLet = Align+ , cfgIndentLetBinds = Align+ , cfgIndentLetIn = Align+ , cfgIndentMultiIf = IndentBy 2+ , cfgIndentTypesig = Align+ , cfgIndentWhereBinds = IndentBy 2 , cfgIndentExportSpecList = IndentBy 2 , cfgIndentImportSpecList = AlignOrIndentBy 7 } - cfgLayout = LayoutConfig { cfgLayoutApp = TryOneline- , cfgLayoutConDecls = Vertical- , cfgLayoutDeclaration = TryOneline+ cfgLayout = LayoutConfig { cfgLayoutApp = TryOneline+ , cfgLayoutConDecls = Vertical+ , cfgLayoutDeclaration = TryOneline , cfgLayoutExportSpecList = TryOneline- , cfgLayoutIf = Vertical+ , cfgLayoutIf = Vertical , cfgLayoutImportSpecList = Flex- , cfgLayoutInfixApp = TryOneline- , cfgLayoutLet = Vertical- , cfgLayoutListComp = Flex- , cfgLayoutRecord = Vertical- , cfgLayoutType = TryOneline+ , cfgLayoutInfixApp = TryOneline+ , cfgLayoutLet = Vertical+ , cfgLayoutListComp = Flex+ , cfgLayoutRecord = Vertical+ , cfgLayoutType = TryOneline } cfgOp =
src/Floskell/Types.hs view
@@ -78,14 +78,14 @@ -- | The state of the pretty printer. data PrintState =- PrintState { psBuffer :: !Buffer -- ^ Output buffer- , psIndentLevel :: !Int -- ^ Current indentation level.- , psOnside :: !Int -- ^ Extra indentation is necessary with next line break.- , psTabStops :: !(Map.Map TabStop Int) -- ^ Tab stops for alignment.- , psConfig :: !Config -- ^ Style definition.- , psEolComment :: !Bool -- ^ An end of line comment has just been outputted.+ PrintState { psBuffer :: !Buffer -- ^ Output buffer+ , psIndentLevel :: !Int -- ^ Current indentation level.+ , psOnside :: !Int -- ^ Extra indentation is necessary with next line break.+ , psTabStops :: !(Map.Map TabStop Int) -- ^ Tab stops for alignment.+ , psConfig :: !Config -- ^ Style definition.+ , psEolComment :: !Bool -- ^ An end of line comment has just been outputted. , psOutputRestriction :: !OutputRestriction- , psTypeLayout :: !TypeLayout+ , psTypeLayout :: !TypeLayout } psLine :: PrintState -> Int@@ -101,7 +101,8 @@ initialPrintState config = PrintState Buffer.empty 0 0 Map.empty config False Anything TypeFree -data CommentType = InlineComment | LineComment | PreprocessorDirective+data CommentType =+ InlineComment | LineComment | PreprocessorDirective | IgnoredLine deriving ( Show ) data Comment = Comment { commentType :: !CommentType@@ -112,8 +113,8 @@ -- | Information for each node in the AST. data NodeInfo =- NodeInfo { nodeInfoSpan :: !SrcSpan -- ^ Location info from the parser.- , nodeInfoLeadingComments :: ![Comment] -- ^ Leading comments attached to this node.+ NodeInfo { nodeInfoSpan :: !SrcSpan -- ^ Location info from the parser.+ , nodeInfoLeadingComments :: ![Comment] -- ^ Leading comments attached to this node. , nodeInfoTrailingComments :: ![Comment] -- ^ Trailing comments attached to this node. } deriving ( Show )
src/main/Benchmark.hs view
@@ -9,20 +9,20 @@ import Criterion import Criterion.Main -import qualified Data.ByteString.Lazy.Char8 as L8-import qualified Data.ByteString.Lazy.UTF8 as UTF8-import qualified Data.Text as T+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.IO as TIO import Floskell -import Language.Haskell.Exts ( Language(Haskell2010) )+import Language.Haskell.Exts ( Language(Haskell2010) ) import Markdone -- | Main benchmarks. main :: IO () main = do- bytes <- L8.readFile "BENCHMARK.md"+ bytes <- TIO.readFile "BENCHMARK.md" !forest <- fmap force (parse (tokenize bytes)) defaultMain [ bgroup (T.unpack $ styleName style) $ toCriterion (AppConfig style@@ -37,11 +37,11 @@ toCriterion :: AppConfig -> [Markdone] -> [Benchmark] toCriterion config = go where- go (Section name children : next) = bgroup (L8.unpack name) (go children)+ go (Section name children : next) = bgroup (TL.unpack name) (go children) : go next go (PlainText desc : CodeFence lang code : next) = if lang == "haskell"- then bench (UTF8.toString desc)+ then bench (TL.unpack desc) (nf (either error id . reformat config (Just "BENCHMARK.md")) code) : go next else go next
src/main/Main.hs view
@@ -4,27 +4,29 @@ -- | Main entry point to floskell. module Main ( main ) where -import Control.Applicative ( many, optional )-import Control.Exception ( catch, throw )+import Control.Applicative ( many, optional )+import Control.Exception ( catch, throw ) -import qualified Data.Aeson.Encode.Pretty as JSON ( encodePretty )-import qualified Data.ByteString.Lazy as BL-import Data.List ( sort )-import Data.Maybe ( isJust )-import Data.Monoid ( (<>) )-import qualified Data.Text as T-import Data.Version ( showVersion )+import qualified Data.Aeson.Encode.Pretty as JSON ( encodePretty )+import qualified Data.ByteString.Lazy as BL+import Data.List ( sort )+import Data.Maybe ( isJust )+import Data.Monoid ( (<>) )+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.IO as TIO+import Data.Version ( showVersion ) import Floskell ( AppConfig(..), Style(..), defaultAppConfig, findAppConfig , readAppConfig, reformat, setExtensions, setFixities , setLanguage, setStyle, styles )-import Floskell.ConfigFile ( showFixity )-import Floskell.Fixities ( packageFixities )+import Floskell.ConfigFile ( showFixity )+import Floskell.Fixities ( packageFixities ) -import Foreign.C.Error ( Errno(..), eXDEV )+import Foreign.C.Error ( Errno(..), eXDEV ) -import GHC.IO.Exception ( ioe_errno )+import GHC.IO.Exception ( ioe_errno ) import Language.Haskell.Exts ( Extension(..), knownExtensions, knownLanguages )@@ -33,9 +35,8 @@ ( ParseError(..), abortOption, argument, execParser, footerDoc , fullDesc, header, help, helper, hidden, info, long, metavar , option, progDesc, short, str, switch )-import qualified Options.Applicative.Help.Pretty as PP -import Paths_floskell ( version )+import Paths_floskell ( version ) import System.Directory ( copyFile, copyPermissions, getTemporaryDirectory, removeFile@@ -43,6 +44,8 @@ import System.IO ( FilePath, hClose, hFlush, openTempFile, stdout ) +import qualified Text.PrettyPrint.ANSI.Leijen as PP+ -- | Program options. data Options = Options { optStyle :: Maybe String , optLanguage :: Maybe String@@ -137,15 +140,15 @@ -- | Reformat stdin according to Style, Language, and Extensions. reformatStdin :: AppConfig -> IO ()-reformatStdin config = BL.interact $ reformatByteString config Nothing+reformatStdin config = TIO.interact $ reformatText config Nothing -- | Reformat a file according to Style, Language, and Extensions. reformatFile :: AppConfig -> FilePath -> IO () reformatFile config file = do- text <- BL.readFile file+ text <- TIO.readFile file tmpDir <- getTemporaryDirectory (fp, h) <- openTempFile tmpDir "floskell.hs"- BL.hPutStr h $ reformatByteString config (Just file) text+ TIO.hPutStr h $ reformatText config (Just file) text hFlush h hClose h let exdev e = if ioe_errno e == Just ((\(Errno a) -> a) eXDEV)@@ -154,11 +157,9 @@ copyPermissions file fp renameFile fp file `catch` exdev --- | Reformat a ByteString according to Style, Language, and Extensions.-reformatByteString- :: AppConfig -> Maybe FilePath -> BL.ByteString -> BL.ByteString-reformatByteString config mpath text =- either error id $ reformat config mpath text+-- | Reformat a Text according to Style, Language, and Extensions.+reformatText :: AppConfig -> Maybe FilePath -> TL.Text -> TL.Text+reformatText config mpath text = either error id $ reformat config mpath text -- | Update the program configuration from the program options. mergeAppConfig :: AppConfig -> Options -> AppConfig
src/main/Markdone.hs view
@@ -13,27 +13,23 @@ import Control.DeepSeq import Control.Monad.Catch -import Data.ByteString.Builder as B-import qualified Data.ByteString.Char8 as S8-import Data.ByteString.Lazy ( ByteString )-import qualified Data.ByteString.Lazy.Char8 as L8 import Data.Char-import Data.Monoid ( (<>) )+import Data.Monoid ( (<>) )+import Data.Text.Lazy ( Text )+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Builder as TB+import qualified Data.Text.Lazy.IO as TIO import Data.Typeable import GHC.Generics -- | A markdone token.-data Token = Heading !Int !ByteString- | PlainLine !ByteString- | BeginFence !ByteString- | EndFence+data Token = Heading !Int !Text | PlainLine !Text | BeginFence !Text | EndFence deriving ( Show ) -- | A markdone document.-data Markdone = Section !ByteString ![Markdone]- | CodeFence !ByteString !ByteString- | PlainText !ByteString+data Markdone =+ Section !Text ![Markdone] | CodeFence !Text !Text | PlainText !Text deriving ( Show, Generic ) instance NFData Markdone@@ -45,18 +41,18 @@ instance Exception MarkdownError -- | Tokenize the bytestring.-tokenize :: ByteString -> [Token]-tokenize = map token . L8.lines+tokenize :: Text -> [Token]+tokenize = map token . TL.lines where token line- | L8.isPrefixOf "#" line = let (hashes, title) = L8.span (== '#') line+ | TL.isPrefixOf "#" line = let (hashes, title) = TL.span (== '#') line in- Heading (fromIntegral $ L8.length hashes)- (L8.dropWhile isSpace title)- | L8.isPrefixOf "```" line =+ Heading (fromIntegral $ TL.length hashes)+ (TL.dropWhile isSpace title)+ | TL.isPrefixOf "```" line = if line == "```" then EndFence- else BeginFence (L8.dropWhile (\c -> c == '`' || c == ' ') line)+ else BeginFence (TL.dropWhile (\c -> c == '`' || c == ' ') line) | otherwise = PlainLine line -- | Parse into a forest.@@ -84,7 +80,7 @@ case rest' of (EndFence : rest'') -> fmap (CodeFence label- (L8.intercalate "\n"+ (TL.intercalate "\n" (map getPlain content)) :) (go level rest'')@@ -96,7 +92,7 @@ _ -> False) (PlainLine p : rest) in- fmap (PlainText (L8.intercalate "\n" (map getPlain content)) :)+ fmap (PlainText (TL.intercalate "\n" (map getPlain content)) :) (go level rest') [] -> return [] _ -> throwM ExpectedSection@@ -104,16 +100,17 @@ getPlain (PlainLine x) = x getPlain _ = "" -print :: [Markdone] -> B.Builder-print = mconcat . map (go (0 :: Int))+print :: [Markdone] -> TB.Builder+print = mconcat . map (go 0) where go level = \case (Section heading children) -> let level' = level + 1 in- B.byteString (S8.replicate level' '#') <> B.char7 ' '- <> B.lazyByteString heading <> B.byteString "\n"+ TB.fromLazyText (TL.replicate level' "#") <> TB.singleton ' '+ <> TB.fromLazyText heading <> TB.fromString "\n" <> mconcat (map (go level') children)- (CodeFence lang code) -> B.byteString "``` " <> B.lazyByteString lang- <> B.char7 '\n' <> B.lazyByteString code <> B.byteString "\n```\n"- (PlainText text) -> B.lazyByteString text <> B.byteString "\n"+ (CodeFence lang code) ->+ TB.fromString "``` " <> TB.fromLazyText lang <> TB.singleton '\n'+ <> TB.fromLazyText code <> TB.fromString "\n```\n"+ (PlainText text) -> TB.fromLazyText text <> TB.fromString "\n"
src/main/Test.hs view
@@ -5,43 +5,43 @@ -- | Test the pretty printer. module Main where -import Control.Applicative ( (<|>) )-import Control.Monad ( forM_, guard )+import Control.Applicative ( (<|>) )+import Control.Monad ( forM_, guard ) -import Data.ByteString.Lazy ( ByteString )-import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString.Builder as B ( toLazyByteString )-import qualified Data.ByteString.Lazy.UTF8 as UTF8-import Data.Maybe ( mapMaybe )-import qualified Data.Text as T+import Data.Maybe ( mapMaybe )+import qualified Data.Text as T+import Data.Text.Lazy ( Text )+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Builder as TB ( toLazyText )+import qualified Data.Text.Lazy.IO as TIO import Floskell -import Language.Haskell.Exts ( Language(Haskell2010) )+import Language.Haskell.Exts ( Language(Haskell2010) ) -import Markdone ( Markdone(..) )-import qualified Markdone as MD+import Markdone ( Markdone(..) )+import qualified Markdone as MD -import System.Environment ( getArgs )+import System.Environment ( getArgs ) import Test.Hspec data TestTree =- TestSection String [TestTree] | TestSnippet ByteString | TestMismatchMarker+ TestSection String [TestTree] | TestSnippet Text | TestMismatchMarker -- | Prints a string without quoting and escaping.-newtype Readable = Readable ByteString+newtype Readable = Readable Text deriving ( Eq ) instance Show Readable where- show (Readable x) = "\n" ++ UTF8.toString x+ show (Readable x) = "\n" ++ TL.unpack x -- | Version of 'shouldBe' that prints strings in a readable way, -- better for our use-case.-shouldBeReadable :: ByteString -> ByteString -> Expectation+shouldBeReadable :: Text -> Text -> Expectation shouldBeReadable x y = Readable x `shouldBe` Readable y -haskell :: ByteString+haskell :: Text haskell = "haskell" referenceFile :: Style -> String@@ -51,19 +51,18 @@ loadMarkdone :: String -> IO [Markdone] loadMarkdone filename = do- bytes <- L.readFile filename+ bytes <- TIO.readFile filename MD.parse (MD.tokenize bytes) saveMarkdone :: String -> [Markdone] -> IO () saveMarkdone filename doc =- L.writeFile filename . B.toLazyByteString $ MD.print doc+ TIO.writeFile filename . TB.toLazyText $ MD.print doc -- | Extract code snippets from a Markdone document.-extractSnippets :: ByteString -> [Markdone] -> [TestTree]+extractSnippets :: Text -> [Markdone] -> [TestTree] extractSnippets lang = mapMaybe convert where- convert (Section name children) =- return $ TestSection (UTF8.toString name) $+ convert (Section name children) = return $ TestSection (TL.unpack name) $ extractSnippets lang children convert (CodeFence l c) = do guard $ l == lang@@ -80,7 +79,8 @@ disabled style path = lookup (Just style, path) disabledTests <|> lookup (Nothing :: Maybe T.Text, path) disabledTests where- disabledTests = []+ disabledTests =+ [] #if MIN_VERSION_haskell_src_exts(1,21,0) #else ++ [ ((Nothing, [ 2, 3, 4, 1 ]), "requires haskell-src-exts >=1.21.0")@@ -134,7 +134,7 @@ tree <- loadSnippets $ referenceFile style return (name, style, tree) -reformatSnippet :: Style -> ByteString -> Either String ByteString+reformatSnippet :: Style -> Text -> Either String Text reformatSnippet style = reformat (AppConfig style Haskell2010 defaultExtensions []) (Just "TEST.md")@@ -144,7 +144,7 @@ where fmt (CodeFence lang code) = if lang == haskell- then CodeFence lang $ either (UTF8.fromString . ("-- " ++) . show) id $+ then CodeFence lang $ either (TL.pack . ("-- " ++) . show) id $ reformatSnippet style code else CodeFence lang code fmt (Section heading children) =
styles/base.md view
@@ -642,12 +642,12 @@ foo = Point { x = 1, y = 2 } foo = Point { x = 1 -- the one- , y, .. }+ , y, .. } foo = bar { x = 1 } foo = bar { x = 1 -- the one- , y, .. }+ , y, .. } ``` ### Let, If, MultiIf, and Case@@ -777,9 +777,9 @@ Long types allow linebreaks. ``` haskell-newtype MyMonadT a b m- = MyMonad { runMyMonad :: StateT ([ ( a, a -> b ) ])- (ReaderT a (ExceptT [ IM.IntMap b ]) (WriterT [ IS.IntSet x ] m)) }+newtype MyMonadT a b m = MyMonad { runMyMonad :: StateT ([ ( a, a -> b ) ])+ (ReaderT a (ExceptT [ IM.IntMap b ])+ (WriterT [ IS.IntSet x ] m)) } ``` Promoted types.@@ -869,7 +869,7 @@ ``` haskell data Foo = Foo { fooBar :: Text- -- ^A comment, long enough to end up on its own line, or at least I hope so.+ -- ^A comment, long enough to end up on its own line, or at least I hope so. } deriving ( Eq ) ```@@ -930,6 +930,80 @@ f :: () -- f = ()+```++## Preprocessor Directives++Preprocessor directives are accepted and retained.++``` haskell+ #include <file.h>+ instance Monoid Penalty where+ mempty = 0++ #if !(MIN_VERSION_base(4,11,0))+ mappend = (<>)+ #endif++ #define FOO 1+ #undef FOO++ #warning "WARNING"+ #error "ERROR"+```++Multiline directives++``` haskell+ #define FOO \+ bar++ #if FOO \+ && BAR+ foo = bar+ #endif+```++Support for Hsc2hs #enum++``` haskell+ #enum CInt, \+ , fs = CTL_FS \+ , hw = CTL_HW \+ , kern = CTL_KERN \+ , net = CTL_NET \+ , vfs = CTL_VFS \+ , mem = CTL_VM+```++## Ignored Lines++Ignore lines nested in `floskell-disable` and `floskell-enable`++``` haskell+-- floskell-disable+This is ignored.+-- floskell-enable++{- floskell-disable -}+And so is this.+{- floskell-enable -}+```++Ignore shebang lines++``` haskell+ #! /usr/bin/env nix-shell+ #! nix-shell -p ghcid+ #! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [ shower ])"+ #! nix-shell -i "ghcid -c 'ghci -Wall' -T':!pkill --full ghc\\ .\\*./Main.hs' -T main"++ module Main where++ import Shower++ main :: IO ()+ main = printer "Hello" ``` ## Indentation and Line Prefixes
styles/chris-done.md view
@@ -997,6 +997,80 @@ f = () ``` +## Preprocessor Directives++Preprocessor directives are accepted and retained.++``` haskell+ #include <file.h>+ instance Monoid Penalty where+ mempty = 0++ #if !(MIN_VERSION_base(4,11,0))+ mappend = (<>)+ #endif++ #define FOO 1+ #undef FOO++ #warning "WARNING"+ #error "ERROR"+```++Multiline directives++``` haskell+ #define FOO \+ bar++ #if FOO \+ && BAR+ foo = bar+ #endif+```++Support for Hsc2hs #enum++``` haskell+ #enum CInt, \+ , fs = CTL_FS \+ , hw = CTL_HW \+ , kern = CTL_KERN \+ , net = CTL_NET \+ , vfs = CTL_VFS \+ , mem = CTL_VM+```++## Ignored Lines++Ignore lines nested in `floskell-disable` and `floskell-enable`++``` haskell+-- floskell-disable+This is ignored.+-- floskell-enable++{- floskell-disable -}+And so is this.+{- floskell-enable -}+```++Ignore shebang lines++``` haskell+ #! /usr/bin/env nix-shell+ #! nix-shell -p ghcid+ #! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [ shower ])"+ #! nix-shell -i "ghcid -c 'ghci -Wall' -T':!pkill --full ghc\\ .\\*./Main.hs' -T main"++ module Main where++ import Shower++ main :: IO ()+ main = printer "Hello"+```+ ## Indentation and Line Prefixes Preserving indentation and line prefixes so that Floskell can be run
styles/cramer.md view
@@ -973,6 +973,80 @@ f = () ``` +## Preprocessor Directives++Preprocessor directives are accepted and retained.++``` haskell+ #include <file.h>+ instance Monoid Penalty where+ mempty = 0++ #if !(MIN_VERSION_base(4,11,0))+ mappend = (<>)+ #endif++ #define FOO 1+ #undef FOO++ #warning "WARNING"+ #error "ERROR"+```++Multiline directives++``` haskell+ #define FOO \+ bar++ #if FOO \+ && BAR+ foo = bar+ #endif+```++Support for Hsc2hs #enum++``` haskell+ #enum CInt, \+ , fs = CTL_FS \+ , hw = CTL_HW \+ , kern = CTL_KERN \+ , net = CTL_NET \+ , vfs = CTL_VFS \+ , mem = CTL_VM+```++## Ignored Lines++Ignore lines nested in `floskell-disable` and `floskell-enable`++``` haskell+-- floskell-disable+This is ignored.+-- floskell-enable++{- floskell-disable -}+And so is this.+{- floskell-enable -}+```++Ignore shebang lines++``` haskell+ #! /usr/bin/env nix-shell+ #! nix-shell -p ghcid+ #! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [ shower ])"+ #! nix-shell -i "ghcid -c 'ghci -Wall' -T':!pkill --full ghc\\ .\\*./Main.hs' -T main"++ module Main where++ import Shower++ main :: IO ()+ main = printer "Hello"+```+ ## Indentation and Line Prefixes Preserving indentation and line prefixes so that Floskell can be run
styles/gibiansky.md view
@@ -964,6 +964,80 @@ f = () ``` +## Preprocessor Directives++Preprocessor directives are accepted and retained.++``` haskell+ #include <file.h>+ instance Monoid Penalty where+ mempty = 0++ #if !(MIN_VERSION_base(4,11,0))+ mappend = (<>)+ #endif++ #define FOO 1+ #undef FOO++ #warning "WARNING"+ #error "ERROR"+```++Multiline directives++``` haskell+ #define FOO \+ bar++ #if FOO \+ && BAR+ foo = bar+ #endif+```++Support for Hsc2hs #enum++``` haskell+ #enum CInt, \+ , fs = CTL_FS \+ , hw = CTL_HW \+ , kern = CTL_KERN \+ , net = CTL_NET \+ , vfs = CTL_VFS \+ , mem = CTL_VM+```++## Ignored Lines++Ignore lines nested in `floskell-disable` and `floskell-enable`++``` haskell+-- floskell-disable+This is ignored.+-- floskell-enable++{- floskell-disable -}+And so is this.+{- floskell-enable -}+```++Ignore shebang lines++``` haskell+ #! /usr/bin/env nix-shell+ #! nix-shell -p ghcid+ #! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [ shower ])"+ #! nix-shell -i "ghcid -c 'ghci -Wall' -T':!pkill --full ghc\\ .\\*./Main.hs' -T main"++ module Main where++ import Shower++ main :: IO ()+ main = printer "Hello"+```+ ## Indentation and Line Prefixes Preserving indentation and line prefixes so that Floskell can be run
styles/johan-tibell.md view
@@ -521,10 +521,10 @@ {-# DEPRECATED #-} {-# DEPRECATED foo "use bar instead" #-}-{-# DEPRECATED foo, bar, baz "no longer supported" #-}+{-# DEPRECATED foo,bar,baz "no longer supported" #-} {-# WARNING #-} {-# WARNING foo "use bar instead" #-}-{-# WARNING foo, bar, baz "no longer supported" #-}+{-# WARNING foo,bar,baz "no longer supported" #-} {-# INLINE foo #-} {-# INLINE [3] foo #-} {-# INLINE [~3] foo #-}@@ -1026,6 +1026,80 @@ f :: () -- f = ()+```++## Preprocessor Directives++Preprocessor directives are accepted and retained.++``` haskell+ #include <file.h>+ instance Monoid Penalty where+ mempty = 0++ #if !(MIN_VERSION_base(4,11,0))+ mappend = (<>)+ #endif++ #define FOO 1+ #undef FOO++ #warning "WARNING"+ #error "ERROR"+```++Multiline directives++``` haskell+ #define FOO \+ bar++ #if FOO \+ && BAR+ foo = bar+ #endif+```++Support for Hsc2hs #enum++``` haskell+ #enum CInt, \+ , fs = CTL_FS \+ , hw = CTL_HW \+ , kern = CTL_KERN \+ , net = CTL_NET \+ , vfs = CTL_VFS \+ , mem = CTL_VM+```++## Ignored Lines++Ignore lines nested in `floskell-disable` and `floskell-enable`++``` haskell+-- floskell-disable+This is ignored.+-- floskell-enable++{- floskell-disable -}+And so is this.+{- floskell-enable -}+```++Ignore shebang lines++``` haskell+ #! /usr/bin/env nix-shell+ #! nix-shell -p ghcid+ #! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [ shower ])"+ #! nix-shell -i "ghcid -c 'ghci -Wall' -T':!pkill --full ghc\\ .\\*./Main.hs' -T main"++ module Main where++ import Shower++ main :: IO ()+ main = printer "Hello" ``` ## Indentation and Line Prefixes