Overleaf - Additional Keymaps

Adds new keybindings to Overleaf

目前为 2023-04-19 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Overleaf - Additional Keymaps
  3. // @namespace https://github.com/BLumbye/overleaf-userscripts
  4. // @version 0.2
  5. // @description Adds new keybindings to Overleaf
  6. // @author Benjamin Lumbye
  7. // @license GPL-3
  8. // @match https://www.overleaf.com/project/*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. 'use strict';
  13.  
  14. (function () {
  15. window.addEventListener('UNSTABLE_editor:extensions', (event) => {
  16. const { CodeMirror, CodeMirrorVim, extensions } = event.detail;
  17.  
  18. // Add CodeMirror keymaps
  19. extensions.push(
  20. CodeMirror.keymap.of([
  21. {
  22. key: 'Ctrl-m',
  23. run(view) {
  24. wrapSelection(CodeMirror, view, '\\texttt{', '}');
  25. return true;
  26. },
  27. },
  28. {
  29. key: 'Alt-e',
  30. run(view) {
  31. escapeSelection(CodeMirror, view);
  32. return true;
  33. },
  34. },
  35. ]),
  36. );
  37.  
  38. // Add other keymaps
  39. window.onkeydown = (event) => {
  40. if (event.key === 'F2') {
  41. const selectedTreeItem = document.querySelector('.selected[role="treeitem"]');
  42. if (selectedTreeItem.contains(document.activeElement)) {
  43. event.preventDefault();
  44. document.querySelector('.toolbar-right > button:has(> .fa-pencil)').click();
  45. }
  46. }
  47. };
  48. });
  49. })();
  50.  
  51. /**
  52. * Puts some text before and after what is currently selected
  53. * @param {*} CodeMirror The CodeMirror instance
  54. * @param {*} view The CodeMirror view
  55. * @param {string} before The text to put before the selection
  56. * @param {string} after The text to put after the selection
  57. */
  58. function wrapSelection(CodeMirror, view, before, after) {
  59. view.dispatch(
  60. view.state.changeByRange((range) => ({
  61. changes: [
  62. { from: range.from, insert: before },
  63. { from: range.to, insert: after },
  64. ],
  65. range: CodeMirror.EditorSelection.range(range.from + before.length, range.to + before.length),
  66. })),
  67. );
  68. }
  69.  
  70. /**
  71. * Escapes the characters # $ % & { } _ ~ ^ \ in the current selection
  72. * @param {*} CodeMirror The CodeMirror instance
  73. * @param {*} view The CodeMirror view
  74. */
  75. function escapeSelection(CodeMirror, view) {
  76. view.dispatch(
  77. view.state.changeByRange((range) => {
  78. const changes = [];
  79. let lengthOfChanges = 0;
  80. const text = view.state.doc.sliceString(range.from, range.to);
  81. console.log(text);
  82.  
  83. // Replace # $ % & { } _ with \# \$ \% \& \{ \} \_
  84. for (const match of text.matchAll(/[#$%&{}_]/g)) {
  85. console.log(match);
  86. changes.push({
  87. from: range.from + match.index,
  88. to: range.from + match.index + match[0].length,
  89. insert: `\\${match[0]}`,
  90. });
  91. lengthOfChanges++;
  92. }
  93.  
  94. // Replace ~ ^ with \~{} \^{}
  95. for (const match of text.matchAll(/[~^]/g)) {
  96. console.log(match);
  97. changes.push({
  98. from: range.from + match.index,
  99. to: range.from + match.index + match[0].length,
  100. insert: `\\${match[0]}{}`,
  101. });
  102. lengthOfChanges += 3;
  103. }
  104.  
  105. // Replace \ with \textbackslash{}
  106. for (const match of text.matchAll(/\\/g)) {
  107. console.log(match);
  108. changes.push({
  109. from: range.from + match.index,
  110. to: range.from + match.index + match[0].length,
  111. insert: `\\textbackslash{}`,
  112. });
  113. lengthOfChanges += 15;
  114. }
  115.  
  116. return {
  117. changes,
  118. range: CodeMirror.EditorSelection.range(range.from, range.to + lengthOfChanges),
  119. };
  120. }),
  121. );
  122. }