123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- // Copyright (c) Jupyter Development Team.
- // Distributed under the terms of the Modified BSD License.
- import {
- ILayoutRestorer, JupyterLab, JupyterLabPlugin
- } from '@jupyterlab/application';
- import {
- Dialog, ICommandPalette, InstanceTracker, showDialog
- } from '@jupyterlab/apputils';
- import {
- IEditorServices
- } from '@jupyterlab/codeeditor';
- import {
- ConsolePanel, IConsoleTracker
- } from '@jupyterlab/console';
- import {
- PageConfig
- } from '@jupyterlab/coreutils';
- import {
- IFileBrowserFactory
- } from '@jupyterlab/filebrowser';
- import {
- ILauncher
- } from '@jupyterlab/launcher';
- import {
- IMainMenu
- } from '@jupyterlab/mainmenu';
- import {
- find
- } from '@phosphor/algorithm';
- import {
- ReadonlyJSONObject
- } from '@phosphor/coreutils';
- import {
- Menu
- } from '@phosphor/widgets';
- /**
- * The command IDs used by the console plugin.
- */
- namespace CommandIDs {
- export
- const create = 'console:create';
- export
- const clear = 'console:clear';
- export
- const runUnforced = 'console:run-unforced';
- export
- const runForced = 'console:run-forced';
- export
- const linebreak = 'console:linebreak';
- export
- const interrupt = 'console:interrupt-kernel';
- export
- const restart = 'console:restart-kernel';
- export
- const closeAndShutdown = 'console:close-and-shutdown';
- export
- const open = 'console:open';
- export
- const inject = 'console:inject';
- export
- const changeKernel = 'console:change-kernel';
- }
- /**
- * The console widget tracker provider.
- */
- const tracker: JupyterLabPlugin<IConsoleTracker> = {
- id: '@jupyterlab/console-extension:tracker',
- provides: IConsoleTracker,
- requires: [
- IMainMenu,
- ICommandPalette,
- ConsolePanel.IContentFactory,
- IEditorServices,
- ILayoutRestorer,
- IFileBrowserFactory
- ],
- optional: [ILauncher],
- activate: activateConsole,
- autoStart: true
- };
- /**
- * The console widget content factory.
- */
- const factory: JupyterLabPlugin<ConsolePanel.IContentFactory> = {
- id: '@jupyterlab/console-extension:factory',
- provides: ConsolePanel.IContentFactory,
- requires: [IEditorServices],
- autoStart: true,
- activate: (app: JupyterLab, editorServices: IEditorServices) => {
- const editorFactory = editorServices.factoryService.newInlineEditor
- .bind(editorServices.factoryService);
- return new ConsolePanel.ContentFactory({ editorFactory });
- }
- };
- /**
- * Export the plugins as the default.
- */
- const plugins: JupyterLabPlugin<any>[] = [factory, tracker];
- export default plugins;
- /**
- * Activate the console extension.
- */
- function activateConsole(app: JupyterLab, mainMenu: IMainMenu, palette: ICommandPalette, contentFactory: ConsolePanel.IContentFactory, editorServices: IEditorServices, restorer: ILayoutRestorer, browserFactory: IFileBrowserFactory, launcher: ILauncher | null): IConsoleTracker {
- const manager = app.serviceManager;
- const { commands, shell } = app;
- const category = 'Console';
- const menu = new Menu({ commands });
- // Create an instance tracker for all console panels.
- const tracker = new InstanceTracker<ConsolePanel>({ namespace: 'console' });
- // Handle state restoration.
- restorer.restore(tracker, {
- command: CommandIDs.open,
- args: panel => ({
- path: panel.console.session.path,
- name: panel.console.session.name
- }),
- name: panel => panel.console.session.path,
- when: manager.ready
- });
- // Update the command registry when the console state changes.
- tracker.currentChanged.connect(() => {
- if (tracker.size <= 1) {
- commands.notifyCommandChanged(CommandIDs.interrupt);
- }
- });
- // The launcher callback.
- let callback = (cwd: string, name: string) => {
- return createConsole({ basePath: cwd, kernelPreference: { name } });
- };
- // Add a launcher item if the launcher is available.
- if (launcher) {
- manager.ready.then(() => {
- const specs = manager.specs;
- if (!specs) {
- return;
- }
- let baseUrl = PageConfig.getBaseUrl();
- for (let name in specs.kernelspecs) {
- let displayName = specs.kernelspecs[name].display_name;
- let rank = name === specs.default ? 0 : Infinity;
- let kernelIconUrl = specs.kernelspecs[name].resources['logo-64x64'];
- if (kernelIconUrl) {
- let index = kernelIconUrl.indexOf('kernelspecs');
- kernelIconUrl = baseUrl + kernelIconUrl.slice(index);
- }
- launcher.add({
- displayName,
- category: 'Console',
- name,
- iconClass: 'jp-CodeConsoleIcon',
- callback,
- rank,
- kernelIconUrl
- });
- }
- });
- }
- // Set the main menu title.
- menu.title.label = category;
- /**
- * Create a console for a given path.
- */
- function createConsole(options: Partial<ConsolePanel.IOptions>): Promise<ConsolePanel> {
- return manager.ready.then(() => {
- let panel = new ConsolePanel({
- manager,
- rendermime: app.rendermime.clone(),
- contentFactory,
- mimeTypeService: editorServices.mimeTypeService,
- ...options
- });
- // Add the console panel to the tracker.
- tracker.add(panel);
- shell.addToMainArea(panel);
- shell.activateById(panel.id);
- return panel;
- });
- }
- /**
- * Whether there is an active console.
- */
- function hasWidget(): boolean {
- return tracker.currentWidget !== null;
- }
- let command = CommandIDs.open;
- commands.addCommand(command, {
- execute: (args: Partial<ConsolePanel.IOptions>) => {
- let path = args['path'];
- let widget = tracker.find(value => {
- return value.console.session.path === path;
- });
- if (widget) {
- shell.activateById(widget.id);
- } else {
- return manager.ready.then(() => {
- let model = find(manager.sessions.running(), item => {
- return item.path === path;
- });
- if (model) {
- return createConsole(args);
- }
- return Promise.reject(`No running console for path: ${path}`);
- });
- }
- },
- });
- command = CommandIDs.create;
- commands.addCommand(command, {
- label: 'New Console',
- execute: (args: Partial<ConsolePanel.IOptions>) => {
- let basePath = args.basePath || browserFactory.defaultBrowser.model.path;
- return createConsole({ basePath, ...args });
- }
- });
- palette.addItem({ command, category });
- // Get the current widget and activate unless the args specify otherwise.
- function getCurrent(args: ReadonlyJSONObject): ConsolePanel | null {
- let widget = tracker.currentWidget;
- let activate = args['activate'] !== false;
- if (activate && widget) {
- shell.activateById(widget.id);
- }
- return widget;
- }
- command = CommandIDs.clear;
- commands.addCommand(command, {
- label: 'Clear Cells',
- execute: args => {
- let current = getCurrent(args);
- if (!current) {
- return;
- }
- current.console.clear();
- },
- isEnabled: hasWidget
- });
- palette.addItem({ command, category });
- command = CommandIDs.runUnforced;
- commands.addCommand(command, {
- label: 'Run Cell (unforced)',
- execute: args => {
- let current = getCurrent(args);
- if (!current) {
- return;
- }
- return current.console.execute();
- },
- isEnabled: hasWidget
- });
- palette.addItem({ command, category });
- command = CommandIDs.runForced;
- commands.addCommand(command, {
- label: 'Run Cell (forced)',
- execute: args => {
- let current = getCurrent(args);
- if (!current) {
- return;
- }
- current.console.execute(true);
- },
- isEnabled: hasWidget
- });
- palette.addItem({ command, category });
- command = CommandIDs.linebreak;
- commands.addCommand(command, {
- label: 'Insert Line Break',
- execute: args => {
- let current = getCurrent(args);
- if (!current) {
- return;
- }
- current.console.insertLinebreak();
- },
- isEnabled: hasWidget
- });
- palette.addItem({ command, category });
- command = CommandIDs.interrupt;
- commands.addCommand(command, {
- label: 'Interrupt Kernel',
- execute: args => {
- let current = getCurrent(args);
- if (!current) {
- return;
- }
- let kernel = current.console.session.kernel;
- if (kernel) {
- return kernel.interrupt();
- }
- },
- isEnabled: hasWidget
- });
- palette.addItem({ command, category });
- command = CommandIDs.restart;
- commands.addCommand(command, {
- label: 'Restart Kernel',
- execute: args => {
- let current = getCurrent(args);
- if (!current) {
- return;
- }
- return current.console.session.restart();
- },
- isEnabled: hasWidget
- });
- palette.addItem({ command, category });
- command = CommandIDs.closeAndShutdown;
- commands.addCommand(command, {
- label: 'Close and Shutdown',
- execute: args => {
- const current = getCurrent(args);
- if (!current) {
- return;
- }
- return showDialog({
- title: 'Shutdown the console?',
- body: `Are you sure you want to close "${current.title.label}"?`,
- buttons: [Dialog.cancelButton(), Dialog.warnButton()]
- }).then(result => {
- if (result.button.accept) {
- current.console.session.shutdown().then(() => {
- current.dispose();
- });
- } else {
- return false;
- }
- });
- },
- isEnabled: hasWidget
- });
- command = CommandIDs.inject;
- commands.addCommand(command, {
- execute: args => {
- let path = args['path'];
- tracker.find(widget => {
- if (widget.console.session.path === path) {
- if (args['activate'] !== false) {
- shell.activateById(widget.id);
- }
- widget.console.inject(args['code'] as string);
- return true;
- }
- return false;
- });
- },
- isEnabled: hasWidget
- });
- command = CommandIDs.changeKernel;
- commands.addCommand(command, {
- label: 'Change Kernel',
- execute: args => {
- let current = getCurrent(args);
- if (!current) {
- return;
- }
- return current.console.session.selectKernel();
- },
- isEnabled: hasWidget
- });
- palette.addItem({ command, category });
- // Add a console creator to the File menu
- mainMenu.fileMenu.newMenu.addItem({ command: CommandIDs.create });
- // Add a kernel user to the Kernel menu
- mainMenu.kernelMenu.addUser<ConsolePanel>({
- tracker,
- interruptKernel: current => {
- let kernel = current.console.session.kernel;
- if (kernel) {
- return kernel.interrupt();
- }
- return Promise.resolve(void 0);
- },
- restartKernel: current => current.console.session.restart(),
- changeKernel: current => current.console.session.selectKernel()
- });
- // Add a code runner to the Run menu.
- mainMenu.runMenu.addRunner<ConsolePanel>({
- tracker,
- run: current => current.console.execute(true)
- });
- // Add the console menu.
- menu.addItem({ command: CommandIDs.runUnforced });
- menu.addItem({ command: CommandIDs.runForced });
- menu.addItem({ command: CommandIDs.linebreak });
- menu.addItem({ type: 'separator' });
- menu.addItem({ command: CommandIDs.clear });
- menu.addItem({ type: 'separator' });
- menu.addItem({ command: CommandIDs.closeAndShutdown });
- mainMenu.addMenu(menu, {rank: 50});
- app.contextMenu.addItem({command: CommandIDs.clear, selector: '.jp-CodeConsole'});
- app.contextMenu.addItem({command: CommandIDs.restart, selector: '.jp-CodeConsole'});
- return tracker;
- }
|