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 Data.Text.Lazy as TL
32 import qualified System.Environment as Env
33 import qualified Text.Blaze.Renderer.Utf8 as Blaze
34 import qualified Text.Blaze.Utils as Blaze
38 import qualified Data.TreeSeq.Strict as Tree
40 import qualified Language.DTC.Read.TCT as DTC.Read.TCT
41 import qualified Language.DTC.Sym as DTC
42 import qualified Language.DTC.Write.HTML5 as DTC.Write.HTML5
43 import qualified Language.DTC.Write.XML as DTC.Write.XML
44 import qualified Text.Blaze.DTC as Blaze.DTC
45 import qualified Text.Blaze.HTML5 as Blaze.HTML5
47 -- import qualified Language.RNC.Write as RNC
48 import qualified Language.TCT as TCT
49 -- import qualified Language.TCT.Write.HTML5 as TCT.Write.HTML5
50 -- import qualified Language.TCT.Write.XML as TCT.Write.XML
51 import qualified Text.Megaparsec as P
55 type Langs = '[FR, EN]
56 type Lang = LocaleIn Langs
61 (\v -> Map.findWithDefault
62 (LocaleIn @Langs en_US)
63 (Text.pack $ List.takeWhile (\c -> Char.isAlphaNum c || c == '_') v)
66 <$> Env.lookupEnv "LANG"
67 cmd <- execParser $ pArgv lang
71 info (pCommand lang <**> helper) $ mconcat
73 , progDesc "document tool"
74 , header "hdoc - TCT and DTC command line tool"
77 mainWithCommand :: Command -> IO ()
78 mainWithCommand (CommandTCT ArgsTCT{..}) =
79 readFile input $ \_fp txt ->
80 case TCT.readTrees input $ TL.fromStrict txt of
81 Left err -> error $ P.parseErrorPretty err
83 when (trace_TCT trace) $ do
84 hPutStrLn stderr "### TCT ###"
85 hPrint stderr $ Tree.Pretty tct
87 when (trace_XML trace) $ do
88 hPutStrLn stderr "### XML ###"
89 let xml = TCT.Write.XML.xmlDocument tct
90 hPrint stderr $ Tree.Pretty xml
93 Blaze.renderMarkupToByteStringIO BS.putStr $
94 TCT.Write.HTML5.html5Document tct
97 mainWithCommand (CommandDTC ArgsDTC{..}) =
98 readFile input $ \_fp txt ->
99 case TCT.readTCTs input txt of
100 Left err -> error $ P.parseErrorPretty err
102 when (trace_TCT trace) $ do
103 hPutStrLn stderr "### TCT ###"
104 hPrint stderr $ Tree.Pretty tct
105 let xml = TCT.Write.XML.xmlDocument tct
106 when (trace_XML trace) $ do
107 hPutStrLn stderr "### XML ###"
108 hPrint stderr $ Tree.Pretty xml
109 case DTC.Read.TCT.readDTC xml of
110 Left err -> error $ P.parseErrorPretty err
112 when (trace_DTC trace) $ do
113 hPutStrLn stderr "### DTC ###"
117 Blaze.prettyMarkupIO Blaze.DTC.indentTag BS.putStr $
118 DTC.Write.XML.xmlDocument locale dtc
120 Blaze.prettyMarkupIO Blaze.HTML5.indentTag BS.putStr $
121 DTC.Write.HTML5.html5Document locale dtc
122 mainWithCommand (CommandRNC ArgsRNC{}) =
123 forM_ DTC.dtcRNC $ \w ->
124 Text.hPutStrLn stdout $ RNC.renderWriter w
129 instance IsList (Opt.Mod f a) where
130 type Item (Opt.Mod f a) = Opt.Mod f a
134 readMap :: Map String a -> ReadM a
137 case Map.lookup s m of
138 Nothing -> Left $ "cannot parse value \"" <> s
139 <> "\"\nexpecting one of: "
140 <> (List.intercalate ", " $ Map.keys m)
151 pCommand :: Lang -> Parser Command
156 info (CommandTCT <$> pArgsTCT) $
157 progDesc "TCT (Texte Convivial Technique) rendition."
162 info (CommandDTC <$> pArgsDTC lang) $
163 progDesc "DTC (Document Technique Convivial) rendition."
168 info (CommandRNC <$> pArgsRNC) $
169 progDesc "RNC (RelaxNG Compact) schema."
179 instance Default Trace where
185 instance Semigroup Trace where
188 { trace_TCT = trace_TCT x || trace_TCT y
189 , trace_XML = trace_XML x || trace_XML y
190 , trace_DTC = trace_DTC x || trace_DTC y
192 instance Monoid Trace where
196 pTrace :: Parser Trace
203 , help $ "Print trace. (choices: "
204 <> (List.intercalate ", " $ Map.keys m) <> ")"
208 [ ("tct", def{trace_TCT=True})
209 , ("xml", def{trace_XML=True})
210 , ("dtc", def{trace_DTC=True})
217 , format :: TctFormat
221 pArgsTCT :: Parser ArgsTCT
224 <$> argument str (metavar "FILE")
228 -- *** Type 'TctFormat'
232 pTctFormat :: Parser TctFormat
234 flag TctFormatHTML5 TctFormatHTML5
236 , help "Render as HTML5."
243 , format :: DtcFormat
247 pArgsDTC :: Lang -> Parser ArgsDTC
250 <$> argument str (metavar "FILE")
255 pLocale :: Lang -> Parser (LocaleIn Langs)
258 (maybeReader $ \s -> Map.lookup (Text.pack s) $ locales @Langs)
266 -- *** Type 'DtcFormat'
271 pDtcFormat :: Parser DtcFormat
273 flag DtcFormatHTML5 DtcFormatHTML5
275 , help "Render as HTML5."
277 flag DtcFormatHTML5 DtcFormatXML
279 , help "Render as XML."
286 pArgsRNC :: Parser ArgsRNC
287 pArgsRNC = pure ArgsRNC
292 <$> strOption ( long "hello"
294 <> help "Target for the greeting")
295 <*> switch ( long "quiet"
297 <> help "Whether to be quiet")
298 <*> option auto ( long "enthusiasm"
299 <> help "How enthusiastically to greet"