X-Git-Url: https://git.madduck.net/etc/awesome.git/blobdiff_plain/925c0276a567c35bb3cf140aedc368b9a6e152db..716595550f974afc115b492b6f9be6d048dbfca4:/asyncshell.lua

diff --git a/asyncshell.lua b/asyncshell.lua
index 36ccc47..61336db 100644
--- a/asyncshell.lua
+++ b/asyncshell.lua
@@ -2,80 +2,78 @@
 --[[
                                                   
      Licensed under GNU General Public License v2 
+      * (c) 2015, worron                          
       * (c) 2013, Alexander Yakushev              
                                                   
 --]]
 
 -- Asynchronous io.popen for Awesome WM.
--- How to use...
--- ...asynchronously:
--- asyncshell.request('wscript -Kiev', function(f) wwidget.text = f:read("*l") end)
--- ...synchronously
--- widget:set_text(asyncshell.demand('wscript -Kiev', 5):read("*l") or "Error")
+-- How to use:
+-- asyncshell.request('wscript -Kiev', function(output) wwidget.text = output end)
 
--- This is more cpu demanding, but makes things faster.
+-- Grab environment
+local awful = require('awful')
 
-local spawn = require('awful.util').spawn
+-- Avoid discrepancies across multiple shells
+awful.util.shell = '/bin/sh'
 
-asyncshell               = {}
-asyncshell.request_table = {}
-asyncshell.id_counter    = 0
-asyncshell.folder        = "/tmp/asyncshell"
-asyncshell.file_template = asyncshell.folder .. '/req'
+-- Initialize tables for module
+asyncshell = { request_table = {}, id_counter = 0 }
 
--- Create a directory for asynchell response files
-os.execute("mkdir -p " .. asyncshell.folder)
-
--- Returns next tag - unique identifier of the request
+-- Request counter
 local function next_id()
-   asyncshell.id_counter = (asyncshell.id_counter + 1) % 100000
-   return asyncshell.id_counter
+    asyncshell.id_counter = (asyncshell.id_counter + 1) % 10000
+    return asyncshell.id_counter
+end
+
+-- Remove given request
+function asyncshell.clear(id)
+    if asyncshell.request_table[id] then
+        if asyncshell.request_table[id].timer then
+            asyncshell.request_table[id].timer:stop()
+            asyncshell.request_table[id].timer = nil
+        end
+        asyncshell.request_table[id] = nil
+    end
 end
 
--- Sends an asynchronous request for an output of the shell command.
+-- Sends an asynchronous request for an output of the shell command
 -- @param command Command to be executed and taken output from
 -- @param callback Function to be called when the command finishes
--- @return Request ID
-function asyncshell.request(command, callback)
-   local id = next_id()
-   local tmpfname = asyncshell.file_template .. id
-   asyncshell.request_table[id] = { callback = callback }
-   local req =
-      string.format("sh -c '%s > %s; " ..
-                    'echo "asyncshell.deliver(%s)" | ' ..
-                    "awesome-client' 2> /dev/null",
-                    string.gsub(command, "'", "'\\''"), tmpfname, id)
-   spawn(req, false)
-   return id
-end
+-- @param timeout Maximum amount of time to wait for the result (optional)
+function asyncshell.request(command, callback, timeout)
+    local id = next_id()
+    asyncshell.request_table[id] = { callback = callback }
 
--- Calls the remembered callback function on the output of the shell
--- command.
--- @param id Request ID
--- @param output The output file of the shell command to be delievered
-function asyncshell.deliver(id)
-   if asyncshell.request_table[id] and
-      asyncshell.request_table[id].callback then
-      local output = io.open(asyncshell.file_template .. id, 'r')
-      asyncshell.request_table[id].callback(output)
-   end
+    local formatted_command = string.gsub(command, '"','\"')
+
+    local req = string.format(
+        "echo \"asyncshell.deliver(%s, [[\\\"$(%s)\\\"]])\" | awesome-client &",
+        id, formatted_command
+    )
+
+    if type(awful.spawn) == 'table' and awful.spawn.with_shell then
+        awful.spawn.with_shell(req)
+    else
+        awful.util.spawn_with_shell(req)
+    end
+
+    if timeout then
+        asyncshell.request_table[id].timer = timer({ timeout = timeout })
+        asyncshell.request_table[id].timer:connect_signal("timeout", function() asyncshell.clear(id) end)
+        asyncshell.request_table[id].timer:start()
+    end
 end
 
--- Sends a synchronous request for an output of the command. Waits for
--- the output, but if the given timeout expires returns nil.
--- @param command Command to be executed and taken output from
--- @param timeout Maximum amount of time to wait for the result
--- @return File handler on success, nil otherwise
-function asyncshell.demand(command, timeout)
-   local id = next_id()
-   local tmpfname = asyncshell.file_template .. id
-   local f = io.popen(string.format("(%s > %s; echo asyncshell_done) & " ..
-                                    "(sleep %s; echo asynchell_timeout)",
-                                    command, tmpfname, timeout))
-   local result = f:read("*line")
-   if result == "asyncshell_done" then
-      return io.open(tmpfname)
-   end
+-- Calls the remembered callback function on the output of the shell command
+-- @param id Request ID
+-- @param output Shell command output to be delievered
+function asyncshell.deliver(id, output)
+    local output = string.sub(output, 2, -2)
+    if asyncshell.request_table[id] then
+        asyncshell.request_table[id].callback(output)
+        asyncshell.clear(id)
+    end
 end
 
 return asyncshell