1
0
silverbullet/plugs/core/attributes.ts
2023-08-01 21:35:19 +02:00

90 lines
2.3 KiB
TypeScript

import { index } from "$sb/silverbullet-syscall/mod.ts";
import type { CompleteEvent } from "$sb/app_event.ts";
export type AttributeContext = "page" | "item" | "task";
type AttributeEntry = {
type: string;
};
function determineType(v: any): string {
const t = typeof v;
if (t === "object") {
if (Array.isArray(v)) {
return "array";
}
}
return t;
}
const attributeKeyPrefix = "attr:";
export async function indexAttributes(
pageName: string,
attributes: Record<string, any>,
context: AttributeContext,
) {
await index.batchSet(
pageName,
Object.entries(attributes).map(([k, v]) => {
return {
key: `${attributeKeyPrefix}${context}:${k}`,
value: {
type: determineType(v),
} as AttributeEntry,
};
}),
);
}
export async function attributeComplete(completeEvent: CompleteEvent) {
const inlineAttributeMatch = /([^\[]|^)\[(\w+)$/.exec(
completeEvent.linePrefix,
);
if (inlineAttributeMatch) {
// console.log("Parents", completeEvent.parentNodes);
let type = "page";
if (completeEvent.parentNodes.includes("Task")) {
type = "task";
} else if (completeEvent.parentNodes.includes("ListItem")) {
type = "item";
}
const allAttributes = await index.queryPrefix(
`${attributeKeyPrefix}${type}:`,
);
return {
from: completeEvent.pos - inlineAttributeMatch[2].length,
options: allAttributes.map((attr) => {
const [_prefix, _context, name] = attr.key.split(":");
return {
label: name,
apply: `${name}: `,
detail: attr.value.type,
type: "attribute",
};
}),
};
}
const attributeMatch = /^(\w+)$/.exec(completeEvent.linePrefix);
if (attributeMatch) {
if (completeEvent.parentNodes.includes("FrontMatterCode")) {
const allAttributes = await index.queryPrefix(
`${attributeKeyPrefix}page:`,
);
return {
from: completeEvent.pos - attributeMatch[1].length,
options: allAttributes.map((attr) => {
const [_prefix, _context, name] = attr.key.split(":");
return {
label: name,
apply: `${name}: `,
detail: attr.value.type,
type: "attribute",
};
}),
};
}
}
return null;
}