Fixes #539 linter support, now checking YAML formats
parent
aa5bff548d
commit
2aed9e5685
|
@ -12,7 +12,7 @@
|
||||||
"@codemirror/commands": "https://esm.sh/@codemirror/commands@6.2.4?external=@codemirror/state,@codemirror/view&target=es2022",
|
"@codemirror/commands": "https://esm.sh/@codemirror/commands@6.2.4?external=@codemirror/state,@codemirror/view&target=es2022",
|
||||||
"@codemirror/view": "https://esm.sh/@codemirror/view@6.9.0?external=@codemirror/state,@lezer/common&target=es2022",
|
"@codemirror/view": "https://esm.sh/@codemirror/view@6.9.0?external=@codemirror/state,@lezer/common&target=es2022",
|
||||||
"@codemirror/autocomplete": "https://esm.sh/@codemirror/autocomplete@6.7.1?external=@codemirror/state,@codemirror/commands,@lezer/common,@codemirror/view&target=es2022",
|
"@codemirror/autocomplete": "https://esm.sh/@codemirror/autocomplete@6.7.1?external=@codemirror/state,@codemirror/commands,@lezer/common,@codemirror/view&target=es2022",
|
||||||
"@codemirror/lint": "https://esm.sh/@codemirror/lint@6.2.1?external=@codemirror/state,@lezer/common&target=es2022",
|
"@codemirror/lint": "https://esm.sh/@codemirror/lint@6.4.1?external=@codemirror/state,@codemirror/view,@lezer/common&target=es2022",
|
||||||
"@codemirror/lang-css": "https://esm.sh/@codemirror/lang-css@6.2.0?external=@codemirror/language,@codemirror/autocomplete,@codemirror/state,@lezer/lr,@lezer/html&target=es2022",
|
"@codemirror/lang-css": "https://esm.sh/@codemirror/lang-css@6.2.0?external=@codemirror/language,@codemirror/autocomplete,@codemirror/state,@lezer/lr,@lezer/html&target=es2022",
|
||||||
"@codemirror/lang-html": "https://esm.sh/@codemirror/lang-html@6.4.3?external=@codemirror/language,@codemirror/autocomplete,@codemirror/lang-css,@codemirror/state,@lezer/lr,@lezer/html&target=es2022",
|
"@codemirror/lang-html": "https://esm.sh/@codemirror/lang-html@6.4.3?external=@codemirror/language,@codemirror/autocomplete,@codemirror/lang-css,@codemirror/state,@lezer/lr,@lezer/html&target=es2022",
|
||||||
"@codemirror/search": "https://esm.sh/@codemirror/search@6.4.0?external=@codemirror/state,@codemirror/view&target=es2022",
|
"@codemirror/search": "https://esm.sh/@codemirror/search@6.4.0?external=@codemirror/state,@codemirror/view&target=es2022",
|
||||||
|
|
|
@ -7,6 +7,7 @@ export type AppEvent =
|
||||||
| "editor:complete"
|
| "editor:complete"
|
||||||
| "minieditor:complete"
|
| "minieditor:complete"
|
||||||
| "slash:complete"
|
| "slash:complete"
|
||||||
|
| "editor:lint"
|
||||||
| "page:load"
|
| "page:load"
|
||||||
| "editor:init"
|
| "editor:init"
|
||||||
| "editor:pageLoaded" // args: pageName, previousPage, isSynced
|
| "editor:pageLoaded" // args: pageName, previousPage, isSynced
|
||||||
|
|
|
@ -133,3 +133,10 @@ export type CodeWidgetContent = {
|
||||||
markdown?: string;
|
markdown?: string;
|
||||||
script?: string;
|
script?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LintDiagnostic = {
|
||||||
|
from: number;
|
||||||
|
to: number;
|
||||||
|
severity: "error" | "warning" | "info" | "hint";
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
|
@ -174,3 +174,8 @@ functions:
|
||||||
|
|
||||||
renderMentions:
|
renderMentions:
|
||||||
path: "./mentions_ps.ts:renderMentions"
|
path: "./mentions_ps.ts:renderMentions"
|
||||||
|
|
||||||
|
lintYAML:
|
||||||
|
path: lint.ts:lintYAML
|
||||||
|
events:
|
||||||
|
- editor:lint
|
|
@ -0,0 +1,83 @@
|
||||||
|
import { editor, markdown, YAML } from "$sb/syscalls.ts";
|
||||||
|
import { LintDiagnostic } from "$sb/types.ts";
|
||||||
|
import {
|
||||||
|
findNodeOfType,
|
||||||
|
renderToText,
|
||||||
|
traverseTreeAsync,
|
||||||
|
} from "$sb/lib/tree.ts";
|
||||||
|
|
||||||
|
export async function lintYAML(): Promise<LintDiagnostic[]> {
|
||||||
|
const text = await editor.getText();
|
||||||
|
const tree = await markdown.parseMarkdown(text);
|
||||||
|
const diagnostics: LintDiagnostic[] = [];
|
||||||
|
await traverseTreeAsync(tree, async (node) => {
|
||||||
|
if (node.type === "FrontMatterCode") {
|
||||||
|
const lintResult = await lintYaml(
|
||||||
|
renderToText(node),
|
||||||
|
node.from!,
|
||||||
|
);
|
||||||
|
if (lintResult) {
|
||||||
|
diagnostics.push(lintResult);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node.type === "FencedCode") {
|
||||||
|
const codeInfo = findNodeOfType(node, "CodeInfo")!;
|
||||||
|
if (!codeInfo) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const codeLang = codeInfo.children![0].text!;
|
||||||
|
// All known YAML formats
|
||||||
|
if (
|
||||||
|
codeLang === "template" || codeLang === "yaml" ||
|
||||||
|
codeLang.startsWith("#")
|
||||||
|
) {
|
||||||
|
const codeText = findNodeOfType(node, "CodeText");
|
||||||
|
if (!codeText) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const yamlCode = renderToText(codeText);
|
||||||
|
const lintResult = await lintYaml(
|
||||||
|
yamlCode,
|
||||||
|
codeText.from!,
|
||||||
|
);
|
||||||
|
if (lintResult) {
|
||||||
|
diagnostics.push(lintResult);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorRegex = /at line (\d+),? column (\d+)/;
|
||||||
|
|
||||||
|
async function lintYaml(
|
||||||
|
yamlText: string,
|
||||||
|
from: number,
|
||||||
|
): Promise<LintDiagnostic | undefined> {
|
||||||
|
try {
|
||||||
|
await YAML.parse(yamlText);
|
||||||
|
} catch (e) {
|
||||||
|
const errorMatch = errorRegex.exec(e.message);
|
||||||
|
if (errorMatch) {
|
||||||
|
console.log("YAML error", e.message);
|
||||||
|
const line = parseInt(errorMatch[1], 10) - 1;
|
||||||
|
const yamlLines = yamlText.split("\n");
|
||||||
|
let pos = from;
|
||||||
|
for (let i = 0; i < line; i++) {
|
||||||
|
pos += yamlLines[i].length + 1;
|
||||||
|
}
|
||||||
|
const endPos = pos + yamlLines[line]?.length || pos;
|
||||||
|
|
||||||
|
return {
|
||||||
|
from: pos,
|
||||||
|
to: endPos,
|
||||||
|
severity: "error",
|
||||||
|
message: e.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,15 @@
|
||||||
import type { IndexTreeEvent } from "$sb/app_event.ts";
|
import type { IndexTreeEvent } from "$sb/app_event.ts";
|
||||||
import { space } from "$sb/syscalls.ts";
|
import { editor, markdown, space, YAML } from "$sb/syscalls.ts";
|
||||||
|
|
||||||
import type { PageMeta } from "$sb/types.ts";
|
import type { LintDiagnostic, PageMeta } from "$sb/types.ts";
|
||||||
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
||||||
import { extractAttributes } from "$sb/lib/attribute.ts";
|
import { extractAttributes } from "$sb/lib/attribute.ts";
|
||||||
import { indexObjects } from "./api.ts";
|
import { indexObjects } from "./api.ts";
|
||||||
|
import {
|
||||||
|
findNodeOfType,
|
||||||
|
renderToText,
|
||||||
|
traverseTreeAsync,
|
||||||
|
} from "$sb/lib/tree.ts";
|
||||||
|
|
||||||
export async function indexPage({ name, tree }: IndexTreeEvent) {
|
export async function indexPage({ name, tree }: IndexTreeEvent) {
|
||||||
if (name.startsWith("_")) {
|
if (name.startsWith("_")) {
|
||||||
|
@ -22,7 +27,84 @@ export async function indexPage({ name, tree }: IndexTreeEvent) {
|
||||||
pageMeta.tags = [...new Set(["page", ...pageMeta.tags || []])];
|
pageMeta.tags = [...new Set(["page", ...pageMeta.tags || []])];
|
||||||
|
|
||||||
// console.log("Page object", pageObj);
|
// console.log("Page object", pageObj);
|
||||||
|
|
||||||
// console.log("Extracted page meta data", pageMeta);
|
|
||||||
await indexObjects<PageMeta>(name, [pageMeta]);
|
await indexObjects<PageMeta>(name, [pageMeta]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function lintFrontmatter(): Promise<LintDiagnostic[]> {
|
||||||
|
const text = await editor.getText();
|
||||||
|
const tree = await markdown.parseMarkdown(text);
|
||||||
|
const diagnostics: LintDiagnostic[] = [];
|
||||||
|
await traverseTreeAsync(tree, async (node) => {
|
||||||
|
if (node.type === "FrontMatterCode") {
|
||||||
|
const lintResult = await lintYaml(
|
||||||
|
renderToText(node),
|
||||||
|
node.from!,
|
||||||
|
node.to!,
|
||||||
|
);
|
||||||
|
if (lintResult) {
|
||||||
|
diagnostics.push(lintResult);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node.type === "FencedCode") {
|
||||||
|
const codeInfo = findNodeOfType(node, "CodeInfo")!;
|
||||||
|
if (!codeInfo) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const codeLang = codeInfo.children![0].text!;
|
||||||
|
// All known YAML formats
|
||||||
|
if (
|
||||||
|
codeLang === "template" || codeLang === "yaml" ||
|
||||||
|
codeLang.startsWith("#")
|
||||||
|
) {
|
||||||
|
const codeText = findNodeOfType(node, "CodeText");
|
||||||
|
if (!codeText) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const yamlCode = renderToText(codeText);
|
||||||
|
const lintResult = await lintYaml(
|
||||||
|
yamlCode,
|
||||||
|
codeText.from!,
|
||||||
|
codeText.to!,
|
||||||
|
);
|
||||||
|
if (lintResult) {
|
||||||
|
diagnostics.push(lintResult);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorRegex = /at line (\d+),? column (\d+)/;
|
||||||
|
|
||||||
|
async function lintYaml(
|
||||||
|
yamlText: string,
|
||||||
|
from: number,
|
||||||
|
to: number,
|
||||||
|
): Promise<LintDiagnostic | undefined> {
|
||||||
|
try {
|
||||||
|
await YAML.parse(yamlText);
|
||||||
|
} catch (e) {
|
||||||
|
const errorMatch = errorRegex.exec(e.message);
|
||||||
|
if (errorMatch) {
|
||||||
|
console.log("YAML error", e.message);
|
||||||
|
// const line = parseInt(errorMatch[1], 10) - 1;
|
||||||
|
// const yamlLines = yamlText.split("\n");
|
||||||
|
// let pos = posOffset;
|
||||||
|
// for (let i = 0; i < line; i++) {
|
||||||
|
// pos += yamlLines[i].length + 1;
|
||||||
|
// }
|
||||||
|
// const endPos = pos + yamlLines[line].length;
|
||||||
|
|
||||||
|
return {
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
severity: "error",
|
||||||
|
message: e.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class AdmonitionIconWidget extends WidgetType {
|
||||||
toDOM(): HTMLElement {
|
toDOM(): HTMLElement {
|
||||||
const outerDiv = document.createElement("div");
|
const outerDiv = document.createElement("div");
|
||||||
outerDiv.classList.add("sb-admonition-icon");
|
outerDiv.classList.add("sb-admonition-icon");
|
||||||
outerDiv.addEventListener("click", (e) => {
|
outerDiv.addEventListener("click", () => {
|
||||||
this.editorView.dispatch({
|
this.editorView.dispatch({
|
||||||
selection: {
|
selection: {
|
||||||
anchor: this.pos,
|
anchor: this.pos,
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { Diagnostic, linter } from "@codemirror/lint";
|
||||||
|
import type { Client } from "../client.ts";
|
||||||
|
|
||||||
|
export function plugLinter(client: Client) {
|
||||||
|
return linter(async (): Promise<Diagnostic[]> => {
|
||||||
|
const results = (await client.dispatchAppEvent("editor:lint", {
|
||||||
|
name: client.currentPage!,
|
||||||
|
})).flat();
|
||||||
|
return results;
|
||||||
|
});
|
||||||
|
}
|
|
@ -42,22 +42,23 @@ import {
|
||||||
import { TextChange } from "$sb/lib/change.ts";
|
import { TextChange } from "$sb/lib/change.ts";
|
||||||
import { postScriptPlugin } from "./cm_plugins/post_script.ts";
|
import { postScriptPlugin } from "./cm_plugins/post_script.ts";
|
||||||
import { languageFor } from "../common/languages.ts";
|
import { languageFor } from "../common/languages.ts";
|
||||||
|
import { plugLinter } from "./cm_plugins/lint.ts";
|
||||||
|
|
||||||
export function createEditorState(
|
export function createEditorState(
|
||||||
editor: Client,
|
client: Client,
|
||||||
pageName: string,
|
pageName: string,
|
||||||
text: string,
|
text: string,
|
||||||
readOnly: boolean,
|
readOnly: boolean,
|
||||||
): EditorState {
|
): EditorState {
|
||||||
const commandKeyBindings: KeyBinding[] = [];
|
const commandKeyBindings: KeyBinding[] = [];
|
||||||
for (const def of editor.system.commandHook.editorCommands.values()) {
|
for (const def of client.system.commandHook.editorCommands.values()) {
|
||||||
if (def.command.key) {
|
if (def.command.key) {
|
||||||
commandKeyBindings.push({
|
commandKeyBindings.push({
|
||||||
key: def.command.key,
|
key: def.command.key,
|
||||||
mac: def.command.mac,
|
mac: def.command.mac,
|
||||||
run: (): boolean => {
|
run: (): boolean => {
|
||||||
if (def.command.contexts) {
|
if (def.command.contexts) {
|
||||||
const context = editor.getContext();
|
const context = client.getContext();
|
||||||
if (!context || !def.command.contexts.includes(context)) {
|
if (!context || !def.command.contexts.includes(context)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -66,14 +67,14 @@ export function createEditorState(
|
||||||
.then(def.run)
|
.then(def.run)
|
||||||
.catch((e: any) => {
|
.catch((e: any) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
editor.flashNotification(
|
client.flashNotification(
|
||||||
`Error running command: ${e.message}`,
|
`Error running command: ${e.message}`,
|
||||||
"error",
|
"error",
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// Always be focusing the editor after running a command
|
// Always be focusing the editor after running a command
|
||||||
editor.focus();
|
client.focus();
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
@ -82,24 +83,25 @@ export function createEditorState(
|
||||||
}
|
}
|
||||||
let touchCount = 0;
|
let touchCount = 0;
|
||||||
|
|
||||||
const markdownLanguage = buildMarkdown(editor.system.mdExtensions);
|
const markdownLanguage = buildMarkdown(client.system.mdExtensions);
|
||||||
|
|
||||||
return EditorState.create({
|
return EditorState.create({
|
||||||
doc: text,
|
doc: text,
|
||||||
extensions: [
|
extensions: [
|
||||||
// Not using CM theming right now, but some extensions depend on the "dark" thing
|
// Not using CM theming right now, but some extensions depend on the "dark" thing
|
||||||
EditorView.theme({}, {
|
EditorView.theme({}, {
|
||||||
dark: editor.ui.viewState.uiOptions.darkMode,
|
dark: client.ui.viewState.uiOptions.darkMode,
|
||||||
}),
|
}),
|
||||||
// Enable vim mode, or not
|
// Enable vim mode, or not
|
||||||
[
|
[
|
||||||
...editor.ui.viewState.uiOptions.vimMode ? [vim({ status: true })] : [],
|
...client.ui.viewState.uiOptions.vimMode ? [vim({ status: true })] : [],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
...readOnly || editor.ui.viewState.uiOptions.forcedROMode
|
...readOnly || client.ui.viewState.uiOptions.forcedROMode
|
||||||
? [readonlyMode()]
|
? [readonlyMode()]
|
||||||
: [],
|
: [],
|
||||||
],
|
],
|
||||||
|
|
||||||
// The uber markdown mode
|
// The uber markdown mode
|
||||||
markdown({
|
markdown({
|
||||||
base: markdownLanguage,
|
base: markdownLanguage,
|
||||||
|
@ -119,16 +121,16 @@ export function createEditorState(
|
||||||
markdownLanguage.data.of({
|
markdownLanguage.data.of({
|
||||||
closeBrackets: { brackets: ["(", "{", "[", "`"] },
|
closeBrackets: { brackets: ["(", "{", "[", "`"] },
|
||||||
}),
|
}),
|
||||||
syntaxHighlighting(customMarkdownStyle(editor.system.mdExtensions)),
|
syntaxHighlighting(customMarkdownStyle(client.system.mdExtensions)),
|
||||||
autocompletion({
|
autocompletion({
|
||||||
override: [
|
override: [
|
||||||
editor.editorComplete.bind(editor),
|
client.editorComplete.bind(client),
|
||||||
editor.system.slashCommandHook.slashCommandCompleter.bind(
|
client.system.slashCommandHook.slashCommandCompleter.bind(
|
||||||
editor.system.slashCommandHook,
|
client.system.slashCommandHook,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
inlineImagesPlugin(editor),
|
inlineImagesPlugin(client),
|
||||||
highlightSpecialChars(),
|
highlightSpecialChars(),
|
||||||
history(),
|
history(),
|
||||||
drawSelection(),
|
drawSelection(),
|
||||||
|
@ -137,9 +139,12 @@ export function createEditorState(
|
||||||
placeholderText: "…",
|
placeholderText: "…",
|
||||||
}),
|
}),
|
||||||
indentOnInput(),
|
indentOnInput(),
|
||||||
...cleanModePlugins(editor),
|
...cleanModePlugins(client),
|
||||||
EditorView.lineWrapping,
|
EditorView.lineWrapping,
|
||||||
postScriptPlugin(editor),
|
plugLinter(client),
|
||||||
|
// lintGutter(),
|
||||||
|
// gutters(),
|
||||||
|
postScriptPlugin(client),
|
||||||
lineWrapper([
|
lineWrapper([
|
||||||
{ selector: "ATXHeading1", class: "sb-line-h1" },
|
{ selector: "ATXHeading1", class: "sb-line-h1" },
|
||||||
{ selector: "ATXHeading2", class: "sb-line-h2" },
|
{ selector: "ATXHeading2", class: "sb-line-h2" },
|
||||||
|
@ -173,8 +178,8 @@ export function createEditorState(
|
||||||
key: "Ctrl-k",
|
key: "Ctrl-k",
|
||||||
mac: "Cmd-k",
|
mac: "Cmd-k",
|
||||||
run: (): boolean => {
|
run: (): boolean => {
|
||||||
editor.ui.viewDispatch({ type: "start-navigate" });
|
client.ui.viewDispatch({ type: "start-navigate" });
|
||||||
editor.space.updatePageList();
|
client.space.updatePageList();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
@ -183,9 +188,9 @@ export function createEditorState(
|
||||||
key: "Ctrl-/",
|
key: "Ctrl-/",
|
||||||
mac: "Cmd-/",
|
mac: "Cmd-/",
|
||||||
run: (): boolean => {
|
run: (): boolean => {
|
||||||
editor.ui.viewDispatch({
|
client.ui.viewDispatch({
|
||||||
type: "show-palette",
|
type: "show-palette",
|
||||||
context: editor.getContext(),
|
context: client.getContext(),
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
@ -194,9 +199,9 @@ export function createEditorState(
|
||||||
key: "Ctrl-.",
|
key: "Ctrl-.",
|
||||||
mac: "Cmd-.",
|
mac: "Cmd-.",
|
||||||
run: (): boolean => {
|
run: (): boolean => {
|
||||||
editor.ui.viewDispatch({
|
client.ui.viewDispatch({
|
||||||
type: "show-palette",
|
type: "show-palette",
|
||||||
context: editor.getContext(),
|
context: client.getContext(),
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
@ -229,7 +234,7 @@ export function createEditorState(
|
||||||
y: touch.clientY,
|
y: touch.clientY,
|
||||||
})!,
|
})!,
|
||||||
};
|
};
|
||||||
await editor.dispatchAppEvent("page:click", clickEvent);
|
await client.dispatchAppEvent("page:click", clickEvent);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
touchCount = 0;
|
touchCount = 0;
|
||||||
|
@ -257,7 +262,7 @@ export function createEditorState(
|
||||||
if (parentA) {
|
if (parentA) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
await editor.dispatchAppEvent(
|
await client.dispatchAppEvent(
|
||||||
"page:click",
|
"page:click",
|
||||||
potentialClickEvent,
|
potentialClickEvent,
|
||||||
);
|
);
|
||||||
|
@ -270,7 +275,7 @@ export function createEditorState(
|
||||||
// this may not be the case with locations that expand signifcantly based on live preview (such as links), we don't want any accidental clicks
|
// this may not be the case with locations that expand signifcantly based on live preview (such as links), we don't want any accidental clicks
|
||||||
// Fixes #357
|
// Fixes #357
|
||||||
if (distanceX <= view.defaultCharacterWidth) {
|
if (distanceX <= view.defaultCharacterWidth) {
|
||||||
await editor.dispatchAppEvent("page:click", potentialClickEvent);
|
await client.dispatchAppEvent("page:click", potentialClickEvent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -287,16 +292,16 @@ export function createEditorState(
|
||||||
newRange: { from: fromB, to: toB },
|
newRange: { from: fromB, to: toB },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
editor.dispatchAppEvent("editor:pageModified", { changes });
|
client.dispatchAppEvent("editor:pageModified", { changes });
|
||||||
editor.ui.viewDispatch({ type: "page-changed" });
|
client.ui.viewDispatch({ type: "page-changed" });
|
||||||
editor.debouncedUpdateEvent();
|
client.debouncedUpdateEvent();
|
||||||
editor.save().catch((e) => console.error("Error saving", e));
|
client.save().catch((e) => console.error("Error saving", e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
pasteLinkExtension,
|
pasteLinkExtension,
|
||||||
attachmentExtension(editor),
|
attachmentExtension(client),
|
||||||
closeBrackets(),
|
closeBrackets(),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue