mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-03 04:56:44 +01:00
124 lines
3.3 KiB
TypeScript
124 lines
3.3 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { EditorController, EditorModel, EditorView, StringEdit, StringValue, findNodeOffsetById, taskCheckboxRange } from '@vscode/markdown-editor';
|
|
import { autorun } from '@vscode/markdown-editor/observables';
|
|
import mermaid from 'mermaid';
|
|
import 'katex/dist/katex.min.css';
|
|
import '@vscode/markdown-editor/editor.css';
|
|
import '@vscode/markdown-editor/themes/github.css';
|
|
|
|
mermaid.initialize({ startOnLoad: false, theme: 'default' });
|
|
|
|
let mermaidCounter = 0;
|
|
|
|
interface VsCodeApi {
|
|
postMessage(message: unknown): void;
|
|
getState(): unknown;
|
|
setState(state: unknown): void;
|
|
}
|
|
|
|
declare function acquireVsCodeApi(): VsCodeApi;
|
|
|
|
const vscode = acquireVsCodeApi();
|
|
|
|
interface EditorInstance {
|
|
readonly model: EditorModel;
|
|
isUpdatingFromExtension: boolean;
|
|
}
|
|
|
|
function createEditor(
|
|
host: HTMLElement,
|
|
content: string,
|
|
options: { readonly readonly: boolean; readonly onEdit?: (text: string) => void }
|
|
): EditorInstance {
|
|
const model = new EditorModel();
|
|
model.sourceText.set(new StringValue(content), undefined);
|
|
|
|
const instance: EditorInstance = {
|
|
model,
|
|
isUpdatingFromExtension: false,
|
|
};
|
|
|
|
const view = new EditorView(model, {
|
|
classNames: ['github-markdown-theme'],
|
|
onToggleCheckbox(item, newChecked) {
|
|
if (options.readonly) {
|
|
return;
|
|
}
|
|
const doc = model.document.get();
|
|
const itemOffset = findNodeOffsetById(doc, item);
|
|
if (itemOffset === undefined) { return; }
|
|
const range = taskCheckboxRange(item);
|
|
if (!range) { return; }
|
|
model.applyEdit(
|
|
StringEdit.replace(
|
|
range.delta(itemOffset),
|
|
newChecked ? '[x]' : '[ ]'
|
|
)
|
|
);
|
|
},
|
|
renderCustomCodeBlock(language, content) {
|
|
if (language !== 'mermaid') {
|
|
return undefined;
|
|
}
|
|
const div = document.createElement('div');
|
|
div.className = 'md-mermaid';
|
|
const id = `mermaid-${mermaidCounter++}`;
|
|
mermaid
|
|
.render(id, content)
|
|
.then(({ svg }) => {
|
|
div.innerHTML = svg;
|
|
})
|
|
.catch(() => {
|
|
div.textContent = content;
|
|
});
|
|
return div;
|
|
},
|
|
});
|
|
new EditorController(model, view);
|
|
host.appendChild(view.element);
|
|
|
|
if (!options.readonly && options.onEdit) {
|
|
const onEdit = options.onEdit;
|
|
autorun((reader) => {
|
|
const text = reader.readObservable(model.sourceText).value;
|
|
if (!instance.isUpdatingFromExtension) {
|
|
onEdit(text);
|
|
}
|
|
});
|
|
}
|
|
|
|
return instance;
|
|
}
|
|
|
|
let single: EditorInstance | undefined;
|
|
|
|
window.addEventListener('message', (event) => {
|
|
const message = event.data;
|
|
switch (message.type) {
|
|
case 'init': {
|
|
const host = document.getElementById('editor')!;
|
|
single = createEditor(host, message.content, {
|
|
readonly: !!message.readonly,
|
|
onEdit: (text) => vscode.postMessage({ type: 'edit', content: text }),
|
|
});
|
|
break;
|
|
}
|
|
case 'update': {
|
|
const target = single;
|
|
if (!target) {
|
|
return;
|
|
}
|
|
target.isUpdatingFromExtension = true;
|
|
target.model.sourceText.set(new StringValue(message.content), undefined);
|
|
target.isUpdatingFromExtension = false;
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
vscode.postMessage({ type: 'ready' });
|