Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package ghc-hledger-lib for openSUSE:Factory
checked in at 2025-03-17 22:18:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-hledger-lib (Old)
and /work/SRC/openSUSE:Factory/.ghc-hledger-lib.new.19136 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-hledger-lib"
Mon Mar 17 22:18:58 2025 rev:33 rq:1253814 version:1.42
Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-hledger-lib/ghc-hledger-lib.changes
2024-12-20 23:11:10.901860828 +0100
+++
/work/SRC/openSUSE:Factory/.ghc-hledger-lib.new.19136/ghc-hledger-lib.changes
2025-03-17 22:22:57.891946154 +0100
@@ -1,0 +2,9 @@
+Fri Mar 7 17:17:45 UTC 2025 - Peter Simons <[email protected]>
+
+- Update hledger-lib to version 1.42.
+ Upstream's change log file format is strange (too much unmodified
+ text at at the top). The automatic updater cannot extract the
+ relevant additions. You can find the file at:
+ http://hackage.haskell.org/package/hledger-lib-1.42/src/CHANGES.md
+
+-------------------------------------------------------------------
Old:
----
hledger-lib-1.41.tar.gz
New:
----
hledger-lib-1.42.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ghc-hledger-lib.spec ++++++
--- /var/tmp/diff_new_pack.asIOMW/_old 2025-03-17 22:22:58.363965907 +0100
+++ /var/tmp/diff_new_pack.asIOMW/_new 2025-03-17 22:22:58.363965907 +0100
@@ -1,7 +1,7 @@
#
# spec file for package ghc-hledger-lib
#
-# Copyright (c) 2024 SUSE LLC
+# Copyright (c) 2025 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -20,7 +20,7 @@
%global pkgver %{pkg_name}-%{version}
%bcond_with tests
Name: ghc-%{pkg_name}
-Version: 1.41
+Version: 1.42
Release: 0
Summary: A library providing the core functionality of hledger
License: GPL-3.0-or-later
@@ -69,6 +69,8 @@
BuildRequires: ghc-directory-prof
BuildRequires: ghc-doclayout-devel
BuildRequires: ghc-doclayout-prof
+BuildRequires: ghc-encoding-devel
+BuildRequires: ghc-encoding-prof
BuildRequires: ghc-extra-devel
BuildRequires: ghc-extra-prof
BuildRequires: ghc-file-embed-devel
++++++ hledger-lib-1.41.tar.gz -> hledger-lib-1.42.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/CHANGES.md
new/hledger-lib-1.42/CHANGES.md
--- old/hledger-lib-1.41/CHANGES.md 2024-12-10 00:51:49.000000000 +0100
+++ new/hledger-lib-1.42/CHANGES.md 2025-03-07 17:50:07.000000000 +0100
@@ -22,7 +22,24 @@
For user-visible changes, see the hledger package changelog.
-# 2024-12-09 1.41
+# 2025-03-07 1.42
+
+Improvements
+
+- readJournal, when not given a file name, now always assumes it is "-" rather
than "(string)".
+ [#2328]
+- Make test/unittest.hs more buildable; remove PackageImports that was causing
+ trouble for ghci.
+ (Thomas Miedema, [#2337])
+- Added: postingNegate
+- Renamed: negatePostingAmount -> postingNegateMainAmount
+- Refactor Hledger.Write.Html etc, reducing Lucid references.
+ Clarify the HTML lib situation a bit, and clean up some imports.
+ [#2244]
+- Added: dropRawOpt, cliOptsDropArgs
+- Hledger.Data.Amount: showAmountCost(B) now drops leading whitespace.
+
+# 1.41 2024-12-09
Breaking changes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Data/Amount.hs
new/hledger-lib-1.42/Hledger/Data/Amount.hs
--- old/hledger-lib-1.41/Hledger/Data/Amount.hs 2024-11-10 22:55:17.000000000
+0100
+++ new/hledger-lib-1.42/Hledger/Data/Amount.hs 2025-03-07 17:50:07.000000000
+0100
@@ -88,6 +88,7 @@
showAmount,
showAmountWith,
showAmountB,
+ showAmountCost,
showAmountCostB,
cshowAmount,
showAmountWithZeroCommodity,
@@ -672,18 +673,22 @@
space = if not (T.null comm) && ascommodityspaced style then WideBuilder
(TB.singleton ' ') 1 else mempty
cost = if displayCost then showAmountCostB afmt a else mempty
--- Show an amount's cost as @ UNITCOST or @@ TOTALCOST (builder version).
+-- Show an amount's cost as @ UNITCOST or @@ TOTALCOST, plus a leading space,
or "" if there's no cost.
+showAmountCost :: Amount -> String
+showAmountCost = wbUnpack . showAmountCostB defaultFmt
+
+-- showAmountCost, efficient builder version.
showAmountCostB :: AmountFormat -> Amount -> WideBuilder
showAmountCostB afmt amt = case acost amt of
- Nothing -> mempty
+ Nothing -> mempty
Just (UnitCost pa) -> WideBuilder (TB.fromString " @ ") 3 <> showAmountB
afmt pa
Just (TotalCost pa) -> WideBuilder (TB.fromString " @@ ") 4 <> showAmountB
afmt (sign pa)
where sign = if aquantity amt < 0 then negate else id
showAmountCostDebug :: Maybe AmountCost -> String
showAmountCostDebug Nothing = ""
-showAmountCostDebug (Just (UnitCost pa)) = " @ " ++ showAmountDebug pa
-showAmountCostDebug (Just (TotalCost pa)) = " @@ " ++ showAmountDebug pa
+showAmountCostDebug (Just (UnitCost pa)) = "@ " ++ showAmountDebug pa
+showAmountCostDebug (Just (TotalCost pa)) = "@@ " ++ showAmountDebug pa
-- | Colour version. For a negative amount, adds ANSI codes to change the
colour,
-- currently to hard-coded red.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Data/Balancing.hs
new/hledger-lib-1.42/Hledger/Data/Balancing.hs
--- old/hledger-lib-1.41/Hledger/Data/Balancing.hs 2024-11-10
22:55:17.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Data/Balancing.hs 2025-03-07
17:50:07.000000000 +0100
@@ -64,7 +64,7 @@
, infer_balancing_costs_ :: Bool -- ^ Are we permitted to infer missing
costs to balance transactions ?
-- Distinct from InputOpts{infer_costs_}.
, commodity_styles_ :: Maybe (M.Map CommoditySymbol AmountStyle) -- ^
commodity display styles
- } deriving (Show)
+ } deriving (Eq, Ord, Show)
defbalancingopts :: BalancingOpts
defbalancingopts = BalancingOpts
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Data/Dates.hs
new/hledger-lib-1.42/Hledger/Data/Dates.hs
--- old/hledger-lib-1.41/Hledger/Data/Dates.hs 2024-11-10 22:55:17.000000000
+0100
+++ new/hledger-lib-1.42/Hledger/Data/Dates.hs 2025-03-07 17:50:07.000000000
+0100
@@ -218,7 +218,7 @@
-- >>> t (Months 2) 2008 01 01 2008 04 01
-- [DateSpan 2008-01-01..2008-02-29,DateSpan 2008-03-01..2008-04-30]
-- >>> t (Weeks 1) 2008 01 01 2008 01 15
--- [DateSpan 2007-W01,DateSpan 2008-W02,DateSpan 2008-W03]
+-- [DateSpan 2008-W01,DateSpan 2008-W02,DateSpan 2008-W03]
-- >>> t (Weeks 2) 2008 01 01 2008 01 15
-- [DateSpan 2007-12-31..2008-01-13,DateSpan 2008-01-14..2008-01-27]
-- >>> t (MonthDay 2) 2008 01 01 2008 04 01
@@ -252,6 +252,7 @@
splitSpan _ (DaysOfWeek days@(n:_)) ds = spansFromBoundaries e bdrys
where
(s, e) = dateSpanSplitLimits (nthdayofweekcontaining n) nextday ds
+ -- can't show this when debugging, it'll hang:
bdrys = concatMap (flip map starts . addDays) [0,7..]
-- The first representative of each weekday
starts = map (\d -> addDays (toInteger $ d - n) $ nthdayofweekcontaining n
s) days
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Data/Journal.hs
new/hledger-lib-1.42/Hledger/Data/Journal.hs
--- old/hledger-lib-1.41/Hledger/Data/Journal.hs 2024-12-06
10:10:33.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Data/Journal.hs 2025-03-07
17:50:07.000000000 +0100
@@ -1164,17 +1164,27 @@
pivotAccount fieldortagname p =
T.intercalate ":" [pivotComponent x p | x <- T.splitOn ":" fieldortagname]
+-- | Get the value of the given field or tag for this posting.
+-- "comm" and "cur" are accepted as synonyms meaning the commodity symbol.
+-- Pivoting on an unknown field or tag, or on commodity when there are
multiple commodities, returns "".
+-- Pivoting on a tag when there are multiple values for that tag, returns the
first value.
pivotComponent :: Text -> Posting -> Text
pivotComponent fieldortagname p
- | fieldortagname == "acct" = paccount p
- | Just t <- ptransaction p, fieldortagname == "code" = tcode t
- | Just t <- ptransaction p, fieldortagname == "desc" = tdescription t
- | Just t <- ptransaction p, fieldortagname == "description" = tdescription t
-- backward compatible with 1.30 and older
- | Just t <- ptransaction p, fieldortagname == "payee" =
transactionPayee t
- | Just t <- ptransaction p, fieldortagname == "note" =
transactionNote t
- | Just t <- ptransaction p, fieldortagname == "status" = T.pack . show
. tstatus $ t
- | Just (_, value) <- postingFindTag fieldortagname p = value
- | otherwise = ""
+ | fieldortagname == "code", Just t <- ptransaction p = tcode t
+ | fieldortagname `elem` descnames, Just t <- ptransaction p = tdescription t
+ | fieldortagname == "payee", Just t <- ptransaction p =
transactionPayee t
+ | fieldortagname == "note", Just t <- ptransaction p =
transactionNote t
+ | fieldortagname == "status", Just t <- ptransaction p = T.pack . show
. tstatus $ t
+ | fieldortagname == "acct" = paccount p
+ | fieldortagname `elem` commnames = case map acommodity $ amounts $ pamount
p of [s] -> s; _ -> unknown
+ | fieldortagname == "amt" = case amounts $ pamount p of [a] ->
T.pack $ show $ aquantity a; _ -> unknown
+ | fieldortagname == "cost" = case amounts $ pamount p of
[a@Amount{acost=Just _}] -> T.pack $ lstrip $ showAmountCost a; _ -> unknown
+ | Just (_, tagvalue) <- postingFindTag fieldortagname p = tagvalue
+ | otherwise = unknown
+ where
+ descnames = ["desc", "description"] -- allow "description" for hledger
<=1.30 compat
+ commnames = ["cur","comm"] -- allow either; cur is the query
prefix, comm is more consistent
+ unknown = ""
postingFindTag :: TagName -> Posting -> Maybe (TagName, TagValue)
postingFindTag tagname p = find ((tagname==) . fst) $ postingAllTags p
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Data/Period.hs
new/hledger-lib-1.42/Hledger/Data/Period.hs
--- old/hledger-lib-1.41/Hledger/Data/Period.hs 2024-11-10 22:55:17.000000000
+0100
+++ new/hledger-lib-1.42/Hledger/Data/Period.hs 2025-03-07 17:50:07.000000000
+0100
@@ -26,6 +26,7 @@
,periodGrow
,periodShrink
,mondayBefore
+ ,thursdayOfWeekContaining
,yearMonthContainingWeekStarting
,quarterContainingMonth
,firstMonthOfQuarter
@@ -174,9 +175,14 @@
--
-- >>> showPeriod (WeekPeriod (fromGregorian 2016 7 25))
-- "2016-W30"
+-- >>> showPeriod (WeekPeriod (fromGregorian 2024 12 30))
+-- "2025-W01"
showPeriod :: Period -> Text
showPeriod (DayPeriod b) = T.pack $ formatTime defaultTimeLocale "%F" b
-- DATE
-showPeriod (WeekPeriod b) = T.pack $ formatTime defaultTimeLocale
"%0Y-W%V" b -- YYYY-Www
+showPeriod (WeekPeriod b) = T.pack $ y <> "-W" <> w
-- YYYY-Www
+ where
+ y = formatTime defaultTimeLocale "%0Y" $ thursdayOfWeekContaining b -- be
careful at year boundary
+ w = formatTime defaultTimeLocale "%V" b
showPeriod (MonthPeriod y m) = T.pack $ printf "%04d-%02d" y m
-- YYYY-MM
showPeriod (QuarterPeriod y q) = T.pack $ printf "%04dQ%d" y q
-- YYYYQN
showPeriod (YearPeriod y) = T.pack $ printf "%04d" y
-- YYYY
@@ -190,6 +196,8 @@
-- an abbreviated form.
-- >>> showPeriodAbbrev (WeekPeriod (fromGregorian 2016 7 25))
-- "W30"
+-- >>> showPeriodAbbrev (WeekPeriod (fromGregorian 2024 12 30))
+-- "W01"
showPeriodAbbrev :: Period -> Text
showPeriodAbbrev (MonthPeriod _ m)
-- Jan
| m > 0 && m <= length monthnames = T.pack . snd $ monthnames !! (m-1)
@@ -325,6 +333,8 @@
where
(_,_,wd) = toWeekDate d
+thursdayOfWeekContaining = (addDays 3).mondayBefore
+
yearMonthContainingWeekStarting weekstart = (y,m)
where
thu = addDays 3 weekstart
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Data/Posting.hs
new/hledger-lib-1.42/Hledger/Data/Posting.hs
--- old/hledger-lib-1.41/Hledger/Data/Posting.hs 2024-11-18
20:30:07.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Data/Posting.hs 2025-03-07
17:50:07.000000000 +0100
@@ -63,7 +63,8 @@
-- * arithmetic
sumPostings,
- negatePostingAmount,
+ postingNegate,
+ postingNegateMainAmount,
-- * rendering
showPosting,
showPostingLines,
@@ -381,9 +382,16 @@
sumPostings :: [Posting] -> MixedAmount
sumPostings = foldl' (\amt p -> maPlus amt $ pamount p) nullmixedamt
--- | Negate amount in a posting.
-negatePostingAmount :: Posting -> Posting
-negatePostingAmount = postingTransformAmount negate
+-- | Negate the posting's main amount and balance assertion amount if any.
+postingNegate :: Posting -> Posting
+postingNegate p@Posting{pamount=a, pbalanceassertion=mb} =
+ p{pamount=negate a, pbalanceassertion=fmap balanceAssertionNegate mb}
+ where
+ balanceAssertionNegate b@BalanceAssertion{baamount=ba} = b{baamount=negate
ba}
+
+-- | Negate the posting's main amount but not the balance assertion amount.
+postingNegateMainAmount :: Posting -> Posting
+postingNegateMainAmount p@Posting{pamount=a} = p{pamount=negate a}
-- | Strip all prices from a Posting.
postingStripCosts :: Posting -> Posting
@@ -532,7 +540,7 @@
postingPriceDirectivesFromCost p@Posting{pamount} =
mapMaybe (amountPriceDirectiveFromCost $ postingDate p) $ amountsRaw
pamount
--- | Apply a transform function to this posting's amount.
+-- | Apply a transform function to this posting's main amount (but not its
balance assertion amount).
postingTransformAmount :: (MixedAmount -> MixedAmount) -> Posting -> Posting
postingTransformAmount f p@Posting{pamount=a} = p{pamount=f a}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Data/RawOptions.hs
new/hledger-lib-1.42/Hledger/Data/RawOptions.hs
--- old/hledger-lib-1.41/Hledger/Data/RawOptions.hs 2024-11-10
22:55:17.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Data/RawOptions.hs 2025-03-07
17:50:07.000000000 +0100
@@ -11,6 +11,7 @@
RawOpts,
mkRawOpts,
overRawOpts,
+ dropRawOpt,
setopt,
setboolopt,
unsetboolopt,
@@ -53,6 +54,9 @@
overRawOpts :: ([(String,String)] -> [(String,String)]) -> RawOpts -> RawOpts
overRawOpts f = RawOpts . f . unRawOpts
+dropRawOpt :: String -> RawOpts -> RawOpts
+dropRawOpt a = overRawOpts $ filter (not.(==a).fst)
+
setopt :: String -> String -> RawOpts -> RawOpts
setopt name val = overRawOpts (++ [(name, val)])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Data/Transaction.hs
new/hledger-lib-1.42/Hledger/Data/Transaction.hs
--- old/hledger-lib-1.41/Hledger/Data/Transaction.hs 2024-11-18
20:30:07.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Data/Transaction.hs 2025-03-07
17:50:07.000000000 +0100
@@ -33,6 +33,7 @@
, transactionMapPostings
, transactionMapPostingAmounts
, transactionAmounts
+, transactionNegate
, partitionAndCheckConversionPostings
, transactionAddTags
, transactionAddHiddenAndMaybeVisibleTag
@@ -478,10 +479,14 @@
transactionMapPostingAmounts :: (MixedAmount -> MixedAmount) -> Transaction ->
Transaction
transactionMapPostingAmounts f = transactionMapPostings
(postingTransformAmount f)
--- | All posting amounts from this transactin, in order.
+-- | All posting amounts from this transaction, in order.
transactionAmounts :: Transaction -> [MixedAmount]
transactionAmounts = map pamount . tpostings
+-- | Flip the sign of this transaction's posting amounts (and balance
assertion amounts).
+transactionNegate :: Transaction -> Transaction
+transactionNegate = transactionMapPostings postingNegate
+
-- | The file path from which this transaction was parsed.
transactionFile :: Transaction -> FilePath
transactionFile Transaction{tsourcepos} = sourceName $ fst tsourcepos
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Data/Types.hs
new/hledger-lib-1.42/Hledger/Data/Types.hs
--- old/hledger-lib-1.41/Hledger/Data/Types.hs 2024-12-06 16:57:54.000000000
+0100
+++ new/hledger-lib-1.42/Hledger/Data/Types.hs 2025-03-07 17:50:07.000000000
+0100
@@ -651,7 +651,7 @@
-- any
included journal files. The main file is first,
--
followed by any included files in the order encountered.
--
TODO: FilePath is a sloppy type here, don't assume it's a
- --
real file; values like "", "-", "(string)" can be seen
+ --
real file; values like "" or "-" can be seen
,jlastreadtime :: POSIXTime -- ^
when this journal was last read from its file(s)
-- NOTE: after adding new fields, eg involving account names, consider
updating
-- the Anon instance in Hleger.Cli.Anon
@@ -666,7 +666,7 @@
= Csv -- comma-separated
| Tsv -- tab-separated
| Ssv -- semicolon-separated
- deriving Eq
+ deriving (Eq, Ord)
-- | The id of a data format understood by hledger, eg @journal@ or @csv@.
-- The --output-format option selects one of these for output.
@@ -677,7 +677,7 @@
| Timeclock
| Timedot
| Sep SepFormat
- deriving Eq
+ deriving (Eq, Ord)
instance Show SepFormat where
show Csv = "csv"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Read/Common.hs
new/hledger-lib-1.42/Hledger/Read/Common.hs
--- old/hledger-lib-1.41/Hledger/Read/Common.hs 2024-12-06 16:57:54.000000000
+0100
+++ new/hledger-lib-1.42/Hledger/Read/Common.hs 2025-03-07 17:50:07.000000000
+0100
@@ -34,6 +34,7 @@
HasInputOpts(..),
definputopts,
rawOptsToInputOpts,
+ handleReadFnToTextReadFn,
-- * parsing utilities
parseAndFinaliseJournal,
@@ -148,6 +149,7 @@
import Data.Time.LocalTime (LocalTime(..), TimeOfDay(..))
import Data.Word (Word8)
import System.FilePath (takeFileName)
+import System.IO (Handle)
import Text.Megaparsec
import Text.Megaparsec.Char (char, char', digitChar, newline, string)
import Text.Megaparsec.Char.Lexer (decimal)
@@ -179,9 +181,9 @@
,rExtensions :: [String]
-- The entry point for reading this format, accepting input options, file
- -- path for error messages and file contents, producing an
exception-raising IO
+ -- path for error messages and file contents via the handle, producing an
exception-raising IO
-- action that produces a journal or error message.
- ,rReadFn :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal
+ ,rReadFn :: InputOpts -> FilePath -> Handle -> ExceptT String IO Journal
-- The actual megaparsec parser called by the above, in case
-- another parser (includedirectivep) wants to use it directly.
@@ -231,6 +233,10 @@
,_ioDay = day
}
+handleReadFnToTextReadFn :: (InputOpts -> FilePath -> Text -> ExceptT String
IO Journal) -> InputOpts -> FilePath -> Handle -> ExceptT String IO Journal
+handleReadFnToTextReadFn p iopts fp =
+ p iopts fp <=< lift . readHandlePortably
+
-- | Get the date span from --forecast's PERIODEXPR argument, if any.
-- This will fail with a usage error if the period expression cannot be parsed,
-- or if it contains a report interval.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Read/CsvReader.hs
new/hledger-lib-1.42/Hledger/Read/CsvReader.hs
--- old/hledger-lib-1.41/Hledger/Read/CsvReader.hs 2024-11-10
22:55:17.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Read/CsvReader.hs 2025-03-07
17:50:07.000000000 +0100
@@ -28,7 +28,7 @@
import Prelude hiding (Applicative(..))
import Control.Monad.Except (ExceptT(..), liftEither)
import Control.Monad.IO.Class (MonadIO)
-import Data.Text (Text)
+import System.IO (Handle)
import Hledger.Data
import Hledger.Utils
@@ -54,10 +54,10 @@
-- This file path is normally the CSV(/SSV/TSV) data file, and a corresponding
rules file is inferred.
-- But it can also be the rules file, in which case the corresponding data
file is inferred.
-- This does not check balance assertions.
-parse :: SepFormat -> InputOpts -> FilePath -> Text -> ExceptT String IO
Journal
-parse sep iopts f t = do
+parse :: SepFormat -> InputOpts -> FilePath -> Handle -> ExceptT String IO
Journal
+parse sep iopts f h = do
let mrulesfile = mrules_file_ iopts
- readJournalFromCsv (Right <$> mrulesfile) f t (Just sep)
+ readJournalFromCsv (Right <$> mrulesfile) f h (Just sep)
-- apply any command line account aliases. Can fail with a bad replacement
pattern.
>>= liftEither . journalApplyAliases (aliasesFromOpts iopts)
-- journalFinalise assumes the journal's items are
@@ -65,7 +65,7 @@
-- But here they are already properly ordered. So we'd
-- better preemptively reverse them once more. XXX inefficient
. journalReverse
- >>= journalFinalise iopts{balancingopts_=(balancingopts_
iopts){ignore_assertions_=True}} f t
+ >>= journalFinalise iopts{balancingopts_=(balancingopts_
iopts){ignore_assertions_=True}} f ""
--- ** tests
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Read/InputOptions.hs
new/hledger-lib-1.42/Hledger/Read/InputOptions.hs
--- old/hledger-lib-1.41/Hledger/Read/InputOptions.hs 2024-12-06
16:57:54.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Read/InputOptions.hs 2025-03-07
17:50:07.000000000 +0100
@@ -44,7 +44,7 @@
,strict_ :: Bool -- ^ do extra correctness
checks ?
,_defer :: Bool -- ^ internal flag: postpone
checks, because we are processing multiple files ?
,_ioDay :: Day -- ^ today's date, for use
with forecast transactions XXX this duplicates _rsDay, and should eventually
be removed when it's not needed anymore.
- } deriving (Show)
+ } deriving (Eq, Ord, Show)
definputopts :: InputOpts
definputopts = InputOpts
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Read/JournalReader.hs
new/hledger-lib-1.42/Hledger/Read/JournalReader.hs
--- old/hledger-lib-1.41/Hledger/Read/JournalReader.hs 2024-11-10
22:55:17.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Read/JournalReader.hs 2025-03-07
17:50:07.000000000 +0100
@@ -194,7 +194,7 @@
reader = Reader
{rFormat = Journal'
,rExtensions = ["journal", "j", "hledger", "ledger"]
- ,rReadFn = parse
+ ,rReadFn = handleReadFnToTextReadFn parse
,rParser = journalp -- no need to add command line aliases like journalp'
-- when called as a subparser I think
}
@@ -282,10 +282,11 @@
]
) <?> "directive"
--- | Parse an include directive. include's argument is an optionally
--- file-format-prefixed file path or glob pattern. In the latter case,
--- the prefix is applied to each matched path. Examples:
--- foo.j, foo/bar.j, timedot:foo/2020*.md
+-- | Parse an include directive, and the file(s) it refers to, possibly
recursively.
+-- include's argument is a file path or glob pattern, optionally with a file
type prefix.
+-- ~ at the start is expanded to the user's home directory.
+-- Relative paths are relative to the current file.
+-- Examples: foo.j, ../foo/bar.j, timedot:/foo/2020*, *.journal
includedirectivep :: MonadIO m => ErroringJournalParser m ()
includedirectivep = do
string "include"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Read/RulesReader.hs
new/hledger-lib-1.42/Hledger/Read/RulesReader.hs
--- old/hledger-lib-1.41/Hledger/Read/RulesReader.hs 2024-12-06
10:10:33.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Read/RulesReader.hs 2025-03-07
17:50:07.000000000 +0100
@@ -52,6 +52,7 @@
import Control.Monad.Trans.Class (lift)
import Data.Char (toLower, isDigit, isSpace, isAlphaNum, ord)
import Data.Bifunctor (first)
+import Data.Encoding (encodingFromStringExplicit)
import Data.Functor ((<&>))
import Data.List (elemIndex, mapAccumL, nub, sortOn)
#if !MIN_VERSION_base(4,20,0)
@@ -69,6 +70,7 @@
defaultTimeLocale, getCurrentTimeZone, localDay, parseTimeM, utcToLocalTime,
localTimeToUTC, zonedTimeToUTC)
import Safe (atMay, headMay, lastMay, readMay)
import System.FilePath ((</>), takeDirectory, takeExtension, stripExtension,
takeFileName)
+import System.IO (Handle, hClose)
import qualified Data.Csv as Cassava
import qualified Data.Csv.Parser.Megaparsec as CassavaMegaparsec
import qualified Data.ByteString as B
@@ -116,10 +118,11 @@
-- file's directory. When a glob pattern matches multiple files, the
alphabetically
-- last is used. (Eg in case of multiple numbered downloads, the
highest-numbered
-- will be used.)
--- The provided text, or a --rules option, are ignored by this reader.
+-- The provided handle, or a --rules option, are ignored by this reader.
-- Balance assertions are not checked.
-parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal
-parse iopts f _ = do
+parse :: InputOpts -> FilePath -> Handle -> ExceptT String IO Journal
+parse iopts f h = do
+ lift $ hClose h -- We don't need it
rules <- readRulesFile $ dbg4 "reading rules file" f
-- XXX higher-than usual debug level for file reading to bypass excessive
noise from elsewhere, normally 6 or 7
mdatafile <- liftIO $ do
@@ -139,8 +142,8 @@
if not (dat=="-" || exists)
then return nulljournal -- data file inferred from rules file name
was not found
else do
- t <- liftIO $ readFileOrStdinPortably dat
- readJournalFromCsv (Just $ Left rules) dat t Nothing
+ dath <- liftIO $ openFileOrStdin dat
+ readJournalFromCsv (Just $ Left rules) dat dath Nothing
-- apply any command line account aliases. Can fail with a bad
replacement pattern.
>>= liftEither . journalApplyAliases (aliasesFromOpts iopts)
-- journalFinalise assumes the journal's items are
@@ -500,6 +503,7 @@
directives :: [Text]
directives =
["source"
+ ,"encoding"
,"date-format"
,"decimal-mark"
,"separator"
@@ -633,19 +637,19 @@
])
when (null body) $
customFailure $ parseErrorAt start $ "start of conditional table found,
but no assignment rules afterward"
- return $ flip map body $ \(m,vs) ->
- CB{cbMatchers=[m], cbAssignments=zip fields vs}
+ return $ flip map body $ \(ms,vs) ->
+ CB{cbMatchers=ms, cbAssignments=zip fields vs}
<?> "conditional table"
where
- bodylinep :: Char -> [Text] -> CsvRulesParser (Matcher,[FieldTemplate])
+ bodylinep :: Char -> [Text] -> CsvRulesParser ([Matcher],[FieldTemplate])
bodylinep sep fields = do
off <- getOffset
- m <- matcherp' $ void $ char sep
+ ms <- matcherp' (lookAhead . void . char $ sep) `manyTill` char sep
vs <- T.split (==sep) . T.pack <$> lift restofline
if (length vs /= length fields)
then customFailure $ parseErrorAt off $ ((printf "line of conditional
table should have %d values, but this one has only %d" (length fields) (length
vs)) :: String)
- else return (m,vs)
-
+ else return (ms,vs)
+
-- A single matcher, on one line.
-- This tries to parse first as a field matcher, then if that fails, as a
whole-record matcher;
@@ -696,7 +700,7 @@
matcherprefixp = do
lift $ dbgparse 8 "trying matcherprefixp"
(do
- char '&' >> lift skipNonNewlineSpaces
+ char '&' >> optional (char '&') >> lift skipNonNewlineSpaces
fromMaybe And <$> optional (char '!' >> lift skipNonNewlineSpaces >>
return AndNot))
<|> (char '!' >> lift skipNonNewlineSpaces >> return Not)
<|> return Or
@@ -714,10 +718,12 @@
lift $ dbgparse 8 "trying regexp"
-- notFollowedBy matchoperatorp
c <- lift nonspace
- cs <- anySingle `manyTill` end
+ cs <- anySingle `manyTill` (double_ampersand <|> end)
case toRegexCI . T.strip . T.pack $ c:cs of
Left x -> Fail.fail $ "CSV parser: " ++ x
Right x -> return x
+ where
+ double_ampersand = lookAhead . void $ char '&' >> char '&'
-- -- A match operator, indicating the type of match to perform.
-- -- Currently just ~ meaning case insensitive infix regex match.
@@ -908,9 +914,9 @@
--
-- 4. Return the transactions as a Journal.
--
-readJournalFromCsv :: Maybe (Either CsvRules FilePath) -> FilePath -> Text ->
Maybe SepFormat -> ExceptT String IO Journal
-readJournalFromCsv Nothing "-" _ _ = throwError "please use --rules when
reading CSV from stdin"
-readJournalFromCsv merulesfile csvfile csvtext sep = do
+readJournalFromCsv :: Maybe (Either CsvRules FilePath) -> FilePath -> Handle
-> Maybe SepFormat -> ExceptT String IO Journal
+readJournalFromCsv Nothing "-" h _ = lift (hClose h) *> throwError "please use
--rules when reading CSV from stdin"
+readJournalFromCsv merulesfile csvfile csvhandle sep = do
-- for now, correctness is the priority here, efficiency not so much
rules <- case merulesfile of
@@ -919,6 +925,16 @@
Nothing -> readRulesFile $ rulesFileFor csvfile
dbg6IO "csv rules" rules
+ -- read csv while being aware of the encoding
+ mencoding <- do
+ -- XXX higher-than usual debug level for file reading to bypass
excessive noise from elsewhere, normally 6 or 7
+ case T.unpack <$> getDirective "encoding" rules of
+ Just rawenc -> case encodingFromStringExplicit $ dbg4 "raw-encoding"
rawenc of
+ Just enc -> return . Just $ dbg4 "encoding" enc
+ Nothing -> throwError $ "Invalid encoding: " <> rawenc
+ Nothing -> return Nothing
+ csvtext <- lift $ readHandlePortably' mencoding csvhandle
+
-- convert the csv data to lines and remove all empty/blank lines
let csvlines1 = dbg9 "csvlines1" $ filter (not . T.null . T.strip) $ dbg9
"csvlines0" $ T.lines csvtext
@@ -1545,7 +1561,7 @@
,testCase "quoted name" $ parseWithState' defrules csvfieldreferencep
"%\"csv date\"" @?= (Right "%\"csv date\"")
]
- ,testGroup "matcherp" [
+ ,testGroup "recordmatcherp" [
testCase "recordmatcherp" $
parseWithState' defrules matcherp "A A\n" @?= (Right $ RecordMatcher Or
$ toRegexCI' "A A")
@@ -1553,18 +1569,47 @@
,testCase "recordmatcherp.starts-with-&" $
parseWithState' defrules matcherp "& A A\n" @?= (Right $ RecordMatcher
And $ toRegexCI' "A A")
- ,testCase "fieldmatcherp.starts-with-%" $
+ ,testCase "recordmatcherp.starts-with-&&" $
+ parseWithState' defrules matcherp "&& A A\n" @?= (Right $ RecordMatcher
And $ toRegexCI' "A A")
+
+ ,testCase "recordmatcherp.starts-with-&&-!" $
+ parseWithState' defrules matcherp "&& ! A A\n" @?= (Right $
RecordMatcher AndNot $ toRegexCI' "A A")
+
+ ,testCase "recordmatcherp.does-not-start-with-%" $
parseWithState' defrules matcherp "description A A\n" @?= (Right $
RecordMatcher Or $ toRegexCI' "description A A")
+ ]
- ,testCase "fieldmatcherp" $
+ ,testGroup "fieldmatcherp" [
+ testCase "fieldmatcherp" $
parseWithState' defrules matcherp "%description A A\n" @?= (Right $
FieldMatcher Or "%description" $ toRegexCI' "A A")
,testCase "fieldmatcherp.starts-with-&" $
parseWithState' defrules matcherp "& %description A A\n" @?= (Right $
FieldMatcher And "%description" $ toRegexCI' "A A")
+ ,testCase "fieldmatcherp.starts-with-&&" $
+ parseWithState' defrules matcherp "&& %description A A\n" @?= (Right $
FieldMatcher And "%description" $ toRegexCI' "A A")
+
+ ,testCase "fieldmatcherp.starts-with-&&-!" $
+ parseWithState' defrules matcherp "&& ! %description A A\n" @?= (Right $
FieldMatcher AndNot "%description" $ toRegexCI' "A A")
+
-- ,testCase "fieldmatcherp with operator" $
-- parseWithState' defrules matcherp "%description ~ A A\n" @?= (Right $
FieldMatcher "%description" "A A")
+ ]
+
+ ,testGroup "regexp" [
+ testCase "regexp.ends-before-&&" $
+ parseWithState' defrules (regexp empty) "A A && xxx" @?= (Right $
toRegexCI' "A A")
+ ]
+ , let matchers = [RecordMatcher Or (toRegexCI' "A"), RecordMatcher And
(toRegexCI' "B")]
+ assignments = [("account2", "foo"), ("comment2", "bar")]
+ block = CB matchers assignments
+ in
+ testGroup "Combine multiple matchers on the same line" [
+ testCase "conditionalblockp" $
+ parseWithState' defrules conditionalblockp "if A && B\n account2 foo\n
comment2 bar" @?= (Right block)
+ ,testCase "conditionaltablep" $
+ parseWithState' defrules conditionaltablep "if,account2,comment2\nA &&
B,foo,bar" @?= (Right [block])
]
,testGroup "hledgerField" [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Read/TimeclockReader.hs
new/hledger-lib-1.42/Hledger/Read/TimeclockReader.hs
--- old/hledger-lib-1.41/Hledger/Read/TimeclockReader.hs 2024-11-10
22:55:17.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Read/TimeclockReader.hs 2025-03-07
17:50:07.000000000 +0100
@@ -79,7 +79,7 @@
reader = Reader
{rFormat = Timeclock
,rExtensions = ["timeclock"]
- ,rReadFn = parse
+ ,rReadFn = handleReadFnToTextReadFn parse
,rParser = timeclockfilep
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Read/TimedotReader.hs
new/hledger-lib-1.42/Hledger/Read/TimedotReader.hs
--- old/hledger-lib-1.41/Hledger/Read/TimedotReader.hs 2024-11-10
22:55:17.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Read/TimedotReader.hs 2025-03-07
17:50:07.000000000 +0100
@@ -68,7 +68,7 @@
reader = Reader
{rFormat = Timedot
,rExtensions = ["timedot"]
- ,rReadFn = parse
+ ,rReadFn = handleReadFnToTextReadFn parse
,rParser = timedotp
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Read.hs
new/hledger-lib-1.42/Hledger/Read.hs
--- old/hledger-lib-1.41/Hledger/Read.hs 2024-12-06 10:10:33.000000000
+0100
+++ new/hledger-lib-1.42/Hledger/Read.hs 2025-03-07 17:50:07.000000000
+0100
@@ -102,6 +102,7 @@
-- * Easy journal parsing
readJournal',
+ readJournal'',
readJournalFile',
readJournalFiles',
orDieTrying,
@@ -125,7 +126,7 @@
--- ** imports
import qualified Control.Exception as C
-import Control.Monad (unless, when, forM)
+import Control.Monad (unless, when, forM, (<=<))
import "mtl" Control.Monad.Except (ExceptT(..), runExceptT, liftEither)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Default (def)
@@ -145,7 +146,7 @@
import System.Exit (exitFailure)
import System.FilePath ((<.>), (</>), splitDirectories, splitFileName,
takeFileName)
import System.Info (os)
-import System.IO (hPutStr, stderr)
+import System.IO (Handle, hPutStr, stderr)
import Hledger.Data.Dates (getCurrentDay, parsedateM, showDate)
import Hledger.Data.Types
@@ -205,7 +206,7 @@
-- | @readJournal iopts mfile txt@
--
--- Read a Journal from some text, with strict checks if enabled,
+-- Read a Journal from some handle, with strict checks if enabled,
-- or return an error message.
--
-- The reader (data format) is chosen based on, in this order:
@@ -217,13 +218,17 @@
-- - a file extension in @mfile@
--
-- If none of these is available, or if the reader name is unrecognised,
--- we use the journal reader (for predictability).
+-- the journal reader is used.
--
-readJournal :: InputOpts -> Maybe FilePath -> Text -> ExceptT String IO Journal
-readJournal iopts@InputOpts{strict_, _defer} mpath txt = do
+-- If a file path is not provided, "-" is assumed (and may appear in error
messages,
+-- `files` output etc, where it will be a slight lie: it will mean "not from a
file",
+-- not necessarily "from standard input".
+--
+readJournal :: InputOpts -> Maybe FilePath -> Handle -> ExceptT String IO
Journal
+readJournal iopts@InputOpts{strict_, _defer} mpath hdl = do
let r :: Reader IO = fromMaybe JournalReader.reader $ findReader (mformat_
iopts) mpath
dbg6IO "readJournal: trying reader" (rFormat r)
- j <- rReadFn r iopts (fromMaybe "(string)" mpath) txt
+ j <- rReadFn r iopts (fromMaybe "-" mpath) hdl
when (strict_ && not _defer) $ liftEither $ journalStrictChecks j
return j
@@ -264,11 +269,11 @@
(mfmt, f) = splitReaderPrefix prefixedfile
iopts' = iopts{mformat_=asum [mfmt, mformat_ iopts]}
liftIO $ requireJournalFileExists f
- t <-
+ h <-
traceOrLogAt 6 ("readJournalFile: "++takeFileName f) $
- liftIO $ readFileOrStdinPortably f
+ liftIO $ openFileOrStdin f
-- <- T.readFile f -- or without line ending translation, for testing
- j <- readJournal iopts' (Just f) t
+ j <- readJournal iopts' (Just f) h
if new_ iopts
then do
ds <- liftIO $ previousLatestDates f
@@ -313,9 +318,14 @@
-- | An easy version of 'readJournal' which assumes default options, and fails
-- in the IO monad.
-readJournal' :: Text -> IO Journal
+readJournal' :: Handle -> IO Journal
readJournal' = orDieTrying . readJournal definputopts Nothing
+-- | An even easier version of 'readJournal' which additionally to
'readJournal''
+-- also takes a 'Text' instead of a 'Handle'.
+readJournal'' :: Text -> IO Journal
+readJournal'' = readJournal' <=< inputToHandle
+
-- | An easy version of 'readJournalFile' which assumes default options, and
fails
-- in the IO monad.
readJournalFile' :: PrefixedFilePath -> IO Journal
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/hledger-lib-1.41/Hledger/Reports/AccountTransactionsReport.hs
new/hledger-lib-1.42/Hledger/Reports/AccountTransactionsReport.hs
--- old/hledger-lib-1.41/Hledger/Reports/AccountTransactionsReport.hs
2024-11-10 22:55:17.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Reports/AccountTransactionsReport.hs
2025-03-07 17:50:07.000000000 +0100
@@ -162,7 +162,7 @@
. traceAtWith 5 (("ts4:\n"++).pshowTransactions.map snd)
. sortBy (comparing (Down . fst) <> comparing (Down . tindex . snd))
. map (\t -> (transactionRegisterDate wd reportq thisacctq t, t))
- . map (if invert_ ropts then (\t -> t{tpostings = map
negatePostingAmount $ tpostings t}) else id)
+ . map (if invert_ ropts then (\t -> t{tpostings = map
postingNegateMainAmount $ tpostings t}) else id)
$ jtxns acctJournal
pshowTransactions :: [Transaction] -> String
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Reports/EntriesReport.hs
new/hledger-lib-1.42/Hledger/Reports/EntriesReport.hs
--- old/hledger-lib-1.41/Hledger/Reports/EntriesReport.hs 2024-12-10
01:25:47.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Reports/EntriesReport.hs 2025-03-07
17:50:07.000000000 +0100
@@ -35,7 +35,9 @@
-- | Select transactions for an entries report.
entriesReport :: ReportSpec -> Journal -> EntriesReport
entriesReport rspec@ReportSpec{_rsReportOpts=ropts} =
- sortBy (comparing $ transactionDateFn ropts) . jtxns
+ sortBy (comparing $ transactionDateFn ropts)
+ . map (if invert_ ropts then transactionNegate else id)
+ . jtxns
. journalApplyValuationFromOpts (setDefaultConversionOp NoConversionOp
rspec)
. filterJournalTransactions (filterQuery (not.queryIsDepth) $ _rsQuery
rspec)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Reports/PostingsReport.hs
new/hledger-lib-1.42/Hledger/Reports/PostingsReport.hs
--- old/hledger-lib-1.41/Hledger/Reports/PostingsReport.hs 2024-12-06
10:10:33.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Reports/PostingsReport.hs 2025-03-07
17:50:07.000000000 +0100
@@ -158,7 +158,7 @@
beforestartq = dbg3 "beforestartq" $ dateqtype $ DateSpan Nothing (Exact
<$> spanStart reportspan)
beforeandduringps =
sortOn (postingDateOrDate2 (whichDate ropts)) -- sort
postings by date or date2
- . (if invert_ ropts then map negatePostingAmount else id) -- with
--invert, invert amounts
+ . (if invert_ ropts then map postingNegateMainAmount else id) -- with
--invert, invert amounts
. journalPostings
-- With most calls we will not require transaction prices past this
point, and can get a big
-- speed improvement by stripping them early. In some cases, such as in
hledger-ui, we still
@@ -301,7 +301,7 @@
,"postings report with cleared option" ~:
do
let opts = defreportopts{cleared_=True}
- j <- readJournal' sample_journal_str
+ j <- readJournal'' sample_journal_str
(postingsReportAsText opts $ postingsReport opts (queryFromOpts date1
opts) j) `is` unlines
["2008/06/03 eat & shop expenses:food $1
$1"
," expenses:supplies $1
$2"
@@ -313,7 +313,7 @@
,"postings report with uncleared option" ~:
do
let opts = defreportopts{uncleared_=True}
- j <- readJournal' sample_journal_str
+ j <- readJournal'' sample_journal_str
(postingsReportAsText opts $ postingsReport opts (queryFromOpts date1
opts) j) `is` unlines
["2008/01/01 income assets:bank:checking $1
$1"
," income:salary $-1
0"
@@ -325,7 +325,7 @@
,"postings report sorts by date" ~:
do
- j <- readJournal' $ unlines
+ j <- readJournal'' $ unlines
["2008/02/02 a"
," b 1"
," c"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Reports/ReportOptions.hs
new/hledger-lib-1.42/Hledger/Reports/ReportOptions.hs
--- old/hledger-lib-1.41/Hledger/Reports/ReportOptions.hs 2024-12-06
10:10:33.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Reports/ReportOptions.hs 2025-03-07
17:50:07.000000000 +0100
@@ -88,7 +88,6 @@
import Hledger.Utils
import Data.Function ((&))
-
-- | What to calculate for each cell in a balance report.
-- "Balance report types -> Calculation type" in the hledger manual.
data BalanceCalculation =
@@ -890,10 +889,13 @@
-- Left "This regular expression is invalid or unsupported, please correct
it:\n(assets"
-- >>> _rsQuery $ set querystring ["assets"] defreportspec
-- Acct (RegexpCI "assets")
--- >>> _rsQuery $ set querystring ["(assets"] defreportspec
--- *** Exception: Error: Updating ReportSpec failed: try using overEither
instead of over or setEither instead of set
-- >>> _rsQuery $ set period (MonthPeriod 2021 08) defreportspec
-- Date DateSpan 2021-08
+--
+-- XXX testing error output isn't working since adding color to it:
+-- > import System.Environment
+-- > setEnv "NO_COLOR" "1" >> return (_rsQuery $ set querystring ["(assets"]
defreportspec)
+-- *** Exception: Error: Updating ReportSpec failed: try using overEither
instead of over or setEither instead of set
class HasReportOptsNoUpdate a => HasReportOpts a where
reportOpts :: ReportableLens' a ReportOpts
reportOpts = reportOptsNoUpdate
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Utils/IO.hs
new/hledger-lib-1.42/Hledger/Utils/IO.hs
--- old/hledger-lib-1.41/Hledger/Utils/IO.hs 2024-12-06 10:10:33.000000000
+0100
+++ new/hledger-lib-1.42/Hledger/Utils/IO.hs 2025-03-07 17:50:07.000000000
+0100
@@ -4,7 +4,9 @@
terminals, pager output, ANSI colour/styles, etc.
-}
+{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -31,11 +33,15 @@
expandPath,
expandGlob,
sortByModTime,
+ openFileOrStdin,
readFileOrStdinPortably,
+ readFileOrStdinPortably',
readFileStrictly,
readFilePortably,
readHandlePortably,
+ readHandlePortably',
-- hereFileRelative,
+ inputToHandle,
-- * Command line parsing
progArgs,
@@ -83,6 +89,7 @@
brightCyan',
brightWhite',
rgb',
+ sgrresetall,
-- ** Generic
@@ -110,6 +117,7 @@
import Data.Colour.RGBSpace (RGB(RGB))
import Data.Colour.RGBSpace.HSL (lightness)
import Data.Colour.SRGB (sRGB)
+import Data.Encoding (DynEncoding)
import Data.FileEmbed (makeRelativeToProject, embedStringFile)
import Data.Functor ((<&>))
import Data.List hiding (uncons)
@@ -135,8 +143,9 @@
import "Glob" System.FilePath.Glob (glob)
import System.Info (os)
import System.IO (Handle, IOMode (..), hGetEncoding, hSetEncoding,
hSetNewlineMode, openFile, stdin, stdout, stderr, universalNewlineMode,
utf8_bom, hIsTerminalDevice, hPutStr, hClose)
+import qualified System.IO.Encoding as Enc
import System.IO.Unsafe (unsafePerformIO)
-import System.Process (CreateProcess(..), StdStream(CreatePipe),
shell, waitForProcess, withCreateProcess)
+import System.Process (CreateProcess(..), StdStream(CreatePipe),
createPipe, shell, waitForProcess, withCreateProcess)
import Text.Pretty.Simple (CheckColorTty(..), OutputOptions(..),
defaultOutputOptionsDarkBg, defaultOutputOptionsNoColor, pShowOpt, pPrintOpt)
import Hledger.Utils.Text (WideBuilder(WideBuilder))
@@ -186,22 +195,39 @@
-- Errors
--- | Simpler alias for errorWithoutStackTrace
+-- | Call errorWithoutStackTrace, prepending a "Error:" label.
+-- Also do some ANSI styling of the first line when allowed (using unsafe IO).
error' :: String -> a
-error' = errorWithoutStackTrace . ("Error: " <>)
+error' =
+ if useColorOnStderrUnsafe
+ then -- color the program name as well
+ unsafePerformIO $ do
+ putStr fmt
+ return $ errorWithoutStackTrace . modifyFirstLine ((<>sgrresetall) .
(label<>))
+ else
+ errorWithoutStackTrace . modifyFirstLine (label<>)
+ where
+ label = "Error: "
+ fmt = sgrbrightred <> sgrbold
--- | A version of errorWithoutStackTrace that adds a usage hint.
+-- | Like error', but add a hint about using -h.
usageError :: String -> a
usageError = error' . (++ " (use -h to see usage)")
--- | Show a warning message on stderr before returning the given value.
--- Use this when you want to show the user a message on stderr, without
stopping the program.
--- Currently we do this very sparingly in hledger; we prefer to either quietly
work,
--- or loudly raise an error. Variable output can make scripting harder.
+-- | Show a message, with "Warning:" label, on stderr before returning the
given value.
+-- Also do some ANSI styling of the first line when we detect that's supported
(using unsafe IO).
+-- Currently we use this very sparingly in hledger; we prefer to either
quietly work,
+-- or loudly raise an error. (Varying output can make scripting harder.)
warn :: String -> a -> a
-warn msg = trace ("Warning: " <> msg)
-
+warn msg = trace (modifyFirstLine f (label <> msg))
+ where
+ label = "Warning: "
+ f = if useColorOnStderrUnsafe then ((<>sgrresetall).(fmt<>)) else id
+ where
+ fmt = sgrbrightyellow <> sgrbold
+-- Transform a string's first line.
+modifyFirstLine f s = unlines $ map f l <> ls where (l,ls) = splitAt 1 $ lines
s -- total
-- Time
@@ -262,19 +288,39 @@
-- | Like readFilePortably, but read from standard input if the path is "-".
readFileOrStdinPortably :: String -> IO T.Text
-readFileOrStdinPortably f = openFileOrStdin f ReadMode >>= readHandlePortably
- where
- openFileOrStdin :: String -> IOMode -> IO Handle
- openFileOrStdin "-" _ = return stdin
- openFileOrStdin f' m = openFile f' m
+readFileOrStdinPortably = readFileOrStdinPortably' Nothing
+
+-- | Like readFileOrStdinPortably, but take an optional converter.
+readFileOrStdinPortably' :: Maybe DynEncoding -> String -> IO T.Text
+readFileOrStdinPortably' c f = openFileOrStdin f >>= readHandlePortably' c
+
+openFileOrStdin :: String -> IO Handle
+openFileOrStdin "-" = return stdin
+openFileOrStdin f' = openFile f' ReadMode
readHandlePortably :: Handle -> IO T.Text
-readHandlePortably h = do
+readHandlePortably = readHandlePortably' Nothing
+
+readHandlePortably' :: Maybe DynEncoding -> Handle -> IO T.Text
+readHandlePortably' Nothing h = do
hSetNewlineMode h universalNewlineMode
menc <- hGetEncoding h
when (fmap show menc == Just "UTF-8") $ -- XXX no Eq instance, rely on Show
hSetEncoding h utf8_bom
T.hGetContents h
+readHandlePortably' (Just e) h =
+ -- We need to manually apply the newline mode
+ -- Since we already have a Text
+ T.replace "\r\n" "\n" . T.pack <$> let ?enc = e in Enc.hGetContents h
+
+inputToHandle :: T.Text -> IO Handle
+inputToHandle t = do
+ (r, w) <- createPipe
+ hSetEncoding r utf8_bom
+ hSetEncoding w utf8_bom
+ T.hPutStr w t
+ hClose w
+ return r
-- | Like embedFile, but takes a path relative to the package directory.
embedFileRelative :: FilePath -> Q Exp
@@ -367,8 +413,29 @@
-- Terminal size
+-- [NOTE: Alternative methods of getting the terminal size]
+-- terminal-size uses the TIOCGWINSZ ioctl to get the window size on Unix
+-- systems, which may not be completely portable according to people in
+-- #linux@liberachat.
+--
+-- If this turns out to be the case, supplementary coverage can be given by
+-- using the terminfo package.
+--
+-- Conversely, terminfo on its own is not a full solution, firstly because it
+-- only works on Unix (not Windows), and secondly since in some scenarios (eg
+-- stripped-down build systems) the terminfo database may be limited and lack
+-- the correct entries. (A hack that sometimes works but which isn't robust
+-- enough to be relied upon is to set TERM=dumb -- while this advice does
appear
+-- in some places, it's not guaranteed to work)
+--
+-- In any case, $LINES/$COLUMNS should not be used as a source for the terminal
+-- size - they are not available or do not update reliably in all shells.
+--
+-- See #2332 for details
+
-- | An alternative to ansi-terminal's getTerminalSize, based on
-- the more robust-looking terminal-size package.
+--
-- Tries to get stdout's terminal's current height and width.
getTerminalHeightWidth :: IO (Maybe (Int,Int))
getTerminalHeightWidth = fmap (fmap unwindow) size
@@ -401,7 +468,6 @@
-- --shift=8
-- --squeeze-blank-lines
-- --use-backslash
--- --use-color
--
-- You can choose different options by setting the HLEDGER_LESS variable;
-- if set, its value will be used instead of LESS.
@@ -424,7 +490,7 @@
,"--shift=8"
,"--squeeze-blank-lines"
,"--use-backslash"
- ,"--use-color"
+ -- ,"--use-color" #2335 rejected by older less versions (eg 551)
]
mhledgerless <- lookupEnv "HLEDGER_LESS"
mless <- lookupEnv "LESS"
@@ -554,6 +620,8 @@
sgrfaint = setSGRCode [SetConsoleIntensity FaintIntensity]
sgrnormal = setSGRCode [SetConsoleIntensity NormalIntensity]
sgrresetfg = setSGRCode [SetDefaultColor Foreground]
+sgrresetbg = setSGRCode [SetDefaultColor Background]
+sgrresetall = sgrresetfg <> sgrresetbg <> sgrnormal
sgrblack = setSGRCode [SetColor Foreground Dull Black]
sgrred = setSGRCode [SetColor Foreground Dull Red]
sgrgreen = setSGRCode [SetColor Foreground Dull Green]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Write/Html/Blaze.hs
new/hledger-lib-1.42/Hledger/Write/Html/Blaze.hs
--- old/hledger-lib-1.41/Hledger/Write/Html/Blaze.hs 2024-11-10
22:55:17.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Write/Html/Blaze.hs 2025-03-07
17:50:07.000000000 +0100
@@ -1,18 +1,17 @@
{-# LANGUAGE OverloadedStrings #-}
{- |
-Export spreadsheet table data as HTML table.
-
-This is derived from
<https://hackage.haskell.org/package/classify-frog-0.2.4.3/src/src/Spreadsheet/Format.hs>
+HTML writing helpers using blaze-html.
-}
+
module Hledger.Write.Html.Blaze (
- printHtml,
+ styledTableHtml,
formatRow,
formatCell,
) where
import qualified Hledger.Write.Html.Attribute as Attr
import qualified Hledger.Write.Spreadsheet as Spr
-import Hledger.Write.Html (Lines, borderStyles)
+import Hledger.Write.Html.HtmlCommon (Lines, borderStyles)
import Hledger.Write.Spreadsheet (Type(..), Style(..), Emphasis(..), Cell(..))
import qualified Text.Blaze.Html4.Transitional.Attributes as HtmlAttr
@@ -22,8 +21,10 @@
import Data.Foldable (traverse_)
-printHtml :: (Lines border) => [[Cell border Html]] -> Html
-printHtml table = do
+-- | Export spreadsheet table data as HTML table.
+-- This is derived from
<https://hackage.haskell.org/package/classify-frog-0.2.4.3/src/src/Spreadsheet/Format.hs>
+styledTableHtml :: (Lines border) => [[Cell border Html]] -> Html
+styledTableHtml table = do
Html.style $ toHtml $ Attr.tableStylesheet
Html.table $ traverse_ formatRow table
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Write/Html/HtmlCommon.hs
new/hledger-lib-1.42/Hledger/Write/Html/HtmlCommon.hs
--- old/hledger-lib-1.41/Hledger/Write/Html/HtmlCommon.hs 1970-01-01
01:00:00.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Write/Html/HtmlCommon.hs 2025-03-07
17:50:07.000000000 +0100
@@ -0,0 +1,39 @@
+{-# LANGUAGE OverloadedStrings #-}
+{- |
+Common definitions used by both Html.Blaze and Html.Lucid.
+-}
+
+module Hledger.Write.Html.HtmlCommon (
+ Lines(..),
+ borderStyles,
+ ) where
+
+import Data.Text (Text)
+
+import Hledger.Write.Spreadsheet (Cell(..))
+import qualified Hledger.Write.Spreadsheet as Spr
+
+
+borderStyles :: Lines border => Cell border text -> [Text]
+borderStyles cell =
+ let border field access =
+ map (field<>) $ borderLines $ access $ cellBorder cell in
+ let leftBorder = border "border-left:" Spr.borderLeft in
+ let rightBorder = border "border-right:" Spr.borderRight in
+ let topBorder = border "border-top:" Spr.borderTop in
+ let bottomBorder = border "border-bottom:" Spr.borderBottom in
+ leftBorder++rightBorder++topBorder++bottomBorder
+
+
+class (Spr.Lines border) => Lines border where
+ borderLines :: border -> [Text]
+
+instance Lines () where
+ borderLines () = []
+
+instance Lines Spr.NumLines where
+ borderLines prop =
+ case prop of
+ Spr.NoLine -> []
+ Spr.SingleLine -> ["black"]
+ Spr.DoubleLine -> ["double black"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Write/Html/Lucid.hs
new/hledger-lib-1.42/Hledger/Write/Html/Lucid.hs
--- old/hledger-lib-1.41/Hledger/Write/Html/Lucid.hs 2024-11-10
22:55:17.000000000 +0100
+++ new/hledger-lib-1.42/Hledger/Write/Html/Lucid.hs 2025-03-07
17:50:07.000000000 +0100
@@ -1,36 +1,39 @@
{-# LANGUAGE OverloadedStrings #-}
{- |
-Export spreadsheet table data as HTML table.
-
-This is derived from
<https://hackage.haskell.org/package/classify-frog-0.2.4.3/src/src/Spreadsheet/Format.hs>
+HTML writing helpers using lucid.
-}
+
module Hledger.Write.Html.Lucid (
- printHtml,
+ Html,
+ L.toHtml,
+ styledTableHtml,
formatRow,
formatCell,
) where
+import Data.Foldable (traverse_)
+import qualified Data.Text as Text
+import qualified Lucid.Base as L
+import qualified Lucid as L
+
import qualified Hledger.Write.Html.Attribute as Attr
+import Hledger.Write.Html.HtmlCommon
+import Hledger.Write.Spreadsheet (Type(..), Style(..), Emphasis(..),
Cell(..))
import qualified Hledger.Write.Spreadsheet as Spr
-import Hledger.Write.Html (Lines, borderStyles)
-import Hledger.Write.Spreadsheet (Type(..), Style(..), Emphasis(..), Cell(..))
-import qualified Data.Text as Text
-import qualified Lucid.Base as HtmlBase
-import qualified Lucid as Html
-import Data.Foldable (traverse_)
+type Html = L.Html ()
-type Html = Html.Html ()
-
-printHtml :: (Lines border) => [[Cell border Html]] -> Html
-printHtml table = do
- Html.link_ [Html.rel_ "stylesheet", Html.href_ "hledger.css"]
- Html.style_ Attr.tableStylesheet
- Html.table_ $ traverse_ formatRow table
+-- | Export spreadsheet table data as HTML table.
+-- This is derived from
<https://hackage.haskell.org/package/classify-frog-0.2.4.3/src/src/Spreadsheet/Format.hs>
+styledTableHtml :: (Lines border) => [[Cell border Html]] -> Html
+styledTableHtml table = do
+ L.link_ [L.rel_ "stylesheet", L.href_ "hledger.css"]
+ L.style_ Attr.tableStylesheet
+ L.table_ $ traverse_ formatRow table
formatRow:: (Lines border) => [Cell border Html] -> Html
-formatRow = Html.tr_ . traverse_ formatCell
+formatRow = L.tr_ . traverse_ formatCell
formatCell :: (Lines border) => Cell border Html -> Html
formatCell cell =
@@ -38,41 +41,42 @@
let content =
if Text.null $ cellAnchor cell
then str
- else Html.a_ [Html.href_ $ cellAnchor cell] str in
+ else L.a_ [L.href_ $ cellAnchor cell] str in
let style =
case borderStyles cell of
[] -> []
- ss -> [Html.style_ $ Attr.concatStyles ss] in
+ ss -> [L.style_ $ Attr.concatStyles ss] in
let class_ =
- map Html.class_ $
+ map L.class_ $
filter (not . Text.null) [Spr.textFromClass $ cellClass cell] in
let span_ makeCell attrs cont =
case Spr.cellSpan cell of
Spr.NoSpan -> makeCell attrs cont
Spr.Covered -> pure ()
Spr.SpanHorizontal n ->
- makeCell (Html.colspan_ (Text.pack $ show n) : attrs) cont
+ makeCell (L.colspan_ (Text.pack $ show n) : attrs) cont
Spr.SpanVertical n ->
- makeCell (Html.rowspan_ (Text.pack $ show n) : attrs) cont
+ makeCell (L.rowspan_ (Text.pack $ show n) : attrs) cont
in
case cellStyle cell of
- Head -> span_ Html.th_ (style++class_) content
+ Head -> span_ L.th_ (style++class_) content
Body emph ->
let align =
case cellType cell of
TypeString -> []
TypeDate -> []
- _ -> [HtmlBase.makeAttribute "align" "right"]
+ _ -> [L.makeAttribute "align" "right"]
valign =
case Spr.cellSpan cell of
Spr.SpanVertical n ->
if n>1
- then [HtmlBase.makeAttribute "valign" "top"]
+ then [L.makeAttribute "valign" "top"]
else []
_ -> []
withEmph =
case emph of
Item -> id
- Total -> Html.b_
- in span_ Html.td_ (style++align++valign++class_) $
+ Total -> L.b_
+ in span_ L.td_ (style++align++valign++class_) $
withEmph content
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/Hledger/Write/Html.hs
new/hledger-lib-1.42/Hledger/Write/Html.hs
--- old/hledger-lib-1.41/Hledger/Write/Html.hs 2024-11-10 22:55:17.000000000
+0100
+++ new/hledger-lib-1.42/Hledger/Write/Html.hs 2025-03-07 17:50:07.000000000
+0100
@@ -1,38 +1,41 @@
-{-# LANGUAGE OverloadedStrings #-}
{- |
-Common definitions for Html.Blaze and Html.Lucid
+HTML writing helpers.
+This module would ideally hide the details of which HTML library is used, but
it doesn't yet.
+
+Currently hledger-web uses blaze-html, but hledger CLI reports use lucid.
+lucid has a more usable API than blaze-html
(https://chrisdone.com/posts/lucid).
+lucid2's is even better.
+Unfortunately lucid* can not render multi-line or indented text.
+We want this so that humans can read and troubleshoot our HTML output.
+So a transition to blaze-html may be coming.
+
-}
+
+{-# LANGUAGE OverloadedStrings #-}
+
module Hledger.Write.Html (
- Lines(..),
- borderStyles,
- ) where
-
-import qualified Hledger.Write.Spreadsheet as Spr
-import Hledger.Write.Spreadsheet (Cell(..))
-
-import Data.Text (Text)
-
-
-borderStyles :: Lines border => Cell border text -> [Text]
-borderStyles cell =
- let border field access =
- map (field<>) $ borderLines $ access $ cellBorder cell in
- let leftBorder = border "border-left:" Spr.borderLeft in
- let rightBorder = border "border-right:" Spr.borderRight in
- let topBorder = border "border-top:" Spr.borderTop in
- let bottomBorder = border "border-bottom:" Spr.borderBottom in
- leftBorder++rightBorder++topBorder++bottomBorder
-
-
-class (Spr.Lines border) => Lines border where
- borderLines :: border -> [Text]
-
-instance Lines () where
- borderLines () = []
-
-instance Lines Spr.NumLines where
- borderLines prop =
- case prop of
- Spr.NoLine -> []
- Spr.SingleLine -> ["black"]
- Spr.DoubleLine -> ["double black"]
+ L.toHtml,
+ Html,
+ formatRow,
+ htmlAsText,
+ htmlAsLazyText,
+ styledTableHtml,
+ tests_Hledger_Write_Html
+ ) where
+
+import qualified Data.Text as T (Text)
+import qualified Data.Text.Lazy as TL (Text, toStrict)
+import qualified Lucid as L (renderText, toHtml)
+import Test.Tasty (testGroup)
+
+import Hledger.Write.Html.Lucid (Html, formatRow, styledTableHtml)
+
+
+htmlAsText :: Html -> T.Text
+htmlAsText = TL.toStrict . L.renderText
+
+htmlAsLazyText :: Html -> TL.Text
+htmlAsLazyText = L.renderText
+
+tests_Hledger_Write_Html = testGroup "Write.Html" [
+ ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/hledger-lib.cabal
new/hledger-lib-1.42/hledger-lib.cabal
--- old/hledger-lib-1.41/hledger-lib.cabal 2024-12-09 03:06:59.000000000
+0100
+++ new/hledger-lib-1.42/hledger-lib.cabal 2025-03-07 17:54:15.000000000
+0100
@@ -5,7 +5,7 @@
-- see: https://github.com/sol/hpack
name: hledger-lib
-version: 1.41
+version: 1.42
synopsis: A library providing the core functionality of hledger
description: This library contains hledger's core functionality.
It is used by most hledger* packages so that they support the
same
@@ -93,6 +93,7 @@
Hledger.Write.Html.Attribute
Hledger.Write.Html.Blaze
Hledger.Write.Html.Lucid
+ Hledger.Write.Html.HtmlCommon
Hledger.Write.Spreadsheet
Hledger.Reports
Hledger.Reports.ReportOptions
@@ -140,6 +141,7 @@
, deepseq
, directory >=1.2.6.1
, doclayout >=0.3 && <0.6
+ , encoding >=0.10
, extra >=1.6.3
, file-embed >=0.0.10
, filepath
@@ -174,7 +176,6 @@
type: exitcode-stdio-1.0
main-is: doctests.hs
hs-source-dirs:
- ./
test
ghc-options: -Wall -Wno-incomplete-uni-patterns -Wno-missing-signatures
-Wno-orphans -Wno-type-defaults -Wno-unused-do-bind
build-depends:
@@ -200,6 +201,7 @@
, directory >=1.2.6.1
, doclayout >=0.3 && <0.6
, doctest >=0.18.1
+ , encoding >=0.10
, extra >=1.6.3
, file-embed >=0.0.10
, filepath
@@ -236,7 +238,6 @@
type: exitcode-stdio-1.0
main-is: unittest.hs
hs-source-dirs:
- ./
test
ghc-options: -Wall -Wno-incomplete-uni-patterns -Wno-missing-signatures
-Wno-orphans -Wno-type-defaults -Wno-unused-do-bind
build-depends:
@@ -261,6 +262,7 @@
, deepseq
, directory >=1.2.6.1
, doclayout >=0.3 && <0.6
+ , encoding >=0.10
, extra >=1.6.3
, file-embed >=0.0.10
, filepath
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.41/test/unittest.hs
new/hledger-lib-1.42/test/unittest.hs
--- old/hledger-lib-1.41/test/unittest.hs 2023-05-27 20:23:02.000000000
+0200
+++ new/hledger-lib-1.42/test/unittest.hs 2025-03-07 17:50:07.000000000
+0100
@@ -2,9 +2,7 @@
Run the hledger-lib package's unit tests using the tasty test runner.
-}
--- package-qualified import to avoid cabal missing-home-modules warning (and
double-building ?)
-{-# LANGUAGE PackageImports #-}
-import "hledger-lib" Hledger (tests_Hledger)
+import Hledger (tests_Hledger)
import System.Environment (setEnv)
import Test.Tasty (defaultMain)