diff --git a/package.json b/package.json index 3236d22..02830f7 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@jupyterlab/application": "^4.0.3", "@jupyterlab/cells": "^4.0.3", "@jupyterlab/codemirror": "^4.0.3", + "@jupyterlab/fileeditor": "^4.0.3", "@jupyterlab/notebook": "^4.0.3", "@jupyterlab/settingregistry": "^4.0.3", "@lumino/commands": "^2.0.1", @@ -74,6 +75,7 @@ "@codemirror/language": "^6.8.0", "@codemirror/search": "^6.5.0", "@jupyterlab/builder": "^4.0.0", + "@jupyterlab/codeeditor": "^4.0.3", "@types/codemirror": "^0.0.87", "@types/json-schema": "^7.0.11", "@types/react": "^18.0.26", diff --git a/schema/plugin.json b/schema/plugin.json index eaf9e4d..42f58ad 100644 --- a/schema/plugin.json +++ b/schema/plugin.json @@ -10,6 +10,31 @@ "selector": ".jp-Notebook.jp-mod-editMode", "disabled": true }, + { + "command": "vim:enter-normal-mode", + "keys": ["Escape"], + "selector": ".jp-FileEditor" + }, + { + "command": "documentsearch:end", + "keys": ["Escape"], + "selector": ".jp-mod-searchable .jp-FileEditor .cm-vimMode" + }, + { + "command": "documentsearch:end", + "keys": ["Escape"], + "selector": ".jp-mod-searchable .jp-Notebook .cm-vimMode" + }, + { + "command": "documentsearch:end", + "keys": ["Escape"], + "selector": ".jp-mod-search-active .jp-FileEditor .cm-vimMode" + }, + { + "command": "documentsearch:end", + "keys": ["Escape"], + "selector": ".jp-mod-search-active .jp-Notebook .cm-vimMode" + }, { "selector": ".jp-NotebookPanel[data-jp-vim-mode='true'] .jp-Notebook.jp-mod-editMode", "keys": ["Ctrl O", "U"], @@ -256,7 +281,13 @@ "enabled": { "type": "boolean", "title": "Enabled", - "description": "Enable/disable notebook vim (may require a page refresh)", + "description": "Enable/disable vim extension (may require a page refresh)", + "default": true + }, + "enabledInEditors": { + "type": "boolean", + "title": "Enabled in Text Editor", + "description": "Enable/disable vim in text editors (may require a page refresh)", "default": true }, "extraKeybindings": { diff --git a/src/codemirrorCommands.ts b/src/codemirrorCommands.ts index 41d835d..15162a9 100644 --- a/src/codemirrorCommands.ts +++ b/src/codemirrorCommands.ts @@ -1,6 +1,9 @@ import { Cell, ICellModel, MarkdownCell } from '@jupyterlab/cells'; import { CodeMirrorEditor } from '@jupyterlab/codemirror'; import { INotebookTracker } from '@jupyterlab/notebook'; +import { IEditorTracker, FileEditor } from '@jupyterlab/fileeditor'; +import { IDocumentWidget } from '@jupyterlab/docregistry'; +import type { CodeEditor } from '@jupyterlab/codeeditor'; import { CommandRegistry } from '@lumino/commands'; import { Vim, getCM, CodeMirror } from '@replit/codemirror-vim'; @@ -21,50 +24,55 @@ export interface IKeybinding { enabled: boolean; } -export interface IOptions { - commands: CommandRegistry; - enabled: boolean; - userKeybindings: IKeybinding[]; +export namespace VimEditorManager { + export interface IOptions { + enabled: boolean; + userKeybindings: IKeybinding[]; + } } -export class VimCellManager { - constructor({ commands, enabled, userKeybindings }: IOptions) { - this._commands = commands; - this.enabled = enabled; - this.lastActiveCell = null; - this.userKeybindings = userKeybindings ?? []; +export namespace VimCellManager { + export interface IOptions extends VimEditorManager.IOptions { + commands: CommandRegistry; } +} - onActiveCellChanged( - tracker: INotebookTracker, - activeCell: Cell | null - ): void { - this.modifyCell(activeCell).catch(console.error); +export class VimEditorManager { + constructor({ enabled, userKeybindings }: VimEditorManager.IOptions) { + this.enabled = enabled; + this.userKeybindings = userKeybindings ?? []; } - async modifyCell(activeCell: Cell | null): Promise { - if (!activeCell) { + async onActiveEditorChanged( + tracker: IEditorTracker, + activeEditor: IDocumentWidget | null + ): Promise { + if (!activeEditor) { return; } - this.lastActiveCell = activeCell; - await activeCell.ready; - const editor = activeCell.editor as CodeMirrorEditor | null; + await activeEditor.content.ready; + this.modifyEditor(activeEditor.content.editor); + } - if (activeCell.isDisposed) { - console.warn('Cell was already disposed, cannot setup vim mode'); - return; - } + updateLastActive() { + this.modifyEditor(this._lastActiveEditor); + } + + modifyEditor(editor: CodeEditor.IEditor | null): boolean { + // JupyterLab 4.0 only supports CodeMirror editors + const mirrorEditor = editor as CodeMirrorEditor | null; - if (!editor) { - throw Error('Cell editor not available'); + if (!mirrorEditor) { + throw Error('Editor not available'); } + this._lastActiveEditor = mirrorEditor; - const view = editor.editor; + const view = mirrorEditor.editor; if (this.enabled) { - if (!editor.getOption('vim')) { + if (!mirrorEditor.getOption('vim')) { // this erases state, we do not want to call it if not needed. - editor.setOption('vim', true); + mirrorEditor.setOption('vim', true); // On each key press the notebook (`Notebook.handleEvent`) invokes // a handler ensuring focus (`Notebook._ensureFocus`); the logic does @@ -72,7 +80,7 @@ export class VimCellManager { // as blurred because it exists outside of the CodeMirror6 state; here // we override `hasFocus` handler to ensure it is taken into account. const cm = getCM(view)!; - editor.hasFocus = () => { + mirrorEditor.hasFocus = () => { if ( cm.state.dialog && cm.state.dialog.contains(document.activeElement) @@ -83,10 +91,9 @@ export class VimCellManager { }; } const lcm = getCM(view); - const lvim = Vim; // Clear existing user keybindings, then re-register in case they changed in the user settings - ['normal', 'visual', 'insert'].forEach(ctx => lvim.mapclear(ctx)); + ['normal', 'visual', 'insert'].forEach(ctx => Vim.mapclear(ctx)); this.userKeybindings.forEach( ({ command, @@ -97,9 +104,9 @@ export class VimCellManager { }: IKeybinding) => { if (keybindEnabled) { if (mapfn === 'map') { - lvim.map(command, keys, context); + Vim.map(command, keys, context); } else { - lvim.noremap(command, keys, context); + Vim.noremap(command, keys, context); } } } @@ -107,188 +114,225 @@ export class VimCellManager { Vim.handleKey(lcm, ''); - // Define a function to use as Vim motion - // This replaces the codemirror moveByLines function to - // for jumping between notebook cells. - const moveByLinesOrCell = ( - cm: IVimCodeMirror, - head: any, - motionArgs: any, - vim: any - ): any => { - const cur = head; - let endCh = cur.ch; - const currentCell = activeCell; - // TODO: these references will be undefined - // Depending what our last motion was, we may want to do different - // things. If our last motion was moving vertically, we want to - // preserve the HPos from our last horizontal move. If our last motion - // was going to the end of a line, moving vertically we should go to - // the end of the line, etc. - switch (vim?.lastMotion) { - case cm.moveByLines: - case cm.moveByDisplayLines: - case cm.moveByScroll: - case cm.moveToColumn: - case cm.moveToEol: - // JUPYTER PATCH: add our custom method to the motion cases - // eslint-disable-next-line no-fallthrough - case moveByLinesOrCell: - endCh = vim.lastHPos; - break; - default: - vim.lastHPos = endCh; - } - const repeat = motionArgs.repeat + (motionArgs.repeatOffset || 0); - let line = motionArgs.forward ? cur.line + repeat : cur.line - repeat; - const first = cm.firstLine(); - const last = cm.lastLine(); - const posV = cm.findPosV( - cur, - motionArgs.forward ? repeat : -repeat, - 'line', - vim.lastHSPos - ); - const hasMarkedText = motionArgs.forward - ? posV.line > line - : posV.line < line; - if (hasMarkedText) { - line = posV.line; - endCh = posV.ch; - } + return true; + } else if (mirrorEditor.getOption('vim')) { + mirrorEditor.setOption('vim', false); + return false; + } + return false; + } - // JUPYTER PATCH BEGIN - // here we insert the jumps to the next cells + private _lastActiveEditor: CodeEditor.IEditor | null = null; + public enabled: boolean; + public userKeybindings: IKeybinding[]; +} - if (line < first || line > last) { - // var currentCell = ns.notebook.get_selected_cell(); - // var currentCell = tracker.activeCell; - // var key = ''; - // `currentCell !== null should not be needed since `activeCell` - // is already check against null (row 61). Added to avoid warning. - if (currentCell !== null && currentCell.model.type === 'markdown') { - if (!motionArgs.handleArrow) { - // markdown cells tends to improperly handle arrow keys movement, - // on the way up the cell is rendered, but down movement is ignored - // when use arrows the cell will remain unrendered (need to shift+enter) - // However, this is the same as Jupyter default behaviour - (currentCell as MarkdownCell).rendered = true; - } - // currentCell.execute(); +export class VimCellManager extends VimEditorManager { + constructor({ commands, enabled, userKeybindings }: VimCellManager.IOptions) { + super({ userKeybindings, enabled }); + this._commands = commands; + } + + onActiveCellChanged( + tracker: INotebookTracker, + activeCell: Cell | null + ): void { + this.modifyCell(activeCell).catch(console.error); + } + + updateLastActive() { + this.modifyCell(this._lastActiveCell); + } + + async modifyCell(activeCell: Cell | null): Promise { + if (!activeCell) { + return; + } + this._lastActiveCell = activeCell; + await activeCell.ready; + + if (activeCell.isDisposed) { + console.warn('Cell was already disposed, cannot setup vim mode'); + return; + } + const wasEnabled = this.modifyEditor(activeCell.editor); + if (wasEnabled) { + this._modifyEdgeNavigation(activeCell); + } + } + + private _modifyEdgeNavigation(activeCell: Cell) { + // Define a function to use as Vim motion + // This replaces the codemirror moveByLines function to + // for jumping between notebook cells. + const moveByLinesOrCell = ( + cm: IVimCodeMirror, + head: any, + motionArgs: any, + vim: any + ): any => { + const cur = head; + let endCh = cur.ch; + const currentCell = activeCell; + // TODO: these references will be undefined + // Depending what our last motion was, we may want to do different + // things. If our last motion was moving vertically, we want to + // preserve the HPos from our last horizontal move. If our last motion + // was going to the end of a line, moving vertically we should go to + // the end of the line, etc. + switch (vim?.lastMotion) { + case cm.moveByLines: + case cm.moveByDisplayLines: + case cm.moveByScroll: + case cm.moveToColumn: + case cm.moveToEol: + // JUPYTER PATCH: add our custom method to the motion cases + // eslint-disable-next-line no-fallthrough + case moveByLinesOrCell: + endCh = vim.lastHPos; + break; + default: + vim.lastHPos = endCh; + } + const repeat = motionArgs.repeat + (motionArgs.repeatOffset || 0); + let line = motionArgs.forward ? cur.line + repeat : cur.line - repeat; + const first = cm.firstLine(); + const last = cm.lastLine(); + const posV = cm.findPosV( + cur, + motionArgs.forward ? repeat : -repeat, + 'line', + vim.lastHSPos + ); + const hasMarkedText = motionArgs.forward + ? posV.line > line + : posV.line < line; + if (hasMarkedText) { + line = posV.line; + endCh = posV.ch; + } + + // JUPYTER PATCH BEGIN + // here we insert the jumps to the next cells + + if (line < first || line > last) { + // var currentCell = ns.notebook.get_selected_cell(); + // var currentCell = tracker.activeCell; + // var key = ''; + // `currentCell !== null should not be needed since `activeCell` + // is already check against null (row 61). Added to avoid warning. + if (currentCell !== null && currentCell.model.type === 'markdown') { + if (!motionArgs.handleArrow) { + // markdown cells tends to improperly handle arrow keys movement, + // on the way up the cell is rendered, but down movement is ignored + // when use arrows the cell will remain unrendered (need to shift+enter) + // However, this is the same as Jupyter default behaviour + (currentCell as MarkdownCell).rendered = true; } - if (motionArgs.forward) { - // ns.notebook.select_next(); - if (!motionArgs.handleArrow) { + // currentCell.execute(); + } + if (motionArgs.forward) { + // ns.notebook.select_next(); + if (!motionArgs.handleArrow) { + this._commands.execute('notebook:move-cursor-down'); + } else { + // This block preventing double cell hop when you use arrow keys for navigation + // also arrow key navigation works properly when current cursor position + // at the beginning of line for up move, and at the end for down move + const cursor = cm.getCursor(); + // CM6 is 1-based + const last_char = cm.cm6.state.doc.line(last + 1).length; + if (cursor.line !== last || cursor.ch !== last_char) { + cm.setCursor(last, last_char); this._commands.execute('notebook:move-cursor-down'); - } else { - // This block preventing double cell hop when you use arrow keys for navigation - // also arrow key navigation works properly when current cursor position - // at the beginning of line for up move, and at the end for down move - const cursor = cm.getCursor(); - // CM6 is 1-based - const last_char = view.state.doc.line(last + 1).length; - if (cursor.line !== last || cursor.ch !== last_char) { - cm.setCursor(last, last_char); - this._commands.execute('notebook:move-cursor-down'); - } } - // key = 'j'; + } + // key = 'j'; + } else { + // ns.notebook.select_prev(); + if (!motionArgs.handleArrow) { + this._commands.execute('notebook:move-cursor-up'); } else { - // ns.notebook.select_prev(); - if (!motionArgs.handleArrow) { + // This block preventing double cell hop when you use arrow keys for navigation + // also arrow key navigation works properly when current cursor position + // at the beginning of line for up move, and at the end for down move + const cursor = cm.getCursor(); + if (cursor.line !== 0 || cursor.ch !== 0) { + cm.setCursor(0, 0); this._commands.execute('notebook:move-cursor-up'); - } else { - // This block preventing double cell hop when you use arrow keys for navigation - // also arrow key navigation works properly when current cursor position - // at the beginning of line for up move, and at the end for down move - const cursor = cm.getCursor(); - if (cursor.line !== 0 || cursor.ch !== 0) { - cm.setCursor(0, 0); - this._commands.execute('notebook:move-cursor-up'); - } } - // key = 'k'; } - return; + // key = 'k'; } - // JUPYTER PATCH END + return; + } + // JUPYTER PATCH END - // function taken from https://github.com/codemirror/CodeMirror/blob/9d0f9d19de70abe817e8b8e161034fbd3f907030/keymap/vim.js#L3328 - function findFirstNonWhiteSpaceCharacter(text: any): number { - if (!text) { - return 0; - } - const firstNonWS = text.search(/\S/); - return firstNonWS === -1 ? text.length : firstNonWS; + // function taken from https://github.com/codemirror/CodeMirror/blob/9d0f9d19de70abe817e8b8e161034fbd3f907030/keymap/vim.js#L3328 + function findFirstNonWhiteSpaceCharacter(text: any): number { + if (!text) { + return 0; } + const firstNonWS = text.search(/\S/); + return firstNonWS === -1 ? text.length : firstNonWS; + } - if (motionArgs.toFirstChar) { - endCh = findFirstNonWhiteSpaceCharacter(cm.getLine(line)); - vim.lastHPos = endCh; - } + if (motionArgs.toFirstChar) { + endCh = findFirstNonWhiteSpaceCharacter(cm.getLine(line)); + vim.lastHPos = endCh; + } - vim.lastHSPos = cm.charCoords( - new CodeMirror.Pos(line, endCh), - 'div' - ).left; - return new CodeMirror.Pos(line, endCh); - }; - lvim.defineMotion('moveByLinesOrCell', moveByLinesOrCell); + vim.lastHSPos = cm.charCoords( + new CodeMirror.Pos(line, endCh), + 'div' + ).left; + return new CodeMirror.Pos(line, endCh); + }; + Vim.defineMotion('moveByLinesOrCell', moveByLinesOrCell); - lvim.mapCommand( - '', - 'motion', - 'moveByLinesOrCell', - { forward: false, linewise: true, handleArrow: true }, - { context: 'normal' } - ); - lvim.mapCommand( - '', - 'motion', - 'moveByLinesOrCell', - { forward: true, linewise: true, handleArrow: true }, - { context: 'normal' } - ); - lvim.mapCommand( - 'k', - 'motion', - 'moveByLinesOrCell', - { forward: false, linewise: true }, - { context: 'normal' } - ); - lvim.mapCommand( - 'j', - 'motion', - 'moveByLinesOrCell', - { forward: true, linewise: true }, - { context: 'normal' } - ); + Vim.mapCommand( + '', + 'motion', + 'moveByLinesOrCell', + { forward: false, linewise: true, handleArrow: true }, + { context: 'normal' } + ); + Vim.mapCommand( + '', + 'motion', + 'moveByLinesOrCell', + { forward: true, linewise: true, handleArrow: true }, + { context: 'normal' } + ); + Vim.mapCommand( + 'k', + 'motion', + 'moveByLinesOrCell', + { forward: false, linewise: true }, + { context: 'normal' } + ); + Vim.mapCommand( + 'j', + 'motion', + 'moveByLinesOrCell', + { forward: true, linewise: true }, + { context: 'normal' } + ); - lvim.defineAction('moveCellDown', (cm: any, actionArgs: any) => { - this._commands.execute('notebook:move-cell-down'); - }); - lvim.defineAction('moveCellUp', (cm: any, actionArgs: any) => { - this._commands.execute('notebook:move-cell-up'); - }); - lvim.mapCommand( - '', - 'action', - 'moveCellDown', - {}, - { extra: 'normal' } - ); - lvim.mapCommand('', 'action', 'moveCellUp', {}, { extra: 'normal' }); - lvim.defineAction('splitCell', (cm: any, actionArgs: any) => { - this._commands.execute('notebook:split-cell-at-cursor'); - }); - lvim.mapCommand('-', 'action', 'splitCell', {}, { extra: 'normal' }); - } else if (editor.getOption('vim')) { - editor.setOption('vim', false); - } + Vim.defineAction('moveCellDown', (cm: any, actionArgs: any) => { + this._commands.execute('notebook:move-cell-down'); + }); + Vim.defineAction('moveCellUp', (cm: any, actionArgs: any) => { + this._commands.execute('notebook:move-cell-up'); + }); + Vim.mapCommand('', 'action', 'moveCellDown', {}, { extra: 'normal' }); + Vim.mapCommand('', 'action', 'moveCellUp', {}, { extra: 'normal' }); + Vim.defineAction('splitCell', (cm: any, actionArgs: any) => { + this._commands.execute('notebook:split-cell-at-cursor'); + }); + Vim.mapCommand('-', 'action', 'splitCell', {}, { extra: 'normal' }); } private _commands: CommandRegistry; - public lastActiveCell: Cell | null; - public enabled: boolean; - public userKeybindings: IKeybinding[]; + private _lastActiveCell: Cell | null = null; } diff --git a/src/index.ts b/src/index.ts index 825d060..910fda0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ import { } from '@jupyterlab/application'; import { INotebookTracker } from '@jupyterlab/notebook'; +import { IEditorTracker } from '@jupyterlab/fileeditor'; import { IEditorExtensionRegistry, @@ -15,12 +16,17 @@ import { vim, Vim } from '@replit/codemirror-vim'; import { EditorView } from '@codemirror/view'; import { Prec } from '@codemirror/state'; -import { VimCellManager, IKeybinding } from './codemirrorCommands'; -import { addJLabCommands } from './labCommands'; +import { + VimEditorManager, + VimCellManager, + IKeybinding +} from './codemirrorCommands'; +import { addNotebookCommands } from './labCommands'; const PLUGIN_NAME = '@axlair/jupyterlab_vim'; const TOGGLE_ID = 'jupyterlab-vim:toggle'; let enabled = false; +let enabledInEditors = true; /** * Initialization data for the jupyterlab_vim extension. @@ -29,14 +35,16 @@ const extension: JupyterFrontEndPlugin = { id: PLUGIN_NAME, autoStart: true, activate: activateCellVim, - requires: [INotebookTracker, IEditorExtensionRegistry, ISettingRegistry] + requires: [INotebookTracker, IEditorExtensionRegistry, ISettingRegistry], + optional: [IEditorTracker] }; async function activateCellVim( app: JupyterFrontEnd, - tracker: INotebookTracker, + notebookTracker: INotebookTracker, editorExtensionRegistry: IEditorExtensionRegistry, - settingRegistry: ISettingRegistry + settingRegistry: ISettingRegistry, + editorTracker: IEditorTracker ): Promise { const theme = Prec.highest( EditorView.theme({ @@ -67,7 +75,7 @@ async function activateCellVim( }); app.commands.addCommand(TOGGLE_ID, { - label: 'Enable Notebook Vim mode', + label: 'Enable Vim Mode', execute: () => { if (settingRegistry) { void settingRegistry.set(`${PLUGIN_NAME}:plugin`, 'enabled', !enabled); @@ -76,11 +84,39 @@ async function activateCellVim( isToggled: () => enabled }); + app.commands.addCommand('vim:enter-normal-mode', { + label: 'Enter Normal Vim Mode', + execute: () => { + const current = app.shell.currentWidget; + if (!current) { + console.warn('Current widget not found'); + } else if (editorTracker.currentWidget === current) { + editorManager.modifyEditor(editorTracker.currentWidget.content.editor); + } else if (notebookTracker.currentWidget === current) { + cellManager.modifyCell( + notebookTracker.currentWidget.content.activeCell + ); + } else { + console.warn('Current widget is not vim-enabled'); + } + }, + isEnabled: () => enabled + }); + const userKeybindings = ( await settingRegistry.get(`${PLUGIN_NAME}:plugin`, 'extraKeybindings') ).composite as unknown as Array; - let cellManager: VimCellManager | null = null; + const cellManager = new VimCellManager({ + commands: app.commands, + enabled, + userKeybindings + }); + const editorManager = new VimEditorManager({ + enabled: enabled && enabledInEditors, + userKeybindings + }); + let escBinding: IDisposable | null = null; let hasEverBeenEnabled = false; @@ -96,21 +132,20 @@ async function activateCellVim( }); }); - cellManager = new VimCellManager({ - commands: app.commands, - enabled, - userKeybindings - }); // it's ok to connect here because we will never reach the vim section unless // ensureVimKeyMap has been called due to the checks for enabled. // we need to have now in order to keep track of the last active cell // so that we can modify it when vim is turned on or off. - tracker.activeCellChanged.connect( + notebookTracker.activeCellChanged.connect( cellManager.onActiveCellChanged, cellManager ); + editorTracker.currentChanged.connect( + editorManager.onActiveEditorChanged, + editorManager + ); - addJLabCommands(app, tracker); + addNotebookCommands(app, notebookTracker); async function updateSettings( settings: ISettingRegistry.ISettings @@ -120,11 +155,15 @@ async function activateCellVim( ).composite as unknown as Array; enabled = settings.get('enabled').composite === true; + enabledInEditors = settings.get('enabledInEditors').composite === true; app.commands.notifyCommandChanged(TOGGLE_ID); - if (cellManager) { - cellManager.enabled = enabled; - cellManager.userKeybindings = userKeybindings; - } + + cellManager.enabled = enabled; + cellManager.userKeybindings = userKeybindings; + + editorManager.enabled = enabled && enabledInEditors; + editorManager.userKeybindings = userKeybindings; + if (enabled) { escBinding?.dispose(); if (!hasEverBeenEnabled) { @@ -139,15 +178,22 @@ async function activateCellVim( }); } - tracker.forEach(notebook => { + notebookTracker.forEach(notebook => { notebook.node.dataset.jpVimMode = `${enabled}`; }); - cellManager?.modifyCell(cellManager.lastActiveCell); + editorTracker.forEach(document => { + document.node.dataset.jpVimMode = `${enabled && enabledInEditors}`; + }); + editorManager?.updateLastActive(); + cellManager?.updateLastActive(); // make sure our css selector is added to new notebooks - tracker.widgetAdded.connect((sender, notebook) => { + notebookTracker.widgetAdded.connect((sender, notebook) => { notebook.node.dataset.jpVimMode = `${enabled}`; }); + editorTracker.widgetAdded.connect((sender, document) => { + document.node.dataset.jpVimMode = `${enabled && enabledInEditors}`; + }); } settingRegistry.load(`${PLUGIN_NAME}:plugin`).then( diff --git a/src/labCommands.ts b/src/labCommands.ts index 7195fbd..7d5555d 100644 --- a/src/labCommands.ts +++ b/src/labCommands.ts @@ -12,7 +12,7 @@ import { ReadonlyPartialJSONObject } from '@lumino/coreutils'; import { IDisposable } from '@lumino/disposable'; import { ElementExt } from '@lumino/domutils'; -export function addJLabCommands( +export function addNotebookCommands( app: JupyterFrontEnd, tracker: INotebookTracker ): Array { diff --git a/yarn.lock b/yarn.lock index d43308c..9cdf018 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,7 +23,9 @@ __metadata: "@jupyterlab/application": ^4.0.3 "@jupyterlab/builder": ^4.0.0 "@jupyterlab/cells": ^4.0.3 + "@jupyterlab/codeeditor": ^4.0.3 "@jupyterlab/codemirror": ^4.0.3 + "@jupyterlab/fileeditor": ^4.0.3 "@jupyterlab/notebook": ^4.0.3 "@jupyterlab/settingregistry": ^4.0.3 "@lumino/commands": ^2.0.1 @@ -852,6 +854,31 @@ __metadata: languageName: node linkType: hard +"@jupyterlab/fileeditor@npm:^4.0.3": + version: 4.0.3 + resolution: "@jupyterlab/fileeditor@npm:4.0.3" + dependencies: + "@jupyterlab/apputils": ^4.1.3 + "@jupyterlab/codeeditor": ^4.0.3 + "@jupyterlab/codemirror": ^4.0.3 + "@jupyterlab/coreutils": ^6.0.3 + "@jupyterlab/docregistry": ^4.0.3 + "@jupyterlab/documentsearch": ^4.0.3 + "@jupyterlab/lsp": ^4.0.3 + "@jupyterlab/statusbar": ^4.0.3 + "@jupyterlab/toc": ^6.0.3 + "@jupyterlab/translation": ^4.0.3 + "@jupyterlab/ui-components": ^4.0.3 + "@lumino/commands": ^2.1.1 + "@lumino/coreutils": ^2.1.1 + "@lumino/messaging": ^2.0.0 + "@lumino/widgets": ^2.1.1 + react: ^18.2.0 + regexp-match-indices: ^1.0.2 + checksum: 9ff129ffa6b91752d3c4f0d36357532a29bec56a4a91d2d3a182e7cba2d3a5ba9b67317bb66356bbd201ca75af30bf5b0985f4629ef4acc4c2842cc7bca72ff6 + languageName: node + linkType: hard + "@jupyterlab/lsp@npm:^4.0.3": version: 4.0.3 resolution: "@jupyterlab/lsp@npm:4.0.3" @@ -4788,6 +4815,24 @@ __metadata: languageName: node linkType: hard +"regexp-match-indices@npm:^1.0.2": + version: 1.0.2 + resolution: "regexp-match-indices@npm:1.0.2" + dependencies: + regexp-tree: ^0.1.11 + checksum: 8cc779f6cf8f404ead828d09970a7d4bd66bd78d43ab9eb2b5e65f2ef2ba1ed53536f5b5fa839fb90b350365fb44b6a851c7f16289afc3f37789c113ab2a7916 + languageName: node + linkType: hard + +"regexp-tree@npm:^0.1.11": + version: 0.1.27 + resolution: "regexp-tree@npm:0.1.27" + bin: + regexp-tree: bin/regexp-tree + checksum: 129aebb34dae22d6694ab2ac328be3f99105143737528ab072ef624d599afecbcfae1f5c96a166fa9e5f64fa1ecf30b411c4691e7924c3e11bbaf1712c260c54 + languageName: node + linkType: hard + "require-from-string@npm:^2.0.2": version: 2.0.2 resolution: "require-from-string@npm:2.0.2"