1
0

Linked mentions improvements and other fixes

This commit is contained in:
Zef Hemel 2023-10-09 20:39:03 +02:00
parent ae3e5f375e
commit 17ba536801
9 changed files with 97 additions and 36 deletions

View File

@ -60,9 +60,15 @@ export class EventHook implements Hook<EventHookT> {
) { ) {
// Only dispatch functions that can run in this environment // Only dispatch functions that can run in this environment
if (await plug.canInvoke(name)) { if (await plug.canInvoke(name)) {
const result = await plug.invoke(name, args); try {
if (result !== undefined) { const result = await plug.invoke(name, args);
responses.push(result); if (result !== undefined) {
responses.push(result);
}
} catch (e: any) {
console.error(
`Error dispatching event ${eventName} to plug ${plug.name}: ${e.message}`,
);
} }
} }
} }

View File

@ -19,7 +19,13 @@ const directiveUpdateQueueName = "directiveUpdateQueue";
export async function updateDirectivesOnPageCommand() { export async function updateDirectivesOnPageCommand() {
// If `arg` is a string, it's triggered automatically via an event, not explicitly via a command // If `arg` is a string, it's triggered automatically via an event, not explicitly via a command
const currentPage = await editor.getCurrentPage(); const currentPage = await editor.getCurrentPage();
const pageMeta = await space.getPageMeta(currentPage); let pageMeta: PageMeta | undefined;
try {
pageMeta = await space.getPageMeta(currentPage);
} catch {
console.info("Page not found, not updating directives");
return;
}
const text = await editor.getText(); const text = await editor.getText();
const tree = await markdown.parseMarkdown(text); const tree = await markdown.parseMarkdown(text);
const metaData = await extractFrontmatter(tree, ["$disableDirectives"]); const metaData = await extractFrontmatter(tree, ["$disableDirectives"]);

View File

@ -77,8 +77,9 @@ export async function indexObjects<T>(
value: obj, value: obj,
}); });
// Index attributes // Index attributes
if (!builtins[tag]) { const builtinAttributes = builtins[tag];
// But only for non-builtin tags if (!builtinAttributes) {
// For non-builtin tags, index all attributes
for ( for (
const [attrName, attrValue] of Object.entries( const [attrName, attrValue] of Object.entries(
obj as Record<string, any>, obj as Record<string, any>,
@ -89,6 +90,20 @@ export async function indexObjects<T>(
} }
allAttributes.set(`${tag}:${attrName}`, determineType(attrValue)); allAttributes.set(`${tag}:${attrName}`, determineType(attrValue));
} }
} else if (tag !== "attribute") {
// For builtin tags, only index custom ones
for (
const [attrName, attrValue] of Object.entries(
obj as Record<string, any>,
)
) {
// console.log("Indexing", tag, attrName, attrValue);
// Skip builtins and internal attributes
if (builtinAttributes[attrName] || attrName.startsWith("$")) {
continue;
}
allAttributes.set(`${tag}:${attrName}`, determineType(attrValue));
}
} }
} }
} }

View File

@ -8,10 +8,12 @@ function processClick(e) {
} }
document.getElementById("link-ul").addEventListener("click", processClick); document.getElementById("link-ul").addEventListener("click", processClick);
document.getElementById("hide-button").addEventListener("click", function () { document.getElementById("hide-button").addEventListener("click", () => {
console.log("HERE") syscall("system.invokeFunction", "index.toggleMentions").catch(console.error);
syscall( });
"system.invokeFunction",
"index.toggleMentions", document.getElementById("reload-button").addEventListener("click", () => {
).catch(console.error); syscall("system.invokeFunction", "index.renderMentions").catch(
console.error,
);
}); });

View File

@ -33,12 +33,25 @@ body {
background-color: rgba(233, 233, 233, 0.5); background-color: rgba(233, 233, 233, 0.5);
} }
#hide-button { #button-bar {
position: absolute; position: absolute;
right: 15px; right: 10px;
top: 15px; top: 10px;
padding: 0 3px;
} }
#button-bar button {
border: none;
background: none;
cursor: pointer;
color: var(--root-color);
}
#edit-button {
margin-left: -10px;
}
li code { li code {
font-size: 80%; font-size: 80%;
color: #a5a4a4; color: #a5a4a4;

View File

@ -1,6 +1,6 @@
import type { CompleteEvent } from "$sb/app_event.ts"; import type { CompleteEvent } from "$sb/app_event.ts";
import { events } from "$sb/syscalls.ts"; import { events } from "$sb/syscalls.ts";
import { queryObjects } from "./api.ts"; import { getObjectByRef, queryObjects } from "./api.ts";
import { ObjectValue, QueryExpression } from "$sb/types.ts"; import { ObjectValue, QueryExpression } from "$sb/types.ts";
import { builtinPseudoPage } from "./builtins.ts"; import { builtinPseudoPage } from "./builtins.ts";
@ -85,18 +85,32 @@ export async function attributeComplete(completeEvent: CompleteEvent) {
} }
const attributeMatch = /^(\w+)$/.exec(completeEvent.linePrefix); const attributeMatch = /^(\w+)$/.exec(completeEvent.linePrefix);
if (attributeMatch) { if (attributeMatch) {
if (completeEvent.parentNodes.includes("FrontMatterCode")) { if (completeEvent.parentNodes.includes("FrontMatter")) {
const completions = (await events.dispatchEvent( const pageMeta = await getObjectByRef(
`attribute:complete:page`, completeEvent.pageName,
{ "page",
source: "page", completeEvent.pageName,
prefix: attributeMatch[1], );
} as AttributeCompleteEvent, let tags = ["page"];
)).flat() as AttributeCompletion[]; if (pageMeta?.tags) {
tags = pageMeta.tags;
}
const completions = (await Promise.all(tags.map((tag) =>
events.dispatchEvent(
`attribute:complete:${tag}`,
{
source: tag,
prefix: attributeMatch[1],
} as AttributeCompleteEvent,
)
))).flat(2) as AttributeCompletion[];
// console.log("Completions", completions);
return { return {
from: completeEvent.pos - attributeMatch[1].length, from: completeEvent.pos - attributeMatch[1].length,
options: attributeCompletionsToCMCompletion( options: attributeCompletionsToCMCompletion(
completions.filter((completion) => !completion.builtin), completions.filter((completion) =>
!completion.builtin
),
), ),
}; };
} }

View File

@ -7,6 +7,7 @@ export const builtinPseudoPage = ":builtin:";
export const builtins: Record<string, Record<string, string>> = { export const builtins: Record<string, Record<string, string>> = {
page: { page: {
ref: "string",
name: "string", name: "string",
lastModified: "date", lastModified: "date",
perm: "rw|ro", perm: "rw|ro",
@ -15,6 +16,7 @@ export const builtins: Record<string, Record<string, string>> = {
tags: "array", tags: "array",
}, },
task: { task: {
ref: "string",
name: "string", name: "string",
done: "boolean", done: "boolean",
page: "string", page: "string",
@ -24,22 +26,26 @@ export const builtins: Record<string, Record<string, string>> = {
tags: "array", tags: "array",
}, },
tag: { tag: {
ref: "string",
name: "string", name: "string",
page: "string", page: "string",
context: "string", context: "string",
}, },
attribute: { attribute: {
ref: "string",
name: "string", name: "string",
attributeType: "string", attributeType: "string",
type: "string", type: "string",
page: "string", page: "string",
}, },
anchor: { anchor: {
ref: "string",
name: "string", name: "string",
page: "string", page: "string",
pos: "number", pos: "number",
}, },
link: { link: {
ref: "string",
name: "string", name: "string",
page: "string", page: "string",
pos: "number", pos: "number",

View File

@ -102,11 +102,6 @@ functions:
events: events:
- attribute:complete:* - attribute:complete:*
# builtinAttributeCompleter:
# path: ./attributes.ts:builtinAttributeCompleter
# events:
# - attribute:complete:*
# Item indexing # Item indexing
indexItem: indexItem:
path: "./item.ts:indexItems" path: "./item.ts:indexItems"
@ -172,3 +167,5 @@ functions:
navigateToMention: navigateToMention:
path: "./mentions_ps.ts:navigate" path: "./mentions_ps.ts:navigate"
renderMentions:
path: "./mentions_ps.ts:renderMentions"

View File

@ -10,8 +10,7 @@ export async function toggleMentions() {
hideMentions = !hideMentions; hideMentions = !hideMentions;
await clientStore.set(hideMentionsKey, hideMentions); await clientStore.set(hideMentionsKey, hideMentions);
if (!hideMentions) { if (!hideMentions) {
const name = await editor.getCurrentPage(); await renderMentions();
await renderMentions(name);
} else { } else {
await editor.hidePanel("ps"); await editor.hidePanel("ps");
} }
@ -22,8 +21,7 @@ export async function updateMentions() {
if (await clientStore.get(hideMentionsKey)) { if (await clientStore.get(hideMentionsKey)) {
return; return;
} }
const name = await editor.getCurrentPage(); await renderMentions();
await renderMentions(name);
} }
// use internal navigation via syscall to prevent reloading the full page. // use internal navigation via syscall to prevent reloading the full page.
@ -39,7 +37,8 @@ function escapeHtml(unsafe: string) {
); );
} }
async function renderMentions(page: string) { export async function renderMentions() {
const page = await editor.getCurrentPage();
const linksResult = await queryObjects<LinkObject>("link", { const linksResult = await queryObjects<LinkObject>("link", {
// Query all links that point to this page, excluding those that are inside directives and self pointers. // Query all links that point to this page, excluding those that are inside directives and self pointers.
filter: ["and", ["!=", ["attr", "page"], ["string", page]], ["and", ["=", [ filter: ["and", ["!=", ["attr", "page"], ["string", page]], ["and", ["=", [
@ -60,7 +59,10 @@ async function renderMentions(page: string) {
` <style>${css}</style> ` <style>${css}</style>
<link rel="stylesheet" href="/.client/main.css" /> <link rel="stylesheet" href="/.client/main.css" />
<div id="sb-main"><div id="sb-editor"><div class="cm-editor"> <div id="sb-main"><div id="sb-editor"><div class="cm-editor">
<button id="hide-button">Hide</button> <div id="button-bar">
<button id="reload-button" title="Reload"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path></svg></button>
<button id="hide-button" title="Hide linked mentions"><svg viewBox="0 0 24 24" width="12" height="12" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" class="css-i6dzq1"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg></button>
</div>
<div class="cm-line sb-line-h2">Linked Mentions</div> <div class="cm-line sb-line-h2">Linked Mentions</div>
<ul id="link-ul"> <ul id="link-ul">
${ ${