UNPKG

jupyterlab-emrys

Version:

A computational environment for Jupyter. Powered by Emrys

395 lines (394 loc) 13.3 kB
// Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. "use strict"; var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var phosphor_panel_1 = require('phosphor-panel'); var phosphor_signaling_1 = require('phosphor-signaling'); var phosphor_widget_1 = require('phosphor-widget'); var inspector_1 = require('../inspector'); var cells_1 = require('../notebook/cells'); var mimetype_1 = require('../notebook/common/mimetype'); var completion_1 = require('../notebook/completion'); var history_1 = require('./history'); /** * The class name added to console widgets. */ var CONSOLE_CLASS = 'jp-Console'; /** * The class name added to the console banner. */ var BANNER_CLASS = 'jp-Console-banner'; /** * The class name of the active prompt */ var PROMPT_CLASS = 'jp-Console-prompt'; /** * A widget containing a Jupyter console. */ var ConsoleWidget = (function (_super) { __extends(ConsoleWidget, _super); /** * Construct a console widget. */ function ConsoleWidget(options) { var _this = this; _super.call(this); this._completion = null; this._completionHandler = null; this._inspectionHandler = null; this._mimetype = 'text/x-ipython'; this._rendermime = null; this._renderer = null; this._history = null; this._session = null; this.addClass(CONSOLE_CLASS); var layout = new phosphor_panel_1.PanelLayout(); this.layout = layout; this._renderer = options.renderer || ConsoleWidget.defaultRenderer; this._rendermime = options.rendermime; this._session = options.session; this._history = new history_1.ConsoleHistory(this._session.kernel); // Instantiate tab completion widget. var completion = options.completion || new completion_1.CompletionWidget({ model: new completion_1.CompletionModel() }); this._completion = completion; // Set the completion widget's anchor node to peg its position. completion.anchor = this.node; // Because a completion widget may be passed in, check if it is attached. if (!completion.isAttached) { completion.attach(document.body); } // Set up the completion handler. this._completionHandler = new completion_1.CellCompletionHandler(this._completion); this._completionHandler.kernel = this._session.kernel; // Set up the inspection handler. this._inspectionHandler = new inspector_1.InspectionHandler(this._rendermime); this._inspectionHandler.kernel = this._session.kernel; // Create the banner. var banner = this._renderer.createBanner(); banner.addClass(BANNER_CLASS); banner.readOnly = true; banner.model.source = '...'; layout.addChild(banner); // Set the banner text and the mimetype. this.initialize(); // Create the prompt. this.newPrompt(); // Handle changes to the kernel. this._session.kernelChanged.connect(function (s, kernel) { _this.clear(); _this.newPrompt(); _this.initialize(); _this._history.dispose(); _this._history = new history_1.ConsoleHistory(kernel); _this._completionHandler.kernel = kernel; _this._inspectionHandler.kernel = kernel; }); } Object.defineProperty(ConsoleWidget.prototype, "inspectionHandler", { /** * Get the inspection handler used by the console. * * #### Notes * This is a read-only property. */ get: function () { return this._inspectionHandler; }, enumerable: true, configurable: true }); Object.defineProperty(ConsoleWidget.prototype, "prompt", { /* * The last cell in a console is always a `CodeCellWidget` prompt. */ get: function () { var layout = this.layout; var last = layout.childCount() - 1; return last > 0 ? layout.childAt(last) : null; }, enumerable: true, configurable: true }); Object.defineProperty(ConsoleWidget.prototype, "session", { /** * Get the session used by the console. * * #### Notes * This is a read-only property. */ get: function () { return this._session; }, enumerable: true, configurable: true }); /** * Dispose of the resources held by the widget. */ ConsoleWidget.prototype.dispose = function () { // Do nothing if already disposed. if (this.isDisposed) { return; } this._history.dispose(); this._history = null; this._completionHandler.dispose(); this._completionHandler = null; this._completion.dispose(); this._completion = null; this._inspectionHandler.dispose(); this._inspectionHandler = null; this._session.dispose(); this._session = null; _super.prototype.dispose.call(this); }; /** * Execute the current prompt. */ ConsoleWidget.prototype.execute = function () { var _this = this; this.dismissCompletion(); if (this._session.status === 'dead') { this._inspectionHandler.handleExecuteReply(null); return; } var prompt = this.prompt; prompt.trusted = true; this._history.push(prompt.model.source); // Create a new prompt before kernel execution to allow typeahead. this.newPrompt(); return prompt.execute(this._session.kernel).then(function (value) { if (!value) { _this._inspectionHandler.handleExecuteReply(null); return; } if (value.content.status === 'ok') { var content = value.content; _this._inspectionHandler.handleExecuteReply(content); } Private.scrollToBottom(_this.node); }, function () { Private.scrollToBottom(_this.node); }); }; /** * Clear the code cells. */ ConsoleWidget.prototype.clear = function () { while (this.prompt) { this.prompt.dispose(); } this.newPrompt(); }; /** * Dismiss the completion widget for a console. */ ConsoleWidget.prototype.dismissCompletion = function () { this._completion.reset(); }; /** * Serialize the output. */ ConsoleWidget.prototype.serialize = function () { var output = []; var layout = this.layout; for (var i = 1; i < layout.childCount(); i++) { var widget = layout.childAt(i); output.push(widget.model.toJSON()); } return output; }; /** * Handle the DOM events for the widget. * * @param event - The DOM event sent to the widget. * * #### Notes * This method implements the DOM `EventListener` interface and is * called in response to events on the dock panel's node. It should * not be called directly by user code. */ ConsoleWidget.prototype.handleEvent = function (event) { switch (event.type) { case 'click': var prompt_1 = this.prompt; if (prompt_1) { prompt_1.focus(); } break; default: break; } }; /** * Handle `after_attach` messages for the widget. */ ConsoleWidget.prototype.onAfterAttach = function (msg) { this.node.addEventListener('click', this); var prompt = this.prompt; if (prompt) { prompt.focus(); } }; /** * Handle `before_detach` messages for the widget. */ ConsoleWidget.prototype.onBeforeDetach = function (msg) { this.node.removeEventListener('click', this); }; /** * Handle an edge requested signal. */ ConsoleWidget.prototype.onEdgeRequest = function (editor, location) { var prompt = this.prompt; if (location === 'top') { this._history.back().then(function (value) { if (!value) { return; } prompt.model.source = value; prompt.editor.setCursorPosition(0); }); } else { this._history.forward().then(function (value) { // If at the bottom end of history, then clear the prompt. var text = value || ''; prompt.model.source = text; prompt.editor.setCursorPosition(text.length); }); } }; /** * Handle `update_request` messages. */ ConsoleWidget.prototype.onUpdateRequest = function (msg) { var prompt = this.prompt; Private.scrollIfNeeded(this.parent.node, prompt.node); }; /** * Initialize the banner and mimetype. */ ConsoleWidget.prototype.initialize = function () { var _this = this; if (this._session.kernel.info) { this._handleInfo(this._session.kernel.info); } else { this._session.kernel.kernelInfo().then(function (msg) { _this._handleInfo(msg.content); }); } }; /** * Make a new prompt. */ ConsoleWidget.prototype.newPrompt = function () { // Make the previous editor read-only and clear its signals. var prompt = this.prompt; if (prompt) { prompt.readOnly = true; prompt.removeClass(PROMPT_CLASS); phosphor_signaling_1.clearSignalData(prompt.editor); } // Create the new prompt and add to layout. var layout = this.layout; prompt = this._renderer.createPrompt(this._rendermime); prompt.mimetype = this._mimetype; prompt.addClass(PROMPT_CLASS); layout.addChild(prompt); // Hook up completion and history handling. var editor = prompt.editor; editor.edgeRequested.connect(this.onEdgeRequest, this); // Associate the new prompt with the completion handler. this._completionHandler.activeCell = prompt; this._inspectionHandler.activeCell = prompt; // Jump to the bottom of the console. Private.scrollToBottom(this.node); prompt.focus(); }; /** * Update the console based on the kernel info. */ ConsoleWidget.prototype._handleInfo = function (info) { var layout = this.layout; var banner = layout.childAt(0); banner.model.source = info.banner; this._mimetype = mimetype_1.mimetypeForLanguage(info.language_info); this.prompt.mimetype = this._mimetype; }; return ConsoleWidget; }(phosphor_widget_1.Widget)); exports.ConsoleWidget = ConsoleWidget; /** * A namespace for ConsoleWidget statics. */ var ConsoleWidget; (function (ConsoleWidget) { /** * The default implementation of an `IRenderer`. */ var Renderer = (function () { function Renderer() { } /** * Create a new banner widget. */ Renderer.prototype.createBanner = function () { var widget = new cells_1.RawCellWidget(); widget.model = new cells_1.RawCellModel(); return widget; }; /** * Create a new prompt widget. */ Renderer.prototype.createPrompt = function (rendermime) { var widget = new cells_1.CodeCellWidget({ rendermime: rendermime }); widget.model = new cells_1.CodeCellModel(); return widget; }; return Renderer; }()); ConsoleWidget.Renderer = Renderer; /** * The default `IRenderer` instance. */ ConsoleWidget.defaultRenderer = new Renderer(); })(ConsoleWidget = exports.ConsoleWidget || (exports.ConsoleWidget = {})); /** * A namespace for console widget private data. */ var Private; (function (Private) { /** * Scroll an element into view if needed. * * @param area - The scroll area element. * * @param elem - The element of interest. */ function scrollIfNeeded(area, elem) { var ar = area.getBoundingClientRect(); var er = elem.getBoundingClientRect(); if (er.top < ar.top - 10) { area.scrollTop -= ar.top - er.top + 10; } else if (er.bottom > ar.bottom + 10) { area.scrollTop += er.bottom - ar.bottom + 10; } } Private.scrollIfNeeded = scrollIfNeeded; /** * Jump to the bottom of a node. * * @param node - The scrollable element. */ function scrollToBottom(node) { node.scrollTop = node.scrollHeight; } Private.scrollToBottom = scrollToBottom; })(Private || (Private = {}));