packages feed

repline 0.2.1.0 → 0.2.2.0

raw patch · 4 files changed

+88/−23 lines, 4 filesdep +exceptions

Dependencies added: exceptions

Files

ChangeLog.md view
@@ -1,9 +1,16 @@ HEAD ==== +0.2.2.0+=======++- `ReplOpts` configuration type and `evalReplOpts` function.+- Only use `fail` for GHC<8.0+ 0.2.1.0 ======= +- Add `exceptions` dependency. - Add a `MonadFail` instance to `HaskelineT`.  0.2.0.0
README.md view
@@ -8,6 +8,13 @@ transformers. Mostly exists because I got tired of implementing the same interface for simple shells over and over and decided to canonize the giant pile of hacks that I use to make Haskeline work. +Examples+--------++* [Simple](examples/Simple.hs)+* [Prefix](examples/Prefix.hs)+* [Stateful](examples/Stateful.hs)+ Usage ----- @@ -49,8 +56,9 @@ Trying it out:  ```haskell-$ runhaskell Simple.hs-# Or if in a sandbox: cabal exec runhaskell Simple.hs+$ stack repl Simple.hs+Prelude> main+ Welcome! >>> <TAB> kirk spock mccoy@@ -113,7 +121,7 @@ -- Tab completion inside of StateT repl :: IO () repl = flip evalStateT Set.empty-     $ evalRepl (pure ">>> ") cmd opts Nothing (Word comp) init+     $ evalRepl (pure ">>> ") cmd opts Nothing (Word comp) ini ```  @@ -170,7 +178,9 @@ Trying it out:  ```haskell-$ runhaskell Main.hs+$ stack repl examples/Prefix.hs+Prelude> main+ >>> :file <TAB> sample1.txt sample2.txt @@ -183,5 +193,5 @@ License ------- -Copyright (c) 2014-2019, Stephen Diehl+Copyright (c) 2014-2020, Stephen Diehl Released under the MIT License
repline.cabal view
@@ -1,5 +1,5 @@ name:                repline-version:             0.2.1.0+version:             0.2.2.0 synopsis:            Haskeline wrapper for GHCi-like REPL interfaces. license:             MIT license-file:        LICENSE@@ -31,8 +31,10 @@   build-depends:     base       >= 4.6 && <5.0,     containers >= 0.5 && <0.7,-    fail       >= 4.9 && <4.10,+    exceptions >= 0.10 && < 0.11,     mtl        >= 2.2 && <2.3,     process    >= 1.2 && <2.0,-    haskeline  >= 0.7 && <0.8+    haskeline  >= 0.7 && <0.9+  if !impl(ghc >= 8.0)+    Build-Depends: fail >= 4.9 && <4.10   default-language:    Haskell2010
src/System/Console/Repline.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE KindSignatures #-}+{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeSynonymInstances #-}@@ -104,9 +105,16 @@ -}  module System.Console.Repline (+  -- * Repline Monad   HaskelineT,   runHaskelineT, +  -- * Toplevel+  evalRepl,+  ReplOpts(..),+  evalReplOpts,++  -- * Repline Types   Cmd,   Options,   WordCompleter,@@ -114,20 +122,20 @@   CompleterStyle(..),   Command, +  -- * Completers   CompletionFunc, -- re-export    wordCompleter,   listCompleter,   fileCompleter,   listWordCompleter,-   runMatcher,-  evalRepl,+  trimComplete,++  -- * Utilities   abort,   tryAction,   dontCrash,--  trimComplete, ) where  import System.Console.Haskeline.Completion@@ -147,6 +155,7 @@ newtype HaskelineT (m :: * -> *) a = HaskelineT { unHaskeline :: H.InputT m a }  deriving (Monad, Functor, Applicative, MonadIO, MonadException, MonadTrans, MonadHaskeline) +-- | Run HaskelineT monad runHaskelineT :: MonadException m => H.Settings m -> HaskelineT m a -> m a runHaskelineT s m = H.runInputT s (H.withInterrupt (unHaskeline m)) @@ -183,11 +192,19 @@ -- Repl ------------------------------------------------------------------------------- +-- | Command function synonym type Cmd m = [String] -> m ()++-- | Options function synonym type Options m = [(String, Cmd m)]++-- | Command function synonym type Command m = String -> m () +-- | Word completer type WordCompleter m = (String -> m [String])++-- | Line completer type LineCompleter m = (String -> String -> m [Completion])  -- | Wrap a HasklineT action so that if an interrupt is thrown the shell continues as normal.@@ -205,10 +222,10 @@  -- | Completion loop. replLoop :: (Functor m, MonadException m)-         => HaskelineT m String-         -> Command (HaskelineT m)-         -> Options (HaskelineT m)-         -> Maybe Char+         => HaskelineT m String -- ^ banner function+         -> Command (HaskelineT m) -- ^ command function+         -> Options (HaskelineT m) -- ^ options function+         -> Maybe Char             -- ^ options prefix          -> HaskelineT m () replLoop banner cmdM opts optsPrefix = loop   where@@ -241,6 +258,31 @@   | s `isPrefixOf` x = m args   | otherwise = optMatcher s xs args +-------------------------------------------------------------------------------+-- Toplevel+-------------------------------------------------------------------------------++-- | REPL Options datatype+data ReplOpts m = ReplOpts {+    banner      :: HaskelineT m String    -- ^ Banner+  , command     :: Command (HaskelineT m) -- ^ Command function+  , options     :: Options (HaskelineT m) -- ^ Options list and commands+  , prefix      :: Maybe Char             -- ^ Optional command prefix ( passing Nothing ignores the Options argument )+  , tabComplete :: CompleterStyle m       -- ^ Tab completion function+  , initialiser :: HaskelineT m ()        -- ^ Initialiser+  }++-- | Evaluate the REPL logic into a MonadException context from the ReplOpts+-- configuration.+evalReplOpts :: (Functor m, MonadException m) => ReplOpts m -> m ()+evalReplOpts (ReplOpts {..}) = evalRepl+  banner+  command+  options+  prefix+  tabComplete+  initialiser+ -- | Evaluate the REPL logic into a MonadException context. evalRepl :: (Functor m, MonadException m)  -- Terminal monad ( often IO ).          => HaskelineT m String            -- ^ Banner@@ -248,7 +290,7 @@          -> 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+         -> HaskelineT m a                 -- ^ Initialiser          -> m () evalRepl banner cmd opts optsPrefix comp initz = runHaskelineT _readline (initz >> monad)   where@@ -263,8 +305,6 @@ -- Completions ------------------------------------------------------------------------------- ---type CompletionFunc m = (String, String) -> m (String, [Completion])- data CompleterStyle m   = Word (WordCompleter m)       -- ^ Completion function takes single word.   | Word0 (WordCompleter m)      -- ^ Completion function takes single word ( no space ).@@ -274,6 +314,7 @@       (CompletionFunc m)       [(String, CompletionFunc m)] -- ^ Conditional tab completion based on prefix. +-- | Make a completer function from a completion type mkCompleter :: MonadIO m => CompleterStyle m -> CompletionFunc m mkCompleter (Word f)          = completeWord (Just '\\') " \t()[]" (_simpleComplete f) mkCompleter (Word0 f)         = completeWord (Just '\\') " \t()[]" (_simpleCompleteNoSpace f)@@ -283,7 +324,7 @@  -- haskeline takes the first argument as the reversed string, don't know why unRev0 :: LineCompleter m -> LineCompleter m-unRev0 f x y = f (reverse x) y+unRev0 f x = f (reverse x)  trimComplete :: String -> Completion -> Completion trimComplete prefix (Completion a b c) = Completion (drop (length prefix) a) b c@@ -297,15 +338,18 @@ completionNoSpace :: String -> Completion completionNoSpace str = Completion str str False +-- | Word completer function wordCompleter :: Monad m => WordCompleter m -> CompletionFunc m wordCompleter f (start, n) = completeWord (Just '\\') " \t()[]" (_simpleComplete f) (start, n) +-- | List completer function listCompleter :: Monad m => [String] -> CompletionFunc m listCompleter names (start, n) = completeWord (Just '\\') " \t()[]" (_simpleComplete (complete_aux names)) (start, n)  listWordCompleter :: Monad m => [String] -> WordCompleter m listWordCompleter = complete_aux +-- | File completer function fileCompleter :: MonadIO m => CompletionFunc m fileCompleter = completeFilename @@ -321,8 +365,10 @@   | x `isPrefixOf` s = f args   | otherwise = completeMatcher def s xs args -runMatcher :: Monad m => [(String, CompletionFunc m)]-                      -> CompletionFunc m-                      -> CompletionFunc m+-- | Return a completion function a line fragment+runMatcher+  :: Monad m => [(String, CompletionFunc m)]+  -> CompletionFunc m+  -> CompletionFunc m runMatcher opts def (start, n) =   completeMatcher def (n ++ reverse start) opts (start, n)