module XMonad.Util.Run (
runProcessWithInput,
runProcessWithInputAndWait,
safeSpawn,
safeSpawnProg,
unsafeSpawn,
runInTerm,
safeRunInTerm,
seconds,
spawnPipe,
spawnPipeWithLocaleEncoding,
spawnPipeWithUtf8Encoding,
spawnPipeWithNoEncoding,
hPutStr, hPutStrLn
) where
import Codec.Binary.UTF8.String
import System.Posix.IO
import System.Posix.Process (createSession, executeFile, forkProcess)
import Control.Concurrent (threadDelay)
import System.IO
import System.Process (runInteractiveProcess)
import XMonad
import XMonad.Prelude
runProcessWithInput :: MonadIO m => FilePath -> [String] -> String -> m String
runProcessWithInput :: FilePath -> [FilePath] -> FilePath -> m FilePath
runProcessWithInput FilePath
cmd [FilePath]
args FilePath
input = IO FilePath -> m FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO FilePath -> m FilePath) -> IO FilePath -> m FilePath
forall a b. (a -> b) -> a -> b
$ do
(Handle
pin, Handle
pout, Handle
perr, ProcessHandle
_) <- FilePath
-> [FilePath]
-> Maybe FilePath
-> Maybe [(FilePath, FilePath)]
-> IO (Handle, Handle, Handle, ProcessHandle)
runInteractiveProcess (FilePath -> FilePath
encodeString FilePath
cmd)
((FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map FilePath -> FilePath
encodeString [FilePath]
args) Maybe FilePath
forall a. Maybe a
Nothing Maybe [(FilePath, FilePath)]
forall a. Maybe a
Nothing
Handle -> FilePath -> IO ()
hPutStr Handle
pin FilePath
input
Handle -> IO ()
hClose Handle
pin
FilePath
output <- Handle -> IO FilePath
hGetContents Handle
pout
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (FilePath
output FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath
output) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Handle -> IO ()
hClose Handle
pout
Handle -> IO ()
hClose Handle
perr
FilePath -> IO FilePath
forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
output
runProcessWithInputAndWait :: MonadIO m => FilePath -> [String] -> String -> Int -> m ()
runProcessWithInputAndWait :: FilePath -> [FilePath] -> FilePath -> Int -> m ()
runProcessWithInputAndWait FilePath
cmd [FilePath]
args FilePath
input Int
timeout = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ do
ProcessID
_ <- IO () -> IO ProcessID
forall (m :: * -> *). MonadIO m => IO () -> m ProcessID
xfork (IO () -> IO ProcessID) -> IO () -> IO ProcessID
forall a b. (a -> b) -> a -> b
$ do
(Handle
pin, Handle
pout, Handle
perr, ProcessHandle
_) <- FilePath
-> [FilePath]
-> Maybe FilePath
-> Maybe [(FilePath, FilePath)]
-> IO (Handle, Handle, Handle, ProcessHandle)
runInteractiveProcess (FilePath -> FilePath
encodeString FilePath
cmd)
((FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map FilePath -> FilePath
encodeString [FilePath]
args) Maybe FilePath
forall a. Maybe a
Nothing Maybe [(FilePath, FilePath)]
forall a. Maybe a
Nothing
Handle -> FilePath -> IO ()
hPutStr Handle
pin FilePath
input
Handle -> IO ()
hFlush Handle
pin
Int -> IO ()
threadDelay Int
timeout
Handle -> IO ()
hClose Handle
pin
Handle -> IO ()
hClose Handle
pout
Handle -> IO ()
hClose Handle
perr
() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
seconds :: Rational -> Int
seconds :: Rational -> Int
seconds = Rational -> Int
forall a. Enum a => a -> Int
fromEnum (Rational -> Int) -> (Rational -> Rational) -> Rational -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Rational
1000000)
safeSpawn :: MonadIO m => FilePath -> [String] -> m ()
safeSpawn :: FilePath -> [FilePath] -> m ()
safeSpawn FilePath
prog [FilePath]
args = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ IO ProcessID -> IO ()
forall a. IO a -> IO ()
void_ (IO ProcessID -> IO ()) -> IO ProcessID -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ProcessID
forkProcess (IO () -> IO ProcessID) -> IO () -> IO ProcessID
forall a b. (a -> b) -> a -> b
$ do
IO ()
forall (m :: * -> *). MonadIO m => m ()
uninstallSignalHandlers
ProcessID
_ <- IO ProcessID
createSession
FilePath
-> Bool -> [FilePath] -> Maybe [(FilePath, FilePath)] -> IO ()
forall a.
FilePath
-> Bool -> [FilePath] -> Maybe [(FilePath, FilePath)] -> IO a
executeFile (FilePath -> FilePath
encodeString FilePath
prog) Bool
True ((FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map FilePath -> FilePath
encodeString [FilePath]
args) Maybe [(FilePath, FilePath)]
forall a. Maybe a
Nothing
where void_ :: IO a -> IO ()
void_ = (IO a -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())
safeSpawnProg :: MonadIO m => FilePath -> m ()
safeSpawnProg :: FilePath -> m ()
safeSpawnProg = (FilePath -> [FilePath] -> m ()) -> [FilePath] -> FilePath -> m ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip FilePath -> [FilePath] -> m ()
forall (m :: * -> *). MonadIO m => FilePath -> [FilePath] -> m ()
safeSpawn []
unsafeSpawn :: MonadIO m => String -> m ()
unsafeSpawn :: FilePath -> m ()
unsafeSpawn = FilePath -> m ()
forall (m :: * -> *). MonadIO m => FilePath -> m ()
spawn
unsafeRunInTerm, runInTerm :: String -> String -> X ()
unsafeRunInTerm :: FilePath -> FilePath -> X ()
unsafeRunInTerm FilePath
options FilePath
command = (XConf -> FilePath) -> X FilePath
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks (XConfig Layout -> FilePath
forall (l :: * -> *). XConfig l -> FilePath
terminal (XConfig Layout -> FilePath)
-> (XConf -> XConfig Layout) -> XConf -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. XConf -> XConfig Layout
config) X FilePath -> (FilePath -> X ()) -> X ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \FilePath
t -> FilePath -> X ()
forall (m :: * -> *). MonadIO m => FilePath -> m ()
unsafeSpawn (FilePath -> X ()) -> FilePath -> X ()
forall a b. (a -> b) -> a -> b
$ FilePath
t FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
options FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" -e " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
command
runInTerm :: FilePath -> FilePath -> X ()
runInTerm = FilePath -> FilePath -> X ()
unsafeRunInTerm
safeRunInTerm :: String -> String -> X ()
safeRunInTerm :: FilePath -> FilePath -> X ()
safeRunInTerm FilePath
options FilePath
command = (XConf -> FilePath) -> X FilePath
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks (XConfig Layout -> FilePath
forall (l :: * -> *). XConfig l -> FilePath
terminal (XConfig Layout -> FilePath)
-> (XConf -> XConfig Layout) -> XConf -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. XConf -> XConfig Layout
config) X FilePath -> (FilePath -> X ()) -> X ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \FilePath
t -> FilePath -> [FilePath] -> X ()
forall (m :: * -> *). MonadIO m => FilePath -> [FilePath] -> m ()
safeSpawn FilePath
t [FilePath
options, FilePath
" -e " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
command]
spawnPipe :: MonadIO m => String -> m Handle
spawnPipe :: FilePath -> m Handle
spawnPipe = FilePath -> m Handle
forall (m :: * -> *). MonadIO m => FilePath -> m Handle
spawnPipeWithLocaleEncoding
spawnPipeWithLocaleEncoding :: MonadIO m => String -> m Handle
spawnPipeWithLocaleEncoding :: FilePath -> m Handle
spawnPipeWithLocaleEncoding = TextEncoding -> FilePath -> m Handle
forall (m :: * -> *).
MonadIO m =>
TextEncoding -> FilePath -> m Handle
spawnPipe' TextEncoding
localeEncoding
spawnPipeWithUtf8Encoding :: MonadIO m => String -> m Handle
spawnPipeWithUtf8Encoding :: FilePath -> m Handle
spawnPipeWithUtf8Encoding = TextEncoding -> FilePath -> m Handle
forall (m :: * -> *).
MonadIO m =>
TextEncoding -> FilePath -> m Handle
spawnPipe' TextEncoding
utf8
spawnPipeWithNoEncoding :: MonadIO m => String -> m Handle
spawnPipeWithNoEncoding :: FilePath -> m Handle
spawnPipeWithNoEncoding = TextEncoding -> FilePath -> m Handle
forall (m :: * -> *).
MonadIO m =>
TextEncoding -> FilePath -> m Handle
spawnPipe' TextEncoding
char8
spawnPipe' :: MonadIO m => TextEncoding -> String -> m Handle
spawnPipe' :: TextEncoding -> FilePath -> m Handle
spawnPipe' TextEncoding
encoding FilePath
x = IO Handle -> m Handle
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO Handle -> m Handle) -> IO Handle -> m Handle
forall a b. (a -> b) -> a -> b
$ do
(Fd
rd, Fd
wr) <- IO (Fd, Fd)
createPipe
Fd -> FdOption -> Bool -> IO ()
setFdOption Fd
wr FdOption
CloseOnExec Bool
True
Handle
h <- Fd -> IO Handle
fdToHandle Fd
wr
Handle -> TextEncoding -> IO ()
hSetEncoding Handle
h TextEncoding
encoding
Handle -> BufferMode -> IO ()
hSetBuffering Handle
h BufferMode
LineBuffering
ProcessID
_ <- IO () -> IO ProcessID
forall (m :: * -> *). MonadIO m => IO () -> m ProcessID
xfork (IO () -> IO ProcessID) -> IO () -> IO ProcessID
forall a b. (a -> b) -> a -> b
$ do
Fd
_ <- Fd -> Fd -> IO Fd
dupTo Fd
rd Fd
stdInput
FilePath
-> Bool -> [FilePath] -> Maybe [(FilePath, FilePath)] -> IO ()
forall a.
FilePath
-> Bool -> [FilePath] -> Maybe [(FilePath, FilePath)] -> IO a
executeFile FilePath
"/bin/sh" Bool
False [FilePath
"-c", FilePath -> FilePath
encodeString FilePath
x] Maybe [(FilePath, FilePath)]
forall a. Maybe a
Nothing
Fd -> IO ()
closeFd Fd
rd
Handle -> IO Handle
forall (m :: * -> *) a. Monad m => a -> m a
return Handle
h