def discover_pane_by_pid(target_pid: int) -> Do: panes = yield all_panes() indicators = yield TmuxIO.from_io( panes.traverse(lambda a: contains_child_pid(target_pid, a), IO)) candidate = panes.zip(indicators).find_map(lambda a: a[1].m(a[0])) yield TmuxIO.from_maybe(candidate, f'could not find pane with pid `{target_pid}`')
def create_pane_from_data(window: Window, pane: Pane, dir: Path) -> Do: target_window = yield TmuxIO.from_maybe(window.id, lambda: f'{window} has no id') args = List('-t', window_id(target_window), '-d', '-P', '-c', dir) panes = yield tmux_data_cmd('split-window', args, cmd_data_pane) yield TmuxIO.from_maybe( panes.head, lambda: f'no output when creating pane in {window}')
def setup(self) -> None: self.tmux_proc = start_tmux(tmux_spec_socket, self.win_width, self.win_height, self.tmux_in_terminal()) self.tmux = Tmux.cons(tmux_spec_socket) self._wait(.2) cmd = TmuxIO.read('list-clients -F "#{client_name}"') self.tmux_client = cmd.unsafe(self.tmux).head.get_or_fail('no clients')
def setup_test_tmux(config: TestConfig) -> Tuple[subprocess.Popen, str, Tmux]: tmux_proc = start_tmux(config.socket, config.win_width, config.win_height, config.terminal) tmux = Tmux.cons(tmux_spec_socket) time.sleep(.2) cmd = TmuxIO.read('list-clients -F "#{client_name}"') tmux_client = cmd.unsafe(tmux).head.get_or_fail('no clients') return tmux_proc, tmux_client, tmux
def unit_test( io: Callable[..., TS[SpecData, Expectation]], config: TestConfig = TestConfig.cons(), *a: Any, **kw: Any, ) -> Expectation: tmux_proc, tmux_client, tmux = setup_test_tmux(config) @do(TmuxIO[Expectation]) def run() -> Do: data = SpecData.cons(config.layout) yield io(*a, **kw).run_a(data) return run_test_io( TmuxIO.to_io(run(), tmux).ensure, cleanup(tmux_proc, tmux))
def tmuxio_repeat_timeout( thunk: Callable[[], TmuxIO[A]], check: Callable[[A], bool], error: str, timeout: float, interval: float = None, ) -> Do: effective_interval = .01 if interval is None else interval start = yield TmuxIO.simple(time.time) @do(TmuxIO[None]) def wait_and_recurse() -> Do: yield TmuxIO.sleep(effective_interval) yield recurse() @do(TmuxIO[None]) def recurse() -> Do: result = yield thunk() done = check(result) yield (TmuxIO.pure(result) if done else TmuxIO.error(error) if time.time() - start > timeout else wait_and_recurse()) yield recurse()
def failed(self, e: str) -> 'TmuxIOState[S, A]': return TmuxIOState.lift(TmuxIO.failed(e))
def simple_tmux_cmd_attr(cmd: str, args: List[str], attr: str) -> Do: attrs = yield simple_tmux_cmd_attrs(cmd, args, List(attr)) yield TmuxIO.from_maybe(attrs.traverse(lambda a: a.lift(attr), Maybe), f'attr `{attr}` missing in output')
def tmux_data_cmd(cmd: str, args: List[str], cmd_data: TmuxCmdData[A]) -> Do: data = yield simple_tmux_cmd_attrs(cmd, args, cmd_data.attrs) yield TmuxIO.from_either(cons_tmux_data(data, cmd_data.cons))
def kill_server() -> TmuxIO[None]: return TmuxIO.write('kill-server')
def simple_tmux_cmd_attrs(cmd: str, args: List[str], attrs: List[str]) -> Do: output = yield TmuxIO.read(cmd, '-F', tmux_fmt_attrs(attrs), *args) yield TmuxIO.pure(output / L(tmux_attr_map)(attrs, _))
def pane(pane_id: int) -> Do: panes = yield all_panes() yield TmuxIO.from_maybe(panes.find(_.id == pane_id), f'no pane with id `{pane_id}`')
def create_window(target_session: int, ident: str) -> Do: args = List('-t', f'{session_id(target_session)}:', '-n', ident, '-P') windows = yield tmux_data_cmd('new-window', args, cmd_data_window) yield TmuxIO.from_maybe(windows.head, f'no output when creating window `{ident}`')
def existing_window(session: Session, window: Window) -> Do: sid = yield TmuxIO.from_maybe(session.id, 'session has no id') wid = yield TmuxIO.from_maybe(window.id, 'window has no id') e = yield session_window(sid, wid) yield TmuxIO.from_either(e)
def pure(self, a: A) -> TmuxIO[A]: return TmuxIO.pure(a)
def move_pane(id: int, ref_id: int, vertical: Boolean) -> TmuxIO[None]: direction = '-v' if vertical else '-h' return TmuxIO.write('move-pane', '-d', '-s', pane_id(id), '-t', pane_id(ref_id), direction)
def wait_and_recurse() -> Do: yield TmuxIO.sleep(effective_interval) yield recurse()
def resize_pane(id: int, vertical: Boolean, size: int) -> TmuxIO[None]: direction = '-y' if vertical else '-x' return TmuxIO.write('resize-pane', '-t', pane_id(id), direction, size)
def tmux_pane_open(pane: Ident) -> Do: tpane = yield pane_by_ident(pane) yield TS.lift(tpane.id.cata(pane_open, lambda: TmuxIO.pure(false)))
def pane_from_data(window: Window, pane: Pane) -> Do: yield (pane_loc(window, pane) / pane_from_loc).value_or(lambda e: TmuxIO.pure(Left(e)))
def run(self, prog: TS[D, None], data: D) -> None: self._wait(.2) r = prog.run(data).unsafe(self.tmux) TmuxIO.write('display-panes', '-t', self.tmux_client).result(self.tmux) self._wait(.2) return r
def create_session(name: str) -> Do: sessions = yield tmux_data_cmd('new-session', List('-s', name, '-P'), cmd_data_session) yield TmuxIO.from_maybe(sessions.head, f'no output when creating session `{name}`')
def close_pane_id(pane_id: int) -> TmuxIO[None]: return TmuxIO.write(*pane_cmd(pane_id, 'kill-pane'))
def window_pane(wid: int, pane_id: int) -> Do: panes = yield window_panes(wid) yield TmuxIO.from_maybe(panes.find(_.id == pane_id), f'no pane with id `{pane_id}`')
def recurse() -> Do: result = yield thunk() done = check(result) yield (TmuxIO.pure(result) if done else TmuxIO.error(error) if time.time() - start > timeout else wait_and_recurse())
def capture_pane(id: int) -> Do: output = yield TmuxIO.read(*pane_cmd(id, 'capture-pane', '-p')) yield TmuxIO.pure(output.reversed.drop_while(_ == '').reversed)
def pane_dir(pane: P) -> Do: ui_pane = yield TmuxIO.from_either(UiPane.e_for(pane)) yield (ui_pane.cwd(pane) / TmuxIO.pure).get_or(lambda: TmuxIO.from_io(IO.delay(Path.cwd)))
def pipe_pane(id: int, path: Path) -> TmuxIO[None]: return TmuxIO.write( *pane_cmd(id, 'pipe-pane', quote(f'{pipe_filter} > {str(path)}')))
def ensure_session(session: Session) -> Do: exists = yield TS.lift(session.id.map(session_exists) | TmuxIO.pure(false)) yield TS.pure(session) if exists else create_and_update_session(session)
def select_pane(id: int) -> TmuxIO[int]: return TmuxIO.write(*pane_cmd(id, 'select-pane'))