diff --git a/InvisiXML.cabal b/InvisiXML.cabal index 1a58dfd00da428a92032e35147fca8afca9ea9bf..857afc0da2839bcc67027de33e01e23a6397125f 100644 --- a/InvisiXML.cabal +++ b/InvisiXML.cabal @@ -36,9 +36,13 @@ library executable invisiXML main-is: Main.hs + other-modules: CLI + , Paths_InvisiXML build-depends: base >=4.12 && <4.15 + , filepath , InvisiXML , mtl + , optparse-applicative , text hs-source-dirs: app default-language: Haskell2010 diff --git a/app/CLI.hs b/app/CLI.hs new file mode 100644 index 0000000000000000000000000000000000000000..e549eaf54e599f57004c94d1181933419a20e251 --- /dev/null +++ b/app/CLI.hs @@ -0,0 +1,45 @@ +module CLI ( + Command(..) + , Input(..) + , getCommand + ) where + +import Data.Version (showVersion) +import Control.Applicative ((<*>), optional) +import Options.Applicative ( + Parser, ReadM, argument, execParser, fullDesc, header + , help, helper, info, long, metavar, option, short, str, switch, value + ) +import qualified Paths_InvisiXML as InvisiXML (version) + +data Input = StdIn | FileInput FilePath + +data Command = Command { + input :: Input + , outputPrefix :: Maybe FilePath + , pristine :: Bool + } + +inputArg :: ReadM Input +inputArg = fileOrStdIn <$> str + where + fileOrStdIn "-" = StdIn + fileOrStdIn f = FileInput f + +command :: Parser Command +command = Command + <$> argument inputArg (metavar "INPUT_FILE" <> value StdIn + <> help "XML file to process" + ) + <*> option (optional str) (short 'o' <> long "outputPrefix" <> value Nothing + <> help "prefix for the output files" + ) + <*> switch (short 'p' <> long "pristine" + <> help "keep input exactly as is, not unindenting or normalizing it in any way" + ) + +getCommand :: IO Command +getCommand = execParser $ + info + (helper <*> command) + (fullDesc <> header ("InvisiXML v" ++ showVersion InvisiXML.version)) diff --git a/app/Main.hs b/app/Main.hs index 214d1a3a88cea7d1df5987d623ea3c68ea4a0533..5f4032e967a4498ddc01b2b452d884e3412a91de 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -1,14 +1,31 @@ +{-# LANGUAGE NamedFieldPuns #-} module Main where - +import CLI (Command(..), Input(..), getCommand) import Control.Monad.Except (runExceptT) -import qualified Data.Text.IO as Text (putStr) +import Data.Maybe (fromMaybe) +import Data.Text (Text) +import qualified Data.Text.IO as Text (getContents, readFile, writeFile) import Text.InvisiXML (InvisiXML(..), parse) import Text.XML.Light.Serializer (encode) +import System.FilePath ((<.>), dropExtension) -main :: IO () -main = getContents >>= runExceptT . parse >>= either (fail . show) display +endPoints :: Command -> (IO Text, FilePath) +endPoints (Command {input = StdIn, outputPrefix}) = + (Text.getContents, fromMaybe noOutputPrefix outputPrefix) + where + noOutputPrefix = error "output prefix (-o) is necessary when running on stdin" +endPoints (Command {input = FileInput f, outputPrefix}) = + (Text.readFile f, fromMaybe (dropExtension f) outputPrefix) + +run :: Command -> IO () +run command = + source >>= runExceptT . parse >>= either (fail . show) create where - display result = do - Text.putStr $ text result - putStr . encode $ structure result + (source, prefix) = endPoints command + create (InvisiXML {text, structure}) = do + Text.writeFile (prefix <.> "txt") text + writeFile (prefix <.> "ixml") $ encode structure + +main :: IO () +main = getCommand >>= run