lib: textification: comments and tags

No change.

hledger -f data/100x100x10.journal stats
<<ghc: 42859576 bytes, 84 GCs, 193781/269984 avg/max bytes residency (3 samples), 2M in use, 0.000 INIT (0.001 elapsed), 0.016 MUT (0.020 elapsed), 0.009 GC (0.011 elapsed) :ghc>>
<<ghc: 42859576 bytes, 84 GCs, 193781/269984 avg/max bytes residency (3 samples), 2M in use, 0.000 INIT (0.001 elapsed), 0.015 MUT (0.018 elapsed), 0.009 GC (0.013 elapsed) :ghc>>

hledger -f data/1000x1000x10.journal stats
<<ghc: 349576344 bytes, 681 GCs, 1407388/4091680 avg/max bytes residency (7 samples), 11M in use, 0.000 INIT (0.000 elapsed), 0.124 MUT (0.130 elapsed), 0.047 GC (0.055 elapsed) :ghc>>
<<ghc: 349576280 bytes, 681 GCs, 1407388/4091680 avg/max bytes residency (7 samples), 11M in use, 0.000 INIT (0.000 elapsed), 0.126 MUT (0.132 elapsed), 0.049 GC (0.058 elapsed) :ghc>>

hledger -f data/10000x1000x10.journal stats
<<ghc: 3424030664 bytes, 6658 GCs, 11403359/41071624 avg/max bytes residency (11 samples), 111M in use, 0.000 INIT (0.000 elapsed), 1.207 MUT (1.228 elapsed), 0.473 GC (0.528 elapsed) :ghc>>
<<ghc: 3424030760 bytes, 6658 GCs, 11403874/41077288 avg/max bytes residency (11 samples), 111M in use, 0.000 INIT (0.002 elapsed), 1.234 MUT (1.256 elapsed), 0.470 GC (0.520 elapsed) :ghc>>

hledger -f data/100000x1000x10.journal stats
<<ghc: 34306547448 bytes, 66727 GCs, 76805504/414629288 avg/max bytes residency (14 samples), 1009M in use, 0.000 INIT (0.003 elapsed), 12.615 MUT (12.813 elapsed), 4.656 GC (5.291 elapsed) :ghc>>
<<ghc: 34306547320 bytes, 66727 GCs, 76805504/414629288 avg/max bytes residency (14 samples), 1009M in use, 0.000 INIT (0.009 elapsed), 12.802 MUT (13.065 elapsed), 4.774 GC (5.441 elapsed) :ghc>>
This commit is contained in:
Simon Michael 2016-05-24 17:09:20 -07:00
parent c89c33b36e
commit 770dcee742
14 changed files with 51 additions and 49 deletions

View File

@ -174,7 +174,7 @@ nulljournal = Journal {
,jmodifiertxns = [] ,jmodifiertxns = []
,jperiodictxns = [] ,jperiodictxns = []
,jtxns = [] ,jtxns = []
,jfinalcommentlines = [] ,jfinalcommentlines = ""
,jfiles = [] ,jfiles = []
,jlastreadtime = TOD 0 0 ,jlastreadtime = TOD 0 0
} }

View File

@ -54,7 +54,7 @@ import Data.Maybe
import Data.MemoUgly (memo) import Data.MemoUgly (memo)
import Data.Monoid import Data.Monoid
import Data.Ord import Data.Ord
-- import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import Data.Time.Calendar import Data.Time.Calendar
import Safe import Safe
@ -102,8 +102,8 @@ showPosting p@Posting{paccount=a,pamount=amt,ptype=t} =
showamount = padLeftWide 12 . showMixedAmount showamount = padLeftWide 12 . showMixedAmount
showComment :: String -> String showComment :: Text -> String
showComment s = if null s then "" else " ;" ++ s showComment t = if T.null t then "" else " ;" ++ T.unpack t
isReal :: Posting -> Bool isReal :: Posting -> Bool
isReal p = ptype p == RegularPosting isReal p = ptype p == RegularPosting

View File

@ -42,7 +42,7 @@ module Hledger.Data.Transaction (
where where
import Data.List import Data.List
import Data.Maybe import Data.Maybe
-- import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import Data.Time.Calendar import Data.Time.Calendar
import Test.HUnit import Test.HUnit
@ -159,9 +159,9 @@ showTransactionHelper elide onelineamounts t =
c:cs -> (c,cs) c:cs -> (c,cs)
-- Render a transaction or posting's comment as indented, semicolon-prefixed comment lines. -- Render a transaction or posting's comment as indented, semicolon-prefixed comment lines.
renderCommentLines :: String -> [String] renderCommentLines :: Text -> [String]
renderCommentLines s = case lines s of ("":ls) -> "":map commentprefix ls renderCommentLines t = case lines $ T.unpack t of ("":ls) -> "":map commentprefix ls
ls -> map commentprefix ls ls -> map commentprefix ls
where where
commentprefix = indent . ("; "++) commentprefix = indent . ("; "++)

View File

@ -128,8 +128,8 @@ data PostingType = RegularPosting | VirtualPosting | BalancedVirtualPosting
instance NFData PostingType instance NFData PostingType
type TagName = String type TagName = Text
type TagValue = String type TagValue = Text
type Tag = (TagName, TagValue) -- ^ A tag name and (possibly empty) value. type Tag = (TagName, TagValue) -- ^ A tag name and (possibly empty) value.
data ClearedStatus = Uncleared | Pending | Cleared data ClearedStatus = Uncleared | Pending | Cleared
@ -148,7 +148,7 @@ data Posting = Posting {
pstatus :: ClearedStatus, pstatus :: ClearedStatus,
paccount :: AccountName, paccount :: AccountName,
pamount :: MixedAmount, pamount :: MixedAmount,
pcomment :: String, -- ^ this posting's comment lines, as a single non-indented multi-line string pcomment :: Text, -- ^ this posting's comment lines, as a single non-indented multi-line string
ptype :: PostingType, ptype :: PostingType,
ptags :: [Tag], -- ^ tag names and values, extracted from the comment ptags :: [Tag], -- ^ tag names and values, extracted from the comment
pbalanceassertion :: Maybe MixedAmount, -- ^ optional: the expected balance in the account after this posting pbalanceassertion :: Maybe MixedAmount, -- ^ optional: the expected balance in the account after this posting
@ -178,10 +178,10 @@ data Transaction = Transaction {
tstatus :: ClearedStatus, tstatus :: ClearedStatus,
tcode :: String, tcode :: String,
tdescription :: String, tdescription :: String,
tcomment :: String, -- ^ this transaction's comment lines, as a single non-indented multi-line string tcomment :: Text, -- ^ this transaction's comment lines, as a single non-indented multi-line string
ttags :: [Tag], -- ^ tag names and values, extracted from the comment ttags :: [Tag], -- ^ tag names and values, extracted from the comment
tpostings :: [Posting], -- ^ this transaction's postings tpostings :: [Posting], -- ^ this transaction's postings
tpreceding_comment_lines :: String -- ^ any comment lines immediately preceding this transaction tpreceding_comment_lines :: Text -- ^ any comment lines immediately preceding this transaction
} deriving (Eq,Typeable,Data,Generic) } deriving (Eq,Typeable,Data,Generic)
instance NFData Transaction instance NFData Transaction
@ -250,7 +250,7 @@ data Journal = Journal {
,jmodifiertxns :: [ModifierTransaction] ,jmodifiertxns :: [ModifierTransaction]
,jperiodictxns :: [PeriodicTransaction] ,jperiodictxns :: [PeriodicTransaction]
,jtxns :: [Transaction] ,jtxns :: [Transaction]
,jfinalcommentlines :: String -- ^ any final trailing comments in the (main) journal file ,jfinalcommentlines :: Text -- ^ any final trailing comments in the (main) journal file
,jfiles :: [(FilePath, Text)] -- ^ the file path and raw text of the main and ,jfiles :: [(FilePath, Text)] -- ^ the file path and raw text of the main and
-- any included journal files. The main file is first, -- any included journal files. The main file is first,
-- followed by any included files in the order encountered. -- followed by any included files in the order encountered.

View File

@ -726,8 +726,8 @@ tests_matchesTransaction = [
matchedTags :: Regexp -> Maybe Regexp -> [Tag] -> [Tag] matchedTags :: Regexp -> Maybe Regexp -> [Tag] -> [Tag]
matchedTags namepat valuepat tags = filter (match namepat valuepat) tags matchedTags namepat valuepat tags = filter (match namepat valuepat) tags
where where
match npat Nothing (n,_) = regexMatchesCI npat n match npat Nothing (n,_) = regexMatchesCI npat (T.unpack n) -- XXX
match npat (Just vpat) (n,v) = regexMatchesCI npat n && regexMatchesCI vpat v match npat (Just vpat) (n,v) = regexMatchesCI npat (T.unpack n) && regexMatchesCI vpat (T.unpack v)
-- tests -- tests

View File

@ -27,7 +27,7 @@ import Data.Functor.Identity
import Data.List.Compat import Data.List.Compat
import Data.List.Split (wordsBy) import Data.List.Split (wordsBy)
import Data.Maybe import Data.Maybe
-- import Data.Monoid import Data.Monoid
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import Data.Time.Calendar import Data.Time.Calendar
@ -560,12 +560,12 @@ emptyorcommentlinep = do
return () return ()
-- | Parse a possibly multi-line comment following a semicolon. -- | Parse a possibly multi-line comment following a semicolon.
followingcommentp :: Monad m => JournalParser m String followingcommentp :: Monad m => JournalParser m Text
followingcommentp = followingcommentp =
-- ptrace "followingcommentp" -- ptrace "followingcommentp"
do samelinecomment <- many spacenonewline >> (try semicoloncommentp <|> (newline >> return "")) do samelinecomment <- many spacenonewline >> (try semicoloncommentp <|> (newline >> return ""))
newlinecomments <- many (try (many1 spacenonewline >> semicoloncommentp)) newlinecomments <- many (try (many1 spacenonewline >> semicoloncommentp))
return $ unlines $ samelinecomment:newlinecomments return $ T.unlines $ samelinecomment:newlinecomments
-- | Parse a possibly multi-line comment following a semicolon, and -- | Parse a possibly multi-line comment following a semicolon, and
-- any tags and/or posting dates within it. Posting dates can be -- any tags and/or posting dates within it. Posting dates can be
@ -586,7 +586,7 @@ followingcommentp =
-- >>> rejp (followingcommentandtagsp (Just $ fromGregorian 2000 1 2)) "; date:3/4=5/6" -- >>> rejp (followingcommentandtagsp (Just $ fromGregorian 2000 1 2)) "; date:3/4=5/6"
-- Right ("date:3/4=5/6\n",[("date","3/4=5/6")],Just 2000-03-04,Nothing) -- Right ("date:3/4=5/6\n",[("date","3/4=5/6")],Just 2000-03-04,Nothing)
-- --
followingcommentandtagsp :: Maybe Day -> ErroringJournalParser (String, [Tag], Maybe Day, Maybe Day) followingcommentandtagsp :: Maybe Day -> ErroringJournalParser (Text, [Tag], Maybe Day, Maybe Day)
followingcommentandtagsp mdefdate = do followingcommentandtagsp mdefdate = do
-- pdbg 0 "followingcommentandtagsp" -- pdbg 0 "followingcommentandtagsp"
@ -600,7 +600,7 @@ followingcommentandtagsp mdefdate = do
l1 <- try semicoloncommentp' <|> (newline >> return "") l1 <- try semicoloncommentp' <|> (newline >> return "")
ls <- many $ try ((++) <$> many1 spacenonewline <*> semicoloncommentp') ls <- many $ try ((++) <$> many1 spacenonewline <*> semicoloncommentp')
return $ unlines $ (sp1 ++ l1) : ls return $ unlines $ (sp1 ++ l1) : ls
let comment = unlines $ map (lstrip . dropWhile (==';') . strip) $ lines commentandwhitespace let comment = T.pack $ unlines $ map (lstrip . dropWhile (==';') . strip) $ lines commentandwhitespace
-- pdbg 0 $ "commentws:"++show commentandwhitespace -- pdbg 0 $ "commentws:"++show commentandwhitespace
-- pdbg 0 $ "comment:"++show comment -- pdbg 0 $ "comment:"++show comment
@ -621,23 +621,23 @@ followingcommentandtagsp mdefdate = do
return (comment, tags, mdate, mdate2) return (comment, tags, mdate, mdate2)
commentp :: Monad m => JournalParser m String commentp :: Monad m => JournalParser m Text
commentp = commentStartingWithp commentchars commentp = commentStartingWithp commentchars
commentchars :: [Char] commentchars :: [Char]
commentchars = "#;*" commentchars = "#;*"
semicoloncommentp :: Monad m => JournalParser m String semicoloncommentp :: Monad m => JournalParser m Text
semicoloncommentp = commentStartingWithp ";" semicoloncommentp = commentStartingWithp ";"
commentStartingWithp :: Monad m => String -> JournalParser m String commentStartingWithp :: Monad m => [Char] -> JournalParser m Text
commentStartingWithp cs = do commentStartingWithp cs = do
-- ptrace "commentStartingWith" -- ptrace "commentStartingWith"
oneOf cs oneOf cs
many spacenonewline many spacenonewline
l <- anyChar `manyTill` eolof l <- anyChar `manyTill` eolof
optional newline optional newline
return l return $ T.pack l
--- ** tags --- ** tags
@ -694,16 +694,16 @@ tagp = do
-- | -- |
-- >>> rsp tagnamep "a:" -- >>> rsp tagnamep "a:"
-- Right "a" -- Right "a"
tagnamep :: Monad m => TextParser u m String tagnamep :: Monad m => TextParser u m Text
tagnamep = -- do tagnamep = -- do
-- pdbg 0 "tagnamep" -- pdbg 0 "tagnamep"
many1 (noneOf ": \t\n") <* char ':' T.pack <$> many1 (noneOf ": \t\n") <* char ':'
tagvaluep :: Monad m => TextParser u m String tagvaluep :: Monad m => TextParser u m Text
tagvaluep = do tagvaluep = do
-- ptrace "tagvalue" -- ptrace "tagvalue"
v <- anyChar `manyTill` (void (try (char ',')) <|> eolof) v <- anyChar `manyTill` (void (try (char ',')) <|> eolof)
return $ strip $ reverse $ dropWhile (==',') $ reverse $ strip v return $ T.pack $ strip $ reverse $ dropWhile (==',') $ reverse $ strip v
--- ** posting dates --- ** posting dates
@ -741,7 +741,7 @@ datetagp :: Maybe Day -> ErroringJournalParser (TagName,Day)
datetagp mdefdate = do datetagp mdefdate = do
-- pdbg 0 "datetagp" -- pdbg 0 "datetagp"
string "date" string "date"
n <- fromMaybe "" <$> optionMaybe (string "2") n <- T.pack . fromMaybe "" <$> optionMaybe (string "2")
char ':' char ':'
startpos <- getPosition startpos <- getPosition
v <- tagvaluep v <- tagvaluep
@ -755,10 +755,10 @@ datetagp mdefdate = do
(do (do
setPosition startpos setPosition startpos
datep) -- <* eof) datep) -- <* eof)
(T.pack v) v
case ep case ep
of Left e -> throwError $ show e of Left e -> throwError $ show e
Right d -> return ("date"++n, d) Right d -> return ("date"<>n, d)
--- ** bracketed dates --- ** bracketed dates

View File

@ -651,8 +651,8 @@ transactionFromCsvRecord sourcepos rules record = t
tstatus = status, tstatus = status,
tcode = code, tcode = code,
tdescription = description, tdescription = description,
tcomment = comment, tcomment = T.pack comment,
tpreceding_comment_lines = precomment, tpreceding_comment_lines = T.pack precomment,
tpostings = tpostings =
[posting {paccount=account2, pamount=amount2, ptransaction=Just t} [posting {paccount=account2, pamount=amount2, ptransaction=Just t}
,posting {paccount=account1, pamount=amount1, ptransaction=Just t} ,posting {paccount=account1, pamount=amount1, ptransaction=Just t}

View File

@ -29,7 +29,7 @@ import cycles.
--- * module --- * module
{-# LANGUAGE CPP, RecordWildCards, NamedFieldPuns, NoMonoLocalBinds, ScopedTypeVariables, FlexibleContexts, TupleSections #-} {-# LANGUAGE CPP, RecordWildCards, NamedFieldPuns, NoMonoLocalBinds, ScopedTypeVariables, FlexibleContexts, TupleSections, OverloadedStrings #-}
module Hledger.Read.JournalReader ( module Hledger.Read.JournalReader (
@ -140,7 +140,7 @@ journalp = do
-- | A side-effecting parser; parses any kind of journal item -- | A side-effecting parser; parses any kind of journal item
-- and updates the parse state accordingly. -- and updates the parse state accordingly.
addJournalItemP :: ErroringJournalParser () addJournalItemP :: ErroringJournalParser ()
addJournalItemP = do addJournalItemP =
-- all journal line types can be distinguished by the first -- all journal line types can be distinguished by the first
-- character, can use choice without backtracking -- character, can use choice without backtracking
choice [ choice [
@ -433,7 +433,7 @@ transactionp = do
code <- codep <?> "transaction code" code <- codep <?> "transaction code"
description <- strip <$> descriptionp description <- strip <$> descriptionp
comment <- try followingcommentp <|> (newline >> return "") comment <- try followingcommentp <|> (newline >> return "")
let tags = commentTags $ T.pack comment let tags = commentTags comment
postings <- postingsp (Just date) postings <- postingsp (Just date)
n <- incrementTransactionCount n <- incrementTransactionCount
return $ txnTieKnot $ Transaction n sourcepos date edate status code description comment tags postings "" return $ txnTieKnot $ Transaction n sourcepos date edate status code description comment tags postings ""

View File

@ -21,6 +21,8 @@ inc.client1 .... .... ..
-} -}
{-# LANGUAGE OverloadedStrings #-}
module Hledger.Read.TimedotReader ( module Hledger.Read.TimedotReader (
-- * Reader -- * Reader
reader, reader,

View File

@ -77,7 +77,7 @@ textstrip = textlstrip . textrstrip
-- | Remove leading whitespace. -- | Remove leading whitespace.
textlstrip :: Text -> Text textlstrip :: Text -> Text
textlstrip = T.dropWhile (`elem` " \t") :: Text -> Text -- XXX isSpace ? textlstrip = T.dropWhile (`elem` (" \t" :: String)) :: Text -> Text -- XXX isSpace ?
-- | Remove trailing whitespace. -- | Remove trailing whitespace.
textrstrip = T.reverse . textlstrip . T.reverse textrstrip = T.reverse . textlstrip . T.reverse

View File

@ -95,8 +95,8 @@ postAddForm = do
| map fst acctparams == [1..num] && | map fst acctparams == [1..num] &&
map fst amtparams `elem` [[1..num], [1..num-1]] = [] map fst amtparams `elem` [[1..num], [1..num-1]] = []
| otherwise = ["the posting parameters are malformed"] | otherwise = ["the posting parameters are malformed"]
eaccts = map (runParser (accountnamep <* eof) () "" . T.pack . strip . T.unpack . snd) acctparams eaccts = map (runParser (accountnamep <* eof) () "" . textstrip . snd) acctparams
eamts = map (runParser (amountp <* eof) mempty "" . T.pack . strip . T.unpack . snd) amtparams eamts = map (runParser (amountp <* eof) mempty "" . textstrip . snd) amtparams
(accts, acctErrs) = (rights eaccts, map show $ lefts eaccts) (accts, acctErrs) = (rights eaccts, map show $ lefts eaccts)
(amts', amtErrs) = (rights eamts, map show $ lefts eamts) (amts', amtErrs) = (rights eamts, map show $ lefts eamts)
amts | length amts' == num = amts' amts | length amts' == num = amts'

View File

@ -201,7 +201,7 @@ descriptionAndCommentWizard EntryState{..} = do
maybeRestartTransaction $ maybeRestartTransaction $
line $ green $ printf "Description%s: " (showDefault def) line $ green $ printf "Description%s: " (showDefault def)
let (desc,comment) = (strip a, strip $ dropWhile (==';') b) where (a,b) = break (==';') s let (desc,comment) = (strip a, strip $ dropWhile (==';') b) where (a,b) = break (==';') s
return (desc,comment) return (desc, T.pack comment)
postingsWizard es@EntryState{..} = do postingsWizard es@EntryState{..} = do
mp <- postingWizard es mp <- postingWizard es
@ -278,11 +278,11 @@ amountAndCommentWizard EntryState{..} = do
where where
parseAmountAndComment = either (const Nothing) Just . runParser (amountandcommentp <* eof) nodefcommodityj "" . T.pack parseAmountAndComment = either (const Nothing) Just . runParser (amountandcommentp <* eof) nodefcommodityj "" . T.pack
nodefcommodityj = esJournal{jparsedefaultcommodity=Nothing} nodefcommodityj = esJournal{jparsedefaultcommodity=Nothing}
amountandcommentp :: Monad m => JournalParser m (Amount, String) amountandcommentp :: Monad m => JournalParser m (Amount, Text)
amountandcommentp = do amountandcommentp = do
a <- amountp a <- amountp
many spacenonewline many spacenonewline
c <- fromMaybe "" `fmap` optionMaybe (char ';' >> many anyChar) c <- T.pack <$> fromMaybe "" `fmap` optionMaybe (char ';' >> many anyChar)
-- eof -- eof
return (a,c) return (a,c)
balancingamt = negate $ sum $ map pamount realps where realps = filter isReal esPostings balancingamt = negate $ sum $ map pamount realps where realps = filter isReal esPostings

View File

@ -121,7 +121,7 @@ transactionToCSV n t =
date2 = maybe "" showDate (tdate2 t) date2 = maybe "" showDate (tdate2 t)
status = show $ tstatus t status = show $ tstatus t
code = tcode t code = tcode t
comment = chomp $ strip $ tcomment t comment = chomp $ strip $ T.unpack $ tcomment t
postingToCSV :: Posting -> CSV postingToCSV :: Posting -> CSV
postingToCSV p = postingToCSV p =
@ -137,7 +137,7 @@ postingToCSV p =
Mixed amounts = pamount p Mixed amounts = pamount p
status = show $ pstatus p status = show $ pstatus p
account = showAccountName Nothing (ptype p) (paccount p) account = showAccountName Nothing (ptype p) (paccount p)
comment = chomp $ strip $ pcomment p comment = chomp $ strip $ T.unpack $ pcomment p
-- --match -- --match

View File

@ -25,7 +25,7 @@ where
import Control.Exception as C import Control.Exception as C
import Data.List import Data.List
import Data.Maybe import Data.Maybe
-- import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import Data.Time (Day) import Data.Time (Day)
import Safe (readMay) import Safe (readMay)
@ -78,16 +78,16 @@ withJournalDo opts cmd = do
pivotByOpts :: CliOpts -> Journal -> Journal pivotByOpts :: CliOpts -> Journal -> Journal
pivotByOpts opts = pivotByOpts opts =
case maybestringopt "pivot" . rawopts_ $ opts of case maybestringopt "pivot" . rawopts_ $ opts of
Just tag -> pivot tag Just tag -> pivot $ T.pack tag
Nothing -> id Nothing -> id
-- | Apply the pivot transformation by given tag on a journal. -- | Apply the pivot transformation by given tag on a journal.
pivot :: String -> Journal -> Journal pivot :: Text -> Journal -> Journal
pivot tag j = j{jtxns = map pivotTrans . jtxns $ j} pivot tag j = j{jtxns = map pivotTrans . jtxns $ j}
where where
pivotTrans t = t{tpostings = map pivotPosting . tpostings $ t} pivotTrans t = t{tpostings = map pivotPosting . tpostings $ t}
pivotPosting p pivotPosting p
| Just (_ , value) <- tagTuple = p{paccount = joinAccountNames (T.pack tag) (T.pack value)} | Just (_ , value) <- tagTuple = p{paccount = joinAccountNames tag value}
| _ <- tagTuple = p | _ <- tagTuple = p
where tagTuple = find ((tag ==) . fst) . ptags $ p where tagTuple = find ((tag ==) . fst) . ptags $ p