UNPKG

jupyterlab-emrys

Version:

A computational environment for Jupyter. Powered by Emrys

396 lines (395 loc) 12.7 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_domutil_1 = require('phosphor-domutil'); var phosphor_messaging_1 = require('phosphor-messaging'); var phosphor_widget_1 = require('phosphor-widget'); var Xterm = require('xterm'); /** * The class name added to a terminal widget. */ var TERMINAL_CLASS = 'jp-TerminalWidget'; /** * The class name added to a terminal body. */ var TERMINAL_BODY_CLASS = 'jp-TerminalWidget-body'; /** * The number of rows to use in the dummy terminal. */ var DUMMY_ROWS = 24; /** * The number of cols to use in the dummy terminal. */ var DUMMY_COLS = 80; /** * A widget which manages a terminal session. */ var TerminalWidget = (function (_super) { __extends(TerminalWidget, _super); /** * Construct a new terminal widget. * * @param options - The terminal configuration options. */ function TerminalWidget(options) { if (options === void 0) { options = {}; } _super.call(this); this._term = null; this._sheet = null; this._dummyTerm = null; this._fontSize = -1; this._dirty = false; this._rowHeight = -1; this._colWidth = -1; this._background = ''; this._color = ''; this._box = null; this._session = null; this.addClass(TERMINAL_CLASS); // Create the xterm, dummy terminal, and private style sheet. this._term = new Xterm(Private.getConfig(options)); this._initializeTerm(); this._dummyTerm = Private.createDummyTerm(); this._sheet = document.createElement('style'); this.node.appendChild(this._sheet); // Initialize settings. this.fontSize = options.fontSize || 14; this.background = options.background || 'black'; this.color = options.color || 'white'; this.id = "jp-TerminalWidget-" + Private.id++; this.title.text = 'Terminal'; Xterm.brokenBold = true; } Object.defineProperty(TerminalWidget.prototype, "session", { /** * The terminal session associated with the widget. */ get: function () { return this._session; }, set: function (value) { if (this._session && !this._session.isDisposed) { this._session.messageReceived.disconnect(this._onMessage, this); } this._session = value; this._session.messageReceived.connect(this._onMessage, this); this.title.text = "Terminal " + this._session.name; this._resizeTerminal(-1, -1); }, enumerable: true, configurable: true }); Object.defineProperty(TerminalWidget.prototype, "fontSize", { /** * Get the font size of the terminal in pixels. */ get: function () { return this._fontSize; }, /** * Set the font size of the terminal in pixels. */ set: function (size) { this._fontSize = size; this._term.element.style.fontSize = size + "px"; this._snapTermSizing(); }, enumerable: true, configurable: true }); Object.defineProperty(TerminalWidget.prototype, "background", { /** * Get the background color of the terminal. */ get: function () { return this._background; }, /** * Set the background color of the terminal. */ set: function (value) { this._background = value; this.update(); }, enumerable: true, configurable: true }); Object.defineProperty(TerminalWidget.prototype, "color", { /** * Get the text color of the terminal. */ get: function () { return this._color; }, /** * Set the text color of the terminal. */ set: function (value) { this._color = value; this.update(); }, enumerable: true, configurable: true }); Object.defineProperty(TerminalWidget.prototype, "visualBell", { /** * Get whether the bell is shown. */ get: function () { return this._term.visualBell; }, /** * Set whether the bell is shown. */ set: function (value) { this._term.visualBell = value; }, enumerable: true, configurable: true }); Object.defineProperty(TerminalWidget.prototype, "popOnBell", { /** * Get whether to focus on a bell event. */ get: function () { return this._term.popOnBell; }, /** * Set whether to focus on a bell event. */ set: function (value) { this._term.popOnBell = value; }, enumerable: true, configurable: true }); Object.defineProperty(TerminalWidget.prototype, "scrollback", { /** * Get the size of the scrollback buffer in the terminal. */ get: function () { return this._term.scrollback; }, /** * Set the size of the scrollback buffer in the terminal. */ set: function (value) { this._term.scrollback = value; }, enumerable: true, configurable: true }); /** * Dispose of the resources held by the terminal widget. */ TerminalWidget.prototype.dispose = function () { if (this.isDisposed) { return; } this._session = null; this._sheet = null; this._term = null; this._dummyTerm = null; this._box = null; _super.prototype.dispose.call(this); }; /** * Process a message sent to the widget. * * @param msg - The message sent to the widget. * * #### Notes * Subclasses may reimplement this method as needed. */ TerminalWidget.prototype.processMessage = function (msg) { _super.prototype.processMessage.call(this, msg); switch (msg.type) { case 'fit-request': this.onFitRequest(msg); break; } }; /** * Set the size of the terminal when attached if dirty. */ TerminalWidget.prototype.onAfterAttach = function (msg) { if (this._dirty) { this._snapTermSizing(); } }; /** * Set the size of the terminal when shown if dirty. */ TerminalWidget.prototype.onAfterShow = function (msg) { if (this._dirty) { this._snapTermSizing(); } this._term.focus(); }; /** * Dispose of the terminal when closing. */ TerminalWidget.prototype.onCloseRequest = function (msg) { _super.prototype.onCloseRequest.call(this, msg); this.dispose(); }; /** * On resize, use the computed row and column sizes to resize the terminal. */ TerminalWidget.prototype.onResize = function (msg) { this._resizeTerminal(msg.width, msg.height); }; /** * A message handler invoked on an `'update-request'` message. */ TerminalWidget.prototype.onUpdateRequest = function (msg) { // Set the fg and bg colors of the terminal and cursor. this.node.style.backgroundColor = this.background; this.node.style.color = this.color; this._term.element.style.backgroundColor = this.background; this._term.element.style.color = this.color; this._sheet.innerHTML = ("#" + this.node.id + " .terminal-cursor {background:\n " + this.color + ";color:" + this.background + ";}"); }; /** * A message handler invoked on an `'fit-request'` message. */ TerminalWidget.prototype.onFitRequest = function (msg) { var resize = phosphor_widget_1.ResizeMessage.UnknownSize; phosphor_messaging_1.sendMessage(this, resize); }; /** * Create the terminal object. */ TerminalWidget.prototype._initializeTerm = function () { var _this = this; this._term.open(this.node); this._term.element.classList.add(TERMINAL_BODY_CLASS); this._term.on('data', function (data) { if (_this._session) { _this._session.send({ type: 'stdin', content: [data] }); } }); this._term.on('title', function (title) { _this.title.text = title; }); }; /** * Handle a message from the terminal session. */ TerminalWidget.prototype._onMessage = function (sender, msg) { switch (msg.type) { case 'stdout': this._term.write(msg.content[0]); break; case 'disconnect': this._term.write('\r\n\r\n[Finished... Term Session]\r\n'); break; } }; /** * Use the dummy terminal to measure the row and column sizes. */ TerminalWidget.prototype._snapTermSizing = function () { if (!this.isVisible) { this._dirty = true; return; } var node = this._dummyTerm; this._term.element.appendChild(node); this._rowHeight = node.offsetHeight / DUMMY_ROWS; this._colWidth = node.offsetWidth / DUMMY_COLS; this._term.element.removeChild(node); this._resizeTerminal(-1, -1); }; /** * Resize the terminal based on the computed geometry. * * The parent offset dimensions should be `-1` if unknown. */ TerminalWidget.prototype._resizeTerminal = function (offsetWidth, offsetHeight) { if (this._rowHeight === -1 || !this.isVisible || !this._session) { this._dirty = true; return; } if (offsetWidth < 0) { offsetWidth = this.node.offsetWidth; } if (offsetHeight < 0) { offsetHeight = this.node.offsetHeight; } var box = this._box || (this._box = phosphor_domutil_1.boxSizing(this.node)); var height = offsetHeight - box.verticalSum; var width = offsetWidth - box.horizontalSum; var rows = Math.floor(height / this._rowHeight) - 1; var cols = Math.floor(width / this._colWidth) - 1; this._term.resize(cols, rows); this._session.send({ type: 'set_size', content: [rows, cols, height, width] }); this._dirty = false; this.update(); }; return TerminalWidget; }(phosphor_widget_1.Widget)); exports.TerminalWidget = TerminalWidget; /** * A namespace for private data. */ var Private; (function (Private) { /** * Get term.js options from ITerminalOptions. */ function getConfig(options) { var config = {}; if (options.cursorBlink !== void 0) { config.cursorBlink = options.cursorBlink; } else { config.cursorBlink = true; } if (options.visualBell !== void 0) { config.visualBell = options.visualBell; } if (options.popOnBell !== void 0) { config.popOnBell = options.popOnBell; } if (options.scrollback !== void 0) { config.scrollback = options.scrollback; } return config; } Private.getConfig = getConfig; /** * Create a dummy terminal element used to measure text size. */ function createDummyTerm() { var node = document.createElement('div'); var rowspan = document.createElement('span'); rowspan.innerHTML = Array(DUMMY_ROWS).join('a<br>'); var colspan = document.createElement('span'); colspan.textContent = Array(DUMMY_COLS + 1).join('a'); node.appendChild(rowspan); node.appendChild(colspan); node.style.visibility = 'hidden'; node.style.position = 'absolute'; node.style.height = 'auto'; node.style.width = 'auto'; node.style['white-space'] = 'nowrap'; return node; } Private.createDummyTerm = createDummyTerm; /** * An incrementing counter for ids. */ Private.id = 0; })(Private || (Private = {}));