stylus/edit/show-keymap-help.js
tophf fdbfb23547
API groups + use executeScript for early injection (#1149)
* parserlib: fast section extraction, tweaks and speedups
* csslint: "simple-not" rule
* csslint: enable and fix "selector-newline" rule
* simplify db: resolve with result
* simplify download()
* remove noCode param as it wastes more time/memory on copying
* styleManager: switch style<->data names to reflect their actual contents
* inline method bodies to avoid indirection and enable better autocomplete/hint/jump support in IDE
* upgrade getEventKeyName to handle mouse clicks
* don't trust location.href as it hides text fragment
* getAllKeys is implemented since Chrome48, FF44
* allow recoverable css errors + async'ify usercss.js
* openManage: unminimize windows
* remove the obsolete Chrome pre-65 workaround
* fix temporal dead zone in apply.js
* ff bug workaround for simple editor window
* consistent window scrolling in scrollToEditor and jumpToPos
* rework waitForSelector and collapsible <details>
* blank paint frame workaround for new Chrome
* extract stuff from edit.js and load on demand
* simplify regexpTester::isShown
* move MozDocMapper to sections-util.js
* extract fitSelectBox()
* initialize router earlier
* use helpPopup.close()
* fix autofocus in popups, follow-up to 5bb1b5ef
* clone objects in prefs.get() + cosmetics
* reuse getAll result for INC
2021-01-01 17:27:58 +03:00

114 lines
3.9 KiB
JavaScript

/* global $$ $create */// dom.js
/* global CodeMirror */
/* global helpPopup */// util.js
/* global prefs */
/* global stringAsRegExp */// toolbox.js
/* global t */// localization.js
'use strict';
/* exported showKeymapHelp */
function showKeymapHelp() {
const keyMap = mergeKeyMaps({}, prefs.get('editor.keyMap'), CodeMirror.defaults.extraKeys);
const keyMapSorted = Object.keys(keyMap)
.map(key => ({key, cmd: keyMap[key]}))
.sort((a, b) => (a.cmd < b.cmd || (a.cmd === b.cmd && a.key < b.key) ? -1 : 1));
const table = t.template.keymapHelp.cloneNode(true);
const tBody = table.tBodies[0];
const row = tBody.rows[0];
const cellA = row.children[0];
const cellB = row.children[1];
tBody.textContent = '';
for (const {key, cmd} of keyMapSorted) {
cellA.textContent = key;
cellB.textContent = cmd;
tBody.appendChild(row.cloneNode(true));
}
helpPopup.show(t('cm_keyMap') + ': ' + prefs.get('editor.keyMap'), table);
const inputs = $$('input', table);
inputs[0].on('keydown', hotkeyHandler);
inputs[1].focus();
table.oninput = filterTable;
function hotkeyHandler(event) {
const keyName = CodeMirror.keyName(event);
if (keyName === 'Esc' ||
keyName === 'Tab' ||
keyName === 'Shift-Tab') {
return;
}
event.preventDefault();
event.stopPropagation();
// normalize order of modifiers,
// for modifier-only keys ('Ctrl-Shift') a dummy main key has to be temporarily added
const keyMap = {};
keyMap[keyName.replace(/(Shift|Ctrl|Alt|Cmd)$/, '$&-dummy')] = '';
const normalizedKey = Object.keys(CodeMirror.normalizeKeyMap(keyMap))[0];
this.value = normalizedKey.replace('-dummy', '');
filterTable(event);
}
function filterTable(event) {
const input = event.target;
const col = input.parentNode.cellIndex;
inputs[1 - col].value = '';
for (const row of tBody.rows) {
const cell = row.children[col];
const text = cell.textContent;
const query = stringAsRegExp(input.value, 'gi');
const test = query.test(text);
row.style.display = input.value && test === false ? 'none' : '';
if (input.value && test) {
cell.textContent = '';
let offset = 0;
text.replace(query, (match, index) => {
if (index > offset) {
cell.appendChild(document.createTextNode(text.substring(offset, index)));
}
cell.appendChild($create('mark', match));
offset = index + match.length;
});
if (offset < text.length) {
cell.appendChild(document.createTextNode(text.substring(offset)));
}
} else {
cell.textContent = text;
}
// clear highlight from the other column
const otherCell = row.children[1 - col];
if (otherCell.children.length) {
const text = otherCell.textContent;
otherCell.textContent = text;
}
}
}
function mergeKeyMaps(merged, ...more) {
more.forEach(keyMap => {
if (typeof keyMap === 'string') {
keyMap = CodeMirror.keyMap[keyMap];
}
Object.keys(keyMap).forEach(key => {
let cmd = keyMap[key];
// filter out '...', 'attach', etc. (hotkeys start with an uppercase letter)
if (!merged[key] && !key.match(/^[a-z]/) && cmd !== '...') {
if (typeof cmd === 'function') {
// for 'emacs' keymap: provide at least something meaningful (hotkeys and the function body)
// for 'vim*' keymaps: almost nothing as it doesn't rely on CM keymap mechanism
cmd = cmd.toString().replace(/^function.*?{[\s\r\n]*([\s\S]+?)[\s\r\n]*}$/, '$1');
merged[key] = cmd.length <= 200 ? cmd : cmd.substr(0, 200) + '...';
} else {
merged[key] = cmd;
}
}
});
if (keyMap.fallthrough) {
merged = mergeKeyMaps(merged, keyMap.fallthrough);
}
});
return merged;
}
}