    module System.Console.Haskeline.Term where

    import System.Console.Haskeline.Monads
    import System.Console.Haskeline.LineState
    import System.Console.Haskeline.Key
    import System.Console.Haskeline.Prefs(Prefs)
    import System.Console.Haskeline.Completion(Completion)

    import Control.Concurrent
    import Control.Concurrent.STM
    import Control.Exception (Exception, SomeException(..))
    import Control.Monad.Catch
        ( MonadMask
        , bracket
        , handle
        , throwM
        , finally
        )
    import Data.Word
    import Control.Exception (fromException, AsyncException(..))
    import Data.Typeable
    import System.IO
    import Control.Monad(liftM,when,guard)
    import System.IO.Error (isEOFError)
    import Data.ByteString (ByteString)
    import qualified Data.ByteString.Char8 as BC

    class (MonadReader Layout m, MonadIO m, MonadMask m) => Term m where
        reposition :: Layout -> LineChars -> m ()
        moveToNextLine :: LineChars -> m ()
        printLines :: [String] -> m ()
        drawLineDiff :: LineChars -> LineChars -> m ()
        clearLayout :: m ()
        ringBell :: Bool -> m ()

    drawLine, clearLine :: Term m => LineChars -> m ()
    drawLine :: forall (m :: * -> *). Term m => LineChars -> m ()
    drawLine = LineChars -> LineChars -> m ()
    forall (m :: * -> *). Term m => LineChars -> LineChars -> m ()
    drawLineDiff ([],[])

    clearLine :: forall (m :: * -> *). Term m => LineChars -> m ()
    clearLine = (LineChars -> LineChars -> m ()) -> LineChars -> LineChars -> m ()
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip LineChars -> LineChars -> m ()
    forall (m :: * -> *). Term m => LineChars -> LineChars -> m ()
    drawLineDiff ([],[])

    data RunTerm = RunTerm {
                -- | Write unicode characters to stdout.
                RunTerm -> String -> IO ()
    putStrOut :: String -> IO (),
                RunTerm -> Either TermOps FileOps
    termOps :: Either TermOps FileOps,
                RunTerm
    -> forall a (m :: * -> *). (MonadIO m, MonadMask m) => m a -> m a
    wrapInterrupt :: forall a m . (MonadIO m, MonadMask m) => m a -> m a,
                RunTerm -> IO ()
    closeTerm :: IO ()
        }

    -- | Operations needed for terminal-style interaction.
    data TermOps = TermOps
        { TermOps -> IO Layout
    getLayout :: IO Layout
        , TermOps
    -> forall (m :: * -> *) a.
       CommandMonad m =>
       (m Event -> m a) -> m a
    withGetEvent :: forall m a . CommandMonad m => (m Event -> m a) -> m a
        , TermOps -> forall (m :: * -> *). CommandMonad m => EvalTerm m
    evalTerm :: forall m . CommandMonad m => EvalTerm m
        , TermOps -> [Key] -> IO ()
    saveUnusedKeys :: [Key] -> IO ()
        , TermOps -> String -> IO ()
    externalPrint :: String -> IO ()
        }

    -- This hack is needed to grab latest writes from some other thread.
    -- Without it, if you are using another thread to process the logging
    -- and write on screen via exposed externalPrint, latest writes from
    -- this thread are not able to cross the thread boundary in time.
    flushEventQueue :: (String -> IO ()) -> TChan Event -> IO ()
    flushEventQueue :: (String -> IO ()) -> TChan Event -> IO ()
    flushEventQueue String -> IO ()
    print' TChan Event
    eventChan = IO ()
    yield IO () -> IO () -> IO ()
    forall a b. IO a -> IO b -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> IO ()
    loopUntilFlushed
        where loopUntilFlushed :: IO ()
    loopUntilFlushed = do
                  flushed <- STM Bool -> IO Bool
    forall a. STM a -> IO a
    atomically (STM Bool -> IO Bool) -> STM Bool -> IO Bool
    forall a b. (a -> b) -> a -> b
    $ TChan Event -> STM Bool
    forall a. TChan a -> STM Bool
    isEmptyTChan TChan Event
    eventChan
                  if flushed then return () else do
                      event <- atomically $ readTChan eventChan
                      case event of
                          ExternalPrint String
    str -> do
                              String -> IO ()
    print' (String
    str String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "\n") IO () -> IO () -> IO ()
    forall a b. IO a -> IO b -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> IO ()
    loopUntilFlushed
                          -- We don't want to raise exceptions when doing cleanup.
                          Event
    _ -> IO ()
    loopUntilFlushed

    -- | Operations needed for file-style interaction.
    --
    -- Backends can assume that getLocaleLine, getLocaleChar and maybeReadNewline
    -- are "wrapped" by wrapFileInput.
    data FileOps = FileOps {
                FileOps
    -> forall (m :: * -> *) a. (MonadIO m, MonadMask m) => m a -> m a
    withoutInputEcho :: forall m a . (MonadIO m, MonadMask m) => m a -> m a,
                -- ^ Perform an action without echoing input.
                FileOps -> forall a. IO a -> IO a
    wrapFileInput :: forall a . IO a -> IO a,
                FileOps -> MaybeT IO String
    getLocaleLine :: MaybeT IO String,
                FileOps -> MaybeT IO Char
    getLocaleChar :: MaybeT IO Char,
                FileOps -> IO ()
    maybeReadNewline :: IO ()
            }

    -- | Are we using terminal-style interaction?
    isTerminalStyle :: RunTerm -> Bool
    isTerminalStyle :: RunTerm -> Bool
    isTerminalStyle RunTerm
    r = case RunTerm -> Either TermOps FileOps
    termOps RunTerm
    r of
                        Left TermOps{} -> Bool
    True
                        Either TermOps FileOps
    _ -> Bool
    False

    -- Specific, hidden terminal action type
    -- Generic terminal actions which are independent of the Term being used.
    data EvalTerm m
        = forall n . (Term n, CommandMonad n)
                => EvalTerm (forall a . n a -> m a) (forall a . m a -> n a)

    mapEvalTerm :: (forall a . n a -> m a) -> (forall a . m a -> n a)
            -> EvalTerm n -> EvalTerm m
    mapEvalTerm :: forall (n :: * -> *) (m :: * -> *).
    (forall a. n a -> m a)
    -> (forall a. m a -> n a) -> EvalTerm n -> EvalTerm m
    mapEvalTerm forall a. n a -> m a
    eval forall a. m a -> n a
    liftE (EvalTerm forall a. n a -> n a
    eval' forall a. n a -> n a
    liftE')
        = (forall a. n a -> m a) -> (forall a. m a -> n a) -> EvalTerm m
    forall (m :: * -> *) (n :: * -> *).
    (Term n, CommandMonad n) =>
    (forall a. n a -> m a) -> (forall a. m a -> n a) -> EvalTerm m
    EvalTerm (n a -> m a
    forall a. n a -> m a
    eval (n a -> m a) -> (n a -> n a) -> n a -> m a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . n a -> n a
    forall a. n a -> n a
    eval') (n a -> n a
    forall a. n a -> n a
    liftE' (n a -> n a) -> (m a -> n a) -> m a -> n a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . m a -> n a
    forall a. m a -> n a
    liftE)

    data Interrupt = Interrupt
                    deriving (Int -> Interrupt -> String -> String
    [Interrupt] -> String -> String
    Interrupt -> String
    (Int -> Interrupt -> String -> String)
    -> (Interrupt -> String)
    -> ([Interrupt] -> String -> String)
    -> Show Interrupt
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> Interrupt -> String -> String
    showsPrec :: Int -> Interrupt -> String -> String
    $cshow :: Interrupt -> String
    show :: Interrupt -> String
    $cshowList :: [Interrupt] -> String -> String
    showList :: [Interrupt] -> String -> String
    Show,Typeable,Interrupt -> Interrupt -> Bool
    (Interrupt -> Interrupt -> Bool)
    -> (Interrupt -> Interrupt -> Bool) -> Eq Interrupt
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Interrupt -> Interrupt -> Bool
    == :: Interrupt -> Interrupt -> Bool
    $c/= :: Interrupt -> Interrupt -> Bool
    /= :: Interrupt -> Interrupt -> Bool
    Eq)

    instance Exception Interrupt where

    class (MonadReader Prefs m , MonadReader Layout m, MonadIO m, MonadMask m)
            => CommandMonad m where
        runCompletion :: (String,String) -> m (String,[Completion])

    instance {-# OVERLAPPABLE #-} (MonadTrans t, CommandMonad m, MonadReader Prefs (t m),
            MonadIO (t m), MonadMask (t m),
            MonadReader Layout (t m))
                => CommandMonad (t m) where
        runCompletion :: (String, String) -> t m (String, [Completion])
    runCompletion = m (String, [Completion]) -> t m (String, [Completion])
    forall (m :: * -> *) a. Monad m => m a -> t m a
    forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
    (MonadTrans t, Monad m) =>
    m a -> t m a
    lift (m (String, [Completion]) -> t m (String, [Completion]))
    -> ((String, String) -> m (String, [Completion]))
    -> (String, String)
    -> t m (String, [Completion])
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String, String) -> m (String, [Completion])
    forall (m :: * -> *).
    CommandMonad m =>
    (String, String) -> m (String, [Completion])
    runCompletion

    -- Utility function for drawLineDiff instances.
    matchInit :: Eq a => [a] -> [a] -> ([a],[a])
    matchInit :: forall a. Eq a => [a] -> [a] -> ([a], [a])
    matchInit (a
    x:[a]
    xs) (a
    y:[a]
    ys)  | a
    x a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == a
    y = [a] -> [a] -> ([a], [a])
    forall a. Eq a => [a] -> [a] -> ([a], [a])
    matchInit [a]
    xs [a]
    ys
    matchInit [a]
    xs [a]
    ys = ([a]
    xs,[a]
    ys)

    data Event
      = WindowResize
      | KeyInput [Key]
      | ErrorEvent SomeException
      | ExternalPrint String
      deriving Int -> Event -> String -> String
    [Event] -> String -> String
    Event -> String
    (Int -> Event -> String -> String)
    -> (Event -> String) -> ([Event] -> String -> String) -> Show Event
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> Event -> String -> String
    showsPrec :: Int -> Event -> String -> String
    $cshow :: Event -> String
    show :: Event -> String
    $cshowList :: [Event] -> String -> String
    showList :: [Event] -> String -> String
    Show

    keyEventLoop :: IO [Event] -> TChan Event -> IO Event
    keyEventLoop :: IO [Event] -> TChan Event -> IO Event
    keyEventLoop IO [Event]
    readEvents TChan Event
    eventChan = do
        -- first, see if any events are already queued up (from a key/ctrl-c
        -- event or from a previous call to getEvent where we read in multiple
        -- keys)
        isEmpty <- STM Bool -> IO Bool
    forall a. STM a -> IO a
    atomically (STM Bool -> IO Bool) -> STM Bool -> IO Bool
    forall a b. (a -> b) -> a -> b
    $ TChan Event -> STM Bool
    forall a. TChan a -> STM Bool
    isEmptyTChan TChan Event
    eventChan
        if not isEmpty
            then atomically $ readTChan eventChan
            else do
                tid <- forkIO $ handleErrorEvent readerLoop
                atomically (readTChan eventChan) `finally` killThread tid
      where
        readerLoop :: IO ()
    readerLoop = do
            es <- IO [Event]
    readEvents
            if null es
                then readerLoop
                else atomically $ mapM_ (writeTChan eventChan) es
        handleErrorEvent :: IO () -> IO ()
    handleErrorEvent = (SomeException -> IO ()) -> IO () -> IO ()
    forall (m :: * -> *) e a.
    (HasCallStack, MonadCatch m, Exception e) =>
    (e -> m a) -> m a -> m a
    handle ((SomeException -> IO ()) -> IO () -> IO ())
    -> (SomeException -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \SomeException
    e -> case SomeException -> Maybe AsyncException
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    e of
                                    Just AsyncException
    ThreadKilled -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
                                    Maybe AsyncException
    _ -> STM () -> IO ()
    forall a. STM a -> IO a
    atomically (STM () -> IO ()) -> STM () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ TChan Event -> Event -> STM ()
    forall a. TChan a -> a -> STM ()
    writeTChan TChan Event
    eventChan (SomeException -> Event
    ErrorEvent SomeException
    e)

    saveKeys :: TChan Event -> [Key] -> IO ()
    saveKeys :: TChan Event -> [Key] -> IO ()
    saveKeys TChan Event
    ch = STM () -> IO ()
    forall a. STM a -> IO a
    atomically (STM () -> IO ()) -> ([Key] -> STM ()) -> [Key] -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . TChan Event -> Event -> STM ()
    forall a. TChan a -> a -> STM ()
    writeTChan TChan Event
    ch (Event -> STM ()) -> ([Key] -> Event) -> [Key] -> STM ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Key] -> Event
    KeyInput

    data Layout = Layout {Layout -> Int
    width, Layout -> Int
    height :: Int}
                        deriving (Int -> Layout -> String -> String
    [Layout] -> String -> String
    Layout -> String
    (Int -> Layout -> String -> String)
    -> (Layout -> String)
    -> ([Layout] -> String -> String)
    -> Show Layout
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> Layout -> String -> String
    showsPrec :: Int -> Layout -> String -> String
    $cshow :: Layout -> String
    show :: Layout -> String
    $cshowList :: [Layout] -> String -> String
    showList :: [Layout] -> String -> String
    Show,Layout -> Layout -> Bool
    (Layout -> Layout -> Bool)
    -> (Layout -> Layout -> Bool) -> Eq Layout
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Layout -> Layout -> Bool
    == :: Layout -> Layout -> Bool
    $c/= :: Layout -> Layout -> Bool
    /= :: Layout -> Layout -> Bool
    Eq)

    -----------------------------------
    -- Utility functions for the various backends.

    -- | Utility function since we're not using the new IO library yet.
    hWithBinaryMode :: (MonadIO m, MonadMask m) => Handle -> m a -> m a
    hWithBinaryMode :: forall (m :: * -> *) a.
    (MonadIO m, MonadMask m) =>
    Handle -> m a -> m a
    hWithBinaryMode Handle
    h = m (Maybe TextEncoding)
    -> (Maybe TextEncoding -> m ())
    -> (Maybe TextEncoding -> m a)
    -> m a
    forall (m :: * -> *) a c b.
    (HasCallStack, MonadMask m) =>
    m a -> (a -> m c) -> (a -> m b) -> m b
    bracket (IO (Maybe TextEncoding) -> m (Maybe TextEncoding)
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO (Maybe TextEncoding) -> m (Maybe TextEncoding))
    -> IO (Maybe TextEncoding) -> m (Maybe TextEncoding)
    forall a b. (a -> b) -> a -> b
    $ Handle -> IO (Maybe TextEncoding)
    hGetEncoding Handle
    h)
                            (m () -> (TextEncoding -> m ()) -> Maybe TextEncoding -> m ()
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (() -> m ()
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()) (IO () -> m ()
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> m ()) -> (TextEncoding -> IO ()) -> TextEncoding -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Handle -> TextEncoding -> IO ()
    hSetEncoding Handle
    h))
                            ((Maybe TextEncoding -> m a) -> m a)
    -> (m a -> Maybe TextEncoding -> m a) -> m a -> m a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . m a -> Maybe TextEncoding -> m a
    forall a b. a -> b -> a
    const (m a -> Maybe TextEncoding -> m a)
    -> (m a -> m a) -> m a -> Maybe TextEncoding -> m a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (IO () -> m ()
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (Handle -> Bool -> IO ()
    hSetBinaryMode Handle
    h Bool
    True) m () -> m a -> m a
    forall a b. m a -> m b -> m b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >>)

    -- | Utility function for changing a property of a terminal for the duration of
    -- a computation.
    bracketSet :: (MonadMask m, MonadIO m) => IO a -> (a -> IO ()) -> a -> m b -> m b
    bracketSet :: forall (m :: * -> *) a b.
    (MonadMask m, MonadIO m) =>
    IO a -> (a -> IO ()) -> a -> m b -> m b
    bracketSet IO a
    getState a -> IO ()
    set a
    newState m b
    f = m a -> (a -> m ()) -> (a -> m b) -> m b
    forall (m :: * -> *) a c b.
    (HasCallStack, MonadMask m) =>
    m a -> (a -> m c) -> (a -> m b) -> m b
    bracket (IO a -> m a
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO IO a
    getState)
                                (IO () -> m ()
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> m ()) -> (a -> IO ()) -> a -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> IO ()
    set)
                                (\a
    _ -> IO () -> m ()
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (a -> IO ()
    set a
    newState) m () -> m b -> m b
    forall a b. m a -> m b -> m b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> m b
    f)

    -- | Returns one 8-bit word.  Needs to be wrapped by hWithBinaryMode.
    hGetByte :: Handle -> MaybeT IO Word8
    hGetByte :: Handle -> MaybeT IO Word8
    hGetByte = (Handle -> IO Word8) -> Handle -> MaybeT IO Word8
    forall a. (Handle -> IO a) -> Handle -> MaybeT IO a
    guardedEOF ((Handle -> IO Word8) -> Handle -> MaybeT IO Word8)
    -> (Handle -> IO Word8) -> Handle -> MaybeT IO Word8
    forall a b. (a -> b) -> a -> b
    $ (Char -> Word8) -> IO Char -> IO Word8
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM (Int -> Word8
    forall a. Enum a => Int -> a
    toEnum (Int -> Word8) -> (Char -> Int) -> Char -> Word8
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Char -> Int
    forall a. Enum a => a -> Int
    fromEnum) (IO Char -> IO Word8) -> (Handle -> IO Char) -> Handle -> IO Word8
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Handle -> IO Char
    hGetChar

    guardedEOF :: (Handle -> IO a) -> Handle -> MaybeT IO a
    guardedEOF :: forall a. (Handle -> IO a) -> Handle -> MaybeT IO a
    guardedEOF Handle -> IO a
    f Handle
    h = do
        eof <- IO Bool -> MaybeT IO Bool
    forall (m :: * -> *) a. Monad m => m a -> MaybeT m a
    forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
    (MonadTrans t, Monad m) =>
    m a -> t m a
    lift (IO Bool -> MaybeT IO Bool) -> IO Bool -> MaybeT IO Bool
    forall a b. (a -> b) -> a -> b
    $ Handle -> IO Bool
    hIsEOF Handle
    h
        guard (not eof)
        lift $ f h

    -- If another character is immediately available, and it is a newline, consume it.
    --
    -- Two portability fixes:
    --
    -- 1) By itself, this (by using hReady) might crash on invalid characters.
    -- The handle should be set to binary mode or a TextEncoder that
    -- transliterates or ignores invalid input.
    --
    -- 1) Note that in ghc-6.8.3 and earlier, hReady returns False at an EOF,
    -- whereas in ghc-6.10.1 and later it throws an exception.  (GHC trac #1063).
    -- This code handles both of those cases.
    hMaybeReadNewline :: Handle -> IO ()
    hMaybeReadNewline :: Handle -> IO ()
    hMaybeReadNewline Handle
    h = () -> IO () -> IO ()
    forall (m :: * -> *) a. MonadMask m => a -> m a -> m a
    returnOnEOF () (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ do
        ready <- Handle -> IO Bool
    hReady Handle
    h
        when ready $ do
            c <- hLookAhead h
            when (c == '\n') $ getChar >> return ()

    returnOnEOF :: MonadMask m => a -> m a -> m a
    returnOnEOF :: forall (m :: * -> *) a. MonadMask m => a -> m a -> m a
    returnOnEOF a
    x = (IOError -> m a) -> m a -> m a
    forall (m :: * -> *) e a.
    (HasCallStack, MonadCatch m, Exception e) =>
    (e -> m a) -> m a -> m a
    handle ((IOError -> m a) -> m a -> m a) -> (IOError -> m a) -> m a -> m a
    forall a b. (a -> b) -> a -> b
    $ \IOError
    e -> if IOError -> Bool
    isEOFError IOError
    e
                                    then a -> m a
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return a
    x
                                    else IOError -> m a
    forall e a. (HasCallStack, Exception e) => e -> m a
    forall (m :: * -> *) e a.
    (MonadThrow m, HasCallStack, Exception e) =>
    e -> m a
    throwM IOError
    e

    -- | Utility function to correctly get a line of input as an undecoded ByteString.
    hGetLocaleLine :: Handle -> MaybeT IO ByteString
    hGetLocaleLine :: Handle -> MaybeT IO ByteString
    hGetLocaleLine = (Handle -> IO ByteString) -> Handle -> MaybeT IO ByteString
    forall a. (Handle -> IO a) -> Handle -> MaybeT IO a
    guardedEOF ((Handle -> IO ByteString) -> Handle -> MaybeT IO ByteString)
    -> (Handle -> IO ByteString) -> Handle -> MaybeT IO ByteString
    forall a b. (a -> b) -> a -> b
    $ \Handle
    h -> do
        -- It's more efficient to use B.getLine, but that function throws an
        -- error if the Handle (e.g., stdin) is set to NoBuffering.
        buff <- IO BufferMode -> IO BufferMode
    forall a. IO a -> IO a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO BufferMode -> IO BufferMode) -> IO BufferMode -> IO BufferMode
    forall a b. (a -> b) -> a -> b
    $ Handle -> IO BufferMode
    hGetBuffering Handle
    h
        liftIO $ if buff == NoBuffering
            then fmap BC.pack $ System.IO.hGetLine h
            else BC.hGetLine h