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]