s = start_session('fastmux-test-bg', width=60, height=8)
test_eq(s.name, 'fastmux-test-bg')
test_eq(start_session('fastmux-test-bg').id, s.id)
sBackground sessions
fastmux’s handle API assumes you can hold a Pane between calls. A background terminal often outlives that: it is created in one tool call and driven from another, shared with a user who attaches by name, and referred to by nothing but that name. This module provides that functionality.
start_session creates-or-reuses a named session, and every verb takes a sid — a session name, a %pane_id, a Session or Pane handle, or None for the current pane.
Managed sessions
A managed session differs from a bare new_session in the ways background work needs: it is found again by name instead of erroring as a duplicate; remain is set (with the dead-pane banner cleared) so a finished command’s output and exit status stay inspectable; and the created pane’s id is recorded in the @fastmux_pane_id session option, so later splits don’t change which pane the sid addresses. cmd is started with respawn-pane only after those options are in place, since a fast-failing command could otherwise die before they land.
start_session
def start_session(
sid:NoneType=None, # Session name; default: a generated `fastmux-`-prefixed name
cmd:NoneType=None, # Command to run (str or argv list); default: the user's shell
cwd:NoneType=None, # Working directory
env:NoneType=None, # Extra environment vars as a dict
width:NoneType=None, # Terminal width in columns
height:NoneType=None, # Terminal height in rows
):The session named sid, created detached (managed, with remain set) if it doesn’t exist
Addressing by sid
pane turns any sid form into the Pane it addresses, and is the bridge to the full handle API: everything this module doesn’t wrap (wait, search, splitting, transcript slicing) is a method on its result. For a session name, the managed pane recorded at creation wins over the currently-active one:
pane
def pane(
sid:NoneType=None
):The pane sid addresses: a session name (its managed pane), a %pane_id, a Session or Pane handle, or None for the current pane
p = pane('fastmux-test-bg')
test_eq(p.id, pane(s).id)
test_eq(p.id, pane(p.id).id)Splitting the managed session doesn’t move the sid’s target:
q = p.bsplit(size=3)
test_eq(pane('fastmux-test-bg').id, p.id)
q.kill()Driving by sid
The verbs mirror Pane’s, with a sid in front: each sends (or just waits), polls until the pane differs from its last-seen state, and returns a Capture. Output that arrived between calls satisfies the next poll immediately.
display
def display(
sid:NoneType=None, lines:int=80
):Capture the last lines of sid’s pane
poll
def poll(
sid:NoneType=None, wait_ms:int=0, interval_ms:int=50, lines:int=80
):Wait for sid’s pane to differ from its last-seen state, then capture the last lines
interrupt
def interrupt(
sid:NoneType=None, wait_ms:int=0, interval_ms:int=50, lines:int=80
):Send Ctrl-C to sid’s pane, then poll
send_keys
def send_keys(
sid:NoneType=None, *keys, wait_ms:int=0, interval_ms:int=50, lines:int=80
):Send tmux key names to sid’s pane, then poll
send
def send(
sid:NoneType=None, chars:str='', wait_ms:int=0, interval_ms:int=50, lines:int=80
):Paste chars into sid’s pane literally, then poll
c = send('fastmux-test-bg', 'echo $((6*7)) apples\n', wait_ms=2000)
assert '42 apples' in c.text
cLifecycle
close kills the whole session owning the sid’s pane — including when the sid is a %pane_id — and managed_sessions lists every session start_session created, whatever it was named:
managed_sessions
def managed_sessions():Sessions created by start_session
close
def close(
sid:NoneType=None
):Kill the session owning sid’s pane
test_eq('fastmux-test-bg' in managed_sessions().attrgot('name'), True)
close('fastmux-test-bg')
with expect_fail(TmuxError): pane('fastmux-test-bg')