OILS / spec / stateful / bind.py View on Github | oilshell.org

164 lines, 98 significant
1#!/usr/bin/env python3
2"""
3spec/stateful/bind.py
4"""
5from __future__ import print_function
6
7import sys
8import tempfile
9import time
10
11import harness
12from harness import expect_prompt, register
13
14from test.spec_lib import log
15
16
17def add_foo_fn(sh):
18 sh.sendline('function foo() { echo "FOO"; }')
19 time.sleep(0.1)
20
21
22def send_bind(sh, opts, keymap=None):
23 "Helper method to send a bind command and sleep for a moment. W/ optional keymap."
24
25 if keymap:
26 sh.sendline(f"bind -m {keymap} {opts}")
27 else:
28 sh.sendline(f"bind {opts}")
29 time.sleep(0.1)
30
31
32@register(not_impl_shells=['dash', 'mksh'])
33def bind_plain(sh):
34 "test bind (w/out flags) for adding bindings to readline fns"
35 expect_prompt(sh)
36
37 # There aren't many readline fns that will work nicely with pexpect (e.g., cursor-based fns)
38 # Editing input seems like a reasonable choice
39 send_bind(sh, ''' '"\C-x\C-h": backward-delete-char' ''')
40 expect_prompt(sh)
41
42 sh.send("echo FOOM")
43 sh.sendcontrol('x')
44 sh.sendcontrol('h')
45 sh.sendline("P")
46 time.sleep(0.1)
47
48 sh.expect("FOOP")
49
50
51@register(not_impl_shells=['dash', 'mksh'])
52def bind_r(sh):
53 "test bind -r for removing bindings"
54 expect_prompt(sh)
55
56 add_foo_fn(sh)
57 expect_prompt(sh)
58
59 send_bind(sh, """-x '"\C-x\C-f": foo' """)
60 expect_prompt(sh)
61
62 sh.sendcontrol('x')
63 sh.sendcontrol('f')
64 time.sleep(0.1)
65 sh.expect("FOO")
66
67 send_bind(sh, '-r "\C-x\C-f" ')
68
69 sh.sendcontrol('x')
70 sh.sendcontrol('f')
71 time.sleep(0.1)
72
73 expect_prompt(sh)
74
75
76@register(not_impl_shells=['dash', 'mksh'])
77def bind_x(sh):
78 "test bind -x for setting bindings to custom shell functions"
79 expect_prompt(sh)
80
81 add_foo_fn(sh)
82 expect_prompt(sh)
83
84 send_bind(sh, """-x '"\C-x\C-f": foo' """)
85 expect_prompt(sh)
86
87 sh.sendcontrol('x')
88 sh.sendcontrol('f')
89 time.sleep(0.1)
90
91 sh.expect("FOO")
92
93
94@register(not_impl_shells=['dash', 'mksh'])
95def bind_u(sh):
96 "test bind -u for unsetting all bindings to a fn"
97 expect_prompt(sh)
98
99 send_bind(sh, "'\C-p: yank'")
100 expect_prompt(sh)
101
102 send_bind(sh, "-u yank")
103 expect_prompt(sh)
104
105 send_bind(sh, "-q yank")
106 sh.expect("yank is not bound to any keys")
107
108
109@register(not_impl_shells=['dash', 'mksh'])
110def bind_q(sh):
111 "test bind -q for querying bindings to a fn"
112 expect_prompt(sh)
113
114 # Probably bound, but we're not testing that precisely
115 send_bind(sh, "-q yank")
116 sh.expect(["yank can be invoked via", "yank is not bound to any keys"])
117
118 expect_prompt(sh)
119
120 # Probably NOT bound, but we're not testing that precisely
121 send_bind(sh, "-q dump-functions")
122 sh.expect([
123 "dump-functions can be invoked via",
124 "dump-functions is not bound to any keys"
125 ])
126
127
128@register(not_impl_shells=['dash', 'mksh'])
129def bind_m(sh):
130 "test bind -m for setting bindings in specific keymaps"
131 expect_prompt(sh)
132
133 send_bind(sh, "-u yank", "vi")
134 expect_prompt(sh)
135
136 send_bind(sh, "'\C-p: yank'", "emacs")
137 expect_prompt(sh)
138
139 send_bind(sh, "-q yank", "vi")
140 sh.expect("yank is not bound to any keys")
141 expect_prompt(sh)
142
143 send_bind(sh, "-q yank", "emacs")
144 sh.expect("yank can be invoked via")
145
146
147@register(not_impl_shells=['dash', 'mksh'])
148def bind_f(sh):
149 "test bind -f for setting bindings from an inputrc init file"
150 expect_prompt(sh)
151
152 send_bind(sh, "-f spec/testdata/bind/bind_f.inputrc")
153 expect_prompt(sh)
154
155 send_bind(sh, "-q downcase-word")
156 sh.expect('downcase-word can be invoked via.*"\\\C-o\\\C-s\\\C-h"')
157
158
159if __name__ == '__main__':
160 try:
161 sys.exit(harness.main(sys.argv))
162 except RuntimeError as e:
163 print('FATAL: %s' % e, file=sys.stderr)
164 sys.exit(1)