提交 4aa13a56 编写于 作者: R rebornix

find in markdown content

上级 e8dae6d0
......@@ -484,7 +484,8 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
* Returns false if some lines need to be reevaluated (in a slow fashion).
*/
private _updateLineWidthsFast(): boolean {
return this._updateLineWidths(true);
// TODO@rebornix triggering `updateLineWidthsFast` flushes scroll left.
return this._updateLineWidths(false);
}
private _updateLineWidthsSlow(): void {
......
......@@ -6,7 +6,7 @@
import { SimpleFindWidget } from 'vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, INotebookEditor, CellFindMatch } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, INotebookEditor, CellFindMatch, CellState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { FindDecorations } from 'vs/editor/contrib/find/findDecorations';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { IModelDeltaDecoration } from 'vs/editor/common/model';
......@@ -40,12 +40,7 @@ export class NotebookFindWidget extends SimpleFindWidget {
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);
this.revealCellRange(nextIndex.index, nextIndex.remainder);
}
} else {
this.set(null);
......@@ -79,12 +74,14 @@ export class NotebookFindWidget extends SimpleFindWidget {
this._currentMatch = nextVal;
const nextIndex = this._findMatchesStarts!.getIndexOf(nextVal);
const cellIndex = nextIndex.index;
const matchIndex = nextIndex.remainder;
this.setCurrentFindMatchDecoration(nextIndex.index, nextIndex.remainder);
this.revealCellRange(nextIndex.index, nextIndex.remainder);
}
this.setCurrentFindMatchDecoration(cellIndex, matchIndex);
this._findMatches[cellIndex].cell.isEditing = true;
this._notebookEditor.setSelection(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range);
private revealCellRange(cellIndex: number, matchIndex: number) {
this._findMatches[cellIndex].cell.state = CellState.PreviewContent;
this._notebookEditor.selectElement(this._findMatches[cellIndex].cell);
this._notebookEditor.setCellSelection(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range);
this._notebookEditor.revealRangeInCenterIfOutsideViewport(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range);
}
......
......@@ -34,6 +34,11 @@ export interface INotebookEditor {
*/
focus(): void;
/**
* Select & focus cell
*/
selectElement(cell: CellViewModel): void;
/**
* Layout info for the notebook editor
*/
......@@ -141,7 +146,7 @@ export interface INotebookEditor {
*/
revealRangeInCenterIfOutsideViewport(cell: CellViewModel, range: Range): void;
setSelection(cell: CellViewModel, selection: Range): void;
setCellSelection(cell: CellViewModel, selection: Range): void;
/**
* Change the decorations on cells.
......@@ -194,3 +199,24 @@ export enum CellRevealPosition {
Top,
Center
}
export enum CellState {
/**
* Default state.
* For markdown cell, it's Markdown preview.
* For code cell, the browser focus should be on the container instead of the editor
*/
Read,
/**
* Content preview mode.
* For markdown cell, the source is now rendered in the editor. When the cell is not longer focsued/selected, it will fall back to Read mode.
* For code cell, this state is the same as Editing
*/
PreviewContent,
/**
* Eding mode. Source for markdown or code is rendered in editors and the state will be persistent.
*/
Editing
}
......@@ -21,7 +21,7 @@ import { contrastBorder, editorBackground, focusBorder, foreground, textBlockQuo
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { EditorOptions, IEditorMemento, ICompositeCodeEditor, IEditorCloseEvent } from 'vs/workbench/common/editor';
import { INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditor, NotebookLayoutInfo, CellState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookEditorInput, NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
......@@ -411,6 +411,15 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
//#region Editor Features
selectElement(cell: CellViewModel) {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.setSelection([index]);
this.list?.setFocus([index]);
}
}
revealInView(cell: CellViewModel) {
const index = this.notebookViewModel?.getViewCellIndex(cell);
......@@ -483,7 +492,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
}
setSelection(cell: CellViewModel, range: Range): void {
setCellSelection(cell: CellViewModel, range: Range): void {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
......@@ -547,7 +556,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.list?.setFocus([insertIndex]);
if (type === CellKind.Markdown) {
newCell.isEditing = true;
newCell.state = CellState.Editing;
}
DOM.scheduleAtNextAnimationFrame(() => {
......@@ -563,13 +572,13 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
editNotebookCell(cell: CellViewModel): void {
cell.isEditing = true;
cell.state = CellState.Editing;
this.renderedEditors.get(cell)?.focus();
}
saveNotebookCell(cell: CellViewModel): void {
cell.isEditing = false;
cell.state = CellState.Read;
}
getActiveCell() {
......@@ -593,7 +602,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
(document.activeElement as HTMLElement).blur();
}
cell.isEditing = false;
cell.state = CellState.Read;
}
this.list?.setFocus([index]);
......
......@@ -18,13 +18,17 @@ import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/n
import { EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Range } from 'vs/editor/common/core/range';
import { CellRevealType, CellRevealPosition } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { TestHistoryService } from 'vs/workbench/test/browser/workbenchTestServices';
export class NotebookCellList extends WorkbenchList<CellViewModel> {
export class NotebookCellList extends WorkbenchList<CellViewModel> implements IDisposable {
get onWillScroll(): Event<ScrollEvent> { return this.view.onWillScroll; }
get rowsContainer(): HTMLElement {
return this.view.containerDomNode;
}
private _previousSelectedElements: CellViewModel[] = [];
private _localDisposableStore = new DisposableStore();
constructor(
private listUser: string,
......@@ -40,6 +44,16 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> {
) {
super(listUser, container, delegate, renderers, options, contextKeyService, listService, themeService, configurationService, keybindingService);
this._previousSelectedElements = this.getSelectedElements();
this._localDisposableStore.add(this.onDidChangeSelection((e) => {
this._previousSelectedElements.forEach(element => {
if (e.elements.indexOf(element) < 0) {
element.onDeselect();
}
});
this._previousSelectedElements = e.elements;
}));
}
domElementAtIndex(index: number): HTMLElement | null {
......@@ -264,9 +278,17 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> {
setCellSelection(index: number, range: Range) {
const element = this.view.element(index);
element.setSelection(range);
if (element.editorAttached) {
element.setSelection(range);
} else {
getEditorAttachedPromise(element).then(() => { element.setSelection(range); });
}
}
dispose() {
this._localDisposableStore.dispose();
super.dispose();
}
}
function getEditorAttachedPromise(element: CellViewModel) {
......
......@@ -68,7 +68,6 @@ export class StatefullMarkdownCell extends Disposable {
}
}, {});
viewCell.attachTextEditor(this.editor);
const cts = new CancellationTokenSource();
this._register({ dispose() { cts.dispose(true); } });
......@@ -78,7 +77,6 @@ export class StatefullMarkdownCell extends Disposable {
}
this.editor!.setModel(model);
viewCell.attachTextEditor(this.editor!);
if (notebookEditor.getActiveCell() === viewCell) {
this.editor!.focus();
}
......@@ -93,6 +91,8 @@ export class StatefullMarkdownCell extends Disposable {
);
}
viewCell.attachTextEditor(this.editor!);
this.localDisposables.add(model.onDidChangeContent(() => {
viewCell.setText(model.getLinesContent());
let clientHeight = this.cellContainer.clientHeight;
......@@ -132,12 +132,17 @@ export class StatefullMarkdownCell extends Disposable {
}, () => {
let newWidth = cellWidthResizeObserver.getWidth();
let realContentHeight = this.editor!.getContentHeight();
this.editor!.layout(
{
width: newWidth,
height: realContentHeight
}
);
let layoutInfo = this.editor!.getLayoutInfo();
// the dimension generated by the resize observer are float numbers, let's round it a bit to avoid relayout.
if (newWidth < layoutInfo.width - 0.3 || layoutInfo.width + 0.3 < newWidth) {
this.editor!.layout(
{
width: newWidth,
height: realContentHeight
}
);
}
});
cellWidthResizeObserver.startObserving();
......
......@@ -16,7 +16,7 @@ import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { MarkdownRenderer } from 'vs/workbench/contrib/notebook/browser/view/renderers/mdRenderer';
import { CellKind, EDITOR_BOTTOM_PADDING, EDITOR_TOP_PADDING, ICell, IOutput, NotebookCellOutputsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellFindMatch } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellFindMatch, CellState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
export class CellViewModel extends Disposable {
......@@ -50,8 +50,27 @@ export class CellViewModel extends Disposable {
get isEditing(): boolean {
return this._isEditing;
}
set isEditing(newState: boolean) {
this._isEditing = newState;
private _state: CellState = CellState.Read;
get state(): CellState {
return this._state;
}
set state(newState: CellState) {
// no downgrade from Editing to PreviewContent
if (this._state === CellState.Editing && newState === CellState.PreviewContent) {
return;
}
this._state = newState;
if (newState !== CellState.Read) {
this._isEditing = true;
} else {
this._isEditing = false;
}
this._onDidChangeEditingState.fire();
}
......@@ -300,7 +319,7 @@ export class CellViewModel extends Disposable {
}
revealRangeInCenter(range: Range) {
this._textEditor?.revealRangeInCenter(range);
this._textEditor?.revealRangeInCenter(range, editorCommon.ScrollType.Immediate);
}
setSelection(range: Range) {
......@@ -353,6 +372,12 @@ export class CellViewModel extends Disposable {
return ret;
}
onDeselect() {
if (this.state === CellState.PreviewContent) {
this.state = CellState.Read;
}
}
getMarkdownRenderer() {
if (!this._mdRenderer) {
this._mdRenderer = this._instaService.createInstance(MarkdownRenderer);
......
......@@ -12,7 +12,7 @@ import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/n
import { NotebookCellsSplice, ICell } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IModelDeltaDecoration } from 'vs/editor/common/model';
import { onUnexpectedError } from 'vs/base/common/errors';
import { CellFindMatch } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellFindMatch, CellState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
export interface INotebookEditorViewState {
editingCells: { [key: number]: boolean };
......@@ -89,7 +89,7 @@ export class NotebookViewModel extends Disposable {
hide() {
this.viewCells.forEach(cell => {
if (cell.getText() !== '') {
cell.isEditing = false;
cell.state = CellState.Read;
}
});
}
......@@ -154,7 +154,7 @@ export class NotebookViewModel extends Disposable {
const isEditing = viewState.editingCells && viewState.editingCells[cell.handle];
const editorViewState = viewState.editorViewStates && viewState.editorViewStates[cell.handle];
cell.isEditing = isEditing;
cell.state = isEditing ? CellState.Editing : CellState.Read;
cell.restoreEditorViewState(editorViewState);
});
}
......@@ -196,7 +196,9 @@ export class NotebookViewModel extends Disposable {
}
const data = mapping.get(ownerId)!;
data.oldDecorations = oldDecoration.decorations;
if (data) {
data.oldDecorations = oldDecoration.decorations;
}
});
newDecorations.forEach(newDecoration => {
......@@ -211,7 +213,9 @@ export class NotebookViewModel extends Disposable {
}
const data = mapping.get(ownerId)!;
data.newDecorations = newDecoration.decorations;
if (data) {
data.newDecorations = newDecoration.decorations;
}
});
const ret: ICellModelDecorations[] = [];
......
......@@ -90,8 +90,11 @@ export class TestNotebookEditor implements INotebookEditor {
constructor(
) { }
selectElement(cell: CellViewModel): void {
throw new Error('Method not implemented.');
}
setSelection(cell: CellViewModel, selection: Range): void {
setCellSelection(cell: CellViewModel, selection: Range): void {
throw new Error('Method not implemented.');
}
revealRangeInView(cell: CellViewModel, range: Range): void {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册