index.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import {
  2. EditorView,
  3. highlightSpecialChars,
  4. keymap,
  5. rectangularSelection,
  6. tooltips,
  7. crosshairCursor,
  8. dropCursor,
  9. highlightActiveLineGutter,
  10. } from '@codemirror/view'
  11. import { EditorState, Extension } from '@codemirror/state'
  12. import { foldGutter, indentOnInput } from '@codemirror/language'
  13. import { history, historyKeymap, defaultKeymap } from '@codemirror/commands'
  14. import { lintKeymap } from '@codemirror/lint'
  15. import { language } from './language'
  16. import { lineWrappingIndentation } from './line-wrapping-indentation'
  17. import { theme } from './theme'
  18. import { realtime } from './realtime'
  19. import { cursorPosition } from './cursor-position'
  20. import { scrollPosition } from './scroll-position'
  21. import { annotations } from './annotations'
  22. import { cursorHighlights } from './cursor-highlights'
  23. import { autoComplete } from './auto-complete'
  24. import { editable } from './editable'
  25. import { autoPair } from './auto-pair'
  26. import { phrases } from './phrases'
  27. import { spelling } from './spelling'
  28. import { shortcuts } from './shortcuts'
  29. import { symbolPalette } from './symbol-palette'
  30. import { trackChanges } from './track-changes'
  31. import { search } from './search'
  32. import { filterCharacters } from './filter-characters'
  33. import { keybindings } from './keybindings'
  34. import { bracketMatching, bracketSelection } from './bracket-matching'
  35. import { verticalOverflow } from './vertical-overflow'
  36. import { exceptionLogger } from './exception-logger'
  37. import { thirdPartyExtensions } from './third-party-extensions'
  38. import { lineNumbers } from './line-numbers'
  39. import { highlightActiveLine } from './highlight-active-line'
  40. import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
  41. import { emptyLineFiller } from './empty-line-filler'
  42. import { goToLinePanel } from './go-to-line'
  43. import { parserWatcher } from './wait-for-parser'
  44. import { drawSelection } from './draw-selection'
  45. import { sourceOnly, visual } from './visual/visual'
  46. import { scrollOneLine } from './scroll-one-line'
  47. import { foldingKeymap } from './folding-keymap'
  48. import { inlineBackground } from './inline-background'
  49. import { fontLoad } from './font-load'
  50. import { indentationMarkers } from './indentation-markers'
  51. import { codemirrorDevTools } from '../languages/latex/codemirror-dev-tools'
  52. const ignoredDefaultKeybindings = new Set([
  53. // NOTE: disable "Mod-Enter" as it's used for "Compile"
  54. 'Mod-Enter',
  55. // Disable Alt+Arrow as we have special behaviour on Windows / Linux
  56. 'Alt-ArrowLeft',
  57. 'Alt-ArrowRight',
  58. // This keybinding causes issues on some keyboard layouts where \ is entered
  59. // using AltGr. Windows treats Ctrl-Alt as AltGr, so trying to insert a \
  60. // with Ctrl-Alt would trigger this keybinding, rather than inserting a \
  61. 'Mod-Alt-\\',
  62. ])
  63. const ignoredDefaultMacKeybindings = new Set([
  64. // We replace these with our custom visual-line versions
  65. 'Mod-Backspace',
  66. 'Mod-Delete',
  67. ])
  68. const moduleExtensions: Array<() => Extension> = importOverleafModules(
  69. 'sourceEditorExtensions'
  70. ).map((item: { import: { extension: Extension } }) => item.import.extension)
  71. export const createExtensions = (options: Record<string, any>): Extension[] => [
  72. lineNumbers(),
  73. sourceOnly(
  74. false,
  75. highlightSpecialChars({
  76. addSpecialChars: new RegExp(
  77. // non standard space characters (https://jkorpela.fi/chars/spaces.html)
  78. '[\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u200B\u202F\u205F\u3000\uFEFF]',
  79. /x/.unicode != null ? 'gu' : 'g'
  80. ),
  81. })
  82. ),
  83. history({ newGroupDelay: 250 }),
  84. foldGutter({
  85. openText: '▾',
  86. closedText: '▸',
  87. }),
  88. drawSelection(),
  89. EditorState.allowMultipleSelections.of(true),
  90. EditorView.lineWrapping,
  91. indentOnInput(),
  92. lineWrappingIndentation(options.visual.visual),
  93. indentationMarkers(options.visual.visual),
  94. bracketMatching(),
  95. bracketSelection(),
  96. rectangularSelection(),
  97. crosshairCursor(),
  98. dropCursor(),
  99. tooltips({
  100. parent: document.body,
  101. }),
  102. keymap.of([
  103. ...defaultKeymap.filter(
  104. // We only filter on keys, so if the keybinding doesn't have a key,
  105. // allow it
  106. item => {
  107. if (item.key && ignoredDefaultKeybindings.has(item.key)) {
  108. return false
  109. }
  110. if (item.mac && ignoredDefaultMacKeybindings.has(item.mac)) {
  111. return false
  112. }
  113. return true
  114. }
  115. ),
  116. ...historyKeymap,
  117. ...lintKeymap,
  118. ]),
  119. foldingKeymap(),
  120. goToLinePanel(),
  121. filterCharacters(),
  122. // `autoComplete` needs to be before `keybindings` so that arrow key handling
  123. // in the autocomplete pop-up takes precedence over Vim/Emacs key bindings
  124. autoComplete(options.settings),
  125. // `keybindings` needs to be before `language` so that Vim/Emacs bindings take
  126. // precedence over language-specific keyboard shortcuts
  127. keybindings(),
  128. annotations(), // NOTE: must be before `language`
  129. language(options.currentDoc, options.metadata, options.settings),
  130. theme(options.theme),
  131. realtime(options.currentDoc, options.handleError),
  132. cursorPosition(options.currentDoc),
  133. scrollPosition(options.currentDoc),
  134. cursorHighlights(),
  135. autoPair(options.settings),
  136. editable(),
  137. search(),
  138. phrases(options.phrases),
  139. parserWatcher(),
  140. spelling(options.spelling),
  141. shortcuts(),
  142. symbolPalette(),
  143. emptyLineFiller(), // NOTE: must be before `trackChanges`
  144. trackChanges(options.currentDoc, options.changeManager),
  145. visual(options.currentDoc, options.visual),
  146. verticalOverflow(),
  147. highlightActiveLine(options.visual.visual),
  148. highlightActiveLineGutter(),
  149. scrollOneLine(),
  150. fontLoad(),
  151. inlineBackground(options.visual.visual),
  152. codemirrorDevTools(),
  153. exceptionLogger(),
  154. moduleExtensions.map(extension => extension()),
  155. thirdPartyExtensions(),
  156. ]