summaryrefslogtreecommitdiff
path: root/test/fs.py
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 18:32:37 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commita22129c343d9236277dcc0353c48cb53bc3417ce (patch)
tree6a1d07cfc2881b6701991c2fa167400400341952 /test/fs.py
parent1db5ba2b267f030e2de54a2cb4de9fb155c4139d (diff)
downloadpardes-a22129c343d9236277dcc0353c48cb53bc3417ce.tar.gz
pardes-a22129c343d9236277dcc0353c48cb53bc3417ce.zip
pardes --wait (-w) in a pane returns only once the pane its file landed in is deleted, so it can be $EDITOR
A launch inside a pane forwards its file to the session's look and returned at once, so fish's Ctrl-O (edit_command_buffer), git commit and crontab -e read their still-unedited file back and went on. With --wait, as acme's E against B and read the way plan9port's E reads acme's log, it finds the pane /index names the file by (the one already showing it, if open), follows /log on one connection with 'follow new', reads /index once more to catch a Del that came first, and then blocks with no deadline until that pane's del record: exit 0, or 1 when the connection ends with the session. The 9P client's one-shot requests keep their 2 s deadline; its new follow takes it for the setup only. Outside pardes nothing changes. --help, docs/fs.md, the README and the 9P skill say to set EDITOR='pardes --wait', which GIT_EDITOR follows. Tested in fs.py (it returns within 50 ms of the Del, a second -w waits on the same pane, one whose session is killed exits 1) and end to end: fish 4.8 in a detached session, echo hi, Ctrl-O, the waiting launch idle in poll, the line edited over 9P, Save, Del, and fish ran echo edited. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'test/fs.py')
-rw-r--r--test/fs.py41
1 files changed, 41 insertions, 0 deletions
diff --git a/test/fs.py b/test/fs.py
index 7401861b..db10f32d 100644
--- a/test/fs.py
+++ b/test/fs.py
@@ -1224,6 +1224,47 @@ def test(binary, quic=False):
cell[0] for cell in local.screen()['cells'])
assert client.read('/index') == before
+ # --wait (acme's E): a launch inside a pane lasts until the pane it
+ # opened is deleted, as an $EDITOR must; one on a file already open
+ # waits on that pane; a session that goes away ends it with 1.
+ with session(binary, root, 'wait') as (client, address):
+ status = dict(line.split(maxsplit=1) for line in client.read('/status').decode().splitlines())
+ env = {k: v for k, v in os.environ.items() if k != 'PARDES_FORWARD_LOOK'}
+ env.update(PARDES_9P=str(address), PARDES_PANE='1', PARDES_PID=status['pid'])
+ edited = root / 'wait edit.txt'
+ edited.write_bytes(b'edit me\n')
+
+ def serials():
+ return {int(row.split()[0]) for row in client.read('/index').splitlines()}
+
+ def launch(flag):
+ before = serials()
+ child = subprocess.Popen([binary, flag, str(edited)], cwd=root, env=env,
+ stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
+ deadline = time.monotonic() + 3
+ while child.poll() is None and not serials() - before and time.monotonic() < deadline:
+ time.sleep(.01)
+ return child
+
+ first = launch('--wait')
+ opened, = serials() - {1}
+ second = launch('-w')
+ time.sleep(.5)
+ assert first.poll() is None and second.poll() is None, (first.stderr.read(), second.stderr.read())
+ assert serials() == {1, opened}
+ client.write(f'/pane/{opened}/body', b'edited\n', truncate=True)
+ execute(client, opened, 'Save')
+ client.remove(f'/pane/{opened}')
+ deleted = time.monotonic()
+ assert first.wait(timeout=5) == 0
+ # Woken by the `del` record, not a poll.
+ assert time.monotonic() - deleted < .05, time.monotonic() - deleted
+ assert second.wait(timeout=5) == 0
+ assert edited.read_bytes() == b'edited\n'
+ orphan = launch('--wait')
+ assert orphan.poll() is None
+ assert orphan.wait(timeout=5) == 1
+
for tty in [False, True]:
name = 'lsp-tty' if tty else 'lsp-detached'
with session(binary, root, name, tty=tty) as (client, _):