Attribute indexing and code completion

This commit is contained in:
Zef Hemel
2023-08-01 21:35:19 +02:00
parent 52a28c78a7
commit 701a567c95
10 changed files with 210 additions and 17 deletions
+89
View File
@@ -0,0 +1,89 @@
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;
}
+7 -2
View File
@@ -89,6 +89,11 @@ functions:
events:
- editor:complete
attributeComplete:
path: "./attributes.ts:attributeComplete"
events:
- editor:complete
# Commands
commandComplete:
path: "./command.ts:commandComplete"
@@ -317,7 +322,7 @@ functions:
extractToPageCommand:
path: ./refactor.ts:extractToPageCommand
command:
name: "Extract text to new page"
name: "Page: Extract"
renamePageCommand:
path: "./refactor.ts:renamePageCommand"
command:
@@ -328,7 +333,7 @@ functions:
renamePrefixCommand:
path: "./refactor.ts:renamePrefixCommand"
command:
name: "Refactor: Batch Rename Page Prefix"
name: "Page: Batch Rename Prefix"
# Plug manager
updatePlugsCommand:
+6
View File
@@ -5,6 +5,7 @@ import { collectNodesOfType, ParseTree, renderToText } from "$sb/lib/tree.ts";
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
import { extractAttributes } from "$sb/lib/attribute.ts";
import { rewritePageRefs } from "$sb/lib/resolve.ts";
import { indexAttributes } from "./attributes.ts";
export type Item = {
name: string;
@@ -23,6 +24,8 @@ export async function indexItems({ name, tree }: IndexTreeEvent) {
const coll = collectNodesOfType(tree, "ListItem");
const allAttributes: Record<string, any> = {};
for (const n of coll) {
if (!n.children) {
continue;
@@ -46,8 +49,10 @@ export async function indexItems({ name, tree }: IndexTreeEvent) {
}
// Extract attributes and remove from tree
const extractedAttributes = await extractAttributes(child, true);
for (const [key, value] of Object.entries(extractedAttributes)) {
item[key] = value;
allAttributes[key] = value;
}
textNodes.push(child);
}
@@ -71,6 +76,7 @@ export async function indexItems({ name, tree }: IndexTreeEvent) {
}
// console.log("Found", items, "item(s)");
await index.batchSet(name, items);
await indexAttributes(name, allAttributes, "item");
}
export async function queryProvider({
+3
View File
@@ -5,6 +5,7 @@ import { extractAttributes } from "$sb/lib/attribute.ts";
import { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
import { applyQuery } from "$sb/lib/query.ts";
import { resolvePath } from "$sb/lib/resolve.ts";
import { indexAttributes } from "./attributes.ts";
// Key space:
// l:toPage:pos => {name: pageName, inDirective: true, asTemplate: true}
@@ -41,6 +42,8 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) {
await index.set(name, "meta:", pageMeta);
}
await indexAttributes(name, pageMeta, "page");
let directiveDepth = 0;
traverseTree(tree, (n): boolean => {
if (n.type === "DirectiveStart") {