alm
Version:
The best IDE for TypeScript
216 lines (215 loc) • 8.27 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
/** Imports */
var commands = require("../../commands/commands");
var React = require("react");
var ReactDOM = require("react-dom");
var utils = require("../../../common/utils");
var events = require("../../../common/events");
var monacoUtils = require("../monacoUtils");
/** Load jumpy css */
require('./jumpy.css');
/**
* Setup key characters used for jumpy points
*/
var lowerCharacters = [];
for (var i = 'a'.charCodeAt(0); i <= 'z'.charCodeAt(0); i++) {
var key = String.fromCharCode(i);
lowerCharacters.push(key);
}
exports.keys = [];
for (var _i = 0, lowerCharacters_1 = lowerCharacters; _i < lowerCharacters_1.length; _i++) {
var c1 = lowerCharacters_1[_i];
for (var _a = 0, lowerCharacters_2 = lowerCharacters; _a < lowerCharacters_2.length; _a++) {
var c2 = lowerCharacters_2[_a];
exports.keys.push(c1 + c2);
}
}
function getWidgetId(wg) {
return "jumpy:" + wg.line + ":" + wg.ch;
}
/** Gets or creates a state */
function getState(editor) {
return editor._jumpyState || (editor._jumpyState = { widgets: [], shown: false, disposible: new events.CompositeDisposible() });
}
exports.getState = getState;
/**
*
* The bulk of the logic
*
*/
function addOverlay(editor) {
clearAnyOverlay(editor);
/** Create the overlays */
var state = createOverlays(editor);
/** A clear overlay function just for this editor 🌹 */
var clearOverlay = function () { return clearAnyOverlay(editor); };
// Subscribe to esc to clear
state.disposible.add(commands.esc.on(clearOverlay));
/** Subscribe to jump */
state.disposible.add(editor.onKeyDown(function (e) {
if (e.keyCode >= monaco.KeyCode.KEY_A && e.keyCode <= monaco.KeyCode.KEY_Z) {
// We always prevent ascii chars as the user might have mistyped some keystroke
e.preventDefault();
e.stopPropagation();
// The character representation
var char = String.fromCharCode(e.browserEvent.which).toLowerCase();
// console.log({char}); // DEBUG
var state_1 = getState(editor);
if (!state_1.key1) {
state_1.key1 = char;
// remove not matched
state_1.widgets.filter(function (wg) { return !wg.keys.startsWith(state_1.key1); }).forEach(function (wg) { return editor.removeContentWidget(wg.monacoWiget); });
// only keep matched
state_1.widgets = state_1.widgets.filter(function (wg) { return wg.keys.startsWith(state_1.key1); });
// remove all if nothing matched
if (state_1.widgets.length == 0) {
clearOverlay();
}
}
else {
var total_1 = state_1.key1 + char;
var matched = state_1.widgets.find(function (wg) { return wg.keys == total_1; });
if (matched) {
var position = { lineNumber: matched.line + 1, column: matched.ch + 1 };
editor.setPosition(position);
// We actually allow them to jump one line before / one line after
// So calling this isn't a bad idea. No-op if the line is in view ;)
editor.revealLine(position.lineNumber);
}
clearOverlay();
}
}
else {
clearOverlay();
}
}));
/** Best to exit on these conditions too */
state.disposible.add(editor.onDidScrollChange(clearOverlay));
state.disposible.add(editor.onDidChangeCursorSelection(clearOverlay));
state.disposible.add(editor.onDidBlurEditor(clearOverlay));
}
/**
* Clears previous overlays if any
*/
function clearAnyOverlay(editor) {
var state = getState(editor);
if (state.shown) {
state.widgets.forEach(function (wg) { return editor.removeContentWidget(wg.monacoWiget); });
state.widgets = [];
state.key1 = null;
state.key2 = null;
state.shown = false;
state.disposible.dispose();
}
}
/**
* Renders the overlays on the editor
*/
function createOverlays(editor) {
// The model
var doc = editor.getModel();
// DEBUG
// console.log(editor);
// window.foo = editor;
// The text in viewport
var range = monacoUtils.getVisibleLines(editor);
var text = doc.getValueInRange(range);
/** What we use to split the text */
var splitRegex = /^[A-Z]?[0-9a-z]+|^[\{\};]+/;
var lineNumbers = [];
for (var i = range.startLineNumber; i <= range.endLineNumber; i++) {
lineNumbers.push(i);
}
// keeps track of the next jump point key we can use
var keysIndex = 0;
var overlayByLines = utils.selectMany(lineNumbers.map(function (lineNumber, i) {
var string = doc.getLineContent(lineNumber);
var pos = 0;
var lineOverlays = [];
while (pos < string.length) {
var matches = splitRegex.exec(string.substr(pos));
if (matches && matches.length) {
var matched = matches[0];
var name_1 = exports.keys[keysIndex++];
var nodeRendered = React.createElement("div", { key: i + ':' + pos, className: "monaco-jumpy", style: {} }, name_1);
var node = document.createElement('div');
ReactDOM.render(nodeRendered, node);
var widget = {
node: node,
line: lineNumber - 1,
ch: pos,
keys: name_1,
// This is setup later
monacoWiget: null,
};
lineOverlays.push(widget);
// we want some minimum space between matches
pos += Math.max(matched.length, 2);
}
else {
pos++;
}
}
return lineOverlays;
}));
// Add to dom + State
overlayByLines.forEach(function (wg) {
wg.monacoWiget = {
allowEditorOverflow: true,
getId: function () { return getWidgetId(wg); },
getDomNode: function () { return wg.node; },
getPosition: function () {
return {
position: { lineNumber: wg.line + 1, column: wg.ch + 1 },
preference: [
monaco.editor.ContentWidgetPositionPreference.ABOVE,
monaco.editor.ContentWidgetPositionPreference.BELOW,
]
};
}
};
editor.addContentWidget(wg.monacoWiget);
});
// Setup state and return
var state = getState(editor);
state.widgets = overlayByLines;
state.shown = true;
state.disposible = new events.CompositeDisposible();
return state;
}
var CommonEditorRegistry = monaco.CommonEditorRegistry;
var EditorAction = monaco.EditorAction;
var KeyMod = monaco.KeyMod;
var KeyCode = monaco.KeyCode;
var EditorContextKeys = monaco.EditorContextKeys;
var JumpyAction = /** @class */ (function (_super) {
__extends(JumpyAction, _super);
function JumpyAction() {
return _super.call(this, {
id: 'editor.action.jumpy',
label: 'Jumpy',
alias: 'Jumpy',
precondition: EditorContextKeys.Focus,
kbOpts: {
kbExpr: EditorContextKeys.TextFocus,
primary: KeyMod.CtrlCmd | KeyCode.Enter
}
}) || this;
}
JumpyAction.prototype.run = function (accessor, editor) {
addOverlay(editor);
};
return JumpyAction;
}(EditorAction));
CommonEditorRegistry.registerEditorAction(new JumpyAction());