module Restyler.Config.Interpreter
    ( Interpreter(..)
    , readInterpreter
    )
where

import Restyler.Prelude

import Data.Aeson
import qualified Data.Text as T
import System.FilePath (takeFileName)

data Interpreter
    = Sh
    | Bash
    | Python
    | Ruby
    deriving (Interpreter -> Interpreter -> Bool
(Interpreter -> Interpreter -> Bool)
-> (Interpreter -> Interpreter -> Bool) -> Eq Interpreter
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Interpreter -> Interpreter -> Bool
$c/= :: Interpreter -> Interpreter -> Bool
== :: Interpreter -> Interpreter -> Bool
$c== :: Interpreter -> Interpreter -> Bool
Eq, Int -> Interpreter -> ShowS
[Interpreter] -> ShowS
Interpreter -> String
(Int -> Interpreter -> ShowS)
-> (Interpreter -> String)
-> ([Interpreter] -> ShowS)
-> Show Interpreter
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Interpreter] -> ShowS
$cshowList :: [Interpreter] -> ShowS
show :: Interpreter -> String
$cshow :: Interpreter -> String
showsPrec :: Int -> Interpreter -> ShowS
$cshowsPrec :: Int -> Interpreter -> ShowS
Show)

instance FromJSON Interpreter where
    parseJSON :: Value -> Parser Interpreter
parseJSON =
        String
-> (Text -> Parser Interpreter) -> Value -> Parser Interpreter
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText "Interpreter"
            ((Text -> Parser Interpreter) -> Value -> Parser Interpreter)
-> (Text -> Parser Interpreter) -> Value -> Parser Interpreter
forall a b. (a -> b) -> a -> b
$ (String -> Parser Interpreter)
-> (Interpreter -> Parser Interpreter)
-> Either String Interpreter
-> Parser Interpreter
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> Parser Interpreter
forall (m :: * -> *) a. MonadFail m => String -> m a
fail Interpreter -> Parser Interpreter
forall (f :: * -> *) a. Applicative f => a -> f a
pure
            (Either String Interpreter -> Parser Interpreter)
-> (Text -> Either String Interpreter)
-> Text
-> Parser Interpreter
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Either String Interpreter
intepreterFromString
            (String -> Either String Interpreter)
-> (Text -> String) -> Text -> Either String Interpreter
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
unpack

instance ToJSON Interpreter where
    -- N.B. this may not always work, but it works for now
    toJSON :: Interpreter -> Value
toJSON = Text -> Value
forall a. ToJSON a => a -> Value
toJSON (Text -> Value) -> (Interpreter -> Text) -> Interpreter -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
T.toLower (Text -> Text) -> (Interpreter -> Text) -> Interpreter -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Interpreter -> Text
forall a. Show a => a -> Text
tshow

readInterpreter :: Text -> Maybe Interpreter
readInterpreter :: Text -> Maybe Interpreter
readInterpreter contents :: Text
contents = do
    Text
line <- [Text] -> Maybe Text
forall a. [a] -> Maybe a
headMaybe ([Text] -> Maybe Text) -> [Text] -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Text -> [Text]
T.lines Text
contents
    String -> Maybe Interpreter
parseInterpreter (String -> Maybe Interpreter)
-> (Text -> String) -> Text -> Maybe Interpreter
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
unpack (Text -> Maybe Interpreter) -> Text -> Maybe Interpreter
forall a b. (a -> b) -> a -> b
$ Text -> Text
T.strip Text
line

-- | TODO: Megaparsec?
parseInterpreter :: String -> Maybe Interpreter
parseInterpreter :: String -> Maybe Interpreter
parseInterpreter ('#' : '!' : rest :: String
rest) =
    Either String Interpreter -> Maybe Interpreter
forall a b. Either a b -> Maybe b
hush (Either String Interpreter -> Maybe Interpreter)
-> Either String Interpreter -> Maybe Interpreter
forall a b. (a -> b) -> a -> b
$ String -> Either String Interpreter
intepreterFromString (String -> Either String Interpreter)
-> Either String String -> Either String Interpreter
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< case String -> [String]
words String
rest of
        [exec :: String
exec] -> String -> Either String String
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Either String String) -> String -> Either String String
forall a b. (a -> b) -> a -> b
$ ShowS
takeFileName String
exec
        ["/usr/bin/env", arg :: String
arg] -> String -> Either String String
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
arg
        _ -> String -> Either String String
forall a b. a -> Either a b
Left "Unexpected shebang length"

parseInterpreter _ = Maybe Interpreter
forall a. Maybe a
Nothing

intepreterFromString :: String -> Either String Interpreter
intepreterFromString :: String -> Either String Interpreter
intepreterFromString "sh" = Interpreter -> Either String Interpreter
forall a b. b -> Either a b
Right Interpreter
Sh
intepreterFromString "bash" = Interpreter -> Either String Interpreter
forall a b. b -> Either a b
Right Interpreter
Bash
intepreterFromString "python" = Interpreter -> Either String Interpreter
forall a b. b -> Either a b
Right Interpreter
Python
intepreterFromString "python2" = Interpreter -> Either String Interpreter
forall a b. b -> Either a b
Right Interpreter
Python
intepreterFromString "python2.7" = Interpreter -> Either String Interpreter
forall a b. b -> Either a b
Right Interpreter
Python
intepreterFromString "python3" = Interpreter -> Either String Interpreter
forall a b. b -> Either a b
Right Interpreter
Python
intepreterFromString "python3.6" = Interpreter -> Either String Interpreter
forall a b. b -> Either a b
Right Interpreter
Python
intepreterFromString "ruby" = Interpreter -> Either String Interpreter
forall a b. b -> Either a b
Right Interpreter
Ruby
intepreterFromString x :: String
x = String -> Either String Interpreter
forall a b. a -> Either a b
Left (String -> Either String Interpreter)
-> String -> Either String Interpreter
forall a b. (a -> b) -> a -> b
$ "Unknown executable: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
x