Skip to content

Commit

Permalink
select next node when on first or last line of editor (eclipse-theia#…
Browse files Browse the repository at this point in the history
…13656)

Signed-off-by: Jonah Iden <jonah.iden@typefox.io>
  • Loading branch information
jonah-iden authored Apr 29, 2024
1 parent 68cb055 commit 020a4cb
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ import { NotebookKernelQuickPickService } from '../service/notebook-kernel-quick
import { NotebookExecutionService } from '../service/notebook-execution-service';
import { NotebookEditorWidget } from '../notebook-editor-widget';
import { NotebookEditorWidgetService } from '../service/notebook-editor-widget-service';
import { NOTEBOOK_CELL_FOCUSED, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_HAS_OUTPUTS } from './notebook-context-keys';
import { NOTEBOOK_CELL_CURSOR_FIRST_LINE, NOTEBOOK_CELL_CURSOR_LAST_LINE, NOTEBOOK_CELL_FOCUSED, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_HAS_OUTPUTS } from './notebook-context-keys';
import { NotebookClipboardService } from '../service/notebook-clipboard-service';
import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';

export namespace NotebookCommands {
export const ADD_NEW_CELL_COMMAND = Command.toDefaultLocalizedCommand({
Expand Down Expand Up @@ -110,6 +111,9 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
@inject(NotebookClipboardService)
protected notebookClipboardService: NotebookClipboardService;

@inject(ContextKeyService)
protected contextKeyService: ContextKeyService;

registerCommands(commands: CommandRegistry): void {
commands.registerCommand(NotebookCommands.ADD_NEW_CELL_COMMAND, {
execute: (notebookModel: NotebookModel, cellKind: CellKind = CellKind.Markup, index?: number | 'above' | 'below') => {
Expand Down Expand Up @@ -169,15 +173,29 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
commands.registerCommand(NotebookCommands.CHANGE_SELECTED_CELL,
{
execute: (change: number | CellChangeDirection) => {
const model = this.notebookEditorWidgetService.focusedEditor?.model;
const focusedEditor = this.notebookEditorWidgetService.focusedEditor;
const model = focusedEditor?.model;
if (model && typeof change === 'number') {
model.setSelectedCell(model.cells[change]);
} else if (model && model.selectedCell) {
const currentIndex = model.cells.indexOf(model.selectedCell);
const shouldFocusEditor = this.contextKeyService.match('editorTextFocus');

if (change === CellChangeDirection.Up && currentIndex > 0) {
model.setSelectedCell(model.cells[currentIndex - 1]);
if (model.selectedCell?.cellKind === CellKind.Code && shouldFocusEditor) {
model.selectedCell.requestFocusEditor('lastLine');
}
} else if (change === CellChangeDirection.Down && currentIndex < model.cells.length - 1) {
model.setSelectedCell(model.cells[currentIndex + 1]);
if (model.selectedCell?.cellKind === CellKind.Code && shouldFocusEditor) {
model.selectedCell.requestFocusEditor();
}
}

if (model.selectedCell.cellKind === CellKind.Markup) {
// since were losing focus from the cell editor, we need to focus the notebook editor again
focusedEditor?.node.focus();
}
}
}
Expand Down Expand Up @@ -294,13 +312,13 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
command: NotebookCommands.CHANGE_SELECTED_CELL.id,
keybinding: 'up',
args: CellChangeDirection.Up,
when: `!editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`
when: `(!editorTextFocus || ${NOTEBOOK_CELL_CURSOR_FIRST_LINE}) && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`
},
{
command: NotebookCommands.CHANGE_SELECTED_CELL.id,
keybinding: 'down',
args: CellChangeDirection.Down,
when: `!editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`
when: `(!editorTextFocus || ${NOTEBOOK_CELL_CURSOR_LAST_LINE}) && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`
},
{
command: NotebookCommands.CUT_SELECTED_CELL.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ export const NOTEBOOK_INTERRUPTIBLE_KERNEL = 'notebookInterruptibleKernel';
export const NOTEBOOK_MISSING_KERNEL_EXTENSION = 'notebookMissingKernelExtension';
export const NOTEBOOK_HAS_OUTPUTS = 'notebookHasOutputs';

export const NOTEBOOK_CELL_CURSOR_FIRST_LINE = 'cellEditorCursorPositionFirstLine';
export const NOTEBOOK_CELL_CURSOR_LAST_LINE = 'cellEditorCursorPositionLastLine';

export namespace NotebookContextKeys {
export function initNotebookContextKeys(service: ContextKeyService): void {
service.createKey(HAS_OPENED_NOTEBOOK, false);
Expand Down Expand Up @@ -93,6 +96,8 @@ export namespace NotebookContextKeys {
service.createKey(NOTEBOOK_CELL_INPUT_COLLAPSED, false);
service.createKey(NOTEBOOK_CELL_OUTPUT_COLLAPSED, false);
service.createKey(NOTEBOOK_CELL_RESOURCE, '');
service.createKey(NOTEBOOK_CELL_CURSOR_FIRST_LINE, false);
service.createKey(NOTEBOOK_CELL_CURSOR_LAST_LINE, false);

// Kernels
service.createKey(NOTEBOOK_KERNEL, undefined);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import { LanguageService } from '@theia/core/lib/browser/language-service';
export const NotebookCellModelFactory = Symbol('NotebookModelFactory');
export type NotebookCellModelFactory = (props: NotebookCellModelProps) => NotebookCellModel;

export type CellEditorFocusRequest = number | 'lastLine' | undefined;

export function createNotebookCellModelContainer(parent: interfaces.Container, props: NotebookCellModelProps): interfaces.Container {
const child = parent.createChild();

Expand Down Expand Up @@ -104,7 +106,7 @@ export class NotebookCellModel implements NotebookCell, Disposable {
protected readonly onDidRequestCellEditChangeEmitter = new Emitter<boolean>();
readonly onDidRequestCellEditChange = this.onDidRequestCellEditChangeEmitter.event;

protected readonly onWillFocusCellEditorEmitter = new Emitter<void>();
protected readonly onWillFocusCellEditorEmitter = new Emitter<CellEditorFocusRequest>();
readonly onWillFocusCellEditor = this.onWillFocusCellEditorEmitter.event;

protected readonly onWillBlurCellEditorEmitter = new Emitter<void>();
Expand Down Expand Up @@ -278,9 +280,9 @@ export class NotebookCellModel implements NotebookCell, Disposable {
this.onDidRequestCellEditChangeEmitter.fire(false);
}

requestFocusEditor(): void {
requestFocusEditor(focusRequest?: CellEditorFocusRequest): void {
this.requestEdit();
this.onWillFocusCellEditorEmitter.fire();
this.onWillFocusCellEditorEmitter.fire(focusRequest);
}

requestBlurEditor(): void {
Expand Down
25 changes: 24 additions & 1 deletion packages/notebook/src/browser/view/notebook-cell-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { NotebookContextManager } from '../service/notebook-context-manager';
import { DisposableCollection, OS } from '@theia/core';
import { NotebookViewportService } from './notebook-viewport-service';
import { BareFontInfo } from '@theia/monaco-editor-core/esm/vs/editor/common/config/fontInfo';
import { NOTEBOOK_CELL_CURSOR_FIRST_LINE, NOTEBOOK_CELL_CURSOR_LAST_LINE } from '../contributions/notebook-context-keys';

interface CellEditorProps {
notebookModel: NotebookModel,
Expand Down Expand Up @@ -54,8 +55,19 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {

override componentDidMount(): void {
this.disposeEditor();
this.toDispose.push(this.props.cell.onWillFocusCellEditor(() => {
this.toDispose.push(this.props.cell.onWillFocusCellEditor(focusRequest => {
this.editor?.getControl().focus();
const lineCount = this.editor?.getControl().getModel()?.getLineCount();
if (focusRequest && lineCount) {
this.editor?.getControl().setPosition(focusRequest === 'lastLine' ?
{ lineNumber: lineCount, column: 1 } :
{ lineNumber: focusRequest, column: 1 },
'keyboard');
}
const currentLine = this.editor?.getControl().getPosition()?.lineNumber;
this.props.notebookContextManager.scopedStore.setContext(NOTEBOOK_CELL_CURSOR_FIRST_LINE, currentLine === 1);
this.props.notebookContextManager.scopedStore.setContext(NOTEBOOK_CELL_CURSOR_LAST_LINE, currentLine === lineCount);

}));

this.toDispose.push(this.props.cell.onDidChangeEditorOptions(options => {
Expand Down Expand Up @@ -119,10 +131,21 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {
}));
this.toDispose.push(this.editor.getControl().onDidFocusEditorText(() => {
this.props.notebookContextManager.onDidEditorTextFocus(true);
this.props.notebookModel.setSelectedCell(cell);
}));
this.toDispose.push(this.editor.getControl().onDidBlurEditorText(() => {
this.props.notebookContextManager.onDidEditorTextFocus(false);
}));
this.toDispose.push(this.editor.getControl().onDidChangeCursorPosition(e => {
if (e.secondaryPositions.length === 0) {
this.props.notebookContextManager.scopedStore.setContext(NOTEBOOK_CELL_CURSOR_FIRST_LINE, e.position.lineNumber === 1);
this.props.notebookContextManager.scopedStore.setContext(NOTEBOOK_CELL_CURSOR_LAST_LINE,
e.position.lineNumber === this.editor!.getControl().getModel()!.getLineCount());
} else {
this.props.notebookContextManager.scopedStore.setContext(NOTEBOOK_CELL_CURSOR_FIRST_LINE, false);
this.props.notebookContextManager.scopedStore.setContext(NOTEBOOK_CELL_CURSOR_LAST_LINE, false);
}
}));
if (cell.editing && notebookModel.selectedCell === cell) {
this.editor.getControl().focus();
}
Expand Down

0 comments on commit 020a4cb

Please sign in to comment.