mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-18 09:35:20 +02:00
142 lines
4.3 KiB
TypeScript
142 lines
4.3 KiB
TypeScript
/* eslint-disable import/prefer-default-export */
|
|
|
|
// This contains the CodeMirror instance, which needs to be built into a bundle
|
|
// using `npm run buildInjectedJs`. This bundle is then loaded from
|
|
// NoteEditor.tsx into the webview.
|
|
//
|
|
// In general, since this file is harder to debug due to the intermediate built
|
|
// step, it's better to keep it as light as possible - it shoud just be a light
|
|
// wrapper to access CodeMirror functionalities. Anything else should be done
|
|
// from NoteEditor.tsx.
|
|
|
|
import createTheme from './theme';
|
|
import decoratorExtension from './decoratorExtension';
|
|
|
|
import { EditorState } from '@codemirror/state';
|
|
import { markdown } from '@codemirror/lang-markdown';
|
|
import { highlightSelectionMatches, search } from '@codemirror/search';
|
|
import { EditorView, drawSelection, highlightSpecialChars, ViewUpdate } from '@codemirror/view';
|
|
import { undo, redo, history, undoDepth, redoDepth } from '@codemirror/commands';
|
|
|
|
import { keymap } from '@codemirror/view';
|
|
import { indentOnInput } from '@codemirror/language';
|
|
import { searchKeymap } from '@codemirror/search';
|
|
import { historyKeymap, defaultKeymap } from '@codemirror/commands';
|
|
import { MarkdownMathExtension } from './markdownMathParser';
|
|
import { GFM as GitHubFlavoredMarkdownExtension } from '@lezer/markdown';
|
|
import syntaxHighlightingLanguages from './syntaxHighlightingLanguages';
|
|
|
|
interface CodeMirrorResult {
|
|
editor: EditorView;
|
|
undo: Function;
|
|
redo: Function;
|
|
select(anchor: number, head: number): void;
|
|
scrollSelectionIntoView(): void;
|
|
insertText(text: string): void;
|
|
}
|
|
|
|
function postMessage(name: string, data: any) {
|
|
(window as any).ReactNativeWebView.postMessage(JSON.stringify({
|
|
data,
|
|
name,
|
|
}));
|
|
}
|
|
|
|
function logMessage(...msg: any[]) {
|
|
postMessage('onLog', { value: msg });
|
|
}
|
|
|
|
export function initCodeMirror(parentElement: any, initialText: string, theme: any): CodeMirrorResult {
|
|
logMessage('Initializing CodeMirror...');
|
|
|
|
let schedulePostUndoRedoDepthChangeId_: any = 0;
|
|
function schedulePostUndoRedoDepthChange(editor: EditorView, doItNow: boolean = false) {
|
|
if (schedulePostUndoRedoDepthChangeId_) {
|
|
if (doItNow) {
|
|
clearTimeout(schedulePostUndoRedoDepthChangeId_);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
schedulePostUndoRedoDepthChangeId_ = setTimeout(() => {
|
|
schedulePostUndoRedoDepthChangeId_ = null;
|
|
postMessage('onUndoRedoDepthChange', {
|
|
undoDepth: undoDepth(editor.state),
|
|
redoDepth: redoDepth(editor.state),
|
|
});
|
|
}, doItNow ? 0 : 1000);
|
|
}
|
|
|
|
const editor = new EditorView({
|
|
state: EditorState.create({
|
|
// See https://github.com/codemirror/basic-setup/blob/main/src/codemirror.ts
|
|
// for a sample configuration.
|
|
extensions: [
|
|
markdown({
|
|
extensions: [
|
|
MarkdownMathExtension,
|
|
GitHubFlavoredMarkdownExtension,
|
|
],
|
|
codeLanguages: syntaxHighlightingLanguages,
|
|
}),
|
|
...createTheme(theme),
|
|
history(),
|
|
search(),
|
|
drawSelection(),
|
|
highlightSpecialChars(),
|
|
highlightSelectionMatches(),
|
|
indentOnInput(),
|
|
|
|
decoratorExtension,
|
|
EditorView.lineWrapping,
|
|
EditorView.contentAttributes.of({ autocapitalize: 'sentence' }),
|
|
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
|
if (viewUpdate.docChanged) {
|
|
postMessage('onChange', { value: editor.state.doc.toString() });
|
|
schedulePostUndoRedoDepthChange(editor);
|
|
}
|
|
|
|
if (!viewUpdate.state.selection.eq(viewUpdate.startState.selection)) {
|
|
const mainRange = viewUpdate.state.selection.main;
|
|
const selStart = mainRange.from;
|
|
const selEnd = mainRange.to;
|
|
postMessage('onSelectionChange', { selection: { start: selStart, end: selEnd } });
|
|
}
|
|
}),
|
|
keymap.of([
|
|
...defaultKeymap, ...historyKeymap, ...searchKeymap,
|
|
]),
|
|
],
|
|
doc: initialText,
|
|
}),
|
|
parent: parentElement,
|
|
});
|
|
|
|
return {
|
|
editor,
|
|
undo: () => {
|
|
undo(editor);
|
|
schedulePostUndoRedoDepthChange(editor, true);
|
|
},
|
|
redo: () => {
|
|
redo(editor);
|
|
schedulePostUndoRedoDepthChange(editor, true);
|
|
},
|
|
select: (anchor: number, head: number) => {
|
|
editor.dispatch(editor.state.update({
|
|
selection: { anchor, head },
|
|
scrollIntoView: true,
|
|
}));
|
|
},
|
|
scrollSelectionIntoView: () => {
|
|
editor.dispatch(editor.state.update({
|
|
scrollIntoView: true,
|
|
}));
|
|
},
|
|
insertText: (text: string) => {
|
|
editor.dispatch(editor.state.replaceSelection(text));
|
|
},
|
|
};
|
|
}
|