show-keymap-help.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /* global $$ $create */// dom.js
  2. /* global CodeMirror */
  3. /* global helpPopup */// util.js
  4. /* global prefs */
  5. /* global stringAsRegExp */// toolbox.js
  6. /* global t */// localization.js
  7. 'use strict';
  8. /* exported showKeymapHelp */
  9. function showKeymapHelp() {
  10. const keyMap = mergeKeyMaps({}, prefs.get('editor.keyMap'), CodeMirror.defaults.extraKeys);
  11. const keyMapSorted = Object.keys(keyMap)
  12. .map(key => ({key, cmd: keyMap[key]}))
  13. .sort((a, b) => (a.cmd < b.cmd || (a.cmd === b.cmd && a.key < b.key) ? -1 : 1));
  14. const table = t.template.keymapHelp.cloneNode(true);
  15. const tBody = table.tBodies[0];
  16. const row = tBody.rows[0];
  17. const cellA = row.children[0];
  18. const cellB = row.children[1];
  19. tBody.textContent = '';
  20. for (const {key, cmd} of keyMapSorted) {
  21. cellA.textContent = key;
  22. cellB.textContent = cmd;
  23. tBody.appendChild(row.cloneNode(true));
  24. }
  25. helpPopup.show(t('cm_keyMap') + ': ' + prefs.get('editor.keyMap'), table);
  26. const inputs = $$('input', table);
  27. inputs[0].on('keydown', hotkeyHandler);
  28. inputs[1].focus();
  29. table.oninput = filterTable;
  30. function hotkeyHandler(event) {
  31. const keyName = CodeMirror.keyName(event);
  32. if (keyName === 'Esc' ||
  33. keyName === 'Tab' ||
  34. keyName === 'Shift-Tab') {
  35. return;
  36. }
  37. event.preventDefault();
  38. event.stopPropagation();
  39. // normalize order of modifiers,
  40. // for modifier-only keys ('Ctrl-Shift') a dummy main key has to be temporarily added
  41. const keyMap = {};
  42. keyMap[keyName.replace(/(Shift|Ctrl|Alt|Cmd)$/, '$&-dummy')] = '';
  43. const normalizedKey = Object.keys(CodeMirror.normalizeKeyMap(keyMap))[0];
  44. this.value = normalizedKey.replace('-dummy', '');
  45. filterTable(event);
  46. }
  47. function filterTable(event) {
  48. const input = event.target;
  49. const col = input.parentNode.cellIndex;
  50. inputs[1 - col].value = '';
  51. for (const row of tBody.rows) {
  52. const cell = row.children[col];
  53. const text = cell.textContent;
  54. const query = stringAsRegExp(input.value, 'gi');
  55. const test = query.test(text);
  56. row.style.display = input.value && test === false ? 'none' : '';
  57. if (input.value && test) {
  58. cell.textContent = '';
  59. let offset = 0;
  60. text.replace(query, (match, index) => {
  61. if (index > offset) {
  62. cell.appendChild(document.createTextNode(text.substring(offset, index)));
  63. }
  64. cell.appendChild($create('mark', match));
  65. offset = index + match.length;
  66. });
  67. if (offset < text.length) {
  68. cell.appendChild(document.createTextNode(text.substring(offset)));
  69. }
  70. } else {
  71. cell.textContent = text;
  72. }
  73. // clear highlight from the other column
  74. const otherCell = row.children[1 - col];
  75. if (otherCell.children.length) {
  76. const text = otherCell.textContent;
  77. otherCell.textContent = text;
  78. }
  79. }
  80. }
  81. function mergeKeyMaps(merged, ...more) {
  82. more.forEach(keyMap => {
  83. if (typeof keyMap === 'string') {
  84. keyMap = CodeMirror.keyMap[keyMap];
  85. }
  86. Object.keys(keyMap).forEach(key => {
  87. let cmd = keyMap[key];
  88. // filter out '...', 'attach', etc. (hotkeys start with an uppercase letter)
  89. if (!merged[key] && !key.match(/^[a-z]/) && cmd !== '...') {
  90. if (typeof cmd === 'function') {
  91. // for 'emacs' keymap: provide at least something meaningful (hotkeys and the function body)
  92. // for 'vim*' keymaps: almost nothing as it doesn't rely on CM keymap mechanism
  93. cmd = cmd.toString().replace(/^function.*?{[\s\r\n]*([\s\S]+?)[\s\r\n]*}$/, '$1');
  94. merged[key] = cmd.length <= 200 ? cmd : cmd.substr(0, 200) + '...';
  95. } else {
  96. merged[key] = cmd;
  97. }
  98. }
  99. });
  100. if (keyMap.fallthrough) {
  101. merged = mergeKeyMaps(merged, keyMap.fallthrough);
  102. }
  103. });
  104. return merged;
  105. }
  106. }