\begin{code} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE FlexibleContexts #-} module Text.RE.Tools.Grep ( grep , grepLines , GrepScript , grepScript ) where import Control.Applicative import qualified Data.ByteString.Lazy.Char8 as LBS import Text.Printf import Text.RE.Capture import Text.RE.IsRegex import Text.RE.LineNo data Line = Line { _ln_no :: LineNo , _ln_matches :: 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 . lines_matched where fmt Line{..} = printf "%05d %s" (getLineNo _ln_no) $ LBS.unpack $ matchesSource _ln_matches lines_matched :: [Line] -> [Line] lines_matched = filter $ anyMatches . _ln_matches \end{code}