stylish-haskell (empty) → 0.1.0.0
raw patch · 19 files changed
+814/−0 lines, 19 filesdep +HUnitdep +basedep +haskell-src-extssetup-changed
Dependencies added: HUnit, base, haskell-src-exts, test-framework, test-framework-hunit
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- src/Main.hs +49/−0
- src/StylishHaskell/Block.hs +60/−0
- src/StylishHaskell/Editor.hs +105/−0
- src/StylishHaskell/Imports.hs +110/−0
- src/StylishHaskell/LanguagePragmas.hs +53/−0
- src/StylishHaskell/Parse.hs +41/−0
- src/StylishHaskell/Stylish.hs +23/−0
- src/StylishHaskell/Tabs.hs +21/−0
- src/StylishHaskell/TrailingWhitespace.hs +22/−0
- src/StylishHaskell/Util.hs +21/−0
- stylish-haskell.cabal +64/−0
- tests/StylishHaskell/Imports/Tests.hs +51/−0
- tests/StylishHaskell/LanguagePragmas/Tests.hs +41/−0
- tests/StylishHaskell/Tabs/Tests.hs +42/−0
- tests/StylishHaskell/Tests/Util.hs +17/−0
- tests/StylishHaskell/TrailingWhitespace/Tests.hs +37/−0
- tests/TestSuite.hs +25/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2012, Jasper Van der Jeugt <m@jaspervdj.be>++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Jasper Van der Jeugt <m@jaspervdj.be> nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Main.hs view
@@ -0,0 +1,49 @@+--------------------------------------------------------------------------------+module Main+ ( main+ ) where+++--------------------------------------------------------------------------------+import Control.Applicative ((<$>))+import Data.Maybe (listToMaybe)+import System.Environment (getArgs)+++--------------------------------------------------------------------------------+import qualified StylishHaskell.Imports+import qualified StylishHaskell.LanguagePragmas+import StylishHaskell.Parse+import StylishHaskell.Stylish+import qualified StylishHaskell.Tabs+import qualified StylishHaskell.TrailingWhitespace+++--------------------------------------------------------------------------------+runStylish :: Maybe FilePath -> Stylish -> Lines -> Lines+runStylish mfp f ls = case parseModule mfp (unlines ls) of+ Left err -> error err -- TODO: maybe return original lines?+ Right module' -> f ls module'+++--------------------------------------------------------------------------------+chainStylish :: Maybe FilePath -> [Stylish] -> Lines -> Lines+chainStylish mfp filters = foldr (.) id filters'+ where+ filters' :: [Lines -> Lines]+ filters' = map (runStylish mfp) filters+++--------------------------------------------------------------------------------+main :: IO ()+main = do+ filePath <- listToMaybe <$> getArgs+ contents <- maybe getContents readFile filePath+ putStr $ unlines $ chainStylish filePath filters $ lines contents+ where+ filters =+ [ StylishHaskell.Imports.stylish+ , StylishHaskell.LanguagePragmas.stylish+ , StylishHaskell.Tabs.stylish+ , StylishHaskell.TrailingWhitespace.stylish+ ]
+ src/StylishHaskell/Block.hs view
@@ -0,0 +1,60 @@+--------------------------------------------------------------------------------+module StylishHaskell.Block+ ( Block (..)+ , blockLength+ , fromSrcSpanInfo+ , moveBlock+ , adjacent+ , merge+ , overlapping+ ) where+++--------------------------------------------------------------------------------+import Control.Arrow (arr, (&&&), (>>>))+import qualified Language.Haskell.Exts.Annotated as H+++--------------------------------------------------------------------------------+-- | Indicates a line span+data Block = Block+ { blockStart :: Int+ , blockEnd :: Int+ } deriving (Eq, Ord, Show)+++--------------------------------------------------------------------------------+blockLength :: Block -> Int+blockLength (Block start end) = end - start + 1+++--------------------------------------------------------------------------------+fromSrcSpanInfo :: H.SrcSpanInfo -> Block+fromSrcSpanInfo = H.srcInfoSpan >>>+ H.srcSpanStartLine &&& H.srcSpanEndLine >>>+ arr (uncurry Block)+++--------------------------------------------------------------------------------+moveBlock :: Int -> Block -> Block+moveBlock offset (Block start end) = Block (start + offset) (end + offset)+++--------------------------------------------------------------------------------+adjacent :: Block -> Block -> Bool+adjacent b1 b2 = follows b1 b2 || follows b2 b1+ where+ follows (Block _ e1) (Block s2 _) = e1 + 1 == s2+++--------------------------------------------------------------------------------+merge :: Block -> Block -> Block+merge (Block s1 e1) (Block s2 e2) = Block (min s1 s2) (max e1 e2)+++--------------------------------------------------------------------------------+overlapping :: [Block] -> Bool+overlapping blocks =+ any (uncurry overlapping') $ zip blocks (drop 1 blocks)+ where+ overlapping' (Block _ e1) (Block s2 _) = e1 >= s2
+ src/StylishHaskell/Editor.hs view
@@ -0,0 +1,105 @@+--------------------------------------------------------------------------------+-- | This module provides you with a line-based editor. It's main feature is+-- that you can specify multiple changes at the same time, e.g.:+--+-- > [deleteLine 3, changeLine 4 ["Foo"]]+--+-- when this is evaluated, we take into account that 4th line will become the+-- 3rd line before it needs changing.+module StylishHaskell.Editor+ ( Change+ , applyChanges++ , change+ , changeLine+ , delete+ , deleteLine+ , insert+ ) where+++--------------------------------------------------------------------------------+import StylishHaskell.Block+import StylishHaskell.Stylish+++--------------------------------------------------------------------------------+-- | Changes the lines indicated by the 'Block' into the given 'Lines'+data Change = Change+ { changeBlock :: Block+ , changeLines :: Lines+ } deriving (Eq, Show)+++--------------------------------------------------------------------------------+moveChange :: Int -> Change -> Change+moveChange offset (Change block ls) = Change (moveBlock offset block) ls+++--------------------------------------------------------------------------------+-- | Number of additional lines introduced when a change is made.+changeExtraLines :: Change -> Int+changeExtraLines (Change block ls) = length ls - blockLength block+++--------------------------------------------------------------------------------+applyChanges :: [Change] -> Lines -> Lines+applyChanges changes+ | overlapping blocks = error $+ "StylishHaskell.Editor.applyChanges: " +++ "refusing to make overlapping changes"+ | otherwise = go 1 changes+ where+ blocks = map changeBlock changes++ go _ [] ls = ls+ go n (ch : chs) ls =+ -- Divide the remaining lines into:+ --+ -- > pre+ -- > old (lines that are affected by the change)+ -- > post+ --+ -- And generate:+ --+ -- > pre+ -- > new+ -- > (recurse)+ --+ let block = changeBlock ch+ (pre, ls') = splitAt (blockStart block - n) ls+ (_, post) = splitAt (blockLength block) ls'+ extraLines = changeExtraLines ch+ chs' = map (moveChange extraLines) chs+ n' = blockStart block + blockLength block + extraLines+ in pre ++ (changeLines ch) ++ go n' chs' post+++--------------------------------------------------------------------------------+-- | Change a block of lines for some other lines+change :: Block -> Lines -> Change+change = Change+++--------------------------------------------------------------------------------+-- | Change a single line for some other lines+changeLine :: Int -> Lines -> Change+changeLine start = change (Block start start)+++--------------------------------------------------------------------------------+-- | Delete a block of lines+delete :: Block -> Change+delete block = Change block []+++--------------------------------------------------------------------------------+-- | Delete a single line+deleteLine :: Int -> Change+deleteLine start = delete (Block start start)+++--------------------------------------------------------------------------------+-- | Insert something /before/ the given lines+insert :: Int -> Lines -> Change+insert start = Change (Block start (start - 1))
+ src/StylishHaskell/Imports.hs view
@@ -0,0 +1,110 @@+--------------------------------------------------------------------------------+module StylishHaskell.Imports+ ( stylish+ ) where+++--------------------------------------------------------------------------------+import Control.Arrow ((&&&))+import Data.Char (isAlpha)+import Data.List (sortBy)+import Data.Maybe (isJust, maybeToList)+import Data.Ord (comparing)+import qualified Language.Haskell.Exts.Annotated as H+++--------------------------------------------------------------------------------+import StylishHaskell.Block+import StylishHaskell.Editor+import StylishHaskell.Stylish+import StylishHaskell.Util+++--------------------------------------------------------------------------------+imports :: H.Module l -> [H.ImportDecl l]+imports (H.Module _ _ _ is _) = is+imports _ = []+++--------------------------------------------------------------------------------+importName :: H.ImportDecl l -> String+importName i = let (H.ModuleName _ n) = H.importModule i in n+++--------------------------------------------------------------------------------+longestImport :: [H.ImportDecl l] -> Int+longestImport = maximum . map (length . importName)+++--------------------------------------------------------------------------------+-- | Groups adjacent imports into larger import blocks+groupAdjacent :: [H.ImportDecl Block] -> [(Block, [H.ImportDecl Block])]+groupAdjacent = foldr step []+ where+ -- This code is ugly and not optimal, and no fucks were given.+ step imp is = case break (adjacent b1 . fst) is of+ (_, []) -> (b1, [imp]) : is+ (xs, ((b2, imps) : ys)) -> (merge b1 b2, imp : imps) : (xs ++ ys)+ where+ b1 = H.ann imp+++--------------------------------------------------------------------------------+-- | Compare imports for ordering+compareImports :: H.ImportDecl l -> H.ImportDecl l -> Ordering+compareImports = comparing (importName &&& H.importQualified)+++--------------------------------------------------------------------------------+-- | The implementation is a bit hacky to get proper sorting for input specs:+-- constructors first, followed by functions, and then operators.+compareImportSpecs :: H.ImportSpec l -> H.ImportSpec l -> Ordering+compareImportSpecs = comparing key+ where+ key :: H.ImportSpec l -> (Int, Int, String)+ key (H.IVar _ x) = let n = nameToString x in (1, operator n, n)+ key (H.IAbs _ x) = (0, 0, nameToString x)+ key (H.IThingAll _ x) = (0, 0, nameToString x)+ key (H.IThingWith _ x _) = (0, 0, nameToString x)++ operator [] = 0 -- But this should not happen+ operator (x : _) = if isAlpha x then 0 else 1+++--------------------------------------------------------------------------------+-- | Sort the input spec list inside an 'H.ImportDecl'+sortImportSpecs :: H.ImportDecl l -> H.ImportDecl l+sortImportSpecs imp = imp {H.importSpecs = fmap sort $ H.importSpecs imp}+ where+ sort (H.ImportSpecList l h specs) = H.ImportSpecList l h $+ sortBy compareImportSpecs specs+++--------------------------------------------------------------------------------+prettyImport :: Int -> H.ImportDecl l -> String+prettyImport longest imp = unwords $ concat+ [ ["import"]+ , [if H.importQualified imp then "qualified" else " "]+ , [(if hasExtras then padRight longest else id) (importName imp)]+ , ["as " ++ as | H.ModuleName _ as <- maybeToList $ H.importAs imp]+ , [H.prettyPrint specs | specs <- maybeToList $ H.importSpecs imp]+ ]+ where+ hasExtras = isJust (H.importAs imp) || isJust (H.importSpecs imp)+++--------------------------------------------------------------------------------+prettyImportGroup :: Int -> [H.ImportDecl Block] -> Lines+prettyImportGroup longest = map (prettyImport longest) . sortBy compareImports+++--------------------------------------------------------------------------------+stylish :: Stylish+stylish ls (module', _) = flip applyChanges ls+ [ change block (prettyImportGroup longest importGroup)+ | (block, importGroup) <- groups+ ]+ where+ imps = map sortImportSpecs $ imports $ fmap fromSrcSpanInfo module'+ longest = longestImport imps+ groups = groupAdjacent imps
+ src/StylishHaskell/LanguagePragmas.hs view
@@ -0,0 +1,53 @@+--------------------------------------------------------------------------------+module StylishHaskell.LanguagePragmas+ ( stylish+ ) where+++--------------------------------------------------------------------------------+import Data.List (nub, sort)+import qualified Language.Haskell.Exts.Annotated as H+++--------------------------------------------------------------------------------+import StylishHaskell.Block+import StylishHaskell.Editor+import StylishHaskell.Stylish+import StylishHaskell.Util+++--------------------------------------------------------------------------------+pragmas :: H.Module l -> [(l, [String])]+pragmas (H.Module _ _ ps _ _) =+ [(l, map nameToString names) | H.LanguagePragma l names <- ps]+pragmas _ = []+++--------------------------------------------------------------------------------+-- | The start of the first block+firstLocation :: [(Block, [String])] -> Int+firstLocation = minimum . map (blockStart . fst)+++--------------------------------------------------------------------------------+-- | TODO: multiple lines if longer than 80 columns+prettyPragmas :: [String] -> Lines+prettyPragmas pragmas' =+ [ "{-# LANGUAGE " ++ padRight longest pragma ++ " #-}"+ | pragma <- pragmas'+ ]+ where+ longest = maximum $ map length pragmas'+++--------------------------------------------------------------------------------+stylish :: Stylish+stylish ls (module', _)+ | null pragmas' = ls+ | otherwise = applyChanges changes ls+ where+ pragmas' = pragmas $ fmap fromSrcSpanInfo module'+ deletes = map (delete . fst) pragmas'+ uniques = nub $ sort $ concatMap snd pragmas'+ loc = firstLocation pragmas'+ changes = insert loc (prettyPragmas uniques) : deletes
+ src/StylishHaskell/Parse.hs view
@@ -0,0 +1,41 @@+--------------------------------------------------------------------------------+module StylishHaskell.Parse+ ( parseModule+ ) where+++--------------------------------------------------------------------------------+import Data.Maybe (fromMaybe)+import qualified Language.Haskell.Exts.Annotated as H+++--------------------------------------------------------------------------------+import StylishHaskell.Stylish+++--------------------------------------------------------------------------------+-- | Filter out lines which use CPP macros+unCpp :: String -> String+unCpp = unlines . map unCpp' . lines+ where+ unCpp' ('#' : _) = ""+ unCpp' xs = xs+++--------------------------------------------------------------------------------+-- | Abstraction over HSE's parsing+parseModule :: Maybe FilePath -> String -> Either String Module+parseModule mfp string =+ let fp = fromMaybe "<unknown>" mfp+ -- Determine the extensions used in the file, and update the parsing+ -- mode based upon those+ exts = fromMaybe [] $ H.readExtensions string+ mode = H.defaultParseMode+ {H.extensions = exts, H.fixities = Nothing}+ -- Special handling for CPP, haskell-src-exts can't deal with it+ string' = if H.CPP `elem` exts then unCpp string else string+ in case H.parseModuleWithComments mode string' of+ H.ParseOk md -> Right md+ err -> Left $+ "StylishHaskell.Parse.parseModule: could not parse " +++ fp ++ ": " ++ show err
+ src/StylishHaskell/Stylish.hs view
@@ -0,0 +1,23 @@+--------------------------------------------------------------------------------+module StylishHaskell.Stylish+ ( Lines+ , Module+ , Stylish+ ) where+++--------------------------------------------------------------------------------+import qualified Language.Haskell.Exts.Annotated as H+++--------------------------------------------------------------------------------+type Lines = [String]+++--------------------------------------------------------------------------------+-- | Concrete module type+type Module = (H.Module H.SrcSpanInfo, [H.Comment])+++--------------------------------------------------------------------------------+type Stylish = Lines -> Module -> Lines
+ src/StylishHaskell/Tabs.hs view
@@ -0,0 +1,21 @@+--------------------------------------------------------------------------------+module StylishHaskell.Tabs+ ( stylish+ ) where+++--------------------------------------------------------------------------------+import StylishHaskell.Stylish+++--------------------------------------------------------------------------------+removeTabs :: String -> String+removeTabs = concatMap removeTabs'+ where+ removeTabs' '\t' = " "+ removeTabs' x = [x]+++--------------------------------------------------------------------------------+stylish :: Stylish+stylish ls _ = map removeTabs ls
+ src/StylishHaskell/TrailingWhitespace.hs view
@@ -0,0 +1,22 @@+--------------------------------------------------------------------------------+module StylishHaskell.TrailingWhitespace+ ( stylish+ ) where+++--------------------------------------------------------------------------------+import Data.Char (isSpace)+++--------------------------------------------------------------------------------+import StylishHaskell.Stylish+++--------------------------------------------------------------------------------+dropTrailingWhitespace :: String -> String+dropTrailingWhitespace = reverse . dropWhile isSpace . reverse+++--------------------------------------------------------------------------------+stylish :: Stylish+stylish ls _ = map dropTrailingWhitespace ls
+ src/StylishHaskell/Util.hs view
@@ -0,0 +1,21 @@+--------------------------------------------------------------------------------+module StylishHaskell.Util+ ( nameToString+ , padRight+ ) where+++--------------------------------------------------------------------------------+import qualified Language.Haskell.Exts.Annotated as H+++--------------------------------------------------------------------------------+-- | TODO: put this in utilities?+nameToString :: H.Name l -> String+nameToString (H.Ident _ str) = str+nameToString (H.Symbol _ str) = str+++--------------------------------------------------------------------------------+padRight :: Int -> String -> String+padRight len str = str ++ replicate (len - length str) ' '
+ stylish-haskell.cabal view
@@ -0,0 +1,64 @@+Name: stylish-haskell+Version: 0.1.0.0+Synopsis: Haskell code prettifier+Homepage: https://github.com/jaspervdj/stylish-haskell+License: BSD3+License-file: LICENSE+Author: Jasper Van der Jeugt <m@jaspervdj.be>+Maintainer: Jasper Van der Jeugt <m@jaspervdj.be>+Copyright: 2012 Jasper Van der Jeugt+Category: Language+Build-type: Simple+Cabal-version: >= 1.8++Description:+ A Haskell code prettifier. For more information, see:++ .++ <https://github.com/jaspervdj/stylish-haskell/blob/master/README.markdown>++Executable stylish-haskell+ Ghc-options: -Wall+ Hs-source-dirs: src+ Main-is: Main.hs++ Other-modules:+ StylishHaskell.Block+ StylishHaskell.Editor+ StylishHaskell.Imports+ StylishHaskell.LanguagePragmas+ StylishHaskell.Parse+ StylishHaskell.Stylish+ StylishHaskell.Tabs+ StylishHaskell.TrailingWhitespace+ StylishHaskell.Util++ Build-depends:+ base >= 4 && < 5,+ haskell-src-exts >= 1.13 && < 1.14++Test-suite stylish-haskell-tests+ Ghc-options: -Wall+ Hs-source-dirs: src tests+ Main-is: TestSuite.hs+ Type: exitcode-stdio-1.0++ Other-modules:+ StylishHaskell.Imports.Tests+ StylishHaskell.LanguagePragmas.Tests+ StylishHaskell.Tests.Util+ StylishHaskell.Tabs.Tests+ StylishHaskell.TrailingWhitespace.Tests++ Build-depends:+ HUnit >= 1.2 && < 1.3,+ test-framework >= 0.4 && < 0.7,+ test-framework-hunit >= 0.2 && < 0.3,+ -- Copied from regular dependencies...+ base >= 4 && < 5,+ haskell-src-exts >= 1.13 && < 1.14++Source-repository head+ Type: git+ Location: https://github.com/jaspervdj/stylish-haskell
+ tests/StylishHaskell/Imports/Tests.hs view
@@ -0,0 +1,51 @@+--------------------------------------------------------------------------------+module StylishHaskell.Imports.Tests+ ( tests+ ) where+++--------------------------------------------------------------------------------+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit ((@=?))+++--------------------------------------------------------------------------------+import StylishHaskell.Imports+import StylishHaskell.Tests.Util+++--------------------------------------------------------------------------------+tests :: Test+tests = testGroup "StylishHaskell.Imports.Tests"+ [ case01+ ]+++--------------------------------------------------------------------------------+case01 :: Test+case01 = testCase "case 01" $ expected @=? testStylish stylish input+ where+ input = unlines+ [ "module Herp where"+ , ""+ , "import qualified Data.Map as M"+ , "import Control.Monad"+ , "import Data.Map (lookup, (!), insert, Map)"+ , ""+ , "import Herp.Derp.Internals"+ , ""+ , "herp = putStrLn \"import Hello world\""+ ]++ expected = unlines+ [ "module Herp where"+ , ""+ , "import Control.Monad"+ , "import Data.Map (Map, insert, lookup, (!))"+ , "import qualified Data.Map as M"+ , ""+ , "import Herp.Derp.Internals"+ , ""+ , "herp = putStrLn \"import Hello world\""+ ]
+ tests/StylishHaskell/LanguagePragmas/Tests.hs view
@@ -0,0 +1,41 @@+--------------------------------------------------------------------------------+module StylishHaskell.LanguagePragmas.Tests+ ( tests+ ) where+++--------------------------------------------------------------------------------+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit ((@=?))+++--------------------------------------------------------------------------------+import StylishHaskell.LanguagePragmas+import StylishHaskell.Tests.Util+++--------------------------------------------------------------------------------+tests :: Test+tests = testGroup "StylishHaskell.LanguagePragmas.Tests"+ [ case01+ ]+++--------------------------------------------------------------------------------+case01 :: Test+case01 = testCase "case 01" $ expected @=? testStylish stylish input+ where+ input = unlines+ [ "{-# LANGUAGE ViewPatterns #-}"+ , "{-# LANGUAGE TemplateHaskell, ViewPatterns #-}"+ , "{-# LANGUAGE ScopedTypeVariables #-}"+ , "module Main where"+ ]++ expected = unlines+ [ "{-# LANGUAGE ScopedTypeVariables #-}"+ , "{-# LANGUAGE TemplateHaskell #-}"+ , "{-# LANGUAGE ViewPatterns #-}"+ , "module Main where"+ ]
+ tests/StylishHaskell/Tabs/Tests.hs view
@@ -0,0 +1,42 @@+--------------------------------------------------------------------------------+module StylishHaskell.Tabs.Tests+ ( tests+ ) where+++--------------------------------------------------------------------------------+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit ((@=?))+++--------------------------------------------------------------------------------+import StylishHaskell.Tabs+import StylishHaskell.Tests.Util+++--------------------------------------------------------------------------------+tests :: Test+tests = testGroup "StylishHaskell.Tabs.Tests" [case01]+++--------------------------------------------------------------------------------+case01 :: Test+case01 = testCase "case 01" $ expected @=? testStylish stylish input+ where+ input = unlines+ [ "module Main"+ , "\t\twhere"+ , "data Foo"+ , "\t= Bar"+ , " | Qux"+ ]++ expected = unlines+ [ "module Main"+ , " where"+ , "data Foo"+ , " = Bar"+ , " | Qux"+ ]+
+ tests/StylishHaskell/Tests/Util.hs view
@@ -0,0 +1,17 @@+module StylishHaskell.Tests.Util+ ( testStylish+ ) where+++--------------------------------------------------------------------------------+import StylishHaskell.Parse+import StylishHaskell.Stylish+++--------------------------------------------------------------------------------+testStylish :: Stylish -> String -> String+testStylish stylish str = case parseModule Nothing str of+ Left err -> error err+ Right module' -> unlines $ stylish ls module'+ where+ ls = lines str
+ tests/StylishHaskell/TrailingWhitespace/Tests.hs view
@@ -0,0 +1,37 @@+--------------------------------------------------------------------------------+module StylishHaskell.TrailingWhitespace.Tests+ ( tests+ ) where+++--------------------------------------------------------------------------------+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit ((@=?))+++--------------------------------------------------------------------------------+import StylishHaskell.TrailingWhitespace+import StylishHaskell.Tests.Util+++--------------------------------------------------------------------------------+tests :: Test+tests = testGroup "StylishHaskell.TrailingWhitespace.Tests" [case01]+++--------------------------------------------------------------------------------+case01 :: Test+case01 = testCase "case 01" $ expected @=? testStylish stylish input+ where+ input = unlines+ [ "module Main where"+ , " "+ , "data Foo = Bar | Qux\t "+ ]++ expected = unlines+ [ "module Main where"+ , ""+ , "data Foo = Bar | Qux"+ ]
+ tests/TestSuite.hs view
@@ -0,0 +1,25 @@+--------------------------------------------------------------------------------+module Main+ ( main+ ) where+++--------------------------------------------------------------------------------+import Test.Framework (defaultMain)+++--------------------------------------------------------------------------------+import qualified StylishHaskell.Imports.Tests+import qualified StylishHaskell.LanguagePragmas.Tests+import qualified StylishHaskell.Tabs.Tests+import qualified StylishHaskell.TrailingWhitespace.Tests+++--------------------------------------------------------------------------------+main :: IO ()+main = defaultMain+ [ StylishHaskell.Imports.Tests.tests+ , StylishHaskell.LanguagePragmas.Tests.tests+ , StylishHaskell.Tabs.Tests.tests+ , StylishHaskell.TrailingWhitespace.Tests.tests+ ]