diff --git a/hledger-ui/Hledger/UI/AccountsScreen.hs b/hledger-ui/Hledger/UI/AccountsScreen.hs index 2a4994b40..b7e5c7cdd 100644 --- a/hledger-ui/Hledger/UI/AccountsScreen.hs +++ b/hledger-ui/Hledger/UI/AccountsScreen.hs @@ -268,7 +268,7 @@ asHandle ui0@UIState{ EvKey (KChar c) [] | c `elem` ['h','?'] -> continue $ setMode Help ui EvKey (KChar 'g') [] -> liftIO (uiReloadJournalIfChanged copts d j ui) >>= continue EvKey (KChar 'a') [] -> suspendAndResume $ clearScreen >> setCursorPosition 0 0 >> add copts j >> uiReloadJournalIfChanged copts d j ui - EvKey (KChar 'E') [] -> suspendAndResume $ void (journalRunEditor endPos j) >> uiReloadJournalIfChanged copts d j ui + EvKey (KChar 'E') [] -> suspendAndResume $ void (runEditor endPos (journalFilePath j)) >> uiReloadJournalIfChanged copts d j ui EvKey (KChar '0') [] -> continue $ regenerateScreens j d $ setDepth (Just 0) ui EvKey (KChar '1') [] -> continue $ regenerateScreens j d $ setDepth (Just 1) ui EvKey (KChar '2') [] -> continue $ regenerateScreens j d $ setDepth (Just 2) ui diff --git a/hledger-ui/Hledger/UI/Editor.hs b/hledger-ui/Hledger/UI/Editor.hs index e0b403e88..4202b5040 100644 --- a/hledger-ui/Hledger/UI/Editor.hs +++ b/hledger-ui/Hledger/UI/Editor.hs @@ -29,9 +29,8 @@ endPos = Just (-1,Nothing) -- | Try running the user's preferred text editor, or a default edit command, -- on the main journal file, blocking until it exits, and returning the exit code; -- or raise an error. -journalRunEditor :: Maybe TextPosition -> Journal -> IO ExitCode -journalRunEditor mpos j = - editorOpenPositionCommand mpos (journalFilePath j) >>= runCommand >>= waitForProcess +runEditor :: Maybe TextPosition -> FilePath -> IO ExitCode +runEditor mpos f = editorOpenPositionCommand mpos f >>= runCommand >>= waitForProcess -- Get the basic shell command to start the user's preferred text editor. -- This is the value of environment variable $HLEDGER_UI_EDITOR, or $EDITOR, or @@ -64,12 +63,15 @@ editorOpenPositionCommand mpos f = do let f' = singleQuoteIfNeeded f return $ case (identifyEditor cmd, mpos) of - (Emacs, Just (line,_)) | line < 0 -> cmd ++ " " ++ f' ++ " -f end-of-buffer" - (Emacs, Just (line,mcol)) | line >= 0 -> cmd ++ " " ++ posopt ++ " " ++ f' - where posopt = "+" ++ show line ++ maybe "" ((":"++).show) mcol - (Vi, Just (line,_)) -> cmd ++ " " ++ posopt ++ " " ++ f' - where posopt = "+" ++ if line >= 0 then show line else "" - _ -> cmd ++ " " ++ f' + (EmacsClient, Just (l,mc)) | l >= 0 -> cmd ++ " " ++ emacsposopt l mc ++ " " ++ f' + (EmacsClient, Just (l,mc)) | l < 0 -> cmd ++ " " ++ emacsposopt 999999999 mc ++ " " ++ f' + (Emacs, Just (l,mc)) | l >= 0 -> cmd ++ " " ++ emacsposopt l mc ++ " " ++ f' + (Emacs, Just (l,_)) | l < 0 -> cmd ++ " " ++ f' ++ " -f end-of-buffer" + (Vi, Just (l,_)) -> cmd ++ " " ++ viposopt l ++ " " ++ f' + _ -> cmd ++ " " ++ f' + where + emacsposopt l mc = "+" ++ show l ++ maybe "" ((":"++).show) mc + viposopt l = "+" ++ if l >= 0 then show l else "" -- Identify which text editor is used in the basic editor command, if possible. identifyEditor :: String -> EditorType diff --git a/hledger-ui/Hledger/UI/ErrorScreen.hs b/hledger-ui/Hledger/UI/ErrorScreen.hs index ca61e05e8..ff1146cd1 100644 --- a/hledger-ui/Hledger/UI/ErrorScreen.hs +++ b/hledger-ui/Hledger/UI/ErrorScreen.hs @@ -8,12 +8,13 @@ module Hledger.UI.ErrorScreen ) where +import Brick import Control.Monad import Control.Monad.IO.Class (liftIO) import Data.Monoid import Data.Time.Calendar (Day) -import Graphics.Vty -import Brick +import Graphics.Vty hiding (char, string)-- (Event(..)) +import Text.Parsec import Hledger.Cli hiding (progname,prognameandversion,green) import Hledger.UI.UIOptions @@ -61,7 +62,7 @@ esDraw _ = error "draw function called with wrong screen type, should not happen esHandle :: UIState -> Event -> EventM (Next UIState) esHandle ui@UIState{ - aScreen=ErrorScreen{} + aScreen=ErrorScreen{..} ,aopts=UIOpts{cliopts_=copts} ,ajournal=j ,aMode=mode @@ -78,7 +79,11 @@ esHandle ui@UIState{ EvKey (KChar 'q') [] -> halt ui EvKey KEsc [] -> continue $ resetScreens d ui EvKey (KChar c) [] | c `elem` ['h','?'] -> continue $ setMode Help ui - EvKey (KChar 'E') [] -> suspendAndResume $ void (journalRunEditor endPos j) >> uiReloadJournalIfChanged copts d j (popScreen ui) + EvKey (KChar 'E') [] -> suspendAndResume $ void (runEditor pos f) >> uiReloadJournalIfChanged copts d j (popScreen ui) + where + (pos,f) = case parsewith hledgerparseerrorpositionp esError of + Right (f,l,c) -> (Just (l, Just c),f) + Left _ -> (endPos, journalFilePath j) EvKey (KChar 'g') [] -> liftIO (uiReloadJournalIfChanged copts d j (popScreen ui)) >>= continue -- (ej, _) <- liftIO $ journalReloadIfChanged copts d j -- case ej of @@ -88,6 +93,17 @@ esHandle ui@UIState{ esHandle _ _ = error "event handler called with wrong screen type, should not happen" +-- | Parse the file name, line and column number from a hledger parse error message, if possible. +-- Temporary, we should keep the original parse error location. XXX +hledgerparseerrorpositionp = do + anyChar `manyTill` char '"' + f <- anyChar `manyTill` (oneOf ['"','\n']) + string " (line " + l <- read <$> many1 digit + string ", column " + c <- read <$> many1 digit + return (f, l, c) + -- If journal file(s) have changed, reload the journal and regenerate all screens. -- This is here so it can reference the error screen. uiReloadJournalIfChanged :: CliOpts -> Day -> Journal -> UIState -> IO UIState diff --git a/hledger-ui/Hledger/UI/RegisterScreen.hs b/hledger-ui/Hledger/UI/RegisterScreen.hs index 1e0c5726c..a92d3f3b3 100644 --- a/hledger-ui/Hledger/UI/RegisterScreen.hs +++ b/hledger-ui/Hledger/UI/RegisterScreen.hs @@ -250,7 +250,11 @@ rsHandle ui@UIState{ EvKey (KChar c) [] | c `elem` ['h','?'] -> continue $ setMode Help ui EvKey (KChar 'g') [] -> liftIO (uiReloadJournalIfChanged copts d j ui) >>= continue EvKey (KChar 'a') [] -> suspendAndResume $ clearScreen >> setCursorPosition 0 0 >> add copts j >> uiReloadJournalIfChanged copts d j ui - EvKey (KChar 'E') [] -> suspendAndResume $ void (journalRunEditor endPos j) >> uiReloadJournalIfChanged copts d j ui + EvKey (KChar 'E') [] -> suspendAndResume $ void (runEditor pos f) >> uiReloadJournalIfChanged copts d j ui + where + (pos,f) = case listSelectedElement rsList of + Nothing -> (endPos, journalFilePath j) + Just (_, RegisterScreenItem{rsItemTransaction=Transaction{tsourcepos=GenericSourcePos f l c}}) -> (Just (l, Just c),f) EvKey (KChar 'F') [] -> scrollTop >> (continue $ regenerateScreens j d $ toggleFlat ui) EvKey (KChar 'Z') [] -> scrollTop >> (continue $ regenerateScreens j d $ toggleEmpty ui) EvKey (KChar 'C') [] -> scrollTop >> (continue $ regenerateScreens j d $ toggleCleared ui) diff --git a/hledger-ui/Hledger/UI/TransactionScreen.hs b/hledger-ui/Hledger/UI/TransactionScreen.hs index 1d8852ce7..354edce03 100644 --- a/hledger-ui/Hledger/UI/TransactionScreen.hs +++ b/hledger-ui/Hledger/UI/TransactionScreen.hs @@ -124,7 +124,9 @@ tsHandle ui@UIState{aScreen=s@TransactionScreen{tsTransaction=(i,t) EvKey (KChar 'q') [] -> halt ui EvKey KEsc [] -> continue $ resetScreens d ui EvKey (KChar c) [] | c `elem` ['h','?'] -> continue $ setMode Help ui - EvKey (KChar 'E') [] -> suspendAndResume $ void (journalRunEditor endPos j) >> uiReloadJournalIfChanged copts d j ui + EvKey (KChar 'E') [] -> suspendAndResume $ void (runEditor pos f) >> uiReloadJournalIfChanged copts d j ui + where + (pos,f) = let GenericSourcePos f l c = tsourcepos t in (Just (l, Just c),f) EvKey (KChar 'g') [] -> do d <- liftIO getCurrentDay (ej, _) <- liftIO $ journalReloadIfChanged copts d j diff --git a/hledger-ui/hledger-ui.cabal b/hledger-ui/hledger-ui.cabal index d9ed0d711..b186d69d6 100644 --- a/hledger-ui/hledger-ui.cabal +++ b/hledger-ui/hledger-ui.cabal @@ -70,6 +70,7 @@ executable hledger-ui , HUnit , microlens >= 0.4 && < 0.5 , microlens-platform >= 0.2.3.1 && < 0.4 + , parsec >= 3 , process >= 1.2 , safe >= 0.2 , split >= 0.1 && < 0.3 diff --git a/hledger-ui/package.yaml b/hledger-ui/package.yaml index 15576b09e..9bf090a59 100644 --- a/hledger-ui/package.yaml +++ b/hledger-ui/package.yaml @@ -75,6 +75,7 @@ executables: - HUnit - microlens >= 0.4 && < 0.5 - microlens-platform >= 0.2.3.1 && < 0.4 + - parsec >= 3 - process >= 1.2 - safe >= 0.2 - split >= 0.1 && < 0.3