Skip to content

Commit a905a3f

Browse files
committed
docs(config[examples]): Add examples and tests for new features
why: New features need example configs and tests to verify them. what: - Add example YAMLs: synchronize, lifecycle hooks, templating, pane titles - Add pytest tests for all four examples - Update examples.md with literalinclude sections
1 parent 0ab75ae commit a905a3f

7 files changed

Lines changed: 182 additions & 0 deletions

File tree

docs/configuration/examples.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,58 @@ windows:
785785
[poetry]: https://python-poetry.org/
786786
[uv]: https://github.com/astral-sh/uv
787787

788+
## Synchronize panes (shorthand)
789+
790+
The `synchronize` window-level key provides a shorthand for enabling
791+
`synchronize-panes` without needing `options_after`:
792+
793+
````{tab} YAML
794+
```{literalinclude} ../../examples/synchronize-shorthand.yaml
795+
:language: yaml
796+
797+
```
798+
````
799+
800+
## Lifecycle hooks
801+
802+
Run shell commands at different stages of the session lifecycle:
803+
804+
````{tab} YAML
805+
```{literalinclude} ../../examples/lifecycle-hooks.yaml
806+
:language: yaml
807+
808+
```
809+
````
810+
811+
See {ref}`top-level` for full hook documentation.
812+
813+
## Config templating
814+
815+
Use `{{ variable }}` placeholders in workspace configs. Pass values via
816+
`--set KEY=VALUE`:
817+
818+
```console
819+
$ tmuxp load --set project=myapp config-templating.yaml
820+
```
821+
822+
````{tab} YAML
823+
```{literalinclude} ../../examples/config-templating.yaml
824+
:language: yaml
825+
826+
```
827+
````
828+
829+
## Pane titles
830+
831+
Enable pane border titles to label individual panes:
832+
833+
````{tab} YAML
834+
```{literalinclude} ../../examples/pane-titles.yaml
835+
:language: yaml
836+
837+
```
838+
````
839+
788840
## Kung fu
789841

790842
:::{note}

examples/config-templating.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
session_name: "{{ project }}"
2+
windows:
3+
- window_name: "{{ project }}-main"
4+
panes:
5+
- echo "Working on {{ project }}"

examples/lifecycle-hooks.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
session_name: lifecycle hooks
2+
on_project_start: echo "project starting"
3+
on_project_exit: echo "project exiting"
4+
windows:
5+
- window_name: main
6+
panes:
7+
-

examples/pane-titles.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
session_name: pane titles
2+
enable_pane_titles: true
3+
pane_title_position: top
4+
pane_title_format: "#{pane_index}: #{pane_title}"
5+
windows:
6+
- window_name: titled
7+
panes:
8+
- title: editor
9+
shell_command:
10+
- echo pane0
11+
- title: runner
12+
shell_command:
13+
- echo pane1
14+
- shell_command:
15+
- echo pane2
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
session_name: synchronize shorthand
2+
windows:
3+
- window_name: synced-before
4+
synchronize: before
5+
panes:
6+
- echo 0
7+
- echo 1
8+
- window_name: synced-after
9+
synchronize: after
10+
panes:
11+
- echo 0
12+
- echo 1
13+
- window_name: not-synced
14+
panes:
15+
- echo 0
16+
- echo 1

tests/docs/examples/__init__.py

Whitespace-only changes.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""Tests for example workspace YAML files."""
2+
3+
from __future__ import annotations
4+
5+
import functools
6+
import typing as t
7+
8+
from libtmux.pane import Pane
9+
from libtmux.session import Session
10+
from libtmux.test.retry import retry_until
11+
12+
from tests.constants import EXAMPLE_PATH
13+
from tmuxp._internal.config_reader import ConfigReader
14+
from tmuxp.workspace import loader
15+
from tmuxp.workspace.builder import WorkspaceBuilder
16+
17+
18+
def test_synchronize_shorthand(session: Session) -> None:
19+
"""Test synchronize-shorthand.yaml builds and sets synchronize-panes."""
20+
config = ConfigReader._from_file(EXAMPLE_PATH / "synchronize-shorthand.yaml")
21+
config = loader.expand(config)
22+
builder = WorkspaceBuilder(session_config=config, server=session.server)
23+
builder.build(session=session)
24+
25+
windows = session.windows
26+
assert len(windows) == 3
27+
28+
synced_before = windows[0]
29+
synced_after = windows[1]
30+
not_synced = windows[2]
31+
32+
assert synced_before.show_option("synchronize-panes") is True
33+
assert synced_after.show_option("synchronize-panes") is True
34+
assert not_synced.show_option("synchronize-panes") is not True
35+
36+
37+
def test_lifecycle_hooks(session: Session) -> None:
38+
"""Test lifecycle-hooks.yaml loads without error."""
39+
config = ConfigReader._from_file(EXAMPLE_PATH / "lifecycle-hooks.yaml")
40+
config = loader.expand(config)
41+
builder = WorkspaceBuilder(session_config=config, server=session.server)
42+
builder.build(session=session)
43+
44+
assert len(session.windows) >= 1
45+
46+
47+
def test_config_templating(session: Session) -> None:
48+
"""Test config-templating.yaml renders templates and builds."""
49+
config = ConfigReader._from_file(
50+
EXAMPLE_PATH / "config-templating.yaml",
51+
template_context={"project": "myapp"},
52+
)
53+
config = loader.expand(config)
54+
55+
assert config["session_name"] == "myapp"
56+
assert config["windows"][0]["window_name"] == "myapp-main"
57+
58+
builder = WorkspaceBuilder(session_config=config, server=session.server)
59+
builder.build(session=session)
60+
61+
assert len(session.windows) >= 1
62+
63+
64+
def test_pane_titles(session: Session) -> None:
65+
"""Test pane-titles.yaml builds with pane title options."""
66+
config = ConfigReader._from_file(EXAMPLE_PATH / "pane-titles.yaml")
67+
config = loader.expand(config)
68+
builder = WorkspaceBuilder(session_config=config, server=session.server)
69+
builder.build(session=session)
70+
71+
window = session.windows[0]
72+
assert window.show_option("pane-border-status") == "top"
73+
assert window.show_option("pane-border-format") == "#{pane_index}: #{pane_title}"
74+
75+
panes = window.panes
76+
assert len(panes) == 3
77+
78+
def check_title(p: Pane, expected: str) -> bool:
79+
p.refresh()
80+
return p.pane_title == expected
81+
82+
assert retry_until(
83+
functools.partial(check_title, panes[0], "editor"),
84+
), f"Expected title 'editor', got '{panes[0].pane_title}'"
85+
assert retry_until(
86+
functools.partial(check_title, panes[1], "runner"),
87+
), f"Expected title 'runner', got '{panes[1].pane_title}'"

0 commit comments

Comments
 (0)