1 -- Asynchronous io.popen for Awesome WM.
 
   4 -- asyncshell.request('wscript -Kiev', function(f) wwidget.text = f:read("*l") end)
 
   6 -- wwidget.text = asyncshell.demand('wscript -Kiev', 5):read("*l") or "Error"
 
   8 local awful = require('awful')
 
  11 asyncshell.request_table = {}
 
  12 asyncshell.id_counter = 0
 
  13 asyncshell.folder = "/tmp/asyncshell"
 
  14 asyncshell.file_template = asyncshell.folder .. '/req'
 
  16 -- Create a directory for asynchell response files
 
  17 os.execute("mkdir -p " .. asyncshell.folder)
 
  19 -- Returns next tag - unique identifier of the request
 
  20 local function next_id()
 
  21    asyncshell.id_counter = (asyncshell.id_counter + 1) % 100000
 
  22    return asyncshell.id_counter
 
  25 -- Sends an asynchronous request for an output of the shell command.
 
  26 -- @param command Command to be executed and taken output from
 
  27 -- @param callback Function to be called when the command finishes
 
  29 function asyncshell.request(command, callback)
 
  31    local tmpfname = asyncshell.file_template .. id
 
  32    asyncshell.request_table[id] = {callback = callback}
 
  34       string.format("bash -c '%s > %s; " ..
 
  35                     'echo "asyncshell.deliver(%s)" | ' ..
 
  36                     "awesome-client' 2> /dev/null",
 
  37                  string.gsub(command, "'", "'\\''"), tmpfname, id, tmpfname)
 
  38    awful.util.spawn(req, false)
 
  42 -- Calls the remembered callback function on the output of the shell
 
  44 -- @param id Request ID
 
  45 -- @param output The output file of the shell command to be delievered
 
  46 function asyncshell.deliver(id)
 
  47    if asyncshell.request_table[id] and
 
  48       asyncshell.request_table[id].callback then
 
  49       local output = io.open(asyncshell.file_template .. id, 'r')
 
  50       asyncshell.request_table[id].callback(output)
 
  54 -- Sends a synchronous request for an output of the command. Waits for
 
  55 -- the output, but if the given timeout expires returns nil.
 
  56 -- @param command Command to be executed and taken output from
 
  57 -- @param timeout Maximum amount of time to wait for the result
 
  58 -- @return File handler on success, nil otherwise
 
  59 function asyncshell.demand(command, timeout)
 
  61    local tmpfname = asyncshell.file_template .. id
 
  62    local f = io.popen(string.format("(%s > %s; echo asyncshell_done) & " ..
 
  63                                     "(sleep %s; echo asynchell_timeout)",
 
  64                                     command, tmpfname, timeout))
 
  65    local result = f:read("*line")
 
  66    if result == "asyncshell_done" then
 
  67       return io.open(tmpfname)