{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE RecordWildCards #-}

module Emanote.CLI
  ( Cli (..),
    Cmd (..),
    parseCli,
    cliParser,
  )
where

import Data.Text qualified as T
import Data.Version (showVersion)
import Ema.CLI qualified
import Options.Applicative hiding (action)
import Paths_emanote qualified
import Relude
import UnliftIO.Directory (getCurrentDirectory)

data Cli = Cli
  { Cli -> NonEmpty String
layers :: NonEmpty FilePath,
    Cli -> Bool
allowBrokenLinks :: Bool,
    Cli -> Cmd
cmd :: Cmd
  }

data Cmd
  = Cmd_Ema Ema.CLI.Cli
  | Cmd_Export

cliParser :: FilePath -> Parser Cli
cliParser :: String -> Parser Cli
cliParser String
cwd = do
  NonEmpty String
layers <- NonEmpty String -> Parser (NonEmpty String)
pathList (OneItem (NonEmpty String) -> NonEmpty String
forall x. One x => OneItem x -> x
one String
OneItem (NonEmpty String)
cwd)
  Bool
allowBrokenLinks <- Mod FlagFields Bool -> Parser Bool
switch (String -> Mod FlagFields Bool
forall (f :: Type -> Type) a. HasName f => String -> Mod f a
long String
"allow-broken-links" Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: Type -> Type) a. String -> Mod f a
help String
"Report but do not fail on broken links")
  Cmd
cmd <-
    (Cli -> Cmd) -> Parser Cli -> Parser Cmd
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap Cli -> Cmd
Cmd_Ema Parser Cli
Ema.CLI.cliParser
      Parser Cmd -> Parser Cmd -> Parser Cmd
forall (f :: Type -> Type) a. Alternative f => f a -> f a -> f a
<|> Mod CommandFields Cmd -> Parser Cmd
forall a. Mod CommandFields a -> Parser a
subparser (String -> ParserInfo Cmd -> Mod CommandFields Cmd
forall a. String -> ParserInfo a -> Mod CommandFields a
command String
"export" (Parser Cmd -> InfoMod Cmd -> ParserInfo Cmd
forall a. Parser a -> InfoMod a -> ParserInfo a
info (Cmd -> Parser Cmd
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Cmd
Cmd_Export) (String -> InfoMod Cmd
forall a. String -> InfoMod a
progDesc String
"Export metadata JSON")))
  pure Cli :: NonEmpty String -> Bool -> Cmd -> Cli
Cli {Bool
NonEmpty String
Cmd
cmd :: Cmd
allowBrokenLinks :: Bool
layers :: NonEmpty String
cmd :: Cmd
allowBrokenLinks :: Bool
layers :: NonEmpty String
..}
  where
    pathList :: NonEmpty String -> Parser (NonEmpty String)
pathList NonEmpty String
defaultPath = do
      ReadM (NonEmpty String)
-> Mod OptionFields (NonEmpty String) -> Parser (NonEmpty String)
forall a. ReadM a -> Mod OptionFields a -> Parser a
option ReadM (NonEmpty String)
pathListReader (Mod OptionFields (NonEmpty String) -> Parser (NonEmpty String))
-> Mod OptionFields (NonEmpty String) -> Parser (NonEmpty String)
forall a b. (a -> b) -> a -> b
$
        [Mod OptionFields (NonEmpty String)]
-> Mod OptionFields (NonEmpty String)
forall a. Monoid a => [a] -> a
mconcat
          [ String -> Mod OptionFields (NonEmpty String)
forall (f :: Type -> Type) a. HasName f => String -> Mod f a
long String
"layers",
            Char -> Mod OptionFields (NonEmpty String)
forall (f :: Type -> Type) a. HasName f => Char -> Mod f a
short Char
'L',
            String -> Mod OptionFields (NonEmpty String)
forall (f :: Type -> Type) a. HasMetavar f => String -> Mod f a
metavar String
"LAYERS",
            NonEmpty String -> Mod OptionFields (NonEmpty String)
forall (f :: Type -> Type) a. HasValue f => a -> Mod f a
value NonEmpty String
defaultPath,
            String -> Mod OptionFields (NonEmpty String)
forall (f :: Type -> Type) a. String -> Mod f a
help String
"List of (semicolon delimited) notebook folders to 'union mount', with the left-side folders being overlaid on top of the right-side ones. The default layer is implicitly included at the end of this list."
          ]
    pathListReader :: ReadM (NonEmpty FilePath)
    pathListReader :: ReadM (NonEmpty String)
pathListReader =
      (String -> Maybe (NonEmpty String)) -> ReadM (NonEmpty String)
forall a. (String -> Maybe a) -> ReadM a
maybeReader ((String -> Maybe (NonEmpty String)) -> ReadM (NonEmpty String))
-> (String -> Maybe (NonEmpty String)) -> ReadM (NonEmpty String)
forall a b. (a -> b) -> a -> b
$ \String
paths ->
        [String] -> Maybe (NonEmpty String)
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty ([String] -> Maybe (NonEmpty String))
-> [String] -> Maybe (NonEmpty String)
forall a b. (a -> b) -> a -> b
$ (Text -> String) -> [Text] -> [String]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> String
forall a. ToString a => a -> String
toString ([Text] -> [String]) -> [Text] -> [String]
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Text -> [Text]
T.split (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
';') (Text -> [Text]) -> (String -> Text) -> String -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a. ToText a => a -> Text
toText (String -> [Text]) -> String -> [Text]
forall a b. (a -> b) -> a -> b
$ String
paths

parseCli' :: FilePath -> ParserInfo Cli
parseCli' :: String -> ParserInfo Cli
parseCli' String
cwd =
  Parser Cli -> InfoMod Cli -> ParserInfo Cli
forall a. Parser a -> InfoMod a -> ParserInfo a
info
    (Parser (Cli -> Cli)
forall {a}. Parser (a -> a)
versionOption Parser (Cli -> Cli) -> Parser Cli -> Parser Cli
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> String -> Parser Cli
cliParser String
cwd Parser Cli -> Parser (Cli -> Cli) -> Parser Cli
forall (f :: Type -> Type) a b.
Applicative f =>
f a -> f (a -> b) -> f b
<**> Parser (Cli -> Cli)
forall {a}. Parser (a -> a)
helper)
    ( InfoMod Cli
forall a. InfoMod a
fullDesc
        InfoMod Cli -> InfoMod Cli -> InfoMod Cli
forall a. Semigroup a => a -> a -> a
<> String -> InfoMod Cli
forall a. String -> InfoMod a
progDesc String
"Emanote - A spiritual successor to Neuron"
        InfoMod Cli -> InfoMod Cli -> InfoMod Cli
forall a. Semigroup a => a -> a -> a
<> String -> InfoMod Cli
forall a. String -> InfoMod a
header String
"Emanote"
    )
  where
    versionOption :: Parser (a -> a)
versionOption =
      String -> Mod OptionFields (a -> a) -> Parser (a -> a)
forall a. String -> Mod OptionFields (a -> a) -> Parser (a -> a)
infoOption
        (Version -> String
showVersion Version
Paths_emanote.version)
        (String -> Mod OptionFields (a -> a)
forall (f :: Type -> Type) a. HasName f => String -> Mod f a
long String
"version" Mod OptionFields (a -> a)
-> Mod OptionFields (a -> a) -> Mod OptionFields (a -> a)
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields (a -> a)
forall (f :: Type -> Type) a. String -> Mod f a
help String
"Show version")

parseCli :: IO Cli
parseCli :: IO Cli
parseCli =
  ParserInfo Cli -> IO Cli
forall a. ParserInfo a -> IO a
execParser (ParserInfo Cli -> IO Cli)
-> (String -> ParserInfo Cli) -> String -> IO Cli
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ParserInfo Cli
parseCli' (String -> IO Cli) -> IO String -> IO Cli
forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO String
forall (m :: Type -> Type). MonadIO m => m String
getCurrentDirectory