silverbullet/plugs/index/anchor.ts

67 lines
1.8 KiB
TypeScript
Raw Permalink Normal View History

import { collectNodesOfType } from "@silverbulletmd/silverbullet/lib/tree";
2024-05-28 02:33:41 +08:00
import type {
CompleteEvent,
IndexTreeEvent,
ObjectValue,
QueryExpression,
} from "@silverbulletmd/silverbullet/types";
import { indexObjects, queryObjects } from "./api.ts";
import { parsePageRef } from "@silverbulletmd/silverbullet/lib/page_ref";
2022-08-30 16:44:20 +08:00
type AnchorObject = ObjectValue<{
name: string;
page: string;
pos: number;
}>;
2022-08-30 16:44:20 +08:00
export async function indexAnchors({ name: pageName, tree }: IndexTreeEvent) {
const anchors: ObjectValue<AnchorObject>[] = [];
2024-03-15 03:39:38 +08:00
const anchorNames = new Set<string>();
2022-08-30 16:44:20 +08:00
collectNodesOfType(tree, "NamedAnchor").forEach((n) => {
2022-10-25 01:40:52 +08:00
const aName = n.children![0].text!.substring(1);
2024-03-15 03:39:38 +08:00
if (anchorNames.has(aName)) {
console.warn("Duplicate anchor", aName, "in", pageName);
return;
} else {
anchorNames.add(aName);
}
2022-08-30 16:44:20 +08:00
anchors.push({
2023-11-03 19:01:33 +08:00
ref: `${pageName}$${aName}`,
tag: "anchor",
name: aName,
page: pageName,
pos: n.from!,
2022-08-30 16:44:20 +08:00
});
});
// console.log("Found", anchors.length, "anchors(s)");
await indexObjects(pageName, anchors);
2022-08-30 16:44:20 +08:00
}
export async function anchorComplete(completeEvent: CompleteEvent) {
const match = /\[\[([^\]$:]*\$[\w\.\-\/]*)$/.exec(
2023-11-03 19:01:33 +08:00
completeEvent.linePrefix,
);
if (!match) {
2022-08-30 16:44:20 +08:00
return null;
}
const pageRef = parsePageRef(match[1]).page;
2023-11-02 23:19:33 +08:00
let filter: QueryExpression | undefined = ["=", ["attr", "page"], [
"string",
pageRef,
]];
2022-08-30 16:44:20 +08:00
if (!pageRef) {
2023-11-02 23:19:33 +08:00
// "bare" anchor, match any page for completion purposes
filter = undefined;
2022-08-30 16:44:20 +08:00
}
const allAnchors = await queryObjects<AnchorObject>("anchor", { filter }, 5);
2022-08-30 16:44:20 +08:00
return {
2023-11-02 23:19:33 +08:00
from: completeEvent.pos - match[1].length,
2022-08-30 16:44:20 +08:00
options: allAnchors.map((a) => ({
2023-11-03 19:01:33 +08:00
label: a.page === completeEvent.pageName ? `\$${a.name}` : a.ref,
2022-08-30 16:44:20 +08:00
type: "anchor",
})),
};
}