readline-in-other-words (empty) → 0.1.0.0
raw patch · 8 files changed
+762/−0 lines, 8 filesdep +basedep +haskelinedep +in-other-words
Dependencies added: base, haskeline, in-other-words, in-other-words-plugin, monad-control, mtl, readline-in-other-words
Files
- ChangeLog.md +5/−0
- LICENSE +25/−0
- README.md +36/−0
- examples/Echo.hs +19/−0
- readline-in-other-words.cabal +75/−0
- src/Control/Effect/Readline.hs +77/−0
- src/Control/Effect/Readline/History.hs +14/−0
- src/Control/Effect/Readline/Internal.hs +511/−0
+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Revision history for readline-in-other-words++## 0.1.0.0 -- 2021-11-04++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,25 @@+BSD 2-Clause License++Copyright (c) 2021, Devin Lehmacher+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+ list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+ this list of conditions and the following disclaimer in the documentation+ and/or other materials provided with the distribution.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,36 @@+# readline-in-other-words+[](https://github.com/lehmacdj/readline-in-other-words/actions/workflows/ci.yml)+[](https://hackage.haskell.org/package/readline-in-other-words)++This package provides a few [in-other-words](https://github.com/KingoftheHomeless/in-other-words#readme) effects that collectively provide the full functionality of [haskeline](https://github.com/judah/haskeline#readme). See Haskeline's documentation for additional usage information.++## Example Usage+This is all it takes to write a miniature repl using this library:+```+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}++module Main where++import Control.Effect+import Control.Effect.Readline++repl :: Effs '[Readline, HandleInterrupt] m => m ()+repl = handleInterrupt (outputStrLn "Interrupt!" *> repl) $+ withInterrupt $ do+ mline <- getInputLine "> "+ case mline of+ Nothing -> pure ()+ Just line -> outputStrLn line *> repl++main :: IO ()+main = runM $ runReadline defaultSettings repl+```++This will echo whatever text you write, and catches interrupts announcing that+they occurred and preventing the program from terminating. This example is also+available as the `echo-repl` target in `examples/Echo.hs`.++## Contributions+Bug reports and PRs are welcome.
+ examples/Echo.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}++module Main where++import Control.Effect+import Control.Effect.Readline++repl :: Effs '[Readline, HandleInterrupt] m => m ()+repl = handleInterrupt (outputStrLn "Interrupt!" *> repl) $+ withInterrupt $ do+ mline <- getInputLine "> "+ case mline of+ Nothing -> pure ()+ Just line -> outputStrLn line *> repl++main :: IO ()+main = runM $ runReadline defaultSettings repl
+ readline-in-other-words.cabal view
@@ -0,0 +1,75 @@+cabal-version: 2.4+name: readline-in-other-words+synopsis: Readline effect for in-other-words.+category: User Interfaces, Effect+homepage: https://github.com/lehmacdj/readline-in-other-words#readme+bug-reports: https://github.com/lehmacdj/readline-in-other-words/issues+author: Devin Lehmacher+maintainer: Devin Lehmacher+copyright: (c) 2021 Devin Lehmacher+license: BSD-2-Clause+license-file: LICENSE+build-type: Simple+extra-source-files:+ README.md+ ChangeLog.md+description:+ This library provides effects for in-other-words offering the functionality of+ haskeline. Please see the README on GitHub at+ <https://github.com/lehmacdj/readline-in-other-words#readme> for more details.++-- version change checklist:+-- 1. changelog+-- 2. make tag; update @source-repository this@ clause+-- 3. right here+version: 0.1.0.0++source-repository head+ type: git+ location: git://github.com/lehmacdj/readline-in-other-words.git++source-repository this+ type: git+ location: git://github.com/lehmacdj/readline-in-other-words.git+ tag: 0.1.0.0++common options+ ghc-options: -Wall -fplugin=Control.Effect.Plugin+ build-depends:+ base >=4.13 && <4.17+ , haskeline >=0.8.1 && <0.8.3+ , in-other-words >=0.2.0.0 && <0.2.1.0+ , in-other-words-plugin ==0.1.0.0+ , monad-control >=1.0 && <1.1+ -- ^ same bound as in-other-words+ , mtl >=2.2 && <2.3+ -- ^ same bound as in-other-words+ default-language: Haskell2010++common exe-options+ ghc-options: -threaded -rtsopts -with-rtsopts=-N++library+ import: options+ hs-source-dirs:+ src+ exposed-modules:+ Control.Effect.Readline+ Control.Effect.Readline.History+ Control.Effect.Readline.Internal+ other-modules:+ Paths_readline_in_other_words+ autogen-modules:+ Paths_readline_in_other_words++executable echo-repl+ import: options+ import: exe-options+ hs-source-dirs: examples+ main-is: Echo.hs+ other-modules:+ Paths_readline_in_other_words+ autogen-modules:+ Paths_readline_in_other_words+ build-depends:+ readline-in-other-words
+ src/Control/Effect/Readline.hs view
@@ -0,0 +1,77 @@+-- | This libraries provides an in-other-words effect that provides interactive+-- command line usage.+--+-- This module provides the following effects:+--+-- * 'Readline' which offers basic I/O operations on the command line+--+-- * 'HandleInterrupt' which offers the ability to handle Ctrl-C interrupts+--+-- In addition to providing effects/handlers this also re-exports haskeline's+-- types/functions where relevant, so you shouldn't need to import any+-- haskeline modules.+--+-- If you need to tamper with the history functionality provided by haskeline,+-- check out "Control.Effect.Readline.History" which provides a+-- 'Control.Effect.Readline.History.ReadlineHistory' effect for doing that.+module Control.Effect.Readline+ ( -- * Effect and Actions++ -- ** Readline+ Readline (..),+ getInputLine,+ getInputLineWithInitial,+ getInputChar,+ getPassword,+ waitForAnyKey,+ outputStr,+ outputStrLn,++ -- ** HandleInterrupt+ HandleInterrupt (..),+ withInterrupt,+ handleInterrupt,+ catchInterrupt,++ -- * Interpreters+ runReadline,+ runReadlineBehavior,+ runReadlineWithPrefs,+ runReadlineBehaviorWithPrefs,+ runReadline',+ runReadlineBehavior',+ runReadlineWithPrefs',+ runReadlineBehaviorWithPrefs',++ -- * Carriers + Threading+ ReadlineC,+ ReadlineInterruptC,+ ReadlineThreads,++ -- * Re-exports from haskeline++ -- ** Settings+ H.Settings (..),+ H.defaultSettings,+ H.setComplete,++ -- *** Completion+ module System.Console.Haskeline.Completion,++ -- ** Behavior+ H.Behavior,+ H.defaultBehavior,+ H.useFileHandle,+ H.useFile,+ H.preferTerm,++ -- ** Preferences+ H.Prefs,+ H.readPrefs,+ H.defaultPrefs,+ )+where++import Control.Effect.Readline.Internal+import qualified System.Console.Haskeline as H+import System.Console.Haskeline.Completion
+ src/Control/Effect/Readline/History.hs view
@@ -0,0 +1,14 @@+-- | Provides low level access to history associated with the readline effect.+-- This effect can be interpreted using any of the interpretations using the+-- 'ReadlineC' carrier.+module Control.Effect.Readline.History+ ( ReadlineHistory (..),+ getHistory,+ putHistory,+ modifyHistory,+ module System.Console.Haskeline.History,+ )+where++import Control.Effect.Readline.Internal+import System.Console.Haskeline.History
+ src/Control/Effect/Readline/Internal.hs view
@@ -0,0 +1,511 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}++-- | __WARNING: the API of this module is not included in the PvP versioning of+-- this package.__+--+-- This module mostly exists to break a cyclic dependency between the Carrier+-- instance and 'ReadlineHistory' which isn't exported from+-- "Control.Effect.Readline".+module Control.Effect.Readline.Internal where++import Control.Effect+import Control.Effect.Carrier+import Control.Effect.Optional+import Control.Effect.Type.Bracket+import Control.Effect.Type.Fix+import Control.Effect.Type.Internal.BaseControl+import Control.Effect.Type.ListenPrim+import Control.Effect.Type.Mask+import Control.Effect.Type.Optional+import Control.Effect.Type.ReaderPrim+import Control.Effect.Type.Regional+import Control.Effect.Type.Split+import Control.Effect.Type.Unlift+import Control.Effect.Type.Unravel+import Control.Effect.Type.WriterPrim+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans.Control hiding (embed)+import qualified System.Console.Haskeline as H+import qualified System.Console.Haskeline.History as H+import Prelude++data Readline :: Effect 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 ()++-- | Reads one line of input. The final newline (if any) is removed. When using+-- terminal-style interaction, this function provides a rich line-editing user+-- interface.+--+-- If @'H.autoAddHistory' == 'True'@ and the line input is nonblank (i.e., is not all+-- spaces), it will be automatically added to the history.+getInputLine :: Eff Readline m => String -> m (Maybe String)+getInputLine = send . GetInputLine++-- | Reads one line of input and fills the insertion space with initial text. When using+-- terminal-style interaction, this function provides a rich line-editing user interface with the+-- added ability to give the user default values.+--+-- This function behaves in the exact same manner as 'H.getInputLine', except that+-- it pre-populates the input area. The text that resides in the input area is given as a 2-tuple+-- with two 'String's. The string on the left of the tuple (obtained by calling 'fst') is+-- what will appear to the left of the cursor and the string on the right (obtained by+-- calling 'snd') is what will appear to the right of the cursor.+--+-- Some examples of calling of this function are:+--+-- > getInputLineWithInitial "prompt> " ("left", "") -- The cursor starts at the end of the line.+-- > getInputLineWithInitial "prompt> " ("left ", "right") -- The cursor starts before the second word.+getInputLineWithInitial ::+ Eff Readline m => String -> (String, String) -> m (Maybe String)+getInputLineWithInitial p = send . GetInputLineWithInitial p++-- | Reads one character of input. Ignores non-printable characters.+--+-- When using terminal-style interaction, the character will be read without waiting+-- for a newline.+--+-- When using file-style interaction, a newline will be read if it is immediately+-- available after the input character.+getInputChar :: Eff Readline m => String -> m (Maybe Char)+getInputChar = send . GetInputChar++-- | Reads one line of input, without displaying the input while it is being typed.+-- When using terminal-style interaction, the masking character (if given) will replace each typed character.+--+-- When using file-style interaction, this function turns off echoing while reading+-- the line of input.+--+-- Note that if Haskeline is built against a version of the @Win32@ library+-- earlier than 2.5, 'getPassword' will incorrectly echo back input on MinTTY+-- consoles (such as Cygwin or MSYS).+getPassword :: Eff Readline m => Maybe Char -> String -> m (Maybe String)+getPassword m = send . GetPassword m++-- | Waits for one key to be pressed, then returns. Ignores the value+-- of the specific key.+--+-- Returns 'True' if it successfully accepted one key. Returns 'False'+-- if it encountered the end of input; i.e., an @EOF@ in file-style interaction,+-- or a @Ctrl-D@ in terminal-style interaction.+--+-- When using file-style interaction, consumes a single character from the input which may+-- be non-printable.+waitForAnyKey :: Eff Readline m => String -> m Bool+waitForAnyKey = send . WaitForAnyKey++-- | Write a Unicode string to the user's standard output.+outputStr :: Eff Readline m => String -> m ()+outputStr = send . OutputStr++-- | Write a Unicode string to the user's standard output, followed by a newline.+outputStrLn :: Eff Readline m => String -> m ()+outputStrLn str = outputStr (str <> "\n")++data HandleInterrupt :: Effect where+ WithInterrupt :: m a -> HandleInterrupt m a+ HandleInterrupt :: m a -> m a -> HandleInterrupt m a++-- | If Ctrl-C is pressed during the given action, enables interrupt handling+-- within the nested scope. For example:+--+-- > tryAction :: Eff '[Readline, HandleInterrupt] m => m ()+-- > tryAction = handleInterrupt (outputStrLn "Cancelled.")+-- > $ withInterrupt $ someLongAction+--+-- The action can handle the interrupt itself every time Ctrl-C is pressed.+--+-- > {-# LANGUAGE -XBlockArguments #-}+-- > tryAction :: Eff '[Readline, HandleInterrupt] m => m ()+-- > tryAction = withInterrupt loop where+-- > loop = someLongAction `catchInterrupt` do+-- > outputStrLn "Cancelled; trying again."+-- > loop+--+-- This behavior differs from GHC's built-in Ctrl-C handling, which+-- may immediately terminate the program after the second time that the user presses+-- Ctrl-C.+withInterrupt :: Eff HandleInterrupt m => m a -> m a+withInterrupt = send . WithInterrupt++-- | Handle an 'H.Interrupt'. When an interrupt occurs in the second argument,+-- the first argument will be called.+handleInterrupt :: Eff HandleInterrupt m => m a -> m a -> m a+handleInterrupt handler = send . HandleInterrupt handler++-- | Specify a continuation that should be called when an 'H.Interrupt' occurs.+--+-- > catchInterrupt = flip handleInterrupt+catchInterrupt :: Eff HandleInterrupt m => m a -> m a -> m a+catchInterrupt = flip handleInterrupt++data ReadlineHistory :: Effect where+ GetHistory :: ReadlineHistory m H.History+ PutHistory :: H.History -> ReadlineHistory m ()++-- | Get the 'H.History'.+getHistory :: Eff ReadlineHistory m => m H.History+getHistory = send GetHistory++-- | Set the 'H.History'.+putHistory :: Eff ReadlineHistory m => H.History -> m ()+putHistory = send . PutHistory++-- | Modify the 'H.History'. The modification is not atomic.+modifyHistory :: Eff ReadlineHistory m => (H.History -> H.History) -> m ()+modifyHistory f = getHistory >>= putHistory . f++-- Threading constraints + EfflyIO + HelperInputT++-- | newtype that provides MonadIO when Eff (Embed IO) m and otherwise just+-- passes through instances to the base monad+newtype EfflyIO m a = EfflyIO {unEfflyIO :: m a}+ deriving newtype+ ( Functor,+ Applicative,+ Monad,+ MonadFix,+ MonadFail,+ MonadThrow,+ MonadCatch,+ MonadMask,+ MonadBase b,+ MonadBaseControl b+ )+ deriving (MonadTrans, MonadTransControl) via IdentityT++instance Eff (Embed IO) m => MonadIO (EfflyIO m) where+ liftIO = lift . embed++-- | Version of InputT that we "own" so that we can define new instances on it,+-- in particular threading constraints without creating orphan instances.+newtype ReadlineT m a = ReadlineT {unReadlineT :: H.InputT m a}+ deriving newtype+ ( Functor,+ Applicative,+ Monad,+ MonadFix,+ MonadFail,+ MonadIO,+ MonadThrow,+ MonadCatch,+ MonadMask,+ MonadTrans+ )++instance MonadBase b m => MonadBase b (ReadlineT m) where+ liftBase b = lift $ liftBase b++instance MonadBaseControl b m => MonadBaseControl b (ReadlineT m) where+ type StM (ReadlineT m) a = StM m a+ liftBaseWith f =+ ReadlineT $+ H.withRunInBase $ \runInputTInBase ->+ liftBaseWith $ \runMInBase ->+ f (runMInBase . runInputTInBase . unReadlineT)+ restoreM = lift . restoreM++instance ThreadsEff ReadlineT (Unravel p) where+ threadEff alg (Unravel p cataM main) =+ ReadlineT $+ H.withRunInBase $ \runInBase ->+ alg $ Unravel p (cataM . lift) (runInBase . unReadlineT $ main)++instance ThreadsEff ReadlineT (Regional s) where+ threadEff = threadRegionalViaOptional++instance ThreadsEff ReadlineT Mask where+ threadEff = threadMaskViaClass++instance Functor s => ThreadsEff ReadlineT (Optional s) where+ threadEff = threadOptionalViaBaseControl++instance ThreadsEff ReadlineT (ReaderPrim i) where+ threadEff = threadReaderPrimViaRegional++instance Monoid o => ThreadsEff ReadlineT (WriterPrim o) where+ threadEff = threadWriterPrim $ \alg m -> ReadlineT $+ H.withRunInBase $ \runInBase ->+ alg $ WriterPrimPass $ runInBase . unReadlineT $ m++instance ThreadsEff ReadlineT Bracket where+ threadEff = threadBracketViaClass++instance ThreadsEff ReadlineT (Unlift b) where+ threadEff alg (Unlift main) =+ ReadlineT $+ H.withRunInBase $ \runInBase ->+ alg $ Unlift $ \lower -> main (lower . runInBase . unReadlineT)++instance ThreadsEff ReadlineT Split where+ threadEff alg (Split c m) =+ ReadlineT $+ H.withRunInBase $ \runInBase ->+ alg $ Split (c . (fmap . fmap) lift) (runInBase . unReadlineT $ m)++instance Monoid o => ThreadsEff ReadlineT (ListenPrim o) where+ threadEff = threadListenPrim $ \alg m -> ReadlineT $+ H.withRunInBase $ \runInBase ->+ alg $ ListenPrimListen $ runInBase . unReadlineT $ m++instance ThreadsEff ReadlineT (BaseControl b) where+ threadEff = threadBaseControlViaClass++instance ThreadsEff ReadlineT Fix where+ threadEff = threadFixViaClass++-- | Threading constraint for handlers using 'H.InputT'/'ReadlineT' internally.+--+-- 'ReadlineThreads' accepts all the primitive effects+-- (intended to be used as such) offered by in-other-words.+--+-- Most notably, 'ReadlineThreads' accepts @'Control.Effect.Unlift.Unlift' b@.+class Threads ReadlineT p => ReadlineThreads p++instance Threads ReadlineT p => ReadlineThreads p++-- -- | A pseudo-effect providing the full haskeline functionality in a single+-- -- effect.+--+-- -- @'Haskeline'@ should only ever be used inside of 'Eff' and 'Effs'+-- -- constraints. It is not a real effect! See 'Control.Effect.Bundle'.+-- type Haskeline = Bundle [Readline, ReadlineHistory, HandleInterrupt]++newtype ReadlineC m a = ReadlineC {unReadlineC :: ReadlineT (EfflyIO m) a}+ deriving newtype+ ( Functor,+ Applicative,+ Monad,+ MonadFix,+ MonadFail,+ MonadThrow,+ MonadCatch,+ MonadMask,+ MonadBase b,+ MonadBaseControl b+ )+ deriving (MonadTrans) via ReadlineT++deriving newtype instance Eff (Embed IO) m => MonadIO (ReadlineC m)++readlineC :: H.InputT (EfflyIO m) a -> ReadlineC m a+readlineC = coerce++runReadlineC ::+ (H.InputT (EfflyIO m) a -> EfflyIO m a) -> ReadlineC m a -> m a+runReadlineC = coerce++instance+ ( Carrier m,+ Eff (Embed IO) m,+ MonadMask m,+ Threads ReadlineT (Prims m)+ ) =>+ Carrier (ReadlineC m)+ where+ type Derivs (ReadlineC m) = Readline ': ReadlineHistory ': Derivs m+ type Prims (ReadlineC m) = Prims m+ algPrims = coerce (thread @ReadlineT (algPrims @m))+{- ORMOLU_DISABLE -}+ reformulate =+ addDeriv+ ( \case+ GetInputLine p -> liftBase $ readlineC $ H.getInputLine p+ GetInputLineWithInitial p i -> liftBase $ readlineC $ H.getInputLineWithInitial p i+ GetInputChar p -> liftBase $ readlineC $ H.getInputChar p+ GetPassword m p -> liftBase $ readlineC $ H.getPassword m p+ WaitForAnyKey p -> liftBase $ readlineC $ H.waitForAnyKey p+ OutputStr s -> liftBase $ readlineC $ H.outputStr s+ ) $+ addDeriv+ ( \case+ GetHistory -> liftBase $ readlineC H.getHistory+ PutHistory h -> liftBase $ readlineC $ H.putHistory h+ ) $+ liftReform $+ reformulate @m+{- ORMOLU_ENABLE -}++newtype ReadlineInterruptC m a = ReadlineInterruptC {unReadlineInterruptC :: ReadlineT (EfflyIO m) a}+ deriving newtype+ ( Functor,+ Applicative,+ Monad,+ MonadFix,+ MonadFail,+ MonadThrow,+ MonadCatch,+ MonadMask,+ MonadBase b,+ MonadBaseControl b+ )+ deriving (MonadTrans) via ReadlineT++deriving newtype instance Eff (Embed IO) m => MonadIO (ReadlineInterruptC m)++readlineInterruptC :: H.InputT (EfflyIO m) a -> ReadlineInterruptC m a+readlineInterruptC = coerce++runReadlineInterruptC ::+ (H.InputT (EfflyIO m) a -> EfflyIO m a) -> ReadlineInterruptC m a -> m a+runReadlineInterruptC = coerce++-- | Type for denoting which kind of 'Optional' we are inside of.+data WithOrHandleInterrupt a+ = WithInterrupts+ | OnInterruptContinueWith a++instance+ ( Carrier m,+ Eff (Embed IO) m,+ MonadMask m,+ Threads ReadlineT (Prims m)+ ) =>+ Carrier (ReadlineInterruptC m)+ where+ type Derivs (ReadlineInterruptC m) = HandleInterrupt ': Derivs (ReadlineC m)+ type Prims (ReadlineInterruptC m) = Optional WithOrHandleInterrupt ': Prims (ReadlineC m)+ algPrims = powerAlg (coerce (algPrims @(ReadlineC m))) $ \case+ Optionally WithInterrupts a ->+ readlineInterruptC $ H.withInterrupt (unReadlineT $ unReadlineInterruptC a)+ Optionally (OnInterruptContinueWith c) a ->+ readlineInterruptC $ H.handleInterrupt (pure c) (unReadlineT $ unReadlineInterruptC a)+{- ORMOLU_DISABLE -}+ reformulate =+ weakenReformUnder1 $+ addDeriv+ ( \case+ WithInterrupt a -> join $ optionally WithInterrupts (fmap pure a)+ HandleInterrupt c a ->+ join $ optionally (OnInterruptContinueWith c) (fmap pure a)+ ) $+ addPrim $+ coerceReform $+ reformulate @(ReadlineC m)+{- ORMOLU_ENABLE -}++-- | Main interpreter for 'Readline', 'ReadlineHistory', and 'HandleInterrupt'+-- effects. 'H.defaultSettings' exists as a default for settings.+--+-- Example usage:+--+-- > import Control.Effect+-- > import Control.Effect.Readline+-- >+-- > repl :: Effs '[Readline, HandleInterrupt] m => m ()+-- > repl = handleInterrupt (outputStrLn "Interrupt!" *> repl) $+-- > withInterrupt $ do+-- > mline <- getInputLine "> "+-- > case mline of+-- > Nothing -> pure ()+-- > Just line -> outputStrLn line *> repl+-- >+-- > main :: IO ()+-- > main = runM $ runReadline defaultSettings repl+runReadline ::+ (Eff (Embed IO) m, MonadMask m, Carrier m, Threaders '[ReadlineThreads] m p) =>+ H.Settings m ->+ ReadlineInterruptC m a ->+ m a+runReadline settings =+ unEfflyIO . H.runInputT (coerce settings) . unReadlineT . unReadlineInterruptC++-- | Like 'runReadline' but additionally allows specifying a 'H.Behavior'.+runReadlineBehavior ::+ (Eff (Embed IO) m, MonadMask m, Carrier m, Threaders '[ReadlineThreads] m p) =>+ H.Behavior ->+ H.Settings m ->+ ReadlineInterruptC m a ->+ m a+runReadlineBehavior behavior settings =+ runReadlineInterruptC $ H.runInputTBehavior behavior (coerce settings)++-- | Like 'runReadline' but additionally allows specifying a 'H.Prefs'.+runReadlineWithPrefs ::+ (Eff (Embed IO) m, MonadMask m, Carrier m, Threaders '[ReadlineThreads] m p) =>+ H.Prefs ->+ H.Settings m ->+ ReadlineInterruptC m a ->+ m a+runReadlineWithPrefs prefs settings =+ runReadlineInterruptC $ H.runInputTWithPrefs prefs (coerce settings)++-- | Like 'runReadline' but additionally allows specifying a 'H.Behavior' and a+-- 'H.Prefs'.+runReadlineBehaviorWithPrefs ::+ (Eff (Embed IO) m, MonadMask m, Carrier m, Threaders '[ReadlineThreads] m p) =>+ H.Behavior ->+ H.Prefs ->+ H.Settings m ->+ ReadlineInterruptC m a ->+ m a+runReadlineBehaviorWithPrefs behavior prefs settings =+ runReadlineInterruptC $ H.runInputTBehaviorWithPrefs behavior prefs (coerce settings)++-- | Weaker version of 'runReadline' intended for circumstances where the+-- primitive effect 'Optional' can't be threaded. This version is incapable of+-- interpreting 'HandleInterrupt' though.+runReadline' ::+ (Eff (Embed IO) m, MonadMask m, Carrier m, Threaders '[ReadlineThreads] m p) =>+ H.Settings m ->+ ReadlineC m a ->+ m a+runReadline' settings = runReadlineC $ H.runInputT (coerce settings)++-- | Weaker version of 'runReadlineBehavior' intended for circumstances where+-- the primitive effect 'Optional' can't be threaded. This version is incapable+-- of interpreting 'HandleInterrupt' though.+runReadlineBehavior' ::+ (Eff (Embed IO) m, MonadMask m, Carrier m, Threaders '[ReadlineThreads] m p) =>+ H.Behavior ->+ H.Settings m ->+ ReadlineC m a ->+ m a+runReadlineBehavior' behavior settings =+ runReadlineC $ H.runInputTBehavior behavior (coerce settings)++-- | Weaker version of 'runReadlineWithPrefs' intended for circumstances where+-- the primitive effect 'Optional' can't be threaded. This version is incapable+-- of interpreting 'HandleInterrupt' though.+runReadlineWithPrefs' ::+ (Eff (Embed IO) m, MonadMask m, Carrier m, Threaders '[ReadlineThreads] m p) =>+ H.Prefs ->+ H.Settings m ->+ ReadlineC m a ->+ m a+runReadlineWithPrefs' prefs settings =+ runReadlineC $ H.runInputTWithPrefs prefs (coerce settings)++-- | Weaker version of 'runReadlineBehaviorWithPrefs' intended for+-- circumstances where the primitive effect 'Optional' can't be threaded. This+-- version is incapable of interpreting 'HandleInterrupt' though.+runReadlineBehaviorWithPrefs' ::+ (Eff (Embed IO) m, MonadMask m, Carrier m, Threaders '[ReadlineThreads] m p) =>+ H.Behavior ->+ H.Prefs ->+ H.Settings m ->+ ReadlineC m a ->+ m a+runReadlineBehaviorWithPrefs' behavior prefs settings =+ runReadlineC $ H.runInputTBehaviorWithPrefs behavior prefs (coerce settings)