UNPKG

jupyterlab-emrys

Version:

A computational environment for Jupyter. Powered by Emrys

262 lines (261 loc) 8.99 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 CodeMirror = require('codemirror'); var widget_1 = require('../../codemirror/widget'); var phosphor_signaling_1 = require('phosphor-signaling'); /** * The key code for the up arrow key. */ var UP_ARROW = 38; /** * The key code for the down arrow key. */ var DOWN_ARROW = 40; /** * The key code for the tab key. */ var TAB = 9; /** * The class name added to cell editor widget nodes. */ var CELL_EDITOR_CLASS = 'jp-CellEditor'; /** * A widget for a cell editor. */ var CellEditorWidget = (function (_super) { __extends(CellEditorWidget, _super); /** * Construct a new cell editor widget. */ function CellEditorWidget(options) { var _this = this; if (options === void 0) { options = {}; } _super.call(this, options); this._model = null; this.addClass(CELL_EDITOR_CLASS); CodeMirror.on(this.editor.getDoc(), 'change', function (instance, change) { _this.onDocChange(instance, change); }); CodeMirror.on(this.editor, 'keydown', function (instance, evt) { _this.onEditorKeydown(instance, evt); }); } Object.defineProperty(CellEditorWidget.prototype, "edgeRequested", { /** * A signal emitted when either the top or bottom edge is requested. */ get: function () { return Private.edgeRequestedSignal.bind(this); }, enumerable: true, configurable: true }); Object.defineProperty(CellEditorWidget.prototype, "textChanged", { /** * A signal emitted when a text change is completed. */ get: function () { return Private.textChangedSignal.bind(this); }, enumerable: true, configurable: true }); Object.defineProperty(CellEditorWidget.prototype, "completionRequested", { /** * A signal emitted when a tab (text) completion is requested. */ get: function () { return Private.completionRequestedSignal.bind(this); }, enumerable: true, configurable: true }); Object.defineProperty(CellEditorWidget.prototype, "model", { /** * The cell model used by the editor. */ get: function () { return this._model; }, set: function (model) { if (!model && !this._model || model === this._model) { return; } var doc = this.editor.getDoc(); // If the model is being replaced, disconnect the old signal handler. if (this._model) { this._model.stateChanged.disconnect(this.onModelStateChanged, this); } if (!model) { doc.setValue(''); this._model = null; return; } this._model = model; doc.setValue(this._model.source || ''); this._model.stateChanged.connect(this.onModelStateChanged, this); }, enumerable: true, configurable: true }); Object.defineProperty(CellEditorWidget.prototype, "lineNumbers", { /** * The line numbers state of the editor. */ get: function () { return this.editor.getOption('lineNumbers'); }, set: function (value) { this.editor.setOption('lineNumbers', value); }, enumerable: true, configurable: true }); /** * Dispose of the resources held by the editor. */ CellEditorWidget.prototype.dispose = function () { this._model = null; _super.prototype.dispose.call(this); }; /** * Get the current cursor position of the editor. */ CellEditorWidget.prototype.getCursorPosition = function () { var doc = this.editor.getDoc(); var position = doc.getCursor(); return doc.indexFromPos(position); }; /** * Set the current cursor position of the editor. */ CellEditorWidget.prototype.setCursorPosition = function (position) { var doc = this.editor.getDoc(); doc.setCursor(doc.posFromIndex(position)); }; /** * Handle changes in the model state. */ CellEditorWidget.prototype.onModelStateChanged = function (model, args) { switch (args.name) { case 'source': var doc = this.editor.getDoc(); if (doc.getValue() !== args.newValue) { doc.setValue(args.newValue); } break; default: break; } }; /** * Handle change events from the document. */ CellEditorWidget.prototype.onDocChange = function (doc, change) { if (change.origin === 'setValue') { return; } var model = this.model; var editor = this.editor; var oldValue = model.source; var newValue = doc.getValue(); if (oldValue === newValue) { return; } model.source = newValue; var cursor = doc.getCursor(); var line = cursor.line; var ch = cursor.ch; var chHeight = editor.defaultTextHeight(); var chWidth = editor.defaultCharWidth(); var coords = editor.charCoords({ line: line, ch: ch }, 'page'); var position = editor.getDoc().indexFromPos({ line: line, ch: ch }); this.textChanged.emit({ line: line, ch: ch, chHeight: chHeight, chWidth: chWidth, coords: coords, position: position, oldValue: oldValue, newValue: newValue }); }; /** * Handle keydown events from the editor. */ CellEditorWidget.prototype.onEditorKeydown = function (editor, event) { var doc = editor.getDoc(); var cursor = doc.getCursor(); var line = cursor.line; var ch = cursor.ch; if (event.keyCode === TAB) { // If the tab is modified, ignore it. if (event.ctrlKey || event.shiftKey || event.altKey || event.metaKey) { return; } return this.onTabEvent(event, ch, line); } if (line === 0 && ch === 0 && event.keyCode === UP_ARROW) { this.edgeRequested.emit('top'); return; } var lastLine = doc.lastLine(); var lastCh = doc.getLineHandle(lastLine).text.length; if (line === lastLine && ch === lastCh && event.keyCode === DOWN_ARROW) { this.edgeRequested.emit('bottom'); return; } }; /** * Handle a tab key press. */ CellEditorWidget.prototype.onTabEvent = function (event, ch, line) { var editor = this.editor; var doc = editor.getDoc(); // If there is a text selection, no completion requests should be emitted. if (doc.getSelection()) { return; } var currentValue = doc.getValue(); var currentLine = currentValue.split('\n')[line]; var chHeight = editor.defaultTextHeight(); var chWidth = editor.defaultCharWidth(); var coords = editor.charCoords({ line: line, ch: ch }, 'page'); var position = editor.getDoc().indexFromPos({ line: line, ch: ch }); // A completion request signal should only be emitted if the current // character or a preceding character is not whitespace. // // Otherwise, the default tab action of creating a tab character should be // allowed to propagate. if (!currentLine.substring(0, ch).match(/\S/)) { return; } event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); var data = { line: line, ch: ch, chHeight: chHeight, chWidth: chWidth, coords: coords, position: position, currentValue: currentValue }; this.completionRequested.emit(data); }; return CellEditorWidget; }(widget_1.CodeMirrorWidget)); exports.CellEditorWidget = CellEditorWidget; /** * A namespace for private data. */ var Private; (function (Private) { /** * A signal emitted when either the top or bottom edge is requested. */ Private.edgeRequestedSignal = new phosphor_signaling_1.Signal(); /** * A signal emitted when a text change is completed. */ Private.textChangedSignal = new phosphor_signaling_1.Signal(); /** * A signal emitted when a tab (text) completion is requested. */ Private.completionRequestedSignal = new phosphor_signaling_1.Signal(); })(Private || (Private = {}));