content: module Unused.CLI.Util
      ( resetScreen
      , withRuntime
      , installChildInterruptHandler
      , module System.Console.ANSI
      ) where
  
  import qualified Control.Concurrent as CC
  import qualified Control.Concurrent.ParallelIO as PIO
  import qualified Control.Exception as E
  import qualified Control.Monad as M
  import           System.Console.ANSI
  import qualified System.Exit as Ex
  import           System.IO (hSetBuffering, BufferMode(NoBuffering), stdout)
  import qualified System.Posix.Signals as S
  
  withRuntime :: IO a -> IO a
  withRuntime a = do
      hSetBuffering stdout NoBuffering
      withInterruptHandler $ withoutCursor a <* PIO.stopGlobalPool
  
  resetScreen :: IO ()
  resetScreen = do
      clearScreen
      setCursorPosition 0 0
  
  withoutCursor :: IO a -> IO a
  withoutCursor body = do
      hideCursor
      body <* showCursor
  
  withInterruptHandler :: IO a -> IO a
  withInterruptHandler body = do
      tid <- CC.myThreadId
      M.void $ S.installHandler S.keyboardSignal (S.Catch (handleInterrupt tid)) Nothing
      body
  
  installChildInterruptHandler :: CC.ThreadId -> IO ()
  installChildInterruptHandler tid = do
      currentThread <- CC.myThreadId
      M.void $ S.installHandler S.keyboardSignal (S.Catch (handleChildInterrupt currentThread tid)) Nothing
  
  handleInterrupt :: CC.ThreadId -> IO ()
  handleInterrupt tid = do
      resetScreenState
      E.throwTo tid $ Ex.ExitFailure interruptExitCode
  
  handleChildInterrupt :: CC.ThreadId -> CC.ThreadId -> IO ()
  handleChildInterrupt parentTid childTid = do
      CC.killThread childTid
      resetScreenState
      E.throwTo parentTid $ Ex.ExitFailure interruptExitCode
      handleInterrupt parentTid
  
  interruptExitCode :: Int
  interruptExitCode =
      signalToInt $ 128 + S.keyboardSignal
    where
      signalToInt s = read $ show s :: Int
  
  resetScreenState :: IO ()
  resetScreenState = do
      resetScreen
      showCursor
      setSGR [Reset]
  