packages feed

polysemy-readline 0.2.0.0 → 0.3.0.0

raw patch · 5 files changed

+68/−55 lines, 5 filesdep ~basedep ~polysemydep ~polysemy-pluginPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, polysemy, polysemy-plugin

API changes (from Hackage documentation)

+ Polysemy.Readline: [HandleInterrupt] :: forall (m :: Type -> Type) a. m a -> m a -> Readline m a
+ Polysemy.Readline: [WithInterrupt] :: forall (m :: Type -> Type) a. m a -> Readline m a
+ Polysemy.Readline: handleInterrupt :: forall (r :: EffectRow) a. Member Readline r => Sem r a -> Sem r a -> Sem r a
+ Polysemy.Readline: withInterrupt :: forall (r :: EffectRow) a. Member Readline r => Sem r a -> Sem r a
- Polysemy.Readline: [GetInputChar] :: String -> Readline m (Maybe Char)
+ Polysemy.Readline: [GetInputChar] :: forall (m :: Type -> Type). String -> Readline m (Maybe Char)
- Polysemy.Readline: [GetInputLineWithInitial] :: String -> (String, String) -> Readline m (Maybe String)
+ Polysemy.Readline: [GetInputLineWithInitial] :: forall (m :: Type -> Type). String -> (String, String) -> Readline m (Maybe String)
- Polysemy.Readline: [GetInputLine] :: String -> Readline m (Maybe String)
+ Polysemy.Readline: [GetInputLine] :: forall (m :: Type -> Type). String -> Readline m (Maybe String)
- Polysemy.Readline: [GetPassword] :: Maybe Char -> String -> Readline m (Maybe String)
+ Polysemy.Readline: [GetPassword] :: forall (m :: Type -> Type). Maybe Char -> String -> Readline m (Maybe String)
- Polysemy.Readline: [OutputStr] :: String -> Readline m ()
+ Polysemy.Readline: [OutputStr] :: forall (m :: Type -> Type). String -> Readline m ()
- Polysemy.Readline: [WaitForAnyKey] :: String -> Readline m Bool
+ Polysemy.Readline: [WaitForAnyKey] :: forall (m :: Type -> Type). String -> Readline m Bool
- Polysemy.Readline: data Readline (m :: * -> *) a
+ Polysemy.Readline: data Readline (m :: Type -> Type) a
- Polysemy.Readline: getInputChar :: forall r_acke. MemberWithError Readline r_acke => String -> Sem r_acke (Maybe Char)
+ Polysemy.Readline: getInputChar :: forall (r :: EffectRow). Member Readline r => String -> Sem r (Maybe Char)
- Polysemy.Readline: getInputLine :: forall r_ack9. MemberWithError Readline r_ack9 => String -> Sem r_ack9 (Maybe String)
+ Polysemy.Readline: getInputLine :: forall (r :: EffectRow). Member Readline r => String -> Sem r (Maybe String)
- Polysemy.Readline: getInputLineWithInitial :: forall r_ackb. MemberWithError Readline r_ackb => String -> (String, String) -> Sem r_ackb (Maybe String)
+ Polysemy.Readline: getInputLineWithInitial :: forall (r :: EffectRow). Member Readline r => String -> (String, String) -> Sem r (Maybe String)
- Polysemy.Readline: getPassword :: forall r_ackg. MemberWithError Readline r_ackg => Maybe Char -> String -> Sem r_ackg (Maybe String)
+ Polysemy.Readline: getPassword :: forall (r :: EffectRow). Member Readline r => Maybe Char -> String -> Sem r (Maybe String)
- Polysemy.Readline: interpretReadlineAsInputT :: forall m r a. (MonadIO m, MonadMask m, Member (Embed (InputT m)) r) => Sem (Readline : r) a -> Sem r a
+ Polysemy.Readline: interpretReadlineAsInputT :: forall (m :: Type -> Type) (r :: EffectRow) a. (MonadIO m, MonadMask m, Member (Embed (InputT m)) r) => Sem (Readline ': r) a -> Sem r a
- Polysemy.Readline: outputStr :: forall r_ackl. MemberWithError Readline r_ackl => String -> Sem r_ackl ()
+ Polysemy.Readline: outputStr :: forall (r :: EffectRow). Member Readline r => String -> Sem r ()
- Polysemy.Readline: outputStrLn :: Member Readline r => String -> Sem r ()
+ Polysemy.Readline: outputStrLn :: forall (r :: EffectRow). Member Readline r => String -> Sem r ()
- Polysemy.Readline: runReadline :: forall m r a. (MonadIO m, MonadMask m, Member (Embed m) r) => Settings m -> Sem (Readline : r) a -> Sem r a
+ Polysemy.Readline: runReadline :: (MonadIO m, MonadMask m) => Settings m -> Sem '[Readline] a -> m a
- Polysemy.Readline: runReadlineFinal :: forall m r a. (MonadIO m, MonadMask m, Member (Final (InputT m)) r) => Sem (Readline : r) a -> Sem r a
+ Polysemy.Readline: runReadlineFinal :: forall (m :: Type -> Type) (r :: EffectRow) a. (MonadIO m, MonadMask m, Member (Final (InputT m)) r) => Sem (Readline ': r) a -> Sem r a
- Polysemy.Readline: waitForAnyKey :: forall r_ackj. MemberWithError Readline r_ackj => String -> Sem r_ackj Bool
+ Polysemy.Readline: waitForAnyKey :: forall (r :: EffectRow). Member Readline r => String -> Sem r Bool

Files

ChangeLog.md view
@@ -2,10 +2,12 @@  ## Unreleased Changes +## 0.3.0.0 - October 3 2025+- Deprecate `interpretReadlineAsInputT` as it wasn't possible to support interrupts using it alone+- Bump GHC versions+ ## 0.2.0.0 - July 27th 2021-- Add `runReadlineFinal` and improved instructions for mitigating lack of-  support for repl history when using `runReadline` in the simplest way-  possible.+- Add `runReadlineFinal` and improved instructions for mitigating lack of support for repl history when using `runReadline` in the simplest way possible.  ## 0.1.0.0 — June 24th 2021 - Release candidate for Hackage.
README.md view
@@ -6,9 +6,8 @@  ## Contributions Bug reports and PRs are welcome. In particular there are a number of things that I don't use frequently enough from Haskeline to justify working on or just haven't gotten around to implementing yet:-- interrupt handling: `withInterrupt`, `handleInterrupt`+- version bumps for dependencies that already compile but aren't allowed - pure interpreter for use in tests - support for older versions of Haskeline (currently only 0.8.1+ is supported)-- version bumps for dependencies that already compile but aren't allowed  PRs for any of these things would be greatly appreciated or I will try to get around to implementing them myself later 🙂.
examples/Echo.hs view
@@ -17,6 +17,5 @@ main =   runInputT defaultSettings     . runFinal-    . embedToFinal-    . interpretReadlineAsInputT+    . runReadlineFinal     $ repl
polysemy-readline.cabal view
@@ -1,8 +1,8 @@-cabal-version: 2.2+cabal-version: 3.0  name:           polysemy-readline synopsis:       Readline effect for polysemy.-version:        0.2.0.0+version:        0.3.0.0 category:       User Interfaces, Effect homepage:       https://github.com/lehmacdj/polysemy-readline#readme bug-reports:    https://github.com/lehmacdj/polysemy-readline/issues@@ -12,7 +12,10 @@ license:        BSD-2-Clause license-file:   LICENSE build-type:     Simple-extra-source-files:+tested-with:    GHC == 9.2.5+              , GHC == 9.10.1+              , GHC == 9.12.1+extra-doc-files:     README.md     ChangeLog.md description:@@ -31,11 +34,11 @@                -flate-specialise                -fspecialise-aggressively   build-depends:-      base >=4.12 && <4.15+      base >=4.12 && <5     , exceptions >=0.10.4 && <0.11     , haskeline >=0.8.1 && <0.9.0-    , polysemy >=1.5.0 && <1.6-    , polysemy-plugin >=0.3.0 && <0.4+    , polysemy >=1.5.0 && <1.10+    , polysemy-plugin >=0.3.0 && <0.5   default-language: Haskell2010  common exe-options
src/Polysemy/Readline.hs view
@@ -20,70 +20,64 @@     waitForAnyKey,     outputStr,     outputStrLn,+    withInterrupt,+    handleInterrupt,      -- * Interpreters     runReadline,     runReadlineFinal,-    interpretReadlineAsInputT,      -- * Re-exports from @haskeline@     H.Settings (..),     H.defaultSettings,     H.runInputT,++    -- * Deprecated+    interpretReadlineAsInputT,   ) where  import Control.Monad.Catch import Control.Monad.IO.Class import Polysemy-import Polysemy.Embed+import Polysemy.Final import qualified System.Console.Haskeline as H  -- | For documentation on actions see haskeline's functions with the same name -- and similar type signatures.-data Readline (m :: * -> *) a where+data Readline m a where   GetInputLine :: String -> Readline m (Maybe String)   GetInputLineWithInitial :: String -> (String, String) -> Readline m (Maybe String)   GetInputChar :: String -> Readline m (Maybe Char)   GetPassword :: Maybe Char -> String -> Readline m (Maybe String)   WaitForAnyKey :: String -> Readline m Bool   OutputStr :: String -> Readline m ()---- TODO(Devin): add these two values as well--- WithInterrupt :: m a -> Readline m a--- HandleInterrupt :: m a -> m a -> Readline m a+  WithInterrupt :: m a -> Readline m a+  HandleInterrupt :: m a -> m a -> Readline m a  makeSem ''Readline -outputStrLn :: Member Readline r => String -> Sem r ()+outputStrLn :: (Member Readline r) => String -> Sem r () outputStrLn str = outputStr (str <> "\n") --- | The simplest way to run a Readline effect. Immediately eliminates the--- resulting 'H.InputT'. There is one problem with this approach however.--- Internal details of polysemy cause 'H.runInputT' to be run once per effect--- call (e.g. @getInputLine "> " >> getInputLine "> "@ will result in two calls--- to 'H.runInputT'), and the History state of consecutive runs is not--- preserved unless there is a history file. If you want history for your repl--- there are therefore two recommended approaches:+-- | The simplest way to run a Readline effect. Runs the entire Readline+-- computation in a single 'H.runInputT' call, preserving history state between+-- effect calls. This is the recommended approach for most use cases. ----- * Provide a history file in the settings you specify. e.g.--- @runReadline ('H.defaultSettings' {historyFile = Just ".repl_history"})@.--- This is the easiest approach but technically suboptimal because the history--- file will be read between every different primitive effect call.--- * Use 'interpretReadlineAsInputT' or 'runReadlineFinal' and keep the--- `H.InputT` around until after using 'runFinal' to escape polysemy land. This--- way state can be preserved between effect calls. For an example using this--- see @examples/Echo.hs@.+-- For more control over when 'H.runInputT' is invoked, use 'runReadlineFinal'+-- directly and manage the 'H.InputT' context yourself. See @examples/Echo.hs@+-- for an example. runReadline ::-  forall m r a.-  (MonadIO m, MonadMask m, Member (Embed m) r) =>+  forall m a.+  (MonadIO m, MonadMask m) =>   H.Settings m ->-  Sem (Readline : r) a ->-  Sem r a-runReadline settings =-  runEmbedded (H.runInputT settings)-    . interpretReadlineAsInputT-    . raiseUnder @(Embed (H.InputT m))+  Sem '[Readline] a ->+  m a+runReadline settings sem =+  H.runInputT settings $+    runFinal $+      runReadlineFinal $+        raiseUnder @(Final (H.InputT m)) sem  -- | Interpreter for the somewhat common case of wanting to keep InputT around -- until after 'runFinal' to ensure that state is preserved between subsequent@@ -93,22 +87,38 @@   (MonadIO m, MonadMask m, Member (Final (H.InputT m)) r) =>   Sem (Readline : r) a ->   Sem r a-runReadlineFinal =-  embedToFinal-    . interpretReadlineAsInputT-    . raiseUnder @(Embed (H.InputT m))+runReadlineFinal = interpretFinal $ \case+  GetInputLine prompt -> liftS $ H.getInputLine prompt+  GetInputLineWithInitial prompt initial -> liftS $ H.getInputLineWithInitial prompt initial+  GetInputChar prompt -> liftS $ H.getInputChar prompt+  GetPassword maskChar prompt -> liftS $ H.getPassword maskChar prompt+  WaitForAnyKey prompt -> liftS $ H.waitForAnyKey prompt+  OutputStr str -> liftS $ H.outputStr str+  WithInterrupt action -> do+    action' <- runS action+    pure $ H.withInterrupt action'+  HandleInterrupt handler action -> do+    handler' <- runS handler+    action' <- runS action+    pure $ H.handleInterrupt handler' action'  -- | Interpret in terms of an embedded 'H.InputT' stack.+--+-- Using this is deprecated in favor of 'runReadlineFinal'. Errors when+-- handling 'WithInterrupt' and 'HandleInterrupt', they are not supported. interpretReadlineAsInputT ::   forall m r a.   (MonadIO m, MonadMask m, Member (Embed (H.InputT m)) r) =>   Sem (Readline : r) a ->   Sem r a-interpretReadlineAsInputT = interpret $ \case-  GetInputLine prompt -> embed $ H.getInputLine prompt+interpretReadlineAsInputT = interpretH $ \case+  GetInputLine prompt -> pureT =<< embed (H.getInputLine prompt)   GetInputLineWithInitial prompt initial ->-    embed $ H.getInputLineWithInitial prompt initial-  GetInputChar prompt -> embed $ H.getInputChar prompt-  GetPassword maskChar prompt -> embed $ H.getPassword maskChar prompt-  WaitForAnyKey prompt -> embed $ H.waitForAnyKey prompt-  OutputStr str -> embed $ H.outputStr str+    pureT =<< embed (H.getInputLineWithInitial prompt initial)+  GetInputChar prompt -> pureT =<< embed (H.getInputChar prompt)+  GetPassword maskChar prompt -> pureT =<< embed (H.getPassword maskChar prompt)+  WaitForAnyKey prompt -> pureT =<< embed (H.waitForAnyKey prompt)+  OutputStr str -> pureT =<< embed (H.outputStr str)+  WithInterrupt _ -> error "interpretReadlineAsInputT: WithInterrupt not supported"+  HandleInterrupt _ _ -> error "interpretReadlineAsInputT: HandleInterrupt not supported"+{-# DEPRECATED interpretReadlineAsInputT "Use runReadlineFinal instead" #-}