packages feed

chiasma-0.2.0.0: lib/Chiasma/Native/StreamParse.hs

module Chiasma.Native.StreamParse(
  parseConduit,
  parseBlocks,
  TmuxOutputBlock(..),
) where

import Conduit (ConduitT, mapC, (.|))
import Control.Monad.Catch (MonadThrow)
import Data.Attoparsec.ByteString (Parser)
import Data.Conduit.Attoparsec (conduitParser)
import qualified Data.Text as T (pack)
import Text.Parser.Char (CharParsing, anyChar, newline, string)
import Text.Parser.Combinators (choice, manyTill, notFollowedBy, skipMany, try)
import Text.Parser.LookAhead (LookAheadParsing, lookAhead)

data End =
  EndSuccess
  |
  EndError
  deriving (Eq, Show)

data TmuxOutputBlock =
  Success [Text]
  |
  Error [Text]
  deriving (Eq, Show)

tillEol :: (Alternative m, CharParsing m) => m Text
tillEol = T.pack <$> manyTill anyChar newline

beginLine :: (Alternative m, CharParsing m, Monad m) => m ()
beginLine = void $ string "%begin" >> tillEol

endLine :: (Alternative m, CharParsing m) => m End
endLine = do
  end <- choice [EndSuccess <$ string "%end", EndError <$ string "%error"]
  _ <- tillEol
  return end

notBeginLine :: (Alternative m, CharParsing m, Monad m) => m ()
notBeginLine = void $ notFollowedBy (string "%begin") >> tillEol

-- |Parse a sequence of lines between a %start and a %end line.
-- Tmux pads output lines with a single space on both sides, so strip those if the leading one is present.
parseBlock :: (Alternative m, CharParsing m, Monad m, LookAheadParsing m) => m TmuxOutputBlock
parseBlock = do
  _ <- skipMany notBeginLine
  _ <- beginLine
  dataLines <- manyTill tillEol $ try $ lookAhead endLine
  end <- endLine
  return $ case end of
    EndSuccess -> Success dataLines
    EndError -> Error dataLines

parseBlocks :: (Alternative m, CharParsing m, Monad m, LookAheadParsing m) => m [TmuxOutputBlock]
parseBlocks = do
  result <- many (try parseBlock)
  skipMany tillEol
  return result

parser :: Parser TmuxOutputBlock
parser = parseBlock

parseConduit :: MonadThrow m => ConduitT ByteString TmuxOutputBlock m ()
parseConduit = conduitParser parser .| mapC snd