Fix: support $ref transclusions

This commit is contained in:
Zef Hemel
2026-05-23 17:50:06 +02:00
parent 2b80cf497d
commit 3e064e2ddd
4 changed files with 51 additions and 36 deletions
+39 -1
View File
@@ -31,6 +31,7 @@ import type {
PageMeta,
} from "@silverbulletmd/silverbullet/type/index";
import type { StyleObject } from "../plugs/index/space_style.ts";
import type { ResolveAnchorResult } from "../plugs/index/types.ts";
import { publicVersion } from "../public_version.ts";
import { ClientSystem } from "./client_system.ts";
import {
@@ -759,7 +760,8 @@ export class Client {
let cursorWasVisible = false;
try {
const block = editorView.lineBlockAt(previousSelection.main.head);
const scrollBottom = previousScrollTop + editorView.scrollDOM.clientHeight;
const scrollBottom =
previousScrollTop + editorView.scrollDOM.clientHeight;
cursorWasVisible =
block.bottom > previousScrollTop && block.top < scrollBottom;
} catch {
@@ -910,6 +912,42 @@ export class Client {
async navigate(ref: Ref | null, replaceState = false, newWindow = false) {
ref ??= this.getIndexRef();
// Resolve $-anchor refs into a concrete page + position. The page
// navigator only knows about position/header/linecolumn details, so
// we have to translate here.
if (ref.details?.type === "anchor") {
const anchorName = ref.details.name;
const pageFilter = ref.path
? ref.path.endsWith(".md")
? ref.path.slice(0, -3)
: ref.path
: undefined;
const result: ResolveAnchorResult = await this.clientSystem.localSyscall(
"index.resolveAnchor",
[anchorName, pageFilter],
);
if (!result.ok) {
if (result.reason === "missing") {
this.ui.flashNotification(
`Anchor not found: $${anchorName}`,
"error",
);
} else {
const pages = result.hits.map((h) => h.page).join(", ");
this.ui.flashNotification(
`Duplicate anchor $${anchorName} on pages: ${pages}`,
"error",
);
}
return;
}
ref = {
...ref,
path: `${result.page}.md`,
details: { type: "position", pos: result.range[0] },
};
}
if (newWindow) {
console.log(
"Navigating to new page in new window",
+9 -2
View File
@@ -219,10 +219,12 @@ export function editorSyscalls(client: Client): SysCallMapping {
);
} else if (
ref.details &&
!["position", "linecolumn", "header"].includes(ref.details.type)
!["position", "linecolumn", "header", "anchor"].includes(
ref.details.type,
)
) {
throw new Error(
"ref.details.type has to be 'position', 'linecolumn' or 'header'",
"ref.details.type has to be 'position', 'linecolumn', 'header' or 'anchor'",
);
}
@@ -244,6 +246,11 @@ export function editorSyscalls(client: Client): SysCallMapping {
throw new Error(
"ref.details.line and ref.details.column has to be of type `number`",
);
} else if (
ref.details?.type === "anchor" &&
typeof ref.details.name !== "string"
) {
throw new Error("ref.details.name has to be of type `string`");
}
await client.navigate(ref, replaceState, newWindow);
+2 -33
View File
@@ -1,7 +1,6 @@
import {
config,
editor,
index,
markdown,
space,
} from "@silverbulletmd/silverbullet/syscalls";
@@ -59,34 +58,7 @@ async function actionClickOrActionEnter(
);
}
// Resolve anchor refs ($name) into a concrete page+position before
// delegating to editor.navigate (which doesn't know about anchors).
if (ref.details?.type === "anchor") {
const anchorName = ref.details.name;
const pageFilter = ref.path
? ref.path.endsWith(".md") ? ref.path.slice(0, -3) : ref.path
: undefined;
const result = await index.resolveAnchor(anchorName, pageFilter);
if (!result.ok) {
if (result.reason === "missing") {
return editor.flashNotification(
`Anchor not found: $${anchorName}`,
"error",
);
}
return editor.flashNotification(
`Duplicate anchor $${anchorName} on pages: ${
result.hits.map((h) => h.page).join(", ")
}`,
"error",
);
}
ref.path = `${result.page}.md`;
ref.details = { type: "position", pos: result.range[0] };
return editor.navigate(ref, false, inNewWindow);
}
if (ref.path === "") {
if (ref.path === "" && ref.details?.type !== "anchor") {
ref.path = currentPath;
}
@@ -133,10 +105,7 @@ async function actionClickOrActionEnter(
}
case "Hashtag": {
const hashtag = extractHashtag(mdTree.children![0].text!);
const tagPage = await config.get(
["tags", hashtag, "tagPage"],
null,
);
const tagPage = await config.get(["tags", hashtag, "tagPage"], null);
await editor.navigate(
tagPage ?? `${tagPrefix}${hashtag}`,
false,
+1
View File
@@ -7,6 +7,7 @@ Whenever a commit is pushed to the `main` branch, within ~5 minutes, it will be
* **Important**: Run `Space: Reindex` after upgrading (just once) to this version to make linked mentions and other features work again (this should be automatic, but just in case)
* Fix: forced space reindex handling
* Fix: clicking a wiki link to a page now places the cursor just after the page's frontmatter on first visit (matching fresh-load behavior), instead of at position 0. Pages already visited in the session still restore their previously saved cursor position.
* Fix: `$`-anchor refs now resolve through the index from every navigation path
## 2.8.1
* Fix: cursor and clicks no longer drift by a line or two when working below a tall widget (e.g. arrow-up from a list under a `${query[[…]]}` now advances exactly one line). Some other cursor preservation issues addressed as well.