]> git.lizzy.rs Git - bspwm.git/blob - contrib/rules/ruld
Externalize rules
[bspwm.git] / contrib / rules / ruld
1 #! /usr/bin/env lua
2
3 local p = require("posix")
4 local port = 54321
5
6 local short = "hp:"
7 local long = {
8     {"help", "none", 'h'},
9     {"port", "required", 'p'},
10 }
11
12 local rules = {
13     {'type:find("toolbar") or type:find("utility")', 'focus=off'},
14     {'type:find("dialog")', 'floating=on'},
15     {'type:find("dock") or type:find("desktop") or type:find("notification")', 'manage=off'},
16     {'type:find("desktop")', 'lower=on'},
17     {'state:find("fullscreen")', 'fullscreen=on'},
18     {'state:find("sticky")', 'sticky=on'}
19 }
20
21 for opt, optarg, optind, longind in p.getopt(arg, short, long) do
22     if opt == '?' then
23         print("Unrecognized option")
24         os.exit(1)
25     elseif opt == 'h' then
26         print("Usage: ruld [-h|-p PORT]")
27         os.exit(0)
28     elseif opt == 'p' then
29         port = optarg
30     end
31 end
32
33 function eval(exp, env)
34     local f
35     local value = "return " .. exp
36     if env then
37         f = load(value, nil, nil, env)
38     else
39         f = load(value)
40     end
41     return f and f()
42 end
43
44 function test(env)
45     local rsp = ""
46     for index = #rules, 1, -1 do
47         local entry = rules[index]
48         if eval(entry[1], env) then
49             local delay, duration
50             if entry[3] then
51                 delay = entry[3].delay
52                 duration = entry[3].duration
53                 if delay and delay > 0 then
54                     entry[3].delay = delay - 1
55                 end
56                 if ((not delay) or delay == 0) and duration and duration > 0 then
57                     entry[3].duration = duration - 1
58                 end
59             end
60             if (((not delay) or delay == 0) and ((not duration) or duration > 0)) then
61                 if #rsp > 0 then
62                     rsp = rsp .. " " .. entry[2]
63                 else
64                     rsp = entry[2]
65                 end
66             end
67             if duration and duration <= 1 then
68                 table.remove(rules, index)
69             end
70         end
71     end
72     return rsp
73 end
74
75 local fd = p.socket(p.AF_INET, p.SOCK_STREAM, 0)
76 p.bind(fd, {family=p.AF_INET, addr="127.0.0.1", port=port})
77 p.listen(fd, p.SOMAXCONN)
78 local running = true
79
80 while running do
81     ret_fd = p.accept(fd)
82     if ret_fd then
83         local msg = p.recv(ret_fd, p.BUFSIZ)
84         if msg then
85             local cmd, data = nil
86             sep = msg:find(" ")
87             if sep then
88                 cmd = msg:sub(1, sep - 1)
89                 data = msg:sub(sep + 1)
90             else
91                 cmd = msg
92             end
93             if cmd == "test" then
94                 local env = eval(data)
95                 if env then
96                     rsp = test(env)
97                     p.send(ret_fd, rsp)
98                 end
99             elseif cmd == "add" then
100                 local value = eval(data)
101                 if value then
102                     table.insert(rules, value)
103                 end
104             elseif cmd == "remove" then
105                 if data == "tail" then
106                     table.remove(rules, #rules)
107                 elseif data == "head" then
108                     table.remove(rules, 1)
109                 else
110                     for index = #rules, 1, -1 do
111                         if rules[index][1]:find(data) then
112                             table.remove(rules, index)
113                         end
114                     end
115                 end
116             elseif cmd == "quit" then
117                 running = false
118             elseif cmd == "list" then
119                 local rsp = ""
120                 for index, entry in pairs(rules) do
121                     rsp = rsp .. string.format("%s => %s", entry[1], entry[2])
122                     if entry[3] then
123                         if entry[3].delay then
124                             rsp = rsp .. string.format(" @%i", entry[3].delay)
125                         end
126                         if entry[3].duration then
127                             rsp = rsp .. string.format(" +%i", entry[3].duration)
128                         end
129                     end
130                     if index < #rules then
131                         rsp = rsp .. "\n"
132                     end
133                 end
134                 p.send(ret_fd, rsp)
135             end
136         end
137         p.close(ret_fd)
138     end
139 end
140
141 p.close(fd)