packages feed

pgrep-0.1.0.0: src/Scrappy/Grep/Output.hs

module Scrappy.Grep.Output
  ( formatResult
  , formatResults
  , OutputFormat(..)
  ) where

import Scrappy.Grep.DSL (MatchResult(..))
import Data.List (intercalate)

data OutputFormat
  = FormatGrep      -- file:line:col:match
  | FormatVerbose   -- file:line:col: match (with context)
  | FormatJSON      -- JSON output
  | FormatCount     -- Just count of matches
  deriving (Show, Eq)

-- | Format a single match result
formatResult :: OutputFormat -> MatchResult -> String
formatResult fmt mr = case fmt of
  FormatGrep ->
    mrFilePath mr ++ ":" ++
    show (mrLine mr) ++ ":" ++
    show (mrCol mr) ++ ":" ++
    escapeNewlines (mrMatchText mr)

  FormatVerbose ->
    mrFilePath mr ++ ":" ++
    show (mrLine mr) ++ ":" ++
    show (mrCol mr) ++ ": " ++
    mrMatchText mr

  FormatJSON ->
    "{\"file\":\"" ++ escapeJSON (mrFilePath mr) ++
    "\",\"line\":" ++ show (mrLine mr) ++
    ",\"col\":" ++ show (mrCol mr) ++
    ",\"match\":\"" ++ escapeJSON (mrMatchText mr) ++ "\"}"

  FormatCount -> ""

-- | Format multiple results
formatResults :: OutputFormat -> [MatchResult] -> String
formatResults FormatCount results =
  show (length results) ++ " match" ++ (if length results == 1 then "" else "es")
formatResults FormatJSON results =
  "[" ++ intercalate "," (map (formatResult FormatJSON) results) ++ "]"
formatResults fmt results =
  unlines $ map (formatResult fmt) results

-- | Escape newlines for single-line output
escapeNewlines :: String -> String
escapeNewlines = concatMap escape
  where
    escape '\n' = "\\n"
    escape '\t' = "\\t"
    escape '\r' = "\\r"
    escape c = [c]

-- | Escape for JSON strings
escapeJSON :: String -> String
escapeJSON = concatMap escape
  where
    escape '"' = "\\\""
    escape '\\' = "\\\\"
    escape '\n' = "\\n"
    escape '\t' = "\\t"
    escape '\r' = "\\r"
    escape c = [c]