Épure hcompta-lib.
[comptalang.git] / cli / Hcompta / CLI / Format / Ledger.hs
index bd125086fe6117f3a4d1715f0dca685db47bae04..a4fa570950e79883e2924c377521da107324cc43 100644 (file)
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DataKinds #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module Hcompta.CLI.Format.Ledger where
 
-import           Prelude hiding (error)
-import           Control.Exception (tryJust)
-import           Control.Monad (guard)
-import qualified Data.List
+-- import           Control.Monad.Trans.Except (ExceptT(..))
+import           Data.Foldable (Foldable(..))
+import           Data.Function ((.))
+import qualified Data.List as List
+import qualified Data.Text as Text
 import qualified Data.Text.Lazy as TL
-import           System.Environment as Env (getEnv)
-import           System.IO.Error (isDoesNotExistError)
-import qualified Text.Parsec as Parsec
-import qualified Text.Parsec.Error as Parsec.Error
+-- import           Control.DeepSeq (NFData)
+import           Prelude (($))
+-- import           System.IO (IO)
+import           Text.Show (Show(..))
 
+import           Hcompta.Date (Date)
+import qualified Hcompta.Balance as Balance
+-- import qualified Hcompta.CLI.Format as CLI.Format
+-- import           Hcompta.CLI.Lang (Lang)
+import qualified Hcompta.CLI.Lang as Lang
+import qualified Hcompta.Format.Ledger       as Ledger
+import qualified Hcompta.Format.Ledger.Read  as Ledger
+import qualified Hcompta.Format.Ledger.Write as Ledger
+-- import           Hcompta.Lib.Consable (Consable)
+import           Hcompta.Lib.Leijen (ToDoc(..))
 import qualified Hcompta.Lib.Leijen as W
-import           Hcompta.Lib.Leijen (ToDoc(..), (<>))
-import qualified Hcompta.Lib.Parsec as Lib.Parsec
-import qualified Hcompta.Calc.Balance as Calc.Balance
-import qualified Hcompta.CLI.Context as Context
-import           Hcompta.CLI.Context (Context)
-import qualified Hcompta.CLI.I18N as I18N
-import qualified Hcompta.CLI.Write as Write
-import qualified Hcompta.Model.Filter.Read as Filter.Read
-import qualified Hcompta.Format.Ledger.Read as Ledger.Read
-import qualified Hcompta.Format.Ledger.Write as Ledger.Write
-import qualified Hcompta.Model.Amount as Amount
+-- import qualified Hcompta.Lib.Parsec as Parsec
+import qualified Hcompta.Polarize as Polarize
+import qualified Hcompta.CLI.Lib.Leijen.Table as Leijen.Table
 
--- | Return 'FilePath's containing 'Hcompta.Format.Ledger.Journal's:
---
--- * either those given if any,
--- * or the one in LEDGER_FILE environment variable if any,
--- * or the one in LEDGER environment variable if any.
-paths :: Context.Context -> [FilePath] -> IO [FilePath]
-paths context [] = do
-       tryJust (guard . isDoesNotExistError) $ Env.getEnv "LEDGER_FILE"
-       >>= \x -> case x of
-        Right ok -> return [ok]
-        Left  _ko -> do
-               tryJust (guard . isDoesNotExistError) $ Env.getEnv "LEDGER"
-               >>= \xx -> case xx of
-                Right ok -> return [ok]
-                Left  _ko -> do
-                       let langs = Context.langs context
-                       Write.fatal context $
-                               I18N.render langs
-                               I18N.Message_no_ledger_file_given
-paths _context ps = return ps
-
-instance ToDoc Context Parsec.SourcePos where
-       toDoc context pos = do
-               let langs = Context.langs context
-               I18N.render langs $ do
-               case Parsec.sourceName pos of
-                "" -> I18N.Message_at
-                        (Parsec.sourceLine pos)
-                        (Parsec.sourceColumn pos)
-                path -> I18N.Message_in_file path
-                        (Parsec.sourceLine pos)
-                        (Parsec.sourceColumn pos)
-
-instance ToDoc Context e => ToDoc Context [Lib.Parsec.Error e] where
-       toDoc context errors =
-               W.vsep $ do
-               (flip map) errors $ (\error ->
-                       case error of
-                        Lib.Parsec.Error_At pos errs -> W.vsep $
-                               [ toDoc context pos
-                               , toDoc context errs
-                               ]
-                        Lib.Parsec.Error_Parser err ->
-                               W.vsep $
-                                [ toDoc context (Parsec.errorPos err)
-                                , showErrorMessages
-                                        (Parsec.Error.errorMessages err)
-                                ]
-                        Lib.Parsec.Error_Custom pos err -> W.vsep $
-                               [ toDoc context pos
-                               , toDoc context err
-                               ]
-                )
-               where
-                       langs = Context.langs context
-                       showErrorMessages :: [Parsec.Error.Message] -> W.Doc
-                       showErrorMessages msgs
-                               | null msgs = i18n $ I18N.Message_unknown
-                               | otherwise = W.vsep $ -- clean $
-                                       [showSysUnExpect, showUnExpect, showExpect, showMessages]
-                               where
-                                       i18n = I18N.render langs
-                                       (sysUnExpect,msgs1) = span ((Parsec.Error.SysUnExpect "") ==) msgs
-                                       (unExpect,msgs2)    = span ((Parsec.Error.UnExpect    "") ==) msgs1
-                                       (expect,messages)   = span ((Parsec.Error.Expect      "") ==) msgs2
-                                       
-                                       showExpect   = showMany (Just (i18n . I18N.Message_expect)) expect
-                                       showUnExpect = showMany (Just (i18n . I18N.Message_unexpect)) unExpect
-                                       showSysUnExpect
-                                        | not (null unExpect) || null sysUnExpect = W.empty
-                                        | null firstMsg = i18n $ I18N.Message_sysunexpect_end_of_input
-                                        | otherwise     = i18n $ I18N.Message_sysunexpect firstMsg
-                                               where
-                                               firstMsg = Parsec.Error.messageString (head sysUnExpect)
-                                       
-                                       showMessages = showMany Nothing messages
-                                       
-                                       -- helpers
-                                       showMany  :: (Maybe (W.Doc -> W.Doc)) -> [Parsec.Error.Message] -> W.Doc
-                                       showMany pre msgs_ =
-                                               case clean (map Parsec.Error.messageString msgs_) of
-                                                [] -> W.empty
-                                                ms ->
-                                                       case pre of
-                                                        Nothing -> commasOr ms
-                                                        Just p -> p $ commasOr ms
-                                       
-                                       commasOr :: [String] -> W.Doc
-                                       commasOr []  = W.empty
-                                       commasOr [m] = W.text $ TL.pack m
-                                       commasOr ms  = commaSep (init ms)
-                                                      <> (W.space <> i18n I18N.Message_or <> W.space)
-                                                      <> (W.bold $ W.dullblack $ W.text $ TL.pack $ last ms)
-                                       commaSep = W.intercalate (W.comma <> W.space)
-                                                  (W.bold . W.dullblack . W.text . TL.pack)
-                                                  . clean
-                                       
-                                       clean = Data.List.nub . filter (not . null)
-
-instance ToDoc Context Ledger.Read.Error where
-       toDoc context err =
+instance Lang.Translate Ledger.Read_Error W.Doc where
+       translate lang err =
                case err of
-                Ledger.Read.Error_year_or_day_is_missing ->
-                       I18N.render langs $ I18N.Message_year_or_day_is_missing
-                Ledger.Read.Error_invalid_date (y, m, d) ->
-                       I18N.render langs $ I18N.Message_invalid_date y m d
-                Ledger.Read.Error_invalid_time_of_day (h, m, s) ->
-                       I18N.render langs $ I18N.Message_invalid_time_of_day h m s
-                Ledger.Read.Error_transaction_not_equilibrated tr unit_sums ->
-                       i18n_transaction_not_equilibrated tr unit_sums
-                        I18N.Message_the_following_transaction_is_not_equilibrated_because
-                Ledger.Read.Error_virtual_transaction_not_equilibrated tr unit_sums ->
-                       i18n_transaction_not_equilibrated tr unit_sums
-                        I18N.Message_the_following_virtual_transaction_is_not_equilibrated_because
-                Ledger.Read.Error_reading_file file_path exn -> W.vsep $
-                        [ I18N.render langs $
-                               I18N.Message_failed_to_read_file file_path
+                Ledger.Read_Error_date date -> toDoc lang date
+                Ledger.Read_Error_transaction_not_equilibrated styles tr unit_sums ->
+                       i18n_transaction_not_equilibrated styles tr unit_sums
+                        Lang.Error_Transaction_The_following_transaction_is_not_equilibrated_because
+                Ledger.Read_Error_virtual_transaction_not_equilibrated styles tr unit_sums ->
+                       i18n_transaction_not_equilibrated styles tr unit_sums
+                        Lang.Error_Transaction_The_following_virtual_transaction_is_not_equilibrated_because
+                Ledger.Read_Error_reading_file file_path exn ->
+                       W.vsep $
+                        [ Lang.translate lang $ Lang.Error_Failed_to_read_file file_path
                         , W.text $ TL.pack $ show exn
                         ]
-                Ledger.Read.Error_including_file file_path errs -> W.vsep $
-                        [ I18N.render langs $
-                               I18N.Message_failed_to_include_file file_path
-                        , toDoc context errs
+                Ledger.Read_Error_including_file file_path errs ->
+                       W.vsep $
+                        [ Lang.translate lang $ Lang.Error_Failed_to_include_file file_path
+                        , Lang.translate lang errs
                         ]
                where
-                       langs = Context.langs context
-                       i18n_transaction_not_equilibrated tr unit_sums msg =
+                       i18n_transaction_not_equilibrated styles tr unit_sums msg =
                                W.vsep $
-                                [ I18N.render langs msg
-                                , W.vsep $ Data.List.map
-                                        (\Calc.Balance.Unit_Sum{Calc.Balance.unit_sum_amount} ->
-                                               let amt = Calc.Balance.amount_sum_balance unit_sum_amount in
-                                               I18N.render langs $
-                                               I18N.Message_unit_sums_up_to_the_non_null_amount
-                                                (Amount.unit amt) amt
+                                [ Lang.translate lang msg
+                                , W.vsep $ List.map
+                                        (\(unit, Balance.Unit_Sum{Balance.unit_sum_quantity}) ->
+                                               Lang.translate lang $
+                                               Lang.Error_Transaction_Ledger_Unit_sums_up_to_the_non_null_amount unit $
+                                               Ledger.amount_styled styles $
+                                               Ledger.Amount unit $
+                                               Polarize.depolarize unit_sum_quantity
                                         ) unit_sums
                                 , W.space
-                                , Ledger.Write.transaction tr
+                                , Ledger.write_transaction styles tr
                                 ]
 
-instance ToDoc Context Filter.Read.Error where
-       toDoc context err =
-               case err of
-                Filter.Read.Error_Unknown -> toDoc context ("error"::String)
+instance Leijen.Table.Cell_of_forall_param Ledger.Journal Date where
+       cell_of_forall_param _ctx date =
+               Leijen.Table.cell
+                { Leijen.Table.cell_content = Ledger.write_date        date
+                , Leijen.Table.cell_width   = Ledger.write_date_length date
+                }
+instance Leijen.Table.Cell_of_forall_param Ledger.Journal Ledger.Account where
+       cell_of_forall_param _ctx account =
+               let posting_type = Ledger.Posting_Type_Regular in
+               Leijen.Table.cell
+                { Leijen.Table.cell_content = Ledger.write_account        posting_type account
+                , Leijen.Table.cell_width   = Ledger.write_account_length posting_type account
+                }
+instance Leijen.Table.Cell_of_forall_param Ledger.Journal (Ledger.Unit, Ledger.Quantity) where
+       cell_of_forall_param j (unit, qty) =
+               let sty = Ledger.journal_amount_styles j in
+               let amt = Ledger.Amount unit qty in
+               let sa  = Ledger.amount_styled sty amt in
+               Leijen.Table.cell
+                { Leijen.Table.cell_content = Ledger.write_amount        sa
+                , Leijen.Table.cell_width   = Ledger.write_amount_length sa
+                }
+instance Leijen.Table.Cell_of_forall_param Ledger.Journal Ledger.Wording where
+       cell_of_forall_param _j w =
+               Leijen.Table.cell
+                { Leijen.Table.cell_content = toDoc ()    w
+                , Leijen.Table.cell_width   = Text.length w
+                }
+
+instance Foldable f => W.Leijen_of_forall_param Ledger.Journal (f Ledger.Transaction) where
+       leijen_of_forall_param =
+               Ledger.write_transactions .
+               Ledger.journal_amount_styles