From 1db9b018f13559f55beaeb8e5a83e84bb1defcec Mon Sep 17 00:00:00 2001 From: Simon Michael Date: Mon, 15 Oct 2018 15:11:22 -0700 Subject: [PATCH] ui: add --present/--future, hide future txns by default, toggle with F You may have transactions dated later than today, perhaps piped from print --forecast or recorded in the journal, which you don't want to see except when forecasting. By default, we now hide future transactions, showing "today's balance". This can be toggled with the F key, which is easier than setting a date query. --present and --future flags have been added to set the initial mode. (Experimental. Interactions with date queries have not been explored.) --- hledger-ui/Hledger/UI/AccountsScreen.hs | 14 +++++++++++--- hledger-ui/Hledger/UI/RegisterScreen.hs | 17 ++++++++++++----- hledger-ui/Hledger/UI/UIOptions.hs | 20 ++++++++++++++++++++ hledger-ui/Hledger/UI/UIState.hs | 8 ++++++++ hledger-ui/Hledger/UI/UIUtils.hs | 1 + hledger-ui/hledger-ui.m4.md | 23 ++++++++++++++++++----- 6 files changed, 70 insertions(+), 13 deletions(-) diff --git a/hledger-ui/Hledger/UI/AccountsScreen.hs b/hledger-ui/Hledger/UI/AccountsScreen.hs index e60b7550c..1cc9e7343 100644 --- a/hledger-ui/Hledger/UI/AccountsScreen.hs +++ b/hledger-ui/Hledger/UI/AccountsScreen.hs @@ -23,7 +23,7 @@ import Data.Maybe import Data.Monoid #endif import qualified Data.Text as T -import Data.Time.Calendar (Day) +import Data.Time.Calendar (Day, addDays) import qualified Data.Vector as V import Graphics.Vty (Event(..),Key(..),Modifier(..)) import Lens.Micro.Platform @@ -82,7 +82,10 @@ asInit d reset ui@UIState{ uopts' = uopts{cliopts_=copts{reportopts_=ropts'}} ropts' = ropts{accountlistmode_=if tree_ ropts then ALTree else ALFlat} - q = queryFromOpts d ropts + pfq | presentorfuture_ uopts == PFFuture = Any + | otherwise = Date $ DateSpan Nothing (Just $ addDays 1 d) + q = And [queryFromOpts d ropts, pfq] + -- run the report (items,_total) = report ropts' q j @@ -116,7 +119,7 @@ asInit d reset ui@UIState{ asInit _ _ _ = error "init function called with wrong screen type, should not happen" asDraw :: UIState -> [Widget Name] -asDraw UIState{aopts=UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} +asDraw UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} ,ajournal=j ,aScreen=s@AccountsScreen{} ,aMode=mode @@ -223,6 +226,10 @@ asDraw UIState{aopts=UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} ,if tree_ ropts then str "flat/" <+> selectedstr "tree" else selectedstr "flat" <+> str "/tree") + ,("F" + ,if presentorfuture_ uopts == PFFuture + then str "present/" <+> selectedstr "future" + else selectedstr "present" <+> str "/future") ,("-+", str "depth") --,("/", "filter") --,("DEL", "unfilter") @@ -338,6 +345,7 @@ asHandle ui0@UIState{ VtyEvent (EvKey (KChar 'U') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleUnmarked ui VtyEvent (EvKey (KChar 'P') []) -> asCenterAndContinue $ regenerateScreens j d $ togglePending ui VtyEvent (EvKey (KChar 'C') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleCleared ui + VtyEvent (EvKey (KChar 'F') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleFuture ui VtyEvent (EvKey (KDown) [MShift]) -> continue $ regenerateScreens j d $ shrinkReportPeriod d ui VtyEvent (EvKey (KUp) [MShift]) -> continue $ regenerateScreens j d $ growReportPeriod d ui diff --git a/hledger-ui/Hledger/UI/RegisterScreen.hs b/hledger-ui/Hledger/UI/RegisterScreen.hs index c8508f20f..a418ae799 100644 --- a/hledger-ui/Hledger/UI/RegisterScreen.hs +++ b/hledger-ui/Hledger/UI/RegisterScreen.hs @@ -59,7 +59,7 @@ rsSetAccount a forceinclusive scr@RegisterScreen{} = rsSetAccount _ _ scr = scr rsInit :: Day -> Bool -> UIState -> UIState -rsInit d reset ui@UIState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}, ajournal=j, aScreen=s@RegisterScreen{..}} = +rsInit d reset ui@UIState{aopts=uopts@UIOpts{cliopts_=CliOpts{reportopts_=ropts}}, ajournal=j, aScreen=s@RegisterScreen{..}} = ui{aScreen=s{rsList=newitems'}} where -- gather arguments and queries @@ -69,7 +69,9 @@ rsInit d reset ui@UIState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}, ajo ropts' = ropts{ depth_=Nothing } - q = queryFromOpts d ropts' + pfq | presentorfuture_ uopts == PFFuture = Any + | otherwise = Date $ DateSpan Nothing (Just $ addDays 1 d) + q = And [queryFromOpts d ropts', pfq] -- reportq = filterQuery (not . queryIsDepth) q (_label,items) = accountTransactionsReport ropts' j q thisacctq @@ -131,7 +133,7 @@ rsInit d reset ui@UIState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}, ajo rsInit _ _ _ = error "init function called with wrong screen type, should not happen" rsDraw :: UIState -> [Widget Name] -rsDraw UIState{aopts=UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} +rsDraw UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} ,aScreen=RegisterScreen{..} ,aMode=mode } = @@ -235,8 +237,12 @@ rsDraw UIState{aopts=UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} else str "historical/" <+> selectedstr "period") ,("T" ,if inclusive - then str "this/" <+> selectedstr "+subs" - else selectedstr "this" <+> str "/+subs") + then str "flat/" <+> selectedstr "tree" + else selectedstr "flat" <+> str "/tree") + ,("F" + ,if presentorfuture_ uopts == PFFuture + then str "present/" <+> selectedstr "future" + else selectedstr "present" <+> str "/future") -- ,("a", "add") -- ,("g", "reload") -- ,("q", "quit") @@ -329,6 +335,7 @@ rsHandle ui@UIState{ VtyEvent (EvKey (KChar 'U') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleUnmarked ui VtyEvent (EvKey (KChar 'P') []) -> rsCenterAndContinue $ regenerateScreens j d $ togglePending ui VtyEvent (EvKey (KChar 'C') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleCleared ui + VtyEvent (EvKey (KChar 'F') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleFuture ui VtyEvent (EvKey (KChar '/') []) -> continue $ regenerateScreens j d $ showMinibuffer ui VtyEvent (EvKey (KDown) [MShift]) -> continue $ regenerateScreens j d $ shrinkReportPeriod d ui diff --git a/hledger-ui/Hledger/UI/UIOptions.hs b/hledger-ui/Hledger/UI/UIOptions.hs index cc989ee7b..2f4aeb507 100644 --- a/hledger-ui/Hledger/UI/UIOptions.hs +++ b/hledger-ui/Hledger/UI/UIOptions.hs @@ -1,11 +1,14 @@ {-# LANGUAGE CPP #-} +{-# LANGUAGE DeriveDataTypeable #-} {-| -} module Hledger.UI.UIOptions where +import Data.Data (Data) import Data.Default +import Data.Typeable (Typeable) import Data.List (intercalate) import System.Environment @@ -35,6 +38,8 @@ uiflags = [ -- "show historical ending balance in each period (includes postings before report start date)\n " ,flagNone ["flat","F"] (\opts -> setboolopt "flat" opts) "show full account names, unindented (default)" ,flagNone ["tree","T"] (\opts -> setboolopt "tree" opts) "show accounts as a tree" + ,flagNone ["present"] (\opts -> setboolopt "present" opts) "exclude transactions dated later than today (default)" + ,flagNone ["future"] (\opts -> setboolopt "future" opts) "include transactions dated later than today" -- ,flagReq ["drop"] (\s opts -> Right $ setopt "drop" s opts) "N" "with --flat, omit this many leading account name components" -- ,flagReq ["format"] (\s opts -> Right $ setopt "format" s opts) "FORMATSTR" "use this custom line format" -- ,flagNone ["no-elide"] (\opts -> setboolopt "no-elide" opts) "don't compress empty parent accounts on one line" @@ -67,6 +72,7 @@ uimode = (mode "hledger-ui" [("command","ui")] data UIOpts = UIOpts { watch_ :: Bool ,change_ :: Bool + ,presentorfuture_ :: PresentOrFutureOpt ,cliopts_ :: CliOpts } deriving (Show) @@ -74,6 +80,7 @@ defuiopts = UIOpts def def def + def -- instance Default CliOpts where def = defcliopts @@ -83,9 +90,22 @@ rawOptsToUIOpts rawopts = checkUIOpts <$> do return defuiopts { watch_ = boolopt "watch" rawopts ,change_ = boolopt "change" rawopts + ,presentorfuture_ = presentorfutureopt rawopts ,cliopts_ = cliopts } +-- | Should transactions dated later than today be included ? +-- Like flat/tree mode, there are three states, and the meaning of default can vary by command. +data PresentOrFutureOpt = PFDefault | PFPresent | PFFuture deriving (Eq, Show, Data, Typeable) +instance Default PresentOrFutureOpt where def = PFDefault + +presentorfutureopt :: RawOpts -> PresentOrFutureOpt +presentorfutureopt rawopts = + case reverse $ filter (`elem` ["present","future"]) $ map fst rawopts of + ("present":_) -> PFPresent + ("future":_) -> PFFuture + _ -> PFDefault + checkUIOpts :: UIOpts -> UIOpts checkUIOpts opts = either usageError (const opts) $ do diff --git a/hledger-ui/Hledger/UI/UIState.hs b/hledger-ui/Hledger/UI/UIState.hs index d03cf4e43..615ddc6c5 100644 --- a/hledger-ui/Hledger/UI/UIState.hs +++ b/hledger-ui/Hledger/UI/UIState.hs @@ -124,6 +124,14 @@ toggleHistorical ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts b | balancetype_ ropts == HistoricalBalance = PeriodChange | otherwise = HistoricalBalance +-- | Toggle between including and excluding transactions dated later than today. +toggleFuture :: UIState -> UIState +toggleFuture ui@UIState{aopts=uopts@UIOpts{presentorfuture_=pf}} = + ui{aopts=uopts{presentorfuture_=pf'}} + where + pf' | pf == PFFuture = PFPresent + | otherwise = PFFuture + -- | Toggle between showing all and showing only real (non-virtual) items. toggleReal :: UIState -> UIState toggleReal ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} = diff --git a/hledger-ui/Hledger/UI/UIUtils.hs b/hledger-ui/Hledger/UI/UIUtils.hs index b325f9afb..67c008c36 100644 --- a/hledger-ui/Hledger/UI/UIUtils.hs +++ b/hledger-ui/Hledger/UI/UIUtils.hs @@ -92,6 +92,7 @@ helpDialog copts = ,"cycle cleared/not cleared/all" ,"toggle cleared filter" ] !! (statusstyle-1)) + ,renderKey ("F", "toggle future/present") ,renderKey ("R", "toggle real/all") ,renderKey ("Z", "toggle nonzero/all") ,renderKey ("DEL/BS", "remove filters") diff --git a/hledger-ui/hledger-ui.m4.md b/hledger-ui/hledger-ui.m4.md index a8106b2e1..3003647ea 100644 --- a/hledger-ui/hledger-ui.m4.md +++ b/hledger-ui/hledger-ui.m4.md @@ -44,6 +44,7 @@ hledger-ui is hledger's curses-style interface, providing an efficient full-wind for viewing accounts and transactions, and some limited data entry capability. It is easier than hledger's command-line interface, and sometimes quicker and more convenient than the web interface. +Note hledger-ui hides transactions dated in the future, by default. Like hledger, it reads _files_ For more about this see hledger(1), hledger_journal(5) etc. @@ -72,7 +73,13 @@ Any QUERYARGS are interpreted as a hledger search query which filters the data. `-T --tree` : show accounts as a tree -hledger input options: +`--present` +: exclude transactions dated later than today (default) (experimental) + +`--future` +: include transactions dated later than today (experimental) + + hledger input options: _inputoptions_ @@ -122,6 +129,12 @@ press `ENTER` to set it, or `ESCAPE`to cancel. There are also keys for quickly adjusting some common filters like account depth and transaction status (see below). `BACKSPACE` or `DELETE` removes all filters, showing all transactions. +As mentioned above, hledger-ui hides transactions in the future by default. +`F` toggles showing and hiding these future transactions. +This is similar to using a query like `date:-tomorrow`, but more convenient. +(experimental) + + `ESCAPE` removes all filters and jumps back to the top screen. Or, it cancels a minibuffer edit or help dialog in progress. @@ -211,10 +224,10 @@ Similar to the accounts screen, the historical total is affected by transactions If the historical total is not disturbed by a filter query, it will be the running historical balance you would see on a bank register for the current account. -Transactions affecting this account's subaccounts will be shown if -the accounts screen was in tree mode, -or if it was in flat mode but the selected account had depth-clipped subaccounts. -In other words, the register always shows just the transactions contributing to the balance on the accounts screen. +Transactions affecting this account's subaccounts will be included in the register +if the accounts screen is in tree mode, +or if it's in flat mode but this account has subaccounts which are not shown due to a depth limit. +In other words, the register always shows the transactions contributing to the balance shown on the accounts screen. Tree mode/flat mode can be toggled with `T` here also. `U` toggles filtering by [unmarked status](/journal.html#status), showing or hiding unmarked transactions.