summaryrefslogtreecommitdiff
path: root/hsm-command/Hsm/Command/Readline.hs
blob: 66246b5646ca6c4bc9fd745181868bfa95589eb4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE TypeFamilies #-}

module Hsm.Command.Readline
  ( Readline
  , readline
  , runReadline
  )
where

import Data.Function ((&))
import Effectful (Dispatch (Static), DispatchOf, Eff, Effect, IOE, (:>))
import Effectful.Dispatch.Static qualified as S
import Effectful.Log (Log, getLoggerEnv, leLogger, waitForLogger)
import Effectful.Resource (Resource, allocate)
import System.Console.Haskeline qualified as H
import System.Console.Haskeline.IO qualified as H
import Prelude hiding (takeWhile)

data Readline :: Effect

type instance DispatchOf Readline = Static S.WithSideEffects

newtype instance S.StaticRep Readline = Readline H.InputState

readline
  :: forall es
   . ( Log :> es
     , Readline :> es
     )
  => Eff es (Maybe String)
readline = do
  flushLogger
  Readline handle <- S.getStaticRep
  H.getInputLine "% "
    & H.withInterrupt
    & H.handleInterrupt (return Nothing)
    & H.queryInput handle
    & S.unsafeEff_
 where
  flushLogger :: Eff es ()
  flushLogger = getLoggerEnv >>= S.unsafeEff_ . waitForLogger . leLogger

runReadline
  :: ( IOE :> es
     , Resource :> es
     )
  => Eff (Readline : es) a
  -> Eff es a
runReadline action = do
  handle <- snd <$> allocate state H.cancelInput
  S.evalStaticRep (Readline handle) action
 where
  settings :: H.Settings IO
  settings = H.defaultSettings {H.historyFile = Just "/tmp/hsm_command_history"}

  state :: IO H.InputState
  state = H.initializeInput settings