joouha / euporie

Jupyter notebooks in the terminal
https://euporie.readthedocs.io
MIT License
1.54k stars 36 forks source link

Confused about emacs keybindings #66

Closed twrightsman closed 1 year ago

twrightsman commented 1 year ago

This has been a really cool piece of software to try out, but I'm confused by the Emacs keybindings.

First, even though the Emacs bindings are active, I still only see the Micro keybindings described in the help menu.

I can't seem to use some common Emacs keybindings like:

My current configuration file looks like this:

{
  "notebook": {
      "line_numbers": true,
      "edit_mode": "emacs",
      "key_bindings": {
          "euporie.notebook.app.NotebookApp": {
              "go-to-end-of-line": ["c-e"],
              "run-selected-cells": ["c-enter"],
              "start-selection": ["c-space"],
              "cut-selection": ["c-w"]
          }
      }
  }
}

The cut-selection seems to work (and no longer closes the current file), but the other three do not work as expected. Ctrl + e still runs the selected cells and Ctrl + Space doesn't seem to do anything.

twrightsman commented 1 year ago

Taking some inspiration from the code (the docs should probably mention this), my configuration file now looks like:

{
  "notebook": {
      "line_numbers": true,
      "edit_mode": "emacs",
      "key_bindings": {
          "euporie.notebook.app.NotebookApp": {
              "go-to-end-of-line": ["c-e"],
              "run-selected-cells": ["s-enter"],
              "start-selection": ["c-space"],
              "cut-selection": ["c-w"]
          },
          "euporie.notebook.tabs.notebook.Notebook": {
              "run-selected-cells": []
          }
      }
  }
}

Now Ctrl+e moves to the end of the line! And switching from GNOME Terminal to Foot solved an issue with not recognizing Shift+Enter.

I also forgot to mention I am using version 2.3.2 from conda-forge.

Remaining issues include:

  1. Ctrl+Space does not start a selection.
  2. Help menu displays Micro key bindings even if Emacs key bindings enabled.
joouha commented 1 year ago

Hello,

I'll prefix my reply by saying that the key-bindings system is not perfect and still needs a bit of work. Also, the documentation around key-bindings is a bit lacking in some areas. Also, I'm not au fait with emacs' or vim's key-bindings myself, so I haven't really been to test that they work as expected to the extent that I'd like. But I'd like to improve these things!

I'll try and explain things a bit better here.

The first thing to know is that the editor style key-bindings (emacs/vi/micro) apply only to text input fields, so will only be active if you are editing a cell.

Second, the emacs (and vi) style editor key-bindings are inherited from the prompt_toolkit project. They do not use the same centralized command registry system that is used in the rest of euporie, which is part of why the emacs or vi style key-bindings are not shown in the menus when they are active. For this to work, I need to port the prompt_toolkit emacs and vi style bindings to use my centralized command registry, which is a large undertaking.

Third, is that key-bindings cascade up from the active control in the layout to the root of the layout. This means that if a key-binding is set for a cell input, and the same binding is set for a notebook document, then the notebook binding will take precedence.

This is the case for Ctrl-e. When the emacs bindings are active and a cell is being edited, there is an active binding on the text-input to go to the end of the current line, but also an active key-binding on the notebook document to run the current cell (also Ctrl-e).

Ctrl-space is bound to the show-command-palette command in the base application, so you'll need to add the following to your config to disable the command palette:

{
  "notebook": {
    "key_bindings": {
      "euporie.core.app.BaseApp": {
        "show-command-palette": []
      }
   }
}

This should make Ctrl-space work as expected with the emacs style editor bindings turned on.

The method of custom key-binding configuration is clearly far too complicated - I'll have a think about a better way to implement this.

twrightsman commented 1 year ago

Thank you for this detailed and thoughtful explanation!

Yes, it does seem that key binding configuration is fairly complex at the moment but I can also see why it currently works the way it does.

In the interim, is there a way to list the (currently active) key bindings for all of the commands helpfully listed here and at what layout level? Then at least I can try to figure out what is overriding what.

joouha commented 1 year ago

Here are all the default key-bindings in the JSON format used in the configuration file:

{
  "euporie.core.app.BaseApp": {
    "quit": "c-q",
    "close-tab": "c-w",
    "next-tab": "c-pagedown",
    "previous-tab": "c-pageup",
    "focus-next": "s-tab",
    "focus-previous": "tab",
    "clear-screen": "c-l",
    "next-completion": "c-i",
    "previous-completion": "s-tab",
    "cancel-completion": "escape",
    "accept-completion": "enter",
    "open-file": "c-o",
    "save-as": [
      "escape",
      "s"
    ],
    "show-command-palette": "c-@",
    "find": [
      "c-f",
      "f3",
      "f7"
    ],
    "find-next": "c-g",
    "find-previous": "c-p"
  },
  "euporie.core.tabs.base.Tab": {
    "save-file": "c-s",
    "reset-tab": "f5"
  },
  "euporie.notebook.app.NotebookApp": {
    "toggle-side-bar-pane": "c-b",
    "new-notebook": "c-n",
    "toggle-show-top-bar": [
      "escape",
      "m"
    ]
  },
  "euporie.notebook.tabs.notebook.Notebook": {
    "enter-cell-edit-mode": "enter",
    "exit-edit-mode": "escape",
    "run-selected-cells": [
      "c-enter",
      "c-e"
    ],
    "run-and-select-next": [
      "s-enter",
      "c-r"
    ],
    "run-cell-and-insert-below": [
      "escape",
      "enter"
    ],
    "add-cell-above": "a",
    "add-cell-below": "b",
    "delete-cells": [
      "d",
      "d"
    ],
    "undelete-cells": "z",
    "cut-cells": "x",
    "copy-cells": "c",
    "copy-outputs": [
      "escape",
      "c"
    ],
    "paste-cells": "v",
    "interrupt-kernel": [
      "i",
      "i"
    ],
    "restart-kernel": [
      "0",
      "0"
    ],
    "scroll-up": [
      "[",
      "<scroll-up>"
    ],
    "scroll-down": [
      "]",
      "<scroll-down>"
    ],
    "scroll-up-5-lines": "{",
    "scroll-down-5-lines": "}",
    "select-first-cell": [
      "home",
      "c-up"
    ],
    "select-5th-previous-cell": "pageup",
    "select-previous-cell": [
      "up",
      "k"
    ],
    "select-next-cell": [
      "down",
      "j"
    ],
    "select-5th-next-cell": "pagedown",
    "select-last-cell": [
      "end",
      "c-down"
    ],
    "select-all-cells": "c-a",
    "extend-cell-selection-to-top": "s-home",
    "extend-cell-selection-up": [
      "s-up",
      "K"
    ],
    "extend-cell-selection-down": [
      "s-down",
      "J"
    ],
    "extend-cell-selection-to-bottom": "s-end",
    "move-cells-up": [
      "escape",
      "up"
    ],
    "move-cells-down": [
      "escape",
      "down"
    ],
    "cells-to-markdown": "m",
    "cells-to-code": "y",
    "cells-to-raw": "r",
    "reformat-cells": "f",
    "reformat-notebook": "F",
    "edit-in-external-editor": "e",
    "merge-cells": "M",
    "split-cell": "c-\\",
    "edit-previous-cell": "up",
    "edit-next-cell": "down",
    "scroll-output-left": "left",
    "scroll-output-right": "right",
    "toggle-expand": "w",
    "notebook-toggle-line-numbers": "l"
  },
  "euporie.console.app.ConsoleApp": {
    "clear-input": "c-c",
    "run-input": [
      "c-enter",
      "c-e"
    ],
    "history-prev": "c-up",
    "history-next": "c-down",
    "clear-screen": "c-l",
    "end-of-file": "c-d"
  },
  "euporie.console.tabs.console.Console": {
    "cc-interrupt-kernel": "c-c",
    "show-contextual-help": "s-tab"
  },
  "euporie.preview.app.PreviewApp": {
    "quit": [
      "c-c",
      "c-q"
    ]
  },
  "euporie.core.key_binding.bindings.micro.EditMode": {
    "type-key": "<any>",
    "move-cursor-right": "right",
    "move-cursor-left": "left",
    "newline": "enter",
    "accept-line": "enter",
    "backspace": [
      "backspace",
      "c-h"
    ],
    "backward-kill-word": [
      [
        "escape",
        "backspace"
      ],
      [
        "escape",
        "c-h"
      ]
    ],
    "start-selection": [
      "s-up",
      "s-down",
      "s-right",
      "s-left",
      [
        "escape",
        "s-left"
      ],
      [
        "escape",
        "s-right"
      ],
      "c-s-left",
      "c-s-right",
      "s-home",
      "s-end",
      "c-s-home",
      "c-s-end"
    ],
    "extend-selection": [
      "s-up",
      "s-down",
      "s-right",
      "s-left",
      [
        "escape",
        "s-left"
      ],
      [
        "escape",
        "s-right"
      ],
      "c-s-left",
      "c-s-right",
      "s-home",
      "s-end",
      "c-s-home",
      "c-s-end"
    ],
    "cancel-selection": [
      "up",
      "down",
      "right",
      "left",
      [
        "escape",
        "left"
      ],
      [
        "escape",
        "right"
      ],
      "c-left",
      "c-right",
      "home",
      "end",
      "c-home",
      "c-end"
    ],
    "replace-selection": "<any>",
    "delete-selection": [
      "delete",
      "backspace",
      "c-h"
    ],
    "backward-word": [
      "c-left",
      [
        "escape",
        "b"
      ]
    ],
    "forward-word": [
      "c-right",
      [
        "escape",
        "f"
      ]
    ],
    "move-lines-up": [
      "escape",
      "up"
    ],
    "move-lines-down": [
      "escape",
      "down"
    ],
    "go-to-start-of-line": [
      "home",
      [
        "escape",
        "left"
      ],
      [
        "escape",
        "a"
      ]
    ],
    "go-to-end-of-line": [
      "end",
      [
        "escape",
        "right"
      ],
      [
        "escape",
        "e"
      ]
    ],
    "beginning-of-buffer": [
      "c-up",
      "c-home"
    ],
    "end-of-buffer": [
      "c-down",
      "c-end"
    ],
    "go-to-start-of-paragraph": [
      "escape",
      "{"
    ],
    "go-to-end-of-paragraph": [
      "escape",
      "}"
    ],
    "indent-lines": "tab",
    "unindent-line": "backspace",
    "unindent-lines": "s-tab",
    "undo": "c-z",
    "redo": "c-y",
    "copy-selection": "c-c",
    "cut-selection": [
      "c-x",
      "s-delete"
    ],
    "cut-line": "c-k",
    "duplicate-line": "c-d",
    "duplicate-selection": "c-d",
    "paste-clipboard": "c-v",
    "select-all": "c-a",
    "scroll-page-up": "pageup",
    "scroll-page-down": "pagedown",
    "delete": "delete",
    "toggle-case": "f4",
    "toggle-overwrite-mode": "insert",
    "start-macro": "c-u",
    "end-macro": "c-u",
    "run-macro": "c-j",
    "accept-suggestion": [
      "right",
      "c-f"
    ],
    "fill-sugestion": [
      "escape",
      "f"
    ],
    "toggle-comment": "c-_",
    "go-to-matching-bracket": [
      [
        "escape",
        "("
      ],
      [
        "escape",
        ")"
      ]
    ],
    "wrap-selection-\"\"": "\"",
    "wrap-selection-''": "'",
    "wrap-selection-()": [
      "(",
      ")"
    ],
    "wrap-selection-{}": [
      "{",
      "}"
    ],
    "wrap-selection-[]": [
      "[",
      "]"
    ],
    "wrap-selection-``": "`",
    "wrap-selection-**": "*",
    "wrap-selection-__": "_"
  },
  "euporie.core.widgets.pager.Pager": {
    "close-pager": [
      "escape",
      "q"
    ]
  },
  "euporie.core.widgets.inputs.KernelInput": {
    "show-contextual-help": "s-tab"
  },
  "euporie.core.widgets.display.Display": {
    "scroll-display-left": "left",
    "scroll-display-right": "right",
    "scroll-display-up": [
      "up",
      "k"
    ],
    "scroll-display-down": [
      "down",
      "j"
    ],
    "page-up-display": "pageup",
    "page-down-display": "pagedown",
    "go-to-start-of-display": "home",
    "go-to-end-of-display": "end"
  },
  "euporie.web.widgets.webview.WebViewControl": {
    "scroll-webview-left": "left",
    "scroll-webview-right": "right",
    "scroll-webview-up": [
      "up",
      "k"
    ],
    "scroll-webview-down": [
      "down",
      "j"
    ],
    "page-up-webview": "pageup",
    "page-down-webview": "pagedown",
    "go-to-start-of-webview": "home",
    "go-to-end-of-webview": "end",
    "webview-nav-prev": [
      "escape",
      "left"
    ],
    "webview-nav-next": [
      "escape",
      "right"
    ]
  }
}

This will be included in the documentation in the next release.

twrightsman commented 1 year ago

Thank you for this. I think we can consider this particular issue closed, but feel free to re-open if you disagree!