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
38 import qualified Language.DTC.Read.TCT as DTC.Read.TCT
39 import qualified Language.DTC.Sym as DTC
40 import qualified Language.DTC.Write.HTML5 as DTC.Write.HTML5
41 import qualified Language.DTC.Write.XML as DTC.Write.XML
42 import qualified Language.RNC.Write as RNC
43 import qualified Language.TCT as TCT
44 import qualified Language.TCT.Write.HTML5 as TCT.Write.HTML5
45 import qualified Language.TCT.Write.XML as TCT.Write.XML
46 import qualified Text.Blaze.DTC as Blaze.DTC
47 import qualified Text.Blaze.HTML5 as Blaze.HTML5
48 import qualified Text.Megaparsec as P
52 type Langs = '[FR, EN]
53 type Lang = LocaleIn Langs
58 (\v -> Map.findWithDefault
59 (LocaleIn @Langs en_US)
60 (Text.pack $ List.takeWhile (\c -> Char.isAlphaNum c || c == '_') v)
63 <$> Env.lookupEnv "LANG"
64 cmd <- execParser $ pArgv lang
68 info (pCommand lang <**> helper) $ mconcat
70 , progDesc "document tool"
71 , header "hdoc - TCT and DTC command line tool"
74 mainWithCommand :: Command -> IO ()
75 mainWithCommand (CommandTCT ArgsTCT{..}) =
76 readFile input $ \_fp txt ->
77 case TCT.readTCTs input txt of
78 Left err -> error $ P.parseErrorPretty err
80 hPrint stderr $ Tree.Pretty tct
83 Blaze.renderMarkupToByteStringIO BS.putStr $
84 TCT.Write.HTML5.html5ify tct
85 mainWithCommand (CommandDTC ArgsDTC{..}) =
86 readFile input $ \_fp txt ->
87 case TCT.readTCTs input txt of
88 Left err -> error $ P.parseErrorPretty err
90 when (trace_TCT trace) $ do
91 hPutStrLn stderr "### TCT ###"
92 hPrint stderr $ Tree.Pretty tct
93 let xml = TCT.Write.XML.xmlDocument tct
94 when (trace_XML trace) $ do
95 hPutStrLn stderr "### XML ###"
96 hPrint stderr $ Tree.Pretty xml
97 case DTC.Read.TCT.readDTC xml of
98 Left err -> error $ P.parseErrorPretty err
100 when (trace_DTC trace) $ do
101 hPutStrLn stderr "### DTC ###"
105 Blaze.prettyMarkupIO Blaze.DTC.indentTag BS.putStr $
106 DTC.Write.XML.xmlDocument locale dtc
108 Blaze.prettyMarkupIO Blaze.HTML5.indentTag BS.putStr $
109 DTC.Write.HTML5.html5Document locale dtc
110 mainWithCommand (CommandRNC ArgsRNC{}) =
111 forM_ DTC.dtcRNC $ \w ->
112 Text.hPutStrLn stdout $ RNC.renderWriter w
116 instance IsList (Opt.Mod f a) where
117 type Item (Opt.Mod f a) = Opt.Mod f a
121 readMap :: Map String a -> ReadM a
124 case Map.lookup s m of
125 Nothing -> Left $ "cannot parse value \"" <> s
126 <> "\"\nexpecting one of: "
127 <> (List.intercalate ", " $ Map.keys m)
136 pCommand :: Lang -> Parser Command
141 info (CommandTCT <$> pArgsTCT) $
142 progDesc "TCT (Texte Convivial Technique) rendition."
147 info (CommandDTC <$> pArgsDTC lang) $
148 progDesc "DTC (Document Technique Convivial) rendition."
153 info (CommandRNC <$> pArgsRNC) $
154 progDesc "RNC (RelaxNG Compact) schema."
164 instance Default Trace where
170 instance Semigroup Trace where
173 { trace_TCT = trace_TCT x || trace_TCT y
174 , trace_XML = trace_XML x || trace_XML y
175 , trace_DTC = trace_DTC x || trace_DTC y
177 instance Monoid Trace where
181 pTrace :: Parser Trace
188 , help $ "Print trace. (choices: "
189 <> (List.intercalate ", " $ Map.keys m) <> ")"
193 [ ("tct", def{trace_TCT=True})
194 , ("xml", def{trace_XML=True})
195 , ("dtc", def{trace_DTC=True})
202 , format :: TctFormat
205 pArgsTCT :: Parser ArgsTCT
208 <$> argument str (metavar "FILE")
211 -- *** Type 'TctFormat'
215 pTctFormat :: Parser TctFormat
217 flag TctFormatHTML5 TctFormatHTML5
219 , help "Render as HTML5."
226 , format :: DtcFormat
230 pArgsDTC :: Lang -> Parser ArgsDTC
233 <$> argument str (metavar "FILE")
238 pLocale :: Lang -> Parser (LocaleIn Langs)
241 (maybeReader $ \s -> Map.lookup (Text.pack s) $ locales @Langs)
249 -- *** Type 'DtcFormat'
254 pDtcFormat :: Parser DtcFormat
256 flag DtcFormatHTML5 DtcFormatHTML5
258 , help "Render as HTML5."
260 flag DtcFormatHTML5 DtcFormatXML
262 , help "Render as XML."
269 pArgsRNC :: Parser ArgsRNC
270 pArgsRNC = pure ArgsRNC
275 <$> strOption ( long "hello"
277 <> help "Target for the greeting")
278 <*> switch ( long "quiet"
280 <> help "Whether to be quiet")
281 <*> option auto ( long "enthusiasm"
282 <> help "How enthusiastically to greet"