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 <psim...@suse.com>
+
+- 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)
 

Reply via email to