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

Convert CSV to use document searcher #5937

Merged
merged 12 commits into from Feb 4, 2019
2 changes: 2 additions & 0 deletions dev_mode/package.json
Expand Up @@ -31,6 +31,7 @@
"@jupyterlab/docmanager": "^0.19.1",
"@jupyterlab/docmanager-extension": "^0.19.1",
"@jupyterlab/docregistry": "^0.19.1",
"@jupyterlab/documentsearch": "^0.7.1",
"@jupyterlab/documentsearch-extension": "^0.19.1",
"@jupyterlab/extensionmanager": "^0.19.1",
"@jupyterlab/extensionmanager-extension": "^0.19.1",
Expand Down Expand Up @@ -253,6 +254,7 @@
"@jupyterlab/docmanager": "../packages/docmanager",
"@jupyterlab/docmanager-extension": "../packages/docmanager-extension",
"@jupyterlab/docregistry": "../packages/docregistry",
"@jupyterlab/documentsearch": "../packages/documentsearch",
"@jupyterlab/documentsearch-extension": "../packages/documentsearch-extension",
"@jupyterlab/extensionmanager": "../packages/extensionmanager",
"@jupyterlab/extensionmanager-extension": "../packages/extensionmanager-extension",
Expand Down
4 changes: 0 additions & 4 deletions packages/codemirror-extension/src/index.ts
Expand Up @@ -398,10 +398,6 @@ function activateEditorCommands(
// Add find-replace capabilities to the edit menu.
mainMenu.editMenu.findReplacers.add({
tracker,
find: (widget: IDocumentWidget<FileEditor>) => {
let editor = widget.content.editor as CodeMirrorEditor;
editor.execCommand('find');
},
findAndReplace: (widget: IDocumentWidget<FileEditor>) => {
let editor = widget.content.editor as CodeMirrorEditor;
editor.execCommand('replace');
Expand Down
5 changes: 4 additions & 1 deletion packages/csvviewer-extension/package.json
Expand Up @@ -34,8 +34,11 @@
"@jupyterlab/apputils": "^0.19.1",
"@jupyterlab/csvviewer": "^0.19.1",
"@jupyterlab/docregistry": "^0.19.1",
"@jupyterlab/documentsearch": "^0.7.1",
"@jupyterlab/documentsearch-extension": "^0.19.1",
ian-r-rose marked this conversation as resolved.
Show resolved Hide resolved
"@jupyterlab/mainmenu": "^0.8.1",
"@phosphor/datagrid": "^0.1.6"
"@phosphor/datagrid": "^0.1.6",
"@phosphor/signaling": "^1.2.2"
},
"devDependencies": {
"rimraf": "~2.6.2",
Expand Down
32 changes: 15 additions & 17 deletions packages/csvviewer-extension/src/index.ts
Expand Up @@ -9,6 +9,8 @@ import {

import { InstanceTracker, IThemeManager, Dialog } from '@jupyterlab/apputils';

import { ISearchProviderRegistry } from '@jupyterlab/documentsearch';

import {
CSVViewer,
TextRenderConfig,
Expand All @@ -21,6 +23,7 @@ import { IDocumentWidget } from '@jupyterlab/docregistry';
import { DataGrid } from '@phosphor/datagrid';

import { IMainMenu, IEditMenu } from '@jupyterlab/mainmenu';
import { CSVSearchProvider } from './searchprovider';

/**
* The name of the factories that creates widgets.
Expand All @@ -35,6 +38,7 @@ const csv: JupyterFrontEndPlugin<void> = {
activate: activateCsv,
id: '@jupyterlab/csvviewer-extension:csv',
requires: [ILayoutRestorer, IThemeManager, IMainMenu],
optional: [ISearchProviderRegistry],
autoStart: true
};

Expand All @@ -45,6 +49,7 @@ const tsv: JupyterFrontEndPlugin<void> = {
activate: activateTsv,
id: '@jupyterlab/csvviewer-extension:tsv',
requires: [ILayoutRestorer, IThemeManager, IMainMenu],
optional: [ISearchProviderRegistry],
autoStart: true
};

Expand All @@ -55,21 +60,6 @@ function addMenuEntries(
mainMenu: IMainMenu,
tracker: InstanceTracker<IDocumentWidget<CSVViewer>>
) {
// Add find capability to the edit menu.
mainMenu.editMenu.findReplacers.add({
tracker,
find: (widget: IDocumentWidget<CSVViewer>) => {
return Dialog.prompt<string>(
'Search Text',
widget.content.searchService.searchText
).then(value => {
if (value.button.accept) {
widget.content.searchService.find(value.value);
}
});
}
} as IEditMenu.IFindReplacer<IDocumentWidget<CSVViewer>>);

// Add go to line capability to the edit menu.
mainMenu.editMenu.goToLiners.add({
tracker,
Expand All @@ -90,7 +80,8 @@ function activateCsv(
app: JupyterFrontEnd,
restorer: ILayoutRestorer,
themeManager: IThemeManager,
mainMenu: IMainMenu
mainMenu: IMainMenu,
searchregistry: ISearchProviderRegistry = null
): void {
const factory = new CSVViewerFactory({
name: FACTORY_CSV,
Expand Down Expand Up @@ -147,6 +138,9 @@ function activateCsv(
themeManager.themeChanged.connect(updateThemes);

addMenuEntries(mainMenu, tracker);
if (searchregistry) {
searchregistry.registerProvider('csv', CSVSearchProvider);
}
}

/**
Expand All @@ -156,7 +150,8 @@ function activateTsv(
app: JupyterFrontEnd,
restorer: ILayoutRestorer,
themeManager: IThemeManager,
mainMenu: IMainMenu
mainMenu: IMainMenu,
searchregistry: ISearchProviderRegistry = null
): void {
const factory = new TSVViewerFactory({
name: FACTORY_TSV,
Expand Down Expand Up @@ -213,6 +208,9 @@ function activateTsv(
themeManager.themeChanged.connect(updateThemes);

addMenuEntries(mainMenu, tracker);
if (searchregistry) {
searchregistry.registerProvider('tsv', CSVSearchProvider);
}
}

/**
Expand Down
100 changes: 100 additions & 0 deletions packages/csvviewer-extension/src/searchprovider.ts
@@ -0,0 +1,100 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
import { ISearchProvider, ISearchMatch } from '@jupyterlab/documentsearch';
import { CSVViewer } from '@jupyterlab/csvviewer';
import { IDocumentWidget, DocumentWidget } from '@jupyterlab/docregistry';
import { Signal, ISignal } from '@phosphor/signaling';

export class CSVSearchProvider implements ISearchProvider {
/**
* Report whether or not this provider has the ability to search on the given object
*/
static canSearchOn(domain: any): boolean {
ian-r-rose marked this conversation as resolved.
Show resolved Hide resolved
// check to see if the CMSearchProvider can search on the
// first cell, false indicates another editor is present
return (
domain instanceof DocumentWidget && domain.content instanceof CSVViewer
Copy link
Member

Choose a reason for hiding this comment

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

In other places in the codebase we would do a check on an InstanceTracker, which seems safer and more idiomatic. Is there a reason for the instanceof checks instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The tracker won't work here because the csv viewer doesn't expose a tracker. Granted that's a problem with the csv viewer, but I was trying to limit scope here in this PR.

);
}

/**
* Initialize the search using the provided options. Should update the UI
* to highlight all matches and "select" whatever the first match should be.
*
* @param query A RegExp to be use to perform the search
* @param searchTarget The widget to be searched
*
* @returns A promise that resolves with a list of all matches
*/
async startQuery(
query: RegExp,
searchTarget: IDocumentWidget<CSVViewer>
): Promise<ISearchMatch[]> {
this._target = searchTarget;
this._query = query;
searchTarget.content.searchService.find(query);
return this.matches;
}

/**
* Clears state of a search provider to prepare for startQuery to be called
* in order to start a new query or refresh an existing one.
*
* @returns A promise that resolves when the search provider is ready to
* begin a new search.
*/
async endQuery(): Promise<void> {
this._target.content.searchService.clear();
}

/**
* Resets UI state as it was before the search process began. Cleans up and
* disposes of all internal state.
*
* @returns A promise that resolves when all state has been cleaned up.
*/
async endSearch(): Promise<void> {
this._target.content.searchService.clear();
}

/**
* Move the current match indicator to the next match.
*
* @returns A promise that resolves once the action has completed.
*/
async highlightNext(): Promise<ISearchMatch | undefined> {
this._target.content.searchService.find(this._query);
return undefined;
}

/**
* Move the current match indicator to the previous match.
*
* @returns A promise that resolves once the action has completed.
*/
highlightPrevious(): Promise<ISearchMatch | undefined> {
this._target.content.searchService.find(this._query, true);
return undefined;
}

/**
* Signal indicating that something in the search has changed, so the UI should update
*/
get changed(): ISignal<this, void> {
return this._changed;
}

/**
* The same list of matches provided by the startQuery promise resoluton
*/
readonly matches: ISearchMatch[] = [];

/**
* The current index of the selected match.
*/
readonly currentMatchIndex: number | null = null;

private _target: IDocumentWidget<CSVViewer>;
private _query: RegExp;
private _changed = new Signal<this, void>(this);
}
6 changes: 6 additions & 0 deletions packages/csvviewer-extension/tsconfig.json
Expand Up @@ -18,6 +18,12 @@
{
"path": "../docregistry"
},
{
"path": "../documentsearch"
},
{
"path": "../documentsearch-extension"
},
{
"path": "../mainmenu"
}
Expand Down