{-# LANGUAGE OverloadedStrings #-} module MdBlocks.CLI where import qualified Data.Aeson.Encode.Pretty as JSON import qualified Data.ByteString.Lazy.Char8 as BL import qualified Data.Text.IO as T import Options.Applicative import MdBlocks.Address import MdBlocks.Repository import MdBlocks.Resolver import MdBlocks.Types data Command = List FilePath | Extract String | ShowMeta String runCLI :: IO () runCLI = execParser opts >>= run where opts = info (parser <**> helper) (fullDesc <> progDesc "Parse and extract Markdown blocks") parser :: Parser Command parser = listP <|> extractP <|> showP listP :: Parser Command listP = List <$> strOption ( long "list" <> metavar "FILE" <> help "List blocks in a Markdown file" ) extractP :: Parser Command extractP = Extract <$> strOption ( long "extract" <> metavar "FILE#ID" <> help "Extract a block by its address" ) showP :: Parser Command showP = ShowMeta <$> strOption ( long "show" <> metavar "FILE#ID" <> help "Show block metadata" ) run :: Command -> IO () run (List fp) = do bs <- loadBlocks fp BL.putStrLn $ JSON.encodePretty bs run (Extract rawAddr) = case parseAddress rawAddr of Left err -> failWith err Right addr -> extractBlock addr run (ShowMeta addr) = putStrLn ("show not implemented yet: " ++ addr) extractBlock :: Address -> IO () extractBlock addr = do let fp = case addr of FileAddress file _ -> file GlobalId _ -> error "global block addresses are not supported by --extract" blocks <- loadBlocks fp case resolveBlock addr blocks of Nothing -> failWith ("block not found: " ++ showAddress addr) Just block -> T.putStr (blockContent block) failWith :: String -> IO () failWith msg = do putStrLn ("mdblocks: " ++ msg) fail msg showAddress :: Address -> String showAddress (GlobalId ident) = "#" ++ show ident showAddress (FileAddress fp ident) = fp ++ "#" ++ show ident