zim-to-markdown-0.3.0.2: src/ZimToMarkdown/Options.hs
-- | Command line parsing and usage messages.
module ZimToMarkdown.Options (
ConversionRequest (..),
InputPath (..),
Options (..),
OptionsError (..),
OutputPath (..),
helpText,
parseOptions,
renderOptionsError,
) where
import Data.Text (Text)
import Data.Text qualified as Text
import System.FilePath (FilePath)
import ZimToMarkdown.Domain (ConversionDirection (..))
-- | Path of the Zim page or notebook to read.
newtype InputPath = InputPath
{ unInputPath :: FilePath
}
deriving (Eq, Show)
-- | Path where the Markdown document or notebook is written.
newtype OutputPath = OutputPath
{ unOutputPath :: FilePath
}
deriving (Eq, Show)
-- | A conversion requested from the command line.
data ConversionRequest = ConversionRequest
{ conversionInput :: InputPath
, conversionOutput :: Maybe OutputPath
, conversionDirection :: ConversionDirection
}
deriving (Eq, Show)
-- | A command line action.
data Options
= ShowHelp
| ShowVersion
| Convert ConversionRequest
deriving (Eq, Show)
-- | A failure produced while interpreting the command line.
data OptionsError
= MissingInput
| UnknownOption Text
| MissingOptionValue Text
| UnexpectedArgument Text
| InvalidDirection Text
deriving (Eq, Show)
-- | Parses command line arguments without performing any input or output.
parseOptions :: [String] -> Either OptionsError Options
parseOptions arguments
| any (`elem` ["-h", "--help"]) arguments = Right ShowHelp
| any (`elem` ["-V", "--version"]) arguments = Right ShowVersion
| otherwise = Convert <$> parseConversion arguments
data PartialOptions = PartialOptions
{ partialInput :: Maybe FilePath
, partialOutput :: Maybe FilePath
, partialDirection :: ConversionDirection
}
emptyOptions :: PartialOptions
emptyOptions =
PartialOptions
{ partialInput = Nothing
, partialOutput = Nothing
, partialDirection = ZimToMarkdown
}
parseConversion :: [String] -> Either OptionsError ConversionRequest
parseConversion = go emptyOptions
where
go options [] =
case partialInput options of
Nothing -> Left MissingInput
Just path ->
Right
ConversionRequest
{ conversionInput = InputPath path
, conversionOutput = OutputPath <$> partialOutput options
, conversionDirection = partialDirection options
}
go _ ["--output"] = Left (MissingOptionValue "--output")
go _ ["-o"] = Left (MissingOptionValue "-o")
go _ ["--direction"] = Left (MissingOptionValue "--direction")
go _ ["-d"] = Left (MissingOptionValue "-d")
go options ("--output" : value : rest) =
go options{partialOutput = Just value} rest
go options ("-o" : value : rest) =
go options{partialOutput = Just value} rest
go options ("--direction" : value : rest) =
setDirection options value rest
go options ("-d" : value : rest) =
setDirection options value rest
go options (argument : rest)
| isOption argument = Left (UnknownOption (Text.pack argument))
| otherwise =
case partialInput options of
Nothing ->
go options{partialInput = Just argument} rest
Just _ -> Left (UnexpectedArgument (Text.pack argument))
setDirection options value rest =
case parseDirection value of
Nothing -> Left (InvalidDirection (Text.pack value))
Just direction ->
go options{partialDirection = direction} rest
isOption ('-' : _) = True
isOption _ = False
parseDirection :: String -> Maybe ConversionDirection
parseDirection value =
case value of
"zim-to-markdown" -> Just ZimToMarkdown
"markdown-to-zim" -> Just MarkdownToZim
_ -> Nothing
-- | Renders an option parsing failure as a user facing message.
renderOptionsError :: OptionsError -> Text
renderOptionsError optionsError =
case optionsError of
MissingInput -> "Missing input file or directory."
UnknownOption option -> "Unknown option: " <> option
MissingOptionValue option -> "Missing value for option: " <> option
UnexpectedArgument argument -> "Unexpected argument: " <> argument
InvalidDirection direction ->
"Invalid direction: "
<> direction
<> ". Use zim-to-markdown or markdown-to-zim."
-- | Command line usage description.
helpText :: Text
helpText =
Text.unlines
[ "zim-to-markdown - converts between Zim wiki and Markdown."
, ""
, "Usage:"
, " zim-to-markdown [--direction DIRECTION] [--output PATH] INPUT"
, " zim-to-markdown --help"
, " zim-to-markdown --version"
, ""
, "Options:"
, " -d, --direction DIRECTION zim-to-markdown (default) or markdown-to-zim."
, " -o, --output PATH Output file for a page; output directory for a notebook."
, " -h, --help Show this help."
, " -V, --version Show the application version."
, ""
, "A notebook is a directory, or a path to its notebook.zim file. Its"
, "page files are converted and its other files are copied, preserving"
, "the folder structure. Hidden files and symbolic links are skipped."
]