\begin{code}
module Text.RE.Tools.Grep
( Line(..)
, grep
, grepLines
, GrepScript
, grepScript
, linesMatched
) where
import qualified Data.ByteString.Lazy.Char8 as LBS
import Prelude.Compat
import Text.Printf
import Text.RE.Capture
import Text.RE.IsRegex
import Text.RE.LineNo
data Line =
Line
{ getLineNumber :: LineNo
, getLineMatches :: Matches LBS.ByteString
}
deriving (Show)
grep :: IsRegex re LBS.ByteString => re -> FilePath -> IO ()
grep rex fp = grepLines rex fp >>= putStr . report
grepLines :: IsRegex re LBS.ByteString => re -> FilePath -> IO [Line]
grepLines rex fp =
grepScript [(rex,mk)] . LBS.lines <$> LBS.readFile fp
where
mk i mtchs = Just $ Line i mtchs
type GrepScript re s t = [(re,LineNo -> Matches s -> Maybe t)]
grepScript :: IsRegex re s => GrepScript re s t -> [s] -> [t]
grepScript scr = loop firstLine
where
loop _ [] = []
loop i (ln:lns) = seq i $ choose i ln lns scr
choose i _ lns [] = loop (succ i) lns
choose i ln lns ((rex,f):scr') = case f i $ matchMany rex ln of
Nothing -> choose i ln lns scr'
Just t -> t : loop (succ i) lns
report :: [Line] -> String
report = unlines . map fmt . linesMatched
where
fmt Line{..} =
printf "%05d %s" (getLineNo getLineNumber) $
LBS.unpack $ matchesSource getLineMatches
linesMatched :: [Line] -> [Line]
linesMatched = filter $ anyMatches . getLineMatches
\end{code}