packages feed

comparse-0.2.0.0: Data/Stream/StringLines.hs

{-# LANGUAGE TypeFamilies #-}

module Data.Stream.StringLines
  ( StringPos (..),
    StringLines (..),
    fromString,
  )
where

import Data.Stream (Stream (..))

data StringPos = StringPos Int Int String

instance Show StringPos where
  show (StringPos l c ls) =
    lnum ++ ":" ++ cnum ++ ":\n" ++ snippet
    where
      lnum = show (l + 1)
      cnum = show (c + 1)
      gut = replicate (length lnum) ' ' ++ " | "
      ngut = lnum ++ " | "
      snippet = gut ++ "\n" ++ ngut ++ ls ++ "\n" ++ gut ++ cursor
      cursor = replicate c ' ' ++ "^"

instance Eq StringPos where
  (StringPos l1 c1 _) == (StringPos l2 c2 _) = l1 == l2 && c1 == c2

instance Ord StringPos where
  compare (StringPos l1 c1 _) (StringPos l2 c2 _) =
    case compare l1 l2 of
      EQ -> compare c1 c2
      x -> x

start :: String -> StringPos
start s = StringPos 0 0 $ takeWhile (/= '\n') s

adv :: StringPos -> StringPos
adv (StringPos l c s) = StringPos l (c + 1) s

nextl :: StringPos -> String -> StringPos
nextl (StringPos l _ _) s = StringPos (l + 1) 0 (takeWhile (/= '\n') s)

data StringLines = StringLines String StringPos deriving (Eq, Show)

instance Stream StringLines where
  type Item StringLines = Char
  type Pos StringLines = StringPos

  next (StringLines [] _) = Nothing
  next (StringLines ('\n' : xs) p) = Just ('\n', StringLines xs (nextl p xs))
  next (StringLines (x : xs) p) = Just (x, StringLines xs (adv p))

  getPos (StringLines _ p) = p

fromString :: String -> StringLines
fromString s = StringLines s (start s)