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.)
This commit is contained in:
		
							parent
							
								
									e52430bd62
								
							
						
					
					
						commit
						1db9b018f1
					
				| @ -23,7 +23,7 @@ import Data.Maybe | |||||||
| import Data.Monoid | import Data.Monoid | ||||||
| #endif | #endif | ||||||
| import qualified Data.Text as T | import qualified Data.Text as T | ||||||
| import Data.Time.Calendar (Day) | import Data.Time.Calendar (Day, addDays) | ||||||
| import qualified Data.Vector as V | import qualified Data.Vector as V | ||||||
| import Graphics.Vty (Event(..),Key(..),Modifier(..)) | import Graphics.Vty (Event(..),Key(..),Modifier(..)) | ||||||
| import Lens.Micro.Platform | import Lens.Micro.Platform | ||||||
| @ -82,7 +82,10 @@ asInit d reset ui@UIState{ | |||||||
|     uopts' = uopts{cliopts_=copts{reportopts_=ropts'}} |     uopts' = uopts{cliopts_=copts{reportopts_=ropts'}} | ||||||
|     ropts' = ropts{accountlistmode_=if tree_ ropts then ALTree else ALFlat} |     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 |     -- run the report | ||||||
|     (items,_total) = report ropts' q j |     (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" | asInit _ _ _ = error "init function called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| asDraw :: UIState -> [Widget Name] | 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 |                            ,ajournal=j | ||||||
|                            ,aScreen=s@AccountsScreen{} |                            ,aScreen=s@AccountsScreen{} | ||||||
|                            ,aMode=mode |                            ,aMode=mode | ||||||
| @ -223,6 +226,10 @@ asDraw UIState{aopts=UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} | |||||||
|                ,if tree_ ropts |                ,if tree_ ropts | ||||||
|                 then str "flat/" <+> selectedstr "tree"  |                 then str "flat/" <+> selectedstr "tree"  | ||||||
|                 else selectedstr "flat" <+> str "/tree") |                 else selectedstr "flat" <+> str "/tree") | ||||||
|  |               ,("F" | ||||||
|  |                ,if presentorfuture_ uopts == PFFuture | ||||||
|  |                 then str "present/" <+> selectedstr "future"  | ||||||
|  |                 else selectedstr "present" <+> str "/future") | ||||||
|               ,("-+", str "depth") |               ,("-+", str "depth") | ||||||
|               --,("/", "filter") |               --,("/", "filter") | ||||||
|               --,("DEL", "unfilter") |               --,("DEL", "unfilter") | ||||||
| @ -338,6 +345,7 @@ asHandle ui0@UIState{ | |||||||
|         VtyEvent (EvKey (KChar 'U') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleUnmarked ui |         VtyEvent (EvKey (KChar 'U') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleUnmarked ui | ||||||
|         VtyEvent (EvKey (KChar 'P') []) -> asCenterAndContinue $ regenerateScreens j d $ togglePending ui |         VtyEvent (EvKey (KChar 'P') []) -> asCenterAndContinue $ regenerateScreens j d $ togglePending ui | ||||||
|         VtyEvent (EvKey (KChar 'C') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleCleared 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 (KDown)     [MShift]) -> continue $ regenerateScreens j d $ shrinkReportPeriod d ui | ||||||
|         VtyEvent (EvKey (KUp)       [MShift]) -> continue $ regenerateScreens j d $ growReportPeriod d ui |         VtyEvent (EvKey (KUp)       [MShift]) -> continue $ regenerateScreens j d $ growReportPeriod d ui | ||||||
|  | |||||||
| @ -59,7 +59,7 @@ rsSetAccount a forceinclusive scr@RegisterScreen{} = | |||||||
| rsSetAccount _ _ scr = scr | rsSetAccount _ _ scr = scr | ||||||
| 
 | 
 | ||||||
| rsInit :: Day -> Bool -> UIState -> UIState | 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'}} |   ui{aScreen=s{rsList=newitems'}} | ||||||
|   where |   where | ||||||
|     -- gather arguments and queries |     -- gather arguments and queries | ||||||
| @ -69,7 +69,9 @@ rsInit d reset ui@UIState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}, ajo | |||||||
|     ropts' = ropts{ |     ropts' = ropts{ | ||||||
|                depth_=Nothing |                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 | --    reportq = filterQuery (not . queryIsDepth) q | ||||||
| 
 | 
 | ||||||
|     (_label,items) = accountTransactionsReport ropts' j q thisacctq |     (_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" | rsInit _ _ _ = error "init function called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| rsDraw :: UIState -> [Widget Name] | 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{..} |                             ,aScreen=RegisterScreen{..} | ||||||
|                             ,aMode=mode |                             ,aMode=mode | ||||||
|                             } = |                             } = | ||||||
| @ -235,8 +237,12 @@ rsDraw UIState{aopts=UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} | |||||||
|                 else str "historical/" <+> selectedstr "period") |                 else str "historical/" <+> selectedstr "period") | ||||||
|               ,("T" |               ,("T" | ||||||
|                ,if inclusive |                ,if inclusive | ||||||
|                 then str "this/" <+> selectedstr "+subs"  |                 then str "flat/" <+> selectedstr "tree"  | ||||||
|                 else selectedstr "this" <+> str "/+subs") |                 else selectedstr "flat" <+> str "/tree") | ||||||
|  |               ,("F" | ||||||
|  |                ,if presentorfuture_ uopts == PFFuture | ||||||
|  |                 then str "present/" <+> selectedstr "future"  | ||||||
|  |                 else selectedstr "present" <+> str "/future") | ||||||
| --               ,("a", "add") | --               ,("a", "add") | ||||||
| --               ,("g", "reload") | --               ,("g", "reload") | ||||||
| --               ,("q", "quit") | --               ,("q", "quit") | ||||||
| @ -329,6 +335,7 @@ rsHandle ui@UIState{ | |||||||
|         VtyEvent (EvKey (KChar 'U') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleUnmarked ui |         VtyEvent (EvKey (KChar 'U') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleUnmarked ui | ||||||
|         VtyEvent (EvKey (KChar 'P') []) -> rsCenterAndContinue $ regenerateScreens j d $ togglePending ui |         VtyEvent (EvKey (KChar 'P') []) -> rsCenterAndContinue $ regenerateScreens j d $ togglePending ui | ||||||
|         VtyEvent (EvKey (KChar 'C') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleCleared 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 (KChar '/') []) -> continue $ regenerateScreens j d $ showMinibuffer ui | ||||||
|         VtyEvent (EvKey (KDown)     [MShift]) -> continue $ regenerateScreens j d $ shrinkReportPeriod d ui |         VtyEvent (EvKey (KDown)     [MShift]) -> continue $ regenerateScreens j d $ shrinkReportPeriod d ui | ||||||
|  | |||||||
| @ -1,11 +1,14 @@ | |||||||
| {-# LANGUAGE CPP #-} | {-# LANGUAGE CPP #-} | ||||||
|  | {-# LANGUAGE DeriveDataTypeable #-} | ||||||
| {-| | {-| | ||||||
| 
 | 
 | ||||||
| -} | -} | ||||||
| 
 | 
 | ||||||
| module Hledger.UI.UIOptions | module Hledger.UI.UIOptions | ||||||
| where | where | ||||||
|  | import Data.Data (Data) | ||||||
| import Data.Default | import Data.Default | ||||||
|  | import Data.Typeable (Typeable) | ||||||
| import Data.List (intercalate) | import Data.List (intercalate) | ||||||
| import System.Environment | import System.Environment | ||||||
| 
 | 
 | ||||||
| @ -35,6 +38,8 @@ uiflags = [ | |||||||
|   --   "show historical ending balance in each period (includes postings before report start date)\n " |   --   "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 ["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 ["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 ["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" |   -- ,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" |   -- ,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 { | data UIOpts = UIOpts { | ||||||
|      watch_   :: Bool |      watch_   :: Bool | ||||||
|     ,change_  :: Bool |     ,change_  :: Bool | ||||||
|  |     ,presentorfuture_  :: PresentOrFutureOpt | ||||||
|     ,cliopts_ :: CliOpts |     ,cliopts_ :: CliOpts | ||||||
|  } deriving (Show) |  } deriving (Show) | ||||||
| 
 | 
 | ||||||
| @ -74,6 +80,7 @@ defuiopts = UIOpts | |||||||
|     def |     def | ||||||
|     def |     def | ||||||
|     def |     def | ||||||
|  |     def | ||||||
| 
 | 
 | ||||||
| -- instance Default CliOpts where def = defcliopts | -- instance Default CliOpts where def = defcliopts | ||||||
| 
 | 
 | ||||||
| @ -83,9 +90,22 @@ rawOptsToUIOpts rawopts = checkUIOpts <$> do | |||||||
|   return defuiopts { |   return defuiopts { | ||||||
|               watch_   = boolopt "watch" rawopts |               watch_   = boolopt "watch" rawopts | ||||||
|              ,change_  = boolopt "change" rawopts |              ,change_  = boolopt "change" rawopts | ||||||
|  |              ,presentorfuture_ = presentorfutureopt rawopts | ||||||
|              ,cliopts_ = cliopts |              ,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 :: UIOpts -> UIOpts | ||||||
| checkUIOpts opts = | checkUIOpts opts = | ||||||
|   either usageError (const opts) $ do |   either usageError (const opts) $ do | ||||||
|  | |||||||
| @ -124,6 +124,14 @@ toggleHistorical ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts | |||||||
|     b | balancetype_ ropts == HistoricalBalance = PeriodChange |     b | balancetype_ ropts == HistoricalBalance = PeriodChange | ||||||
|       | otherwise                               = HistoricalBalance |       | 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. | -- | Toggle between showing all and showing only real (non-virtual) items. | ||||||
| toggleReal :: UIState -> UIState | toggleReal :: UIState -> UIState | ||||||
| toggleReal ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} = | toggleReal ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} = | ||||||
|  | |||||||
| @ -92,6 +92,7 @@ helpDialog copts = | |||||||
|                     ,"cycle cleared/not cleared/all" |                     ,"cycle cleared/not cleared/all" | ||||||
|                     ,"toggle cleared filter" |                     ,"toggle cleared filter" | ||||||
|                     ] !! (statusstyle-1)) |                     ] !! (statusstyle-1)) | ||||||
|  |                   ,renderKey ("F", "toggle future/present") | ||||||
|                   ,renderKey ("R", "toggle real/all") |                   ,renderKey ("R", "toggle real/all") | ||||||
|                   ,renderKey ("Z", "toggle nonzero/all") |                   ,renderKey ("Z", "toggle nonzero/all") | ||||||
|                   ,renderKey ("DEL/BS", "remove filters") |                   ,renderKey ("DEL/BS", "remove filters") | ||||||
|  | |||||||
| @ -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. | for viewing accounts and transactions, and some limited data entry capability. | ||||||
| It is easier than hledger's command-line interface, and  | It is easier than hledger's command-line interface, and  | ||||||
| sometimes quicker and more convenient than the web interface. | 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_ | Like hledger, it reads _files_ | ||||||
| For more about this see hledger(1), hledger_journal(5) etc. | 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` | `-T --tree` | ||||||
| : show accounts as a 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_ | _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). | 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. | `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. | `ESCAPE` removes all filters and jumps back to the top screen. | ||||||
| Or, it cancels a minibuffer edit or help dialog in progress. | 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 | 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.  | running historical balance you would see on a bank register for the current account.  | ||||||
| 
 | 
 | ||||||
| Transactions affecting this account's subaccounts will be shown if | Transactions affecting this account's subaccounts will be included in the register | ||||||
| the accounts screen was in tree mode,  | if the accounts screen is in tree mode,  | ||||||
| or if it was in flat mode but the selected account had depth-clipped subaccounts.  | 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 just the transactions contributing to the balance on the accounts screen. | 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. | 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.  | `U` toggles filtering by [unmarked status](/journal.html#status), showing or hiding unmarked transactions.  | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user