diff --git a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts index cc1aaae3db1e962967d95d86a06837c4c79441f9..b0d23fd74ba50684586b0e3b62741f7ebcac5524 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts @@ -26,7 +26,7 @@ const NLS_NEXT_MATCH_BTN_LABEL = nls.localize('label.nextMatchButton', "Next mat const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close"); export abstract class SimpleFindWidget extends Widget { - private readonly _findInput: FindInput; + protected readonly _findInput: FindInput; private readonly _domNode: HTMLElement; private readonly _innerDomNode: HTMLElement; private readonly _focusTracker: dom.IFocusTracker; diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/notebookFindWidget.ts b/src/vs/workbench/contrib/notebook/browser/contrib/notebookFindWidget.ts index 72619b1c0d38be4110dd7a8cbc9c3dde2e7b573b..a255b40adaaa856e3dca6c5bdad8195ff06ed372 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/notebookFindWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/notebookFindWidget.ts @@ -12,6 +12,8 @@ import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { IModelDeltaDecoration } from 'vs/editor/common/model'; import { ICellModelDeltaDecorations, ICellModelDecorations } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; +import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { KeyCode } from 'vs/base/common/keyCodes'; export class NotebookFindWidget extends SimpleFindWidget { protected _findWidgetFocused: IContextKey; @@ -28,22 +30,42 @@ export class NotebookFindWidget extends SimpleFindWidget { ) { super(contextViewService, contextKeyService); this._findWidgetFocused = KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED.bindTo(contextKeyService); + this._register(this._findInput.onKeyDown((e) => this._onFindInputKeyDown(e))); + } + + private _onFindInputKeyDown(e: IKeyboardEvent): void { + if (e.equals(KeyCode.Enter)) { + if (this._findMatches.length) { + this.set(this._findMatches); + + if (this._currentMatch !== -1) { + const nextIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch); + const cellIndex = nextIndex.index; + const matchIndex = nextIndex.remainder; + + this._findMatches[cellIndex].cell.isEditing = true; + this._notebookEditor.setSelection(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range); + this._notebookEditor.revealRangeInCenterIfOutsideViewport(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range); + } + } else { + this.set(null); + } + e.preventDefault(); + return; + } } protected onInputChanged(): boolean { const val = this.inputValue; if (val) { - const newMatches = this._notebookEditor.viewModel!.find(val).filter(match => match.matches.length > 0); - if (newMatches.length) { - this.set(newMatches); + this._findMatches = this._notebookEditor.viewModel!.find(val).filter(match => match.matches.length > 0); + if (this._findMatches.length) { return true; } else { - this.set(null); return false; } - } else { - this.set([]); } + return false; } @@ -62,6 +84,7 @@ export class NotebookFindWidget extends SimpleFindWidget { this.setCurrentFindMatchDecoration(cellIndex, matchIndex); this._findMatches[cellIndex].cell.isEditing = true; + this._notebookEditor.setSelection(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range); this._notebookEditor.revealRangeInCenterIfOutsideViewport(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range); } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 7ae9f833c30aa244ff304a12747af5b0e7abef9a..d18a5705c0a7e4f3618fe7e687a3c803ea7090d2 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -141,6 +141,8 @@ export interface INotebookEditor { */ revealRangeInCenterIfOutsideViewport(cell: CellViewModel, range: Range): void; + setSelection(cell: CellViewModel, selection: Range): void; + /** * Change the decorations on cells. * The notebook is virtualized and this method should be called to create/delete editor decorations safely. diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index 6581612e9953eb90668123f7b4a6cffb70e0749d..addfd3081d9d24088c38ddd8e4af90fbb9ad8928 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -483,6 +483,14 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor { } } + setSelection(cell: CellViewModel, range: Range): void { + const index = this.notebookViewModel?.getViewCellIndex(cell); + + if (index !== undefined) { + this.list?.setCellSelection(index, range); + } + } + changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any { return this.notebookViewModel?.changeDecorations(callback); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index 7e6b84fc447762381f2f5b2b254fefc25c01c9f9..beff5d89d68e59df7e326c5adf2f877857d9178d 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -209,10 +209,15 @@ export class NotebookCellList extends WorkbenchList { if (!element.editorAttached) { getEditorAttachedPromise(element).then(() => reveal(index, range, revealType)); } else { - // should not happen + // for example markdown } } else { - element.revealRangeInCenter(range); + if (element.editorAttached) { + element.revealRangeInCenter(range); + } else { + // for example, markdown cell in preview mode + getEditorAttachedPromise(element).then(() => reveal(index, range, revealType)); + } } } @@ -257,6 +262,11 @@ export class NotebookCellList extends WorkbenchList { this._revealInternal(index, true, CellRevealPosition.Center); } + setCellSelection(index: number, range: Range) { + const element = this.view.element(index); + element.setSelection(range); + } + } function getEditorAttachedPromise(element: CellViewModel) { diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel.ts index 1b8cc5e70ebb0903a54892e87f32f8f8a848212f..f2ed5442f79be8d32a0ad510704973e6b667f657 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel.ts @@ -255,6 +255,10 @@ export class CellViewModel extends Disposable { } attachTextEditor(editor: ICodeEditor) { + if (this._textEditor === editor) { + return; + } + this._textEditor = editor; if (this._editorViewStates) { @@ -295,6 +299,10 @@ export class CellViewModel extends Disposable { this._textEditor?.revealRangeInCenter(range); } + setSelection(range: Range) { + this._textEditor?.setSelection(range); + } + getLineScrollTopOffset(line: number): number { if (!this._textEditor) { return 0;