1 {-# LANGUAGE DataKinds #-}
2 {-# LANGUAGE DuplicateRecordFields #-}
3 {-# LANGUAGE OverloadedLists #-}
4 {-# LANGUAGE TypeApplications #-}
5 {-# LANGUAGE TypeFamilies #-}
6 {-# LANGUAGE UndecidableInstances #-}
7 {-# OPTIONS_GHC -fno-warn-orphans #-}
10 import Control.Monad (Monad(..), forM_, when)
11 import Control.Monad.IO.Class (MonadIO(..))
13 import Data.Default.Class (Default(..))
14 import Data.Either (Either(..))
15 import Data.Eq (Eq(..))
16 import Data.Function (($), (.))
17 import Data.Functor ((<$>))
19 import Data.Map.Strict (Map)
20 import Data.Maybe (Maybe(..), fromMaybe)
21 import Data.Monoid (Monoid(..))
22 import Data.Semigroup (Semigroup(..))
23 import Data.String (String)
24 import GHC.Exts (IsList(..))
25 import Options.Applicative as Opt
26 import Prelude (error)
27 import System.IO (IO, FilePath, hPrint, hPutStrLn, stderr, stdout)
28 import Text.Show (Show(..))
29 import qualified Data.ByteString as BS
30 import qualified Data.ByteString.Lazy as BSL
31 import qualified Data.Char as Char
32 import qualified Data.List as List
33 import qualified Data.Map.Strict as Map
34 import qualified Data.Text as Text
35 import qualified Data.Text.IO as Text
36 import qualified Data.Text.Lazy as TL
37 import qualified Data.Text.Lazy.Encoding as TL
38 import qualified Data.Text.Lazy.IO as TL
39 import qualified Data.TreeSeq.Strict as Tree
40 import qualified System.Environment as Env
41 import qualified Text.Blaze.Renderer.Utf8 as Blaze
42 import qualified Text.Blaze.Utils as Blaze
43 import qualified Text.Megaparsec as P
46 import qualified Language.TCT as TCT
47 import qualified Language.TCT.Write.HTML5 as TCT.Write.HTML5
48 import qualified Language.TCT.Write.Plain as TCT.Write.Plain
49 import qualified Language.TCT.Write.XML as TCT.Write.XML
52 import qualified Language.DTC.Read.TCT as DTC.Read.TCT
53 import qualified Language.DTC.Sym as DTC
54 import qualified Language.DTC.Write.HTML5 as DTC.Write.HTML5
55 import qualified Language.DTC.Write.XML as DTC.Write.XML
56 import qualified Language.RNC.Write as RNC
57 import qualified Text.Blaze.DTC as Blaze.DTC
58 import qualified Text.Blaze.HTML5 as Blaze.HTML5
60 type Langs = '[FR, EN]
61 type Lang = LocaleIn Langs
66 (\v -> Map.findWithDefault
67 (LocaleIn @Langs en_US)
68 (Text.pack $ List.takeWhile (\c -> Char.isAlphaNum c || c == '_') v)
71 <$> Env.lookupEnv "LANG"
72 cmd <- execParser $ pArgv lang
76 info (pCommand lang <**> helper) $ mconcat
78 , progDesc "document tool"
79 , header "hdoc - command line tool for TCT and DTC technical documents"
82 mainWithCommand :: Command -> IO ()
83 mainWithCommand (CommandTCT ArgsTCT{..}) = do
84 txt <- TCT.readFile input
85 case TCT.readTCTWithoutIncludes input txt of
86 Left err -> error $ show err
88 when (trace_TCT trace) $ do
89 hPutStrLn stderr "### TCT ###"
90 hPutStrLn stderr $ Tree.prettyTrees tct
91 when (trace_XML trace) $ do
92 hPutStrLn stderr "### XML ###"
93 let xml = TCT.Write.XML.document tct
94 hPutStrLn stderr $ Tree.prettyTrees xml
98 TCT.Write.Plain.document tct
100 Blaze.renderMarkupToByteStringIO BS.putStr $
101 TCT.Write.HTML5.document tct
102 mainWithCommand (CommandDTC ArgsDTC{..}) =
103 TCT.readTCT input >>= \case
104 Left err -> error $ show err
106 when (trace_TCT trace) $ do
107 hPutStrLn stderr "### TCT ###"
108 hPutStrLn stderr $ Tree.prettyTrees tct
109 let xml = TCT.Write.XML.document tct
110 when (trace_XML trace) $ do
111 hPutStrLn stderr "### XML ###"
112 hPutStrLn stderr $ Tree.prettyTrees xml
113 case DTC.Read.TCT.readDTC xml of
114 Left err -> error $ P.parseErrorPretty err
116 when (trace_DTC trace) $ do
117 hPutStrLn stderr "### DTC ###"
121 Blaze.prettyMarkupIO Blaze.DTC.isInlinedElement BS.putStr $
122 DTC.Write.XML.document locale dtc
124 Blaze.prettyMarkupIO Blaze.HTML5.isInlinedElement BS.putStr $
125 DTC.Write.HTML5.document locale dtc
126 mainWithCommand (CommandRNC ArgsRNC{}) =
127 forM_ DTC.schema $ \rule ->
128 Text.hPutStrLn stdout $ RNC.renderWriter rule
130 -- * Filesystem utilities
131 readFile :: MonadIO m => FilePath -> (FilePath -> TL.Text -> m a) -> m a
133 content <- liftIO $ BSL.readFile fp
134 f fp $ TL.decodeUtf8 content
136 -- * Options utilities
138 instance IsList (Opt.Mod f a) where
139 type Item (Opt.Mod f a) = Opt.Mod f a
143 readMap :: Map String a -> ReadM a
146 case Map.lookup s m of
147 Nothing -> Left $ "cannot parse value \"" <> s
148 <> "\"\nexpecting one of: "
149 <> (List.intercalate ", " $ Map.keys m)
158 pCommand :: Lang -> Parser Command
163 info (CommandTCT <$> pArgsTCT) $
164 progDesc "TCT (Texte Convivial Technique) rendition."
169 info (CommandDTC <$> pArgsDTC lang) $
170 progDesc "DTC (Document Technique Convivial) rendition."
175 info (CommandRNC <$> pArgsRNC) $
176 progDesc "RNC (RelaxNG Compact) schema."
186 instance Default Trace where
192 instance Semigroup Trace where
195 { trace_TCT = trace_TCT x || trace_TCT y
196 , trace_XML = trace_XML x || trace_XML y
197 , trace_DTC = trace_DTC x || trace_DTC y
199 instance Monoid Trace where
203 pTrace :: Parser Trace
210 , help $ "Print trace. (choices: "
211 <> (List.intercalate ", " $ Map.keys m) <> ")"
215 [ ("tct", def{trace_TCT=True})
216 , ("xml", def{trace_XML=True})
217 , ("dtc", def{trace_DTC=True})
224 , format :: TctFormat
228 pArgsTCT :: Parser ArgsTCT
231 <$> argument str (metavar "FILE")
235 -- *** Type 'TctFormat'
240 pTctFormat :: Parser TctFormat
242 flag TctFormatPlain TctFormatPlain
244 , help "Render as plain text."
246 flag TctFormatHTML5 TctFormatHTML5
248 , help "Render as HTML5."
255 , format :: DtcFormat
259 pArgsDTC :: Lang -> Parser ArgsDTC
262 <$> argument str (metavar "FILE")
267 pLocale :: Lang -> Parser (LocaleIn Langs)
270 (maybeReader $ \s -> Map.lookup (Text.pack s) $ locales @Langs)
278 -- *** Type 'DtcFormat'
283 pDtcFormat :: Parser DtcFormat
285 flag DtcFormatHTML5 DtcFormatHTML5
287 , help "Render as HTML5."
289 flag DtcFormatHTML5 DtcFormatXML
291 , help "Render as XML."
298 pArgsRNC :: Parser ArgsRNC
299 pArgsRNC = pure ArgsRNC