vgrep-0.1.3.0: src/Vgrep/Parser.hs
module Vgrep.Parser (
-- * Parsing @grep@ output
parseGrepOutput
, parseLine
-- ** Re-export
, FileLineReference
) where
import Control.Applicative
import Data.Attoparsec.Text.Lazy
import Data.Maybe
import Data.Text.Lazy
import Vgrep.Results
-- | Parses lines of 'Text', skipping lines that are not valid @grep@
-- output.
parseGrepOutput :: [Text] -> [FileLineReference]
parseGrepOutput = catMaybes . fmap parseLine
-- | Parses a line of @grep@ output. Returns 'Nothing' if the line cannot
-- be parsed.
--
-- The output should consist of a file name, line number and the content,
-- separated by colons:
--
-- >>> parseLine "path/to/file:123:foobar"
-- Just (FileLineReference {getFile = File {getFileName = "path/to/file"}, getLineReference = LineReference {getLineNumber = Just 123, getLineText = "foobar"}})
--
-- Omitting the line number still produces valid output:
--
-- >>> parseLine "path/to/file:foobar"
-- Just (FileLineReference {getFile = File {getFileName = "path/to/file"}, getLineReference = LineReference {getLineNumber = Nothing, getLineText = "foobar"}})
--
-- However, an file name must be present:
--
-- >>> parseLine "foobar"
-- Nothing
parseLine :: Text -> Maybe FileLineReference
parseLine line = maybeResult (parse lineParser line)
lineParser :: Parser FileLineReference
lineParser = do
file <- manyTill anyChar (char ':')
lineNumber <- optional (decimal <* char ':')
result <- takeLazyText
pure FileLineReference
{ getFile = File
{ getFileName = pack file }
, getLineReference = LineReference
{ getLineNumber = lineNumber
, getLineText = result } }