@@ -25,11 +25,10 @@ import qualified Data.Aeson as A
2525import Data.Aeson (FromJSON (parseJSON ), (.:) , (.:?) , (.!=) )
2626import qualified Data.Aeson.Types as AT
2727
28- -- https://hackage.haskell.org/package/ansi-wl-pprint
29- import Text.PrettyPrint.ANSI.Leijen (Doc )
30-
3128-- https://hackage.haskell.org/package/base
29+ import Control.Applicative (optional )
3230import Control.Monad (forM_ , unless , when )
31+ import Data.Maybe (fromMaybe )
3332#if !MIN_VERSION_base (4,11,0)
3433import Data.Monoid ((<>) )
3534#endif
@@ -86,6 +85,10 @@ import qualified LibOA
8685buildDir :: FilePath
8786buildDir = " queue-sheet-build"
8887
88+ -- | Default template file
89+ defaultTemplate :: FilePath
90+ defaultTemplate = " template.tex"
91+
8992------------------------------------------------------------------------------
9093-- $Types
9194
@@ -180,6 +183,29 @@ instance FromJSON Queue where
180183 (Nothing , Nothing ) -> Nothing
181184 return Queue {.. }
182185
186+ -- | Queues file
187+ data QueuesFile
188+ = QueuesFile
189+ { qfSections :: ! [Section ]
190+ , qfQueues :: ! [Queue ]
191+ }
192+ deriving Show
193+
194+ instance FromJSON QueuesFile where
195+ parseJSON = A. withObject " QueuesFile" $ \ o ->
196+ QueuesFile
197+ <$> o .: " sections"
198+ <*> o .: " queues"
199+
200+ ------------------------------------------------------------------------------
201+ -- $Library
202+
203+ -- | Display an error and exit the program
204+ errorExit :: String -> IO a
205+ errorExit msg = do
206+ putStrLn $ " error: " ++ msg
207+ exitFailure
208+
183209-- | Parse any scalar value as a string
184210--
185211-- Strings, numbers, booleans, and null are parsed as a string. Arrays and
@@ -215,31 +241,19 @@ escapeTeX = T.foldl go ""
215241------------------------------------------------------------------------------
216242-- $Yaml
217243
218- -- | Load @sections.yaml@
219- loadSectionsYaml :: FilePath -> IO [Section ]
220- loadSectionsYaml = loadYamlFile
221-
222244-- | Load @queues.yaml@
223- loadQueuesYaml :: FilePath -> [Section ] -> IO [Queue ]
224- loadQueuesYaml path sections = do
225- queues <- loadYamlFile path
226- forM_ queues $ \ Queue {.. } ->
227- unless (queueSection `elem` sections) . errorExit . unwords $
245+ loadQueuesYaml :: FilePath -> IO QueuesFile
246+ loadQueuesYaml path = do
247+ let yamlError = errorExit
248+ . ((" error loading " ++ path ++ " : " ) ++ )
249+ . Yaml. prettyPrintParseException
250+ qf@ QueuesFile {.. } <- either yamlError pure =<< Yaml. decodeFileEither path
251+ forM_ qfQueues $ \ Queue {.. } ->
252+ unless (queueSection `elem` qfSections) . errorExit . unwords $
228253 [ " queue" , TTC. render queueName
229254 , " has unknown section" , TTC. render queueSection
230255 ]
231- return queues
232-
233- -- | Load a YAML file
234- --
235- -- If there is an error, the error is displayed and the program is exited.
236- loadYamlFile :: FromJSON a => FilePath -> IO [a ]
237- loadYamlFile path = do
238- eer <- Yaml. decodeFileEither path
239- case eer of
240- Right result -> return result
241- Left err -> errorExit $
242- " error loading " ++ path ++ " : " ++ Yaml. prettyPrintParseException err
256+ return qf
243257
244258------------------------------------------------------------------------------
245259-- $Template
@@ -361,54 +375,71 @@ build path = Proc.callProcess "xelatex" ["-halt-on-error", path]
361375------------------------------------------------------------------------------
362376-- $CLI
363377
364- -- | Display an error and exit the program
365- errorExit :: String -> IO a
366- errorExit msg = do
367- putStrLn $ " error: " ++ msg
368- exitFailure
378+ -- | Program options
379+ data Options
380+ = Options
381+ { optTemplate :: ! FilePath
382+ , optOutput :: ! (Maybe FilePath )
383+ , optQueues :: ! FilePath
384+ }
385+ deriving Show
369386
370- -- | CLI parser information
371- pinfo :: OA. ParserInfo FilePath
372- pinfo
373- = OA. info (LibOA. helper <*> LibOA. versioner version <*> queuesYaml )
387+ -- Parse program options
388+ parseOptions :: IO Options
389+ parseOptions = OA. execParser
390+ $ OA. info (LibOA. helper <*> LibOA. versioner version <*> options )
374391 $ mconcat
375392 [ OA. fullDesc
376393 , OA. progDesc " queue sheet utility"
377394 , OA. failureCode 2
378- , OA. footerDoc $ Just filesHelp
379395 ]
380396 where
381397 version :: String
382398 version = " queue-sheet-haskell " ++ showVersion Project. version
383399
384- queuesYaml :: OA. Parser FilePath
385- queuesYaml = OA. strArgument $ mconcat
386- [ OA. metavar " QUEUES.yaml"
387- , OA. help " YAML file specifying queue information"
400+ options :: OA. Parser Options
401+ options = Options
402+ <$> templateOption
403+ <*> optional outputOption
404+ <*> queuesArgument
405+
406+ templateOption :: OA. Parser FilePath
407+ templateOption = OA. strOption $ mconcat
408+ [ OA. long " template"
409+ , OA. short ' t'
410+ , OA. metavar " TEMPLATE.tex"
411+ , OA. value defaultTemplate
412+ , OA. showDefaultWith id
413+ , OA. help " template file"
388414 ]
389415
390- filesHelp :: Doc
391- filesHelp = LibOA. section " Files:" $ LibOA. table
392- [ (" sections.yaml" , " specify section names and order" )
393- , (" QUEUES.yaml" , " specify queues information" )
394- , (" template.tex" , " queue sheet template" )
395- , (" QUEUES.pdf" , " output queue sheet" )
416+ outputOption :: OA. Parser FilePath
417+ outputOption = OA. strOption $ mconcat
418+ [ OA. long " output"
419+ , OA. short ' o'
420+ , OA. metavar " QUEUES.pdf"
421+ , OA. help " output file"
422+ ]
423+
424+ queuesArgument :: OA. Parser FilePath
425+ queuesArgument = OA. strArgument $ mconcat
426+ [ OA. metavar " QUEUES.yaml"
427+ , OA. help " YAML file specifying queue information"
396428 ]
397429
398430-- | Main function
399431main :: IO ()
400432main = do
401- queuesYaml <- OA. execParser pinfo
402- sections <- loadSectionsYaml " sections.yaml"
403- queues <- loadQueuesYaml queuesYaml sections
404- template <- loadTemplate " template.tex"
405- exists <- doesPathExist buildDir
433+ Options {.. } <- parseOptions
434+ QueuesFile {.. } <- loadQueuesYaml optQueues
435+ template <- loadTemplate optTemplate
436+ exists <- doesPathExist buildDir
406437 when exists . errorExit $ " directory already exists: " ++ buildDir
407- let queuesTex = replaceExtension queuesYaml " tex "
408- queuesPdf = replaceExtension queuesYaml " pdf "
438+ let pdfFile = fromMaybe ( replaceExtension optQueues " pdf " ) optOutput
439+ texFile = replaceExtension pdfFile " tex "
409440 createDirectory buildDir
410441 withCurrentDirectory buildDir $ do
411- renderTemplate queuesTex template $ context sections queues
412- build queuesTex
413- renameFile (buildDir </> queuesPdf) queuesPdf
442+ renderTemplate texFile template $ context qfSections qfQueues
443+ build texFile
444+ renameFile (buildDir </> pdfFile) pdfFile
414445 removeDirectoryRecursive buildDir
0 commit comments