prompt-toolkit / python-prompt-toolkit

Library for building powerful interactive command line applications in Python
https://python-prompt-toolkit.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
9.1k stars 717 forks source link

Inconsistent "history forward/backward" Emacs bindings #1794

Open galaux opened 8 months ago

galaux commented 8 months ago

Hi !

First of all, thanks for your time working on this library.

I constantly hit a frustrating inconsistency between the bindings in Emacs and prompt_toolkit's Emacs bindings (I'm using pgcli):

Emacs prompt_toolkit with Emacs bindings
Alt-p Backward in history Letter p
Alt-n Forward in history Letter n
Ctrl-p Move cursor up one line Backward in history unless current history entry is multi-line in which case move cursor up one line
Ctrl-n Move cursor down one line Forward in history unless current history entry is multi-line in which case move cursor down one line

Hours of use of Emacs and terminals have engraved Alt-p/Alt-n in my muscle memory as the history navigation actions, so when I switch to pgcli and want to move back and forth in history, all I get is a frustrating list of p and n.

I've managed to get the expected Emacs behavior with the simple following changes:

diff --git a/src/prompt_toolkit/key_binding/bindings/emacs.py b/src/prompt_toolkit/key_binding/bindings/emacs.py
index 80a66fd2..88b456c6 100644
--- a/src/prompt_toolkit/key_binding/bindings/emacs.py
+++ b/src/prompt_toolkit/key_binding/bindings/emacs.py
@@ -107,12 +107,20 @@ def load_emacs_bindings() -> KeyBindingsBase:
     @handle("c-n")
     def _next(event: E) -> None:
         "Next line."
-        event.current_buffer.auto_down()
+        event.current_buffer.cursor_down(count=event.arg)

     @handle("c-p")
     def _prev(event: E) -> None:
         "Previous line."
-        event.current_buffer.auto_up(count=event.arg)
+        event.current_buffer.cursor_up(count=event.arg)
+
+    @handle("escape", "p")
+    def _history_backward(event: E) -> None:
+        event.current_buffer.history_backward(count=event.arg)
+
+    @handle("escape", "n")
+    def _history_forward(event: E) -> None:
+        event.current_buffer.history_forward(count=event.arg)

     def handle_digit(c: str) -> None:
         """

To be fair, in order for this to work, I also need to remove pgcli's own customization:

diff --git a/pgcli/key_bindings.py b/pgcli/key_bindings.py
index 9c016f7f..eb847aee 100644
--- a/pgcli/key_bindings.py
+++ b/pgcli/key_bindings.py
@@ -120,14 +120,4 @@ def pgcli_bindings(pgcli):
         _logger.debug("Detected alt-enter key.")
         event.app.current_buffer.insert_text("\n")

-    @kb.add("c-p", filter=~has_selection)
-    def _(event):
-        """Move up in history."""
-        event.current_buffer.history_backward(count=event.arg)
-
-    @kb.add("c-n", filter=~has_selection)
-    def _(event):
-        """Move down in history."""
-        event.current_buffer.history_forward(count=event.arg)
-
     return kb

For the sake of consistency, one could want to also set this behavior for ViM bindings though I wouldn't as there isn't anything broken per-se in the ViM bindings:

diff --git a/src/prompt_toolkit/key_binding/bindings/vi.py b/src/prompt_toolkit/key_binding/bindings/vi.py
index 436a553c..39e0151d 100644
--- a/src/prompt_toolkit/key_binding/bindings/vi.py
+++ b/src/prompt_toolkit/key_binding/bindings/vi.py
@@ -454,7 +454,7 @@ def load_vi_bindings() -> KeyBindingsBase:
         """
         Arrow up and ControlP in navigation mode go up.
         """
-        event.current_buffer.auto_up(count=event.arg)
+        event.current_buffer.cursor_up(count=event.arg)

     @handle("k", filter=vi_navigation_mode)
     def _go_up(event: E) -> None:
@@ -472,7 +472,7 @@ def load_vi_bindings() -> KeyBindingsBase:
         """
         Arrow down and Control-N in navigation mode.
         """
-        event.current_buffer.auto_down(count=event.arg)
+        event.current_buffer.cursor_down(count=event.arg)

     @handle("j", filter=vi_navigation_mode)
     def _go_down2(event: E) -> None:

Would you be open to adding these changes ?