简体   繁体   中英

How do I use the output of readProcess in an xmonad keybinding?

Ok, so some time ago I was thinking of basing the effect of a keybinding in my xmonad based on the output of a script on my box. I eventually decided not to do that for unrelated reasons but I did recently try to do something similar just as an exercise in learning Haskell.

So, given the function:

test = readProcess "echo" ["-n", "gvim"] []

This throws up because test returns IO String and spawn expects a String.

((modm, xK_y), spawn ("xmessage " ++ test))

Ok. That's cool. I get it that IO operations are unpredictable and so they should be kept separate. Fine. So I did some poking around online and got to this (dropped the xmessage and just want to pass the output of test by itself):

((modm, xK_y), liftIO test >>= spawn)

This is worse. It annoyingly compiles but nothing happens when I try out the binding. (I also replaced it with just spawn "xmessage test" and that worked)

So, then I thought "Maybe there's something wrong with my function" so I repl it but from GCHi I get "gvim" which is correct. So then I write it to a haskell file:

main = test >>= putStrLn
test = readProcess "echo" ["-n", "gvim"] []

Also works correctly.

So, where did I go wrong?

EDIT: Solution was to use runProcessWithInput instead of readProcess . Related link: https://ghc.haskell.org/trac/ghc/ticket/5212 xmonad io binding not working

Update

Apparently the solution (see the comments below) is to use readProcessWithInput

Original Answer

You said that:

liftIO test >>= spawn

didn't work, but how about:

liftIO test >>= (\m -> spawn ("xmessage " ++ m))

Also note that the string returned by readProcess likely will have a newline at the end, and that may be affecting things.

Some more things to try in this vein:

return "gvim" >>= (\m -> spawn ("xmessage " ++ m))


import Data.Char

do { m <- liftIO test;  spawn ("xmessage " ++ (filter isAlpha m)) }

The first one should succeed since it is equivalent to spawn "xmessage grim" . The second one will strip any newlines (indeed, any non-letters) from the output of test .

Some further things which might shed light on what is going on:

  1. Create a script called /tmp/report with these contents:

     #!/bin/sh ( date; echo "/tmp/report was called with args" "$@") >> /tmp/output 
  2. Make /tmp/report executable.

  3. Run /tmp/report and verify that two lines was appended to /tmp/output
  4. In your monad config, make the action spawn "/tmp/report A" . Test the action by seeing if the expected line is appended to /tmp/output .
  5. Try making the monad action this:

     liftIO (readProcess "/tmp/report" ["B"] "") >> spawn "/tmp/report A" 

    (Note we are using >> here, not >>= .) When you trigger the action you should see a report line for the B call and also one for the A call.

Based on what you see in the file /tmp/output you should be able to determine whether the readProcess command is even being executed as well as the spawn command is triggering.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM