diff options
| author | John MacFarlane <[email protected]> | 2023-07-19 10:56:35 -0700 |
|---|---|---|
| committer | John MacFarlane <[email protected]> | 2023-07-19 11:56:58 -0700 |
| commit | bec5429e4f7180af135cabc2dc79b82a406a357d (patch) | |
| tree | 6d15a1e8c31931a57347881818b895ce2ad00b79 /src | |
| parent | 5b2128512df61085c4a0ae364030482f21626dc6 (diff) | |
Fix regression on short boolean arguments.
In 3.1.5 boolean arguments were allowed an optional argument
(true|false). This created a regression for uses of fused
short arguments, e.g. `-somyfile.html`, which was equivalent
to `-s -omyfile.html`, but now raised an error because
pandoc attempted to parse `o` as a boolean `true` or `false`.
This change adds a preprocessing step on the raw arguments
before they are sent to the option parser. In this preprocessing
step, `-somyfile.html` would be split into two arguments,
`-s` and `-omyfile.html`. The splitting happens when a
short boolean option is followed by another short option.
Closes #8956.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Text/Pandoc/App/CommandLineOptions.hs | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs index a4374478f..22e824ade 100644 --- a/src/Text/Pandoc/App/CommandLineOptions.hs +++ b/src/Text/Pandoc/App/CommandLineOptions.hs @@ -59,13 +59,14 @@ import Control.Monad.Except (ExceptT(..), runExceptT, throwError) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as B import qualified Data.Map as M +import qualified Data.Set as Set import qualified Data.Text as T import qualified Text.Pandoc.UTF8 as UTF8 parseOptions :: [OptDescr (Opt -> ExceptT OptInfo IO Opt)] -> Opt -> IO (Either OptInfo Opt) parseOptions options' defaults = do - rawArgs <- map UTF8.decodeArg <$> liftIO getArgs + rawArgs <- liftIO getArgs prg <- liftIO getProgName parseOptionsFromArgs options' defaults prg rawArgs @@ -74,7 +75,7 @@ parseOptionsFromArgs -> Opt -> String -> [String] -> IO (Either OptInfo Opt) parseOptionsFromArgs options' defaults prg rawArgs = do let (actions, args, unrecognizedOpts, errors) = - getOpt' Permute options' (map UTF8.decodeArg rawArgs) + getOpt' Permute options' (preprocessArgs rawArgs) let unknownOptionErrors = foldr (handleUnrecognizedOption . takeWhile (/= '=')) [] @@ -230,6 +231,37 @@ engines = map ("html",) htmlEngines ++ pdfEngines :: [String] pdfEngines = nubOrd $ map snd engines +-- For motivation see #8956. We want to allow things like `-si` without +-- causing the `i` to be parsed as an optional boolean argument of `-s`. +-- This is for backwards compatibility given the addition of optional +-- boolean arguments in #8879. +preprocessArgs :: [String] -> [String] +preprocessArgs [] = [] +preprocessArgs ("--":xs) = "--" : xs -- a bare '--' ends option parsing +preprocessArgs (('-':c:d:cs):xs) + | isShortBooleanOpt c + , isShortOpt d = splitArg (c:d:cs) ++ preprocessArgs xs +preprocessArgs (x:xs) = x : preprocessArgs xs + +isShortBooleanOpt :: Char -> Bool +isShortBooleanOpt = (`Set.member` shortBooleanOpts) + where + shortBooleanOpts = + Set.fromList [c | Option [c] _ (OptArg _ "true|false") _ <- options] + +isShortOpt :: Char -> Bool +isShortOpt = (`Set.member` shortOpts) + where + shortOpts = Set.fromList $ concat [cs | Option cs _ _ _ <- options] + +splitArg :: String -> [String] +splitArg (c:d:cs) + | isShortBooleanOpt c + , isShortOpt d + = ['-',c] : splitArg (d:cs) +splitArg (c:cs) = ['-':c:cs] +splitArg [] = [] + -- | A list of functions, each transforming the options data structure -- in response to a command-line option. options :: [OptDescr (Opt -> ExceptT OptInfo IO Opt)] |
