jupyterlab-emrys
Version:
A computational environment for Jupyter. Powered by Emrys
262 lines (261 loc) • 8.99 kB
JavaScript
// 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 = {}));