Skip to content

Commit ab85690

Browse files
authored
Add -r flag to recursively find Haskell files
1 parent 41dcda2 commit ab85690

File tree

3 files changed

+109
-10
lines changed

3 files changed

+109
-10
lines changed

lib/Language/Haskell/Stylish.hs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE LambdaCase #-}
12
--------------------------------------------------------------------------------
23
module Language.Haskell.Stylish
34
( -- * Run
@@ -10,6 +11,7 @@ module Language.Haskell.Stylish
1011
, trailingWhitespace
1112
, unicodeSyntax
1213
-- ** Helpers
14+
, findHaskellFiles
1315
, stepName
1416
-- * Config
1517
, module Language.Haskell.Stylish.Config
@@ -25,7 +27,11 @@ module Language.Haskell.Stylish
2527

2628
--------------------------------------------------------------------------------
2729
import Control.Monad (foldM)
28-
30+
import System.Directory (doesDirectoryExist,
31+
doesFileExist,
32+
listDirectory)
33+
import System.FilePath (takeExtension,
34+
(</>))
2935

3036
--------------------------------------------------------------------------------
3137
import Language.Haskell.Stylish.Config
@@ -103,3 +109,37 @@ format :: Maybe ConfigPath -> Maybe FilePath -> String -> IO (Either String Line
103109
format maybeConfigPath maybeFilePath contents = do
104110
conf <- loadConfig (makeVerbose True) (fmap unConfigPath maybeConfigPath)
105111
pure $ runSteps (configLanguageExtensions conf) maybeFilePath (configSteps conf) $ lines contents
112+
113+
114+
--------------------------------------------------------------------------------
115+
-- | Searches Haskell source files in any given folder recursively.
116+
findHaskellFiles :: Bool -> [FilePath] -> IO [FilePath]
117+
findHaskellFiles v fs = mapM (findFilesR v) fs >>= return . concat
118+
119+
120+
--------------------------------------------------------------------------------
121+
findFilesR :: Bool -> FilePath -> IO [FilePath]
122+
findFilesR _ [] = return []
123+
findFilesR v path = do
124+
doesFileExist path >>= \case
125+
True -> return [path]
126+
_ -> doesDirectoryExist path >>= \case
127+
True -> findFilesRecursive path >>=
128+
return . filter (\x -> takeExtension x == ".hs")
129+
False -> do
130+
makeVerbose v ("Input folder does not exists: " <> path)
131+
findFilesR v []
132+
where
133+
findFilesRecursive :: FilePath -> IO [FilePath]
134+
findFilesRecursive = listDirectoryFiles findFilesRecursive
135+
136+
listDirectoryFiles :: (FilePath -> IO [FilePath])
137+
-> FilePath -> IO [FilePath]
138+
listDirectoryFiles go topdir = do
139+
ps <- listDirectory topdir >>=
140+
mapM (\x -> do
141+
let dir = topdir </> x
142+
doesDirectoryExist dir >>= \case
143+
True -> go dir
144+
False -> return [dir])
145+
return $ concat ps

src/Main.hs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ import Language.Haskell.Stylish
2121

2222
--------------------------------------------------------------------------------
2323
data StylishArgs = StylishArgs
24-
{ saVersion :: Bool
25-
, saConfig :: Maybe FilePath
26-
, saVerbose :: Bool
27-
, saDefaults :: Bool
28-
, saInPlace :: Bool
29-
, saNoUtf8 :: Bool
30-
, saFiles :: [FilePath]
24+
{ saVersion :: Bool
25+
, saConfig :: Maybe FilePath
26+
, saRecursive :: Bool
27+
, saVerbose :: Bool
28+
, saDefaults :: Bool
29+
, saInPlace :: Bool
30+
, saNoUtf8 :: Bool
31+
, saFiles :: [FilePath]
3132
} deriving (Show)
3233

3334

@@ -44,6 +45,11 @@ parseStylishArgs = StylishArgs
4445
OA.long "config" <>
4546
OA.short 'c' <>
4647
OA.hidden)
48+
<*> OA.switch (
49+
OA.help "Recursive file search" <>
50+
OA.long "recursive" <>
51+
OA.short 'r' <>
52+
OA.hidden)
4753
<*> OA.switch (
4854
OA.help "Run in verbose mode" <>
4955
OA.long "verbose" <>
@@ -99,14 +105,20 @@ stylishHaskell sa = do
99105

100106
else do
101107
conf <- loadConfig verbose' (saConfig sa)
108+
filesR <- case (saRecursive sa) of
109+
True -> findHaskellFiles (saVerbose sa) (saFiles sa)
110+
_ -> return $ saFiles sa
102111
let steps = configSteps conf
103112
forM_ steps $ \s -> verbose' $ "Enabled " ++ stepName s ++ " step"
104113
verbose' $ "Extra language extensions: " ++
105114
show (configLanguageExtensions conf)
106-
mapM_ (file sa conf) files'
115+
mapM_ (file sa conf) $ files' filesR
107116
where
108117
verbose' = makeVerbose (saVerbose sa)
109-
files' = if null (saFiles sa) then [Nothing] else map Just (saFiles sa)
118+
files' x = case (saRecursive sa, null x) of
119+
(True,True) -> [] -- No file to format and recursive enabled.
120+
(_,True) -> [Nothing] -- Involving IO.stdin.
121+
(_,False) -> map Just x -- Process available files.
110122

111123

112124
--------------------------------------------------------------------------------

tests/Language/Haskell/Stylish/Tests.hs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ module Language.Haskell.Stylish.Tests
55

66

77
--------------------------------------------------------------------------------
8+
import Data.List (sort)
9+
import System.Directory (createDirectory)
10+
import System.FilePath (normalise, (</>))
811
import Test.Framework (Test, testGroup)
912
import Test.Framework.Providers.HUnit (testCase)
1013
import Test.HUnit (Assertion, (@?=))
@@ -21,6 +24,9 @@ tests = testGroup "Language.Haskell.Stylish.Step.Tabs.Tests"
2124
[ testCase "case 01" case01
2225
, testCase "case 02" case02
2326
, testCase "case 03" case03
27+
, testCase "case 04" case04
28+
, testCase "case 05" case05
29+
, testCase "case 06" case06
2430
]
2531

2632

@@ -68,3 +74,44 @@ case03 = (@?= result) =<< format Nothing (Just fileLocation) input
6874
"Language.Haskell.Stylish.Parse.parseModule: could not parse " <>
6975
fileLocation <>
7076
": ParseFailed (SrcLoc \"<unknown>.hs\" 2 1) \"Parse error: EOF\""
77+
78+
79+
--------------------------------------------------------------------------------
80+
-- | When providing current dir including folders and files.
81+
case04 :: Assertion
82+
case04 = withTestDirTree $ do
83+
createDirectory aDir >> writeFile c fileCont
84+
mapM_ (flip writeFile fileCont) fs
85+
result <- findHaskellFiles False input
86+
sort result @?= (sort $ map normalise expected)
87+
where
88+
input = c : fs
89+
fs = ["b.hs", "a.hs"]
90+
c = aDir </> "c.hs"
91+
aDir = "aDir"
92+
expected = ["a.hs", "b.hs", c]
93+
fileCont = ""
94+
95+
96+
--------------------------------------------------------------------------------
97+
-- | When the input item is not file, do not recurse it.
98+
case05 :: Assertion
99+
case05 = withTestDirTree $ do
100+
mapM_ (flip writeFile "") input
101+
result <- findHaskellFiles False input
102+
result @?= expected
103+
where
104+
input = ["b.hs"]
105+
expected = map normalise input
106+
107+
108+
--------------------------------------------------------------------------------
109+
-- | Empty input should result in empty output.
110+
case06 :: Assertion
111+
case06 = withTestDirTree $ do
112+
mapM_ (flip writeFile "") input
113+
result <- findHaskellFiles False input
114+
result @?= expected
115+
where
116+
input = []
117+
expected = input

0 commit comments

Comments
 (0)