| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- /* 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;
- }
- }
|