Skip to content

Commit 702b59e

Browse files
committed
Cleanup and refactor
1 parent 2a64680 commit 702b59e

File tree

1 file changed

+46
-44
lines changed

1 file changed

+46
-44
lines changed

Lib/_pyrepl/unix_eventqueue.py

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@
1818
# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1919
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2020

21-
# Bah, this would be easier to test if curses/terminfo didn't have so
22-
# much non-introspectable global state.
23-
2421
from collections import deque
2522

2623
from . import keymap
@@ -31,7 +28,8 @@
3128
import os
3229

3330

34-
_keynames = {
31+
# Mapping of human-readable key names to their terminal-specific codes
32+
TERMINAL_KEYNAMES = {
3533
"delete": "kdch1",
3634
"down": "kcud1",
3735
"end": "kend",
@@ -46,20 +44,11 @@
4644
}
4745

4846

49-
#function keys x in 1-20 -> fX: kfX
50-
_keynames.update(('f%d' % i, 'kf%d' % i) for i in range(1, 21))
47+
# Function keys F1-F20 mapping
48+
TERMINAL_KEYNAMES.update(("f%d" % i, "kf%d" % i) for i in range(1, 21))
5149

52-
# this is a bit of a hack: CTRL-left and CTRL-right are not standardized
53-
# termios sequences: each terminal emulator implements its own slightly
54-
# different incarnation, and as far as I know, there is no way to know
55-
# programmatically which sequences correspond to CTRL-left and
56-
# CTRL-right. In bash, these keys usually work because there are bindings
57-
# in ~/.inputrc, but pyrepl does not support it. The workaround is to
58-
# hard-code here a bunch of known sequences, which will be seen as "ctrl
59-
# left" and "ctrl right" keys, which can be finally be mapped to commands
60-
# by the reader's keymaps.
61-
#
62-
CTRL_ARROW_KEYCODE = {
50+
# Known CTRL-arrow keycodes
51+
CTRL_ARROW_KEYCODES= {
6352
# for xterm, gnome-terminal, xfce terminal, etc.
6453
b'\033[1;5D': 'ctrl left',
6554
b'\033[1;5C': 'ctrl right',
@@ -68,74 +57,87 @@
6857
b'\033Oc': 'ctrl right',
6958
}
7059

71-
def general_keycodes():
60+
def get_terminal_keycodes():
61+
"""
62+
Generates a dictionary mapping terminal keycodes to human-readable names.
63+
"""
7264
keycodes = {}
73-
for key, tiname in _keynames.items():
74-
keycode = curses.tigetstr(tiname)
65+
for key, terminal_code in TERMINAL_KEYNAMES.items():
66+
keycode = curses.tigetstr(terminal_code)
7567
trace('key {key} tiname {tiname} keycode {keycode!r}', **locals())
7668
if keycode:
7769
keycodes[keycode] = key
78-
keycodes.update(CTRL_ARROW_KEYCODE)
70+
keycodes.update(CTRL_ARROW_KEYCODES)
7971
return keycodes
8072

81-
82-
def EventQueue(fd, encoding):
83-
keycodes = general_keycodes()
84-
if os.isatty(fd):
85-
backspace = tcgetattr(fd)[6][VERASE]
86-
keycodes[backspace] = 'backspace'
87-
k = keymap.compile_keymap(keycodes)
88-
trace('keymap {k!r}', k=k)
89-
return EncodedQueue(k, encoding)
90-
91-
92-
class EncodedQueue(object):
93-
def __init__(self, keymap, encoding):
94-
self.k = self.ck = keymap
73+
class EventQueue(object):
74+
def __init__(self, fd, encoding):
75+
self.keycodes = get_terminal_keycodes()
76+
if os.isatty(fd):
77+
backspace = tcgetattr(fd)[6][VERASE]
78+
self.keycodes[backspace] = "backspace"
79+
self.compiled_keymap = keymap.compile_keymap(self.keycodes)
80+
self.keymap = self.compiled_keymap
81+
trace("keymap {k!r}", k=self.keymap)
82+
self.encoding = encoding
9583
self.events = deque()
9684
self.buf = bytearray()
97-
self.encoding = encoding
9885

9986
def get(self):
87+
"""
88+
Retrieves the next event from the queue.
89+
"""
10090
if self.events:
10191
return self.events.popleft()
10292
else:
10393
return None
10494

10595
def empty(self):
96+
"""
97+
Checks if the queue is empty.
98+
"""
10699
return not self.events
107100

108101
def flush_buf(self):
102+
"""
103+
Flushes the buffer and returns its contents.
104+
"""
109105
old = self.buf
110106
self.buf = bytearray()
111107
return old
112108

113109
def insert(self, event):
110+
"""
111+
Inserts an event into the queue.
112+
"""
114113
trace('added event {event}', event=event)
115114
self.events.append(event)
116115

117116
def push(self, char):
117+
"""
118+
Processes a character by updating the buffer and handling special key mappings.
119+
"""
118120
ord_char = char if isinstance(char, int) else ord(char)
119121
char = bytes(bytearray((ord_char,)))
120122
self.buf.append(ord_char)
121-
if char in self.k:
122-
if self.k is self.ck:
123+
if char in self.keymap:
124+
if self.keymap is self.compiled_keymap:
123125
#sanity check, buffer is empty when a special key comes
124126
assert len(self.buf) == 1
125-
k = self.k[char]
127+
k = self.keymap[char]
126128
trace('found map {k!r}', k=k)
127129
if isinstance(k, dict):
128-
self.k = k
130+
self.keymap = k
129131
else:
130132
self.insert(Event('key', k, self.flush_buf()))
131-
self.k = self.ck
133+
self.keymap = self.compiled_keymap
132134

133135
elif self.buf and self.buf[0] == 27: # escape
134136
# escape sequence not recognized by our keymap: propagate it
135137
# outside so that i can be recognized as an M-... key (see also
136-
# the docstring in keymap.py, in particular the line \\E.
138+
# the docstring in keymap.py
137139
trace('unrecognized escape sequence, propagating...')
138-
self.k = self.ck
140+
self.keymap = self.compiled_keymap
139141
self.insert(Event('key', '\033', bytearray(b'\033')))
140142
for c in self.flush_buf()[1:]:
141143
self.push(chr(c))
@@ -147,4 +149,4 @@ def push(self, char):
147149
return
148150
else:
149151
self.insert(Event('key', decoded, self.flush_buf()))
150-
self.k = self.ck
152+
self.keymap = self.compiled_keymap

0 commit comments

Comments
 (0)