Skip to content
Merged
21 changes: 21 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@
enter: false
```

- #750: Pause execution via `sleep_before: [int]` and `sleep_after: [int]`

```yaml
session_name: Pause / skip command execution (command-level)
windows:
- panes:
- shell_command:
# Executes immediately
- echo "___$((11 + 1))___"
# Delays before sending 2 seconds
- cmd: echo "___$((1 + 3))___"
sleep_before: 2
# Executes immediately
- cmd: echo "___$((1 + 3))___"
# Pauses 2 seconds after
- cmd: echo "Stuff rendering here!"
sleep_after: 2
# Executes after earlier commands (after 2 sec)
- cmd: echo "2 seconds later"
```

- #701: `tmuxp freeze` now accepts `--quiet` and `--yes` along with the
`--config-format` and filename (`--save-to`). This means you can do it all in
one command:
Expand Down
60 changes: 60 additions & 0 deletions docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@ This will add the `shell_command` to the bash history in the pane.

```{versionadded} 1.10.0b1
`enter: false` option. Pane-level support.
```

```{versionadded} 1.10.0b3
Support command-level skipping.
```
Expand Down Expand Up @@ -375,6 +377,64 @@ Omit sending {kbd}`enter` to key commands. Equivalent to

````

## Pausing commands

```{versionadded} 1.10.0b4
`sleep_before` and `sleep_after` options added. Pane and command-level support.
```

```{warning}
This will delay loading as it runs synchronously for each pane. In future version asynchronous support, (i.e. [`asyncio`](asyncio)) will speed up this up.
```

Omit sending {kbd}`enter` to key commands. Equivalent to having
a [`time.sleep`](time.sleep) before and after [`send_keys`](libtmux.Pane.send_keys).

This is especially useful for expensive commands where the terminal needs some breathing room (virtualenv, poetry, pipenv, sourcing a configuration, launching a tui app, etc).

````{tab} Virtualenv

```{literalinclude} ../examples/sleep-virtualenv.yaml
:language: yaml

```
````

````{tab} YAML

```{literalinclude} ../examples/sleep.yaml
:language: yaml

```

````

````{tab} JSON

```{literalinclude} ../examples/sleep.json
:language: json

```

````

````{tab} YAML (pane-level)

```{literalinclude} ../examples/sleep-pane-level.yaml
:language: yaml

```

````

````{tab} JSON (pane-level)

```{literalinclude} ../examples/sleep-pane-level.json
:language: json

```

````

## Window Index

Expand Down
4 changes: 2 additions & 2 deletions examples/skip-send-pane-level.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"session_name": "Skip all pane commands",
"session_name": "Skip command execution (pane-level)",
"windows": [
{
"panes": [
Expand All @@ -17,4 +17,4 @@
]
}
]
}
}
2 changes: 1 addition & 1 deletion examples/skip-send-pane-level.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
session_name: Skip all pane commands
session_name: Skip command execution (pane-level)
windows:
- panes:
- shell_command: echo "___$((1 + 3))___"
Expand Down
27 changes: 27 additions & 0 deletions examples/sleep-pane-level.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"session_name": "Pause / skip command execution (pane-level)",
"windows": [
{
"panes": [
{
"sleep_before": 2,
"shell_command": [
"echo \"___$((11 + 1))___\"",
{
"cmd": "echo \"___$((1 + 3))___\""
},
{
"cmd": "echo \"___$((1 + 3))___\""
},
{
"cmd": "echo \"Stuff rendering here!\""
},
{
"cmd": "echo \"2 seconds later\""
}
]
}
]
}
]
}
13 changes: 13 additions & 0 deletions examples/sleep-pane-level.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
session_name: Pause / skip command execution (pane-level)
windows:
- panes:
-
# Wait 2 seconds before sending all commands in this pane
sleep_before: 2
shell_command:
- echo "___$((11 + 1))___"
- cmd: echo "___$((1 + 3))___"
- cmd: echo "___$((1 + 3))___"
- cmd: echo "Stuff rendering here!"
- cmd: echo "2 seconds later"

11 changes: 11 additions & 0 deletions examples/sleep-virtualenv.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
session_name: virtualenv
shell_command_before:
# - cmd: source $(poetry env info --path)/bin/activate
# - cmd: source `pipenv --venv`/bin/activate
- cmd: source .venv/bin/activate
sleep_before: 1
sleep_after: 1
windows:
- panes:
- shell_command:
- ./manage.py runserver
28 changes: 28 additions & 0 deletions examples/sleep.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"session_name": "Pause / skip command execution (command-level)",
"windows": [
{
"panes": [
{
"shell_command": [
"echo \"___$((11 + 1))___\"",
{
"cmd": "echo \"___$((1 + 3))___\"",
"sleep_before": 2
},
{
"cmd": "echo \"___$((1 + 3))___\""
},
{
"cmd": "echo \"Stuff rendering here!\"",
"sleep_after": 2
},
{
"cmd": "echo \"2 seconds later\""
}
]
}
]
}
]
}
16 changes: 16 additions & 0 deletions examples/sleep.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
session_name: Pause / skip command execution (command-level)
windows:
- panes:
- shell_command:
# Executes immediately
- echo "___$((11 + 1))___"
# Delays before sending 2 seconds
- cmd: echo "___$((1 + 3))___"
sleep_before: 2
# Executes immediately
- cmd: echo "___$((1 + 3))___"
# Pauses 2 seconds after
- cmd: echo "Stuff rendering here!"
sleep_after: 2
# Executes after earlier commands (after 2 sec)
- cmd: echo "2 seconds later"
123 changes: 123 additions & 0 deletions tests/test_workspacebuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -1021,3 +1021,126 @@ def test_load_workspace_enter(
assert output in captured_pane
else:
assert output not in captured_pane


@pytest.mark.parametrize(
"yaml,sleep,output",
[
[
textwrap.dedent(
"""
session_name: Should not execute
windows:
- panes:
- shell_command:
- cmd: echo "___$((1 + 5))___"
sleep_before: 2
- cmd: echo "___$((1 + 3))___"
sleep_before: 1
"""
),
1.5,
"___4___",
],
[
textwrap.dedent(
"""
session_name: Should not execute
windows:
- panes:
- shell_command:
- cmd: echo "___$((1 + 5))___"
sleep_before: 2
- cmd: echo "___$((1 + 3))___"
sleep_before: 1
"""
),
3,
"___4___",
],
[
textwrap.dedent(
"""
session_name: Should not execute
windows:
- panes:
- shell_command:
- cmd: echo "___$((1 + 3))___"
sleep_before: 2
"""
),
2,
"___4___",
],
[
textwrap.dedent(
"""
session_name: Should not execute
windows:
- panes:
- shell_command:
- cmd: echo "___$((1 + 3))___"
sleep_before: 2
"""
),
2,
"___4___",
],
[
textwrap.dedent(
"""
session_name: Should not execute
shell_command_before:
- cmd: echo "sleeping before"
sleep_before: 2
windows:
- panes:
- echo "___$((1 + 3))___"
"""
),
2,
"___4___",
],
],
ids=[
"command_level_sleep_3_shortform",
"command_level_pane_sleep_3_longform",
"pane_sleep_2_shortform",
"pane_sleep_2_longform",
"shell_before_before_command_level",
],
)
@pytest.mark.flaky(reruns=3)
def test_load_workspace_sleep(
tmp_path: pathlib.Path,
server: libtmux.Server,
monkeypatch: pytest.MonkeyPatch,
yaml,
sleep: int,
output,
):
yaml_config = tmp_path / "simple.yaml"
yaml_config.write_text(
yaml,
encoding="utf-8",
)
sconfig = kaptan.Kaptan(handler="yaml")
sconfig = sconfig.import_config(str(yaml_config)).get()
sconfig = config.expand(sconfig)
sconfig = config.trickle(sconfig)
builder = WorkspaceBuilder(sconf=sconfig, server=server)
builder.build()

t = time.process_time()

time.sleep(1)
session = builder.session
pane = session.attached_pane

while (time.process_time() - t) * 1000 < sleep:
captured_pane = "\n".join(pane.capture_pane())

assert output not in captured_pane
time.sleep(0.1)
captured_pane = "\n".join(pane.capture_pane())
assert output in captured_pane
11 changes: 11 additions & 0 deletions tmuxp/workspacebuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

"""
import logging
import time

from libtmux.exc import TmuxSessionExists
from libtmux.pane import Pane
Expand Down Expand Up @@ -363,11 +364,21 @@ def get_pane_shell():
suppress = True

enter = pconf.get("enter", True)
sleep_before = pconf.get("sleep_before", None)
sleep_after = pconf.get("sleep_after", None)
for cmd in pconf["shell_command"]:
enter = cmd.get("enter", enter)
sleep_before = cmd.get("sleep_before", sleep_before)
sleep_after = cmd.get("sleep_after", sleep_after)

if sleep_before is not None:
time.sleep(sleep_before)

p.send_keys(cmd["cmd"], suppress_history=suppress, enter=enter)

if sleep_after is not None:
time.sleep(sleep_after)

if "focus" in pconf and pconf["focus"]:
w.select_pane(p["pane_id"])

Expand Down