#!/usr/bin/env python # vim: fileencoding=utf-8 ft=python et sw=4 ts=4 sts=4 tw=79 from __future__ import ( generators, division, absolute_import, with_statement, print_function ) import urwid # from twisted.internet import reactor from twisted.internet.task import LoopingCall from twisted.internet.utils import getProcessOutput pane_format = 'session_name window_index pane_id pane_title'.split() # TODO: use tmux in command mode: # tmux -L tst -C a -t 0 \; refresh-client -C 256,128 def exit_program(button): raise urwid.ExitMainLoop() class TST(object): """ Vertical tree-style-tabs alike for tmux. """ def __init__(self, sockname='tst'): self.sockname = sockname self._redraw_pending = False self.head = [urwid.Text('TST'), urwid.Divider()] self.body = urwid.SimpleFocusListWalker(self.head) self.main = urwid.Padding(urwid.ListBox(self.body), left=2, right=2) self.top = urwid.Overlay( self.main, urwid.SolidFill(u'\N{MEDIUM SHADE}'), align='center', width=('relative', 60), valign='middle', height=('relative', 60), min_width=20, min_height=9 ) def call_tmux(self, *args): """ Run tmux executable with socket option set. """ return getProcessOutput('/usr/bin/tmux', ('-L', self.sockname) + args) def get_panes(self): """ Call tmux to get list of panes. """ return self.call_tmux(*'list-panes -a -F'.split() + ['|'.join(( '#{%s}' % i for i in pane_format ))]).addCallback(self.got_panes) def got_panes(self, s): """ Process list of panes and update TST accordingly. """ buttons = [] for line in s.split('\n'): if not line: continue d = dict(zip(pane_format, line.split('|'))) b = urwid.Button('%(pane_id)s %(pane_title)s' % d, self.clicked, d['window_index']) buttons.append(urwid.AttrMap(b, None, focus_map='reversed')) self.body[2:] = buttons # self.mainloop.draw_screen() self.redraw() def redraw(self): """ Schedule window redraw at closest idle time. """ if self._redraw_pending: return self._redraw_pending = True self.reactor.callLater(0, self._do_redraw) def _do_redraw(self): self._redraw_pending = False self.mainloop.draw_screen() def clicked(self, button, window): self.call_tmux('select-window', '-t', window) def run(self, reactor=None): """ Run the TST application. """ if reactor is None: from twisted.internet import reactor self.reactor = reactor self.get_panes() self.paneloop = LoopingCall(self.get_panes) self.paneloop.start(1) self.mainloop = urwid.MainLoop( self.main, palette=[('reversed', 'standout', '')], event_loop=urwid.TwistedEventLoop(reactor) ) self.mainloop.run() if __name__ == '__main__': TST().run()