[cm6] Consolidate loose extensions (#13086)

GitOrigin-RevId: ff937418be5092b2b5197435e9cd60bc61f41b2c
This commit is contained in:
Alf Eaton 2023-05-16 13:16:14 +01:00 committed by Copybot
parent e7b33415a1
commit 60370d5227
9 changed files with 102 additions and 113 deletions

View file

@ -1,8 +1,6 @@
import { keymap } from '@codemirror/view'
import { foldAll, toggleFold, unfoldAll } from '@codemirror/language' import { foldAll, toggleFold, unfoldAll } from '@codemirror/language'
export function foldingKeymap() { export const foldingKeymap = [
return keymap.of([
{ {
key: 'F2', key: 'F2',
run: toggleFold, run: toggleFold,
@ -15,5 +13,4 @@ export function foldingKeymap() {
key: 'Alt-Shift-0', key: 'Alt-Shift-0',
run: unfoldAll, run: unfoldAll,
}, },
]) ]
}

View file

@ -5,7 +5,7 @@ import { updateHasEffect } from '../utils/effects'
const fontLoadEffect = StateEffect.define<readonly FontFace[]>() const fontLoadEffect = StateEffect.define<readonly FontFace[]>()
export const hasFontLoadedEffect = updateHasEffect(fontLoadEffect) export const hasFontLoadedEffect = updateHasEffect(fontLoadEffect)
const plugin = ViewPlugin.define(view => { export const fontLoad = ViewPlugin.define(view => {
function listener(this: FontFaceSet, event: FontFaceSetLoadEvent) { function listener(this: FontFaceSet, event: FontFaceSetLoadEvent) {
view.dispatch({ effects: fontLoadEffect.of(event.fontfaces) }) view.dispatch({ effects: fontLoadEffect.of(event.fontfaces) })
} }
@ -27,7 +27,3 @@ const plugin = ViewPlugin.define(view => {
}, },
} }
}) })
export function fontLoad() {
return plugin
}

View file

@ -1,7 +1,6 @@
import { import {
EditorView, EditorView,
highlightSpecialChars, highlightSpecialChars,
keymap,
rectangularSelection, rectangularSelection,
tooltips, tooltips,
crosshairCursor, crosshairCursor,
@ -10,8 +9,7 @@ import {
} from '@codemirror/view' } from '@codemirror/view'
import { EditorState, Extension } from '@codemirror/state' import { EditorState, Extension } from '@codemirror/state'
import { foldGutter, indentOnInput } from '@codemirror/language' import { foldGutter, indentOnInput } from '@codemirror/language'
import { history, historyKeymap, defaultKeymap } from '@codemirror/commands' import { history } from '@codemirror/commands'
import { lintKeymap } from '@codemirror/lint'
import { language } from './language' import { language } from './language'
import { lineWrappingIndentation } from './line-wrapping-indentation' import { lineWrappingIndentation } from './line-wrapping-indentation'
import { theme } from './theme' import { theme } from './theme'
@ -25,7 +23,6 @@ import { editable } from './editable'
import { autoPair } from './auto-pair' import { autoPair } from './auto-pair'
import { phrases } from './phrases' import { phrases } from './phrases'
import { spelling } from './spelling' import { spelling } from './spelling'
import { shortcuts } from './shortcuts'
import { symbolPalette } from './symbol-palette' import { symbolPalette } from './symbol-palette'
import { trackChanges } from './track-changes' import { trackChanges } from './track-changes'
import { search } from './search' import { search } from './search'
@ -40,33 +37,13 @@ import { highlightActiveLine } from './highlight-active-line'
import importOverleafModules from '../../../../macros/import-overleaf-module.macro' import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
import { emptyLineFiller } from './empty-line-filler' import { emptyLineFiller } from './empty-line-filler'
import { goToLinePanel } from './go-to-line' import { goToLinePanel } from './go-to-line'
import { parserWatcher } from './wait-for-parser'
import { drawSelection } from './draw-selection' import { drawSelection } from './draw-selection'
import { sourceOnly, visual } from './visual/visual' import { sourceOnly, visual } from './visual/visual'
import { scrollOneLine } from './scroll-one-line'
import { foldingKeymap } from './folding-keymap'
import { inlineBackground } from './inline-background' import { inlineBackground } from './inline-background'
import { fontLoad } from './font-load'
import { indentationMarkers } from './indentation-markers' import { indentationMarkers } from './indentation-markers'
import { codemirrorDevTools } from '../languages/latex/codemirror-dev-tools' import { codemirrorDevTools } from '../languages/latex/codemirror-dev-tools'
import { keymaps } from './keymaps'
const ignoredDefaultKeybindings = new Set([ import { shortcuts } from './shortcuts'
// 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 moduleExtensions: Array<() => Extension> = importOverleafModules( const moduleExtensions: Array<() => Extension> = importOverleafModules(
'sourceEditorExtensions' 'sourceEditorExtensions'
@ -103,24 +80,7 @@ export const createExtensions = (options: Record<string, any>): Extension[] => [
tooltips({ tooltips({
parent: document.body, parent: document.body,
}), }),
keymap.of([ keymaps,
...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(),
goToLinePanel(), goToLinePanel(),
filterCharacters(), filterCharacters(),
@ -143,9 +103,8 @@ export const createExtensions = (options: Record<string, any>): Extension[] => [
editable(), editable(),
search(), search(),
phrases(options.phrases), phrases(options.phrases),
parserWatcher(),
spelling(options.spelling), spelling(options.spelling),
shortcuts(), shortcuts,
symbolPalette(), symbolPalette(),
emptyLineFiller(), // NOTE: must be before `trackChanges` emptyLineFiller(), // NOTE: must be before `trackChanges`
trackChanges(options.currentDoc, options.changeManager), trackChanges(options.currentDoc, options.changeManager),
@ -153,8 +112,6 @@ export const createExtensions = (options: Record<string, any>): Extension[] => [
verticalOverflow(), verticalOverflow(),
highlightActiveLine(options.visual.visual), highlightActiveLine(options.visual.visual),
highlightActiveLineGutter(), highlightActiveLineGutter(),
scrollOneLine(),
fontLoad(),
inlineBackground(options.visual.visual), inlineBackground(options.visual.visual),
codemirrorDevTools(), codemirrorDevTools(),
exceptionLogger(), exceptionLogger(),

View file

@ -4,7 +4,7 @@ import { themeOptionsChange } from './theme'
import { sourceOnly } from './visual/visual' import { sourceOnly } from './visual/visual'
import { round } from 'lodash' import { round } from 'lodash'
import { hasLanguageLoadedEffect } from './language' import { hasLanguageLoadedEffect } from './language'
import { hasFontLoadedEffect } from './font-load' import { fontLoad, hasFontLoadedEffect } from './font-load'
const themeConf = new Compartment() const themeConf = new Compartment()
const changeHalfLeadingAnnotation = Annotation.define<boolean>() const changeHalfLeadingAnnotation = Annotation.define<boolean>()
@ -92,5 +92,5 @@ const plugin = ViewPlugin.define(
) )
export const inlineBackground = (visual: boolean) => { export const inlineBackground = (visual: boolean) => {
return sourceOnly(visual, plugin) return sourceOnly(visual, [fontLoad, plugin])
} }

View file

@ -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,
])

View file

@ -1,4 +1,4 @@
import { Command, EditorView, keymap } from '@codemirror/view' import { Command, EditorView } from '@codemirror/view'
function scrollByLine(view: EditorView, lineCount: number) { function scrollByLine(view: EditorView, lineCount: number) {
view.scrollDOM.scrollTop += view.defaultLineHeight * lineCount view.scrollDOM.scrollTop += view.defaultLineHeight * lineCount
@ -18,9 +18,8 @@ const scrollDownOneLine: Command = (view: EditorView) => {
return true return true
} }
export function scrollOneLine() {
// Applied to Windows and Linux only // Applied to Windows and Linux only
return keymap.of([ export const scrollOneLineKeymap = [
{ {
linux: 'Ctrl-ArrowUp', linux: 'Ctrl-ArrowUp',
win: 'Ctrl-ArrowUp', win: 'Ctrl-ArrowUp',
@ -31,5 +30,4 @@ export function scrollOneLine() {
win: 'Ctrl-ArrowDown', win: 'Ctrl-ArrowDown',
run: scrollDownOneLine, run: scrollDownOneLine,
}, },
]) ]
}

View file

@ -1,4 +1,4 @@
import { type KeyBinding, keymap } from '@codemirror/view' import { keymap } from '@codemirror/view'
import { Prec } from '@codemirror/state' import { Prec } from '@codemirror/state'
import { indentMore } from '../commands/indent' import { indentMore } from '../commands/indent'
import { import {
@ -24,7 +24,6 @@ import {
deleteToVisualLineStart, deleteToVisualLineStart,
} from './visual-line-selection' } from './visual-line-selection'
export const shortcuts = () => {
const toggleReviewPanel = () => { const toggleReviewPanel = () => {
dispatchEditorEvent('toggle-review-panel') dispatchEditorEvent('toggle-review-panel')
return true return true
@ -40,7 +39,8 @@ export const shortcuts = () => {
return true return true
} }
const keyBindings: KeyBinding[] = [ export const shortcuts = Prec.high(
keymap.of([
{ {
key: 'Tab', key: 'Tab',
run: indentMore, run: indentMore,
@ -191,7 +191,5 @@ export const shortcuts = () => {
mac: 'Cmd-Delete', mac: 'Cmd-Delete',
run: deleteToVisualLineEnd, run: deleteToVisualLineEnd,
}, },
] ])
)
return Prec.high(keymap.of(keyBindings))
}

View file

@ -15,6 +15,7 @@ import {
import { addWordToCache, cacheField, removeWordFromCache } from './cache' import { addWordToCache, cacheField, removeWordFromCache } from './cache'
import { spellingMenuField } from './context-menu' import { spellingMenuField } from './context-menu'
import { SpellChecker } from './spellchecker' import { SpellChecker } from './spellchecker'
import { parserWatcher } from '../wait-for-parser'
const spellCheckLanguageConf = new Compartment() const spellCheckLanguageConf = new Compartment()
const spellCheckLanguageFacet = Facet.define<string | undefined>() const spellCheckLanguageFacet = Facet.define<string | undefined>()
@ -39,6 +40,7 @@ export const spelling = ({ spellCheckLanguage }: Options) => {
borderWidth: '0', borderWidth: '0',
}, },
}), }),
parserWatcher,
spellCheckLanguageConf.of(spellCheckLanguageFacet.of(spellCheckLanguage)), spellCheckLanguageConf.of(spellCheckLanguageFacet.of(spellCheckLanguage)),
spellCheckField, spellCheckField,
misspelledWordsField, misspelledWordsField,

View file

@ -14,7 +14,7 @@ type ParserWait = {
resolve: () => void resolve: () => void
} }
const plugin = ViewPlugin.fromClass( export const parserWatcher = ViewPlugin.fromClass(
class { class {
waits: ParserWait[] = [] 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 // 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 // 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 // specified. CM6 dispatches a transaction after every chunk of parser work
// and the view plugin checks after each, so there is minimal delay // and the view plugin checks after each, so there is minimal delay
export function waitForParser(view: EditorView, upTo?: UpTo) { export function waitForParser(view: EditorView, upTo?: UpTo) {
const pluginInstance = view.plugin(plugin) const pluginInstance = view.plugin(parserWatcher)
if (!pluginInstance) { if (!pluginInstance) {
throw new Error('No parser watcher view plugin found') throw new Error('No parser watcher view plugin found')
} }