{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Kleene.Type.Examples.KleeneSH (
ls_,
LS,
find_,
FIND, FIND', TYPES,
#ifdef KLEENE_TOP
true_,
TRUE,
#endif
command,
Flag,
ToArg (..),
module Kleene.Type,
) where
import Data.Either (partitionEithers)
import Data.Proxy (Proxy (..))
import GHC.TypeLits (KnownSymbol)
import Kleene.Type
import System.Process (readProcess)
ls_ :: REList LS -> IO ()
ls_ = command "ls"
type LS = S (V FilePath \/ Flag "l" \/ Flag "h")
#ifdef KLEENE_TOP
true_ :: REList TRUE -> IO ()
true_ = command "true"
type TRUE = T
#endif
find_ :: REList FIND -> IO ()
find_ (REList match argv) = do
putStrLn $ ">>> " ++ cmd ++ " " ++ unwords args
out <- readProcess cmd args ""
putStr out
where
cmd = "find"
args = fromFindArgs fargs
fargs = map f (haskelly match argv)
f (Left fp) = FindDir fp
f (Right (Left (Key, fp))) = FindName fp
f (Right (Right (Key, Right Key))) = FindType "d"
f (Right (Right (Key, Left Key))) = FindType "f"
data FindArg
= FindDir FilePath
| FindName String
| FindType String
fromFindArgs :: [FindArg] -> [String]
fromFindArgs fargs = dirs ++ concat args where
(dirs, args) = partitionEithers (fmap f fargs)
f (FindDir d) = Left d
f (FindName n) = Right ["-name", n]
f (FindType d) = Right ["-type", d]
type FIND = S FIND'
type FIND' = V FilePath \/ Flag "name" <> V FilePath \/ Flag "type" <> TYPES
type TYPES = Flag "d" \/ Flag "f"
type Flag s = V (Key s)
command
:: forall re. REInductionC ToArg re
=> FilePath
-> REList re
-> IO ()
command cmd (REList match argv) = do
putStrLn $ ">>> " ++ cmd ++ " " ++ unwords (flags ++ args)
out <- readProcess cmd (flags ++ args) ""
putStr out
where
(flags, args) = partitionEithers $ unAux (reInductionC (Proxy :: Proxy ToArg)
e v a l r n c
#ifdef KLEENE_TOP
top
#endif
match)
argv
e = Aux $ \Nil -> []
v :: ToArg x => Aux '[x]
v = Aux $ \(x ::: Nil) -> [toArg x]
a xs' f g = Aux $ \zs -> case split xs' zs of
(xs, ys) -> unAux f xs ++ unAux g ys
l = id
r = id
n = e
c = a
#ifdef KLEENE_TOP
top _ = Aux $ const []
#endif
newtype Aux xs = Aux { unAux :: HList xs -> [Either String String] }
class ToArg a where
toArg :: a -> Either String String
instance c ~ Char => ToArg [c] where
toArg = Right
instance KnownSymbol s => ToArg (Key s) where
toArg = Left . ('-' :) . keyVal