1 {-# LANGUAGE DataKinds #-}
2 {-# LANGUAGE DuplicateRecordFields #-}
3 {-# LANGUAGE TypeApplications #-}
4 {-# LANGUAGE UndecidableInstances #-}
5 {-# LANGUAGE OverloadedLists #-}
6 {-# OPTIONS_GHC -fno-warn-orphans #-}
9 import Control.Monad (forM_, when)
11 import Data.Default.Class (Default(..))
12 import Data.Either (Either(..))
13 import Data.Eq (Eq(..))
14 import Data.Function (($), (.))
15 import Data.Functor ((<$>))
16 import Data.Map.Strict (Map)
17 import Data.Maybe (Maybe(..), fromMaybe)
18 import Data.Monoid (Monoid(..))
19 import Data.Semigroup (Semigroup(..))
20 import Data.String (String)
21 import GHC.Exts (IsList(..))
22 import Options.Applicative as Opt
23 import Prelude (error)
24 import System.IO (IO, FilePath, hPrint, hPutStrLn, stderr, stdout)
25 import qualified Data.ByteString as BS
26 import qualified Data.Char as Char
27 import qualified Data.List as List
28 import qualified Data.Map.Strict as Map
29 import qualified Data.Text as Text
30 import qualified Data.Text.IO as Text
31 import qualified System.Environment as Env
32 import qualified Text.Blaze.Renderer.Utf8 as Blaze
33 import qualified Text.Blaze.Utils as Blaze
37 import qualified Data.TreeSeq.Strict as Tree
39 import qualified Language.DTC.Read.TCT as DTC.Read.TCT
40 import qualified Language.DTC.Sym as DTC
41 import qualified Language.DTC.Write.HTML5 as DTC.Write.HTML5
42 import qualified Language.DTC.Write.XML as DTC.Write.XML
43 import qualified Text.Blaze.DTC as Blaze.DTC
44 import qualified Text.Blaze.HTML5 as Blaze.HTML5
46 import qualified Language.RNC.Write as RNC
47 import qualified Language.TCT as TCT
48 import qualified Language.TCT.Write.HTML5 as TCT.Write.HTML5
49 import qualified Language.TCT.Write.XML as TCT.Write.XML
50 import qualified Text.Megaparsec as P
54 type Langs = '[FR, EN]
55 type Lang = LocaleIn Langs
60 (\v -> Map.findWithDefault
61 (LocaleIn @Langs en_US)
62 (Text.pack $ List.takeWhile (\c -> Char.isAlphaNum c || c == '_') v)
65 <$> Env.lookupEnv "LANG"
66 cmd <- execParser $ pArgv lang
70 info (pCommand lang <**> helper) $ mconcat
72 , progDesc "document tool"
73 , header "hdoc - TCT and DTC command line tool"
76 mainWithCommand :: Command -> IO ()
77 mainWithCommand (CommandTCT ArgsTCT{..}) =
78 readFile input $ \_fp txt ->
79 case TCT.readTCTs input txt of
80 Left err -> error $ P.parseErrorPretty err
82 when (trace_TCT trace) $ do
83 hPutStrLn stderr "### TCT ###"
84 hPrint stderr $ Tree.Pretty tct
85 when (trace_XML trace) $ do
86 hPutStrLn stderr "### XML ###"
87 let xml = TCT.Write.XML.xmlDocument tct
88 hPrint stderr $ Tree.Pretty xml
91 Blaze.renderMarkupToByteStringIO BS.putStr $
92 TCT.Write.HTML5.html5Document tct
94 mainWithCommand (CommandDTC ArgsDTC{..}) =
95 readFile input $ \_fp txt ->
96 case TCT.readTCTs input txt of
97 Left err -> error $ P.parseErrorPretty err
99 when (trace_TCT trace) $ do
100 hPutStrLn stderr "### TCT ###"
101 hPrint stderr $ Tree.Pretty tct
102 let xml = TCT.Write.XML.xmlDocument tct
103 when (trace_XML trace) $ do
104 hPutStrLn stderr "### XML ###"
105 hPrint stderr $ Tree.Pretty xml
106 case DTC.Read.TCT.readDTC xml of
107 Left err -> error $ P.parseErrorPretty err
109 when (trace_DTC trace) $ do
110 hPutStrLn stderr "### DTC ###"
114 Blaze.prettyMarkupIO Blaze.DTC.indentTag BS.putStr $
115 DTC.Write.XML.xmlDocument locale dtc
117 Blaze.prettyMarkupIO Blaze.HTML5.indentTag BS.putStr $
118 DTC.Write.HTML5.html5Document locale dtc
119 mainWithCommand (CommandRNC ArgsRNC{}) =
120 forM_ DTC.dtcRNC $ \w ->
121 Text.hPutStrLn stdout $ RNC.renderWriter w
126 instance IsList (Opt.Mod f a) where
127 type Item (Opt.Mod f a) = Opt.Mod f a
131 readMap :: Map String a -> ReadM a
134 case Map.lookup s m of
135 Nothing -> Left $ "cannot parse value \"" <> s
136 <> "\"\nexpecting one of: "
137 <> (List.intercalate ", " $ Map.keys m)
148 pCommand :: Lang -> Parser Command
153 info (CommandTCT <$> pArgsTCT) $
154 progDesc "TCT (Texte Convivial Technique) rendition."
159 info (CommandDTC <$> pArgsDTC lang) $
160 progDesc "DTC (Document Technique Convivial) rendition."
165 info (CommandRNC <$> pArgsRNC) $
166 progDesc "RNC (RelaxNG Compact) schema."
176 instance Default Trace where
182 instance Semigroup Trace where
185 { trace_TCT = trace_TCT x || trace_TCT y
186 , trace_XML = trace_XML x || trace_XML y
187 , trace_DTC = trace_DTC x || trace_DTC y
189 instance Monoid Trace where
193 pTrace :: Parser Trace
200 , help $ "Print trace. (choices: "
201 <> (List.intercalate ", " $ Map.keys m) <> ")"
205 [ ("tct", def{trace_TCT=True})
206 , ("xml", def{trace_XML=True})
207 , ("dtc", def{trace_DTC=True})
214 , format :: TctFormat
218 pArgsTCT :: Parser ArgsTCT
221 <$> argument str (metavar "FILE")
225 -- *** Type 'TctFormat'
229 pTctFormat :: Parser TctFormat
231 flag TctFormatHTML5 TctFormatHTML5
233 , help "Render as HTML5."
240 , format :: DtcFormat
244 pArgsDTC :: Lang -> Parser ArgsDTC
247 <$> argument str (metavar "FILE")
252 pLocale :: Lang -> Parser (LocaleIn Langs)
255 (maybeReader $ \s -> Map.lookup (Text.pack s) $ locales @Langs)
263 -- *** Type 'DtcFormat'
268 pDtcFormat :: Parser DtcFormat
270 flag DtcFormatHTML5 DtcFormatHTML5
272 , help "Render as HTML5."
274 flag DtcFormatHTML5 DtcFormatXML
276 , help "Render as XML."
283 pArgsRNC :: Parser ArgsRNC
284 pArgsRNC = pure ArgsRNC
289 <$> strOption ( long "hello"
291 <> help "Target for the greeting")
292 <*> switch ( long "quiet"
294 <> help "Whether to be quiet")
295 <*> option auto ( long "enthusiasm"
296 <> help "How enthusiastically to greet"