ui: editor: jump to current txn or error location (emacs, emacsclient, vi)

This commit is contained in:
Simon Michael 2016-06-19 14:52:55 -07:00
parent c79750bafd
commit 1d419eb7e6
7 changed files with 42 additions and 16 deletions

View File

@ -268,7 +268,7 @@ asHandle ui0@UIState{
EvKey (KChar c) [] | c `elem` ['h','?'] -> continue $ setMode Help ui EvKey (KChar c) [] | c `elem` ['h','?'] -> continue $ setMode Help ui
EvKey (KChar 'g') [] -> liftIO (uiReloadJournalIfChanged copts d j ui) >>= continue 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 '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 '0') [] -> continue $ regenerateScreens j d $ setDepth (Just 0) ui
EvKey (KChar '1') [] -> continue $ regenerateScreens j d $ setDepth (Just 1) ui EvKey (KChar '1') [] -> continue $ regenerateScreens j d $ setDepth (Just 1) ui
EvKey (KChar '2') [] -> continue $ regenerateScreens j d $ setDepth (Just 2) ui EvKey (KChar '2') [] -> continue $ regenerateScreens j d $ setDepth (Just 2) ui

View File

@ -29,9 +29,8 @@ endPos = Just (-1,Nothing)
-- | Try running the user's preferred text editor, or a default edit command, -- | 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; -- on the main journal file, blocking until it exits, and returning the exit code;
-- or raise an error. -- or raise an error.
journalRunEditor :: Maybe TextPosition -> Journal -> IO ExitCode runEditor :: Maybe TextPosition -> FilePath -> IO ExitCode
journalRunEditor mpos j = runEditor mpos f = editorOpenPositionCommand mpos f >>= runCommand >>= waitForProcess
editorOpenPositionCommand mpos (journalFilePath j) >>= runCommand >>= waitForProcess
-- Get the basic shell command to start the user's preferred text editor. -- 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 -- 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 let f' = singleQuoteIfNeeded f
return $ return $
case (identifyEditor cmd, mpos) of case (identifyEditor cmd, mpos) of
(Emacs, Just (line,_)) | line < 0 -> cmd ++ " " ++ f' ++ " -f end-of-buffer" (EmacsClient, Just (l,mc)) | l >= 0 -> cmd ++ " " ++ emacsposopt l mc ++ " " ++ f'
(Emacs, Just (line,mcol)) | line >= 0 -> cmd ++ " " ++ posopt ++ " " ++ f' (EmacsClient, Just (l,mc)) | l < 0 -> cmd ++ " " ++ emacsposopt 999999999 mc ++ " " ++ f'
where posopt = "+" ++ show line ++ maybe "" ((":"++).show) mcol (Emacs, Just (l,mc)) | l >= 0 -> cmd ++ " " ++ emacsposopt l mc ++ " " ++ f'
(Vi, Just (line,_)) -> cmd ++ " " ++ posopt ++ " " ++ f' (Emacs, Just (l,_)) | l < 0 -> cmd ++ " " ++ f' ++ " -f end-of-buffer"
where posopt = "+" ++ if line >= 0 then show line else "" (Vi, Just (l,_)) -> cmd ++ " " ++ viposopt l ++ " " ++ f'
_ -> cmd ++ " " ++ 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. -- Identify which text editor is used in the basic editor command, if possible.
identifyEditor :: String -> EditorType identifyEditor :: String -> EditorType

View File

@ -8,12 +8,13 @@ module Hledger.UI.ErrorScreen
) )
where where
import Brick
import Control.Monad import Control.Monad
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Data.Monoid import Data.Monoid
import Data.Time.Calendar (Day) import Data.Time.Calendar (Day)
import Graphics.Vty import Graphics.Vty hiding (char, string)-- (Event(..))
import Brick import Text.Parsec
import Hledger.Cli hiding (progname,prognameandversion,green) import Hledger.Cli hiding (progname,prognameandversion,green)
import Hledger.UI.UIOptions 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 :: UIState -> Event -> EventM (Next UIState)
esHandle ui@UIState{ esHandle ui@UIState{
aScreen=ErrorScreen{} aScreen=ErrorScreen{..}
,aopts=UIOpts{cliopts_=copts} ,aopts=UIOpts{cliopts_=copts}
,ajournal=j ,ajournal=j
,aMode=mode ,aMode=mode
@ -78,7 +79,11 @@ esHandle ui@UIState{
EvKey (KChar 'q') [] -> halt ui EvKey (KChar 'q') [] -> halt ui
EvKey KEsc [] -> continue $ resetScreens d ui EvKey KEsc [] -> continue $ resetScreens d ui
EvKey (KChar c) [] | c `elem` ['h','?'] -> continue $ setMode Help 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 EvKey (KChar 'g') [] -> liftIO (uiReloadJournalIfChanged copts d j (popScreen ui)) >>= continue
-- (ej, _) <- liftIO $ journalReloadIfChanged copts d j -- (ej, _) <- liftIO $ journalReloadIfChanged copts d j
-- case ej of -- case ej of
@ -88,6 +93,17 @@ esHandle ui@UIState{
esHandle _ _ = error "event handler called with wrong screen type, should not happen" 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. -- If journal file(s) have changed, reload the journal and regenerate all screens.
-- This is here so it can reference the error screen. -- This is here so it can reference the error screen.
uiReloadJournalIfChanged :: CliOpts -> Day -> Journal -> UIState -> IO UIState uiReloadJournalIfChanged :: CliOpts -> Day -> Journal -> UIState -> IO UIState

View File

@ -250,7 +250,11 @@ rsHandle ui@UIState{
EvKey (KChar c) [] | c `elem` ['h','?'] -> continue $ setMode Help ui EvKey (KChar c) [] | c `elem` ['h','?'] -> continue $ setMode Help ui
EvKey (KChar 'g') [] -> liftIO (uiReloadJournalIfChanged copts d j ui) >>= continue 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 '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 'F') [] -> scrollTop >> (continue $ regenerateScreens j d $ toggleFlat ui)
EvKey (KChar 'Z') [] -> scrollTop >> (continue $ regenerateScreens j d $ toggleEmpty ui) EvKey (KChar 'Z') [] -> scrollTop >> (continue $ regenerateScreens j d $ toggleEmpty ui)
EvKey (KChar 'C') [] -> scrollTop >> (continue $ regenerateScreens j d $ toggleCleared ui) EvKey (KChar 'C') [] -> scrollTop >> (continue $ regenerateScreens j d $ toggleCleared ui)

View File

@ -124,7 +124,9 @@ tsHandle ui@UIState{aScreen=s@TransactionScreen{tsTransaction=(i,t)
EvKey (KChar 'q') [] -> halt ui EvKey (KChar 'q') [] -> halt ui
EvKey KEsc [] -> continue $ resetScreens d ui EvKey KEsc [] -> continue $ resetScreens d ui
EvKey (KChar c) [] | c `elem` ['h','?'] -> continue $ setMode Help 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 EvKey (KChar 'g') [] -> do
d <- liftIO getCurrentDay d <- liftIO getCurrentDay
(ej, _) <- liftIO $ journalReloadIfChanged copts d j (ej, _) <- liftIO $ journalReloadIfChanged copts d j

View File

@ -70,6 +70,7 @@ executable hledger-ui
, HUnit , HUnit
, microlens >= 0.4 && < 0.5 , microlens >= 0.4 && < 0.5
, microlens-platform >= 0.2.3.1 && < 0.4 , microlens-platform >= 0.2.3.1 && < 0.4
, parsec >= 3
, process >= 1.2 , process >= 1.2
, safe >= 0.2 , safe >= 0.2
, split >= 0.1 && < 0.3 , split >= 0.1 && < 0.3

View File

@ -75,6 +75,7 @@ executables:
- HUnit - HUnit
- microlens >= 0.4 && < 0.5 - microlens >= 0.4 && < 0.5
- microlens-platform >= 0.2.3.1 && < 0.4 - microlens-platform >= 0.2.3.1 && < 0.4
- parsec >= 3
- process >= 1.2 - process >= 1.2
- safe >= 0.2 - safe >= 0.2
- split >= 0.1 && < 0.3 - split >= 0.1 && < 0.3