Change anchor reference syntax
This commit is contained in:
parent
28b0e9f9e9
commit
e0b6fbed3e
@ -6,6 +6,12 @@ export function validatePageName(name: string) {
|
||||
if (name.startsWith(".")) {
|
||||
throw new Error("Page name cannot start with a '.'");
|
||||
}
|
||||
if (name.includes("@")) {
|
||||
throw new Error("Page name cannot contain '@'");
|
||||
}
|
||||
if (name.includes("$")) {
|
||||
throw new Error("Page name cannot contain '$'");
|
||||
}
|
||||
if (/\.[a-zA-Z]+$/.test(name)) {
|
||||
throw new Error("Page name can not end with a file extension");
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ export async function brokenLinksCommand() {
|
||||
traverseTree(tree, (tree) => {
|
||||
if (tree.type === "WikiLinkPage") {
|
||||
// Add the prefix in the link text
|
||||
const [pageName] = tree.children![0].text!.split("@");
|
||||
const [pageName] = tree.children![0].text!.split(/[@$]/);
|
||||
if (pageName.startsWith("!")) {
|
||||
return true;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import { cacheFileListing } from "../federation/federation.ts";
|
||||
|
||||
// Completion
|
||||
export async function pageComplete(completeEvent: CompleteEvent) {
|
||||
const match = /\[\[([^\]@:\{}]*)$/.exec(completeEvent.linePrefix);
|
||||
const match = /\[\[([^\]@$:\{}]*)$/.exec(completeEvent.linePrefix);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
@ -41,8 +41,8 @@ async function actionClickOrActionEnter(
|
||||
case "WikiLink": {
|
||||
let pageLink = mdTree.children![1]!.children![0].text!;
|
||||
let pos;
|
||||
if (pageLink.includes("@")) {
|
||||
[pageLink, pos] = pageLink.split("@");
|
||||
if (pageLink.includes("@") || pageLink.includes("$")) {
|
||||
[pageLink, pos] = pageLink.split(/[@$]/);
|
||||
if (pos.match(/^\d+$/)) {
|
||||
pos = +pos;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export async function indexAnchors({ name: pageName, tree }: IndexTreeEvent) {
|
||||
collectNodesOfType(tree, "NamedAnchor").forEach((n) => {
|
||||
const aName = n.children![0].text!.substring(1);
|
||||
anchors.push({
|
||||
ref: `${pageName}@${aName}`,
|
||||
ref: `${pageName}$${aName}`,
|
||||
tags: ["anchor"],
|
||||
name: aName,
|
||||
page: pageName,
|
||||
@ -29,12 +29,14 @@ export async function indexAnchors({ name: pageName, tree }: IndexTreeEvent) {
|
||||
}
|
||||
|
||||
export async function anchorComplete(completeEvent: CompleteEvent) {
|
||||
const match = /\[\[([^\]@:]*@[\w\.\-\/]*)$/.exec(completeEvent.linePrefix);
|
||||
const match = /\[\[([^\]@$:]*[@$][\w\.\-\/]*)$/.exec(
|
||||
completeEvent.linePrefix,
|
||||
);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pageRef = match[1].split("@")[0];
|
||||
const pageRef = match[1].split(/[@$]/)[0];
|
||||
let filter: QueryExpression | undefined = ["=", ["attr", "page"], [
|
||||
"string",
|
||||
pageRef,
|
||||
@ -47,7 +49,7 @@ export async function anchorComplete(completeEvent: CompleteEvent) {
|
||||
return {
|
||||
from: completeEvent.pos - match[1].length,
|
||||
options: allAnchors.map((a) => ({
|
||||
label: a.page === completeEvent.pageName ? `@${a.name}` : a.ref,
|
||||
label: a.page === completeEvent.pageName ? `\$${a.name}` : a.ref,
|
||||
type: "anchor",
|
||||
})),
|
||||
};
|
||||
|
@ -26,7 +26,7 @@ export async function updateMentions() {
|
||||
|
||||
// use internal navigation via syscall to prevent reloading the full page.
|
||||
export async function navigate(ref: string) {
|
||||
const [page, pos] = ref.split("@");
|
||||
const [page, pos] = ref.split(/[@$]/);
|
||||
await editor.navigate(page, +pos);
|
||||
}
|
||||
|
||||
|
@ -103,9 +103,7 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) {
|
||||
const wikiLinkAlias = findNodeOfType(n, "WikiLinkAlias");
|
||||
let toPage = resolvePath(name, wikiLinkPage.children![0].text!);
|
||||
const pos = wikiLinkPage.from!;
|
||||
if (toPage.includes("@")) {
|
||||
toPage = toPage.split("@")[0];
|
||||
}
|
||||
toPage = toPage.split(/[@$]/)[0];
|
||||
const link: LinkObject = {
|
||||
ref: `${name}@${pos}`,
|
||||
tags: ["link"],
|
||||
|
@ -81,7 +81,7 @@ body:active #button-bar {
|
||||
}
|
||||
|
||||
#edit-button,
|
||||
#source-button {
|
||||
#reload-button {
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ export async function markdownContentWidget(
|
||||
const html = renderMarkdownToHtml(mdTree, { smartHardBreak: true });
|
||||
return {
|
||||
html: await wrapHTML(html),
|
||||
script: await prepareJS(markdownText, pageName),
|
||||
script: await prepareJS(pageName, markdownText),
|
||||
// And add back the markdown text so we can render it in a different way if desired
|
||||
markdown: markdownText,
|
||||
};
|
||||
@ -41,8 +41,8 @@ export async function wrapHTML(html: string): Promise<string> {
|
||||
<div id="sb-main"><div id="sb-editor"><div class="cm-editor">
|
||||
<!-- And add an edit 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="source-button" title="Show Markdown source"><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" class="feather feather-code"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg></button>
|
||||
<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="edit-button" title="Edit"><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" class="feather feather-edit"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg></button>
|
||||
</div>
|
||||
<div id="body-content">
|
||||
|
@ -273,7 +273,7 @@ function render(
|
||||
let externalTaskRef = "";
|
||||
collectNodesOfType(t, "WikiLinkPage").forEach((wikilink) => {
|
||||
const ref = wikilink.children![0].text!;
|
||||
if (!externalTaskRef && ref.includes("@")) {
|
||||
if (!externalTaskRef && (ref.includes("@") || ref.includes("$"))) {
|
||||
externalTaskRef = ref;
|
||||
}
|
||||
});
|
||||
|
@ -62,6 +62,7 @@ export async function widget(
|
||||
return system.invokeFunction(
|
||||
"markdown.markdownContentWidget",
|
||||
resultMarkdown,
|
||||
pageName,
|
||||
);
|
||||
} catch (e: any) {
|
||||
return system.invokeFunction(
|
||||
|
@ -55,11 +55,13 @@ export async function widget(
|
||||
return system.invokeFunction(
|
||||
"markdown.markdownContentWidget",
|
||||
rendered,
|
||||
pageName,
|
||||
);
|
||||
} catch (e: any) {
|
||||
return system.invokeFunction(
|
||||
"markdown.markdownContentWidget",
|
||||
`**Error:** ${e.message}`,
|
||||
pageName,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ export class Client {
|
||||
const matchingAnchor = await this.system.system.localSyscall(
|
||||
"index",
|
||||
"system.invokeFunction",
|
||||
["getObjectByRef", pageName, "anchor", `${pageName}@${pos}`],
|
||||
["getObjectByRef", pageName, "anchor", `${pageName}$${pos}`],
|
||||
);
|
||||
|
||||
if (!matchingAnchor) {
|
||||
|
@ -15,7 +15,7 @@ class IFrameWidget extends WidgetType {
|
||||
constructor(
|
||||
readonly from: number,
|
||||
readonly to: number,
|
||||
readonly editor: Client,
|
||||
readonly client: Client,
|
||||
readonly bodyText: string,
|
||||
readonly codeWidgetCallback: CodeWidgetCallback,
|
||||
) {
|
||||
@ -25,20 +25,20 @@ class IFrameWidget extends WidgetType {
|
||||
toDOM(): HTMLElement {
|
||||
const from = this.from;
|
||||
const iframe = createWidgetSandboxIFrame(
|
||||
this.editor,
|
||||
this.client,
|
||||
this.bodyText,
|
||||
this.codeWidgetCallback(this.bodyText, this.editor.currentPage!),
|
||||
this.codeWidgetCallback(this.bodyText, this.client.currentPage!),
|
||||
(message) => {
|
||||
switch (message.type) {
|
||||
case "blur":
|
||||
this.editor.editorView.dispatch({
|
||||
this.client.editorView.dispatch({
|
||||
selection: { anchor: from },
|
||||
});
|
||||
this.editor.focus();
|
||||
this.client.focus();
|
||||
|
||||
break;
|
||||
case "reload":
|
||||
this.codeWidgetCallback(this.bodyText, this.editor.currentPage!)
|
||||
this.codeWidgetCallback(this.bodyText, this.client.currentPage!)
|
||||
.then(
|
||||
(widgetContent: WidgetContent) => {
|
||||
iframe.contentWindow!.postMessage({
|
||||
@ -61,7 +61,7 @@ class IFrameWidget extends WidgetType {
|
||||
}
|
||||
|
||||
get estimatedHeight(): number {
|
||||
const cachedHeight = this.editor.space.getCachedWidgetHeight(this.bodyText);
|
||||
const cachedHeight = this.client.space.getCachedWidgetHeight(this.bodyText);
|
||||
// console.log("Calling estimated height", cachedHeight);
|
||||
return cachedHeight > 0 ? cachedHeight : 150;
|
||||
}
|
||||
|
@ -31,9 +31,7 @@ export function cleanWikiLinkPlugin(editor: Client) {
|
||||
const allPages = editor.space.listPages();
|
||||
let pageExists = !editor.fullSyncCompleted;
|
||||
let cleanPage = page;
|
||||
if (page.includes("@")) {
|
||||
cleanPage = page.split("@")[0];
|
||||
}
|
||||
cleanPage = page.split(/[@$]/)[0];
|
||||
cleanPage = resolvePath(editor.currentPage!, cleanPage);
|
||||
const lowerCasePageName = cleanPage.toLowerCase();
|
||||
for (const pageMeta of allPages) {
|
||||
|
@ -67,7 +67,7 @@ export class PathPageNavigator {
|
||||
decodeURI(): [string, number | string] {
|
||||
const [page, pos] = decodeURI(
|
||||
location.pathname.substring(this.root.length + 1),
|
||||
).split("@");
|
||||
).split(/[@$]/);
|
||||
if (pos) {
|
||||
if (pos.match(/^\d+$/)) {
|
||||
return [page, +pos];
|
||||
|
@ -1 +1,3 @@
|
||||
Anchor represent named locations within a page and are defined using the $anchor syntax. They can then be referenced withing the page using [[@anchor]], or cross-page via [[Anchors@anchor]].
|
||||
Anchor represent named locations within a page and are defined using the $anchor syntax. They can then be referenced withing the page using [[$anchor]], or cross-page via [[Anchors$anchor]].
|
||||
|
||||
The legacy syntax is to use `@` instead of `$` for referencing, which is still supported but deprecated.
|
@ -6,8 +6,10 @@ release.
|
||||
* Many styling fixes and improvements to [[Live Queries]] and [[Live Templates]]
|
||||
* Added a “source” button to [[Live Queries]] and [[Live Templates]] for better debugging (showing you the markdown code rendered by the template so you can more easily detect issues)
|
||||
* [[Live Queries]]:
|
||||
* Support for `render all` where the entire result set is passed to a single template allowing you to e.g. dynamically build up tables, see [[Live Queries@render]] for an example.
|
||||
* Support for `render all` where the entire result set is passed to a single template allowing you to e.g. dynamically build up tables, see [[Live Queries$render]] for an example.
|
||||
* The default generated [[SETTINGS]] page now contains a link to [[SETTINGS]] on silverbullet.md for documentation purposes.
|
||||
* The syntax to reference [[Anchors]] has now changed to use `$`, instead of `@` (e.g. [[Live Queries$render]]), the old syntax still works but is deprecated. The reason for this change is consistency: you define an anchor using the `$myanchor` syntax, referencing it the same way makes more sense.
|
||||
* [[Page Name Rules]] are now documented
|
||||
|
||||
---
|
||||
## 0.5.3
|
||||
|
6
website/Page Name Rules.md
Normal file
6
website/Page Name Rules.md
Normal file
@ -0,0 +1,6 @@
|
||||
A few rules regarding page names:
|
||||
|
||||
* Page names cannot be empty
|
||||
* Page names cannot start with a `.`
|
||||
* Page names cannot `@` or `$`, due to ambiguity with referencing specific positions or anchors inside a page
|
||||
* Page names cannot end with a _file extension_ containing just letters. That is, a page name like `test.md` is not allowed, whereas `test.123` would be.
|
@ -7,4 +7,3 @@ Here are the current list of “special pages” known to humankind:
|
||||
* [[SETTINGS]] for setting various settings
|
||||
* [[PLUGS]] as a source for the plug manager to decide what plugs to load and where from
|
||||
* [[VIMRC]] for tweaking [[Vim]] mode
|
||||
* [[STYLES]] to override SilverBullet CSS styles (experimental)
|
Loading…
Reference in New Issue
Block a user