Skip to content

Commit f2eaddc

Browse files
committed
wip PyREPL: Add ctrl+up/down for multiline history
Currently, the up/down keys move the cursor in that direction inside the current code block until it reaches the beginning/end, then it goes to the previous/next. However, when traversing history with lots of multiline blocks, this can be a cumbersome process. This PR introduces the ability to traverse history one block at a time using the CTRL+Up or CTRL+Down keys. Originated from https://discuss.python.org/t/pyrepl-add-ctrl-up-down-for-multiline-history-retrieving/107779
1 parent c2ca772 commit f2eaddc

5 files changed

Lines changed: 26 additions & 1 deletion

File tree

‎Lib/_pyrepl/commands.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,23 @@ def do(self) -> None:
371371
for i in range(r.get_arg()):
372372
r.pos = r.bow()
373373

374+
class up_history(MotionCommand):
375+
def do(self) -> None:
376+
r = self.reader
377+
if r.historyi > 0:
378+
r.select_item(r.historyi - 1)
379+
else:
380+
r.error("start of history")
381+
return
382+
383+
class down_history(MotionCommand):
384+
def do(self) -> None:
385+
r = self.reader
386+
if r.historyi < len(r.history):
387+
r.select_item(r.historyi + 1)
388+
else:
389+
r.error("end of history")
390+
return
374391

375392
class self_insert(EditCommand):
376393
def do(self) -> None:

‎Lib/_pyrepl/keymap.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ def _parse_single_key_sequence(key: str, s: int) -> tuple[list[str], int]:
183183
if ctrl:
184184
if len(ret) == 1:
185185
ret = chr(ord(ret) & 0x1F) # curses.ascii.ctrl()
186-
elif ret in {"left", "right"}:
186+
elif ret in {"left", "right", "up", "down"}:
187187
ret = f"ctrl {ret}"
188188
else:
189189
raise KeySpecError("\\C- followed by invalid key")

‎Lib/_pyrepl/reader.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ def make_default_commands() -> dict[CommandName, CommandClass]:
135135
+ [(c, "self-insert") for c in map(chr, range(128, 256)) if c.isalpha()]
136136
+ [
137137
(r"\<up>", "up"),
138+
(r"\C-\<up>", "up_history"),
138139
(r"\<down>", "down"),
140+
(r"\C-\<down>", "down_history"),
139141
(r"\<left>", "left"),
140142
(r"\C-\<left>", "backward-word"),
141143
(r"\<right>", "right"),

‎Lib/_pyrepl/unix_eventqueue.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,13 @@
4949
# for xterm, gnome-terminal, xfce terminal, etc.
5050
b'\033[1;5D': 'ctrl left',
5151
b'\033[1;5C': 'ctrl right',
52+
b'\033[1;5A': 'ctrl up',
53+
b'\033[1;5B': 'ctrl down',
5254
# for rxvt
5355
b'\033Od': 'ctrl left',
5456
b'\033Oc': 'ctrl right',
57+
b'\033Oa': 'ctrl up',
58+
b'\033Ob': 'ctrl down',
5559
}
5660

5761
def get_terminal_keycodes(ti: TermInfo) -> dict[bytes, str]:

‎Lib/_pyrepl/windows_eventqueue.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
b'\x1b[D': 'left',
1414
b'\x1b[1;5D': 'ctrl left',
1515
b'\x1b[1;5C': 'ctrl right',
16+
b'\x1b[1;5A': 'ctrl up',
17+
b'\x1b[1;5B': 'ctrl down',
1618

1719
b'\x1b[H': 'home',
1820
b'\x1b[F': 'end',

0 commit comments

Comments
 (0)