hledger-ui 1.20 → 1.20.1
raw patch · 10 files changed
+152/−132 lines, 10 filesdep ~hledgerdep ~hledger-lib
Dependency ranges changed: hledger, hledger-lib
Files
- CHANGES.md +8/−0
- Hledger/UI/AccountsScreen.hs +5/−4
- Hledger/UI/ErrorScreen.hs +37/−12
- Hledger/UI/Main.hs +1/−2
- Hledger/UI/RegisterScreen.hs +6/−3
- Hledger/UI/UIState.hs +39/−47
- hledger-ui.1 +3/−5
- hledger-ui.cabal +5/−5
- hledger-ui.info +44/−47
- hledger-ui.txt +4/−7
CHANGES.md view
@@ -1,6 +1,14 @@ User-visible changes in hledger-ui. See also the hledger changelog. +# 1.20.1 2020-12-15++- Fix the F key (toggle future/forecast transactions), which in 1.20 + would only work twice. (#1411)++- Fix loss of forecasted transactions when the journal was reloaded+ while they were hidden. (#1204)+ # 1.20 2020-12-05 - When entering a query with `/`, malformed queries/regular expressions
Hledger/UI/AccountsScreen.hs view
@@ -53,11 +53,11 @@ asInit :: Day -> Bool -> UIState -> UIState asInit d reset ui@UIState{- aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportspec_=rspec@ReportSpec{rsOpts=ropts}}},+ aopts=UIOpts{cliopts_=CliOpts{reportspec_=rspec@ReportSpec{rsOpts=ropts}}}, ajournal=j, aScreen=s@AccountsScreen{} } =- ui{aopts=uopts', aScreen=s & asList .~ newitems'}+ ui{aScreen=s & asList .~ newitems'} where newitems = list AccountsList (V.fromList $ displayitems ++ blankitems) 1 @@ -80,7 +80,7 @@ where as = map asItemAccountName displayitems - uopts' = uopts{cliopts_=copts{reportspec_=rspec'}}+ -- Further restrict the query based on the current period and future/forecast mode. rspec' = rspec{rsQuery=simplifyQuery $ And [rsQuery rspec, periodq, excludeforecastq (forecast_ ropts)]} where periodq = Date $ periodAsDateSpan $ period_ ropts@@ -106,7 +106,8 @@ Mixed amts = normaliseMixedAmountSquashPricesForDisplay $ stripPrices bal stripPrices (Mixed as) = Mixed $ map stripprice as where stripprice a = a{aprice=Nothing} displayitems = map displayitem items- -- blanks added for scrolling control, cf RegisterScreen+ -- blanks added for scrolling control, cf RegisterScreen.+ -- XXX Ugly. Changing to 0 helps when debugging. blankitems = replicate 100 AccountsScreenItem{asItemIndentLevel = 0 ,asItemAccountName = ""
Hledger/UI/ErrorScreen.hs view
@@ -30,6 +30,7 @@ import Hledger.UI.UIState import Hledger.UI.UIUtils import Hledger.UI.Editor+import Data.Foldable (asum) errorScreen :: Screen errorScreen = ErrorScreen{@@ -137,36 +138,60 @@ ] --- Unconditionally reload the journal, regenerating the current screen--- and all previous screens in the history.+-- | Unconditionally reload the journal, regenerating the current screen+-- and all previous screens in the history as of the provided today-date. -- If reloading fails, enter the error screen, or if we're already -- on the error screen, update the error displayed.--- The provided CliOpts are used for reloading, and then saved--- in the UIState if reloading is successful (otherwise the--- ui state keeps its old cli opts.) -- Defined here so it can reference the error screen.+--+-- The provided CliOpts are used for reloading, and then saved in the+-- UIState if reloading is successful (otherwise the UIState keeps its old+-- CliOpts.) (XXX needed for.. ?)+--+-- Forecasted transactions are always generated, as at hledger-ui startup.+-- If a forecast period is specified in the provided opts, or was specified+-- at startup, it is preserved.+-- uiReloadJournal :: CliOpts -> Day -> UIState -> IO UIState uiReloadJournal copts d ui = do- ej <- journalReload copts+ ej <-+ let copts' = enableForecastPreservingPeriod ui copts+ in journalReload copts' return $ case ej of- Right j -> regenerateScreens j d ui{aopts=(aopts ui){cliopts_=copts}}+ Right j -> regenerateScreens j d ui Left err -> case ui of UIState{aScreen=s@ErrorScreen{}} -> ui{aScreen=s{esError=err}} _ -> screenEnter d errorScreen{esError=err} ui --- Like uiReloadJournal, but does not bother re-parsing the journal if--- the file(s) have not changed since last loaded. Always regenerates--- the current and previous screens though, since opts or date may have changed.+-- | Like uiReloadJournal, but does not re-parse the journal if the file(s)+-- have not changed since last loaded. Always regenerates the screens though,+-- since the provided options or today-date may have changed. uiReloadJournalIfChanged :: CliOpts -> Day -> Journal -> UIState -> IO UIState uiReloadJournalIfChanged copts d j ui = do- (ej, _changed) <- journalReloadIfChanged copts d j+ (ej, _changed) <-+ let copts' = enableForecastPreservingPeriod ui copts+ in journalReloadIfChanged copts' d j return $ case ej of- Right j' -> regenerateScreens j' d ui{aopts=(aopts ui){cliopts_=copts}}+ Right j' -> regenerateScreens j' d ui Left err -> case ui of UIState{aScreen=s@ErrorScreen{}} -> ui{aScreen=s{esError=err}} _ -> screenEnter d errorScreen{esError=err} ui++-- | Ensure this CliOpts enables forecasted transactions.+-- If a forecast period was specified in the old CliOpts,+-- or in the provided UIState's startup options,+-- it is preserved.+enableForecastPreservingPeriod :: UIState -> CliOpts -> CliOpts+enableForecastPreservingPeriod ui copts@CliOpts{reportspec_=rspec@ReportSpec{rsOpts=ropts}} =+ copts{reportspec_=rspec{rsOpts=ropts{forecast_=mforecast}}}+ where+ mforecast = asum [mprovidedforecastperiod, mstartupforecastperiod, mdefaultforecastperiod]+ where+ mprovidedforecastperiod = forecast_ ropts+ mstartupforecastperiod = forecast_ $ rsOpts $ reportspec_ $ cliopts_ $ astartupopts ui+ mdefaultforecastperiod = Just nulldatespan -- Re-check any balance assertions in the current journal, and if any -- fail, enter (or update) the error screen. Or if balance assertions
Hledger/UI/Main.hs view
@@ -54,8 +54,7 @@ opts@UIOpts{cliopts_=copts@CliOpts{inputopts_=_iopts,reportspec_=rspec@ReportSpec{rsOpts=ropts},rawopts_=rawopts}} <- getHledgerUIOpts -- when (debug_ $ cliopts_ opts) $ printf "%s\n" prognameandversion >> printf "opts: %s\n" (show opts) - -- always include forecasted periodic transactions when loading data;- -- they will be toggled on and off in the UI.+ -- always generate forecasted periodic transactions; their visibility will be toggled by the UI. let copts' = copts{reportspec_=rspec{rsOpts=ropts{forecast_=Just $ fromMaybe nulldatespan (forecast_ ropts)}}} case True of
Hledger/UI/RegisterScreen.hs view
@@ -66,8 +66,10 @@ -- XXX temp inclusive = tree_ ropts || rsForceInclusive thisacctq = Acct $ (if inclusive then accountNameToAccountRegex else accountNameToAccountOnlyRegex) rsAccount+ rspec' = rspec{rsOpts=ropts{depth_=Nothing}}- q = And [rsQuery rspec, periodq, excludeforecastq (forecast_ ropts)]+ -- Further restrict the query based on the current period and future/forecast mode.+ q = simplifyQuery $ And [rsQuery rspec, periodq, excludeforecastq (forecast_ ropts)] where periodq = Date $ periodAsDateSpan $ period_ ropts -- Except in forecast mode, exclude future/forecast transactions.@@ -98,8 +100,9 @@ ,rsItemBalanceAmount = showMixedOneLine showAmountWithoutPrice Nothing (Just 32) False bal ,rsItemTransaction = t }- -- blank items are added to allow more control of scroll position; we won't allow movement over these- blankitems = replicate 100 -- 100 ought to be enough for anyone+ -- blank items are added to allow more control of scroll position; we won't allow movement over these.+ -- XXX Ugly. Changing to 0 helps when debugging.+ blankitems = replicate 100 -- "100 ought to be enough for anyone" RegisterScreenItem{rsItemDate = "" ,rsItemStatus = Unmarked ,rsItemDescription = ""
Hledger/UI/UIState.hs view
@@ -22,17 +22,17 @@ -- | Toggle between showing only unmarked items or all items. toggleUnmarked :: UIState -> UIState toggleUnmarked ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportspec_=rspec}}} =- ui{aopts=uopts{cliopts_=copts{reportspec_=reportSpecToggleStatusSomehow Unmarked copts rspec}}}+ ui{aopts=uopts{cliopts_=copts{reportspec_=reportSpecToggleStatus Unmarked copts rspec}}} -- | Toggle between showing only pending items or all items. togglePending :: UIState -> UIState togglePending ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportspec_=rspec}}} =- ui{aopts=uopts{cliopts_=copts{reportspec_=reportSpecToggleStatusSomehow Pending copts rspec}}}+ ui{aopts=uopts{cliopts_=copts{reportspec_=reportSpecToggleStatus Pending copts rspec}}} -- | Toggle between showing only cleared items or all items. toggleCleared :: UIState -> UIState toggleCleared ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportspec_=rspec}}} =- ui{aopts=uopts{cliopts_=copts{reportspec_=reportSpecToggleStatusSomehow Cleared copts rspec}}}+ ui{aopts=uopts{cliopts_=copts{reportspec_=reportSpecToggleStatus Cleared copts rspec}}} -- TODO testing different status toggle styles @@ -52,18 +52,13 @@ showstatus Pending = "pending" showstatus Unmarked = "unmarked" -reportSpecToggleStatusSomehow :: Status -> CliOpts -> ReportSpec -> ReportSpec-reportSpecToggleStatusSomehow s copts =- either (error "reportSpecToggleStatusSomehow: updating Status should not result in an error") id -- PARTIAL:- . updateReportSpecFromOpts update- where- update = case maybeposintopt "status-toggles" $ rawopts_ copts of- Just 2 -> reportOptsToggleStatus2 s- Just 3 -> reportOptsToggleStatus3 s--- Just 4 -> reportOptsToggleStatus4 s--- Just 5 -> reportOptsToggleStatus5 s- _ -> reportOptsToggleStatus1 s+reportSpecToggleStatus :: Status -> CliOpts -> ReportSpec -> ReportSpec+reportSpecToggleStatus s _copts =+ either (error "reportSpecToggleStatus: changing status should not have caused this error") id -- PARTIAL:+ . updateReportSpecWith (reportOptsToggleStatus1 s) +-- various toggle behaviours:+ -- 1 UPC toggles only X/all reportOptsToggleStatus1 s ropts@ReportOpts{statuses_=ss} | ss == [s] = ropts{statuses_=[]}@@ -77,21 +72,21 @@ -- pressing Y after first or second step starts new cycle: -- [u] P [p] -- [pc] P [p]-reportOptsToggleStatus2 s ropts@ReportOpts{statuses_=ss}- | ss == [s] = ropts{statuses_=complement [s]}- | ss == complement [s] = ropts{statuses_=[]}- | otherwise = ropts{statuses_=[s]} -- XXX assume only three values+-- reportOptsToggleStatus2 s ropts@ReportOpts{statuses_=ss}+-- | ss == [s] = ropts{statuses_=complement [s]}+-- | ss == complement [s] = ropts{statuses_=[]}+-- | otherwise = ropts{statuses_=[s]} -- XXX assume only three values -- 3 UPC toggles each X-reportOptsToggleStatus3 s ropts@ReportOpts{statuses_=ss}- | s `elem` ss = ropts{statuses_=filter (/= s) ss}- | otherwise = ropts{statuses_=simplifyStatuses (s:ss)}+-- reportOptsToggleStatus3 s ropts@ReportOpts{statuses_=ss}+-- | s `elem` ss = ropts{statuses_=filter (/= s) ss}+-- | otherwise = ropts{statuses_=simplifyStatuses (s:ss)} -- 4 upc sets X, UPC sets not-X --reportOptsToggleStatus4 s ropts@ReportOpts{statuses_=ss} -- | s `elem` ss = ropts{statuses_=filter (/= s) ss} -- | otherwise = ropts{statuses_=simplifyStatuses (s:ss)}---+ -- 5 upc toggles X, UPC toggles not-X --reportOptsToggleStatus5 s ropts@ReportOpts{statuses_=ss} -- | s `elem` ss = ropts{statuses_=filter (/= s) ss}@@ -163,36 +158,33 @@ b | balancetype_ ropts == HistoricalBalance = PeriodChange | otherwise = HistoricalBalance --- | Toggle hledger-ui's "forecast mode". In forecast mode, periodic--- transactions (generated by periodic rules) are enabled (as with--- hledger --forecast), and also future transactions in general--- (including non-periodic ones) are displayed. In normal mode, all--- future transactions (periodic or not) are suppressed (unlike--- command-line hledger).------ After toggling this, we do a full reload of the journal from disk--- to make it take effect; currently that's done in the callers (cf--- AccountsScreen, RegisterScreen) where it's easier. This is--- overkill, probably we should just hide/show the periodic--- transactions with a query for their special tag.---+-- | Toggle hledger-ui's "forecast/future mode". When this mode is enabled,+-- hledger-shows regular transactions which have future dates, and+-- "forecast" transactions generated by periodic transaction rules+-- (which are usually but not necessarily future-dated).+-- In normal mode, both of these are hidden. toggleForecast :: Day -> UIState -> UIState-toggleForecast d ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportspec_=rspec@ReportSpec{rsOpts=ropts}}}} =- ui{aopts=uopts{cliopts_=copts'}}- where- copts' = copts{reportspec_=rspec{rsOpts=ropts{forecast_=forecast'}}}- forecast' =- case forecast_ ropts of- Just _ -> Nothing- Nothing -> Just $ fromMaybe nulldatespan $ forecastPeriodFromRawOpts d $ rawopts_ copts+toggleForecast d ui@UIState{aopts=UIOpts{cliopts_=copts@CliOpts{reportspec_=ReportSpec{rsOpts=ropts}}}} =+ uiSetForecast ui $+ case forecast_ ropts of+ Just _ -> Nothing+ Nothing -> Just $ fromMaybe nulldatespan $ forecastPeriodFromRawOpts d $ rawopts_ copts +-- | Helper: set forecast mode (with the given forecast period) on or off in the UI state.+uiSetForecast :: UIState -> Maybe DateSpan -> UIState+uiSetForecast+ ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportspec_=rspec@ReportSpec{rsOpts=ropts}}}}+ mforecast =+ -- we assume forecast mode has no effect on ReportSpec's derived fields+ ui{aopts=uopts{cliopts_=copts{reportspec_=rspec{rsOpts=ropts{forecast_=mforecast}}}}}+ -- | Toggle between showing all and showing only real (non-virtual) items. toggleReal :: UIState -> UIState toggleReal ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportspec_=rspec}}} = ui{aopts=uopts{cliopts_=copts{reportspec_=update rspec}}} where update = either (error "toggleReal: updating Real should not result in an error") id -- PARTIAL:- . updateReportSpecFromOpts (\ropts -> ropts{real_=not $ real_ ropts})+ . updateReportSpecWith (\ropts -> ropts{real_=not $ real_ ropts}) -- | Toggle the ignoring of balance assertions. toggleIgnoreBalanceAssertions :: UIState -> UIState@@ -240,14 +232,14 @@ ui{aopts=uopts{cliopts_=copts{reportspec_=update rspec}}} where update = either (error "updateReportPeriod: updating period should not result in an error") id -- PARTIAL:- . updateReportSpecFromOpts (\ropts -> ropts{period_=updatePeriod $ period_ ropts})+ . updateReportSpecWith (\ropts -> ropts{period_=updatePeriod $ period_ ropts}) -- | Apply a new filter query. setFilter :: String -> UIState -> UIState setFilter s ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportspec_=rspec}}} = ui{aopts=uopts{cliopts_=copts{reportspec_=update rspec}}} where- update = either (const rspec) id . updateReportSpecFromOpts (\ropts -> ropts{querystring_=querystring})+ update = either (const rspec) id . updateReportSpecWith (\ropts -> ropts{querystring_=querystring}) querystring = words'' prefixes $ T.pack s -- | Reset some filters & toggles.@@ -306,7 +298,7 @@ ui{aopts=uopts{cliopts_=copts{reportspec_=update rspec}}} where update = either (error "updateReportDepth: updating depth should not result in an error") id -- PARTIAL:- . updateReportSpecFromOpts (\ropts -> ropts{depth_=updateDepth (depth_ ropts) >>= clipDepth ropts})+ . updateReportSpecWith (\ropts -> ropts{depth_=updateDepth (depth_ ropts) >>= clipDepth ropts}) clipDepth ropts d | d < 0 = depth_ ropts | d >= maxDepth ui = Nothing | otherwise = Just d
hledger-ui.1 view
@@ -1,5 +1,5 @@ -.TH "hledger-ui" "1" "November 2020" "hledger-ui 1.20" "hledger User Manuals"+.TH "hledger-ui" "1" "December 2020" "hledger-ui 1.20.1" "hledger User Manuals" @@ -500,13 +500,11 @@ .SH COPYRIGHT -Copyright (C) 2007-2019 Simon Michael.+Copyright (C) 2007-2020 Simon Michael. .br Released under GNU GPL v3 or later. .SH SEE ALSO-hledger(1), hledger\-ui(1), hledger\-web(1), hledger\-api(1),+hledger(1), hledger\-ui(1), hledger\-web(1), hledger_csv(5), hledger_journal(5), hledger_timeclock(5), hledger_timedot(5), ledger(1)--http://hledger.org
hledger-ui.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 4007bd6deffcff3c3d5a40863cfa11bddaed31c367fdf5033728ec847c292a91+-- hash: aa2ee3de3cbd0649f1506526856f8646a597192d6dcd5e80e30204b3b6764578 name: hledger-ui-version: 1.20+version: 1.20.1 synopsis: Curses-style terminal interface for the hledger accounting system description: A simple curses-style terminal user interface for the hledger accounting system. It can be a more convenient way to browse your accounts than the CLI.@@ -64,7 +64,7 @@ hs-source-dirs: ./. ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans- cpp-options: -DVERSION="1.20"+ cpp-options: -DVERSION="1.20.1" build-depends: ansi-terminal >=0.9 , async@@ -78,8 +78,8 @@ , extra >=1.6.3 , filepath , fsnotify >=0.2.1.2 && <0.4- , hledger >=1.20 && <1.21- , hledger-lib >=1.20 && <1.21+ , hledger >=1.20.1 && <1.21+ , hledger-lib >=1.20.1 && <1.21 , megaparsec >=7.0.0 && <9.1 , microlens >=0.4 , microlens-platform >=0.2.3.1
hledger-ui.info view
@@ -3,8 +3,8 @@ File: hledger-ui.info, Node: Top, Next: OPTIONS, Up: (dir) -hledger-ui(1) hledger-ui 1.20-*****************************+hledger-ui(1) hledger-ui 1.20.1+******************************* hledger-ui - terminal interface for the hledger accounting tool @@ -38,6 +38,10 @@ * OPTIONS:: * keys:: * screens::+* accounts screen::+* Register screen::+* Transaction screen::+* Error screen:: * ENVIRONMENT:: * FILES:: * BUGS::@@ -306,23 +310,16 @@ additional screen-specific keys are described below. -File: hledger-ui.info, Node: screens, Next: ENVIRONMENT, Prev: keys, Up: Top+File: hledger-ui.info, Node: screens, Next: accounts screen, Prev: keys, Up: Top 3 screens ********* -* Menu:--* accounts screen::-* Register screen::-* Transaction screen::-* Error screen::- -File: hledger-ui.info, Node: accounts screen, Next: Register screen, Up: screens+File: hledger-ui.info, Node: accounts screen, Next: Register screen, Prev: screens, Up: Top -3.1 accounts screen-===================+4 accounts screen+***************** this is normally the first screen displayed. it lists accounts and their balances, like hledger's balance command. by default, it shows@@ -368,10 +365,10 @@ Press 'right' or 'enter' to view an account's transactions register. -File: hledger-ui.info, Node: Register screen, Next: Transaction screen, Prev: accounts screen, Up: screens+File: hledger-ui.info, Node: Register screen, Next: Transaction screen, Prev: accounts screen, Up: Top -3.2 Register screen-===================+5 Register screen+***************** This screen shows the transactions affecting a particular account, like a check register. Each line represents one transaction and shows:@@ -415,10 +412,10 @@ detail. -File: hledger-ui.info, Node: Transaction screen, Next: Error screen, Prev: Register screen, Up: screens+File: hledger-ui.info, Node: Transaction screen, Next: Error screen, Prev: Register screen, Up: Top -3.3 Transaction screen-======================+6 Transaction screen+******************** This screen shows a single transaction, as a general journal entry, similar to hledger's print command and journal format@@ -439,10 +436,10 @@ reload). -File: hledger-ui.info, Node: Error screen, Prev: Transaction screen, Up: screens+File: hledger-ui.info, Node: Error screen, Next: ENVIRONMENT, Prev: Transaction screen, Up: Top -3.4 Error screen-================+7 Error screen+************** This screen will appear if there is a problem, such as a parse error, when you press g to reload. Once you have fixed the problem, press g@@ -450,9 +447,9 @@ to cancel the reload attempt.) -File: hledger-ui.info, Node: ENVIRONMENT, Next: FILES, Prev: screens, Up: Top+File: hledger-ui.info, Node: ENVIRONMENT, Next: FILES, Prev: Error screen, Up: Top -4 ENVIRONMENT+8 ENVIRONMENT ************* *COLUMNS* The screen width to use. Default: the full terminal width.@@ -480,7 +477,7 @@ File: hledger-ui.info, Node: FILES, Next: BUGS, Prev: ENVIRONMENT, Up: Top -5 FILES+9 FILES ******* Reads data from one or more files in hledger journal, timeclock,@@ -491,8 +488,8 @@ File: hledger-ui.info, Node: BUGS, Prev: FILES, Up: Top -6 BUGS-******+10 BUGS+******* The need to precede options with '--' when invoked from hledger is awkward.@@ -519,26 +516,26 @@ Tag Table: Node: Top71-Node: OPTIONS1470-Ref: #options1567-Node: keys5634-Ref: #keys5729-Node: screens10061-Ref: #screens10166-Node: accounts screen10256-Ref: #accounts-screen10384-Node: Register screen12599-Ref: #register-screen12754-Node: Transaction screen14751-Ref: #transaction-screen14909-Node: Error screen15779-Ref: #error-screen15901-Node: ENVIRONMENT16145-Ref: #environment16259-Node: FILES17066-Ref: #files17165-Node: BUGS17378-Ref: #bugs17455+Node: OPTIONS1554+Ref: #options1651+Node: keys5718+Ref: #keys5813+Node: screens10145+Ref: #screens10254+Node: accounts screen10254+Ref: #accounts-screen10390+Node: Register screen12605+Ref: #register-screen12752+Node: Transaction screen14749+Ref: #transaction-screen14899+Node: Error screen15769+Ref: #error-screen15903+Node: ENVIRONMENT16147+Ref: #environment16266+Node: FILES17073+Ref: #files17172+Node: BUGS17385+Ref: #bugs17464 End Tag Table
hledger-ui.txt view
@@ -447,17 +447,14 @@ COPYRIGHT- Copyright (C) 2007-2019 Simon Michael.+ Copyright (C) 2007-2020 Simon Michael. Released under GNU GPL v3 or later. SEE ALSO- hledger(1), hledger-ui(1), hledger-web(1), hledger-api(1),- hledger_csv(5), hledger_journal(5), hledger_timeclock(5), hledger_time-- dot(5), ledger(1)-- http://hledger.org+ hledger(1), hledger-ui(1), hledger-web(1), hledger_csv(5),+ hledger_journal(5), hledger_timeclock(5), hledger_timedot(5), ledger(1) -hledger-ui 1.20 November 2020 hledger-ui(1)+hledger-ui 1.20.1 December 2020 hledger-ui(1)