+46
-10
@@ -12,11 +12,6 @@ syntax:
|
||||
- "h"
|
||||
regex: "https?:\\/\\/[-a-zA-Z0-9@:%._\\+~#=]{1,256}([-a-zA-Z0-9()@:%_\\+.~#?&=\\/]*)"
|
||||
className: sb-naked-url
|
||||
CommandLink:
|
||||
firstCharacters:
|
||||
- "{"
|
||||
regex: "\\{\\[[^\\]]+\\]\\}"
|
||||
className: sb-command-link
|
||||
NamedAnchor:
|
||||
firstCharacters:
|
||||
- "$"
|
||||
@@ -171,6 +166,8 @@ functions:
|
||||
# Template commands
|
||||
insertTemplateText:
|
||||
path: "./template.ts:insertTemplateText"
|
||||
applyLineReplace:
|
||||
path: ./template.ts:applyLineReplace
|
||||
insertFrontMatter:
|
||||
redirect: insertTemplateText
|
||||
slashCommand:
|
||||
@@ -180,18 +177,57 @@ functions:
|
||||
---
|
||||
|^|
|
||||
---
|
||||
insertTask:
|
||||
redirect: insertTemplateText
|
||||
makeH1:
|
||||
redirect: applyLineReplace
|
||||
slashCommand:
|
||||
name: task
|
||||
description: Insert a task
|
||||
value: "* [ ] |^|"
|
||||
name: h1
|
||||
description: Turn line into h1 header
|
||||
match: "^#*\\s*"
|
||||
replace: "# "
|
||||
makeH2:
|
||||
redirect: applyLineReplace
|
||||
slashCommand:
|
||||
name: h2
|
||||
description: Turn line into h2 header
|
||||
match: "^#*\\s*"
|
||||
replace: "## "
|
||||
makeH3:
|
||||
redirect: applyLineReplace
|
||||
slashCommand:
|
||||
name: h3
|
||||
description: Turn line into h3 header
|
||||
match: "^#*\\s*"
|
||||
replace: "### "
|
||||
makeH4:
|
||||
redirect: applyLineReplace
|
||||
slashCommand:
|
||||
name: h4
|
||||
description: Turn line into h4 header
|
||||
match: "^#*\\s*"
|
||||
replace: "#### "
|
||||
|
||||
newPage:
|
||||
path: ./page.ts:newPageCommand
|
||||
command:
|
||||
name: "Page: New"
|
||||
key: "Alt-Shift-n"
|
||||
|
||||
insertHRTemplate:
|
||||
redirect: insertTemplateText
|
||||
slashCommand:
|
||||
name: hr
|
||||
description: Insert a horizontal rule
|
||||
value: "---"
|
||||
insertTable:
|
||||
redirect: insertTemplateText
|
||||
slashCommand:
|
||||
name: table
|
||||
description: Insert a table
|
||||
boost: -1 # Low boost because it's likely not very commonly used
|
||||
value: |
|
||||
| Header A | Header B |
|
||||
|----------|----------|
|
||||
| Cell A|^| | Cell B |
|
||||
quickNoteCommand:
|
||||
path: ./template.ts:quickNoteCommand
|
||||
command:
|
||||
|
||||
+22
-9
@@ -1,6 +1,11 @@
|
||||
import type { ClickEvent } from "$sb/app_event.ts";
|
||||
import { editor, markdown, system } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import { nodeAtPos, ParseTree } from "$sb/lib/tree.ts";
|
||||
import {
|
||||
addParentPointers,
|
||||
findParentMatching,
|
||||
nodeAtPos,
|
||||
ParseTree,
|
||||
} from "$sb/lib/tree.ts";
|
||||
|
||||
// Checks if the URL contains a protocol, if so keeps it, otherwise assumes an attachment
|
||||
function patchUrl(url: string): string {
|
||||
@@ -17,10 +22,19 @@ async function actionClickOrActionEnter(
|
||||
if (!mdTree) {
|
||||
return;
|
||||
}
|
||||
// console.log("Attempting to navigate based on syntax node", mdTree);
|
||||
const navigationNodeFinder = (t: ParseTree) =>
|
||||
["WikiLink", "Link", "URL", "NakedURL", "Link", "CommandLink"].includes(
|
||||
t.type!,
|
||||
);
|
||||
if (!navigationNodeFinder(mdTree)) {
|
||||
mdTree = findParentMatching(mdTree, navigationNodeFinder);
|
||||
if (!mdTree) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
switch (mdTree.type) {
|
||||
case "WikiLinkPage": {
|
||||
let pageLink = mdTree.children![0].text!;
|
||||
case "WikiLink": {
|
||||
let pageLink = mdTree.children![1]!.children![0].text!;
|
||||
let pos;
|
||||
if (pageLink.includes("@")) {
|
||||
[pageLink, pos] = pageLink.split("@");
|
||||
@@ -47,11 +61,8 @@ async function actionClickOrActionEnter(
|
||||
break;
|
||||
}
|
||||
case "CommandLink": {
|
||||
const command = mdTree
|
||||
.children![0].text!.substring(2, mdTree.children![0].text!.length - 2)
|
||||
.trim();
|
||||
console.log("Got command link", command);
|
||||
await system.invokeCommand(command);
|
||||
const commandName = mdTree.children![1]!.children![0].text!;
|
||||
await system.invokeCommand(commandName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -60,6 +71,7 @@ async function actionClickOrActionEnter(
|
||||
export async function linkNavigate() {
|
||||
const mdTree = await markdown.parseMarkdown(await editor.getText());
|
||||
const newNode = nodeAtPos(mdTree, await editor.getCursor());
|
||||
addParentPointers(mdTree);
|
||||
await actionClickOrActionEnter(newNode);
|
||||
}
|
||||
|
||||
@@ -69,6 +81,7 @@ export async function clickNavigate(event: ClickEvent) {
|
||||
return;
|
||||
}
|
||||
const mdTree = await markdown.parseMarkdown(await editor.getText());
|
||||
addParentPointers(mdTree);
|
||||
const newNode = nodeAtPos(mdTree, event.pos);
|
||||
await actionClickOrActionEnter(newNode, event.ctrlKey || event.metaKey);
|
||||
}
|
||||
|
||||
+36
-5
@@ -92,17 +92,24 @@ export async function linkQueryProvider({
|
||||
|
||||
export async function deletePage() {
|
||||
const pageName = await editor.getCurrentPage();
|
||||
if (
|
||||
!await editor.confirm(`Are you sure you would like to delete ${pageName}?`)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
console.log("Navigating to index page");
|
||||
await editor.navigate("");
|
||||
console.log("Deleting page from space");
|
||||
await space.deletePage(pageName);
|
||||
}
|
||||
|
||||
export async function renamePage() {
|
||||
export async function renamePage(targetName?: string) {
|
||||
console.log("Got a target name", targetName);
|
||||
const oldName = await editor.getCurrentPage();
|
||||
const cursor = await editor.getCursor();
|
||||
console.log("Old name is", oldName);
|
||||
const newName = await editor.prompt(`Rename ${oldName} to:`, oldName);
|
||||
const newName = targetName ||
|
||||
await editor.prompt(`Rename ${oldName} to:`, oldName);
|
||||
if (!newName) {
|
||||
return;
|
||||
}
|
||||
@@ -117,17 +124,25 @@ export async function renamePage() {
|
||||
|
||||
const text = await editor.getText();
|
||||
console.log("Writing new page to space");
|
||||
await space.writePage(newName, text);
|
||||
const newPageMeta = await space.writePage(newName, text);
|
||||
console.log("Navigating to new page");
|
||||
await editor.navigate(newName, cursor, true);
|
||||
console.log("Deleting page from space");
|
||||
await space.deletePage(oldName);
|
||||
|
||||
// Handling the edge case of a changing page name just in casing on a case insensitive FS
|
||||
const oldPageMeta = await space.getPageMeta(oldName);
|
||||
if (oldPageMeta.lastModified !== newPageMeta.lastModified) {
|
||||
// If they're the same, let's assume it's the same file (case insensitive FS) and not delete, otherwise...
|
||||
console.log("Deleting page from space");
|
||||
await space.deletePage(oldName);
|
||||
}
|
||||
|
||||
const pageToUpdateSet = new Set<string>();
|
||||
for (const pageToUpdate of pagesToUpdate) {
|
||||
pageToUpdateSet.add(pageToUpdate.page);
|
||||
}
|
||||
|
||||
let updatedReferences = 0;
|
||||
|
||||
for (const pageToUpdate of pageToUpdateSet) {
|
||||
if (pageToUpdate === oldName) {
|
||||
continue;
|
||||
@@ -146,12 +161,14 @@ export async function renamePage() {
|
||||
const pageName = n.children![0].text!;
|
||||
if (pageName === oldName) {
|
||||
n.children![0].text = newName;
|
||||
updatedReferences++;
|
||||
return n;
|
||||
}
|
||||
// page name with @pos position
|
||||
if (pageName.startsWith(`${oldName}@`)) {
|
||||
const [, pos] = pageName.split("@");
|
||||
n.children![0].text = `${newName}@${pos}`;
|
||||
updatedReferences++;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
@@ -164,6 +181,20 @@ export async function renamePage() {
|
||||
await space.writePage(pageToUpdate, newText);
|
||||
}
|
||||
}
|
||||
await editor.flashNotification(
|
||||
`Renamed page, and updated ${updatedReferences} references`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function newPageCommand() {
|
||||
const allPages = await space.listPages();
|
||||
let pageName = `Untitled`;
|
||||
let i = 1;
|
||||
while (allPages.find((p) => p.name === pageName)) {
|
||||
pageName = `Untitled ${i}`;
|
||||
i++;
|
||||
}
|
||||
await editor.navigate(pageName);
|
||||
}
|
||||
|
||||
type BackLink = {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { extractMeta } from "../directive/data.ts";
|
||||
import { renderToText } from "$sb/lib/tree.ts";
|
||||
import { niceDate } from "$sb/lib/dates.ts";
|
||||
import { readSettings } from "$sb/lib/settings_page.ts";
|
||||
import { regexp } from "https://deno.land/std@0.163.0/encoding/_yaml/type/regexp.ts";
|
||||
|
||||
export async function instantiateTemplateCommand() {
|
||||
const allPages = await space.listPages();
|
||||
@@ -210,3 +211,31 @@ export async function insertTemplateText(cmdDef: any) {
|
||||
await editor.moveCursor(cursorPos + carretPos);
|
||||
}
|
||||
}
|
||||
|
||||
export async function applyLineReplace(cmdDef: any) {
|
||||
const cursorPos = await editor.getCursor();
|
||||
const text = await editor.getText();
|
||||
const matchRegex = new RegExp(cmdDef.match);
|
||||
let startOfLine = cursorPos;
|
||||
while (startOfLine > 0 && text[startOfLine - 1] !== "\n") {
|
||||
startOfLine--;
|
||||
}
|
||||
let currentLine = text.slice(startOfLine, cursorPos);
|
||||
|
||||
const emptyLine = !currentLine;
|
||||
|
||||
currentLine = currentLine.replace(matchRegex, cmdDef.replace);
|
||||
|
||||
await editor.dispatch({
|
||||
changes: {
|
||||
from: startOfLine,
|
||||
to: cursorPos,
|
||||
insert: currentLine,
|
||||
},
|
||||
selection: emptyLine
|
||||
? {
|
||||
anchor: startOfLine + currentLine.length,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -294,10 +294,8 @@ function render(
|
||||
body: "",
|
||||
};
|
||||
case "CommandLink": {
|
||||
const commandText = t.children![0].text!.substring(
|
||||
2,
|
||||
t.children![0].text!.length - 2,
|
||||
);
|
||||
// Child 0 is CommandLinkMark, child 1 is CommandLinkPage
|
||||
const commandText = t.children![1].children![0].text!;
|
||||
|
||||
return {
|
||||
name: "button",
|
||||
|
||||
@@ -91,7 +91,6 @@ export function taskToggle(event: ClickEvent) {
|
||||
export function previewTaskToggle(eventString: string) {
|
||||
const [eventName, pos] = JSON.parse(eventString);
|
||||
if (eventName === "task") {
|
||||
console.log("Gotta toggle a task at", pos);
|
||||
return taskToggleAtPos(+pos);
|
||||
}
|
||||
}
|
||||
@@ -107,9 +106,6 @@ async function toggleTaskMarker(node: ParseTree, moveToPos: number) {
|
||||
to: node.to,
|
||||
insert: changeTo,
|
||||
},
|
||||
selection: {
|
||||
anchor: moveToPos,
|
||||
},
|
||||
});
|
||||
|
||||
const parentWikiLinks = collectNodesMatching(
|
||||
@@ -147,7 +143,6 @@ export async function taskToggleAtPos(pos: number) {
|
||||
addParentPointers(mdTree);
|
||||
|
||||
const node = nodeAtPos(mdTree, pos);
|
||||
// console.log("Got this node", node?.type);
|
||||
if (node && node.type === "TaskMarker") {
|
||||
await toggleTaskMarker(node, pos);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,14 @@ syntax:
|
||||
styles:
|
||||
backgroundColor: "rgba(22,22,22,0.07)"
|
||||
functions:
|
||||
turnIntoTask:
|
||||
redirect: core.applyLineReplace
|
||||
slashCommand:
|
||||
name: task
|
||||
description: Turn into task
|
||||
match: "^(\\s*)[\\-\\*]?\\s*(\\[[ xX]\\])?\\s*"
|
||||
replace: "$1* [ ] "
|
||||
|
||||
indexTasks:
|
||||
path: "./task.ts:indexTasks"
|
||||
events:
|
||||
|
||||
Reference in New Issue
Block a user