packages feed

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 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+[![GitHub Actions](https://github.com/lehmacdj/readline-in-other-words/actions/workflows/ci.yml/badge.svg)](https://github.com/lehmacdj/readline-in-other-words/actions/workflows/ci.yml)+[![Hackage](https://img.shields.io/hackage/v/readline-in-other-words.svg?logo=haskell)](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)