Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to search in notebook inputs (under experimental flag) #167952

Merged
merged 39 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
f895929
initial marks
andreamah Oct 19, 2022
03ad467
initial changes to support notebook editor binding
andreamah Oct 21, 2022
cc1a778
change notebook track qualifications
andreamah Nov 8, 2022
6bba961
needs to read into dom
andreamah Nov 15, 2022
75dddd2
random logs
andreamah Nov 17, 2022
b7f40ea
some progress on notebook search
andreamah Nov 22, 2022
ac5a174
Improve workspace text search with notebook editors
andreamah Nov 22, 2022
90763cc
some rendered content showing in search viewlet
andreamah Nov 23, 2022
e37722e
rough draft of notebook search
andreamah Nov 30, 2022
d20ea1d
move local notebook search out of searchservice
andreamah Dec 2, 2022
188ee99
working replace
andreamah Jan 17, 2023
51c667e
add propert highlighting and open notebook editor when replace active
andreamah Jan 19, 2023
65337b5
merge main
andreamah Jan 19, 2023
da22b6a
cleanup and compile error fixing
andreamah Jan 19, 2023
779e721
fix function for notebook opening in search
andreamah Jan 19, 2023
b8c5133
clarity on shouldOpenInNotebookEditor
andreamah Jan 19, 2023
15ea8bc
added experimental flag
andreamah Jan 20, 2023
310c13a
extra docs for notebook extractSelectionLine
andreamah Jan 20, 2023
a782747
fix experimental flag bug
andreamah Jan 20, 2023
f262935
resolve merge
andreamah Jan 20, 2023
eff7d26
incorporated shared findMatchDecorationModel
andreamah Jan 21, 2023
b1e69a1
jump to nth result on raw text results to notebook results
andreamah Jan 23, 2023
136438c
Merge branch 'main' into andreamah/issue148068
andreamah Feb 1, 2023
7b97332
fix bug with focus shift
andreamah Feb 7, 2023
349b100
cleanup
andreamah Feb 7, 2023
d11d169
fix tests and cleanup
andreamah Feb 8, 2023
4cd6107
extra cleanup for match decorations
andreamah Feb 8, 2023
5409745
cleanup diffs
andreamah Feb 8, 2023
a368db1
remove comments and add readonly field
andreamah Feb 8, 2023
917ac78
remove webview extract match for now
andreamah Feb 9, 2023
aa79ffc
remove comma
andreamah Feb 9, 2023
99c2baa
use onDidAddNotebookEditor
andreamah Feb 9, 2023
3cbc5af
add simple tests
andreamah Feb 10, 2023
b4c213e
test corrections
andreamah Feb 10, 2023
2bfad50
move notebooksearchhelper tests
andreamah Feb 10, 2023
9d16b92
PR feedback
andreamah Feb 10, 2023
8255fc5
add listener dispose
andreamah Feb 10, 2023
350ed49
get notebook model for replace using notebookEditorModelResolverService
andreamah Feb 10, 2023
3c94737
dispose reference to notebook in replaceService
andreamah Feb 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -3,11 +3,12 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { FindMatch, IModelDeltaDecoration } from 'vs/editor/common/model';
import { IModelDeltaDecoration } from 'vs/editor/common/model';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { FindDecorations } from 'vs/editor/contrib/find/browser/findDecorations';
import { Range } from 'vs/editor/common/core/range';
import { overviewRulerSelectionHighlightForeground, overviewRulerFindMatchForeground } from 'vs/platform/theme/common/colorRegistry';
import { CellFindMatchWithIndex, CellWebviewFindMatch, ICellModelDecorations, ICellModelDeltaDecorations, ICellViewModel, INotebookDeltaDecoration, INotebookEditor, NotebookOverviewRulerLane, } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellFindMatchWithIndex, ICellModelDecorations, ICellModelDeltaDecorations, ICellViewModel, INotebookDeltaDecoration, INotebookEditor, NotebookOverviewRulerLane, } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';

export class FindMatchDecorationModel extends Disposable {
private _allMatchesDecorations: ICellModelDecorations[] = [];
Expand All @@ -25,65 +26,72 @@ export class FindMatchDecorationModel extends Disposable {
return this._currentMatchDecorations;
}

public async highlightCurrentFindMatchDecoration(cell: ICellViewModel, match: FindMatch | CellWebviewFindMatch): Promise<number | null> {
public clearDecorations() {
this.clearCurrentFindMatchDecoration();
this.setAllFindMatchesDecorations([]);
}

if (match instanceof FindMatch) {
this.clearCurrentFindMatchDecoration();

// match is an editor FindMatch, we update find match decoration in the editor
// we will highlight the match in the webview
this._notebookEditor.changeModelDecorations(accessor => {
const findMatchesOptions: ModelDecorationOptions = FindDecorations._CURRENT_FIND_MATCH_DECORATION;

const decorations: IModelDeltaDecoration[] = [
{ range: match.range, options: findMatchesOptions }
];
const deltaDecoration: ICellModelDeltaDecorations = {
ownerId: cell.handle,
decorations: decorations
};

this._currentMatchDecorations = {
kind: 'input',
decorations: accessor.deltaDecorations(this._currentMatchDecorations?.kind === 'input' ? this._currentMatchDecorations.decorations : [], [deltaDecoration])
};
});
public async highlightCurrentFindMatchDecorationInCell(cell: ICellViewModel, cellRange: Range): Promise<number | null> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I split Find Match and Webview Match highlight into different functions, since search needs this. Caller is responsible for calling the correct function.


this._currentMatchCellDecorations = this._notebookEditor.deltaCellDecorations(this._currentMatchCellDecorations, [{
this.clearCurrentFindMatchDecoration();

// match is an editor FindMatch, we update find match decoration in the editor
// we will highlight the match in the webview
this._notebookEditor.changeModelDecorations(accessor => {
const findMatchesOptions: ModelDecorationOptions = FindDecorations._CURRENT_FIND_MATCH_DECORATION;

const decorations: IModelDeltaDecoration[] = [
{ range: cellRange, options: findMatchesOptions }
];
const deltaDecoration: ICellModelDeltaDecorations = {
ownerId: cell.handle,
handle: cell.handle,
options: {
overviewRuler: {
color: overviewRulerSelectionHighlightForeground,
modelRanges: [match.range],
includeOutput: false,
position: NotebookOverviewRulerLane.Center
}
decorations: decorations
};

this._currentMatchDecorations = {
kind: 'input',
decorations: accessor.deltaDecorations(this._currentMatchDecorations?.kind === 'input' ? this._currentMatchDecorations.decorations : [], [deltaDecoration])
};
});

this._currentMatchCellDecorations = this._notebookEditor.deltaCellDecorations(this._currentMatchCellDecorations, [{
ownerId: cell.handle,
handle: cell.handle,
options: {
overviewRuler: {
color: overviewRulerSelectionHighlightForeground,
modelRanges: [cellRange],
includeOutput: false,
position: NotebookOverviewRulerLane.Center
}
} as INotebookDeltaDecoration]);
}
} as INotebookDeltaDecoration]);

return null;
} else {
this.clearCurrentFindMatchDecoration();
return null;
}

const offset = await this._notebookEditor.highlightFind(cell, match.index);
this._currentMatchDecorations = { kind: 'output', index: match.index };
public async highlightCurrentFindMatchDecorationInWebview(cell: ICellViewModel, index: number): Promise<number | null> {

this._currentMatchCellDecorations = this._notebookEditor.deltaCellDecorations(this._currentMatchCellDecorations, [{
ownerId: cell.handle,
handle: cell.handle,
options: {
overviewRuler: {
color: overviewRulerSelectionHighlightForeground,
modelRanges: [],
includeOutput: true,
position: NotebookOverviewRulerLane.Center
}
this.clearCurrentFindMatchDecoration();

const offset = await this._notebookEditor.highlightFind(index);
this._currentMatchDecorations = { kind: 'output', index: index };

this._currentMatchCellDecorations = this._notebookEditor.deltaCellDecorations(this._currentMatchCellDecorations, [{
ownerId: cell.handle,
handle: cell.handle,
options: {
overviewRuler: {
color: overviewRulerSelectionHighlightForeground,
modelRanges: [],
includeOutput: true,
position: NotebookOverviewRulerLane.Center
}
} as INotebookDeltaDecoration]);
}
} as INotebookDeltaDecoration]);

return offset;
}
return offset;
}

public clearCurrentFindMatchDecoration() {
Expand Down
Expand Up @@ -457,11 +457,12 @@ export class FindModel extends Disposable {
private async highlightCurrentFindMatchDecoration(cellIndex: number, matchIndex: number): Promise<number | null> {
const cell = this._findMatches[cellIndex].cell;
const match = this._findMatches[cellIndex].getMatch(matchIndex);
return this._findMatchDecorationModel.highlightCurrentFindMatchDecoration(cell,
(matchIndex < this._findMatches[cellIndex].contentMatches.length) ?
(match as FindMatch) :
(match as CellWebviewFindMatch)
);

if (matchIndex < this._findMatches[cellIndex].contentMatches.length) {
return this._findMatchDecorationModel.highlightCurrentFindMatchDecorationInCell(cell, (match as FindMatch).range);
} else {
return this._findMatchDecorationModel.highlightCurrentFindMatchDecorationInWebview(cell, (match as CellWebviewFindMatch).index);
}
}

clear() {
Expand Down
11 changes: 10 additions & 1 deletion src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts
Expand Up @@ -666,7 +666,7 @@ export interface INotebookEditor {
getNextVisibleCellIndex(index: number): number | undefined;
getPreviousVisibleCellIndex(index: number): number | undefined;
find(query: string, options: INotebookSearchOptions, token: CancellationToken): Promise<CellFindMatchWithIndex[]>;
highlightFind(cell: ICellViewModel, matchIndex: number): Promise<number>;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this argument wasn't be used by the implementation

highlightFind(matchIndex: number): Promise<number>;
unHighlightFind(matchIndex: number): Promise<void>;
findStop(): void;
showProgress(): void;
Expand Down Expand Up @@ -730,8 +730,17 @@ export interface IActiveNotebookEditorDelegate extends INotebookEditorDelegate {
getNextVisibleCellIndex(index: number): number;
}

export interface ISearchPreviewInfo {
line: string;
range: {
start: number;
end: number;
};
}

export interface CellWebviewFindMatch {
readonly index: number;
readonly searchPreviewInfo?: ISearchPreviewInfo;
}

export type CellContentFindMatch = FindMatch;
Expand Down
Expand Up @@ -124,6 +124,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
readonly onDidChangeCellState = this._onDidChangeCellState.event;
private readonly _onDidChangeViewCells = this._register(new Emitter<INotebookViewCellsUpdateEvent>());
readonly onDidChangeViewCells: Event<INotebookViewCellsUpdateEvent> = this._onDidChangeViewCells.event;
private readonly _onWillChangeModel = this._register(new Emitter<NotebookTextModel | undefined>());
readonly onWillChangeModel: Event<NotebookTextModel | undefined> = this._onWillChangeModel.event;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not seeing where this is used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's used here

private readonly _onDidChangeModel = this._register(new Emitter<NotebookTextModel | undefined>());
readonly onDidChangeModel: Event<NotebookTextModel | undefined> = this._onDidChangeModel.event;
private readonly _onDidChangeOptions = this._register(new Emitter<void>());
Expand Down Expand Up @@ -157,7 +159,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
private readonly _onDidResizeOutputEmitter = this._register(new Emitter<ICellViewModel>());
readonly onDidResizeOutput = this._onDidResizeOutputEmitter.event;


//#endregion
private _overlayContainer!: HTMLElement;
private _notebookTopToolbarContainer!: HTMLElement;
Expand Down Expand Up @@ -208,6 +209,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
}

set viewModel(newModel: NotebookViewModel | undefined) {
this._onWillChangeModel.fire(this._notebookViewModel?.notebookDocument);
this._notebookViewModel = newModel;
this._onDidChangeModel.fire(newModel?.notebookDocument);
}
Expand Down Expand Up @@ -2459,7 +2461,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
return ret;
}

async highlightFind(cell: CodeCellViewModel, matchIndex: number): Promise<number> {
async highlightFind(matchIndex: number): Promise<number> {
if (!this._webview) {
return 0;
}
Expand Down
Expand Up @@ -9,6 +9,8 @@ import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebo
import { INotebookEditor, INotebookEditorCreationOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { Event } from 'vs/base/common/event';
import { Dimension } from 'vs/base/browser/dom';
import { NotebookEditorWidget } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget';
import { URI } from 'vs/base/common/uri';

export const INotebookEditorService = createDecorator<INotebookEditorService>('INotebookEditorWidgetService');

Expand All @@ -21,6 +23,8 @@ export interface INotebookEditorService {

retrieveWidget(accessor: ServicesAccessor, group: IEditorGroup, input: NotebookEditorInput, creationOptions?: INotebookEditorCreationOptions, dimension?: Dimension): IBorrowValue<INotebookEditor>;

retrieveExistingWidgetFromURI(resource: URI): IBorrowValue<NotebookEditorWidget> | undefined;
retrieveAllExistingWidgets(): IBorrowValue<NotebookEditorWidget>[];
onDidAddNotebookEditor: Event<INotebookEditor>;
onDidRemoveNotebookEditor: Event<INotebookEditor>;
addNotebookEditor(editor: INotebookEditor): void;
Expand Down
Expand Up @@ -14,6 +14,7 @@ import { INotebookEditor, INotebookEditorCreationOptions } from 'vs/workbench/co
import { Emitter } from 'vs/base/common/event';
import { GroupIdentifier } from 'vs/workbench/common/editor';
import { Dimension } from 'vs/base/browser/dom';
import { URI } from 'vs/base/common/uri';

export class NotebookEditorWidgetService implements INotebookEditorService {

Expand Down Expand Up @@ -129,6 +130,26 @@ export class NotebookEditorWidgetService implements INotebookEditorService {
targetMap.set(input.resource, widget);
}

retrieveExistingWidgetFromURI(resource: URI): IBorrowValue<NotebookEditorWidget> | undefined {
for (const widgetInfo of this._borrowableEditors.values()) {
const widget = widgetInfo.get(resource);
if (widget) {
return this._createBorrowValue(widget.token!, widget);
}
}
return undefined;
}

retrieveAllExistingWidgets(): IBorrowValue<NotebookEditorWidget>[] {
const ret: IBorrowValue<NotebookEditorWidget>[] = [];
for (const widgetInfo of this._borrowableEditors.values()) {
for (const widget of widgetInfo.values()) {
ret.push(this._createBorrowValue(widget.token!, widget));
}
}
return ret;
}

retrieveWidget(accessor: ServicesAccessor, group: IEditorGroup, input: NotebookEditorInput, creationOptions?: INotebookEditorCreationOptions, initialDimension?: Dimension): IBorrowValue<NotebookEditorWidget> {

let value = this._borrowableEditors.get(group.id)?.get(input.resource);
Expand Down
Expand Up @@ -411,11 +411,20 @@ export interface IFindStopMessage {
readonly type: 'findStop';
}

export interface ISearchPreviewInfo {
line: string;
range: {
start: number;
end: number;
};
}

export interface IFindMatch {
readonly type: 'preview' | 'output';
readonly cellId: string;
readonly id: string;
readonly index: number;
readonly searchPreviewInfo?: ISearchPreviewInfo;
}

export interface IDidFindMessage extends BaseToWebviewMessage {
Expand Down
Expand Up @@ -277,9 +277,23 @@ suite('Notebook Find', () => {
mdModel.contentMatches.push(new FindMatch(new Range(1, 1, 1, 2), []));
assert.strictEqual(mdModel.length, 1);
mdModel.webviewMatches.push({
index: 0
index: 0,
searchPreviewInfo: {
line: '',
range: {
start: 0,
end: 0,
}
}
}, {
index: 1
index: 1,
searchPreviewInfo: {
line: '',
range: {
start: 0,
end: 0,
}
}
});

assert.strictEqual(mdModel.length, 3);
Expand Down
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Match, FileMatch, FileMatchOrMatch } from 'vs/workbench/contrib/search/common/searchModel';
import { Match, FileMatch, FileMatchOrMatch } from 'vs/workbench/contrib/search/browser/searchModel';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IProgress, IProgressStep } from 'vs/platform/progress/common/progress';

Expand Down
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IReplaceService } from 'vs/workbench/contrib/search/common/replace';
import { IReplaceService } from 'vs/workbench/contrib/search/browser/replace';
import { ReplaceService, ReplacePreviewContentProvider } from 'vs/workbench/contrib/search/browser/replaceService';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
Expand Down