aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_prefix.py
blob: eff6911eaac83d57949affc5ba7a001db160d9f0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!/usr/bin/env python3
"""The leader key is whatever you say it is — everywhere.

It has always been configurable; what had not been was the badge in the status
bar, which was the string "C-a" whatever you had bound. A prefix you can
change and a UI that keeps naming the old one is worse than no setting: it
teaches you to distrust the thing that is telling you which mode you are in.

So this is mostly one assertion made in several places: rebind it, and the
badge, the cheatsheet, the swallowing and the pass-through all follow.
"""

import sys
import tempfile

from harness import Session, check, report

# `cat -v`, so a control byte that reaches the program is *visible* as ^A
# rather than arriving as an invisible control character and proving nothing.
SH = ["/bin/sh", "-c", 'printf "\\033]2;p\\007"; stty raw -echo; cat -v']


def cfg(prefix):
    f = tempfile.NamedTemporaryFile("w", suffix=".kdl", delete=False)
    f.write('keys {\n    prefix "%s"\n}\n' % prefix)
    f.close()
    return f.name


def strip(s):
    return s.snapshot().line(1)


def test_the_badge_names_the_key_you_bound():
    for prefix, chord, shown in (
        ("ctrl+a", r"\x01", "C-a"),
        ("ctrl+b", r"\x02", "C-b"),
        ("ctrl+space", r"\x00", "C-space"),
        ("alt+x", r"\ex", "M-x"),
    ):
        with Session(SH, cols=60, rows=8, config=cfg(prefix)) as s:
            s.settle()
            check(
                f"{prefix}: no badge until it is pressed",
                shown not in strip(s),
                strip(s),
            )
            s.send(chord)
            s.settle()
            check(f"{prefix}: the badge says {shown}", shown in strip(s), strip(s))


def test_a_rebound_prefix_actually_works():
    with Session(SH, cols=80, rows=14, config=cfg("ctrl+b")) as s:
        s.settle()
        check("one pane to start", len(s.panes()) == 1)
        s.send(r"\x02\\")  # C-b \ : split
        s.settle()
        check("the new prefix runs commands", len(s.panes()) == 2, str(s.panes()))


def test_the_old_prefix_goes_to_the_program_instead():
    """The reason to move it: C-a is start-of-line to half the world."""
    with Session(SH, cols=80, rows=14, config=cfg("ctrl+b")) as s:
        s.settle()
        s.send(r"\x01")  # C-a, no longer ours
        s.settle(40)
        check("C-a is not swallowed as a prefix", "C-a" not in strip(s), strip(s))
        snap = s.until(lambda sn: "^A" in sn.screen())
        check("it reached the program", "^A" in snap.screen(), snap.screen()[:200])


def test_pressing_the_prefix_twice_sends_it_on():
    with Session(SH, cols=80, rows=14, config=cfg("ctrl+b")) as s:
        s.settle()
        s.send(r"\x02\x02")
        s.settle(40)
        check("the badge is gone again", "C-b" not in strip(s), strip(s))
        snap = s.until(lambda sn: "^B" in sn.screen())
        check(
            "and the pane got the keystroke", "^B" in snap.screen(), snap.screen()[:200]
        )


def test_the_cheatsheet_agrees_with_the_badge():
    with Session(SH, cols=92, rows=28, config=cfg("ctrl+b")) as s:
        s.settle()
        s.send(r"\x02?")
        s.settle()
        screen = s.snapshot().screen()
        check("the cheatsheet names the same key", "C-b then:" in screen, screen)
        check("and not the old one", "C-a then:" not in screen, screen)


for name, fn in sorted(list(globals().items())):
    if name.startswith("test_"):
        fn()
sys.exit(report())