unused-0.5.0.2: src/Unused/CLI/Util.hs
module Unused.CLI.Util
( resetScreen
, withRuntime
, installChildInterruptHandler
, module System.Console.ANSI
) where
import Control.Concurrent.ParallelIO
import Control.Monad (void)
import System.Console.ANSI
import System.IO (hSetBuffering, BufferMode(NoBuffering), stdout)
import Control.Exception (throwTo)
import System.Posix.Signals (Handler(Catch), installHandler, keyboardSignal)
import Control.Concurrent (ThreadId, myThreadId, killThread)
import System.Exit (ExitCode(ExitFailure))
withRuntime :: IO a -> IO a
withRuntime a = do
hSetBuffering stdout NoBuffering
withInterruptHandler $ withoutCursor a <* 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 <- myThreadId
void $ installHandler keyboardSignal (Catch (handleInterrupt tid)) Nothing
body
installChildInterruptHandler :: ThreadId -> IO ()
installChildInterruptHandler tid = do
currentThread <- myThreadId
void $ installHandler keyboardSignal (Catch (handleChildInterrupt currentThread tid)) Nothing
handleInterrupt :: ThreadId -> IO ()
handleInterrupt tid = do
resetScreenState
throwTo tid $ ExitFailure interruptExitCode
handleChildInterrupt :: ThreadId -> ThreadId -> IO ()
handleChildInterrupt parentTid childTid = do
killThread childTid
resetScreenState
throwTo parentTid $ ExitFailure interruptExitCode
handleInterrupt parentTid
interruptExitCode :: Int
interruptExitCode =
signalToInt $ 128 + keyboardSignal
where
signalToInt s = read $ show s :: Int
resetScreenState :: IO ()
resetScreenState = do
resetScreen
showCursor
setSGR [Reset]