reg: --width/-w option to adjust register overall output width
This commit is contained in:
parent
58edc161c9
commit
552a15a1ba
@ -755,6 +755,11 @@ summary postings within each interval:
|
||||
$ hledger register --monthly rent
|
||||
$ hledger register --monthly -E food --depth 4
|
||||
|
||||
The `--width`/`-w` option adjusts the width of the output. By default,
|
||||
this is 80 characters. To allow more space for descriptions and account
|
||||
names, use `-w` to increase the width to 120 characters, or `-wN` to set
|
||||
any desired width (at least 50 recommended).
|
||||
|
||||
#### balance
|
||||
|
||||
The balance command displays accounts and their balances, indented to show the account hierarchy.
|
||||
|
||||
@ -38,7 +38,6 @@ module Hledger.Data.Posting (
|
||||
sumPostings,
|
||||
-- * rendering
|
||||
showPosting,
|
||||
showPostingForRegister,
|
||||
-- * misc.
|
||||
showComment,
|
||||
tests_Hledger_Data_Posting
|
||||
@ -95,20 +94,6 @@ showPosting p@Posting{paccount=a,pamount=amt,ptype=t} =
|
||||
showComment :: String -> String
|
||||
showComment s = if null s then "" else " ;" ++ s
|
||||
|
||||
-- XXX refactor
|
||||
showPostingForRegister :: Posting -> String
|
||||
showPostingForRegister (Posting{paccount=a,pamount=amt,ptype=t}) =
|
||||
concatTopPadded [showaccountname a ++ " ", showamount amt]
|
||||
where
|
||||
ledger3ishlayout = False
|
||||
acctnamewidth = if ledger3ishlayout then 25 else 22
|
||||
showaccountname = printf ("%-"++(show acctnamewidth)++"s") . bracket . elideAccountName width
|
||||
(bracket,width) = case t of
|
||||
BalancedVirtualPosting -> (\s -> "["++s++"]", acctnamewidth-2)
|
||||
VirtualPosting -> (\s -> "("++s++")", acctnamewidth-2)
|
||||
_ -> (id,acctnamewidth)
|
||||
showamount = padleft 12 . showMixedAmountWithoutPrice
|
||||
|
||||
isReal :: Posting -> Bool
|
||||
isReal p = ptype p == RegularPosting
|
||||
|
||||
|
||||
@ -223,8 +223,10 @@ registerFromString :: String -> IO String
|
||||
registerFromString s = do
|
||||
d <- getCurrentDay
|
||||
j <- readJournal' s
|
||||
return $ postingsReportAsText opts $ postingsReport opts (queryFromOpts d opts) j
|
||||
where opts = defreportopts{empty_=True}
|
||||
return $ postingsReportAsText opts $ postingsReport ropts (queryFromOpts d ropts) j
|
||||
where
|
||||
ropts = defreportopts{empty_=True}
|
||||
opts = defcliopts{reportopts_=ropts}
|
||||
|
||||
-- | Return a similarity measure, from 0 to 1, for two strings.
|
||||
-- This is Simon White's letter pairs algorithm from
|
||||
|
||||
@ -7,7 +7,7 @@ Command-line options for the hledger program, and option-parsing utilities.
|
||||
|
||||
module Hledger.Cli.Options
|
||||
where
|
||||
import Control.Exception as C
|
||||
import qualified Control.Exception as C
|
||||
import Data.List
|
||||
import Data.List.Split
|
||||
import Data.Maybe
|
||||
@ -19,7 +19,7 @@ import System.Console.CmdArgs.Text
|
||||
import System.Directory
|
||||
import System.Environment
|
||||
import Test.HUnit
|
||||
import Text.ParserCombinators.Parsec
|
||||
import Text.ParserCombinators.Parsec as P
|
||||
import Text.Printf
|
||||
|
||||
import Hledger
|
||||
@ -189,7 +189,7 @@ accountsmode = (commandmode ["balance","bal","accounts"]) {
|
||||
,modeGroupFlags = Group {
|
||||
groupUnnamed = [
|
||||
flagNone ["flat"] (\opts -> setboolopt "flat" opts) "show full account names, unindented"
|
||||
,flagReq ["drop"] (\s opts -> Right $ setopt "drop" s opts) "N" "with --flat, omit this many leading account name components"
|
||||
,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) "no eliding at all, stronger than --empty"
|
||||
,flagNone ["no-total"] (\opts -> setboolopt "no-total" opts) "don't show the final total"
|
||||
@ -213,7 +213,9 @@ postingsmode = (commandmode ["register","postings"]) {
|
||||
modeHelp = "(or postings) show matched postings and running total"
|
||||
,modeArgs = ([], Just commandargsflag)
|
||||
,modeGroupFlags = Group {
|
||||
groupUnnamed = []
|
||||
groupUnnamed = [
|
||||
flagOpt (show defaultWidthWithFlag) ["width","w"] (\s opts -> Right $ setopt "width" s opts) "N" "increase or set the output width (default: 80)"
|
||||
]
|
||||
,groupHidden = []
|
||||
,groupNamed = [(generalflagstitle, generalflags1)]
|
||||
}
|
||||
@ -293,6 +295,7 @@ data CliOpts = CliOpts {
|
||||
,alias_ :: [String]
|
||||
,debug_ :: Bool
|
||||
,no_new_accounts_ :: Bool -- add
|
||||
,width_ :: Maybe String -- register
|
||||
,reportopts_ :: ReportOpts
|
||||
} deriving (Show)
|
||||
|
||||
@ -305,6 +308,7 @@ defcliopts = CliOpts
|
||||
def
|
||||
def
|
||||
def
|
||||
def
|
||||
|
||||
instance Default CliOpts where def = defcliopts
|
||||
|
||||
@ -322,6 +326,7 @@ toCliOpts rawopts = do
|
||||
,alias_ = map stripquotes $ listofstringopt "alias" rawopts
|
||||
,debug_ = boolopt "debug" rawopts
|
||||
,no_new_accounts_ = boolopt "no-new-accounts" rawopts -- add
|
||||
,width_ = maybestringopt "width" rawopts -- register
|
||||
,reportopts_ = defreportopts {
|
||||
begin_ = maybesmartdateopt d "begin" rawopts
|
||||
,end_ = maybesmartdateopt d "end" rawopts
|
||||
@ -441,10 +446,13 @@ checkCliOpts opts@CliOpts{reportopts_=ropts} = do
|
||||
case formatFromOpts ropts of
|
||||
Left err -> optserror $ "could not parse format option: "++err
|
||||
Right _ -> return ()
|
||||
case widthFromOpts opts of
|
||||
Left err -> optserror $ "could not parse width option: "++err
|
||||
Right _ -> return ()
|
||||
return opts
|
||||
|
||||
-- | Parse any format option provided, possibly raising an error, or get
|
||||
-- the default value.
|
||||
-- | Parse the format option if provided, possibly returning an error,
|
||||
-- otherwise get the default value.
|
||||
formatFromOpts :: ReportOpts -> Either String [FormatString]
|
||||
formatFromOpts = maybe (Right defaultBalanceFormatString) parseFormatString . format_
|
||||
|
||||
@ -457,6 +465,35 @@ defaultBalanceFormatString = [
|
||||
, FormatField True Nothing Nothing AccountField
|
||||
]
|
||||
|
||||
data OutputWidth = TotalWidth Width | FieldWidths [Width] deriving Show
|
||||
data Width = Width Int | Auto deriving Show
|
||||
|
||||
defaultWidth = 80
|
||||
defaultWidthWithFlag = 120
|
||||
|
||||
-- | Parse the width option if provided, possibly returning an error,
|
||||
-- otherwise get the default value.
|
||||
widthFromOpts :: CliOpts -> Either String OutputWidth
|
||||
widthFromOpts CliOpts{width_=Nothing} = Right $ TotalWidth $ Width defaultWidth
|
||||
widthFromOpts CliOpts{width_=Just ""} = Right $ TotalWidth $ Width defaultWidthWithFlag
|
||||
widthFromOpts CliOpts{width_=Just s} = parseWidth s
|
||||
|
||||
parseWidth :: String -> Either String OutputWidth
|
||||
parseWidth s = case (runParser outputwidth () "(unknown)") s of
|
||||
Left e -> Left $ show e
|
||||
Right x -> Right x
|
||||
|
||||
outputwidth :: GenParser Char st OutputWidth
|
||||
outputwidth =
|
||||
try (do w <- width
|
||||
ws <- many1 (char ',' >> width)
|
||||
return $ FieldWidths $ w:ws)
|
||||
<|> TotalWidth `fmap` width
|
||||
|
||||
width :: GenParser Char st Width
|
||||
width = (string "auto" >> return Auto)
|
||||
<|> (Width . read) `fmap` many1 digit
|
||||
|
||||
-- | Get the (tilde-expanded, absolute) journal file path from options, an environment variable, or a default.
|
||||
journalFilePathFromOpts :: CliOpts -> IO String
|
||||
journalFilePathFromOpts opts = do
|
||||
|
||||
@ -24,12 +24,12 @@ import Hledger.Cli.Options
|
||||
|
||||
-- | Print a (posting) register report.
|
||||
register :: CliOpts -> Journal -> IO ()
|
||||
register CliOpts{reportopts_=ropts} j = do
|
||||
register opts@CliOpts{reportopts_=ropts} j = do
|
||||
d <- getCurrentDay
|
||||
putStr $ postingsReportAsText ropts $ postingsReport ropts (queryFromOpts d ropts) j
|
||||
putStr $ postingsReportAsText opts $ postingsReport ropts (queryFromOpts d ropts) j
|
||||
|
||||
-- | Render a register report as plain text suitable for console output.
|
||||
postingsReportAsText :: ReportOpts -> PostingsReport -> String
|
||||
postingsReportAsText :: CliOpts -> PostingsReport -> String
|
||||
postingsReportAsText opts = unlines . map (postingsReportItemAsText opts) . snd
|
||||
|
||||
tests_postingsReportAsText = [
|
||||
@ -38,32 +38,50 @@ tests_postingsReportAsText = [
|
||||
j <- readJournal'
|
||||
"2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n"
|
||||
let opts = defreportopts
|
||||
(postingsReportAsText opts $ postingsReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is` unlines
|
||||
(postingsReportAsText defcliopts $ postingsReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is` unlines
|
||||
["2009/01/01 медвежья шкура расходы:покупки 100 100"
|
||||
," актив:наличные -100 0"]
|
||||
]
|
||||
|
||||
-- | Render one register report line item as plain text. Eg:
|
||||
-- | Render one register report line item as plain text. Layout is like so:
|
||||
-- @
|
||||
-- date (10) description (20) account (22) amount (11) balance (12)
|
||||
-- DDDDDDDDDD dddddddddddddddddddd aaaaaaaaaaaaaaaaaaaaaa AAAAAAAAAAA AAAAAAAAAAAA
|
||||
-- ^ displayed for first postings^
|
||||
-- only, otherwise blank
|
||||
-- <----------------------------- width (default: 80) ----------------------------->
|
||||
-- date (10) description (50%) account (50%) amount (12) balance (12)
|
||||
-- DDDDDDDDDD dddddddddddddddddddd aaaaaaaaaaaaaaaaaaa AAAAAAAAAAAA AAAAAAAAAAAA
|
||||
--
|
||||
-- date and description are shown for the first posting of a transaction only.
|
||||
-- @
|
||||
postingsReportItemAsText :: ReportOpts -> PostingsReportItem -> String
|
||||
postingsReportItemAsText _ (dd, p, b) = concatTopPadded [datedesc, pstr, " ", bal]
|
||||
postingsReportItemAsText :: CliOpts -> PostingsReportItem -> String
|
||||
postingsReportItemAsText opts (dd, p, b) =
|
||||
concatTopPadded [date, " ", desc, " ", acct, " ", amt, " ", bal]
|
||||
where
|
||||
datedesc = case dd of Nothing -> replicate datedescwidth ' '
|
||||
Just (da, de) -> printf "%s %s " date desc
|
||||
where
|
||||
date = showDate da
|
||||
desc = printf ("%-"++(show descwidth)++"s") $ elideRight descwidth de :: String
|
||||
where
|
||||
descwidth = datedescwidth - datewidth - 2
|
||||
datedescwidth = 32
|
||||
datewidth = 10
|
||||
pstr = showPostingForRegister p
|
||||
bal = padleft 12 (showMixedAmountWithoutPrice b)
|
||||
totalwidth = case widthFromOpts opts of
|
||||
Left _ -> defaultWidth -- shouldn't happen
|
||||
Right (TotalWidth (Width w)) -> w
|
||||
Right (TotalWidth Auto) -> defaultWidth -- XXX
|
||||
Right (FieldWidths _) -> defaultWidth -- XXX
|
||||
datewidth = 10
|
||||
amtwidth = 12
|
||||
balwidth = 12
|
||||
remaining = totalwidth - (datewidth + 2 + 2 + amtwidth + 2 + balwidth)
|
||||
(descwidth, acctwidth) | even r = (r', r')
|
||||
| otherwise = (r', r'+1)
|
||||
where r = remaining - 2
|
||||
r' = r `div` 2
|
||||
(date, desc) = case dd of
|
||||
Just (da, de) -> (printf ("%-"++show datewidth++"s") (showDate da)
|
||||
,printf ("%-"++show descwidth++"s") (take descwidth $ elideRight descwidth de :: String)
|
||||
)
|
||||
Nothing -> (replicate datewidth ' ', replicate descwidth ' ')
|
||||
acct = printf ("%-"++(show acctwidth)++"s") a
|
||||
where
|
||||
a = bracket $ elideAccountName awidth $ paccount p
|
||||
(bracket, awidth) = case ptype p of
|
||||
BalancedVirtualPosting -> (\s -> "["++s++"]", acctwidth-2)
|
||||
VirtualPosting -> (\s -> "("++s++")", acctwidth-2)
|
||||
_ -> (id,acctwidth)
|
||||
amt = padleft amtwidth $ showMixedAmountWithoutPrice $ pamount p
|
||||
bal = padleft balwidth $ showMixedAmountWithoutPrice b
|
||||
|
||||
-- XXX
|
||||
-- showPostingWithBalanceForVty showtxninfo p b = postingsReportItemAsText defreportopts $ mkpostingsReportItem showtxninfo p b
|
||||
|
||||
Loading…
Reference in New Issue
Block a user