packages feed

haskeline 0.3.2 → 0.4

raw patch · 14 files changed

+214/−178 lines, 14 filesdep +extensible-exceptionsdep −template-haskelldep ~basedep ~stmdep ~utf8-stringPVP ok

version bump matches the API change (PVP)

Dependencies added: extensible-exceptions

Dependencies removed: template-haskell

Dependency ranges changed: base, stm, utf8-string

API changes (from Hackage documentation)

- System.Console.Haskeline: handleSigINT :: Settings m -> Bool
+ System.Console.Haskeline: withInterrupt :: (MonadException m) => InputT m a -> InputT m a
+ System.Console.Haskeline.Completion: completeQuotedWord :: (Monad m) => Maybe Char -> String -> (String -> m [Completion]) -> CompletionFunc m -> CompletionFunc m
+ System.Console.Haskeline.Completion: isFinished :: Completion -> Bool
+ System.Console.Haskeline.Completion: listFiles :: (MonadIO m) => FilePath -> m [Completion]
+ System.Console.Haskeline.MonadException: throwTo :: (MonadIO m, Exception e) => ThreadId -> e -> m ()
- System.Console.Haskeline: Settings :: CompletionFunc m -> Maybe FilePath -> Bool -> Settings m
+ System.Console.Haskeline: Settings :: CompletionFunc m -> Maybe FilePath -> Settings m
- System.Console.Haskeline.Completion: Completion :: String -> String -> Completion
+ System.Console.Haskeline.Completion: Completion :: String -> String -> Bool -> Completion
- System.Console.Haskeline.MonadException: catch :: (MonadException m) => m a -> (Exception -> m a) -> m a
+ System.Console.Haskeline.MonadException: catch :: (MonadException m, Exception e) => m a -> (e -> m a) -> m a
- System.Console.Haskeline.MonadException: handle :: (MonadException m) => (Exception -> m a) -> m a -> m a
+ System.Console.Haskeline.MonadException: handle :: (MonadException m, Exception e) => (e -> m a) -> m a -> m a
- System.Console.Haskeline.MonadException: handleDyn :: (Typeable exception, MonadException m) => (exception -> m a) -> m a -> m a
+ System.Console.Haskeline.MonadException: handleDyn :: (Exception exception, MonadException m) => (exception -> m a) -> m a -> m a
- System.Console.Haskeline.MonadException: throwDynIO :: (Typeable exception, MonadIO m) => exception -> m a
+ System.Console.Haskeline.MonadException: throwDynIO :: (Exception exception, MonadIO m) => exception -> m a
- System.Console.Haskeline.MonadException: throwIO :: (MonadIO m) => Exception -> m a
+ System.Console.Haskeline.MonadException: throwIO :: (MonadIO m, Exception e) => e -> m a

Files

System/Console/Haskeline.hs view
@@ -42,7 +42,9 @@                     defaultSettings,                     setComplete,                     -- * Ctrl-C handling+                    -- $ctrlc                     Interrupt(..),+                    withInterrupt,                     handleInterrupt,                     module System.Console.Haskeline.Completion,                     module System.Console.Haskeline.Prefs,@@ -75,13 +77,11 @@ -- defaultSettings = Settings { --           complete = completeFilename, --           historyFile = Nothing,---           handleSigINT = False --           } -- @ defaultSettings :: MonadIO m => Settings m defaultSettings = Settings {complete = completeFilename,-                        historyFile = Nothing,-                        handleSigINT = False}+                        historyFile = Nothing}  -- | Write a string to the standard output.  Allows cross-platform display of Unicode -- characters.@@ -97,13 +97,13 @@  {- | Read one line of input.  The final newline (if any) is removed. -If 'stdin' is connected to a terminal, 'getInputLine' provides a rich line-editing+If 'stdin' is connected to a terminal with echoing enabled, 'getInputLine' provides a rich line-editing user interface.  It returns 'Nothing' if the user presses @Ctrl-D@ when the input text is empty.  All user interaction, including display of the input prompt, will occur on the user's output terminal (which may differ from 'stdout'). -If 'stdin' is not connected to a terminal, 'getInputLine' reads one line of input, and-prints the prompt and input to 'stdout'. It returns 'Nothing'  if an @EOF@ is+If 'stdin' is not connected to a terminal, 'getInputLine' prints the prompt to 'stdout'+and reads one line of input. It returns 'Nothing'  if an @EOF@ is encountered before any characters are read. -} getInputLine :: forall m . MonadException m => String -- ^ The input prompt@@ -113,9 +113,10 @@     -- appears before we interact with the user on the terminal.     liftIO $ hFlush stdout     rterm <- ask+    echo <- liftIO $ hGetEcho stdin     case termOps rterm of-        Nothing -> simpleFileLoop prefix rterm-        Just tops -> getInputCmdLine tops prefix+        Just tops | echo -> getInputCmdLine tops prefix+        _ -> simpleFileLoop prefix rterm  getInputCmdLine :: MonadException m => TermOps -> String -> InputT m (Maybe String) getInputCmdLine tops prefix = do@@ -124,44 +125,36 @@     emode <- asks (\prefs -> case editMode prefs of                     Vi -> viActions                     Emacs -> emacsCommands)-    wrapper <- sigINTWrapper     -- Run the main event processing loop-    result <- runInputCmdT tops $ wrapper $ runTerm tops+    result <- runInputCmdT tops $ runTerm tops                     $ \getEvent -> do                             let ls = emptyIM                             drawLine prefix ls -                            repeatTillFinish getEvent prefix ls emode+                            repeatTillFinish tops getEvent prefix ls emode     -- Add the line to the history if it's nonempty.     case result of          Just line | not (all isSpace line) -> addHistory line         _ -> return ()     return result -sigINTWrapper :: forall m n a . (Monad m, MonadException n) => InputT m (n a -> n a)-sigINTWrapper = do-    settings :: Settings m <- ask-    rterm <- ask-    return $ if handleSigINT settings-                then wrapInterrupt rterm-                else id- repeatTillFinish :: forall m s d      . (MonadTrans d, Term (d m), LineState s, MonadReader Prefs m)-            => d m Event -> String -> s -> KeyMap m s +            => TermOps -> d m Event -> String -> s -> KeyMap m s              -> d m (Maybe String)-repeatTillFinish getEvent prefix = loop+repeatTillFinish tops getEvent prefix = loop     where -        -- NOTE: since the functions in this mutually recursive binding group do not have the -        -- same contexts, we need the -XGADTs flag (or -fglasgow-exts)         loop :: forall t . LineState t => t -> KeyMap m t -> d m (Maybe String)         loop s processor = do-                event <- handle (\e -> movePast prefix s >> throwIO e) getEvent+                event <- handle (\(e::SomeException) -> movePast prefix s >> throwIO e) getEvent                 case event of-                    WindowResize newLayout -> do+                    WindowResize -> do                         oldLayout <- ask-                        local newLayout $ do-                            reposition oldLayout (lineChars prefix s)-                            loop s processor+                        newLayout <- liftIO $ getLayout tops+                        if oldLayout == newLayout+                            then loop s processor+                            else local newLayout $ do+                                reposition oldLayout (lineChars prefix s)+                                loop s processor                     KeyInput k -> case lookupKM processor k of                         Nothing -> actBell >> loop s processor                         Just g -> case g s of@@ -187,23 +180,7 @@     atEOF <- hIsEOF stdin     if atEOF         then return Nothing-        else do-                l <- UTF8.getLine-                putStrOut rterm (l++"\n")-                return (Just l)--{-- -Note why it is necessary to integrate ctrl-c handling with this module:-if the user is in the middle of a few wrapped lines, we want to clean up-by moving the cursor to the start of the following line.---}---- | Catch and handle an exception of type 'Interrupt'.-handleInterrupt :: MonadException m => m a -                        -- ^ Handler to run if Ctrl-C is pressed-                     -> m a -- ^ Computation to run-                     -> m a-handleInterrupt f = handle (const f)+        else liftM Just UTF8.getLine  drawEffect :: (LineState s, LineState t, Term (d m),                  MonadTrans d, MonadReader Prefs m) @@ -241,3 +218,32 @@  movePast :: (LineState s, Term m) => String -> s -> m () movePast prefix s = moveToNextLine (lineChars prefix s)++++------------+-- Interrupt++{- $ctrlc+The following functions provide portable handling of Ctrl-C events.  ++These functions are not necessary on GHC version 6.10 or later, which+processes Ctrl-C events as exceptions by default.+-}++-- | If Ctrl-C is pressed during the given computation, throw an exception of type +-- 'Interrupt'.+withInterrupt :: MonadException m => InputT m a -> InputT m a+withInterrupt f = do+    rterm <- ask+    wrapInterrupt rterm f++-- | Catch and handle an exception of type 'Interrupt'.+handleInterrupt :: MonadException m => m a +                        -- ^ Handler to run if Ctrl-C is pressed+                     -> m a -- ^ Computation to run+                     -> m a+handleInterrupt f = handleDyn $ \Interrupt -> f+++
System/Console/Haskeline/Backend/Posix.hsc view
@@ -12,7 +12,7 @@ import System.Console.Terminfo import System.Posix.Terminal hiding (Interrupt) import Control.Monad-import Control.Concurrent+import Control.Concurrent hiding (throwTo) import Control.Concurrent.STM import Data.Maybe import System.Posix.Signals.Exts@@ -22,7 +22,6 @@ import qualified Data.ByteString as B import qualified Data.ByteString.UTF8 as UTF8 import System.Environment-import Control.Exception (throwDynTo)  import System.Console.Haskeline.Monads import System.Console.Haskeline.Command@@ -55,7 +54,7 @@ unsafeHandleToFD h = withHandle_ "unsafeHandleToFd" h (return . haFD)  envLayout :: IO (Maybe Layout)-envLayout = handle (\_ -> return Nothing) $ do+envLayout = handle (\(_::IOException) -> return Nothing) $ do     -- note the handle catches both undefined envs and bad reads     r <- getEnv "ROWS"     c <- getEnv "COLUMNS"@@ -168,7 +167,7 @@ withPosixGetEvent h term f = do     baseMap <- liftIO (getKeySequences term)     eventChan <- liftIO $ newTChanIO-    wrapKeypad h term $ withWindowHandler h term eventChan+    wrapKeypad h term $ withWindowHandler eventChan         $ f $ liftIO $ getEvent baseMap eventChan  -- If the keypad on/off capabilities are defined, wrap the computation with them.@@ -180,16 +179,15 @@     maybeOutput cap = liftIO $ hRunTermOutput h term $                             fromMaybe mempty (getCapability term cap) -withWindowHandler :: MonadException m => Handle -> Maybe Terminal -> TChan Event -> m a -> m a-withWindowHandler h term eventChan = withHandler windowChange $ -    Catch $ getPosixLayout h term -                >>= atomically . writeTChan eventChan . WindowResize+withWindowHandler :: MonadException m => TChan Event -> m a -> m a+withWindowHandler eventChan = withHandler windowChange $ +    Catch $ atomically $ writeTChan eventChan WindowResize  withSigIntHandler :: MonadException m => m a -> m a withSigIntHandler f = do     tid <- liftIO myThreadId      withHandler keyboardSignal -            (CatchOnce (throwDynTo tid Interrupt))+            (Catch (throwTo tid Interrupt))             f  withHandler :: MonadException m => Signal -> Handler -> m a -> m a@@ -218,7 +216,7 @@ openTTY = do     inIsTerm <- hIsTerminalDevice stdin     if inIsTerm-        then handle (\_ -> return Nothing) $ do+        then handle (\(_::IOException) -> return Nothing) $ do                 h <- openFile "/dev/tty" WriteMode                 return (Just h)         else return Nothing
System/Console/Haskeline/Backend/Terminfo.hs view
@@ -8,7 +8,7 @@ import Control.Monad import Data.List(intersperse) import System.IO-import qualified Control.Exception as Exception+import qualified Control.Exception.Extensible as Exception  import System.Console.Haskeline.Monads as Monads import System.Console.Haskeline.LineState@@ -108,7 +108,9 @@ runTerminfoDraw = do     mterm <- Exception.try setupTermFromEnv     case mterm of-        Left _ -> return Nothing+        -- XXX narrow this: either an ioexception (from getenv) or a +        -- usererror.+        Left (_::SomeException) -> return Nothing         Right term -> case getCapability term getActions of             Nothing -> return Nothing             Just actions -> fmap Just $ posixRunTerm $ \h -> @@ -230,26 +232,15 @@     output $ mreplicate (lsLinesLeft layout pos s) nl     put initTermPos --posFromLength :: Layout -> Int -> TermPos-posFromLength Layout {width = w} n = TermPos -                            {termRow = n `div` w, termCol = n `mod` w}--posToLength :: Layout -> TermPos -> Int-posToLength Layout {width = w} TermPos {termRow = r, termCol = c}-    = r * w + c--repositionPos :: Layout -> Layout -> TermPos -> TermPos-repositionPos oldLayout newLayout oldPos = posFromLength newLayout $-                                            posToLength oldLayout oldPos- repositionT :: (MonadLayout m, MonadException m) =>                 Layout -> LineChars -> Draw m ()-repositionT oldLayout _ = do+repositionT oldLayout s = do     oldPos <- get-    newLayout <- ask-    let newPos = repositionPos oldLayout newLayout oldPos-    put newPos+    let l = lsLinesLeft oldLayout oldPos s - 1+    output $ cr <#> mreplicate l nl+            <#> mreplicate (l + termRow oldPos) (clearToLineEnd <#> up 1)+    put initTermPos+    drawLineDiffT ("","") s  instance (MonadException m, MonadLayout m) => Term (Draw m) where     drawLineDiff = drawLineDiffT
System/Console/Haskeline/Backend/Win32.hsc view
@@ -15,10 +15,9 @@ import Graphics.Win32.Misc(getStdHandle, sTD_INPUT_HANDLE, sTD_OUTPUT_HANDLE)
 import System.Win32.File
 import Data.List(intercalate)
-import Control.Concurrent
+import Control.Concurrent hiding (throwTo)
 import Control.Concurrent.STM
 import Data.Bits
-import Control.Exception (throwDynTo)
 
 import System.Console.Haskeline.Command
 import System.Console.Haskeline.Monads
@@ -53,7 +52,7 @@     	        Nothing -> eventLoop h
                        
 getConOut :: IO (Maybe HANDLE)
-getConOut = handle (\_ -> return Nothing) $ fmap Just
+getConOut = handle (\(_::IOException) -> return Nothing) $ fmap Just
     $ createFile "CONOUT$" (gENERIC_READ .|. gENERIC_WRITE)
                         (fILE_SHARE_READ .|. fILE_SHARE_WRITE) Nothing
                     oPEN_EXISTING 0 Nothing
@@ -155,18 +154,10 @@             $ c_GetScreenBufferInfo h infoPtr
         f infoPtr
 
-
-getDisplayWindow :: HANDLE -> IO (Coord,Coord)
-getDisplayWindow = withScreenBufferInfo $ \p -> do
-    let windowPtr = (#ptr CONSOLE_SCREEN_BUFFER_INFO, srWindow) p
-    left <- (#peek SMALL_RECT, Left) windowPtr
-    top <- (#peek SMALL_RECT, Top) windowPtr
-    right <- (#peek SMALL_RECT, Right) windowPtr
-    bottom <- (#peek SMALL_RECT, Bottom) windowPtr
-    return (Coord (cvt left) (cvt top), Coord (cvt right) (cvt bottom))
-  where
-    cvt :: CShort -> Int
-    cvt = fromEnum
+getBufferSize :: HANDLE -> IO Layout
+getBufferSize = withScreenBufferInfo $ \p -> do
+    c <- (#peek CONSOLE_SCREEN_BUFFER_INFO, dwSize) p
+    return Layout {width = coordX c, height = coordY c}
 
 foreign import stdcall "windows.h WriteConsoleW" c_WriteConsoleW
     :: HANDLE -> Ptr TCHAR -> DWORD -> Ptr DWORD -> Ptr () -> IO Bool
@@ -199,12 +190,6 @@     ask = lift ask
     local r = Draw . local r . runDraw
 
-getDisplaySize :: HANDLE -> IO Layout
-getDisplaySize h = do
-    (topLeft,bottomRight) <- getDisplayWindow h
-    return Layout {width = coordX bottomRight - coordX topLeft+1, 
-                    height = coordY bottomRight - coordY topLeft+1 }
-    
 getPos :: MonadIO m => Draw m Coord
 getPos = ask >>= liftIO . getPosition
     
@@ -280,7 +265,7 @@                             putStrOut = putter,
                             wrapInterrupt = withCtrlCHandler,
                             termOps = Just TermOps {
-                                            getLayout = getDisplaySize h,
+                                            getLayout = getBufferSize h,
                                             runTerm = consoleRunTerm h},
                             closeTerm = closeHandle h}
 
@@ -329,6 +314,6 @@                                 (const f)
   where
     handler tid (#const CTRL_C_EVENT) = do
-        throwDynTo tid Interrupt
+        throwTo tid Interrupt
         return True
     handler _ _ = return False
System/Console/Haskeline/Command.hs view
@@ -39,7 +39,7 @@ import System.Console.Haskeline.LineState  data Layout = Layout {width, height :: Int}-                    deriving Show+                    deriving (Show,Eq)  data Key = KeyChar Char | KeyMeta Key             | KeyLeft | KeyRight | KeyUp | KeyDown
System/Console/Haskeline/Command/Completion.hs view
@@ -14,6 +14,10 @@  import Data.List(transpose, unfoldr) +fullReplacement :: Completion -> String+fullReplacement c   | isFinished c  = replacement c ++ " "+                    | otherwise     = replacement c+ makeCompletion :: Monad m => InsertMode -> InputCmdT m (InsertMode, [Completion]) makeCompletion (IMode xs ys) = do     f <- asks complete@@ -27,7 +31,7 @@     (rest,completions) <- makeCompletion s     case completionType prefs of         MenuCompletion -> return $ menuCompletion k s-                        $ map (\c -> insertString (replacement c) rest) completions+                        $ map (\c -> insertString (fullReplacement c) rest) completions         ListCompletion ->                  pagingCompletion prefs s rest completions k) @@ -36,7 +40,7 @@                 -> Key -> InputCmdT m (CmdAction (InputCmdT m) InsertMode) pagingCompletion _ oldIM _ [] _ = return $ RingBell oldIM >=> continue pagingCompletion _ _ im [newWord] _ -        = return $ (Change $ insertString (replacement newWord) im) >=> continue+        = return $ (Change $ insertString (fullReplacement newWord) im) >=> continue pagingCompletion prefs oldIM im completions k     | oldIM /= withPartial = return $ Change withPartial >=> continue     | otherwise = do
System/Console/Haskeline/Command/History.hs view
@@ -6,7 +6,7 @@ import System.Console.Haskeline.Monads import Data.List import Data.Maybe(fromMaybe)-import Control.Exception(evaluate)+import Control.Exception.Extensible(evaluate) import qualified Data.ByteString as B import qualified Data.ByteString.UTF8 as UTF8 
System/Console/Haskeline/Completion.hs view
@@ -2,9 +2,13 @@                             CompletionFunc,                             Completion(..),                             completeWord,-                            simpleCompletion,+                            completeQuotedWord,+                            -- * Building 'CompletionFunc's                             noCompletion,+                            simpleCompletion,+                            -- * Filename completion                             completeFilename,+                            listFiles,                             filenameWordBreakChars                         ) where @@ -24,9 +28,12 @@   data Completion = Completion {replacement  :: String, -- ^ Text to insert in line.-                        display  :: String+                        display  :: String,                                 -- ^ Text to display when listing                                 -- alternatives.+                        isFinished :: Bool+                            -- ^ Whether this word should be followed by a+                            -- space, end quote, etc.                             }                     deriving Show @@ -48,17 +55,17 @@                         Nothing -> break (`elem` ws) line                         Just e -> escapedBreak e line     completions <- f (reverse word)-    return (rest,completions)+    return (rest,map (escapeReplacement esc ws) completions)   where-    escapedBreak e (c:d:cs) | d == e-            = let (xs,ys) = escapedBreak e cs in (c:d:xs,ys)+    escapedBreak e (c:d:cs) | d == e && c `elem` (e:ws)+            = let (xs,ys) = escapedBreak e cs in (c:xs,ys)     escapedBreak e (c:cs) | not (elem c ws)             = let (xs,ys) = escapedBreak e cs in (c:xs,ys)     escapedBreak _ cs = ("",cs)     --- | Adds a space after the word when inserting it after expansion.+-- | Create a finished completion out of the given word. simpleCompletion :: String -> Completion-simpleCompletion = setReplacement (++ " ") . completion+simpleCompletion = completion  -- NOTE: this is the same as for readline, except that I took out the '\\' -- so they can be used as a path separator.@@ -67,34 +74,71 @@  -- A completion command for file and folder names. completeFilename :: MonadIO m => CompletionFunc m-completeFilename  = completeWord (Just '\\') filenameWordBreakChars $ -                        (liftIO . quotedFilenames (`elem` "\"\'"))+completeFilename  = completeQuotedWord (Just '\\') "\"'" listFiles+                        $ completeWord (Just '\\') ("\"\'" ++ filenameWordBreakChars)+                                listFiles  completion :: String -> Completion-completion str = Completion str str+completion str = Completion str str True  setReplacement :: (String -> String) -> Completion -> Completion setReplacement f c = c {replacement = f $ replacement c} +escapeReplacement :: Maybe Char -> String -> Completion -> Completion+escapeReplacement esc ws f = case esc of+    Nothing -> f+    Just e -> f {replacement = escape e (replacement f)}+  where+    escape e (c:cs) | c `elem` (e:ws)     = e : c : escape e cs+                    | otherwise = c : escape e cs+    escape _ "" = "" ------------ Helper funcs for file completion -quotedFilenames :: (Char -> Bool) -> String -> IO [Completion]-quotedFilenames isQuote (q:file) | isQuote q = do-    files <- findFiles file-    return $ map (setReplacement ((q:) . appendIfNotDir [q,' '])) files-quotedFilenames _ file = do-    files <- findFiles file-    return $ map (setReplacement (appendIfNotDir " ")) files+---------+-- Quoted completion+completeQuotedWord :: Monad m => Maybe Char -- ^ An optional escape character+                            -> String -- List of characters which set off quotes+                            -> (String -> m [Completion]) -- ^ Function to produce a list of possible completions+                            -> CompletionFunc m -- ^ Alternate completion to perform if the +                                            -- cursor is not at a quoted word+                            -> CompletionFunc m+completeQuotedWord esc qs completer alterative = \line -> case splitAtQuote esc qs line of+    Just (w,rest) | isUnquoted esc qs rest -> do+        cs <- completer (reverse w)+        return (rest, map (addQuotes . escapeReplacement esc qs) cs)+    _ -> alterative line -appendIfNotDir :: String -> FilePath -> FilePath-appendIfNotDir str file | null (takeFileName file) = file-                        | otherwise = file ++ str+addQuotes :: Completion -> Completion+addQuotes c = if isFinished c+    then c {replacement = "\"" ++ replacement c ++ "\""}+    else c {replacement = "\"" ++ replacement c} -findFiles :: FilePath -> IO [Completion]+splitAtQuote :: Maybe Char -> String -> String -> Maybe (String,String)+splitAtQuote esc qs line = case line of+    c:e:cs | isEscape e && isEscapable c  +                        -> do+                            (w,rest) <- splitAtQuote esc qs cs+                            return (c:w,rest)+    q:cs   | isQuote q  -> Just ("",cs)+    c:cs                -> do+                            (w,rest) <- splitAtQuote esc qs cs+                            return (c:w,rest)+    ""                  -> Nothing+  where+    isQuote = (`elem` qs)+    isEscape c = Just c == esc+    isEscapable c = isEscape c || isQuote c++isUnquoted :: Maybe Char -> String -> String -> Bool+isUnquoted esc qs s = case splitAtQuote esc qs s of+    Just (_,s') -> not (isUnquoted esc qs s')+    _ -> True+++-- | List all of the files or folders beginning with this path.+listFiles :: MonadIO m => FilePath -> m [Completion] -- NOTE: 'handle' catches exceptions from getDirectoryContents and getHomeDirectory.-findFiles path = handle (\_ -> return []) $ do+listFiles path = liftIO $ handle (\(_::IOException) -> return []) $ do     fixedDir <- fixPath dir     dirExists <- doesDirectoryExist fixedDir     -- get all of the files in that directory, as basenames@@ -106,13 +150,14 @@     -- have a trailing slash if it's itself a directory.     forM allFiles $ \c -> do             isDir <- doesDirectoryExist (fixedDir </> replacement c)-            return $ setReplacement (fullName . maybeAddSlash isDir) c+            return $ setReplacement fullName $ alterIfDir isDir c   where     (dir, file) = splitFileName path     filterPrefix = filter (\f -> not (f `elem` [".",".."])                                         && file `isPrefixOf` f)-    maybeAddSlash False = id-    maybeAddSlash True = addTrailingPathSeparator+    alterIfDir False c = c+    alterIfDir True c = c {replacement = addTrailingPathSeparator (replacement c),+                            isFinished = False}     -- NOTE In order for completion to work properly, all of the alternatives     -- must have the exact same prefix.  As a result, </> is a little too clever;     -- for example, it doesn't prepend the directory if the file looks like
System/Console/Haskeline/InputT.hs view
@@ -17,9 +17,7 @@  -- | Application-specific customizations to the user interface. data Settings m = Settings {complete :: CompletionFunc m, -- ^ Custom tab completion-                            historyFile :: Maybe FilePath,-                            handleSigINT :: Bool -- ^ Throw an 'Interrupt'-                            -- exception if the user presses Ctrl-C+                            historyFile :: Maybe FilePath                             }  -- | Because 'complete' is the only field of 'Settings' depending on @m@,@@ -87,7 +85,7 @@ -- | Read 'Prefs' from @~/.haskeline.@   If there is an error reading the file, -- the 'defaultPrefs' will be returned. readPrefsFromHome :: IO Prefs-readPrefsFromHome = handle (\_ -> return defaultPrefs) $ do+readPrefsFromHome = handle (\(_::IOException) -> return defaultPrefs) $ do     home <- getHomeDirectory     readPrefs (home </> ".haskeline") 
System/Console/Haskeline/MonadException.hs view
@@ -1,54 +1,67 @@-{- | This module redefines some of the functions in "Control.Exception" to+{- | This module redefines some of the functions in "Control.Exception.Extensible" to work for more general monads than only 'IO'. -} -module System.Console.Haskeline.MonadException where+module System.Console.Haskeline.MonadException(+    MonadException(..),+    handle,+    finally,+    throwIO,+    throwTo,+    bracket,+    throwDynIO,+    handleDyn,+    Exception,+    SomeException(..),+    E.IOException())+     where -import qualified Control.Exception as E+import qualified Control.Exception.Extensible as E+import Control.Exception.Extensible(Exception,SomeException) import Prelude hiding (catch)-import Control.Exception(Exception) import Control.Monad.Reader import Control.Monad.State-import Data.Dynamic+import Control.Concurrent(ThreadId)  class MonadIO m => MonadException m where-    catch :: m a -> (Exception -> m a) -> m a+    catch :: Exception e => m a -> (e -> m a) -> m a     block :: m a -> m a     unblock :: m a -> m a -handle :: MonadException m => (Exception -> m a) -> m a -> m a+handle :: (MonadException m, Exception e) => (e -> m a) -> m a -> m a handle = flip catch  finally :: MonadException m => m a -> m b -> m a finally f ender = block (do     r <- catch             (unblock f)-            (\e -> do {ender; throwIO e})+            (\(e::SomeException) -> do {ender; throwIO e})     ender     return r) -throwIO :: MonadIO m => Exception -> m a+throwIO :: (MonadIO m, Exception e) => e -> m a throwIO = liftIO . E.throwIO +throwTo :: (MonadIO m, Exception e) => ThreadId -> e -> m ()+throwTo tid = liftIO . E.throwTo tid+ bracket :: MonadException m => m a -> (a -> m b) -> (a -> m c) -> m c bracket before after thing =   block (do     a <- before      r <- catch  	   (unblock (thing a))-	   (\e -> do { after a; throwIO e })+	   (\(e::SomeException) -> do { after a; throwIO e })     after a     return r  ) -throwDynIO :: (Typeable exception, MonadIO m) => exception -> m a-throwDynIO = liftIO . E.throwIO . E.DynException . toDyn+throwDynIO :: (Exception exception, MonadIO m) => exception -> m a+throwDynIO = throwIO -handleDyn :: (Typeable exception, MonadException m) => (exception -> m a)+handleDyn :: (Exception exception, MonadException m) => (exception -> m a)                     -> m a -> m a-handleDyn f = handle $ \ex -> case E.dynExceptions ex of-                        Just dyn | Just e <- fromDynamic dyn -> f e-                        _ -> throwIO ex+handleDyn = handle    instance MonadException IO where
System/Console/Haskeline/Prefs.hs view
@@ -21,10 +21,9 @@                         EditMode(..)                         ) where -import Language.Haskell.TH import Data.Char(isSpace,toLower) import Data.List(foldl')-import Control.Exception(handle)+import System.Console.Haskeline.MonadException(handle,IOException)   data Prefs = Prefs { bellStyle :: !BellStyle,@@ -58,7 +57,7 @@ {- | The default preferences which may be overwritten in the @.haskeline@ file:  > defaultPrefs = Prefs {bellStyle = AudibleBell,->                      maxHistorySize = Nothing,+>                      maxHistorySize = Just 100, >                      editMode = Emacs, >                      completionType = ListCompletion, >                      completionPaging = True,@@ -69,7 +68,7 @@ -} defaultPrefs :: Prefs defaultPrefs = Prefs {bellStyle = AudibleBell,-                      maxHistorySize = Nothing,+                      maxHistorySize = Just 100,                       editMode = Emacs,                       completionType = ListCompletion,                       completionPaging = True,@@ -82,22 +81,21 @@                 [(x,_)] -> f x                 _ -> id -settors :: [(String,String -> Prefs -> Prefs)]-settors = $(do-    DataConI _ _ prefsType _ <- reify 'Prefs-    TyConI (DataD _ _ _ [RecC _ fields] _) <- reify prefsType-    x <- newName "x"-    p <- newName "p"-    -- settor f => ("f", mkSettor (\x p -> p {f=x}))-    let settor (f,_,_) = TupE [LitE (StringL (map toLower $ nameBase f)),-                        AppE (VarE 'mkSettor) $ LamE [VarP x,VarP p]-                        $ RecUpdE (VarE p) [(f,VarE x)]]-    return $ ListE $ map settor fields)+settors :: [(String, String -> Prefs -> Prefs)]+settors = [("bellstyle", mkSettor $ \x p -> p {bellStyle = x})+          ,("editmode", mkSettor $ \x p -> p {editMode = x})+          ,("maxhistorysize", mkSettor $ \x p -> p {maxHistorySize = x})+          ,("completiontype", mkSettor $ \x p -> p {completionType = x})+          ,("completionpaging", mkSettor $ \x p -> p {completionPaging = x})+          ,("completionpromptlimit", mkSettor $ \x p -> p {completionPromptLimit = x})+          ,("listcompletionsimmediately", mkSettor $ \x p -> p {listCompletionsImmediately = x}) +          ]+ -- | Read 'Prefs' from a given file.  If there is an error reading the file, -- the 'defaultPrefs' will be returned. readPrefs :: FilePath -> IO Prefs-readPrefs file = handle (\_ -> return defaultPrefs) $ do+readPrefs file = handle (\(_::IOException) -> return defaultPrefs) $ do     ls <- fmap lines $ readFile file     return $ foldl' applyField defaultPrefs ls   where
System/Console/Haskeline/Term.hs view
@@ -38,7 +38,7 @@ matchInit (x:xs) (y:ys)  | x == y = matchInit xs ys matchInit xs ys = (xs,ys) -data Event = WindowResize Layout | KeyInput Key+data Event = WindowResize | KeyInput Key                 deriving Show  keyEventLoop :: (TChan Event -> IO ()) -> TChan Event -> IO Event@@ -64,3 +64,5 @@  data Interrupt = Interrupt                 deriving (Show,Typeable,Eq)++instance Exception Interrupt where
examples/Test.hs view
@@ -3,16 +3,15 @@ import System.Console.Haskeline  mySettings :: Settings IO-mySettings = defaultSettings {historyFile = Just "myhist",-                        handleSigINT = True}+mySettings = defaultSettings {historyFile = Just "myhist"}  main :: IO ()-main = runInputT mySettings (loop 0)+main = runInputT mySettings $ withInterrupt $ loop 0     where         loop :: Int -> InputT IO ()         loop n = do             minput <-  handleInterrupt (return (Just "Caught interrupted"))-                        (getInputLine (show n ++ ":"))+                        $ getInputLine (show n ++ ":")             case minput of                 Nothing -> return ()                 Just "quit" -> return ()
haskeline.cabal view
@@ -1,6 +1,6 @@ Name:           haskeline Cabal-Version:  >=1.2-Version:        0.3.2+Version:        0.4 Category:       User Interfaces License:        BSD3 License-File:   LICENSE@@ -29,20 +29,17 @@     if flag(old-base)         Build-depends: base < 3     else-        Build-depends: base>=3 && <4 , containers>=0.1, directory>=1.0-    Build-depends:  stm>=2.0, filepath>=1.1, template-haskell>=2.1, -                    mtl>=1.1, utf8-string>=0.3.1.1, bytestring>=0.9.0.1+        Build-depends: base>=3 && <5 , containers>=0.1, directory>=1.0+    Build-depends:  stm>=2.0, filepath>=1.1, +                    mtl>=1.1, utf8-string>=0.3.1.1, bytestring>=0.9.0.1,+                    extensible-exceptions>=0.1.1.0     Extensions:     ForeignFunctionInterface, RankNTypes, FlexibleInstances,                 TypeSynonymInstances                 FlexibleContexts, ExistentialQuantification                 ScopedTypeVariables, GeneralizedNewtypeDeriving                 MultiParamTypeClasses, OverlappingInstances                 PatternSignatures, CPP, DeriveDataTypeable,-                PatternGuards, TemplateHaskell, StandaloneDeriving-                -- Note: GADTs are needed to allow contexts of different-                -- lengths (see code of Haskeline.repeatTillFinish)-                GADTs-                FunctionalDependencies+                PatternGuards, StandaloneDeriving     Exposed-Modules:                 System.Console.Haskeline                 System.Console.Haskeline.Completion