From 5d8c72952ee17bd843b11aaab4831ccefe4f4b46 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 22 May 2009 15:32:32 -0400 Subject: [PATCH] Make python wmiirc's event matching a bit more powerful. --- alternative_wmiircs/python/pygmi/__init__.py | 41 +------- alternative_wmiircs/python/pygmi/events.py | 44 +++++++-- alternative_wmiircs/python/pygmi/fs.py | 32 +------ alternative_wmiircs/python/pygmi/menu.py | 2 +- alternative_wmiircs/python/pygmi/monitor.py | 4 +- alternative_wmiircs/python/pygmi/util.py | 52 +++++++++++ .../python/pyxp/asyncclient.py | 92 ++++++++---------- alternative_wmiircs/python/pyxp/client.py | 93 +++++++++---------- alternative_wmiircs/python/wmiirc.py | 44 ++++----- 9 files changed, 207 insertions(+), 197 deletions(-) create mode 100644 alternative_wmiircs/python/pygmi/util.py diff --git a/alternative_wmiircs/python/pygmi/__init__.py b/alternative_wmiircs/python/pygmi/__init__.py index 8f75fd67..540a3245 100644 --- a/alternative_wmiircs/python/pygmi/__init__.py +++ b/alternative_wmiircs/python/pygmi/__init__.py @@ -8,53 +8,20 @@ if 'WMII_ADDRESS' in os.environ: else: client = Client(namespace='wmii') -def call(*args, **kwargs): - background = kwargs.pop('background', False) - input = kwargs.pop('input', None) - import subprocess - p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, cwd=os.environ['HOME'], - **kwargs) - if not background: - return p.communicate(input)[0].rstrip('\n') - -def program_list(path): - names = [] - for d in path: - try: - for f in os.listdir(d): - if f not in names and os.access('%s/%s' % (d, f), - os.X_OK): - names.append(f) - except Exception: - pass - return sorted(names) - -def curry(func, *args, **kwargs): - def curried(*newargs, **newkwargs): - return func(*(args + newargs), **dict(kwargs, **newkwargs)) - curried.__name__ = func.__name__ + '__curried__' - return curried - -def find_script(name): - for path in confpath: - if os.access('%s/%s' % (path, name), os.X_OK): - return '%s/%s' % (path, name) - confpath = os.environ.get('WMII_CONFPATH', '%s/.wmii' % os.environ['HOME']).split(':') shell = os.environ['SHELL'] sys.path += confpath -from pygmi import events, fs, menu, monitor +from pygmi.util import * from pygmi.events import * from pygmi.fs import * from pygmi.menu import * from pygmi.monitor import * +from pygmi import util, events, fs, menu, monitor __all__ = (fs.__all__ + monitor.__all__ + events.__all__ + - menu.__all__ + ( - 'client', 'call', 'curry', 'program_list', - 'find_script', 'confpath', 'shell')) + menu.__all__ + util.__all__ + + ('client', 'confpath', 'shell')) # vim:se sts=4 sw=4 et: diff --git a/alternative_wmiircs/python/pygmi/events.py b/alternative_wmiircs/python/pygmi/events.py index 40c3e311..1805d623 100644 --- a/alternative_wmiircs/python/pygmi/events.py +++ b/alternative_wmiircs/python/pygmi/events.py @@ -4,17 +4,40 @@ import sys import traceback import pygmi -from pygmi import monitor, client, call, program_list +from pygmi import monitor, client, curry, call, program_list, _ __all__ = ('bind_keys', 'bind_events', 'toggle_keys', 'event_loop', - 'event') + 'event', 'Match') keydefs = {} keys = {} events = {} +eventmatchers = {} alive = True +class Match(object): + def __init__(self, *args): + self.args = args + self.matchers = [] + for a in args: + if a is _: + a = lambda k: True + elif isinstance(a, basestring): + a = a.__eq__ + elif isinstance(a, (list, tuple)): + a = curry(lambda ary, k: k in ary, a) + elif hasattr(a, 'search'): + a = a.search + else: + a = str(a).__eq__ + self.matchers.append(a) + + def match(self, string): + ary = string.split(' ', len(self.matchers)) + if all(m(a) for m, a in zip(self.matchers, ary)): + return ary + def flatten(items): for k, v in items.iteritems(): if not isinstance(k, (list, tuple)): @@ -28,7 +51,10 @@ def bind_keys(items): def bind_events(items): for k, v in flatten(items): - events[k] = v + if isinstance(k, Match): + eventmatchers[k] = v + else: + events[k] = v def event(fn): bind_events({fn.__name__: fn}) @@ -50,11 +76,15 @@ def toggle_keys(on=None, restore=None): client.write('/keys', restore or ' ') def dispatch(event, args=''): - if event in events: - try: + try: + if event in events: events[event](args) - except Exception, e: - traceback.print_exc(sys.stderr) + for matcher, action in eventmatchers.iteritems(): + ary = matcher.match(' '.join((event, args))) + if ary is not None: + action(*ary) + except Exception, e: + traceback.print_exc(sys.stderr) def event_loop(): from pygmi import events diff --git a/alternative_wmiircs/python/pygmi/fs.py b/alternative_wmiircs/python/pygmi/fs.py index 58f94193..9b66ab63 100644 --- a/alternative_wmiircs/python/pygmi/fs.py +++ b/alternative_wmiircs/python/pygmi/fs.py @@ -342,12 +342,15 @@ class Button(object): self.create(colors, label) def create(self, colors=None, label=None): + def fail(resp, exc, tb): + self.file = None if not self.file: self.file = client.create(self.path, ORDWR) if colors: - self.file.awrite(self.getval(colors, label), offset=0) + self.file.awrite(self.getval(colors, label), offset=0, fail=fail) elif label: - self.file.awrite(label, offset=24) + self.file.awrite(label, offset=24, fail=fail) + def remove(self): if self.file: self.file.aremove() @@ -579,29 +582,4 @@ class Tags(object): self.idx = min(-1, max(-len(self.mru), self.idx)) wmii['view'] = self.mru[self.idx] -if __name__ == '__main__': - c = Client('sel') - #print c.id - #print c.items() - #print c.urgent - - #print list(wmii.clients) - #print list(wmii.tags) - - #print [a.frames for a in Tag('sel').index] - #print Tag('sel').selclient - #print Tag('sel').selclient.label - #print Tag('sel').selclient.tags - #print Tag('sel').selclient.props - #a = Area(Tag('sel'), 1) - #print a.width - #print a.frames - - #print [[c.hex for c in b.colors] for b in wmii.lbuttons] - #print [[c.hex for c in b.colors] for b in wmii.rbuttons] - Button('left', '1').colors = ((0., 0., 0.), (1., 1., 1.), (0., 0., 0.)) - Button('left', '1').label = 'foo' - Button('left', '5', label='baz') - print repr(wmii['normcolors']) - # vim:se sts=4 sw=4 et: diff --git a/alternative_wmiircs/python/pygmi/menu.py b/alternative_wmiircs/python/pygmi/menu.py index 7e78a5b9..9059d21b 100644 --- a/alternative_wmiircs/python/pygmi/menu.py +++ b/alternative_wmiircs/python/pygmi/menu.py @@ -1,4 +1,4 @@ -from pygmi import call +from pygmi.util import call __all__ = 'Menu', 'ClickMenu' diff --git a/alternative_wmiircs/python/pygmi/monitor.py b/alternative_wmiircs/python/pygmi/monitor.py index 86f3a71b..0261ee87 100644 --- a/alternative_wmiircs/python/pygmi/monitor.py +++ b/alternative_wmiircs/python/pygmi/monitor.py @@ -1,3 +1,5 @@ +from threading import Timer + from pygmi import client from pygmi.fs import * @@ -33,7 +35,6 @@ class MonitorBase(type): return new_cls class Monitor(object): - side = 'right' interval = 1.0 @@ -57,7 +58,6 @@ class Monitor(object): if self.timer and mon is not self: return if self.active: - from threading import Timer label = self.getlabel() if isinstance(label, basestring): label = None, label diff --git a/alternative_wmiircs/python/pygmi/util.py b/alternative_wmiircs/python/pygmi/util.py new file mode 100644 index 00000000..cfac0ee5 --- /dev/null +++ b/alternative_wmiircs/python/pygmi/util.py @@ -0,0 +1,52 @@ +import os +import subprocess + +import pygmi + +__all__ = 'call', 'program_list', 'curry', 'find_script', '_' + +def _(): + pass + +def call(*args, **kwargs): + background = kwargs.pop('background', False) + input = kwargs.pop('input', None) + p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, cwd=os.environ['HOME'], + **kwargs) + if not background: + return p.communicate(input)[0].rstrip('\n') + +def program_list(path): + names = [] + for d in path: + try: + for f in os.listdir(d): + if f not in names and os.access('%s/%s' % (d, f), + os.X_OK): + names.append(f) + except Exception: + pass + return sorted(names) + +def curry(func, *args, **kwargs): + if _ in args: + blank = [i for i in range(0, len(args)) if args[i] is _] + def curried(*newargs, **newkwargs): + ary = list(args) + for k, v in zip(blank, newargs): + ary[k] = v + ary = tuple(ary) + newargs[len(blank):] + return func(*ary, **dict(kwargs, **newkwargs)) + else: + def curried(*newargs, **newkwargs): + return func(*(args + newargs), **dict(kwargs, **newkwargs)) + curried.__name__ = func.__name__ + '__curried__' + return curried + +def find_script(name): + for path in pygmi.confpath: + if os.access('%s/%s' % (path, name), os.X_OK): + return '%s/%s' % (path, name) + +# vim:se sts=4 sw=4 et: diff --git a/alternative_wmiircs/python/pyxp/asyncclient.py b/alternative_wmiircs/python/pyxp/asyncclient.py index 1fa38a1e..b7ebc085 100644 --- a/alternative_wmiircs/python/pyxp/asyncclient.py +++ b/alternative_wmiircs/python/pyxp/asyncclient.py @@ -10,72 +10,55 @@ def awithfile(*oargs, **okwargs): return next return wrapper def wrap_callback(fn, file): - file.called = 0 def callback(data, exc, tb): - file.called += 1 file.close() - if callable(fn): - fn(data, exc, tb) + Client.respond(fn, data, exc, tb) return callback class Client(client.Client): ROOT_FID = 0 - def awalk(self, path, async, fail=None): - ctxt = dict(path=path, fid=self.getfid(), ofid=ROOT_FID) + def _awalk(self, path, callback, fail=None): + ctxt = dict(path=path, fid=self._getfid(), ofid=ROOT_FID) def next(resp=None, exc=None, tb=None): if exc and ctxt['ofid'] != ROOT_FID: - self.aclunk(ctxt['fid']) + self._aclunk(ctxt['fid']) if not ctxt['path'] and resp or exc: if exc and fail: return self.respond(fail, None, exc, tb) - return self.respond(async, ctxt['fid'], exc, tb) + return self.respond(callback, ctxt['fid'], exc, tb) wname = ctxt['path'][:fcall.MAX_WELEM] ofid = ctxt['ofid'] ctxt['path'] = ctxt['path'][fcall.MAX_WELEM:] if resp: ctxt['ofid'] = ctxt['fid'] - self.dorpc(fcall.Twalk(fid=ofid, + self._dorpc(fcall.Twalk(fid=ofid, newfid=ctxt['fid'], wname=wname), next) next() - def _open(self, path, mode, open, origpath=None): - resp = None - - with self.walk(path) as nfid: - fid = nfid - resp = self.dorpc(open(fid)) - - def cleanup(): - self.aclunk(fid) - file = File(self, origpath or '/'.join(path), resp, fid, mode, cleanup) - self.files[fid] = file - - return file - - def _aopen(self, path, mode, open, callback, origpath=None): + _file = property(lambda self: File) + def _aopen(self, path, mode, open, callback, fail=None, origpath=None): resp = None def next(fid, exc, tb): def next(resp, exc, tb): def cleanup(): - self.clunk(fid) - file = File(self, origpath or '/'.join(path), resp, fid, mode, cleanup) - self.files[fid] = file + self._clunk(fid) + file = self._file(self, origpath or '/'.join(path), resp, fid, mode, cleanup) self.respond(callback, file) - self.dorpc(open(fid), next, callback) - self.awalk(path, next, callback) + self._dorpc(open(fid), next, fail or callback) + self._awalk(path, next, fail or callback) - def aopen(self, path, callback=True, mode=OREAD): + def aopen(self, path, callback=True, fail=None, mode=OREAD): assert callable(callback) - path = self.splitpath(path) + path = self._splitpath(path) def open(fid): return fcall.Topen(fid=fid, mode=mode) - return self._aopen(path, mode, open, callback) + return self._aopen(path, mode, open, fail or callback) - def acreate(self, path, callback=True, mode=OREAD, perm=0): - path = self.splitpath(path) + def acreate(self, path, callback=True, fail=None, mode=OREAD, perm=0): + path = self._splitpath(path) name = path.pop() def open(fid): return fcall.Tcreate(fid=fid, mode=mode, name=name, perm=perm) @@ -83,21 +66,21 @@ class Client(client.Client): def callback(resp, exc, tb): if resp: resp.close() - return self._aopen(path, mode, open, async, + return self._aopen(path, mode, open, callback, fail, origpath='/'.join(path + [name])) - def aremove(self, path, callback=True): - path = self.splitpath(path) + def aremove(self, path, callback=True, fail=None): + path = self._splitpath(path) def next(fid, exc, tb): - self.dorpc(fcall.Tremove(fid=fid), callback) - self.awalk(path, next, callback) + self._dorpc(fcall.Tremove(fid=fid), callback, fail) + self._awalk(path, next, callback, fail) - def astat(self, path, callback): - path = self.splitpath(path) + def astat(self, path, callback, fail = None): + path = self._splitpath(path) def next(fid, exc, tb): def next(resp, exc, tb): callback(resp.stat, exc, tb) - self.dorpc(fcall.Tstat(fid=fid), next, callback) + self._dorpc(fcall.Tstat(fid=fid), next, callback) @awithfile() def aread(self, (file, exc, tb), callback, *args, **kwargs): @@ -133,9 +116,9 @@ class File(client.File): def stat(self, callback): def next(resp, exc, tb): callback(resp.stat, exc, tb) - resp = self.dorpc(fcall.Tstat(), next, callback) + resp = self._dorpc(fcall.Tstat(), next, callback) - def aread(self, callback, count=None, offset=None, buf=''): + def aread(self, callback, fail=None, count=None, offset=None, buf=''): ctxt = dict(res=[], count=self.iounit, offset=self.offset) if count is not None: ctxt['count'] = count @@ -153,8 +136,8 @@ class File(client.File): n = min(ctxt['count'], self.iounit) ctxt['count'] -= n - self.dorpc(fcall.Tread(offset=ctxt['offset'], count=n), - next, callback) + self._dorpc(fcall.Tread(offset=ctxt['offset'], count=n), + next, fail or callback) next() def areadlines(self, callback): @@ -178,7 +161,7 @@ class File(client.File): callback(None) self.aread(next) - def awrite(self, data, callback=True, offset=None): + def awrite(self, data, callback=True, fail=None, offset=None): ctxt = dict(offset=self.offset, off=0) if offset is not None: ctxt['offset'] = offset @@ -186,22 +169,25 @@ class File(client.File): if resp: ctxt['off'] += resp.count ctxt['offset'] += resp.count - if ctxt['off'] < len(data): + if ctxt['off'] < len(data) or not (exc or resp): n = min(len(data), self.iounit) - self.dorpc(fcall.Twrite(offset=ctxt['offset'], + self._dorpc(fcall.Twrite(offset=ctxt['offset'], data=data[ctxt['off']:ctxt['off']+n]), - next, callback) + next, fail or callback) else: if offset is None: self.offset = ctxt['offset'] self.respond(callback, ctxt['off'], exc, tb) next() - def aremove(self, callback=True): + def aremove(self, callback=True, fail=None): def next(resp, exc, tb): self.close() - self.respond(resp and True, exc, tb) - self.dorpc(fcall.Tremove(), next) + if exc and fail: + self.respond(fail, resp and True, exc, tb) + else: + self.respond(callback, resp and True, exc, tb) + self._dorpc(fcall.Tremove(), next) # vim:se sts=4 sw=4 et: diff --git a/alternative_wmiircs/python/pyxp/client.py b/alternative_wmiircs/python/pyxp/client.py index 228bcf24..85b8e3e8 100644 --- a/alternative_wmiircs/python/pyxp/client.py +++ b/alternative_wmiircs/python/pyxp/client.py @@ -52,32 +52,31 @@ class Client(object): def __enter__(self): return self def __exit__(self, *args): - self.cleanup() + self._cleanup() def __init__(self, conn=None, namespace=None, root=None): if not conn and namespace: conn = 'unix!%s/%s' % (NAMESPACE, namespace) try: self.lastfid = ROOT_FID - self.fids = [] - self.files = {} + self.fids = set() self.lock = RLock() def process(data): return fcall.Fcall.unmarshall(data)[1] self.mux = Mux(conn, process, maxtag=256) - resp = self.dorpc(fcall.Tversion(version=pyxp.VERSION, msize=65535)) + resp = self._dorpc(fcall.Tversion(version=pyxp.VERSION, msize=65535)) if resp.version != pyxp.VERSION: raise ProtocolException, "Can't speak 9P version '%s'" % resp.version self.msize = resp.msize - self.dorpc(fcall.Tattach(fid=ROOT_FID, afid=fcall.NO_FID, + self._dorpc(fcall.Tattach(fid=ROOT_FID, afid=fcall.NO_FID, uname=os.environ['USER'], aname='')) if root: - path = self.splitpath(root) - resp = self.dorpc(fcall.Twalk(fid=ROOT_FID, + path = self._splitpath(root) + resp = self._dorpc(fcall.Twalk(fid=ROOT_FID, newfid=ROOT_FID, wname=path)) except Exception, e: @@ -86,7 +85,7 @@ class Client(object): self.mux.fd.close() raise e - def cleanup(self): + def _cleanup(self): try: for f in self.files: f.close() @@ -94,7 +93,7 @@ class Client(object): self.mux.fd.close() self.mux = None - def dorpc(self, req, callback=None, error=None): + def _dorpc(self, req, callback=None, error=None): def doresp(resp): if isinstance(resp, fcall.Rerror): raise RPCError, "%s[%d] RPC returned error: %s" % ( @@ -117,38 +116,37 @@ class Client(object): return doresp(self.mux.rpc(req)) self.mux.rpc(req, next) - def splitpath(self, path): + def _splitpath(self, path): return [v for v in path.split('/') if v != ''] - def getfid(self): + def _getfid(self): with self.lock: if self.fids: return self.fids.pop() self.lastfid += 1 return self.lastfid - def putfid(self, fid): + def _putfid(self, fid): with self.lock: - self.files.pop(fid) - self.fids.append(fid) + self.fids.add(fid) - def aclunk(self, fid, callback=None): + def _aclunk(self, fid, callback=None): def next(resp, exc, tb): if resp: - self.putfid(fid) + self._putfid(fid) self.respond(callback, resp, exc, tb) - self.dorpc(fcall.Tclunk(fid=fid), next) + self._dorpc(fcall.Tclunk(fid=fid), next) - def clunk(self, fid): + def _clunk(self, fid): try: - self.dorpc(fcall.Tclunk(fid=fid)) + self._dorpc(fcall.Tclunk(fid=fid)) finally: - self.putfid(fid) + self._putfid(fid) - def walk(self, path): - fid = self.getfid() + def _walk(self, path): + fid = self._getfid() ofid = ROOT_FID while True: - self.dorpc(fcall.Twalk(fid=ofid, newfid=fid, + self._dorpc(fcall.Twalk(fid=ofid, newfid=fid, wname=path[0:fcall.MAX_WELEM])) path = path[fcall.MAX_WELEM:] ofid = fid @@ -161,32 +159,31 @@ class Client(object): return fid def __exit__(res, exc_type, exc_value, traceback): if exc_type: - self.clunk(fid) + self._clunk(fid) return Res + _file = property(lambda self: File) def _open(self, path, mode, open, origpath=None): resp = None - with self.walk(path) as nfid: + with self._walk(path) as nfid: fid = nfid - resp = self.dorpc(open(fid)) + resp = self._dorpc(open(fid)) def cleanup(): - self.aclunk(fid) - file = File(self, origpath or '/'.join(path), resp, fid, mode, cleanup) - self.files[fid] = file - + self._aclunk(fid) + file = self._file(self, origpath or '/'.join(path), resp, fid, mode, cleanup) return file def open(self, path, mode=OREAD): - path = self.splitpath(path) + path = self._splitpath(path) def open(fid): return fcall.Topen(fid=fid, mode=mode) return self._open(path, mode, open) def create(self, path, mode=OREAD, perm=0): - path = self.splitpath(path) + path = self._splitpath(path) name = path.pop() def open(fid): @@ -194,19 +191,19 @@ class Client(object): return self._open(path, mode, open, origpath='/'.join(path + [name])) def remove(self, path): - path = self.splitpath(path) + path = self._splitpath(path) - with self.walk(path) as fid: - self.dorpc(fcall.Tremove(fid=fid)) + with self._walk(path) as fid: + self._dorpc(fcall.Tremove(fid=fid)) def stat(self, path): - path = self.splitpath(path) + path = self._splitpath(path) try: - with self.walk(path) as fid: - resp = self.dorpc(fcall.Tstat(fid= fid)) + with self._walk(path) as fid: + resp = self._dorpc(fcall.Tstat(fid= fid)) st = resp.stat() - self.clunk(fid) + self._clunk(fid) return st except RPCError: return None @@ -238,7 +235,7 @@ class File(object): self.client = client self.path = path self.fid = fid - self.cleanup = cleanup + self._cleanup = cleanup self.mode = mode self.iounit = fcall.iounit self.qid = fcall.qid @@ -247,15 +244,15 @@ class File(object): self.offset = 0 def __del__(self): if not self.closed: - self.cleanup() + self._cleanup() - def dorpc(self, fcall, async=None, error=None): + def _dorpc(self, fcall, async=None, error=None): if hasattr(fcall, 'fid'): fcall.fid = self.fid - return self.client.dorpc(fcall, async, error) + return self.client._dorpc(fcall, async, error) def stat(self): - resp = self.dorpc(fcall.Tstat()) + resp = self._dorpc(fcall.Tstat()) return resp.stat def read(self, count=None, offset=None, buf=''): @@ -270,7 +267,7 @@ class File(object): n = min(count, self.iounit) count -= n - resp = self.dorpc(fcall.Tread(offset=offs, count=n)) + resp = self._dorpc(fcall.Tread(offset=offs, count=n)) data = resp.data offs += len(data) @@ -307,7 +304,7 @@ class File(object): while off < len(data): n = min(len(data), self.iounit) - resp = self.dorpc(fcall.Twrite(offset=offs, + resp = self._dorpc(fcall.Twrite(offset=offs, data=data[off:off+n])) off += resp.count offs += resp.count @@ -331,7 +328,7 @@ class File(object): def close(self): assert not self.closed self.closed = True - self.cleanup() + self._cleanup() self.tg = None self.fid = None self.client = None @@ -339,7 +336,7 @@ class File(object): def remove(self): try: - self.dorpc(fcall.Tremove()) + self._dorpc(fcall.Tremove()) finally: try: self.close() diff --git a/alternative_wmiircs/python/wmiirc.py b/alternative_wmiircs/python/wmiirc.py index f465e1f9..cd222ded 100644 --- a/alternative_wmiircs/python/wmiirc.py +++ b/alternative_wmiircs/python/wmiirc.py @@ -70,8 +70,7 @@ client.awrite('/event', 'Start wmiirc') tags = Tags() bind_events({ - 'Quit': lambda args: sys.exit(), - 'Start': lambda args: args == 'wmiirc' and sys.exit(), + ('Quit', Match('Start', 'wmiirc')): lambda *a: sys.exit(), 'CreateTag': tags.add, 'DestroyTag': tags.delete, 'FocusTag': tags.focus, @@ -88,11 +87,21 @@ bind_events({ 'Notice': lambda args: notice.show(args), - ('LeftBarClick', 'LeftBarDND'): - lambda args: args.split()[0] == '1' and tags.select(args.split(' ', 1)[1]), + Match(('LeftBarClick', 'LeftBarDND'), '1'): lambda e, b, tag: tags.select(tag), + Match('LeftBarClick', '4'): lambda *a: tags.select(tags.next(True)), + Match('LeftBarClick', '5'): lambda *a: tags.select(tags.next()), - 'ClientMouseDown': lambda args: menu(*args.split(), type='client'), - 'LeftBarMouseDown': lambda args: menu(*reversed(args.split()), type='lbar'), + Match('LeftBarMouseDown', 3): lambda e, n, tag: clickmenu(( + ('Delete', lambda t: Tag(t).delete()), + ), (tag,)), + Match('ClientMouseDown', _, 3): lambda e, client, n: clickmenu(( + ('Delete', lambda c: Client(c).kill()), + ('Kill', lambda c: Client(c).slay()), + ('Fullscreen', lambda c: Client(c).set('Fullscreen', 'on')), + ), (client,)), + + Match('ClientClick', _, 4): lambda e, c, n: Tag('sel').select('up'), + Match('ClientClick', _, 5): lambda e, c, n: Tag('sel').select('down'), }) @apply @@ -117,20 +126,10 @@ action_menu = Menu(histfile='%s/history.action' % confpath[0], nhist=500, tag_menu = Menu(histfile='%s/history.tags' % confpath[0], nhist=100, choices=lambda: sorted(tags.tags.keys())) -def menu(target, button, type): - MENUS = { - ('client', '3'): ( - ('Delete', lambda c: Client(c).kill()), - ('Kill', lambda c: Client(c).slay()), - ('Fullscreen', lambda c: Client(c).set('Fullscreen', 'on'))), - ('lbar', '3'): ( - ('Delete', lambda t: Tag(t).delete())), - } - choices = MENUS.get((type, button), None) - if choices: - ClickMenu(choices=(k for k, v in choices), - action=lambda k: dict(choices).get(k, identity)(target) - ).call() +def clickmenu(choices, args): + ClickMenu(choices=(k for k, v in choices), + action=lambda choice: dict(choices).get(choice, identity)(*args)) \ + .call() class Notice(Button): def __init__(self): @@ -138,7 +137,7 @@ class Notice(Button): self.timer = None def tick(self): - self.label = '' + self.label = ' ' def write(self, notice): client.awrite('/event', 'Notice %s' % notice.replace('\n', ' ')) @@ -201,7 +200,8 @@ map(bind_num, range(0, 10)) Actions.rehash() -dirs = ('%s/plugins' % dir for dir in confpath if os.access('%s/plugins' % dir, os.R_OK)) +dirs = filter(curry(os.access, _, os.R_OK), + ('%s/plugins' % dir for dir in confpath)) files = filter(re.compile(r'\.py$').match, reduce(operator.add, map(os.listdir, dirs), [])) for f in ['wmiirc_local'] + ['plugins.%s' % file[:-3] for file in files]: