allow Ctrl+Break in the shell. Works on Windows too.

This commit is contained in:
kr.angelov
2008-05-23 15:16:28 +00:00
parent 0b80bf17d9
commit 53bfa43a58
5 changed files with 142 additions and 1 deletions

View File

@@ -11,6 +11,9 @@ flag readline
Description: Enable Readline in the shell
Default: True
flag interrupt
Description: Enable Ctrl+Break in the shell
Default: True
library
build-depends: base,
@@ -174,3 +177,9 @@ executable gf3
other-modules: GF.System.UseReadline
else
other-modules: GF.System.NoReadline
if flag(interrupt)
ghc-options: -DUSE_INTERRUPT
other-modules: GF.System.UseSignal
else
other-modules: GF.System.NoSignal

View File

@@ -10,6 +10,7 @@ import GF.Command.ParGFShell
import GF.GFCC.API
import GF.GFCC.Macros
import GF.GFCC.DataGFCC
import GF.System.Signal
import GF.Data.ErrM ----
@@ -23,7 +24,10 @@ data CommandEnv = CommandEnv {
interpretCommandLine :: CommandEnv -> String -> IO ()
interpretCommandLine env line = case (pCommandLine (myLexer line)) of
Ok CEmpty -> return ()
Ok (CLine pipes) -> mapM_ interPipe pipes
Ok (CLine pipes) -> do res <- runInterruptibly (mapM_ interPipe pipes)
case res of
Left ex -> print ex
Right x -> return x
_ -> putStrLn "command not parsed"
where
interPipe (PComm cs) = do

View File

@@ -0,0 +1,29 @@
----------------------------------------------------------------------
-- |
-- Module : GF.System.NoSignal
-- Maintainer : Bjorn Bringert
-- Stability : (stability)
-- Portability : (portability)
--
-- > CVS $Date: 2005/11/11 11:12:50 $
-- > CVS $Author: bringert $
-- > CVS $Revision: 1.1 $
--
-- Dummy implementation of signal handling.
-----------------------------------------------------------------------------
module GF.System.NoSignal where
import Control.Exception (Exception,catch)
import Prelude hiding (catch)
{-# NOINLINE runInterruptibly #-}
runInterruptibly :: IO a -> IO (Either Exception a)
--runInterruptibly = fmap Right
runInterruptibly a =
p `catch` h
where p = a >>= \x -> return $! Right $! x
h e = return $ Left e
blockInterrupt :: IO a -> IO a
blockInterrupt = id

View File

@@ -0,0 +1,27 @@
{-# OPTIONS -cpp #-}
----------------------------------------------------------------------
-- |
-- Module : GF.System.Signal
-- Maintainer : Bjorn Bringert
-- Stability : (stability)
-- Portability : (portability)
--
-- > CVS $Date: 2005/11/11 11:12:50 $
-- > CVS $Author: bringert $
-- > CVS $Revision: 1.3 $
--
-- Import the right singal handling module.
-----------------------------------------------------------------------------
module GF.System.Signal (runInterruptibly,blockInterrupt) where
#ifdef USE_INTERRUPT
import GF.System.UseSignal (runInterruptibly,blockInterrupt)
#else
import GF.System.NoSignal (runInterruptibly,blockInterrupt)
#endif

View File

@@ -0,0 +1,72 @@
{-# OPTIONS -cpp #-}
----------------------------------------------------------------------
-- |
-- Module : GF.System.UseSignal
-- Maintainer : Bjorn Bringert
-- Stability : (stability)
-- Portability : (portability)
--
-- > CVS $Date: 2005/11/11 11:12:50 $
-- > CVS $Author: bringert $
-- > CVS $Revision: 1.1 $
--
-- Allows SIGINT (Ctrl-C) to interrupt computations.
-----------------------------------------------------------------------------
module GF.System.UseSignal where
import Control.Concurrent (myThreadId, killThread)
import Control.Exception (Exception,catch)
import Prelude hiding (catch)
import System.IO
#ifdef mingw32_HOST_OS
import GHC.ConsoleHandler
myInstallHandler handler = installHandler handler
myCatch = Catch . const
myIgnore = Ignore
#else
import System.Posix.Signals
myInstallHandler handler = installHandler sigINT handler Nothing
myCatch = Catch
myIgnore = Ignore
#endif
{-# NOINLINE runInterruptibly #-}
-- | Run an IO action, and allow it to be interrupted
-- by a SIGINT to the current process. Returns
-- an exception if the process did not complete
-- normally.
-- NOTES:
-- * This will replace any existing SIGINT
-- handler during the action. After the computation
-- has completed the existing handler will be restored.
-- * If the IO action is lazy (e.g. using readFile,
-- unsafeInterleaveIO etc.) the lazy computation will
-- not be interruptible, as it will be performed
-- after the signal handler has been removed.
runInterruptibly :: IO a -> IO (Either Exception a)
runInterruptibly a =
do t <- myThreadId
oldH <- myInstallHandler (myCatch (print "Seek and Destroy" >> killThread t))
x <- p `catch` h
myInstallHandler oldH
return x
where p = a >>= \x -> return $! Right $! x
h e = return $ Left e
-- | Like 'runInterruptibly', but always returns (), whether
-- the computation fails or not.
runInterruptibly_ :: IO () -> IO ()
runInterruptibly_ = fmap (either (const ()) id) . runInterruptibly
-- | Run an action with SIGINT blocked.
blockInterrupt :: IO a -> IO a
blockInterrupt a =
do oldH <- myInstallHandler Ignore
x <- a
myInstallHandler oldH
return x