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 (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 qualified Data.ByteString as BS
29 import qualified Data.ByteString.Lazy as BSL
30 import qualified Data.Char as Char
31 import qualified Data.List as List
32 import qualified Data.Map.Strict as Map
33 import qualified Data.Text as Text
34 import qualified Data.Text.IO as Text
35 import qualified Data.Text.Lazy as TL
36 import qualified Data.Text.Lazy.Encoding as TL
37 import qualified Data.Text.Lazy.IO as TL
38 import qualified Data.TreeSeq.Strict as Tree
39 import qualified System.Environment as Env
40 import qualified Text.Blaze.Renderer.Utf8 as Blaze
41 import qualified Text.Blaze.Utils as Blaze
42 import qualified Text.Megaparsec as P
45 import qualified Language.TCT as TCT
46 import qualified Language.TCT.Write.HTML5 as TCT.Write.HTML5
47 import qualified Language.TCT.Write.Plain as TCT.Write.Plain
48 import qualified Language.TCT.Write.XML as TCT.Write.XML
51 import qualified Language.DTC.Read.TCT as DTC.Read.TCT
52 import qualified Language.DTC.Sym as DTC
53 import qualified Language.DTC.Write.HTML5 as DTC.Write.HTML5
54 import qualified Language.DTC.Write.XML as DTC.Write.XML
55 import qualified Language.RNC.Write as RNC
56 import qualified Text.Blaze.DTC as Blaze.DTC
57 import qualified Text.Blaze.HTML5 as Blaze.HTML5
59 type Langs = '[FR, EN]
60 type Lang = LocaleIn Langs
65 (\v -> Map.findWithDefault
66 (LocaleIn @Langs en_US)
67 (Text.pack $ List.takeWhile (\c -> Char.isAlphaNum c || c == '_') v)
70 <$> Env.lookupEnv "LANG"
71 cmd <- execParser $ pArgv lang
75 info (pCommand lang <**> helper) $ mconcat
77 , progDesc "document tool"
78 , header "hdoc - command line tool for TCT and DTC technical documents"
81 mainWithCommand :: Command -> IO ()
82 mainWithCommand (CommandTCT ArgsTCT{..}) =
83 readFile input $ \_fp txt ->
84 case TCT.readTCT input txt of
85 Left err -> error $ P.parseErrorPretty err
87 when (trace_TCT trace) $ do
88 hPutStrLn stderr "### TCT ###"
89 hPutStrLn stderr $ Tree.prettyTrees tct
90 when (trace_XML trace) $ do
91 hPutStrLn stderr "### XML ###"
92 let xml = TCT.Write.XML.document tct
93 hPutStrLn stderr $ Tree.prettyTrees xml
97 TCT.Write.Plain.document tct
99 Blaze.renderMarkupToByteStringIO BS.putStr $
100 TCT.Write.HTML5.document tct
101 mainWithCommand (CommandDTC ArgsDTC{..}) =
102 readFile input $ \_fp txt ->
103 case TCT.readTCT input txt of
104 Left err -> error $ P.parseErrorPretty 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.indentTag BS.putStr $
122 DTC.Write.XML.document locale dtc
124 Blaze.prettyMarkupIO Blaze.HTML5.indentTag 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