diff --git a/src/codemirrorCommands.ts b/src/codemirrorCommands.ts index 4f2a2d0..0d2f058 100644 --- a/src/codemirrorCommands.ts +++ b/src/codemirrorCommands.ts @@ -43,6 +43,11 @@ interface IUndoOptions { registerName: unknown; } +export interface ICellContext { + index?: number; + cellCount?: number; +} + export class VimEditorManager { constructor({ enabled, userKeybindings }: VimEditorManager.IOptions) { this.enabled = enabled; @@ -167,21 +172,29 @@ export class VimCellManager extends VimEditorManager { tracker: INotebookTracker, activeCell: Cell | null ): void { - this.modifyCell(activeCell).catch(console.error); + const activeCellContext = { + index: tracker.currentWidget?.content.activeCellIndex, + cellCount: tracker.currentWidget?.content.widgets.length + } as ICellContext; + this.modifyCell(activeCell, activeCellContext).catch(console.error); } updateLastActive() { - if (!this._lastActiveCell) { + if (!this._lastActiveCell || !this._lastActiveCellContext) { return; } - this.modifyCell(this._lastActiveCell); + this.modifyCell(this._lastActiveCell, this._lastActiveCellContext); } - async modifyCell(activeCell: Cell | null): Promise { - if (!activeCell) { + async modifyCell( + activeCell: Cell | null, + activeCellContext: ICellContext + ): Promise { + if (!activeCell || !activeCellContext) { return; } this._lastActiveCell = activeCell; + this._lastActiveCellContext = activeCellContext; await activeCell.ready; if (activeCell.isDisposed) { @@ -190,11 +203,14 @@ export class VimCellManager extends VimEditorManager { } const wasEnabled = this.modifyEditor(activeCell.editor); if (wasEnabled) { - this._modifyEdgeNavigation(activeCell); + this._modifyEdgeNavigation(activeCell, activeCellContext); } } - private _modifyEdgeNavigation(activeCell: Cell) { + private _modifyEdgeNavigation( + activeCell: Cell, + activeCellContext: ICellContext + ) { // Define a function to use as Vim motion // This replaces the codemirror moveByLines function to // for jumping between notebook cells. @@ -254,7 +270,11 @@ export class VimCellManager extends VimEditorManager { // 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 ( + currentCell !== null && + currentCell.model.type === 'markdown' && + !(!motionArgs.forward && activeCellContext.index === 0) + ) { 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 @@ -368,4 +388,5 @@ export class VimCellManager extends VimEditorManager { private _commands: CommandRegistry; private _lastActiveCell: Cell | null = null; + private _lastActiveCellContext: ICellContext | undefined; } diff --git a/src/index.ts b/src/index.ts index 048797c..32d4a40 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,7 +20,8 @@ import { Prec } from '@codemirror/state'; import { VimEditorManager, VimCellManager, - IKeybinding + IKeybinding, + ICellContext } from './codemirrorCommands'; import { addNotebookCommands } from './labCommands'; import { PartialJSONObject } from '@lumino/coreutils'; @@ -97,8 +98,13 @@ async function activateCellVim( } else if (editorTracker.currentWidget === current) { editorManager.modifyEditor(editorTracker.currentWidget.content.editor); } else if (notebookTracker.currentWidget === current) { + const activeCellContext = { + index: notebookTracker.currentWidget.content.activeCellIndex, + cellCount: notebookTracker.currentWidget.content.widgets.length + } as ICellContext; cellManager.modifyCell( - notebookTracker.currentWidget.content.activeCell + notebookTracker.currentWidget.content.activeCell, + activeCellContext ); } else { console.warn('Current widget is not vim-enabled'); @@ -156,7 +162,14 @@ async function activateCellVim( } else if (editorTracker.currentWidget === current) { editorManager.modifyEditor(editorTracker.currentWidget.content.editor); } else if (notebookTracker.currentWidget === current) { - cellManager.modifyCell(notebookTracker.currentWidget.content.activeCell); + const activeCellContext = { + index: notebookTracker.currentWidget.content.activeCellIndex, + cellCount: notebookTracker.currentWidget.content.widgets.length + } as ICellContext; + cellManager.modifyCell( + notebookTracker.currentWidget.content.activeCell, + activeCellContext + ); } else { // no-op } diff --git a/src/labCommands.ts b/src/labCommands.ts index aff421a..af30413 100644 --- a/src/labCommands.ts +++ b/src/labCommands.ts @@ -210,7 +210,7 @@ export function addNotebookCommands( isEnabled }), commands.addCommand('vim:select-above-execute-markdown', { - label: 'Execute Markdown and Select Cell Below', + label: 'Execute Markdown and Select Cell Above', execute: args => { const current = getCurrent(args); @@ -218,7 +218,8 @@ export function addNotebookCommands( const { content } = current; if ( content.activeCell !== null && - content.activeCell.model.type === 'markdown' + content.activeCell.model.type === 'markdown' && + content.activeCellIndex !== 0 ) { (current.content.activeCell as MarkdownCell).rendered = true; }