diff --git a/hledger-ui/Hledger/UI/AccountsScreen.hs b/hledger-ui/Hledger/UI/AccountsScreen.hs index aa0ca7a8e..86214eb87 100644 --- a/hledger-ui/Hledger/UI/AccountsScreen.hs +++ b/hledger-ui/Hledger/UI/AccountsScreen.hs @@ -180,8 +180,8 @@ asDraw UIState{aopts=_uopts@UIOpts{uoCliOpts=copts@CliOpts{reportspec_=rspec}} nonblanks = V.takeWhile (not . T.null . asItemAccountName) $ s ^. asList . listElementsL bottomlabel = case mode of - Minibuffer ed -> minibuffer ed - _ -> quickhelp + Minibuffer label ed -> minibuffer label ed + _ -> quickhelp where quickhelp = borderKeysStr' [ ("?", str "help") @@ -242,15 +242,18 @@ asHandle ui0@UIState{ ui = ui0{aScreen=scr & asSelectedAccount .~ selacct} case mode of - Minibuffer ed -> + Minibuffer _ ed -> case ev of VtyEvent (EvKey KEsc []) -> continue $ closeMinibuffer ui - VtyEvent (EvKey KEnter []) -> continue $ regenerateScreens j d $ setFilter s $ closeMinibuffer ui - where s = chomp $ unlines $ map strip $ getEditContents ed + VtyEvent (EvKey KEnter []) -> continue $ regenerateScreens j d $ + case setFilter s $ closeMinibuffer ui of + Left bad -> showMinibuffer "Cannot compile regular expression" (Just bad) ui + Right ui' -> ui' + where s = chomp $ unlines $ map strip $ getEditContents ed VtyEvent (EvKey (KChar 'l') [MCtrl]) -> redraw ui VtyEvent (EvKey (KChar 'z') [MCtrl]) -> suspend ui VtyEvent ev -> do ed' <- handleEditorEvent ev ed - continue $ ui{aMode=Minibuffer ed'} + continue $ ui{aMode=Minibuffer "filter" ed'} AppEvent _ -> continue ui MouseDown{} -> continue ui MouseUp{} -> continue ui @@ -311,7 +314,7 @@ asHandle ui0@UIState{ 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 (KChar '/') []) -> continue $ regenerateScreens j d $ showMinibuffer "filter" Nothing ui VtyEvent (EvKey k []) | k `elem` [KBS, KDel] -> (continue $ regenerateScreens j d $ resetFilter ui) VtyEvent e | e `elem` moveLeftEvents -> continue $ popScreen ui VtyEvent (EvKey (KChar 'l') [MCtrl]) -> scrollSelectionToMiddle _asList >> redraw ui diff --git a/hledger-ui/Hledger/UI/RegisterScreen.hs b/hledger-ui/Hledger/UI/RegisterScreen.hs index cf6ac5925..ee2fa83ff 100644 --- a/hledger-ui/Hledger/UI/RegisterScreen.hs +++ b/hledger-ui/Hledger/UI/RegisterScreen.hs @@ -227,8 +227,8 @@ rsDraw UIState{aopts=_uopts@UIOpts{uoCliOpts=copts@CliOpts{reportspec_=rspec}} -- query = query_ $ reportopts_ $ cliopts_ opts bottomlabel = case mode of - Minibuffer ed -> minibuffer ed - _ -> quickhelp + Minibuffer label ed -> minibuffer label ed + _ -> quickhelp where quickhelp = borderKeysStr' [ ("?", str "help") @@ -288,15 +288,19 @@ rsHandle ui@UIState{ lastnonblankidx = max 0 (length nonblanks - 1) case mode of - Minibuffer ed -> + Minibuffer _ ed -> case ev of VtyEvent (EvKey KEsc []) -> continue $ closeMinibuffer ui - VtyEvent (EvKey KEnter []) -> continue $ regenerateScreens j d $ setFilter s $ closeMinibuffer ui - where s = chomp $ unlines $ map strip $ getEditContents ed + VtyEvent (EvKey KEnter []) -> continue $ regenerateScreens j d $ + case setFilter s $ closeMinibuffer ui of + Left bad -> showMinibuffer "Cannot compile regular expression" (Just bad) ui + Right ui' -> ui' + where s = chomp . unlines . map strip $ getEditContents ed + -- VtyEvent (EvKey (KChar '/') []) -> continue $ regenerateScreens j d $ showMinibuffer ui VtyEvent (EvKey (KChar 'l') [MCtrl]) -> redraw ui VtyEvent (EvKey (KChar 'z') [MCtrl]) -> suspend ui VtyEvent ev -> do ed' <- handleEditorEvent ev ed - continue $ ui{aMode=Minibuffer ed'} + continue $ ui{aMode=Minibuffer "filter" ed'} AppEvent _ -> continue ui MouseDown{} -> continue ui MouseUp{} -> continue ui @@ -342,7 +346,7 @@ rsHandle ui@UIState{ VtyEvent (EvKey (KChar 'C') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleCleared ui VtyEvent (EvKey (KChar 'F') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleForecast d ui - VtyEvent (EvKey (KChar '/') []) -> continue $ regenerateScreens j d $ showMinibuffer ui + VtyEvent (EvKey (KChar '/') []) -> continue $ regenerateScreens j d $ showMinibuffer "filter" Nothing 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 diff --git a/hledger-ui/Hledger/UI/UIState.hs b/hledger-ui/Hledger/UI/UIState.hs index 9f2a32b22..b8a082b70 100644 --- a/hledger-ui/Hledger/UI/UIState.hs +++ b/hledger-ui/Hledger/UI/UIState.hs @@ -7,9 +7,11 @@ module Hledger.UI.UIState where import Brick.Widgets.Edit +import Data.Bifunctor (first) import Data.Foldable (asum) import Data.Either (fromRight) import Data.List ((\\), foldl', sort) +import Data.Maybe (fromMaybe) import Data.Semigroup (Max(..)) import qualified Data.Text as T import Data.Text.Zipper (gotoEOL) @@ -205,11 +207,9 @@ updateReportPeriod :: (Period -> Period) -> UIState -> UIState updateReportPeriod updatePeriod = fromRight err . overEither period updatePeriod -- PARTIAL: where err = error "updateReportPeriod: updating period should not result in an error" --- | Apply a new filter query. -setFilter :: String -> UIState -> UIState -setFilter s = over reportSpec update - where - update rspec = fromRight rspec $ setEither querystring (words'' prefixes $ T.pack s) rspec -- XXX silently ignores an error +-- | Apply a new filter query, or return the failing query. +setFilter :: String -> UIState -> Either String UIState +setFilter s = first (const s) . setEither querystring (words'' prefixes $ T.pack s) -- | Reset some filters & toggles. resetFilter :: UIState -> UIState @@ -264,11 +264,11 @@ updateReportDepth updateDepth ui = over reportSpec update ui | otherwise = Just d -- | Open the minibuffer, setting its content to the current query with the cursor at the end. -showMinibuffer :: UIState -> UIState -showMinibuffer ui = setMode (Minibuffer e) ui +showMinibuffer :: T.Text -> Maybe String -> UIState -> UIState +showMinibuffer label moldq ui = setMode (Minibuffer label e) ui where e = applyEdit gotoEOL $ editor MinibufferEditor (Just 1) oldq - oldq = T.unpack . T.unwords . map textQuoteIfNeeded $ ui^.querystring + oldq = fromMaybe (T.unpack . T.unwords . map textQuoteIfNeeded $ ui^.querystring) moldq -- | Close the minibuffer, discarding any edit in progress. closeMinibuffer :: UIState -> UIState diff --git a/hledger-ui/Hledger/UI/UITypes.hs b/hledger-ui/Hledger/UI/UITypes.hs index bd790453a..5c0135e71 100644 --- a/hledger-ui/Hledger/UI/UITypes.hs +++ b/hledger-ui/Hledger/UI/UITypes.hs @@ -69,7 +69,7 @@ data UIState = UIState { data Mode = Normal | Help - | Minibuffer (Editor String Name) + | Minibuffer Text (Editor String Name) deriving (Show,Eq) -- Ignore the editor when comparing Modes. diff --git a/hledger-ui/Hledger/UI/UIUtils.hs b/hledger-ui/Hledger/UI/UIUtils.hs index 1844660af..e927f1a08 100644 --- a/hledger-ui/Hledger/UI/UIUtils.hs +++ b/hledger-ui/Hledger/UI/UIUtils.hs @@ -176,11 +176,11 @@ helpHandle ui ev = do ui' = setMode Normal ui closeHelpEvents = moveLeftEvents ++ [EvKey KEsc [], EvKey (KChar '?') [], EvKey (KChar 'q') []] --- | Draw the minibuffer. -minibuffer :: Editor String Name -> Widget Name -minibuffer ed = +-- | Draw the minibuffer with the given label. +minibuffer :: T.Text -> Editor String Name -> Widget Name +minibuffer string ed = forceAttr ("border" <> "minibuffer") $ - hBox [txt "filter: ", renderEditor (str . unlines) True ed] + hBox [txt $ string <> ": ", renderEditor (str . unlines) True ed] borderQueryStr :: String -> Widget Name borderQueryStr "" = str ""