-- The error screen, showing a current error condition (such as a parse error after reloading the journal)

{-# LANGUAGE FlexibleContexts  #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}
{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}

module Hledger.UI.ErrorScreen
 (esNew
 ,esUpdate
 ,esDraw
 ,esHandle
 ,uiCheckBalanceAssertions
 ,uiReload
 ,uiReloadIfFileChanged
 ,uiToggleBalanceAssertions
 )
where

import Brick
-- import Brick.Widgets.Border ("border")
import Control.Monad.IO.Class (liftIO)
import Data.Time.Calendar (Day)
import Data.Void (Void)
import Graphics.Vty (Event(..),Key(..),Modifier(..))
import Lens.Micro ((^.))
import Safe (headMay)
import Text.Megaparsec
import Text.Megaparsec.Char

import Hledger.Cli hiding (mode, progname,prognameandversion)
import Hledger.UI.UIOptions
import Hledger.UI.UITypes
import Hledger.UI.UIState
import Hledger.UI.UIUtils
import Hledger.UI.UIScreens
import Hledger.UI.Editor

esDraw :: UIState -> [Widget Name]
esDraw :: UIState -> [Widget Name]
esDraw UIState{aScreen :: UIState -> Screen
aScreen=ES ESS{String
()
_essError :: String
_essUnused :: ()
_essError :: ErrorScreenState -> String
_essUnused :: ErrorScreenState -> ()
..}
              ,aMode :: UIState -> Mode
aMode=Mode
mode
              } =
  case Mode
mode of
    Mode
Help       -> [Widget Name
helpDialog, Widget Name
maincontent]
    Mode
_          -> [Widget Name
maincontent]
  where
    maincontent :: Widget Name
maincontent = Size -> Size -> RenderM Name (Result Name) -> Widget Name
forall n. Size -> Size -> RenderM n (Result n) -> Widget n
Widget Size
Greedy Size
Greedy (RenderM Name (Result Name) -> Widget Name)
-> RenderM Name (Result Name) -> Widget Name
forall a b. (a -> b) -> a -> b
$ do
      Widget Name -> RenderM Name (Result Name)
forall n. Widget n -> RenderM n (Result n)
render (Widget Name -> RenderM Name (Result Name))
-> Widget Name -> RenderM Name (Result Name)
forall a b. (a -> b) -> a -> b
$ Widget Name -> Widget Name -> Widget Name -> Widget Name
defaultLayout Widget Name
forall {n}. Widget n
toplabel Widget Name
bottomlabel (Widget Name -> Widget Name) -> Widget Name -> Widget Name
forall a b. (a -> b) -> a -> b
$ AttrName -> Widget Name -> Widget Name
forall n. AttrName -> Widget n -> Widget n
withAttr (String -> AttrName
attrName String
"error") (Widget Name -> Widget Name) -> Widget Name -> Widget Name
forall a b. (a -> b) -> a -> b
$ String -> Widget Name
forall n. String -> Widget n
str (String -> Widget Name) -> String -> Widget Name
forall a b. (a -> b) -> a -> b
$ String
_essError
      where
        toplabel :: Widget n
toplabel =
              AttrName -> Widget n -> Widget n
forall n. AttrName -> Widget n -> Widget n
withAttr (String -> AttrName
attrName String
"border" AttrName -> AttrName -> AttrName
forall a. Semigroup a => a -> a -> a
<> String -> AttrName
attrName String
"bold") (String -> Widget n
forall n. String -> Widget n
str String
"Oops. Please fix this problem then press g to reload")
              -- <+> (if ignore_assertions_ copts then withAttr ("border" <> "query") (str " ignoring") else str " not ignoring")

        bottomlabel :: Widget Name
bottomlabel = Widget Name
quickhelp
                        -- case mode of
                        -- Minibuffer ed -> minibuffer ed
                        -- _             -> quickhelp
          where
            quickhelp :: Widget Name
quickhelp = [(String, String)] -> Widget Name
borderKeysStr [
               (String
"h", String
"help")
              ,(String
"ESC", String
"cancel/top")
              ,(String
"E", String
"editor")
              ,(String
"g", String
"reload")
              ,(String
"q", String
"quit")
              ]

esDraw UIState
_ = String -> [Widget Name]
forall a. String -> a
error' String
"draw function called with wrong screen type, should not happen"  -- PARTIAL:

esHandle :: BrickEvent Name AppEvent -> EventM Name UIState ()
esHandle :: BrickEvent Name AppEvent -> EventM Name UIState ()
esHandle BrickEvent Name AppEvent
ev = do
  ui0 <- EventM Name UIState UIState
get'
  case ui0 of
    ui :: UIState
ui@UIState{aScreen :: UIState -> Screen
aScreen=ES ESS{String
()
_essError :: ErrorScreenState -> String
_essUnused :: ErrorScreenState -> ()
_essError :: String
_essUnused :: ()
..}
              ,aopts :: UIState -> UIOpts
aopts=UIOpts{uoCliOpts :: UIOpts -> CliOpts
uoCliOpts=CliOpts
copts}
              ,ajournal :: UIState -> Journal
ajournal=Journal
j
              ,aMode :: UIState -> Mode
aMode=Mode
mode
              } ->
      case Mode
mode of
        Mode
Help ->
          case BrickEvent Name AppEvent
ev of
            VtyEvent (EvKey (KChar Char
'q') []) -> EventM Name UIState ()
forall n s. EventM n s ()
halt
            VtyEvent (EvKey (KChar Char
'l') [Modifier
MCtrl]) -> EventM Name UIState ()
forall n s. EventM n s ()
redraw
            VtyEvent (EvKey (KChar Char
'z') [Modifier
MCtrl]) -> UIState -> EventM Name UIState ()
forall a s. Ord a => s -> EventM a s ()
suspend UIState
ui
            BrickEvent Name AppEvent
_                    -> BrickEvent Name AppEvent -> EventM Name UIState ()
helpHandle BrickEvent Name AppEvent
ev

        Mode
_ -> do
          d <- IO Day -> EventM Name UIState Day
forall a. IO a -> EventM Name UIState a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO Day
getCurrentDay
          case ev of
            VtyEvent (EvKey (KChar Char
'q') []) -> EventM Name UIState ()
forall n s. EventM n s ()
halt
            VtyEvent (EvKey Key
KEsc        []) -> UIState -> EventM Name UIState ()
put' (UIState -> EventM Name UIState ())
-> UIState -> EventM Name UIState ()
forall a b. (a -> b) -> a -> b
$ Day -> UIState -> UIState
uiCheckBalanceAssertions Day
d (UIState -> UIState) -> UIState -> UIState
forall a b. (a -> b) -> a -> b
$ Day -> UIState -> UIState
resetScreens Day
d UIState
ui
            VtyEvent (EvKey (KChar Char
c)   []) | Char
c Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char
'h',Char
'?'] -> UIState -> EventM Name UIState ()
put' (UIState -> EventM Name UIState ())
-> UIState -> EventM Name UIState ()
forall a b. (a -> b) -> a -> b
$ Mode -> UIState -> UIState
setMode Mode
Help UIState
ui

            -- g or file change: reload the journal and rebuild app state.
            BrickEvent Name AppEvent
e | BrickEvent Name AppEvent
e BrickEvent Name AppEvent -> [BrickEvent Name AppEvent] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Event -> BrickEvent Name AppEvent
forall n e. Event -> BrickEvent n e
VtyEvent (Key -> [Modifier] -> Event
EvKey (Char -> Key
KChar Char
'g') []), AppEvent -> BrickEvent Name AppEvent
forall n e. e -> BrickEvent n e
AppEvent AppEvent
FileChange] -> CliOpts -> Day -> UIState -> EventM Name UIState ()
esReload CliOpts
copts Day
d UIState
ui

            -- E: run editor, reload the journal.
            VtyEvent (EvKey (KChar Char
'E') []) -> do
              IO ExitCode -> EventM Name UIState ExitCode
forall n a s. Ord n => IO a -> EventM n s a
suspendAndResume' (IO ExitCode -> EventM Name UIState ExitCode)
-> IO ExitCode -> EventM Name UIState ExitCode
forall a b. (a -> b) -> a -> b
$ do
                let
                  (Maybe (Int, Maybe Int)
pos,String
f) = case Parsec Void String (String, Int, Int)
-> String
-> Either (ParseErrorBundle String Void) (String, Int, Int)
forall e a.
Parsec e String a -> String -> Either (ParseErrorBundle String e) a
parsewithString Parsec Void String (String, Int, Int)
forall (t :: * -> *). ParsecT Void String t (String, Int, Int)
hledgerparseerrorpositionp String
_essError of
                              Right (String
f',Int
l,Int
c) -> ((Int, Maybe Int) -> Maybe (Int, Maybe Int)
forall a. a -> Maybe a
Just (Int
l, Int -> Maybe Int
forall a. a -> Maybe a
Just Int
c),String
f')
                              Left  ParseErrorBundle String Void
_       -> (Maybe (Int, Maybe Int)
endPosition, Journal -> String
journalFilePath Journal
j)
                Maybe (Int, Maybe Int) -> String -> IO ExitCode
runEditor Maybe (Int, Maybe Int)
pos String
f
              CliOpts -> Day -> Journal -> UIState -> EventM Name UIState ()
esReloadIfFileChanged CliOpts
copts Day
d Journal
j UIState
ui

            VtyEvent (EvKey (KChar Char
'I') []) -> Day -> UIState -> EventM Name UIState ()
uiToggleBalanceAssertions Day
d (UIState -> UIState
popScreen UIState
ui)
            VtyEvent (EvKey (KChar Char
'l') [Modifier
MCtrl]) -> EventM Name UIState ()
forall n s. EventM n s ()
redraw
            VtyEvent (EvKey (KChar Char
'z') [Modifier
MCtrl]) -> UIState -> EventM Name UIState ()
forall a s. Ord a => s -> EventM a s ()
suspend UIState
ui
            BrickEvent Name AppEvent
_ -> () -> EventM Name UIState ()
forall a. a -> EventM Name UIState a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

    UIState
_ -> String -> EventM Name UIState ()
forall a. String -> a
errorWrongScreenType String
"esHandle"

    where
      -- Reload and fully regenerate the error screen.
      -- XXX On an error screen below the transaction screen, this is tricky because of a current limitation of regenerateScreens.
      -- For now we try to work around by re-entering the transaction screen.
      -- This can show flicker in the UI and it's hard to handle all situations robustly.
      esReload :: CliOpts -> Day -> UIState -> EventM Name UIState ()
esReload CliOpts
copts Day
d UIState
ui = CliOpts -> Day -> UIState -> EventM Name UIState UIState
uiReload CliOpts
copts Day
d UIState
ui EventM Name UIState UIState
-> (UIState -> EventM Name UIState ()) -> EventM Name UIState ()
forall a b.
EventM Name UIState a
-> (a -> EventM Name UIState b) -> EventM Name UIState b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CliOpts -> Day -> UIState -> EventM Name UIState ()
maybeReloadErrorScreen CliOpts
copts Day
d
      esReloadIfFileChanged :: CliOpts -> Day -> Journal -> UIState -> EventM Name UIState ()
esReloadIfFileChanged CliOpts
copts Day
d Journal
j UIState
ui = IO UIState -> EventM Name UIState UIState
forall a. IO a -> EventM Name UIState a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (CliOpts -> Day -> Journal -> UIState -> IO UIState
uiReloadIfFileChanged CliOpts
copts Day
d Journal
j UIState
ui) EventM Name UIState UIState
-> (UIState -> EventM Name UIState ()) -> EventM Name UIState ()
forall a b.
EventM Name UIState a
-> (a -> EventM Name UIState b) -> EventM Name UIState b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CliOpts -> Day -> UIState -> EventM Name UIState ()
maybeReloadErrorScreen CliOpts
copts Day
d
      maybeReloadErrorScreen :: CliOpts -> Day -> UIState -> EventM Name UIState ()
maybeReloadErrorScreen CliOpts
copts Day
d UIState
ui =
        case [Screen] -> Maybe Screen
forall a. [a] -> Maybe a
headMay ([Screen] -> Maybe Screen) -> [Screen] -> Maybe Screen
forall a b. (a -> b) -> a -> b
$ UIState -> [Screen]
aPrevScreens UIState
ui of
          Just (TS TransactionScreenState
_) -> do
            -- check balance assertions, exit to register screen, enter transaction screen, reload once more
            UIState -> EventM Name UIState ()
put' (UIState -> EventM Name UIState ())
-> UIState -> EventM Name UIState ()
forall a b. (a -> b) -> a -> b
$ UIState -> UIState
popScreen (UIState -> UIState) -> UIState -> UIState
forall a b. (a -> b) -> a -> b
$ UIState -> UIState
popScreen (UIState -> UIState) -> UIState -> UIState
forall a b. (a -> b) -> a -> b
$ Day -> UIState -> UIState
uiCheckBalanceAssertions Day
d UIState
ui
            [Event] -> EventM Name UIState ()
forall n s. [Event] -> EventM n s ()
sendVtyEvents [Key -> [Modifier] -> Event
EvKey Key
KEnter [], Key -> [Modifier] -> Event
EvKey (Char -> Key
KChar Char
'g') []]  -- XXX Might be disrupted if other events are queued ?
          Maybe Screen
_ -> CliOpts -> Day -> UIState -> EventM Name UIState UIState
uiReload CliOpts
copts Day
d (UIState -> UIState
popScreen UIState
ui) EventM Name UIState UIState
-> (UIState -> EventM Name UIState ()) -> EventM Name UIState ()
forall a b.
EventM Name UIState a
-> (a -> EventM Name UIState b) -> EventM Name UIState b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= UIState -> EventM Name UIState ()
put' (UIState -> EventM Name UIState ())
-> (UIState -> UIState) -> UIState -> EventM Name UIState ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Day -> UIState -> UIState
uiCheckBalanceAssertions Day
d

-- | Parse the file name, line and column number from a hledger parse error message, if possible.
-- Temporary, we should keep the original parse error location. XXX
-- Keep in sync with 'Hledger.Data.Transaction.showGenericSourcePos'
hledgerparseerrorpositionp :: ParsecT Void String t (String, Int, Int)
hledgerparseerrorpositionp :: forall (t :: * -> *). ParsecT Void String t (String, Int, Int)
hledgerparseerrorpositionp = do
  ParsecT Void String t (Token String)
forall e s (m :: * -> *). MonadParsec e s m => m (Token s)
anySingle ParsecT Void String t (Token String)
-> ParsecT Void String t Char
-> ParsecT Void String t [Token String]
forall (m :: * -> *) a end. MonadPlus m => m a -> m end -> m [a]
`manyTill` Token String -> ParsecT Void String t (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token String
'"'
  f <- ParsecT Void String t Char
ParsecT Void String t (Token String)
forall e s (m :: * -> *). MonadParsec e s m => m (Token s)
anySingle ParsecT Void String t Char
-> ParsecT Void String t (Token String)
-> ParsecT Void String t String
forall (m :: * -> *) a end. MonadPlus m => m a -> m end -> m [a]
`manyTill` ([Token String] -> ParsecT Void String t (Token String)
forall (f :: * -> *) e s (m :: * -> *).
(Foldable f, MonadParsec e s m) =>
f (Token s) -> m (Token s)
oneOf [Char
'"',Char
'\n'])
  choice [
      do
          string " (line "
          l <- read <$> some digitChar
          string ", column "
          c <- read <$> some digitChar
          return (f, l, c),
      do
          string " (lines "
          l <- read <$> some digitChar
          char '-'
          some digitChar
          char ')'
          return (f, l, 1)
      ]


-- Defined here so it can reference the error screen:

-- | Modify some input options for hledger-ui (enable --forecast).
uiAdjustOpts :: UIOpts -> CliOpts -> CliOpts
uiAdjustOpts :: UIOpts -> CliOpts -> CliOpts
uiAdjustOpts UIOpts
uopts = UIOpts -> CliOpts -> CliOpts
enableForecast UIOpts
uopts

-- | Reload the journal from its input files, then update the ui app state accordingly.
-- This means regenerate the entire screen stack from top level down to the current screen, using the provided today-date.
-- As a convenience (usually), if journal reloading fails, this enters the error screen, or if already there, updates its message.
--
-- The provided cli options can influence reloading; then if reloading succeeds they are saved in the ui state,
-- otherwise the UIState keeps its old options. (XXX needed for.. ?)
--
-- Like at hledger-ui startup, --forecast is always enabled.
-- A forecast period specified in the provided opts, or at startup, is preserved.
--
uiReload :: CliOpts -> Day -> UIState -> EventM Name UIState UIState
uiReload :: CliOpts -> Day -> UIState -> EventM Name UIState UIState
uiReload CliOpts
copts Day
d UIState
ui = IO UIState -> EventM Name UIState UIState
forall a. IO a -> EventM Name UIState a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO UIState -> EventM Name UIState UIState)
-> IO UIState -> EventM Name UIState UIState
forall a b. (a -> b) -> a -> b
$ do
  ej <-
    let copts1 :: CliOpts
copts1 = UIOpts -> CliOpts -> CliOpts
uiAdjustOpts (UIState -> UIOpts
astartupopts UIState
ui) CliOpts
copts
    in ExceptT String IO Journal -> IO (Either String Journal)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT String IO Journal -> IO (Either String Journal))
-> ExceptT String IO Journal -> IO (Either String Journal)
forall a b. (a -> b) -> a -> b
$ CliOpts -> Journal -> Journal
journalTransform CliOpts
copts1 (Journal -> Journal)
-> ExceptT String IO Journal -> ExceptT String IO Journal
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CliOpts -> ExceptT String IO Journal
journalReload CliOpts
copts1
  -- dbg1IO "uiReload before reload" (map tdescription $ jtxns $ ajournal ui)
  return $ case ej of
    Right Journal
j  ->
      -- dbg1 "uiReload after reload" (map tdescription $ jtxns j) $
      Journal -> Day -> UIState -> UIState
regenerateScreens Journal
j Day
d UIState
ui
    Left String
err ->
      case UIState
ui of
        UIState{aScreen :: UIState -> Screen
aScreen=ES ErrorScreenState
_} -> UIState
ui{aScreen=esNew err}
        UIState
_                      -> Screen -> UIState -> UIState
pushScreen (String -> Screen
esNew String
err) UIState
ui
      -- XXX GHC 9.2 warning:
      -- hledger-ui/Hledger/UI/ErrorScreen.hs:164:59: warning: [-Wincomplete-record-updates]
      --     Pattern match(es) are non-exhaustive
      --     In a record-update construct:
      --         Patterns of type ‘Screen’ not matched:
      --             AccountsScreen _ _ _ _ _
      --             RegisterScreen _ _ _ _ _ _
      --             TransactionScreen _ _ _ _ _ _

-- | Like uiReload, except it skips re-reading the journal if its file(s) have not changed
-- since it was last loaded. The up app state is always updated, since the options or today-date may have changed.
-- Also, this one runs in IO, suitable for suspendAndResume.
uiReloadIfFileChanged :: CliOpts -> Day -> Journal -> UIState -> IO UIState
uiReloadIfFileChanged :: CliOpts -> Day -> Journal -> UIState -> IO UIState
uiReloadIfFileChanged CliOpts
copts Day
d Journal
j UIState
ui = do
  ej <-
    let copts1 :: CliOpts
copts1 = UIOpts -> CliOpts -> CliOpts
uiAdjustOpts (UIState -> UIOpts
astartupopts UIState
ui) CliOpts
copts
    in ExceptT String IO (Journal, Bool)
-> IO (Either String (Journal, Bool))
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT String IO (Journal, Bool)
 -> IO (Either String (Journal, Bool)))
-> ExceptT String IO (Journal, Bool)
-> IO (Either String (Journal, Bool))
forall a b. (a -> b) -> a -> b
$ CliOpts -> Day -> Journal -> ExceptT String IO (Journal, Bool)
journalReloadIfChanged CliOpts
copts1 Day
d Journal
j
  return $ case ej of
    Right (Journal
j', Bool
_) -> Journal -> Day -> UIState -> UIState
regenerateScreens Journal
j' Day
d UIState
ui
    Left String
err -> case UIState -> Screen
aScreen UIState
ui of
        ES ErrorScreenState
_ -> UIState
ui{aScreen=esNew err}
        Screen
_    -> Screen -> UIState -> UIState
pushScreen (String -> Screen
esNew String
err) UIState
ui

-- Re-check any balance assertions in the current journal,
-- and if any fail, enter (or update) the error screen.
-- Or if balance assertions are disabled or pivot is active, do nothing.
-- (When pivot is active, assertions have already been checked on the pre-pivot journal,
-- and the current post-pivot journal's account names don't match the original assertions.)
uiCheckBalanceAssertions :: Day -> UIState -> UIState
uiCheckBalanceAssertions :: Day -> UIState -> UIState
uiCheckBalanceAssertions Day
_d ui :: UIState
ui@UIState{ajournal :: UIState -> Journal
ajournal=Journal
j, aopts :: UIState -> UIOpts
aopts=UIOpts{uoCliOpts :: UIOpts -> CliOpts
uoCliOpts=CliOpts{inputopts_ :: CliOpts -> InputOpts
inputopts_=InputOpts{pivot_ :: InputOpts -> String
pivot_=String
pval}}}}
  | UIState
uiUIState -> Getting Bool UIState Bool -> Bool
forall s a. s -> Getting a s a -> a
^.Getting Bool UIState Bool
forall c. HasBalancingOpts c => Lens' c Bool
Lens' UIState Bool
ignore_assertions = UIState
ui        -- user disabled checks
  | Bool -> Bool
not (String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
pval) = UIState
ui              -- post-pivot journal, assertions already checked pre-pivot
  | Bool
otherwise =
    case Journal -> Either String ()
journalCheckBalanceAssertions Journal
j of
      Right () -> UIState
ui
      Left String
err ->
        case UIState
ui of
          UIState{aScreen :: UIState -> Screen
aScreen=ES ErrorScreenState
sst} -> UIState
ui{aScreen=ES sst{_essError=err}}
          UIState
_                        -> Screen -> UIState -> UIState
pushScreen (String -> Screen
esNew String
err) UIState
ui

-- | Toggle ignoring balance assertions (when user presses I), and if no longer ignoring, recheck them.
-- Normally the recheck is done quickly on the in-memory journal.
-- But if --pivot is active, a full journal reload is done instead
-- (because we can't check balance assertions after pivoting has occurred).
-- In that case, this operation could be slower and could reveal other data changes (not just balance assertion failures).
uiToggleBalanceAssertions :: Day -> UIState -> EventM Name UIState ()
uiToggleBalanceAssertions :: Day -> UIState -> EventM Name UIState ()
uiToggleBalanceAssertions Day
d ui :: UIState
ui@UIState{aopts :: UIState -> UIOpts
aopts=UIOpts{uoCliOpts :: UIOpts -> CliOpts
uoCliOpts=copts :: CliOpts
copts@CliOpts{inputopts_ :: CliOpts -> InputOpts
inputopts_=InputOpts{pivot_ :: InputOpts -> String
pivot_=String
pivotval}}}} =
  let ui' :: UIState
ui' = UIState -> UIState
toggleIgnoreBalanceAssertions UIState
ui
  in case (UIState
ui'UIState -> Getting Bool UIState Bool -> Bool
forall s a. s -> Getting a s a -> a
^.Getting Bool UIState Bool
forall c. HasBalancingOpts c => Lens' c Bool
Lens' UIState Bool
ignore_assertions, String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
pivotval) of
    (Bool
True, Bool
_)      -> UIState -> EventM Name UIState ()
put' UIState
ui'                                -- ignoring enabled, no check needed
    (Bool
False, Bool
True)  -> UIState -> EventM Name UIState ()
put' (UIState -> EventM Name UIState ())
-> UIState -> EventM Name UIState ()
forall a b. (a -> b) -> a -> b
$ Day -> UIState -> UIState
uiCheckBalanceAssertions Day
d UIState
ui'   -- unpivoted journal, can check in memory
    (Bool
False, Bool
False) -> CliOpts -> Day -> UIState -> EventM Name UIState UIState
uiReload CliOpts
copts Day
d UIState
ui' EventM Name UIState UIState
-> (UIState -> EventM Name UIState ()) -> EventM Name UIState ()
forall a b.
EventM Name UIState a
-> (a -> EventM Name UIState b) -> EventM Name UIState b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= UIState -> EventM Name UIState ()
put'           -- pivoted journal, must reload to check it