-
-
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
vim support in the notebook #9068
Closed
Closed
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
6042408
Initial VIM support in cell editors
echarles ac55b99
Shortcut to move up/down the cell
echarles 178d012
Add onActiveCellChanged to manage ESC to go out of insert mode
echarles 2bdfefe
Add cells as dependency to codemirror-extension
echarles 1e3ea9f
DD cuts cell instead of deletes cell
ianhi 62d4200
Add more vim shortcuts
ianhi 9b4990b
create newCellCreated signal and add to tracker
ianhi ac9f0b4
use newCellCreated tracker for settting cell keymap
ianhi 268b15c
restore vim escape to leave insert mode
ianhi a5f6a40
add attribution for vim mode setup
ianhi 478e1fc
Make block comment keyboard shortcut a setting
ianhi 3119779
move keymap setup into separate file
ianhi cd87ae2
dispose the keybinds and keymaps when switching
ianhi b7aae68
add sublime keybindings
ianhi 0f9b2d4
consolidate handling of settings
ianhi 83a21d7
allow using Ctrl-C to copy in vim mode
ianhi File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,8 @@ import { | |
|
||
import { IEditMenu, IMainMenu } from '@jupyterlab/mainmenu'; | ||
|
||
import { setupKeymap } from './keymaps'; | ||
|
||
import { IEditorServices } from '@jupyterlab/codeeditor'; | ||
|
||
import { | ||
|
@@ -23,10 +25,14 @@ import { | |
ICodeMirror | ||
} from '@jupyterlab/codemirror'; | ||
|
||
import { IDisposable } from '@lumino/disposable'; | ||
|
||
import { IDocumentWidget } from '@jupyterlab/docregistry'; | ||
|
||
import { IEditorTracker, FileEditor } from '@jupyterlab/fileeditor'; | ||
|
||
import { INotebookTracker } from '@jupyterlab/notebook'; | ||
|
||
import { ISettingRegistry } from '@jupyterlab/settingregistry'; | ||
|
||
import { IStatusBar } from '@jupyterlab/statusbar'; | ||
|
@@ -69,7 +75,7 @@ const services: JupyterFrontEndPlugin<IEditorServices> = { | |
*/ | ||
const commands: JupyterFrontEndPlugin<void> = { | ||
id: '@jupyterlab/codemirror-extension:commands', | ||
requires: [IEditorTracker, ISettingRegistry, ITranslator], | ||
requires: [IEditorTracker, INotebookTracker, ISettingRegistry, ITranslator], | ||
optional: [IMainMenu], | ||
activate: activateEditorCommands, | ||
autoStart: true | ||
|
@@ -165,7 +171,8 @@ function activateCodeMirror(app: JupyterFrontEnd): ICodeMirror { | |
*/ | ||
function activateEditorCommands( | ||
app: JupyterFrontEnd, | ||
tracker: IEditorTracker, | ||
fileEditorTracker: IEditorTracker, | ||
notebookTracker: INotebookTracker, | ||
settingRegistry: ISettingRegistry, | ||
translator: ITranslator, | ||
mainMenu: IMainMenu | null | ||
|
@@ -181,6 +188,12 @@ function activateEditorCommands( | |
selectionPointer, | ||
lineWiseCopyCut | ||
} = CodeMirrorEditor.defaultConfig; | ||
commands; | ||
|
||
let toggleComment = 'Ctrl-/'; | ||
let toggleCommentMac = 'Cmd-/'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment about |
||
let vimDisableCtrlC = true; | ||
let removeKeymaps: IDisposable[] = []; | ||
|
||
/** | ||
* Update the setting values. | ||
|
@@ -189,15 +202,13 @@ function activateEditorCommands( | |
settings: ISettingRegistry.ISettings | ||
): Promise<void> { | ||
keyMap = (settings.get('keyMap').composite as string | null) || keyMap; | ||
|
||
// Lazy loading of vim mode | ||
if (keyMap === 'vim') { | ||
// @ts-expect-error | ||
await import('codemirror/keymap/vim.js'); | ||
} | ||
|
||
removeKeymaps = await setupKeymap( | ||
keyMap, | ||
commands, | ||
notebookTracker, | ||
removeKeymaps | ||
); | ||
theme = (settings.get('theme').composite as string | null) || theme; | ||
|
||
// Lazy loading of theme stylesheets | ||
if (theme !== 'jupyter' && theme !== 'default') { | ||
const filename = | ||
|
@@ -223,64 +234,109 @@ function activateEditorCommands( | |
selectionPointer; | ||
lineWiseCopyCut = | ||
(settings.get('lineWiseCopyCut').composite as boolean) ?? lineWiseCopyCut; | ||
toggleComment = | ||
(settings.get('toggleComment').composite as string) ?? toggleComment; | ||
toggleCommentMac = | ||
(settings.get('toggleCommentMac').composite as string) ?? | ||
toggleCommentMac; | ||
vimDisableCtrlC = | ||
(settings.get('vim:CtrlC-to-copy').composite as boolean) ?? | ||
vimDisableCtrlC; | ||
} | ||
|
||
/** | ||
* Set the settings of an editor instance | ||
*/ | ||
function setEditorOptions(editor: CodeMirrorEditor) { | ||
editor.setOption('keyMap', keyMap); | ||
editor.setOption('theme', theme); | ||
editor.setOption('lineWiseCopyCut', lineWiseCopyCut); | ||
editor.setOption('selectionPointer', selectionPointer); | ||
editor.setOption('styleActiveLine', styleActiveLine); | ||
editor.setOption('styleSelectedText', styleSelectedText); | ||
const extraKeys = editor.getOption('extraKeys') || {}; | ||
extraKeys[toggleComment] = 'toggleComment'; | ||
extraKeys[toggleCommentMac] = 'toggleComment'; | ||
if (vimDisableCtrlC && keyMap === 'vim') { | ||
extraKeys['Ctrl-C'] = false; | ||
} | ||
editor.setOption('extraKeys', extraKeys); | ||
} | ||
|
||
/** | ||
* Update the settings of the current tracker instances. | ||
*/ | ||
function updateTracker(): void { | ||
tracker.forEach(widget => { | ||
function updateFileEditorTracker(): void { | ||
fileEditorTracker.forEach(widget => { | ||
if (widget.content.editor instanceof CodeMirrorEditor) { | ||
const { editor } = widget.content; | ||
editor.setOption('keyMap', keyMap); | ||
editor.setOption('lineWiseCopyCut', lineWiseCopyCut); | ||
const editor = widget.content.editor; | ||
setEditorOptions(editor); | ||
editor.setOption('scrollPastEnd', scrollPastEnd); | ||
editor.setOption('selectionPointer', selectionPointer); | ||
editor.setOption('styleActiveLine', styleActiveLine); | ||
editor.setOption('styleSelectedText', styleSelectedText); | ||
editor.setOption('theme', theme); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Handle the settings of FileEditors | ||
*/ | ||
fileEditorTracker.widgetAdded.connect((sender, widget) => { | ||
if (widget.content.editor instanceof CodeMirrorEditor) { | ||
const editor = widget.content.editor; | ||
setEditorOptions(editor); | ||
editor.setOption('scrollPastEnd', scrollPastEnd); | ||
} | ||
}); | ||
|
||
/** | ||
* Update the settings of the current Notebook instances | ||
*/ | ||
function updateNotebookTracker(): void { | ||
notebookTracker.forEach(widget => { | ||
widget.content.widgets.forEach(cell => { | ||
if (cell.inputArea.editor instanceof CodeMirrorEditor) { | ||
setEditorOptions(cell.inputArea.editor); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
// Fetch the initial state of the settings. | ||
Promise.all([settingRegistry.load(id), restored]) | ||
.then(async ([settings]) => { | ||
await updateSettings(settings); | ||
updateTracker(); | ||
updateFileEditorTracker(); | ||
updateNotebookTracker(); | ||
settings.changed.connect(async () => { | ||
await updateSettings(settings); | ||
updateTracker(); | ||
updateFileEditorTracker(); | ||
updateNotebookTracker(); | ||
}); | ||
// connect to signal here to ensure vim keymap has | ||
// been imported in case we need it | ||
/** | ||
* Handle settings of Notebook cells | ||
*/ | ||
notebookTracker.newCellCreated.connect((sender, cell) => { | ||
if (cell?.inputArea.editor instanceof CodeMirrorEditor) { | ||
setEditorOptions(cell.inputArea.editor); | ||
} | ||
}); | ||
}) | ||
.catch((reason: Error) => { | ||
console.error(reason.message); | ||
updateTracker(); | ||
updateFileEditorTracker(); | ||
updateNotebookTracker(); | ||
}); | ||
|
||
/** | ||
* Handle the settings of new widgets. | ||
*/ | ||
tracker.widgetAdded.connect((sender, widget) => { | ||
if (widget.content.editor instanceof CodeMirrorEditor) { | ||
const { editor } = widget.content; | ||
editor.setOption('keyMap', keyMap); | ||
editor.setOption('lineWiseCopyCut', lineWiseCopyCut); | ||
editor.setOption('selectionPointer', selectionPointer); | ||
editor.setOption('scrollPastEnd', scrollPastEnd); | ||
editor.setOption('styleActiveLine', styleActiveLine); | ||
editor.setOption('styleSelectedText', styleSelectedText); | ||
editor.setOption('theme', theme); | ||
} | ||
}); | ||
|
||
/** | ||
* A test for whether the tracker has an active widget. | ||
*/ | ||
function isEnabled(): boolean { | ||
return ( | ||
tracker.currentWidget !== null && | ||
tracker.currentWidget === app.shell.currentWidget | ||
(fileEditorTracker.currentWidget !== null && | ||
fileEditorTracker.currentWidget === app.shell.currentWidget) || | ||
(notebookTracker.currentWidget !== null && | ||
notebookTracker.currentWidget === app.shell.currentWidget) | ||
); | ||
} | ||
|
||
|
@@ -334,7 +390,7 @@ function activateEditorCommands( | |
commands.addCommand(CommandIDs.find, { | ||
label: trans.__('Find...'), | ||
execute: () => { | ||
const widget = tracker.currentWidget; | ||
const widget = fileEditorTracker.currentWidget; | ||
if (!widget) { | ||
return; | ||
} | ||
|
@@ -347,7 +403,7 @@ function activateEditorCommands( | |
commands.addCommand(CommandIDs.goToLine, { | ||
label: trans.__('Go to Line...'), | ||
execute: () => { | ||
const widget = tracker.currentWidget; | ||
const widget = fileEditorTracker.currentWidget; | ||
if (!widget) { | ||
return; | ||
} | ||
|
@@ -361,7 +417,7 @@ function activateEditorCommands( | |
label: args => args['name'] as string, | ||
execute: args => { | ||
const name = args['name'] as string; | ||
const widget = tracker.currentWidget; | ||
const widget = fileEditorTracker.currentWidget; | ||
if (name && widget) { | ||
const spec = Mode.findByName(name); | ||
if (spec) { | ||
|
@@ -371,7 +427,7 @@ function activateEditorCommands( | |
}, | ||
isEnabled, | ||
isToggled: args => { | ||
const widget = tracker.currentWidget; | ||
const widget = fileEditorTracker.currentWidget; | ||
if (!widget) { | ||
return false; | ||
} | ||
|
@@ -451,7 +507,7 @@ function activateEditorCommands( | |
|
||
// Add go to line capabilities to the edit menu. | ||
mainMenu.editMenu.goToLiners.add({ | ||
tracker, | ||
tracker: fileEditorTracker, | ||
goToLine: (widget: IDocumentWidget<FileEditor>) => { | ||
const editor = widget.content.editor as CodeMirrorEditor; | ||
editor.execCommand('jumpToLine'); | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Does JupyterLab support using
Accel
in this file to avoid having two different shortcuts (if that is a benefit)?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 so, but I just re-interpreted what jlab was already doing into being settings:
jupyterlab/packages/codemirror/src/factory.ts
Lines 40 to 41 in 14776bb
Is accel =
ctrl
oralt
?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.
Ok if this is what JupyterLab has elsewhere then just keep it as is I guess unless someone else with more knowledge chimes in. I believe
Accel
is set toCtrl
on Win/Linux andCmd
on macOS.