{-# LANGUAGE NoImplicitPrelude #-} -- | Description: interpret flags parsed by "IHaskell.Flags" module IHaskell.Convert.Args (ConvertSpec(..), fromJustConvertSpec, toConvertSpec) where import IHaskellPrelude import qualified Data.Text.Lazy as LT import Data.Functor.Identity (Identity(Identity)) import Data.Char (toLower) import IHaskell.Flags (Argument(..), LhsStyle, lhsStyleBird, NotebookFormat(..)) import System.FilePath ((<.>), dropExtension, takeExtension) -- | ConvertSpec is the accumulator for command line arguments data ConvertSpec f = ConvertSpec { convertToIpynb :: f Bool , convertInput :: f FilePath , convertOutput :: f FilePath , convertLhsStyle :: f (LhsStyle LT.Text) , convertOverwriteFiles :: Bool } -- | Convert a possibly-incomplete specification for what to convert into one which can be executed. -- Calls error when data is missing. fromJustConvertSpec :: ConvertSpec Maybe -> ConvertSpec Identity fromJustConvertSpec convertSpec = convertSpec { convertToIpynb = Identity toIpynb , convertInput = Identity inputFile , convertOutput = Identity outputFile , convertLhsStyle = Identity $ fromMaybe (LT.pack <$> lhsStyleBird) (convertLhsStyle convertSpec) } where toIpynb = fromMaybe (error "fromJustConvertSpec: direction for conversion unknown") (convertToIpynb convertSpec) (inputFile, outputFile) = case (convertInput convertSpec, convertOutput convertSpec) of (Nothing, Nothing) -> error "fromJustConvertSpec: no files specified for conversion" (Just i, Nothing) | toIpynb -> (i, dropExtension i <.> "ipynb") | otherwise -> (i, dropExtension i <.> "lhs") (Nothing, Just o) | toIpynb -> (dropExtension o <.> "lhs", o) | otherwise -> (dropExtension o <.> "ipynb", o) (Just i, Just o) -> (i, o) -- | Does this @Argument@ explicitly request a file format? isFormatSpec :: Argument -> Bool isFormatSpec (ConvertToFormat _) = True isFormatSpec (ConvertFromFormat _) = True isFormatSpec _ = False toConvertSpec :: [Argument] -> ConvertSpec Maybe toConvertSpec args = mergeArgs otherArgs (mergeArgs formatSpecArgs initialConvertSpec) where (formatSpecArgs, otherArgs) = partition isFormatSpec args initialConvertSpec = ConvertSpec Nothing Nothing Nothing Nothing False mergeArgs :: [Argument] -> ConvertSpec Maybe -> ConvertSpec Maybe mergeArgs args initialConvertSpec = foldr mergeArg initialConvertSpec args mergeArg :: Argument -> ConvertSpec Maybe -> ConvertSpec Maybe mergeArg OverwriteFiles convertSpec = convertSpec { convertOverwriteFiles = True } mergeArg (ConvertLhsStyle lhsStyle) convertSpec | Just previousLhsStyle <- convertLhsStyle convertSpec, previousLhsStyle /= fmap LT.pack lhsStyle = error $ printf "Conflicting lhs styles requested: <%s> and <%s>" (show lhsStyle) (show previousLhsStyle) | otherwise = convertSpec { convertLhsStyle = Just (LT.pack <$> lhsStyle) } mergeArg (ConvertFrom inputFile) convertSpec | Just previousInputFile <- convertInput convertSpec, previousInputFile /= inputFile = error $ printf "Multiple input files specified: <%s> and <%s>" inputFile previousInputFile | otherwise = convertSpec { convertInput = Just inputFile , convertToIpynb = case (convertToIpynb convertSpec, fromExt inputFile) of (prev, Nothing) -> prev (prev@(Just _), _) -> prev (Nothing, format) -> fmap (== LhsMarkdown) format } mergeArg (ConvertTo outputFile) convertSpec | Just previousOutputFile <- convertOutput convertSpec, previousOutputFile /= outputFile = error $ printf "Multiple output files specified: <%s> and <%s>" outputFile previousOutputFile | otherwise = convertSpec { convertOutput = Just outputFile , convertToIpynb = case (convertToIpynb convertSpec, fromExt outputFile) of (prev, Nothing) -> prev (prev@(Just _), _) -> prev (Nothing, format) -> fmap (== IpynbFile) format } mergeArg (ConvertToFormat format) convertSpec = case format of LhsMarkdown -> convertSpec { convertToIpynb = Just False } IpynbFile -> convertSpec { convertToIpynb = Just True } mergeArg (ConvertFromFormat format) convertSpec = case format of LhsMarkdown -> convertSpec { convertToIpynb = Just True } IpynbFile -> convertSpec { convertToIpynb = Just False } mergeArg unexpectedArg _ = error $ "IHaskell.Convert.mergeArg: impossible argument: " ++ show unexpectedArg -- | Guess the format based on the file extension. fromExt :: FilePath -> Maybe NotebookFormat fromExt s = case map toLower (takeExtension s) of ".lhs" -> Just LhsMarkdown ".ipynb" -> Just IpynbFile _ -> Nothing