-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial VIM support in cell editors #8706
Conversation
Thanks for making a pull request to JupyterLab! To try out this branch on binder, follow this link: |
!!! very excited to see this moving towards core jupyterlab 😄
Is this restriction on More generally given the history and user base of https://github.com/jwkvam/jupyterlab-vim I think that any implementation in core should strive to maintain the extension's approach to adapting the vim keymap to jupyter. Not only are the extension's choices sensible, but many people are accustomed to them and there will be a fracturing of the user base if the core implementation does not match them. Personally I could live without some of the shortcuts in the existing jupyterlab-vim extension, but if
I think it is worth taking most (or even all) of the keymaps for maneuvering the notebook from the existing extensions list here: https://github.com/axelfahy/jupyterlab-vim#key-bindings and defined here and here I'm happy to help with this however would be most useful (feedback, adding coding, meeting to talk about it, other things?). Also CC two other people who may be interested in this: @axelfahy, @jwkvam |
I also see that this is marked as "initial" so I totally get not having worked out all the keymap details, but I guess my contention is that a partial vim support would be worse than no support and people instead using the more complete extensions. |
Thanks @echarles for this! Just tried on the Binder and it looks great. It looks like navigating between cells using k and j when the notebook is in command mode also works. But that seems to be the default in JupyterLab.
Indeed, other bindings such as z,z to recenter the scroll position would also be useful (currently it's the keybinding to delete cells). Or d,d and p to cut a cell and paste it somewhere else. But that goes beyond vim support in cell editors since they apply to the notebook command mode, and could be added in a separate change. |
@echarles is this PR ready to review? |
@blink1073 Nope... (not sure how to put in back in draft) as we have received user feedback on various channels and need to make sure we address them, especially regarding key binding. I need to digest the comments and connect back to have a common agreement on the features before this can be reviewed. |
4e9d4c9
to
b066666
Compare
Last commit adds shortcut to move up/down the cell. I have tried to use
|
{ | ||
"command": "notebook:move-cell-down", | ||
"keys": ["Ctrl J"], | ||
"selector": ".jp-Notebook:focus" | ||
}, | ||
{ | ||
"command": "notebook:move-cell-up", | ||
"keys": ["Ctrl K"], | ||
"selector": ".jp-Notebook:focus" | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The suggested change below would bring these commands in line with what the extensions currently do. Although having a command to move cells up and down in jupyter command mode would also be awesome. Maybe we could add both?
{ | |
"command": "notebook:move-cell-down", | |
"keys": ["Ctrl J"], | |
"selector": ".jp-Notebook:focus" | |
}, | |
{ | |
"command": "notebook:move-cell-up", | |
"keys": ["Ctrl K"], | |
"selector": ".jp-Notebook:focus" | |
}, | |
{ | |
"command": "notebook:move-cursor-down", | |
"keys": ["Ctrl J"], | |
"selector": ".jp-Notebook.jp-mod-editMode" | |
}, | |
{ | |
"command": "notebook:move-cursor-up", | |
"keys": ["Ctrl K"], | |
"selector": ".jp-Notebook.jp-mod-editMode" | |
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
having a command to move cells up and down in jupyter command mode would also be awesome.
this applies in jupyter command mode
. Maybe you mean in VIM command mode
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah, my bad for not being more precise with my terminology. Currently the extensions enable you to shift the cursor up or down to adjacent cells using ctrl-j/k
in either vim-insert
or vim-command
modes. Though I think having these keybinds do something in jupyter-command
mode is also a valuable addition. Like so:
Huh that's tricky. Would just defining the keymap (using addKeyBinding) as a no-op or |
The "disabled" attribute is part of the setting registry, whereas the addKeyBinding is at a lower level, at the application layer. I think you can't add a keybinding identical to one that already exists (though you might try?) |
Yep, saw that, this why I looked at the
Tried that, and various combination like e.g. what @ianhi suggests with |
The last commit introduces a listener on cell change which allows to override the ESC command to go out of insert mode. |
This branch is now aligned with master and takes implements what we have discussed:
It is ready for review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really great! I have one final issue to bring up but otherwise I am a big 👍 on merging this. I've left some comments on places you could optimize the code a bit if you wanted to, but I don't think any of the proposed changes are necessary.
remaining issue:
I just tried this out and found that moving between cells when in vim-command-mode
was not possible using j
or k
and up
still works but down
no longer works:
The vim extensions work around this by adding a custom codemirror command to j
and k
in vim mode:
https://github.com/axelfahy/jupyterlab-vim/blob/c4e43f940ef4be4c961608b6192412d2f3a33d1f/src/index.ts#L164-L173
The expected behavior is that pressing j
or k
in the last or first line will move me to the next cell:
let activeCell: Cell | null = null; | ||
|
||
commands.addCommand('codemirror:leave-vim-insert-mode', { | ||
label: 'Leave VIM Insert Mode', | ||
execute: args => { | ||
if (activeCell) { | ||
let editor = activeCell.editor as CodeMirrorEditor; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is implicitly depending on onActiveCellChanged
having been called in order to have set activeCell
.
let activeCell: Cell | null = null; | |
commands.addCommand('codemirror:leave-vim-insert-mode', { | |
label: 'Leave VIM Insert Mode', | |
execute: args => { | |
if (activeCell) { | |
let editor = activeCell.editor as CodeMirrorEditor; | |
commands.addCommand('codemirror:leave-vim-insert-mode', { | |
label: 'Leave VIM Insert Mode', | |
execute: args => { | |
const activeCell = notebookTracker.activeCell; | |
if (activeCell) { | |
let editor = activeCell.editor as CodeMirrorEditor; |
function onActiveCellChanged(): void { | ||
if (keyMap === 'vim') { | ||
activeCell = notebookTracker.activeCell; | ||
if (activeCell) { | ||
// From https://github.com/axelfahy/jupyterlab-vim/blob/c4e43f940ef4be4c961608b6192412d2f3a33d1f/src/index.ts | ||
CodeMirror.prototype.save = () => { | ||
void commands.execute('docmanager:save'); | ||
}; | ||
const lvim = (CodeMirror as any).Vim as any; | ||
if (lvim) { | ||
lvim.defineEx('quit', 'q', function(cm: any) { | ||
void commands.execute('notebook:enter-command-mode'); | ||
}); | ||
lvim.defineAction('splitCell', (cm: any, actionArgs: any) => { | ||
void commands.execute('notebook:split-cell-at-cursor'); | ||
}); | ||
lvim.mapCommand('-', 'action', 'splitCell', {}, { extra: 'normal' }); | ||
} | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all of these act globally and thus only need to be run when the vim keymap is selected rather than everytime the active cell is changed. I'd suggest moving these definitions under the if( keymap == 'vim')
.
if (keyMap === 'vim') { | ||
// @ts-expect-error | ||
await import('codemirror/keymap/vim.js'); | ||
commands.addKeyBinding({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be easy to add a signal.emit
here with the keymap in it? I could see that being helpful for extensions building around the keymaps. If not easy then it's no big deal.
Rather than purely finding issues I had a go at solving them. #9068 is a rebase of this PR that fixes all of the issues I raised. |
Closing as this work is now done in #9068. |
References
This PR addresses for Cell Editors
Problem 1 - Separated Keymap from Text Editor VIM
discussed in #8592Code changes
code-mirror-extension
now tracks also thenotebook
and update the cell editor options when the Keymap settings is changed.User-facing changes
Cell editors benefit from VIM mode support. Instead of
ESC
, user has to useCTRL-[
to exit from insert mode.Backwards-incompatible changes
None