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 +5/−3
- README.md +1/−2
- examples/Echo.hs +1/−2
- polysemy-readline.cabal +9/−6
- src/Polysemy/Readline.hs +52/−42
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" #-}