hledger/hledger-ui/Hledger/UI/TransactionScreen.hs
Simon Michael 2538d14ea7 lib: textification begins! account names
The first of several conversions from String to (strict) Text, hopefully
reducing space and time usage.

This one shows a small improvement, with GHC 7.10.3 and text-1.2.2.1:

hledger -f data/100x100x10.journal stats
string: <<ghc: 39471064 bytes, 77 GCs, 198421/275048 avg/max bytes residency (3 samples), 2M in use, 0.000 INIT (0.001 elapsed), 0.015 MUT (0.020 elapsed), 0.010 GC (0.014 elapsed) :ghc>>
text:   <<ghc: 39268024 bytes, 77 GCs, 197018/270840 avg/max bytes residency (3 samples), 2M in use, 0.000 INIT (0.002 elapsed), 0.016 MUT (0.022 elapsed), 0.009 GC (0.011 elapsed) :ghc>>

hledger -f data/1000x100x10.journal stats
string: <<ghc: 318555920 bytes, 617 GCs, 2178997/7134472 avg/max bytes residency (7 samples), 16M in use, 0.000 INIT (0.001 elapsed), 0.129 MUT (0.136 elapsed), 0.067 GC (0.077 elapsed) :ghc>>
text:   <<ghc: 314248496 bytes, 612 GCs, 2074045/6617960 avg/max bytes residency (7 samples), 16M in use, 0.000 INIT (0.003 elapsed), 0.137 MUT (0.145 elapsed), 0.067 GC (0.079 elapsed) :ghc>>

hledger -f data/10000x100x10.journal stats
string: <<ghc: 3114763608 bytes, 6026 GCs, 18858950/75552024 avg/max bytes residency (11 samples), 201M in use, 0.000 INIT (0.000 elapsed), 1.331 MUT (1.372 elapsed), 0.699 GC (0.812 elapsed) :ghc>>
text:   <<ghc: 3071468920 bytes, 5968 GCs, 14120344/62951360 avg/max bytes residency (9 samples), 124M in use, 0.000 INIT (0.003 elapsed), 1.272 MUT (1.349 elapsed), 0.513 GC (0.578 elapsed) :ghc>>

hledger -f data/100000x100x10.journal stats
string: <<ghc: 31186579432 bytes, 60278 GCs, 135332581/740228992 avg/max bytes residency (13 samples), 1697M in use, 0.000 INIT (0.008 elapsed), 14.677 MUT (15.508 elapsed), 7.081 GC (8.074 elapsed) :ghc>>
text:   <<ghc: 30753427672 bytes, 59763 GCs, 117595958/666457240 avg/max bytes residency (14 samples), 1588M in use, 0.000 INIT (0.008 elapsed), 13.713 MUT (13.966 elapsed), 6.220 GC (7.108 elapsed) :ghc>>
2016-05-24 19:00:49 -07:00

133 lines
5.2 KiB
Haskell

-- The transaction screen, showing a single transaction's general journal entry.
{-# LANGUAGE OverloadedStrings, TupleSections #-} -- , FlexibleContexts
module Hledger.UI.TransactionScreen
(screen
)
where
-- import Lens.Micro ((^.))
import Control.Monad.IO.Class (liftIO)
-- import Data.List
-- import Data.List.Split (splitOn)
-- import Data.Ord
import Data.Monoid
-- import Data.Maybe
-- import Data.Text (Text)
import qualified Data.Text as T
import Data.Time.Calendar (Day)
-- import qualified Data.Vector as V
import Graphics.Vty as Vty
-- import Safe (headDef, lastDef)
import Brick
import Brick.Widgets.List (listMoveTo)
-- 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
import qualified Hledger.UI.ErrorScreen as ES (screen)
screen = TransactionScreen{
tsState = ((1,nulltransaction),[(1,nulltransaction)],"")
,sInitFn = initTransactionScreen
,sDrawFn = drawTransactionScreen
,sHandleFn = handleTransactionScreen
}
initTransactionScreen :: Day -> AppState -> AppState
initTransactionScreen _d st@AppState{aopts=_opts, ajournal=_j, aScreen=_s@TransactionScreen{tsState=_}} = st
initTransactionScreen _ _ = error "init function called with wrong screen type, should not happen"
drawTransactionScreen :: AppState -> [Widget]
drawTransactionScreen AppState{ -- aopts=_uopts@UIOpts{cliopts_=_copts@CliOpts{reportopts_=_ropts@ReportOpts{query_=querystr}}},
aScreen=TransactionScreen{tsState=((i,t),nts,acct)}} = [ui]
where
-- datedesc = show (tdate t) ++ " " ++ tdescription t
toplabel =
str "Transaction "
-- <+> withAttr ("border" <> "bold") (str $ "#" ++ show (tindex t))
-- <+> str (" ("++show i++" of "++show (length nts)++" in "++acct++")")
<+> (str $ "#" ++ show (tindex t))
<+> str " ("
<+> withAttr ("border" <> "bold") (str $ show i)
<+> str (" of "++show (length nts)++" in "++T.unpack acct++")")
bottomlabel = borderKeysStr [
("left", "back")
,("up/down", "prev/next")
,("g", "reload")
,("q", "quit")
]
ui = Widget Greedy Greedy $ do
render $ defaultLayout toplabel bottomlabel $ str $ showTransactionUnelidedOneLineAmounts t
drawTransactionScreen _ = error "draw function called with wrong screen type, should not happen"
handleTransactionScreen :: AppState -> Vty.Event -> EventM (Next AppState)
handleTransactionScreen st@AppState{
aScreen=s@TransactionScreen{tsState=((i,t),nts,acct)}
,aopts=UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}
,ajournal=j
} e = do
d <- liftIO getCurrentDay
let
(iprev,tprev) = maybe (i,t) ((i-1),) $ lookup (i-1) nts
(inext,tnext) = maybe (i,t) ((i+1),) $ lookup (i+1) nts
case e of
Vty.EvKey Vty.KEsc [] -> halt st
Vty.EvKey (Vty.KChar 'q') [] -> halt st
Vty.EvKey (Vty.KChar 'g') [] -> do
d <- liftIO getCurrentDay
(ej, _) <- liftIO $ journalReloadIfChanged copts d j
case ej of
Right j' -> do
-- got to redo the register screen's transactions report, to get the latest transactions list for this screen
-- XXX duplicates initRegisterScreen
let
ropts' = ropts {depth_=Nothing
,balancetype_=HistoricalBalance
}
q = filterQuery (not . queryIsDepth) $ queryFromOpts d ropts'
thisacctq = Acct $ accountNameToAccountRegex acct -- includes subs
items = reverse $ snd $ accountTransactionsReport ropts j' q thisacctq
ts = map first6 items
numberedts = zip [1..] ts
-- select the best current transaction from the new list
-- stay at the same index if possible, or if we are now past the end, select the last, otherwise select the first
(i',t') = case lookup i numberedts
of Just t'' -> (i,t'')
Nothing | null numberedts -> (0,nulltransaction)
| i > fst (last numberedts) -> last numberedts
| otherwise -> head numberedts
st' = st{aScreen=s{tsState=((i',t'),numberedts,acct)}}
continue $ reload j' d st'
Left err -> continue $ screenEnter d ES.screen{esState=err} st
-- Vty.EvKey (Vty.KChar 'C') [] -> continue $ reload j d $ stToggleCleared st
Vty.EvKey (Vty.KUp) [] -> continue $ reload j d st{aScreen=s{tsState=((iprev,tprev),nts,acct)}}
Vty.EvKey (Vty.KDown) [] -> continue $ reload j d st{aScreen=s{tsState=((inext,tnext),nts,acct)}}
Vty.EvKey (Vty.KLeft) [] -> continue st''
where
st'@AppState{aScreen=scr} = popScreen st
st'' = st'{aScreen=rsSetSelectedTransaction (fromIntegral i) scr}
_ev -> continue st
handleTransactionScreen _ _ = error "event handler called with wrong screen type, should not happen"
rsSetSelectedTransaction i scr@RegisterScreen{rsState=(l,a)} = scr{rsState=(l',a)}
where l' = listMoveTo (i-1) l
rsSetSelectedTransaction _ scr = scr