diff --git a/services/web/frontend/js/features/source-editor/extensions/folding-keymap.ts b/services/web/frontend/js/features/source-editor/extensions/folding-keymap.ts index 76fad5aec0..8bb410339f 100644 --- a/services/web/frontend/js/features/source-editor/extensions/folding-keymap.ts +++ b/services/web/frontend/js/features/source-editor/extensions/folding-keymap.ts @@ -1,19 +1,16 @@ -import { keymap } from '@codemirror/view' import { foldAll, toggleFold, unfoldAll } from '@codemirror/language' -export function foldingKeymap() { - return keymap.of([ - { - key: 'F2', - run: toggleFold, - }, - { - key: 'Alt-Shift-1', - run: foldAll, - }, - { - key: 'Alt-Shift-0', - run: unfoldAll, - }, - ]) -} +export const foldingKeymap = [ + { + key: 'F2', + run: toggleFold, + }, + { + key: 'Alt-Shift-1', + run: foldAll, + }, + { + key: 'Alt-Shift-0', + run: unfoldAll, + }, +] diff --git a/services/web/frontend/js/features/source-editor/extensions/font-load.ts b/services/web/frontend/js/features/source-editor/extensions/font-load.ts index d85269b9f3..df3587b103 100644 --- a/services/web/frontend/js/features/source-editor/extensions/font-load.ts +++ b/services/web/frontend/js/features/source-editor/extensions/font-load.ts @@ -5,7 +5,7 @@ import { updateHasEffect } from '../utils/effects' const fontLoadEffect = StateEffect.define() export const hasFontLoadedEffect = updateHasEffect(fontLoadEffect) -const plugin = ViewPlugin.define(view => { +export const fontLoad = ViewPlugin.define(view => { function listener(this: FontFaceSet, event: FontFaceSetLoadEvent) { view.dispatch({ effects: fontLoadEffect.of(event.fontfaces) }) } @@ -27,7 +27,3 @@ const plugin = ViewPlugin.define(view => { }, } }) - -export function fontLoad() { - return plugin -} diff --git a/services/web/frontend/js/features/source-editor/extensions/index.ts b/services/web/frontend/js/features/source-editor/extensions/index.ts index 2b0bf514fb..f1ec1887f0 100644 --- a/services/web/frontend/js/features/source-editor/extensions/index.ts +++ b/services/web/frontend/js/features/source-editor/extensions/index.ts @@ -1,7 +1,6 @@ import { EditorView, highlightSpecialChars, - keymap, rectangularSelection, tooltips, crosshairCursor, @@ -10,8 +9,7 @@ import { } from '@codemirror/view' import { EditorState, Extension } from '@codemirror/state' import { foldGutter, indentOnInput } from '@codemirror/language' -import { history, historyKeymap, defaultKeymap } from '@codemirror/commands' -import { lintKeymap } from '@codemirror/lint' +import { history } from '@codemirror/commands' import { language } from './language' import { lineWrappingIndentation } from './line-wrapping-indentation' import { theme } from './theme' @@ -25,7 +23,6 @@ import { editable } from './editable' import { autoPair } from './auto-pair' import { phrases } from './phrases' import { spelling } from './spelling' -import { shortcuts } from './shortcuts' import { symbolPalette } from './symbol-palette' import { trackChanges } from './track-changes' import { search } from './search' @@ -40,33 +37,13 @@ import { highlightActiveLine } from './highlight-active-line' import importOverleafModules from '../../../../macros/import-overleaf-module.macro' import { emptyLineFiller } from './empty-line-filler' import { goToLinePanel } from './go-to-line' -import { parserWatcher } from './wait-for-parser' import { drawSelection } from './draw-selection' import { sourceOnly, visual } from './visual/visual' -import { scrollOneLine } from './scroll-one-line' -import { foldingKeymap } from './folding-keymap' import { inlineBackground } from './inline-background' -import { fontLoad } from './font-load' import { indentationMarkers } from './indentation-markers' import { codemirrorDevTools } from '../languages/latex/codemirror-dev-tools' - -const ignoredDefaultKeybindings = new Set([ - // NOTE: disable "Mod-Enter" as it's used for "Compile" - 'Mod-Enter', - // Disable Alt+Arrow as we have special behaviour on Windows / Linux - 'Alt-ArrowLeft', - 'Alt-ArrowRight', - // This keybinding causes issues on some keyboard layouts where \ is entered - // using AltGr. Windows treats Ctrl-Alt as AltGr, so trying to insert a \ - // with Ctrl-Alt would trigger this keybinding, rather than inserting a \ - 'Mod-Alt-\\', -]) - -const ignoredDefaultMacKeybindings = new Set([ - // We replace these with our custom visual-line versions - 'Mod-Backspace', - 'Mod-Delete', -]) +import { keymaps } from './keymaps' +import { shortcuts } from './shortcuts' const moduleExtensions: Array<() => Extension> = importOverleafModules( 'sourceEditorExtensions' @@ -103,24 +80,7 @@ export const createExtensions = (options: Record): Extension[] => [ tooltips({ parent: document.body, }), - keymap.of([ - ...defaultKeymap.filter( - // We only filter on keys, so if the keybinding doesn't have a key, - // allow it - item => { - if (item.key && ignoredDefaultKeybindings.has(item.key)) { - return false - } - if (item.mac && ignoredDefaultMacKeybindings.has(item.mac)) { - return false - } - return true - } - ), - ...historyKeymap, - ...lintKeymap, - ]), - foldingKeymap(), + keymaps, goToLinePanel(), filterCharacters(), @@ -143,9 +103,8 @@ export const createExtensions = (options: Record): Extension[] => [ editable(), search(), phrases(options.phrases), - parserWatcher(), spelling(options.spelling), - shortcuts(), + shortcuts, symbolPalette(), emptyLineFiller(), // NOTE: must be before `trackChanges` trackChanges(options.currentDoc, options.changeManager), @@ -153,8 +112,6 @@ export const createExtensions = (options: Record): Extension[] => [ verticalOverflow(), highlightActiveLine(options.visual.visual), highlightActiveLineGutter(), - scrollOneLine(), - fontLoad(), inlineBackground(options.visual.visual), codemirrorDevTools(), exceptionLogger(), diff --git a/services/web/frontend/js/features/source-editor/extensions/inline-background.ts b/services/web/frontend/js/features/source-editor/extensions/inline-background.ts index ed5f8c7cf7..d95d80ef06 100644 --- a/services/web/frontend/js/features/source-editor/extensions/inline-background.ts +++ b/services/web/frontend/js/features/source-editor/extensions/inline-background.ts @@ -4,7 +4,7 @@ import { themeOptionsChange } from './theme' import { sourceOnly } from './visual/visual' import { round } from 'lodash' import { hasLanguageLoadedEffect } from './language' -import { hasFontLoadedEffect } from './font-load' +import { fontLoad, hasFontLoadedEffect } from './font-load' const themeConf = new Compartment() const changeHalfLeadingAnnotation = Annotation.define() @@ -92,5 +92,5 @@ const plugin = ViewPlugin.define( ) export const inlineBackground = (visual: boolean) => { - return sourceOnly(visual, plugin) + return sourceOnly(visual, [fontLoad, plugin]) } diff --git a/services/web/frontend/js/features/source-editor/extensions/keymaps.ts b/services/web/frontend/js/features/source-editor/extensions/keymaps.ts new file mode 100644 index 0000000000..99431f0f1c --- /dev/null +++ b/services/web/frontend/js/features/source-editor/extensions/keymaps.ts @@ -0,0 +1,45 @@ +import { keymap } from '@codemirror/view' +import { defaultKeymap, historyKeymap } from '@codemirror/commands' +import { lintKeymap } from '@codemirror/lint' +import { scrollOneLineKeymap } from './scroll-one-line' +import { foldingKeymap } from './folding-keymap' + +const ignoredDefaultKeybindings = new Set([ + // NOTE: disable "Mod-Enter" as it's used for "Compile" + 'Mod-Enter', + // Disable Alt+Arrow as we have special behaviour on Windows / Linux + 'Alt-ArrowLeft', + 'Alt-ArrowRight', + // This keybinding causes issues on some keyboard layouts where \ is entered + // using AltGr. Windows treats Ctrl-Alt as AltGr, so trying to insert a \ + // with Ctrl-Alt would trigger this keybinding, rather than inserting a \ + 'Mod-Alt-\\', +]) + +const ignoredDefaultMacKeybindings = new Set([ + // We replace these with our custom visual-line versions + 'Mod-Backspace', + 'Mod-Delete', +]) + +const filteredDefaultKeymap = defaultKeymap.filter( + // We only filter on keys, so if the keybinding doesn't have a key, + // allow it + item => { + if (item.key && ignoredDefaultKeybindings.has(item.key)) { + return false + } + if (item.mac && ignoredDefaultMacKeybindings.has(item.mac)) { + return false + } + return true + } +) + +export const keymaps = keymap.of([ + ...filteredDefaultKeymap, + ...historyKeymap, + ...lintKeymap, + ...foldingKeymap, + ...scrollOneLineKeymap, +]) diff --git a/services/web/frontend/js/features/source-editor/extensions/scroll-one-line.ts b/services/web/frontend/js/features/source-editor/extensions/scroll-one-line.ts index 0dd6fa061b..eb46c48f04 100644 --- a/services/web/frontend/js/features/source-editor/extensions/scroll-one-line.ts +++ b/services/web/frontend/js/features/source-editor/extensions/scroll-one-line.ts @@ -1,4 +1,4 @@ -import { Command, EditorView, keymap } from '@codemirror/view' +import { Command, EditorView } from '@codemirror/view' function scrollByLine(view: EditorView, lineCount: number) { view.scrollDOM.scrollTop += view.defaultLineHeight * lineCount @@ -18,18 +18,16 @@ const scrollDownOneLine: Command = (view: EditorView) => { return true } -export function scrollOneLine() { - // Applied to Windows and Linux only - return keymap.of([ - { - linux: 'Ctrl-ArrowUp', - win: 'Ctrl-ArrowUp', - run: scrollUpOneLine, - }, - { - linux: 'Ctrl-ArrowDown', - win: 'Ctrl-ArrowDown', - run: scrollDownOneLine, - }, - ]) -} +// Applied to Windows and Linux only +export const scrollOneLineKeymap = [ + { + linux: 'Ctrl-ArrowUp', + win: 'Ctrl-ArrowUp', + run: scrollUpOneLine, + }, + { + linux: 'Ctrl-ArrowDown', + win: 'Ctrl-ArrowDown', + run: scrollDownOneLine, + }, +] diff --git a/services/web/frontend/js/features/source-editor/extensions/shortcuts.ts b/services/web/frontend/js/features/source-editor/extensions/shortcuts.ts index 17a0fb59d2..c718f5b925 100644 --- a/services/web/frontend/js/features/source-editor/extensions/shortcuts.ts +++ b/services/web/frontend/js/features/source-editor/extensions/shortcuts.ts @@ -1,4 +1,4 @@ -import { type KeyBinding, keymap } from '@codemirror/view' +import { keymap } from '@codemirror/view' import { Prec } from '@codemirror/state' import { indentMore } from '../commands/indent' import { @@ -24,23 +24,23 @@ import { deleteToVisualLineStart, } from './visual-line-selection' -export const shortcuts = () => { - const toggleReviewPanel = () => { - dispatchEditorEvent('toggle-review-panel') - return true - } +const toggleReviewPanel = () => { + dispatchEditorEvent('toggle-review-panel') + return true +} - const addNewCommentFromKbdShortcut = () => { - dispatchEditorEvent('add-new-comment') - return true - } +const addNewCommentFromKbdShortcut = () => { + dispatchEditorEvent('add-new-comment') + return true +} - const toggleTrackChangesFromKbdShortcut = () => { - dispatchEditorEvent('toggle-track-changes') - return true - } +const toggleTrackChangesFromKbdShortcut = () => { + dispatchEditorEvent('toggle-track-changes') + return true +} - const keyBindings: KeyBinding[] = [ +export const shortcuts = Prec.high( + keymap.of([ { key: 'Tab', run: indentMore, @@ -191,7 +191,5 @@ export const shortcuts = () => { mac: 'Cmd-Delete', run: deleteToVisualLineEnd, }, - ] - - return Prec.high(keymap.of(keyBindings)) -} + ]) +) diff --git a/services/web/frontend/js/features/source-editor/extensions/spelling/index.ts b/services/web/frontend/js/features/source-editor/extensions/spelling/index.ts index 3b068ce4ca..bdbb669e8e 100644 --- a/services/web/frontend/js/features/source-editor/extensions/spelling/index.ts +++ b/services/web/frontend/js/features/source-editor/extensions/spelling/index.ts @@ -15,6 +15,7 @@ import { import { addWordToCache, cacheField, removeWordFromCache } from './cache' import { spellingMenuField } from './context-menu' import { SpellChecker } from './spellchecker' +import { parserWatcher } from '../wait-for-parser' const spellCheckLanguageConf = new Compartment() const spellCheckLanguageFacet = Facet.define() @@ -39,6 +40,7 @@ export const spelling = ({ spellCheckLanguage }: Options) => { borderWidth: '0', }, }), + parserWatcher, spellCheckLanguageConf.of(spellCheckLanguageFacet.of(spellCheckLanguage)), spellCheckField, misspelledWordsField, diff --git a/services/web/frontend/js/features/source-editor/extensions/wait-for-parser.ts b/services/web/frontend/js/features/source-editor/extensions/wait-for-parser.ts index 3fafe04471..96c754edec 100644 --- a/services/web/frontend/js/features/source-editor/extensions/wait-for-parser.ts +++ b/services/web/frontend/js/features/source-editor/extensions/wait-for-parser.ts @@ -14,7 +14,7 @@ type ParserWait = { resolve: () => void } -const plugin = ViewPlugin.fromClass( +export const parserWatcher = ViewPlugin.fromClass( class { waits: ParserWait[] = [] @@ -61,16 +61,12 @@ const plugin = ViewPlugin.fromClass( } ) -export function parserWatcher() { - return plugin -} - // Returns a promise that is resolved as soon as CM6 reports that the parser is // ready, up to a specified offset in the document or the end if none is // specified. CM6 dispatches a transaction after every chunk of parser work // and the view plugin checks after each, so there is minimal delay export function waitForParser(view: EditorView, upTo?: UpTo) { - const pluginInstance = view.plugin(plugin) + const pluginInstance = view.plugin(parserWatcher) if (!pluginInstance) { throw new Error('No parser watcher view plugin found') }