Lint: support rich HTML tooltips
LintDiagnostic adds `messageHtml` (rendered into the hover tooltip) and `markClass` (added to the inline range mark)
This commit is contained in:
@@ -1,14 +1,21 @@
|
||||
import { type Diagnostic, linter } from "@codemirror/lint";
|
||||
import { StateEffect } from "@codemirror/state";
|
||||
import type { Client } from "../client.ts";
|
||||
import { parse } from "../markdown_parser/parse_tree.ts";
|
||||
import { extendedMarkdownLanguage } from "../markdown_parser/parser.ts";
|
||||
import type { LintEvent } from "@silverbulletmd/silverbullet/type/client";
|
||||
import type {
|
||||
LintDiagnostic,
|
||||
LintEvent,
|
||||
} from "@silverbulletmd/silverbullet/type/client";
|
||||
|
||||
/** Signals the linter to re-run even when the document hasn't changed. */
|
||||
export const refreshLintEffect = StateEffect.define<null>();
|
||||
|
||||
export function plugLinter(client: Client) {
|
||||
return linter(async (view): Promise<Diagnostic[]> => {
|
||||
const text = view.state.sliceDoc();
|
||||
const tree = parse(extendedMarkdownLanguage, text);
|
||||
const results = (
|
||||
const results: LintDiagnostic[] = (
|
||||
await client.dispatchAppEvent("editor:lint", {
|
||||
name: client.currentName(),
|
||||
pageMeta: client.currentPageMeta(),
|
||||
@@ -16,6 +23,30 @@ export function plugLinter(client: Client) {
|
||||
text,
|
||||
} as LintEvent)
|
||||
).flat();
|
||||
return results;
|
||||
return results.map(toDiagnostic);
|
||||
}, {
|
||||
needsRefresh: (update) =>
|
||||
update.transactions.some((tr) =>
|
||||
tr.effects.some((e) => e.is(refreshLintEffect))
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
function toDiagnostic(d: LintDiagnostic): Diagnostic {
|
||||
const out: Diagnostic = {
|
||||
from: d.from,
|
||||
to: d.to,
|
||||
severity: d.severity,
|
||||
message: d.message,
|
||||
};
|
||||
if (d.markClass) out.markClass = d.markClass;
|
||||
if (d.messageHtml) {
|
||||
const html = d.messageHtml;
|
||||
out.renderMessage = () => {
|
||||
const wrap = document.createElement("div");
|
||||
wrap.innerHTML = html;
|
||||
return wrap;
|
||||
};
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ import type {
|
||||
UploadFile,
|
||||
} from "@silverbulletmd/silverbullet/type/client";
|
||||
import { openSearchPanel } from "@codemirror/search";
|
||||
import { forceLinting } from "@codemirror/lint";
|
||||
import { refreshLintEffect } from "../../codemirror/lint.ts";
|
||||
import {
|
||||
isValidPath,
|
||||
parseToRef,
|
||||
@@ -249,6 +251,15 @@ export function editorSyscalls(client: Client): SysCallMapping {
|
||||
"editor.reloadPage": async () => {
|
||||
await client.reloadEditor();
|
||||
},
|
||||
"editor.forceLint": () => {
|
||||
// `forceLinting` alone is a no-op on unchanged content after the
|
||||
// linter's internal "scheduled" flag has been cleared; the effect
|
||||
// re-arms it via `needsRefresh`.
|
||||
client.editorView.dispatch({
|
||||
effects: refreshLintEffect.of(null),
|
||||
});
|
||||
forceLinting(client.editorView);
|
||||
},
|
||||
"editor.reloadUI": () => {
|
||||
location.reload();
|
||||
},
|
||||
|
||||
@@ -153,6 +153,11 @@ export function reloadPage(): Promise<void> {
|
||||
return syscall("editor.reloadPage");
|
||||
}
|
||||
|
||||
/** Useful when a plug toggles a piece of state that lint subscribers consult. */
|
||||
export function forceLint(): Promise<void> {
|
||||
return syscall("editor.forceLint");
|
||||
}
|
||||
|
||||
/**
|
||||
* Force reloads the browser UI
|
||||
*/
|
||||
|
||||
@@ -54,6 +54,18 @@ export type LintDiagnostic = {
|
||||
to: number;
|
||||
severity: "error" | "warning" | "info" | "hint";
|
||||
message: string;
|
||||
/**
|
||||
* Optional HTML rendered into the hover tooltip for this diagnostic.
|
||||
* When present, takes precedence over `message` for tooltip display.
|
||||
* `message` is still used as a plain-text fallback (e.g. in the lint
|
||||
* panel) and as the diagnostic's accessible label.
|
||||
*/
|
||||
messageHtml?: string;
|
||||
/**
|
||||
* Optional CSS class added to the inline range mark for this diagnostic,
|
||||
* in addition to CodeMirror's default `.cm-lintRange-<severity>` class.
|
||||
*/
|
||||
markClass?: string;
|
||||
};
|
||||
|
||||
export type UploadFile = {
|
||||
|
||||
Reference in New Issue
Block a user