hledger-ui 1.2 → 1.3
raw patch · 13 files changed
+548/−242 lines, 13 filesdep ~brickdep ~hledgerdep ~hledger-lib
Dependency ranges changed: brick, hledger, hledger-lib
Files
- CHANGES +44/−1
- Hledger/UI/AccountsScreen.hs +82/−40
- Hledger/UI/ErrorScreen.hs +3/−3
- Hledger/UI/RegisterScreen.hs +99/−41
- Hledger/UI/TransactionScreen.hs +5/−5
- Hledger/UI/UIOptions.hs +9/−0
- Hledger/UI/UIState.hs +82/−18
- Hledger/UI/UITypes.hs +1/−0
- Hledger/UI/UIUtils.hs +76/−18
- doc/hledger-ui.1 +28/−17
- doc/hledger-ui.1.info +39/−29
- doc/hledger-ui.1.txt +74/−64
- hledger-ui.cabal +6/−6
CHANGES view
@@ -2,8 +2,50 @@ See also the hledger and project change logs. -# 1.2 (2016/3/31)+# 1.3 (2017/6/30) +Deps: allow brick 0.19 (#575, Felix Yan, Simon Michael)++The P key toggles pending mode.+Also there is a temporary --status-toggles flag for testing different+toggle styles, see `hledger-ui -h`. (#564)++There is now less "warping" of selection when lists change:++- When the selected account disappears, eg when toggling zero+ accounts, the selection moves to the alphabetically preceding item,+ instead of the first one.++- When the selected transaction disappears, eg when toggling status+ filters, the selection moves to the nearest transaction by date (and+ if several have the same date, by journal order), instead of the+ last one.++In the accounts and register screens, you can now scroll down further+so that the last item need not always be shown at the bottom of the+screen. Also we now try to center the selected item in the following+situations:++- after moving to the end with Page down/End+- after toggling filters (status, real, historical..)+- on pressing the control-l key (should force a screen redraw, also)+- on entering the register screen from the accounts screen (there's a+ known problem with this: it doesn't work the first time).++Items near the top of the list can't be centered, as we don't scroll+higher than the top of the list.++Emacs movement keys are now supported, as well as VI keys.+hjkl and CTRL-bfnp should work wherever unmodified arrow keys work.++The register screen now shows transaction status marks.++In the transaction screen, amounts are now better aligned, eg when+there are posting status marks or virtual postings.+++# 1.2 (2017/3/31)+ Fix a pattern match failure when pressing E on the transaction screen (fixes #508) Accounts with ? in name had empty registers (fixes #498) (Bryan Richter)@@ -20,6 +62,7 @@ - allow brick 0.16 (Joshua Chia) - drop obsolete --no-elide flag+ # 1.1 (2016/12/31)
Hledger/UI/AccountsScreen.hs view
@@ -24,6 +24,7 @@ import qualified Data.Vector as V import Graphics.Vty (Event(..),Key(..),Modifier(..)) import Lens.Micro.Platform+import Safe import System.Console.ANSI import System.FilePath (takeFileName) @@ -54,19 +55,27 @@ } = ui{aopts=uopts', aScreen=s & asList .~ newitems'} where- newitems = list AccountsList (V.fromList displayitems) 1+ newitems = list AccountsList (V.fromList $ displayitems ++ blankitems) 1 - -- keep the selection near the last selected account- -- (may need to move to the next leaf account when entering flat mode)+ -- decide which account is selected:+ -- if reset is true, the first account;+ -- otherwise, the previously selected account if possible;+ -- otherwise, the first account with the same prefix (eg first leaf account when entering flat mode);+ -- otherwise, the alphabetically preceding account. newitems' = listMoveTo selidx newitems where selidx = case (reset, listSelectedElement $ _asList s) of (True, _) -> 0 (_, Nothing) -> 0- (_, Just (_,AccountsScreenItem{asItemAccountName=a})) -> fromMaybe (fromMaybe 0 mprefixmatch) mexactmatch- where- mexactmatch = findIndex ((a ==) . asItemAccountName) displayitems- mprefixmatch = findIndex ((a `isAccountNamePrefixOf`) . asItemAccountName) displayitems+ (_, Just (_,AccountsScreenItem{asItemAccountName=a})) -> + headDef 0 $ catMaybes [+ findIndex (a ==) as+ ,findIndex (a `isAccountNamePrefixOf`) as+ ,Just $ max 0 (length (filter (< a) as) - 1)+ ]+ where+ as = map asItemAccountName displayitems+ uopts' = uopts{cliopts_=copts{reportopts_=ropts'}} ropts' = ropts{accountlistmode_=if flat_ ropts then ALFlat else ALTree} @@ -98,6 +107,13 @@ Mixed amts = normaliseMixedAmountSquashPricesForDisplay $ stripPrices bal stripPrices (Mixed as) = Mixed $ map stripprice as where stripprice a = a{aprice=NoPrice} displayitems = map displayitem items+ -- blanks added for scrolling control, cf RegisterScreen + blankitems = replicate 100+ AccountsScreenItem{asItemIndentLevel = 0+ ,asItemAccountName = ""+ ,asItemDisplayAccountName = ""+ ,asItemRenderedAmounts = []+ } asInit _ _ _ = error "init function called with wrong screen type, should not happen"@@ -109,7 +125,7 @@ ,aMode=mode } = case mode of- Help -> [helpDialog, maincontent]+ Help -> [helpDialog copts, maincontent] -- Minibuffer e -> [minibuffer e, maincontent] _ -> [maincontent] where@@ -181,7 +197,7 @@ mdepth = depth_ ropts togglefilters = case concat [- uiShowClearedStatus $ clearedstatus_ ropts+ uiShowStatus copts $ statuses_ ropts ,if real_ ropts then ["real"] else [] ] of [] -> str ""@@ -191,7 +207,8 @@ cur = str (case _asList s ^. listSelectedL of Nothing -> "-" Just i -> show (i + 1))- total = str $ show $ V.length $ s ^. asList . listElementsL+ total = str $ show $ V.length nonblanks + nonblanks = V.takeWhile (not . T.null . asItemAccountName) $ s ^. asList . listElementsL bottomlabel = case mode of Minibuffer ed -> minibuffer ed@@ -255,9 +272,9 @@ ,aMode=mode } ev = do d <- liftIO getCurrentDay- -- c <- getContext- -- let h = c^.availHeightL- -- moveSel n l = listMoveBy n l+ let+ nonblanks = V.takeWhile (not . T.null . asItemAccountName) $ _asList^.listElementsL+ lastnonblankidx = max 0 (length nonblanks - 1) -- save the currently selected account, in case we leave this screen and lose the selection let@@ -315,50 +332,70 @@ VtyEvent (EvKey (KChar '_') []) -> continue $ regenerateScreens j d $ decDepth ui VtyEvent (EvKey (KChar c) []) | c `elem` ['+','='] -> continue $ regenerateScreens j d $ incDepth ui VtyEvent (EvKey (KChar 't') []) -> continue $ regenerateScreens j d $ setReportPeriod (DayPeriod d) ui- VtyEvent (EvKey (KChar 'H') []) -> continue $ regenerateScreens j d $ toggleHistorical ui- VtyEvent (EvKey (KChar 'F') []) -> continue $ regenerateScreens j d $ toggleFlat ui- VtyEvent (EvKey (KChar 'Z') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleEmpty ui)- VtyEvent (EvKey (KChar 'C') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleCleared ui)- VtyEvent (EvKey (KChar 'U') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleUncleared ui)- VtyEvent (EvKey (KChar 'R') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleReal ui)++ -- display mode/query toggles+ VtyEvent (EvKey (KChar 'H') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleHistorical ui+ VtyEvent (EvKey (KChar 'F') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleFlat ui+ VtyEvent (EvKey (KChar 'Z') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleEmpty ui+ VtyEvent (EvKey (KChar 'R') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleReal ui+ 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 (KDown) [MShift]) -> continue $ regenerateScreens j d $ shrinkReportPeriod d ui VtyEvent (EvKey (KUp) [MShift]) -> continue $ regenerateScreens j d $ growReportPeriod d ui VtyEvent (EvKey (KRight) [MShift]) -> continue $ regenerateScreens j d $ nextReportPeriod journalspan ui VtyEvent (EvKey (KLeft) [MShift]) -> continue $ regenerateScreens j d $ previousReportPeriod journalspan ui VtyEvent (EvKey (KChar '/') []) -> continue $ regenerateScreens j d $ showMinibuffer ui VtyEvent (EvKey k []) | k `elem` [KBS, KDel] -> (continue $ regenerateScreens j d $ resetFilter ui)- VtyEvent (EvKey k []) | k `elem` [KLeft, KChar 'h'] -> continue $ popScreen ui- VtyEvent (EvKey k []) | k `elem` [KRight, KChar 'l'] -> scrollTopRegister >> continue (screenEnter d scr ui)+ VtyEvent e | e `elem` moveLeftEvents -> continue $ popScreen ui+ VtyEvent (EvKey (KChar 'l') [MCtrl]) -> scrollSelectionToMiddle _asList >> invalidateCache >> continue ui++ -- enter register screen for selected account (if there is one), + -- centering its selected transaction if possible+ VtyEvent e | e `elem` moveRightEvents + , not $ isBlankElement $ listSelectedElement _asList->+ -- TODO center selection after entering register screen; neither of these works till second time entering; easy strictifications didn't help + rsCenterAndContinue $ + -- flip rsHandle (VtyEvent (EvKey (KChar 'l') [MCtrl])) $+ screenEnter d regscr ui where- scr = rsSetAccount selacct isdepthclipped registerScreen+ regscr = rsSetAccount selacct isdepthclipped registerScreen isdepthclipped = case getDepth ui of Just d -> accountNameLevel selacct >= d Nothing -> False + -- prevent moving down over blank padding items;+ -- instead scroll down by one, until maximally scrolled - shows the end has been reached+ VtyEvent (EvKey (KDown) []) | isBlankElement mnextelement -> do+ vScrollBy (viewportScroll $ _asList^.listNameL) 1 + continue ui+ where + mnextelement = listSelectedElement $ listMoveDown _asList++ -- if page down or end leads to a blank padding item, stop at last non-blank+ VtyEvent e@(EvKey k []) | k `elem` [KPageDown, KEnd] -> do+ list <- handleListEvent e _asList+ if isBlankElement $ listSelectedElement list+ then do+ let list' = listMoveTo lastnonblankidx list+ scrollSelectionToMiddle list'+ continue ui{aScreen=scr{_asList=list'}}+ else+ continue ui{aScreen=scr{_asList=list}}+ -- fall through to the list's event handler (handles up/down)- VtyEvent ev ->- do- let ev' = case ev of- EvKey (KChar 'k') [] -> EvKey (KUp) []- EvKey (KChar 'j') [] -> EvKey (KDown) []- _ -> ev- newitems <- handleListEvent ev' _asList- continue $ ui{aScreen=scr & asList .~ newitems- & asSelectedAccount .~ selacct- }- -- continue =<< handleEventLensed ui someLens ev+ VtyEvent ev -> do+ newitems <- handleListEvent (normaliseMovementKeys ev) _asList+ continue $ ui{aScreen=scr & asList .~ newitems+ & asSelectedAccount .~ selacct+ }+ AppEvent _ -> continue ui MouseDown _ _ _ _ -> continue ui MouseUp _ _ _ -> continue ui where- -- Encourage a more stable scroll position when toggling list items.- -- We scroll to the top, and the viewport will automatically- -- scroll down just far enough to reveal the selection, which- -- usually leaves it at bottom of screen).- -- XXX better: scroll so selection is in middle of screen ?- scrollTop = vScrollToBeginning $ viewportScroll AccountsViewport- scrollTopRegister = vScrollToBeginning $ viewportScroll RegisterViewport journalspan = journalDateSpan False j asHandle _ _ = error "event handler called with wrong screen type, should not happen"@@ -366,3 +403,8 @@ asSetSelectedAccount a s@AccountsScreen{} = s & asSelectedAccount .~ a asSetSelectedAccount _ s = s +isBlankElement mel = ((asItemAccountName . snd) <$> mel) == Just "" ++asCenterAndContinue ui = do+ scrollSelectionToMiddle $ _asList $ aScreen ui+ continue ui
Hledger/UI/ErrorScreen.hs view
@@ -39,11 +39,11 @@ esInit _ _ _ = error "init function called with wrong screen type, should not happen" esDraw :: UIState -> [Widget Name]-esDraw UIState{ --aopts=UIOpts{cliopts_=copts@CliOpts{}}- aScreen=ErrorScreen{..}+esDraw UIState{aopts=UIOpts{cliopts_=copts@CliOpts{}}+ ,aScreen=ErrorScreen{..} ,aMode=mode} = case mode of- Help -> [helpDialog, maincontent]+ Help -> [helpDialog copts, maincontent] -- Minibuffer e -> [minibuffer e, maincontent] _ -> [maincontent] where
Hledger/UI/RegisterScreen.hs view
@@ -4,11 +4,12 @@ module Hledger.UI.RegisterScreen (registerScreen+ ,rsHandle ,rsSetAccount+ ,rsCenterAndContinue ) where -import Lens.Micro.Platform ((^.)) import Control.Monad import Control.Monad.IO.Class (liftIO) import Data.List@@ -16,13 +17,15 @@ import Data.Monoid import Data.Maybe import qualified Data.Text as T-import Data.Time.Calendar (Day)+import Data.Time.Calendar import qualified Data.Vector as V import Graphics.Vty (Event(..),Key(..),Modifier(..)) import Brick import Brick.Widgets.List import Brick.Widgets.Edit import Brick.Widgets.Border (borderAttr)+import Lens.Micro.Platform+import Safe import System.Console.ANSI @@ -76,6 +79,7 @@ where displayitem (t, _, _issplit, otheracctsstr, change, bal) = RegisterScreenItem{rsItemDate = showDate $ transactionRegisterDate q thisacctq t+ ,rsItemStatus = tstatus t ,rsItemDescription = T.unpack $ tdescription t ,rsItemOtherAccounts = case splitOn ", " otheracctsstr of [s] -> s@@ -85,20 +89,41 @@ ,rsItemBalanceAmount = showMixedAmountOneLineWithoutPrice 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+ RegisterScreenItem{rsItemDate = ""+ ,rsItemStatus = Unmarked+ ,rsItemDescription = ""+ ,rsItemOtherAccounts = ""+ ,rsItemChangeAmount = ""+ ,rsItemBalanceAmount = ""+ ,rsItemTransaction = nulltransaction+ } -- build the List- newitems = list RegisterList (V.fromList displayitems) 1+ newitems = list RegisterList (V.fromList $ displayitems ++ blankitems) 1 - -- keep the selection on the previously selected transaction if possible,- -- (eg after toggling nonzero mode), otherwise select the last element.+ -- decide which transaction is selected:+ -- if reset is true, the last (latest) transaction;+ -- otherwise, the previously selected transaction if possible;+ -- otherwise, the transaction nearest in date to it;+ -- or if there's several with the same date, the nearest in journal order;+ -- otherwise, the last (latest) transaction. newitems' = listMoveTo newselidx newitems where- newselidx = case (reset, listSelectedElement rsList) of- (True, _) -> endidx- (_, Nothing) -> endidx- (_, Just (_,RegisterScreenItem{rsItemTransaction=Transaction{tindex=ti}}))- -> fromMaybe endidx $ findIndex ((==ti) . tindex . rsItemTransaction) displayitems- endidx = length displayitems+ newselidx = + case (reset, listSelectedElement rsList) of+ (True, _) -> endidx+ (_, Nothing) -> endidx+ (_, Just (_, RegisterScreenItem{rsItemTransaction=Transaction{tindex=prevselidx, tdate=prevseld}})) ->+ headDef endidx $ catMaybes [+ findIndex ((==prevselidx) . tindex . rsItemTransaction) displayitems+ ,findIndex ((==nearestidbydatethenid) . Just . tindex . rsItemTransaction) displayitems+ ]+ where+ nearestidbydatethenid = third3 <$> (headMay $ sort+ [(abs $ diffDays (tdate t) prevseld, abs (tindex t - prevselidx), tindex t) | t <- ts])+ ts = map rsItemTransaction displayitems+ endidx = length displayitems - 1 rsInit _ _ _ = error "init function called with wrong screen type, should not happen" @@ -108,7 +133,7 @@ ,aMode=mode } = case mode of- Help -> [helpDialog, maincontent]+ Help -> [helpDialog copts, maincontent] -- Minibuffer e -> [minibuffer e, maincontent] _ -> [maincontent] where@@ -127,7 +152,7 @@ -- columns and whitespace. If they don't get all they need, -- allocate it to them proportionally to their maximum widths. whitespacewidth = 10 -- inter-column whitespace, fixed width- minnonamtcolswidth = datewidth + 2 + 2 -- date column plus at least 2 for desc and accts+ minnonamtcolswidth = datewidth + 1 + 2 + 2 -- date column plus at least 1 for status and 2 for desc and accts maxamtswidth = max 0 (totalwidth - minnonamtcolswidth - whitespacewidth) maxchangewidthseen = maximum' $ map (strWidth . rsItemChangeAmount) displayitems maxbalwidthseen = maximum' $ map (strWidth . rsItemBalanceAmount) displayitems@@ -140,7 +165,7 @@ -- maxdescacctswidth = totalwidth - (whitespacewidth - 4) - changewidth - balwidth maxdescacctswidth = -- trace (show (totalwidth, datewidth, changewidth, balwidth, whitespacewidth)) $- max 0 (totalwidth - datewidth - changewidth - balwidth - whitespacewidth)+ max 0 (totalwidth - datewidth - 1 - changewidth - balwidth - whitespacewidth) -- allocating proportionally. -- descwidth' = maximum' $ map (strWidth . second6) displayitems -- acctswidth' = maximum' $ map (strWidth . third6) displayitems@@ -178,7 +203,7 @@ where togglefilters = case concat [- uiShowClearedStatus $ clearedstatus_ ropts+ uiShowStatus copts $ statuses_ ropts ,if real_ ropts then ["real"] else [] ,if empty_ ropts then [] else ["nonzero"] ] of@@ -187,7 +212,8 @@ cur = str $ case rsList ^. listSelectedL of Nothing -> "-" Just i -> show (i + 1)- total = str $ show $ length displayitems+ total = str $ show $ length nonblanks+ nonblanks = V.takeWhile (not . null . rsItemDate) $ rsList^.listElementsL -- query = query_ $ reportopts_ $ cliopts_ opts @@ -220,7 +246,9 @@ Widget Greedy Fixed $ do render $ str (fitString (Just datewidth) (Just datewidth) True True rsItemDate) <+>- str " " <+>+ str " " <+>+ str (fitString (Just 1) (Just 1) True True (show rsItemStatus)) <+>+ str " " <+> str (fitString (Just descwidth) (Just descwidth) True True rsItemDescription) <+> str " " <+> str (fitString (Just acctswidth) (Just acctswidth) True True rsItemOtherAccounts) <+>@@ -244,7 +272,11 @@ ,aMode=mode } ev = do d <- liftIO getCurrentDay-+ let + journalspan = journalDateSpan False j+ nonblanks = V.takeWhile (not . null . rsItemDate) $ rsList^.listElementsL+ lastnonblankidx = max 0 (length nonblanks - 1)+ case mode of Minibuffer ed -> case ev of@@ -285,24 +317,31 @@ rsItemTransaction=Transaction{tsourcepos=GenericSourcePos f l c}}) -> (Just (l, Just c),f) Just (_, RegisterScreenItem{ rsItemTransaction=Transaction{tsourcepos=JournalSourcePos f (l,_)}}) -> (Just (l, Nothing),f)- VtyEvent (EvKey (KChar 'H') []) -> continue $ regenerateScreens j d $ toggleHistorical ui- VtyEvent (EvKey (KChar 'F') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleFlat ui)- VtyEvent (EvKey (KChar 'Z') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleEmpty ui)- VtyEvent (EvKey (KChar 'C') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleCleared ui)- VtyEvent (EvKey (KChar 'U') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleUncleared ui)- VtyEvent (EvKey (KChar 'R') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleReal ui)- VtyEvent (EvKey (KChar '/') []) -> (continue $ regenerateScreens j d $ showMinibuffer ui)++ -- display mode/query toggles+ VtyEvent (EvKey (KChar 'H') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleHistorical ui+ VtyEvent (EvKey (KChar 'F') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleFlat ui+ VtyEvent (EvKey (KChar 'Z') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleEmpty ui+ VtyEvent (EvKey (KChar 'R') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleReal ui+ 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 '/') []) -> continue $ regenerateScreens j d $ showMinibuffer 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 (KRight) [MShift]) -> continue $ regenerateScreens j d $ nextReportPeriod journalspan ui VtyEvent (EvKey (KLeft) [MShift]) -> continue $ regenerateScreens j d $ previousReportPeriod journalspan ui VtyEvent (EvKey k []) | k `elem` [KBS, KDel] -> (continue $ regenerateScreens j d $ resetFilter ui)- VtyEvent (EvKey k []) | k `elem` [KLeft, KChar 'h'] -> continue $ popScreen ui- VtyEvent (EvKey k []) | k `elem` [KRight, KChar 'l'] -> do+ VtyEvent e | e `elem` moveLeftEvents -> continue $ popScreen ui+ VtyEvent (EvKey (KChar 'l') [MCtrl]) -> scrollSelectionToMiddle rsList >> invalidateCache >> continue ui++ -- enter transaction screen for selected transaction+ VtyEvent e | e `elem` moveRightEvents -> do case listSelectedElement rsList of Just (_, RegisterScreenItem{rsItemTransaction=t}) -> let- ts = map rsItemTransaction $ V.toList $ listElements rsList+ ts = map rsItemTransaction $ V.toList $ nonblanks numberedts = zip [1..] ts i = fromIntegral $ maybe 0 (+1) $ elemIndex t ts -- XXX in@@ -310,21 +349,40 @@ ,tsTransactions=numberedts ,tsAccount=rsAccount} ui Nothing -> continue ui- -- fall through to the list's event handler (handles [pg]up/down)++ -- prevent moving down over blank padding items;+ -- instead scroll down by one, until maximally scrolled - shows the end has been reached+ VtyEvent e | e `elem` moveDownEvents, isBlankElement mnextelement -> do+ vScrollBy (viewportScroll $ rsList^.listNameL) 1 + continue ui+ where + mnextelement = listSelectedElement $ listMoveDown rsList++ -- if page down or end leads to a blank padding item, stop at last non-blank+ VtyEvent e@(EvKey k []) | k `elem` [KPageDown, KEnd] -> do+ list <- handleListEvent e rsList+ if isBlankElement $ listSelectedElement list+ then do+ let list' = listMoveTo lastnonblankidx list+ scrollSelectionToMiddle list'+ continue ui{aScreen=s{rsList=list'}}+ else+ continue ui{aScreen=s{rsList=list}}+ + -- fall through to the list's event handler (handles other [pg]up/down events) VtyEvent ev -> do- let ev' = case ev of- EvKey (KChar 'k') [] -> EvKey (KUp) []- EvKey (KChar 'j') [] -> EvKey (KDown) []- _ -> ev- newitems <- handleListEvent ev' rsList- continue ui{aScreen=s{rsList=newitems}}- -- continue =<< handleEventLensed ui someLens ev+ let ev' = normaliseMovementKeys ev+ newitems <- handleListEvent ev' rsList+ continue ui{aScreen=s{rsList=newitems}}+ AppEvent _ -> continue ui MouseDown _ _ _ _ -> continue ui MouseUp _ _ _ -> continue ui- where- -- Encourage a more stable scroll position when toggling list items (cf AccountsScreen.hs)- scrollTop = vScrollToBeginning $ viewportScroll RegisterViewport- journalspan = journalDateSpan False j rsHandle _ _ = error "event handler called with wrong screen type, should not happen"++isBlankElement mel = ((rsItemDate . snd) <$> mel) == Just "" ++rsCenterAndContinue ui = do+ scrollSelectionToMiddle $ rsList $ aScreen ui+ continue ui
Hledger/UI/TransactionScreen.hs view
@@ -53,7 +53,7 @@ ,tsAccount=acct} ,aMode=mode} = case mode of- Help -> [helpDialog, maincontent]+ Help -> [helpDialog copts, maincontent] -- Minibuffer e -> [minibuffer e, maincontent] _ -> [maincontent] where@@ -78,7 +78,7 @@ where togglefilters = case concat [- uiShowClearedStatus $ clearedstatus_ ropts+ uiShowStatus copts $ statuses_ ropts ,if real_ ropts then ["real"] else [] ,if empty_ ropts then [] else ["nonzero"] ] of@@ -168,9 +168,9 @@ -- EvKey (KChar 'E') [] -> continue $ regenerateScreens j d $ stToggleEmpty ui -- EvKey (KChar 'C') [] -> continue $ regenerateScreens j d $ stToggleCleared ui -- EvKey (KChar 'R') [] -> continue $ regenerateScreens j d $ stToggleReal ui- VtyEvent (EvKey k []) | k `elem` [KUp, KChar 'k'] -> continue $ regenerateScreens j d ui{aScreen=s{tsTransaction=(iprev,tprev)}}- VtyEvent (EvKey k []) | k `elem` [KDown, KChar 'j'] -> continue $ regenerateScreens j d ui{aScreen=s{tsTransaction=(inext,tnext)}}- VtyEvent (EvKey k []) | k `elem` [KLeft, KChar 'h'] -> continue ui''+ VtyEvent e | e `elem` moveUpEvents -> continue $ regenerateScreens j d ui{aScreen=s{tsTransaction=(iprev,tprev)}}+ VtyEvent e | e `elem` moveDownEvents -> continue $ regenerateScreens j d ui{aScreen=s{tsTransaction=(inext,tnext)}}+ VtyEvent e | e `elem` moveLeftEvents -> continue ui'' where ui'@UIState{aScreen=scr} = popScreen ui ui'' = ui'{aScreen=rsSelect (fromIntegral i) scr}
Hledger/UI/UIOptions.hs view
@@ -39,6 +39,15 @@ -- ,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"+ ,flagReq ["status-toggles"] (\s opts -> Right $ setopt "status-toggles" s opts) "N"+ (intercalate "\n"+ ["choose how status toggles work:"+ ," 1 UPC toggles X/all"+ ," 2 UPC cycles X/not-X/all"+ ," 3 UPC toggles each X"+-- ," 4 upc sets X, UPC sets not-X"+-- ," 5 upc toggles X, UPC toggles not-X"+ ]) ] --uimode :: Mode [([Char], [Char])]
Hledger/UI/UIState.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {- | UIState operations. -} {-# LANGUAGE OverloadedStrings #-}@@ -6,7 +7,9 @@ module Hledger.UI.UIState where +#if !MIN_VERSION_brick(0,19,0) import Brick+#endif import Brick.Widgets.Edit import Data.List import Data.Text.Zipper (gotoEOL)@@ -17,30 +20,87 @@ import Hledger.UI.UITypes import Hledger.UI.UIOptions --- | Toggle between showing only cleared items or all items.-toggleCleared :: UIState -> UIState-toggleCleared ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =- ui{aopts=uopts{cliopts_=copts{reportopts_=toggleCleared ropts}}}- where- toggleCleared ropts@ReportOpts{clearedstatus_=Just Cleared} = ropts{clearedstatus_=Nothing}- toggleCleared ropts = ropts{clearedstatus_=Just Cleared}+-- | Toggle between showing only unmarked items or all items.+toggleUnmarked :: UIState -> UIState+toggleUnmarked ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =+ ui{aopts=uopts{cliopts_=copts{reportopts_=reportOptsToggleStatusSomehow Unmarked copts ropts}}} -- | Toggle between showing only pending items or all items. togglePending :: UIState -> UIState togglePending ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =- ui{aopts=uopts{cliopts_=copts{reportopts_=togglePending ropts}}}- where- togglePending ropts@ReportOpts{clearedstatus_=Just Pending} = ropts{clearedstatus_=Nothing}- togglePending ropts = ropts{clearedstatus_=Just Pending}+ ui{aopts=uopts{cliopts_=copts{reportopts_=reportOptsToggleStatusSomehow Pending copts ropts}}} --- | Toggle between showing only uncleared items or all items.-toggleUncleared :: UIState -> UIState-toggleUncleared ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =- ui{aopts=uopts{cliopts_=copts{reportopts_=toggleUncleared ropts}}}+-- | Toggle between showing only cleared items or all items.+toggleCleared :: UIState -> UIState+toggleCleared ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =+ ui{aopts=uopts{cliopts_=copts{reportopts_=reportOptsToggleStatusSomehow Cleared copts ropts}}}++-- TODO testing different status toggle styles ++-- | Generate zero or more indicators of the status filters currently active, +-- which will be shown comma-separated as part of the indicators list.+uiShowStatus :: CliOpts -> [Status] -> [String]+uiShowStatus copts ss =+ case style of+ -- in style 2, instead of "Y, Z" show "not X" + Just 2 | length ss == numstatuses-1 + -> map (("not "++). showstatus) $ sort $ complement ss -- should be just one+ _ -> map showstatus $ sort ss where- toggleUncleared ropts@ReportOpts{clearedstatus_=Just Uncleared} = ropts{clearedstatus_=Nothing}- toggleUncleared ropts = ropts{clearedstatus_=Just Uncleared}+ numstatuses = length [minBound..maxBound::Status]+ style = maybeintopt "status-toggles" $ rawopts_ copts+ showstatus Cleared = "cleared"+ showstatus Pending = "pending"+ showstatus Unmarked = "unmarked" +reportOptsToggleStatusSomehow :: Status -> CliOpts -> ReportOpts -> ReportOpts+reportOptsToggleStatusSomehow s copts ropts =+ case maybeintopt "status-toggles" $ rawopts_ copts of + Just 2 -> reportOptsToggleStatus2 s ropts+ Just 3 -> reportOptsToggleStatus3 s ropts+-- Just 4 -> reportOptsToggleStatus4 s ropts+-- Just 5 -> reportOptsToggleStatus5 s ropts+ _ -> reportOptsToggleStatus1 s ropts++-- 1 UPC toggles only X/all+reportOptsToggleStatus1 s ropts@ReportOpts{statuses_=ss}+ | ss == [s] = ropts{statuses_=[]}+ | otherwise = ropts{statuses_=[s]}++-- 2 UPC cycles X/not-X/all+-- repeatedly pressing X cycles:+-- [] U [u]+-- [u] U [pc]+-- [pc] U []+-- 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 ++-- 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)}++-- 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}+-- | otherwise = ropts{statuses_=simplifyStatuses (s:ss)}++-- | Given a list of unique enum values, list the other possible values of that enum.+complement :: (Bounded a, Enum a, Eq a) => [a] -> [a]+complement = ([minBound..maxBound] \\)++--+ -- | Toggle between showing all and showing only nonempty (more precisely, nonzero) items. toggleEmpty :: UIState -> UIState toggleEmpty ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =@@ -125,7 +185,7 @@ ui{aopts=uopts{cliopts_=copts{reportopts_=ropts{ accountlistmode_=ALTree ,empty_=True- ,clearedstatus_=Nothing+ ,statuses_=[] ,real_=False ,query_="" --,period_=PeriodAll@@ -178,7 +238,11 @@ showMinibuffer :: UIState -> UIState showMinibuffer ui = setMode (Minibuffer e) ui where+#if MIN_VERSION_brick(0,19,0)+ e = applyEdit gotoEOL $ editor MinibufferEditor (Just 1) oldq+#else e = applyEdit gotoEOL $ editor MinibufferEditor (str . unlines) (Just 1) oldq+#endif oldq = query_ $ reportopts_ $ cliopts_ $ aopts ui -- | Close the minibuffer, discarding any edit in progress.
Hledger/UI/UITypes.hs view
@@ -142,6 +142,7 @@ -- | An item in the register screen's list of transactions in the current account. data RegisterScreenItem = RegisterScreenItem { rsItemDate :: String -- ^ date+ ,rsItemStatus :: Status -- ^ transaction status ,rsItemDescription :: String -- ^ description ,rsItemOtherAccounts :: String -- ^ other accounts ,rsItemChangeAmount :: String -- ^ the change to the current account from this transaction
Hledger/UI/UIUtils.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {- | Rendering & misc. helpers. -} {-# LANGUAGE OverloadedStrings #-}@@ -11,13 +12,16 @@ -- import Brick.Widgets.Center import Brick.Widgets.Dialog import Brick.Widgets.Edit+import Brick.Widgets.List import Data.List+import Data.Maybe import Data.Monoid-import Graphics.Vty (Event(..),Key(..),Color,Attr,currentAttr)+import Graphics.Vty (Event(..),Key(..),Modifier(..),Color,Attr,currentAttr) import Lens.Micro.Platform import System.Process -import Hledger+import Hledger hiding (Color)+import Hledger.Cli (CliOpts(rawopts_)) import Hledger.UI.UITypes import Hledger.UI.UIState @@ -28,16 +32,9 @@ -- ui -uiShowClearedStatus mc =- case mc of- Just Cleared -> ["cleared"]- Just Pending -> ["pending"]- Just Uncleared -> ["uncleared"]- Nothing -> []- -- | Draw the help dialog, called when help mode is active.-helpDialog :: Widget Name-helpDialog =+helpDialog :: CliOpts -> Widget Name+helpDialog copts = Widget Fixed Fixed $ do c <- getContext render $@@ -48,10 +45,11 @@ padLeftRight 1 $ vBox [ str "NAVIGATION"- ,renderKey ("UP/DOWN/k/j/PGUP/PGDN/HOME/END", "")+ ,renderKey ("UP/DOWN/PGUP/PGDN/HOME/END", "") ,str " move selection"- ,renderKey ("RIGHT/l", "more detail")- ,renderKey ("LEFT/h", "previous screen")+ ,renderKey ("RIGHT", "more detail")+ ,renderKey ("LEFT", "previous screen")+ ,str " (or vi/emacs movement keys)" ,renderKey ("ESC", "cancel / reset to top") ,str " " ,str "MISC"@@ -59,8 +57,9 @@ ,renderKey ("a", "add transaction (hledger add)") ,renderKey ("A", "add transaction (hledger-iadd)") ,renderKey ("E", "open editor")- ,renderKey ("g", "reload data") ,renderKey ("I", "toggle balance assertions")+ ,renderKey ("g", "reload data")+ ,renderKey ("CTRL-l", "redraw & recenter") ,renderKey ("q", "quit") ,str " " ,str "MANUAL"@@ -77,8 +76,21 @@ ,renderKey ("t", "set report period to today") ,str " " ,renderKey ("/", "set a filter query")- ,renderKey ("C", "toggle cleared/all")- ,renderKey ("U", "toggle uncleared/all")+ ,renderKey ("U", + ["toggle unmarked/all"+ ,"cycle unmarked/not unmarked/all"+ ,"toggle unmarked filter"+ ] !! (statusstyle-1))+ ,renderKey ("P",+ ["toggle pending/all"+ ,"cycle pending/not pending/all"+ ,"toggle pending filter"+ ] !! (statusstyle-1))+ ,renderKey ("C",+ ["toggle cleared/all"+ ,"cycle cleared/not cleared/all"+ ,"toggle cleared filter"+ ] !! (statusstyle-1)) ,renderKey ("R", "toggle real/all") ,renderKey ("Z", "toggle nonzero/all") ,renderKey ("DEL/BS", "remove filters")@@ -109,12 +121,13 @@ ] where renderKey (key,desc) = withAttr (borderAttr <> "keys") (str key) <+> str " " <+> str desc+ statusstyle = min 3 $ fromMaybe 1 $ maybeintopt "status-toggles" $ rawopts_ copts -- | Event handler used when help mode is active. helpHandle :: UIState -> BrickEvent Name AppEvent -> EventM Name (Next UIState) helpHandle ui ev = case ev of- VtyEvent (EvKey k []) | k `elem` [KEsc, KLeft, KChar 'h', KChar '?'] -> continue $ setMode Normal ui+ VtyEvent e | e `elem` (moveLeftEvents ++ [EvKey KEsc [], EvKey (KChar '?') []]) -> continue $ setMode Normal ui VtyEvent (EvKey (KChar 't') []) -> suspendAndResume $ runHelp >> return ui' VtyEvent (EvKey (KChar 'm') []) -> suspendAndResume $ runMan >> return ui' VtyEvent (EvKey (KChar 'i') []) -> suspendAndResume $ runInfo >> return ui'@@ -127,7 +140,11 @@ minibuffer ed = forceAttr (borderAttr <> "minibuffer") $ hBox $+#if MIN_VERSION_brick(0,19,0)+ [txt "filter: ", renderEditor (str . unlines) True ed]+#else [txt "filter: ", renderEditor True ed]+#endif -- | Wrap a widget in the default hledger-ui screen layout. defaultLayout :: Widget Name -> Widget Name -> Widget Name -> Widget Name@@ -246,3 +263,44 @@ withBorderAttr :: Attr -> Widget Name -> Widget Name withBorderAttr attr = updateAttrMap (applyAttrMappings [(borderAttr, attr)]) +-- | Like brick's continue, but first run some action to modify brick's state.+-- This action does not affect the app state, but might eg adjust a widget's scroll position.+continueWith :: EventM n () -> ui -> EventM n (Next ui)+continueWith brickaction ui = brickaction >> continue ui++-- | Scroll a list's viewport so that the selected item is centered in the+-- middle of the display area.+scrollToTop :: List Name e -> EventM Name ()+scrollToTop list = do+ let vpname = list^.listNameL+ setTop (viewportScroll vpname) 0 ++-- | Scroll a list's viewport so that the selected item is centered in the+-- middle of the display area.+scrollSelectionToMiddle :: List Name e -> EventM Name ()+scrollSelectionToMiddle list = do+ let mselectedrow = list^.listSelectedL + vpname = list^.listNameL+ mvp <- lookupViewport vpname+ case (mselectedrow, mvp) of+ (Just selectedrow, Just vp) -> do+ let+ itemheight = dbg4 "itemheight" $ list^.listItemHeightL+ vpheight = dbg4 "vpheight" $ vp^.vpSize._2+ itemsperpage = dbg4 "itemsperpage" $ vpheight `div` itemheight+ toprow = dbg4 "toprow" $ max 0 (selectedrow - (itemsperpage `div` 2)) -- assuming ViewportScroll's row offset is measured in list items not screen rows+ setTop (viewportScroll vpname) toprow + _ -> return ()++-- arrow keys vi keys emacs keys+moveUpEvents = [EvKey KUp [] , EvKey (KChar 'k') [], EvKey (KChar 'p') [MCtrl]]+moveDownEvents = [EvKey KDown [] , EvKey (KChar 'j') [], EvKey (KChar 'n') [MCtrl]]+moveLeftEvents = [EvKey KLeft [] , EvKey (KChar 'h') [], EvKey (KChar 'b') [MCtrl]]+moveRightEvents = [EvKey KRight [], EvKey (KChar 'l') [], EvKey (KChar 'f') [MCtrl]]++normaliseMovementKeys ev+ | ev `elem` moveUpEvents = EvKey KUp []+ | ev `elem` moveDownEvents = EvKey KDown []+ | ev `elem` moveLeftEvents = EvKey KLeft []+ | ev `elem` moveRightEvents = EvKey KRight []+ | otherwise = ev
doc/hledger-ui.1 view
@@ -1,5 +1,5 @@ -.TH "hledger\-ui" "1" "March 2017" "hledger\-ui 1.2" "hledger User Manuals"+.TH "hledger\-ui" "1" "June 2017" "hledger\-ui 1.3" "hledger User Manuals" @@ -146,18 +146,18 @@ .RS .RE .TP-.B \f[C]\-C\ \-\-cleared\f[]-include only cleared postings/txns+.B \f[C]\-U\ \-\-unmarked\f[]+include only unmarked postings/txns (can combine with \-P or \-C) .RS .RE .TP-.B \f[C]\-\-pending\f[]+.B \f[C]\-P\ \-\-pending\f[] include only pending postings/txns .RS .RE .TP-.B \f[C]\-U\ \-\-uncleared\f[]-include only uncleared (and pending) postings/txns+.B \f[C]\-C\ \-\-cleared\f[]+include only cleared postings/txns .RS .RE .TP@@ -232,8 +232,9 @@ deeper, \f[C]left\f[] returns to the previous screen, \f[C]up\f[]/\f[C]down\f[]/\f[C]page\ up\f[]/\f[C]page\ down\f[]/\f[C]home\f[]/\f[C]end\f[] move up and down through lists.-Vi\-style \f[C]h\f[]/\f[C]j\f[]/\f[C]k\f[]/\f[C]l\f[] movement keys are-also supported.+Vi\-style (\f[C]h\f[]/\f[C]j\f[]/\f[C]k\f[]/\f[C]l\f[]) and Emacs\-style+(\f[C]CTRL\-p\f[]/\f[C]CTRL\-n\f[]/\f[C]CTRL\-f\f[]/\f[C]CTRL\-b\f[])+movement keys are also supported. A tip: movement speed is limited by your keyboard repeat rate, to move faster you may want to adjust it. (If you\[aq]re on a mac, the Karabiner app is one way to do that.)@@ -255,13 +256,17 @@ While editing the query, you can use CTRL\-a/e/d/k, BS, cursor keys; press \f[C]ENTER\f[] to set it, or \f[C]ESCAPE\f[]to cancel. There are also keys for quickly adjusting some common filters like-account depth and cleared/uncleared (see below).+account depth and transaction status (see below). \f[C]BACKSPACE\f[] or \f[C]DELETE\f[] removes all filters, showing all transactions. .PP \f[C]ESCAPE\f[] removes all filters and jumps back to the top screen. Or, it cancels a minibuffer edit or help dialog in progress. .PP+\f[C]CTRL\-l\f[] redraws the screen and centers the selection if+possible (selections near the top won\[aq]t be centered, since we+don\[aq]t scroll above the top).+.PP \f[C]g\f[] reloads from the data file(s) and updates the current screen and any previous screens. (With large files, this could cause a noticeable pause.)@@ -322,10 +327,13 @@ they show the change in balance during the report period. They are more useful eg when viewing a time log. .PP-\f[C]C\f[] toggles cleared mode, in which uncleared transactions and-postings are not shown.-\f[C]U\f[] toggles uncleared mode, in which only uncleared-transactions/postings are shown.+\f[C]U\f[] toggles filtering by unmarked status, including or excluding+unmarked postings in the balances.+Similarly, \f[C]P\f[] toggles pending postings, and \f[C]C\f[] toggles+cleared postings.+(By default, balances include all postings; if you activate one or two+status filters, only those postings are included; and if you activate+all three, the filter is removed.) .PP \f[C]R\f[] toggles real mode, in which virtual postings are ignored. .PP@@ -367,10 +375,13 @@ for the period balance shown on the accounts screen. As on the accounts screen, this can be toggled with \f[C]F\f[]. .PP-\f[C]C\f[] toggles cleared mode, in which uncleared transactions and-postings are not shown.-\f[C]U\f[] toggles uncleared mode, in which only uncleared-transactions/postings are shown.+\f[C]U\f[] toggles filtering by unmarked status, showing or hiding+unmarked transactions.+Similarly, \f[C]P\f[] toggles pending transactions, and \f[C]C\f[]+toggles cleared transactions.+(By default, transactions with all statuses are shown; if you activate+one or two status filters, only those transactions are shown; and if you+activate all three, the filter is removed.)q .PP \f[C]R\f[] toggles real mode, in which virtual postings are ignored. .PP
doc/hledger-ui.1.info view
@@ -3,7 +3,7 @@ File: hledger-ui.1.info, Node: Top, Next: OPTIONS, Up: (dir) -hledger-ui(1) hledger-ui 1.2+hledger-ui(1) hledger-ui 1.3 **************************** hledger-ui is hledger's curses-style interface, providing an efficient@@ -104,15 +104,15 @@ '--date2' show, and match with -b/-e/-p/date:, secondary dates instead-'-C --cleared'+'-U --unmarked' - include only cleared postings/txns-'--pending'+ include only unmarked postings/txns (can combine with -P or -C)+'-P --pending' include only pending postings/txns-'-U --uncleared'+'-C --cleared' - include only uncleared (and pending) postings/txns+ include only cleared postings/txns '-R --real' include only non-virtual postings@@ -167,10 +167,10 @@ The cursor keys navigate: 'right' (or 'enter') goes deeper, 'left' returns to the previous screen, 'up'/'down'/'page up'/'page down'/'home'/'end' move up and down through lists. Vi-style-'h'/'j'/'k'/'l' movement keys are also supported. A tip: movement speed-is limited by your keyboard repeat rate, to move faster you may want to-adjust it. (If you're on a mac, the Karabiner app is one way to do-that.)+('h'/'j'/'k'/'l') and Emacs-style ('CTRL-p'/'CTRL-n'/'CTRL-f'/'CTRL-b')+movement keys are also supported. A tip: movement speed is limited by+your keyboard repeat rate, to move faster you may want to adjust it.+(If you're on a mac, the Karabiner app is one way to do that.) With shift pressed, the cursor keys adjust the report period, limiting the transactions to be shown (by default, all are shown).@@ -186,13 +186,17 @@ using the same query terms as in hledger and hledger-web. While editing the query, you can use CTRL-a/e/d/k, BS, cursor keys; press 'ENTER' to set it, or 'ESCAPE'to cancel. There are also keys for quickly adjusting-some common filters like account depth and cleared/uncleared (see+some common filters like account depth and transaction status (see below). 'BACKSPACE' or 'DELETE' removes all filters, showing all transactions. 'ESCAPE' removes all filters and jumps back to the top screen. Or, it cancels a minibuffer edit or help dialog in progress. + 'CTRL-l' redraws the screen and centers the selection if possible+(selections near the top won't be centered, since we don't scroll above+the top).+ 'g' reloads from the data file(s) and updates the current screen and any previous screens. (With large files, this could cause a noticeable pause.)@@ -260,9 +264,12 @@ before the report start date, so they show the change in balance during the report period. They are more useful eg when viewing a time log. - 'C' toggles cleared mode, in which uncleared transactions and-postings are not shown. 'U' toggles uncleared mode, in which only-uncleared transactions/postings are shown.+ 'U' toggles filtering by unmarked status, including or excluding+unmarked postings in the balances. Similarly, 'P' toggles pending+postings, and 'C' toggles cleared postings. (By default, balances+include all postings; if you activate one or two status filters, only+those postings are included; and if you activate all three, the filter+is removed.) 'R' toggles real mode, in which virtual postings are ignored. @@ -304,9 +311,12 @@ responsible for the period balance shown on the accounts screen. As on the accounts screen, this can be toggled with 'F'. - 'C' toggles cleared mode, in which uncleared transactions and-postings are not shown. 'U' toggles uncleared mode, in which only-uncleared transactions/postings are shown.+ 'U' toggles filtering by unmarked status, showing or hiding unmarked+transactions. Similarly, 'P' toggles pending transactions, and 'C'+toggles cleared transactions. (By default, transactions with all+statuses are shown; if you activate one or two status filters, only+those transactions are shown; and if you activate all three, the filter+is removed.)q 'R' toggles real mode, in which virtual postings are ignored. @@ -357,17 +367,17 @@ Node: Top73 Node: OPTIONS825 Ref: #options924-Node: KEYS3650-Ref: #keys3747-Node: SCREENS6335-Ref: #screens6422-Node: Accounts screen6512-Ref: #accounts-screen6642-Node: Register screen8691-Ref: #register-screen8848-Node: Transaction screen10737-Ref: #transaction-screen10897-Node: Error screen11767-Ref: #error-screen11891+Node: KEYS3665+Ref: #keys3762+Node: SCREENS6558+Ref: #screens6645+Node: Accounts screen6735+Ref: #accounts-screen6865+Node: Register screen9095+Ref: #register-screen9252+Node: Transaction screen11326+Ref: #transaction-screen11486+Node: Error screen12356+Ref: #error-screen12480 End Tag Table
doc/hledger-ui.1.txt view
@@ -101,14 +101,14 @@ --date2 show, and match with -b/-e/-p/date:, secondary dates instead - -C --cleared- include only cleared postings/txns+ -U --unmarked+ include only unmarked postings/txns (can combine with -P or -C) - --pending+ -P --pending include only pending postings/txns - -U --uncleared- include only uncleared (and pending) postings/txns+ -C --cleared+ include only cleared postings/txns -R --real include only non-virtual postings@@ -151,45 +151,50 @@ The cursor keys navigate: right (or enter) goes deeper, left returns to the previous screen, up/down/page up/page down/home/end move up and- down through lists. Vi-style h/j/k/l movement keys are also supported.- A tip: movement speed is limited by your keyboard repeat rate, to move- faster you may want to adjust it. (If you're on a mac, the Karabiner- app is one way to do that.)+ down through lists. Vi-style (h/j/k/l) and Emacs-style+ (CTRL-p/CTRL-n/CTRL-f/CTRL-b) movement keys are also supported. A tip:+ movement speed is limited by your keyboard repeat rate, to move faster+ you may want to adjust it. (If you're on a mac, the Karabiner app is+ one way to do that.) - With shift pressed, the cursor keys adjust the report period, limiting- the transactions to be shown (by default, all are shown).- shift-down/up steps downward and upward through these standard report+ With shift pressed, the cursor keys adjust the report period, limiting+ the transactions to be shown (by default, all are shown).+ shift-down/up steps downward and upward through these standard report period durations: year, quarter, month, week, day. Then,- shift-left/right moves to the previous/next period. t sets the report- period to today. With the --watch option, when viewing a "current"- period (the current day, week, month, quarter, or year), the period- will move automatically to track the current date. To set a non-stan-+ shift-left/right moves to the previous/next period. t sets the report+ period to today. With the --watch option, when viewing a "current"+ period (the current day, week, month, quarter, or year), the period+ will move automatically to track the current date. To set a non-stan- dard period, you can use / and a date: query. - / lets you set a general filter query limiting the data shown, using- the same query terms as in hledger and hledger-web. While editing the- query, you can use CTRL-a/e/d/k, BS, cursor keys; press ENTER to set+ / lets you set a general filter query limiting the data shown, using+ the same query terms as in hledger and hledger-web. While editing the+ query, you can use CTRL-a/e/d/k, BS, cursor keys; press ENTER to set it, or ESCAPEto cancel. There are also keys for quickly adjusting some- common filters like account depth and cleared/uncleared (see below).+ common filters like account depth and transaction status (see below). BACKSPACE or DELETE removes all filters, showing all transactions. - ESCAPE removes all filters and jumps back to the top screen. Or, it+ ESCAPE removes all filters and jumps back to the top screen. Or, it cancels a minibuffer edit or help dialog in progress. - g reloads from the data file(s) and updates the current screen and any- previous screens. (With large files, this could cause a noticeable+ CTRL-l redraws the screen and centers the selection if possible (selec-+ tions near the top won't be centered, since we don't scroll above the+ top).++ g reloads from the data file(s) and updates the current screen and any+ previous screens. (With large files, this could cause a noticeable pause.) - I toggles balance assertion checking. Disabling balance assertions+ I toggles balance assertion checking. Disabling balance assertions temporarily can be useful for troubleshooting. - a runs command-line hledger's add command, and reloads the updated+ a runs command-line hledger's add command, and reloads the updated file. This allows some basic data entry. - E runs $HLEDGER_UI_EDITOR, or $EDITOR, or a default (emac-+ E runs $HLEDGER_UI_EDITOR, or $EDITOR, or a default (emac- sclient -a "" -nw) on the journal file. With some editors (emacs, vi),- the cursor will be positioned at the current transaction when invoked- from the register and transaction screens, and at the error location+ the cursor will be positioned at the current transaction when invoked+ from the register and transaction screens, and at the error location (if possible) when invoked from the error screen. q quits the application.@@ -198,42 +203,44 @@ SCREENS Accounts screen- This is normally the first screen displayed. It lists accounts and- their balances, like hledger's balance command. By default, it shows- all accounts and their latest ending balances (including the balances- of subaccounts). if you specify a query on the command line, it shows+ This is normally the first screen displayed. It lists accounts and+ their balances, like hledger's balance command. By default, it shows+ all accounts and their latest ending balances (including the balances+ of subaccounts). if you specify a query on the command line, it shows just the matched accounts and the balances from matched transactions. - Account names are normally indented to show the hierarchy (tree mode).+ Account names are normally indented to show the hierarchy (tree mode). To see less detail, set a depth limit by pressing a number key, 1 to 9. 0 shows even less detail, collapsing all accounts to a single total. -- and + (or =) decrease and increase the depth limit. To remove the- depth limit, set it higher than the maximum account depth, or press+ and + (or =) decrease and increase the depth limit. To remove the+ depth limit, set it higher than the maximum account depth, or press ESCAPE. - F toggles flat mode, in which accounts are shown as a flat list, with- their full names. In this mode, account balances exclude subaccounts,- except for accounts at the depth limit (as with hledger's balance com-+ F toggles flat mode, in which accounts are shown as a flat list, with+ their full names. In this mode, account balances exclude subaccounts,+ except for accounts at the depth limit (as with hledger's balance com- mand). H toggles between showing historical balances or period balances. His-- torical balances (the default) are ending balances at the end of the- report period, taking into account all transactions before that date- (filtered by the filter query if any), including transactions before- the start of the report period. In other words, historical balances- are what you would see on a bank statement for that account (unless- disturbed by a filter query). Period balances ignore transactions+ torical balances (the default) are ending balances at the end of the+ report period, taking into account all transactions before that date+ (filtered by the filter query if any), including transactions before+ the start of the report period. In other words, historical balances+ are what you would see on a bank statement for that account (unless+ disturbed by a filter query). Period balances ignore transactions before the report start date, so they show the change in balance during the report period. They are more useful eg when viewing a time log. - C toggles cleared mode, in which uncleared transactions and postings- are not shown. U toggles uncleared mode, in which only uncleared- transactions/postings are shown.+ U toggles filtering by unmarked status, including or excluding unmarked+ postings in the balances. Similarly, P toggles pending postings, and C+ toggles cleared postings. (By default, balances include all postings;+ if you activate one or two status filters, only those postings are+ included; and if you activate all three, the filter is removed.) R toggles real mode, in which virtual postings are ignored. - Z toggles nonzero mode, in which only accounts with nonzero balances- are shown (hledger-ui shows zero items by default, unlike command-line+ Z toggles nonzero mode, in which only accounts with nonzero balances+ are shown (hledger-ui shows zero items by default, unlike command-line hledger). Press right or enter to view an account's transactions register.@@ -242,32 +249,35 @@ This screen shows the transactions affecting a particular account, like a check register. Each line represents one transaction and shows: - o the other account(s) involved, in abbreviated form. (If there are- both real and virtual postings, it shows only the accounts affected+ o the other account(s) involved, in abbreviated form. (If there are+ both real and virtual postings, it shows only the accounts affected by real postings.) - o the overall change to the current account's balance; positive for an+ o the overall change to the current account's balance; positive for an inflow to this account, negative for an outflow. o the running historical total or period total for the current account,- after the transaction. This can be toggled with H. Similar to the- accounts screen, the historical total is affected by transactions- (filtered by the filter query) before the report start date, while+ after the transaction. This can be toggled with H. Similar to the+ accounts screen, the historical total is affected by transactions+ (filtered by the filter query) before the report start date, while the period total is not. If the historical total is not disturbed by- a filter query, it will be the running historical balance you would+ a filter query, it will be the running historical balance you would see on a bank register for the current account. - If the accounts screen was in tree mode, the register screen will+ If the accounts screen was in tree mode, the register screen will include transactions from both the current account and its subaccounts.- If the accounts screen was in flat mode, and a non-depth-clipped- account was selected, the register screen will exclude transactions+ If the accounts screen was in flat mode, and a non-depth-clipped+ account was selected, the register screen will exclude transactions from subaccounts. In other words, the register always shows the trans-- actions responsible for the period balance shown on the accounts+ actions responsible for the period balance shown on the accounts screen. As on the accounts screen, this can be toggled with F. - C toggles cleared mode, in which uncleared transactions and postings- are not shown. U toggles uncleared mode, in which only uncleared- transactions/postings are shown.+ U toggles filtering by unmarked status, showing or hiding unmarked+ transactions. Similarly, P toggles pending transactions, and C toggles+ cleared transactions. (By default, transactions with all statuses are+ shown; if you activate one or two status filters, only those transac-+ tions are shown; and if you activate all three, the filter is+ removed.)q R toggles real mode, in which virtual postings are ignored. @@ -359,4 +369,4 @@ -hledger-ui 1.2 March 2017 hledger-ui(1)+hledger-ui 1.3 June 2017 hledger-ui(1)
hledger-ui.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack name: hledger-ui-version: 1.2+version: 1.3 synopsis: Curses-style user interface for the hledger accounting tool description: This is hledger's curses-style interface. It is simpler and more convenient for browsing data than the command-line interface,@@ -55,10 +55,10 @@ 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.2"+ cpp-options: -DVERSION="1.3" build-depends:- hledger >= 1.2 && < 1.3- , hledger-lib >= 1.2 && < 1.3+ hledger >= 1.3+ , hledger-lib >= 1.3 , ansi-terminal >= 0.6.2.3 && < 0.7 , async , base >= 4.8 && < 5@@ -72,7 +72,7 @@ , HUnit , microlens >= 0.4 && < 0.5 , microlens-platform >= 0.2.3.1 && < 0.4- , megaparsec >=5.0 && < 5.3+ , megaparsec >=5.0 && < 5.4 , pretty-show >=1.6.4 , process >= 1.2 , safe >= 0.2@@ -85,7 +85,7 @@ buildable: False else build-depends:- brick >= 0.12 && < 0.18+ brick >= 0.12 && < 0.20 , vty >= 5.5 && < 5.16 if flag(threaded) ghc-options: -threaded