overleaf/services/web/frontend/js/features/source-editor/extensions/index.ts
Mathias Jakobsen 4b2cc907e2 [cm6] Change Emacs commands to visual-line-mode (#12523)
* [cm6] Change Emacs commands to visual-line-mode
* [cm6] Change line deletion commands to visual line mode

GitOrigin-RevId: 7a4f3d66bec611de410b6c1fbafbfe33b974e37b
2023-04-17 08:05:08 +00:00

155 lines
5.4 KiB
TypeScript

import {
EditorView,
highlightSpecialChars,
keymap,
rectangularSelection,
tooltips,
crosshairCursor,
dropCursor,
highlightActiveLineGutter,
} 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 { language } from './language'
import { lineWrappingIndentation } from './line-wrapping-indentation'
import { theme } from './theme'
import { realtime } from './realtime'
import { cursorPosition } from './cursor-position'
import { scrollPosition } from './scroll-position'
import { annotations } from './annotations'
import { cursorHighlights } from './cursor-highlights'
import { autoComplete } from './auto-complete'
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'
import { filterCharacters } from './filter-characters'
import { keybindings } from './keybindings'
import { bracketMatching, bracketSelection } from './bracket-matching'
import { verticalOverflow } from './vertical-overflow'
import { exceptionLogger } from './exception-logger'
import { thirdPartyExtensions } from './third-party-extensions'
import { lineNumbers } from './line-numbers'
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 { 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',
])
const moduleExtensions: Array<() => Extension> = importOverleafModules(
'sourceEditorExtensions'
).map((item: { import: { extension: Extension } }) => item.import.extension)
export const createExtensions = (options: Record<string, any>): Extension[] => [
lineNumbers(),
highlightSpecialChars(),
history({ newGroupDelay: 250 }),
foldGutter({
openText: '▾',
closedText: '▸',
}),
drawSelection(),
EditorState.allowMultipleSelections.of(true),
EditorView.lineWrapping,
indentOnInput(),
lineWrappingIndentation(options.visual.visual),
indentationMarkers(options.visual.visual),
bracketMatching(),
bracketSelection(),
rectangularSelection(),
crosshairCursor(),
dropCursor(),
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(),
goToLinePanel(),
filterCharacters(),
// `autoComplete` needs to be before `keybindings` so that arrow key handling
// in the autocomplete pop-up takes precedence over Vim/Emacs key bindings
autoComplete(options.settings),
// `keybindings` needs to be before `language` so that Vim/Emacs bindings take
// precedence over language-specific keyboard shortcuts
keybindings(),
annotations(), // NOTE: must be before `language`
language(options.currentDoc, options.metadata, options.settings),
theme(options.theme),
realtime(options.currentDoc, options.handleError),
cursorPosition(options.currentDoc),
scrollPosition(options.currentDoc),
cursorHighlights(),
autoPair(options.settings),
editable(),
search(),
phrases(options.phrases),
parserWatcher(),
spelling(options.spelling),
shortcuts(),
symbolPalette(),
// TODO: re-enable this once incompatibility with @codemirror/view is fixed
// emptyLineFiller(), // NOTE: must be before `trackChanges`
trackChanges(options.currentDoc, options.changeManager),
visual(options.currentDoc, options.visual),
verticalOverflow(),
highlightActiveLine(options.visual.visual),
highlightActiveLineGutter(),
scrollOneLine(),
fontLoad(),
inlineBackground(options.visual.visual),
codemirrorDevTools(),
exceptionLogger(),
moduleExtensions.map(extension => extension()),
thirdPartyExtensions(),
]