Przeglądaj źródła

Populate kernel help links (#3311)

* Work on dynamically populating help links.

* Register the notebook as a kernel user for the help menu.

* Populate the kernel info cache on demand rather than at startup.

* Add the console to the kernel users for the help menu.

* Integrity.

* Fix test build.
Ian Rose 7 lat temu
rodzic
commit
03174dc94c

+ 7 - 1
packages/console-extension/src/index.ts

@@ -30,7 +30,7 @@ import {
 } from '@jupyterlab/launcher';
 
 import {
-  IEditMenu, IFileMenu, IKernelMenu, IMainMenu, IRunMenu
+  IEditMenu, IFileMenu, IHelpMenu, IKernelMenu, IMainMenu, IRunMenu
 } from '@jupyterlab/mainmenu';
 
 import {
@@ -452,6 +452,12 @@ function activateConsole(app: JupyterLab, mainMenu: IMainMenu, palette: ICommand
     clear: (current: ConsolePanel) => { return current.console.clear() }
   } as IEditMenu.IClearer<ConsolePanel>);
 
+  // Add kernel information to the application help menu.
+  mainMenu.helpMenu.kernelUsers.add({
+    tracker,
+    getKernel: current => current.session.kernel
+  } as IHelpMenu.IKernelUser<ConsolePanel>);
+
   app.contextMenu.addItem({command: CommandIDs.clear, selector: '.jp-CodeConsole'});
   app.contextMenu.addItem({command: CommandIDs.restart, selector: '.jp-CodeConsole'});
 

+ 1 - 0
packages/help-extension/package.json

@@ -34,6 +34,7 @@
     "@jupyterlab/apputils": "^0.13.1",
     "@jupyterlab/coreutils": "^0.13.0",
     "@jupyterlab/mainmenu": "^0.2.0",
+    "@jupyterlab/services": "^0.52.0",
     "@phosphor/messaging": "^1.2.2",
     "@phosphor/virtualdom": "^1.1.2",
     "@phosphor/widgets": "^1.5.0"

+ 55 - 30
packages/help-extension/src/index.ts

@@ -17,6 +17,10 @@ import {
   IMainMenu
 } from '@jupyterlab/mainmenu';
 
+import {
+  KernelMessage
+} from '@jupyterlab/services';
+
 import {
   Message
 } from '@phosphor/messaging';
@@ -26,7 +30,7 @@ import {
 } from '@phosphor/virtualdom';
 
 import {
-  PanelLayout, Widget
+  Menu, PanelLayout, Widget
 } from '@phosphor/widgets';
 
 import '../style/index.css';
@@ -84,34 +88,6 @@ const RESOURCES = [
     text: 'Notebook Reference',
     url: 'https://jupyter-notebook.readthedocs.io/en/latest/'
   },
-  {
-    text: 'IPython Reference',
-    url: 'https://ipython.readthedocs.io/en/stable/'
-  },
-  {
-    text: 'Numpy Reference',
-    url: 'https://docs.scipy.org/doc/numpy/reference/'
-  },
-  {
-    text: 'Scipy Reference',
-    url: 'https://docs.scipy.org/doc/scipy/reference/'
-  },
-  {
-    text: 'Python Reference',
-    url: 'https://docs.python.org/3.5/'
-  },
-  {
-    text: 'Matplotlib Reference',
-    url: 'https://matplotlib.org/contents.html?v=20160707164940'
-  },
-  {
-    text: 'SymPy Reference',
-    url: 'http://docs.sympy.org/latest/index.html?v=20160707164940'
-  },
-  {
-    text: 'Pandas Reference',
-    url: 'https://pandas.pydata.org/pandas-docs/stable/?v=20160707164940'
-  },
   {
     text: 'Markdown Reference',
     url: 'https://help.github.com/articles/' +
@@ -190,7 +166,7 @@ function activate(app: JupyterLab, mainMenu: IMainMenu, palette: ICommandPalette
   let counter = 0;
   const category = 'Help';
   const namespace = 'help-doc';
-  const { commands, shell, info} = app;
+  const { commands, shell, info, serviceManager } = app;
   const tracker = new InstanceTracker<HelpWidget>({ namespace });
 
   // Handle state restoration.
@@ -225,6 +201,55 @@ function activate(app: JupyterLab, mainMenu: IMainMenu, palette: ICommandPalette
     RESOURCES.map(args => { return { args, command: CommandIDs.open }; });
   helpMenu.addGroup(resourcesGroup, 10);
 
+  // Generate a cache of the kernel help links.
+  const kernelInfoCache = new Map<string, KernelMessage.IInfoReply>();
+  serviceManager.sessions.runningChanged.connect((m, sessions) => {
+    // If a new session has been added, it is at the back
+    // of the session list. If one has changed or stopped,
+    // it does not hurt to check it.
+    const sessionModel = sessions[sessions.length-1];
+    if (kernelInfoCache.has(sessionModel.kernel.name)) {
+      return;
+    }
+    serviceManager.sessions.connectTo(sessionModel.id).then((session) => {
+      session.kernel.ready.then(() => {
+        // Set the Kernel Info cache.
+        const name = session.kernel.name;
+        kernelInfoCache.set(name, session.kernel.info);
+
+        // Utility function to check if the current widget
+        // has registered itself with the help menu.
+        const usesKernel = () => {
+          let result = false;
+          const widget = app.shell.currentWidget;
+          if (!widget) {
+            return result;
+          }
+          helpMenu.kernelUsers.forEach(u => {
+            if (u.tracker.has(widget) && u.getKernel(widget).name === name) {
+              result = true;
+            }
+          });
+          return result;
+        }
+
+        // Add the kernel info help_links to the Help menu.
+        const kernelGroup: Menu.IItemOptions[] = [];
+        session.kernel.info.help_links.forEach((link) => {
+          const commandId = `help-menu-${name}:${link.text}`;
+          commands.addCommand(commandId, {
+            label: link.text,
+            isVisible: usesKernel,
+            isEnabled: usesKernel,
+            execute: () => { commands.execute(CommandIDs.open, link) }
+          });
+          kernelGroup.push({ command: commandId });
+        });
+        helpMenu.addGroup(kernelGroup, 20);
+      });
+    });
+  });
+
   commands.addCommand(CommandIDs.about, {
     label: `About ${info.name}`,
     execute: () => {

+ 38 - 2
packages/mainmenu/src/help.ts

@@ -2,11 +2,15 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  Menu
+  Kernel
+} from '@jupyterlab/services';
+
+import {
+  Menu, Widget
 } from '@phosphor/widgets';
 
 import {
-  IJupyterLabMenu, JupyterLabMenu
+  IJupyterLabMenu, IMenuExtender, JupyterLabMenu
 } from './labmenu';
 
 /**
@@ -14,6 +18,12 @@ import {
  */
 export
 interface IHelpMenu extends IJupyterLabMenu {
+  /**
+   * A set of kernel users for the help menu.
+   * This is used to populate additional help
+   * links provided by the kernel of a widget.
+   */
+  readonly kernelUsers: Set<IHelpMenu.IKernelUser<Widget>>;
 }
 
 /**
@@ -27,5 +37,31 @@ class HelpMenu extends JupyterLabMenu implements IHelpMenu {
   constructor(options: Menu.IOptions) {
     super(options);
     this.menu.title.label = 'Help';
+    this.kernelUsers = new Set<IHelpMenu.IKernelUser<Widget>>();
+  }
+
+  /**
+   * A set of kernel users for the help menu.
+   * This is used to populate additional help
+   * links provided by the kernel of a widget.
+   */
+  readonly kernelUsers: Set<IHelpMenu.IKernelUser<Widget>>;
+}
+
+/**
+ * Namespace for IHelpMenu
+ */
+export
+namespace IHelpMenu {
+  /**
+   * Interface for a Kernel user to register itself
+   * with the IHelpMenu's semantic extension points.
+   */
+  export
+  interface IKernelUser<T extends Widget> extends IMenuExtender<T> {
+    /**
+     * A function to get the kernel for a widget.
+     */
+    getKernel: (widget: T) => Kernel.IKernelConnection;
   }
 }

+ 7 - 1
packages/notebook-extension/src/index.ts

@@ -26,7 +26,7 @@ import {
 } from '@jupyterlab/launcher';
 
 import {
-  IMainMenu, IEditMenu, IFileMenu, IKernelMenu, IRunMenu, IViewMenu
+  IMainMenu, IEditMenu, IFileMenu, IHelpMenu, IKernelMenu, IRunMenu, IViewMenu
 } from '@jupyterlab/mainmenu';
 
 import {
@@ -1441,4 +1441,10 @@ function populateMenus(app: JupyterLab, mainMenu: IMainMenu, tracker: INotebookT
   ].map(command => { return { command }; });
   mainMenu.editMenu.addGroup(undoCellActionGroup, 4);
   mainMenu.editMenu.addGroup(editGroup, 5);
+
+  // Add kernel information to the application help menu.
+  mainMenu.helpMenu.kernelUsers.add({
+    tracker,
+    getKernel: current => current.session.kernel
+  } as IHelpMenu.IKernelUser<NotebookPanel>);
 }

+ 1 - 1
packages/services/src/kernel/messages.ts

@@ -371,7 +371,7 @@ namespace KernelMessage {
     implementation_version: string;
     language_info: ILanguageInfo;
     banner: string;
-    help_links: { [key: string]: string; };
+    help_links: { text: string; url: string }[];
   }
 
   /**

+ 4 - 2
packages/services/test/src/utils.ts

@@ -75,8 +75,10 @@ const EXAMPLE_KERNEL_INFO: KernelMessage.IInfoReply = {
     nbconverter_exporter: ''
   },
   banner: '',
-  help_links: {
-  }
+  help_links: [{
+    text: 'A very helpful link',
+    url: 'https://very.helpful.website'
+  }]
 };