142 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Haskell
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Haskell
		
	
	
	
	
	
{-|
 | 
						|
hledger-ui - a hledger add-on providing a curses-style interface.
 | 
						|
Copyright (c) 2007-2015 Simon Michael <simon@joyful.com>
 | 
						|
Released under GPL version 3 or later.
 | 
						|
-}
 | 
						|
{-# LANGUAGE OverloadedStrings #-}
 | 
						|
{-# LANGUAGE TemplateHaskell #-}
 | 
						|
{-# LANGUAGE MultiParamTypeClasses #-}
 | 
						|
 | 
						|
module Hledger.UI.Main where
 | 
						|
 | 
						|
-- import Control.Applicative
 | 
						|
-- import Lens.Micro.Platform ((^.))
 | 
						|
import Control.Monad
 | 
						|
-- import Control.Monad.IO.Class (liftIO)
 | 
						|
-- import Data.Default
 | 
						|
-- import Data.Monoid              -- 
 | 
						|
import Data.List
 | 
						|
import Data.Maybe
 | 
						|
-- import Data.Text (Text)
 | 
						|
import qualified Data.Text as T
 | 
						|
-- import Data.Time.Calendar
 | 
						|
import Safe
 | 
						|
import System.Exit
 | 
						|
 | 
						|
import qualified Graphics.Vty as V
 | 
						|
import Brick
 | 
						|
 | 
						|
import Hledger
 | 
						|
import Hledger.Cli hiding (progname,prognameandversion,green)
 | 
						|
import Hledger.UI.UIOptions
 | 
						|
import Hledger.UI.UITypes
 | 
						|
-- import Hledger.UI.UIUtils
 | 
						|
import Hledger.UI.Theme
 | 
						|
import Hledger.UI.AccountsScreen
 | 
						|
import Hledger.UI.RegisterScreen
 | 
						|
 | 
						|
----------------------------------------------------------------------
 | 
						|
 | 
						|
main :: IO ()
 | 
						|
main = do
 | 
						|
  opts <- getHledgerUIOpts
 | 
						|
  -- when (debug_ $ cliopts_ opts) $ printf "%s\n" prognameandversion >> printf "opts: %s\n" (show opts)
 | 
						|
  run opts
 | 
						|
    where
 | 
						|
      run opts
 | 
						|
        | "h"               `inRawOpts` (rawopts_ $ cliopts_ opts) = putStr (showModeUsage uimode) >> exitSuccess
 | 
						|
        | "help"            `inRawOpts` (rawopts_ $ cliopts_ opts) = printHelpForTopic (topicForMode uimode) >> exitSuccess
 | 
						|
        | "man"             `inRawOpts` (rawopts_ $ cliopts_ opts) = runManForTopic (topicForMode uimode) >> exitSuccess
 | 
						|
        | "info"            `inRawOpts` (rawopts_ $ cliopts_ opts) = runInfoForTopic (topicForMode uimode) >> exitSuccess
 | 
						|
        | "version"         `inRawOpts` (rawopts_ $ cliopts_ opts) = putStrLn prognameandversion >> exitSuccess
 | 
						|
        | "binary-filename" `inRawOpts` (rawopts_ $ cliopts_ opts) = putStrLn (binaryfilename progname)
 | 
						|
        | otherwise                                                = withJournalDoUICommand opts runBrickUi
 | 
						|
 | 
						|
-- XXX withJournalDo specialised for UIOpts
 | 
						|
withJournalDoUICommand :: UIOpts -> (UIOpts -> Journal -> IO ()) -> IO ()
 | 
						|
withJournalDoUICommand uopts@UIOpts{cliopts_=copts} cmd = do
 | 
						|
  rulespath <- rulesFilePathFromOpts copts
 | 
						|
  journalpath <- journalFilePathFromOpts copts
 | 
						|
  ej <- readJournalFiles Nothing rulespath (not $ ignore_assertions_ copts) journalpath
 | 
						|
  either error' (cmd uopts . journalApplyAliases (aliasesFromOpts copts)) ej
 | 
						|
 | 
						|
runBrickUi :: UIOpts -> Journal -> IO ()
 | 
						|
runBrickUi uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} j = do
 | 
						|
  d <- getCurrentDay
 | 
						|
 | 
						|
  let
 | 
						|
 | 
						|
    -- depth: is a bit different from other queries. In hledger cli,
 | 
						|
    -- - reportopts{depth_} indicates --depth options
 | 
						|
    -- - reportopts{query_} is the query arguments as a string
 | 
						|
    -- - the report query is based on both of these.
 | 
						|
    -- For hledger-ui, for now, move depth: arguments out of reportopts{query_}
 | 
						|
    -- and into reportopts{depth_}, so that depth and other kinds of filter query
 | 
						|
    -- can be displayed independently.
 | 
						|
    uopts' = uopts{
 | 
						|
      cliopts_=copts{
 | 
						|
         reportopts_= ropts{
 | 
						|
            -- ensure depth_ also reflects depth: args
 | 
						|
            depth_=depthfromoptsandargs,
 | 
						|
            -- remove depth: args from query_
 | 
						|
            query_=unwords $ -- as in ReportOptions, with same limitations
 | 
						|
                   [v | (k,v) <- rawopts_ copts, k=="args", not $ "depth" `isPrefixOf` v],
 | 
						|
            -- show items with zero amount by default, unlike the CLI
 | 
						|
            empty_=True
 | 
						|
            }
 | 
						|
         }
 | 
						|
      }
 | 
						|
      where
 | 
						|
        q = queryFromOpts d ropts
 | 
						|
        depthfromoptsandargs = case queryDepth q of 99999 -> Nothing
 | 
						|
                                                    d     -> Just d
 | 
						|
 | 
						|
    -- XXX move this stuff into Options, UIOpts
 | 
						|
    theme = maybe defaultTheme (fromMaybe defaultTheme . getTheme) $
 | 
						|
            maybestringopt "theme" $ rawopts_ copts
 | 
						|
    mregister = maybestringopt "register" $ rawopts_ copts
 | 
						|
 | 
						|
    (scr, prevscrs) = case mregister of
 | 
						|
      Nothing   -> (accountsScreen, [])
 | 
						|
      -- with --register, start on the register screen, and also put
 | 
						|
      -- the accounts screen on the prev screens stack so you can exit
 | 
						|
      -- to that as usual.
 | 
						|
      Just apat -> (rsSetAccount acct False registerScreen, [ascr'])
 | 
						|
        where
 | 
						|
          acct = headDef
 | 
						|
                 (error' $ "--register "++apat++" did not match any account")
 | 
						|
                 $ filter (regexMatches apat . T.unpack) $ journalAccountNames j
 | 
						|
          -- Initialising the accounts screen is awkward, requiring
 | 
						|
          -- another temporary UIState value..
 | 
						|
          ascr' = aScreen $
 | 
						|
                  asInit d True $
 | 
						|
                  UIState{
 | 
						|
                    aopts=uopts'
 | 
						|
                   ,ajournal=j
 | 
						|
                   ,aScreen=asSetSelectedAccount acct accountsScreen
 | 
						|
                   ,aPrevScreens=[]
 | 
						|
                   ,aMode=Normal
 | 
						|
                   }
 | 
						|
  
 | 
						|
    ui = (sInit scr) d True
 | 
						|
         UIState{
 | 
						|
            aopts=uopts'
 | 
						|
           ,ajournal=j
 | 
						|
           ,aScreen=scr
 | 
						|
           ,aPrevScreens=prevscrs
 | 
						|
           ,aMode=Normal
 | 
						|
           }
 | 
						|
 | 
						|
    brickapp :: App (UIState) V.Event Name
 | 
						|
    brickapp = App {
 | 
						|
        appLiftVtyEvent = id
 | 
						|
      , appStartEvent   = return
 | 
						|
      , appAttrMap      = const theme
 | 
						|
      , appChooseCursor = showFirstCursor
 | 
						|
      , appHandleEvent  = \ui ev -> sHandle (aScreen ui) ui ev
 | 
						|
      , appDraw         = \ui    -> sDraw   (aScreen ui) ui
 | 
						|
      }
 | 
						|
 | 
						|
  void $ defaultMain brickapp ui
 | 
						|
 |