Ver código fonte

fixes #6715: makes ISearchProvider a generic interface

There's already an existing workaround for #6715, but this one
requires fewer casts
telamonian 5 anos atrás
pai
commit
a7041c2ac1

+ 4 - 2
packages/csvviewer-extension/src/searchprovider.ts

@@ -4,12 +4,14 @@ import { ISearchProvider, ISearchMatch } from '@jupyterlab/documentsearch';
 import { CSVViewer } from '@jupyterlab/csvviewer';
 import { IDocumentWidget, DocumentWidget } from '@jupyterlab/docregistry';
 import { Signal, ISignal } from '@phosphor/signaling';
+import { Widget } from '@phosphor/widgets';
 
-export class CSVSearchProvider implements ISearchProvider {
+export class CSVSearchProvider
+  implements ISearchProvider<IDocumentWidget<CSVViewer>> {
   /**
    * Report whether or not this provider has the ability to search on the given object
    */
-  static canSearchOn(domain: any): boolean {
+  static canSearchOn(domain: Widget): boolean {
     // check to see if the CMSearchProvider can search on the
     // first cell, false indicates another editor is present
     return (

+ 1 - 1
packages/documentsearch-extension/src/index.ts

@@ -86,7 +86,7 @@ const extension: JupyterFrontEndPlugin<ISearchProviderRegistry> = {
     registry.register('jp-notebookSearchProvider', NotebookSearchProvider);
     registry.register('jp-codeMirrorSearchProvider', CodeMirrorSearchProvider);
 
-    const activeSearches = new Map<string, SearchInstance>();
+    const activeSearches = new Map<string, SearchInstance<any>>();
 
     const startCommand: string = 'documentsearch:start';
     const nextCommand: string = 'documentsearch:highlightNext';

+ 6 - 6
packages/documentsearch/src/interfaces.ts

@@ -97,15 +97,15 @@ export interface ISearchMatch {
  * This interface is meant to enforce that SearchProviders implement the static
  * canSearchOn function.
  */
-export interface ISearchProviderConstructor {
-  new (): ISearchProvider;
+export interface ISearchProviderConstructor<T extends Widget> {
+  new (): ISearchProvider<T>;
   /**
    * Report whether or not this provider has the ability to search on the given object
    */
   canSearchOn(domain: Widget): boolean;
 }
 
-export interface ISearchProvider {
+export interface ISearchProvider<T extends Widget> {
   /**
    * Get an initial query value if applicable so that it can be entered
    * into the search box as an initial query
@@ -114,7 +114,7 @@ export interface ISearchProvider {
    *
    * @returns Initial value used to populate the search box.
    */
-  getInitialQuery(searchTarget: Widget): any;
+  getInitialQuery(searchTarget: T): any;
   /**
    * Initialize the search using the provided options.  Should update the UI
    * to highlight all matches and "select" whatever the first match should be.
@@ -124,7 +124,7 @@ export interface ISearchProvider {
    *
    * @returns A promise that resolves with a list of all matches
    */
-  startQuery(query: RegExp, searchTarget: Widget): Promise<ISearchMatch[]>;
+  startQuery(query: RegExp, searchTarget: T): Promise<ISearchMatch[]>;
 
   /**
    * Clears state of a search provider to prepare for startQuery to be called
@@ -179,7 +179,7 @@ export interface ISearchProvider {
   /**
    * Signal indicating that something in the search has changed, so the UI should update
    */
-  readonly changed: ISignal<ISearchProvider, void>;
+  readonly changed: ISignal<ISearchProvider<T>, void>;
 
   /**
    * The current index of the selected match.

+ 7 - 8
packages/documentsearch/src/providers/codemirrorsearchprovider.ts

@@ -36,23 +36,23 @@ import { MainAreaWidget } from '@jupyterlab/apputils';
 import { CodeMirrorEditor } from '@jupyterlab/codemirror';
 import { CodeEditor } from '@jupyterlab/codeeditor';
 import { ISignal, Signal } from '@phosphor/signaling';
-import { Widget } from '@phosphor/widgets';
 
 import * as CodeMirror from 'codemirror';
 import { FileEditor } from '@jupyterlab/fileeditor';
+import { Widget } from '@phosphor/widgets';
 
 type MatchMap = { [key: number]: { [key: number]: ISearchMatch } };
 
-export class CodeMirrorSearchProvider implements ISearchProvider {
+export class CodeMirrorSearchProvider
+  implements ISearchProvider<MainAreaWidget> {
   /**
    * Get an initial query value if applicable so that it can be entered
    * into the search box as an initial query
    *
    * @returns Initial value used to populate the search box.
    */
-  getInitialQuery(searchTarget: Widget): any {
-    const target = searchTarget as MainAreaWidget;
-    const content = target.content as FileEditor;
+  getInitialQuery(searchTarget: MainAreaWidget): any {
+    const content = searchTarget.content as FileEditor;
     const cm = content.editor as CodeMirrorEditor;
     const selection = cm.doc.getSelection();
     // if there are newlines, just return empty string
@@ -70,7 +70,7 @@ export class CodeMirrorSearchProvider implements ISearchProvider {
    */
   async startQuery(
     query: RegExp,
-    searchTarget: Widget
+    searchTarget: MainAreaWidget
   ): Promise<ISearchMatch[]> {
     if (!CodeMirrorSearchProvider.canSearchOn(searchTarget)) {
       throw new Error('Cannot find Codemirror instance to search');
@@ -78,8 +78,7 @@ export class CodeMirrorSearchProvider implements ISearchProvider {
 
     // Extract the codemirror object from the editor widget. Each of these casts
     // is justified by the canSearchOn call above.
-    const target = searchTarget as MainAreaWidget;
-    const content = target.content as FileEditor;
+    const content = searchTarget.content as FileEditor;
     this._cm = content.editor as CodeMirrorEditor;
     return this._startQuery(query);
   }

+ 6 - 7
packages/documentsearch/src/providers/notebooksearchprovider.ts

@@ -17,16 +17,15 @@ interface ICellSearchPair {
   provider: CodeMirrorSearchProvider;
 }
 
-export class NotebookSearchProvider implements ISearchProvider {
+export class NotebookSearchProvider implements ISearchProvider<NotebookPanel> {
   /**
    * Get an initial query value if applicable so that it can be entered
    * into the search box as an initial query
    *
    * @returns Initial value used to populate the search box.
    */
-  getInitialQuery(searchTarget: Widget): any {
-    const notebookPanel = searchTarget as NotebookPanel;
-    const activeCell = notebookPanel.content.activeCell;
+  getInitialQuery(searchTarget: NotebookPanel): any {
+    const activeCell = searchTarget.content.activeCell;
     const selection = (activeCell.editor as CodeMirrorEditor).doc.getSelection();
     // if there are newlines, just return empty string
     return selection.search(/\r?\n|\r/g) === -1 ? selection : '';
@@ -43,9 +42,9 @@ export class NotebookSearchProvider implements ISearchProvider {
    */
   async startQuery(
     query: RegExp,
-    searchTarget: Widget
+    searchTarget: NotebookPanel
   ): Promise<ISearchMatch[]> {
-    this._searchTarget = searchTarget as NotebookPanel;
+    this._searchTarget = searchTarget;
     const cells = this._searchTarget.content.widgets;
 
     this._query = query;
@@ -241,7 +240,7 @@ export class NotebookSearchProvider implements ISearchProvider {
   /**
    * Report whether or not this provider has the ability to search on the given object
    */
-  static canSearchOn(domain: any): boolean {
+  static canSearchOn(domain: Widget): boolean {
     // check to see if the CMSearchProvider can search on the
     // first cell, false indicates another editor is present
     return domain instanceof NotebookPanel;

+ 4 - 4
packages/documentsearch/src/searchinstance.ts

@@ -12,8 +12,8 @@ import { Widget } from '@phosphor/widgets';
 /**
  * Represents a search on a single widget.
  */
-export class SearchInstance implements IDisposable {
-  constructor(widget: Widget, searchProvider: ISearchProvider) {
+export class SearchInstance<T extends Widget> implements IDisposable {
+  constructor(widget: T, searchProvider: ISearchProvider<T>) {
     this._widget = widget;
     this._activeProvider = searchProvider;
 
@@ -189,7 +189,7 @@ export class SearchInstance implements IDisposable {
     this._updateDisplay();
   }
 
-  private _widget: Widget;
+  private _widget: T;
   private _displayState: IDisplayState = {
     currentIndex: 0,
     totalMatches: 0,
@@ -205,7 +205,7 @@ export class SearchInstance implements IDisposable {
     replaceEntryShown: false
   };
   private _displayUpdateSignal = new Signal<this, IDisplayState>(this);
-  private _activeProvider: ISearchProvider;
+  private _activeProvider: ISearchProvider<T>;
   private _searchWidget: Widget;
   private _isDisposed = false;
   private _disposed = new Signal<this, void>(this);

+ 1 - 1
packages/documentsearch/src/searchoverlay.tsx

@@ -462,7 +462,7 @@ export function createSearchOverlay(
 
 namespace createSearchOverlay {
   export interface IOptions {
-    widgetChanged: Signal<SearchInstance, IDisplayState>;
+    widgetChanged: Signal<SearchInstance<any>, IDisplayState>;
     overlayState: IDisplayState;
     onCaseSensitiveToggled: Function;
     onRegexToggled: Function;

+ 13 - 8
packages/documentsearch/src/searchproviderregistry.ts

@@ -4,9 +4,9 @@
 import { ISearchProvider, ISearchProviderConstructor } from './interfaces';
 import { ISearchProviderRegistry } from './tokens';
 
-import { Widget } from '@phosphor/widgets';
 import { IDisposable, DisposableDelegate } from '@phosphor/disposable';
 import { ISignal, Signal } from '@phosphor/signaling';
+import { Widget } from '@phosphor/widgets';
 
 export class SearchProviderRegistry implements ISearchProviderRegistry {
   /**
@@ -15,7 +15,10 @@ export class SearchProviderRegistry implements ISearchProviderRegistry {
    * @param key - The provider key.
    * @returns A disposable delegate that, when disposed, deregisters the given search provider
    */
-  register(key: string, provider: ISearchProviderConstructor): IDisposable {
+  register<T extends Widget>(
+    key: string,
+    provider: ISearchProviderConstructor<T>
+  ): IDisposable {
     this._providerMap.set(key, provider);
     this._changed.emit();
     return new DisposableDelegate(() => {
@@ -30,7 +33,9 @@ export class SearchProviderRegistry implements ISearchProviderRegistry {
    * @param widget - The widget to search over.
    * @returns the search provider, or undefined if none exists.
    */
-  getProviderForWidget(widget: Widget): ISearchProvider | undefined {
+  getProviderForWidget<T extends Widget>(
+    widget: T
+  ): ISearchProvider<T> | undefined {
     return this._findMatchingProvider(this._providerMap, widget);
   }
 
@@ -42,10 +47,10 @@ export class SearchProviderRegistry implements ISearchProviderRegistry {
     return this._changed;
   }
 
-  private _findMatchingProvider(
+  private _findMatchingProvider<T extends Widget>(
     providerMap: Private.ProviderMap,
-    widget: Widget
-  ): ISearchProvider | undefined {
+    widget: T
+  ): ISearchProvider<T> | undefined {
     // iterate through all providers and ask each one if it can search on the
     // widget.
     for (let P of providerMap.values()) {
@@ -59,10 +64,10 @@ export class SearchProviderRegistry implements ISearchProviderRegistry {
   private _changed = new Signal<this, void>(this);
   private _providerMap: Private.ProviderMap = new Map<
     string,
-    ISearchProviderConstructor
+    ISearchProviderConstructor<any>
   >();
 }
 
 namespace Private {
-  export type ProviderMap = Map<string, ISearchProviderConstructor>;
+  export type ProviderMap = Map<string, ISearchProviderConstructor<any>>;
 }

+ 2 - 2
packages/documentsearch/src/tokens.ts

@@ -23,7 +23,7 @@ export interface ISearchProviderRegistry {
    * @param key - The provider key.
    * @returns A disposable delegate that, when disposed, deregisters the given search provider
    */
-  register(key: string, provider: ISearchProviderConstructor): IDisposable;
+  register(key: string, provider: ISearchProviderConstructor<any>): IDisposable;
 
   /**
    * Returns a matching provider for the widget.
@@ -31,7 +31,7 @@ export interface ISearchProviderRegistry {
    * @param widget - The widget to search over.
    * @returns the search provider, or undefined if none exists.
    */
-  getProviderForWidget(widget: any): ISearchProvider | undefined;
+  getProviderForWidget(widget: any): ISearchProvider<any> | undefined;
 
   /**
    * Signal that emits when a new search provider has been registered