packages feed

repline 0.1.7.0 → 0.2.0.0

raw patch · 3 files changed

+50/−33 lines, 3 filesdep ~containersPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: containers

API changes (from Hackage documentation)

+ System.Console.Repline: dontCrash :: (MonadIO m, MonadException m) => m () -> m ()
+ System.Console.Repline: instance Control.Monad.Reader.Class.MonadReader r m => Control.Monad.Reader.Class.MonadReader r (System.Console.Repline.HaskelineT m)
- System.Console.Repline: evalRepl :: MonadException m => String -> Command (HaskelineT m) -> Options (HaskelineT m) -> CompleterStyle m -> HaskelineT m a -> m ()
+ System.Console.Repline: evalRepl :: (Functor m, MonadException m) => HaskelineT m String -> Command (HaskelineT m) -> Options (HaskelineT m) -> Maybe Char -> CompleterStyle m -> HaskelineT m a -> m ()
- System.Console.Repline: type LineCompleter m = String -> String -> m [Completion]
+ System.Console.Repline: type LineCompleter m = (String -> String -> m [Completion])
- System.Console.Repline: type WordCompleter m = String -> m [String]
+ System.Console.Repline: type WordCompleter m = (String -> m [String])

Files

README.md view
@@ -43,7 +43,7 @@ ini = liftIO $ putStrLn "Welcome!"  repl :: IO ()-repl = evalRepl ">>> " cmd options (Word completer) ini+repl = evalRepl (pure ">>> ") cmd options (Word completer) ini ```  Trying it out:@@ -62,9 +62,9 @@ "spam"  >>> :say Hello Haskell- _______________ + _______________ < Hello Haskell >- --------------- + ---------------         \   ^__^          \  (oo)\_______             (__)\       )\/\@@ -113,12 +113,12 @@ -- Tab completion inside of StateT repl :: IO () repl = flip evalStateT Set.empty-     $ evalRepl ">>> " cmd opts (Word comp) init+     $ evalRepl (pure ">>> ") cmd opts (Word comp) init ```   Prefix Completion-----------------+-----------------  Just as GHCi will provide different tab completion for kind-level vs type-level symbols based on which prefix the user has entered, we can also set up a provide this as a first-level construct using a ``Prefix`` tab@@ -164,7 +164,7 @@ init = return ()  repl :: IO ()-repl = evalRepl ">> " cmd opts (Prefix (wordCompleter byWord) defaultMatcher) init+repl = evalRepl (pure ">>> ") cmd opts (Prefix (wordCompleter byWord) defaultMatcher) init ```  Trying it out:
repline.cabal view
@@ -1,5 +1,5 @@ name:                repline-version:             0.1.7.0+version:             0.2.0.0 synopsis:            Haskeline wrapper for GHCi-like REPL interfaces. license:             MIT license-file:        LICENSE@@ -26,7 +26,7 @@   exposed-modules:     System.Console.Repline   build-depends:     base       >= 4.6 && <5.0,-    containers >= 0.5 && <0.6,+    containers >= 0.5 && <0.7,     mtl        >= 2.2 && <2.3,     process    >= 1.2 && <2.0,     haskeline  >= 0.7 && <0.8
src/System/Console/Repline.hs view
@@ -72,7 +72,7 @@ Putting it all together we have a little shell.  > main :: IO ()-> main = evalRepl ">>> " cmd options (Word completer) ini+> main = evalRepl (pure ">>> ") cmd options (Word completer) ini  Putting this in a file we can test out our cow-trek shell. @@ -123,6 +123,7 @@   evalRepl,   abort,   tryAction,+  dontCrash,    trimComplete, ) where@@ -134,6 +135,7 @@ import Data.List (isPrefixOf) import Control.Applicative import Control.Monad.State.Strict+import Control.Monad.Reader  ------------------------------------------------------------------------------- -- Haskeline Transformer@@ -161,6 +163,10 @@   get = lift get   put = lift . put +instance MonadReader r m => MonadReader r (HaskelineT m) where+  ask                    = lift ask+  local f (HaskelineT m) = HaskelineT $ H.mapInputT (local f) m+ instance (MonadHaskeline m) => MonadHaskeline (StateT s m) where   getInputLine = lift . getInputLine   getInputChar = lift . getInputChar@@ -183,35 +189,45 @@ tryAction (HaskelineT f) = HaskelineT (H.withInterrupt loop)     where loop = handle (\H.Interrupt -> loop) f +-- | Catch all toplevel failures.+dontCrash :: (MonadIO m, H.MonadException m) => m () -> m ()+dontCrash m = H.catch m ( \ e@SomeException{} -> liftIO ( putStrLn ( show e ) ) )+ -- | Abort the current REPL loop, and continue. abort :: MonadIO m => HaskelineT m a abort = throwIO H.Interrupt  -- | Completion loop.-replLoop :: MonadException m-         => String+replLoop :: (Functor m, MonadException m)+         => HaskelineT m String          -> Command (HaskelineT m)          -> Options (HaskelineT m)+         -> Maybe Char          -> HaskelineT m ()-replLoop banner cmdM opts = loop+replLoop banner cmdM opts optsPrefix = loop   where     loop = do-      minput <- H.handleInterrupt (return (Just "")) $ getInputLine banner+      prefix <- banner+      minput <- H.handleInterrupt (return (Just "")) $ getInputLine prefix       case minput of         Nothing -> outputStrLn "Goodbye."-         Just "" -> loop-        Just ":" -> loop--        Just (':' : cmds) -> do-          let (cmd:args) = words cmds-          optMatcher cmd opts args-          loop-+        Just (prefix: cmds)+          | null cmds -> handleInput [prefix] >> loop+          | Just prefix == optsPrefix ->+            case words cmds of+              [] -> loop+              (cmd:args) -> do+                let optAction = optMatcher cmd opts args+                result <- H.handleInterrupt (return Nothing) $ Just <$> optAction+                maybe exit (const loop) result         Just input -> do-          H.handleInterrupt (return ()) $ cmdM input+          handleInput input           loop +    handleInput input = H.handleInterrupt exit $ cmdM input+    exit = return ()+ -- | Match the options. optMatcher :: MonadHaskeline m => String -> Options m -> [String] -> m () optMatcher s [] _ = outputStrLn $ "No such command :" ++ s@@ -220,16 +236,17 @@   | otherwise = optMatcher s xs args  -- | Evaluate the REPL logic into a MonadException context.-evalRepl :: MonadException m             -- Terminal monad ( often IO ).-         => String                       -- ^ Banner-         -> Command (HaskelineT m)       -- ^ Command function-         -> Options (HaskelineT m)       -- ^ Options list and commands-         -> CompleterStyle m             -- ^ Tab completion function-         -> HaskelineT m a               -- ^ Initializer+evalRepl :: (Functor m, MonadException m)  -- Terminal monad ( often IO ).+         => HaskelineT m String            -- ^ Banner+         -> Command (HaskelineT m)         -- ^ Command function+         -> Options (HaskelineT m)         -- ^ Options list and commands+         -> Maybe Char                     -- ^ Optional command prefix ( passing Nothing ignores the Options argument )+         -> CompleterStyle m               -- ^ Tab completion function+         -> HaskelineT m a                 -- ^ Initializer          -> m ()-evalRepl banner cmd opts comp initz = runHaskelineT _readline (initz >> monad)+evalRepl banner cmd opts optsPrefix comp initz = runHaskelineT _readline (initz >> monad)   where-    monad = replLoop banner cmd opts+    monad = replLoop banner cmd opts optsPrefix     _readline = H.Settings       { H.complete       = mkCompleter comp       , H.historyFile    = Just ".history"@@ -275,7 +292,7 @@ completionNoSpace str = Completion str str False  wordCompleter :: Monad m => WordCompleter m -> CompletionFunc m-wordCompleter f (start, n) = (completeWord (Just '\\') " \t()[]" (_simpleComplete f)) (start, n)+wordCompleter f (start, n) = completeWord (Just '\\') " \t()[]" (_simpleComplete f) (start, n)  listCompleter :: Monad m => [String] -> CompletionFunc m listCompleter names (start, n) = completeWord (Just '\\') " \t()[]" (_simpleComplete (complete_aux names)) (start, n)@@ -301,5 +318,5 @@ runMatcher :: Monad m => [(String, CompletionFunc m)]                       -> CompletionFunc m                       -> CompletionFunc m-runMatcher opts def (start, n) = do-  (completeMatcher def (n ++ reverse start) opts) (start, n)+runMatcher opts def (start, n) =+  completeMatcher def (n ++ reverse start) opts (start, n)