hledger/hledger-ui/Hledger/UI/ErrorScreen.hs

111 lines
4.0 KiB
Haskell

-- The error screen, showing a current error condition (such as a parse error after reloading the journal)
{-# LANGUAGE OverloadedStrings, FlexibleContexts, RecordWildCards #-}
module Hledger.UI.ErrorScreen
(errorScreen
,stReloadJournalIfChanged
)
where
-- import Lens.Micro.Platform ((^.))
import Control.Monad.IO.Class (liftIO)
import Data.Monoid
-- import Data.Maybe
import Data.Time.Calendar (Day)
import Graphics.Vty as Vty
import Brick
-- import Brick.Widgets.List
-- import Brick.Widgets.Border
-- import Brick.Widgets.Border.Style
-- import Brick.Widgets.Center
-- import Text.Printf
-- import Hledger
import Hledger.Cli hiding (progname,prognameandversion,green)
import Hledger.UI.UIOptions
-- import Hledger.UI.Theme
import Hledger.UI.UITypes
import Hledger.UI.UIUtils
errorScreen :: Screen
errorScreen = ErrorScreen{
sInit = esInit
,sDraw = esDraw
,sHandle = esHandle
,esError = ""
}
esInit :: Day -> Bool -> AppState -> AppState
esInit _ _ st@AppState{aScreen=ErrorScreen{}} = st
esInit _ _ _ = error "init function called with wrong screen type, should not happen"
esDraw :: AppState -> [Widget]
esDraw AppState{ -- aopts=_uopts@UIOpts{cliopts_=_copts@CliOpts{reportopts_=_ropts@ReportOpts{query_=querystr}}},
aScreen=ErrorScreen{..}
,aMode=mode} =
case mode of
Help -> [helpDialog, maincontent]
-- Minibuffer e -> [minibuffer e, maincontent]
_ -> [maincontent]
where
toplabel = withAttr ("border" <> "bold") (str "Oops. Please fix this problem then press g to reload")
maincontent = Widget Greedy Greedy $ do
render $ defaultLayout toplabel bottomlabel $ withAttr "error" $ str $ esError
where
bottomlabel = case mode of
-- Minibuffer ed -> minibuffer ed
_ -> quickhelp
quickhelp = borderKeysStr [
("h", "help")
,("ESC", "cancel/top")
,("g", "reload")
,("q", "quit")
]
esDraw _ = error "draw function called with wrong screen type, should not happen"
esHandle :: AppState -> Vty.Event -> EventM (Next AppState)
esHandle st@AppState{
aScreen=s@ErrorScreen{}
,aopts=UIOpts{cliopts_=copts}
,ajournal=j
,aMode=mode
} ev =
case mode of
Help ->
case ev of
Vty.EvKey (Vty.KChar 'q') [] -> halt st
_ -> helpHandle st ev
_ -> do
d <- liftIO getCurrentDay
case ev of
Vty.EvKey (Vty.KChar 'q') [] -> halt st
Vty.EvKey Vty.KEsc [] -> continue $ resetScreens d st
Vty.EvKey k [] | k `elem` [Vty.KChar 'h', Vty.KChar '?'] -> continue $ setMode Help st
Vty.EvKey (Vty.KChar 'g') [] -> do
(ej, _) <- liftIO $ journalReloadIfChanged copts d j
case ej of
Left err -> continue st{aScreen=s{esError=err}} -- show latest parse error
Right j' -> continue $ regenerateScreens j' d $ popScreen st -- return to previous screen, and reload it
-- Vty.EvKey (Vty.KLeft) [] -> continue $ popScreen st
-- Vty.EvKey (Vty.KRight) [] -> error (show curItem) where curItem = listSelectedElement is
-- fall through to the list's event handler (handles [pg]up/down)
_ -> do continue st
-- is' <- handleEvent ev is
-- continue st{aScreen=s{rsState=is'}}
-- continue =<< handleEventLensed st someLens e
esHandle _ _ = error "event handler called with wrong screen type, should not happen"
-- If journal file(s) have changed, reload the journal and regenerate all screens.
-- This is here so it can reference the error screen.
stReloadJournalIfChanged :: CliOpts -> Day -> Journal -> AppState -> IO AppState
stReloadJournalIfChanged copts d j st = do
(ej, _) <- journalReloadIfChanged copts d j
return $ case ej of
Right j' -> regenerateScreens j' d st
Left err -> screenEnter d errorScreen{esError=err} st