#! /usr/bin/env runhaskell
{-# LANGUAGE LambdaCase #-}
import System.Directory (doesFileExist, getDirectoryContents)
import System.FilePath ((</>))
import Data.String.Utils
import Data.List
mapSnd :: (a -> b) -> [(c, a)] -> [(c, b)]
mapSnd f xys = map ( \case (x, y) -> (x, f y) ) xys
mapDir :: (FilePath -> IO ()) -> FilePath -> IO ()
mapDir proc fp = do
isFile <- doesFileExist fp
if isFile then proc fp
else getDirectoryContents fp >>=
mapM_ (mapDir proc . (fp </>)) . filter (`notElem` [".", ".."])
printTitle :: String -> IO()
printTitle title = do
putStrLn ""
putStrLn title
putStrLn $ map (\_ -> '=') title
main :: IO ()
main = do
printTitle "libKActivities"
mapDir process "src/lib/core"
printTitle "libKActivitiesStats"
mapDir process "src/lib/stats"
printTitle "KActivityManagerD"
mapDir process "src/service"
printTitle "QML imports"
mapDir process "src/imports"
printTitle "Workspace plugins"
mapDir process "src/workspace"
printTitle "Other"
mapDir process "src/common"
mapDir process "src/utils"
extractBlock :: [String] -> [String]
extractBlock =
takeWhile (startswith "//")
isTodoBlock :: (Integer, [String]) -> Bool
isTodoBlock (_, block) =
(not $ null block) && (
(startswith "// TODO: " $ head block) ||
(startswith "// FIXME: " $ head block) ||
(startswith "// NOTE: " $ head block)
)
joinBlock :: [String] -> String
joinBlock block =
unlines $
map ( \line ->
( dropWhile (== '/') line )
) $
block
process :: FilePath -> IO ()
process filename = do
content <- readFile filename
let items :: [(Integer, [String])]
items =
zip [1..] $
tails $
map strip $
lines content
let todoBlocks :: [(Integer, [String])]
todoBlocks =
mapSnd extractBlock $
filter isTodoBlock $
items
let todoItems :: [(Integer, String)]
todoItems =
mapSnd joinBlock todoBlocks
if (not $ null todoItems)
then
putStrLn $
concat $
map (\case (lineNo, todoItem) ->
filename ++ ":" ++ (show lineNo) ++ ":\n" ++ todoItem
) todoItems
else
return ()