Template cleanup, autocomplete for more query stuff
This commit is contained in:
parent
e2e7e2f936
commit
60cfefbc95
@ -9,3 +9,4 @@ export const CommentTag = Tag.define();
|
||||
export const CommentMarkerTag = Tag.define();
|
||||
export const BulletList = Tag.define();
|
||||
export const OrderedList = Tag.define();
|
||||
export const Highlight = Tag.define();
|
||||
|
@ -53,6 +53,31 @@ const WikiLink: MarkdownConfig = {
|
||||
],
|
||||
};
|
||||
|
||||
const HighlightDelim = { resolve: "Highlight", mark: "HighlightMark" };
|
||||
|
||||
export const Strikethrough: MarkdownConfig = {
|
||||
defineNodes: [
|
||||
{
|
||||
name: "Highlight",
|
||||
style: { "Highlight/...": ct.Highlight },
|
||||
},
|
||||
{
|
||||
name: "HighlightMark",
|
||||
style: t.processingInstruction,
|
||||
},
|
||||
],
|
||||
parseInline: [
|
||||
{
|
||||
name: "Highlight",
|
||||
parse(cx, next, pos) {
|
||||
if (next != 61 /* '=' */ || cx.char(pos + 1) != 61) return -1;
|
||||
return cx.addDelimiter(HighlightDelim, pos, pos + 2, true, true);
|
||||
},
|
||||
after: "Emphasis",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
class CommentParser implements LeafBlockParser {
|
||||
nextLine() {
|
||||
return false;
|
||||
@ -88,6 +113,7 @@ export default function buildMarkdown(mdExtensions: MDExt[]): Language {
|
||||
WikiLink,
|
||||
TaskList,
|
||||
Comment,
|
||||
Strikethrough,
|
||||
Table,
|
||||
...mdExtensions.map(mdExtensionSyntaxConfig),
|
||||
// parseCode({
|
||||
|
@ -23,3 +23,7 @@ export async function dispatch(
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
export async function listEvents(): Promise<string[]> {
|
||||
return syscall("event.list");
|
||||
}
|
||||
|
@ -21,6 +21,30 @@ export class EventHook implements Hook<EventHookT> {
|
||||
this.localListeners.get(eventName)!.push(callback);
|
||||
}
|
||||
|
||||
// Pull all events listened to
|
||||
listEvents(): string[] {
|
||||
if (!this.system) {
|
||||
throw new Error("Event hook is not initialized");
|
||||
}
|
||||
let eventNames = new Set<string>();
|
||||
for (const plug of this.system.loadedPlugs.values()) {
|
||||
for (const [name, functionDef] of Object.entries(
|
||||
plug.manifest!.functions
|
||||
)) {
|
||||
if (functionDef.events) {
|
||||
for (let eventName of functionDef.events) {
|
||||
eventNames.add(eventName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let eventName of this.localListeners.keys()) {
|
||||
eventNames.add(eventName);
|
||||
}
|
||||
|
||||
return [...eventNames];
|
||||
}
|
||||
|
||||
async dispatchEvent(eventName: string, data?: any): Promise<any[]> {
|
||||
if (!this.system) {
|
||||
throw new Error("Event hook is not initialized");
|
||||
|
@ -6,5 +6,8 @@ export function eventSyscalls(eventHook: EventHook): SysCallMapping {
|
||||
"event.dispatch": async (ctx, eventName: string, data: any) => {
|
||||
return eventHook.dispatchEvent(eventName, data);
|
||||
},
|
||||
"event.list": async () => {
|
||||
return eventHook.listEvents();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -123,34 +123,63 @@ functions:
|
||||
|
||||
# Template commands
|
||||
insertPageMeta:
|
||||
path: "./page.ts:insertPageMeta"
|
||||
path: "./template.ts:insertTemplateText"
|
||||
slashCommand:
|
||||
name: meta
|
||||
value: |
|
||||
```meta
|
||||
|^|
|
||||
```
|
||||
insertTask:
|
||||
path: "./template.ts:insertTemplateText"
|
||||
slashCommand:
|
||||
name: task
|
||||
value: "* [ ] |^|"
|
||||
insertQuery:
|
||||
path: "./template.ts:insertTemplateText"
|
||||
slashCommand:
|
||||
name: query
|
||||
value: |
|
||||
<!-- #query |^| -->
|
||||
|
||||
<!-- /query -->
|
||||
insertTaskToday:
|
||||
path: "./template.ts:insertTemplateText"
|
||||
slashCommand:
|
||||
name: task-today
|
||||
value: "* [ ] |^| 📅 {{today}}"
|
||||
quickNoteCommand:
|
||||
path: ./template.ts:quickNoteCommand
|
||||
command:
|
||||
name: "Template: Quick Note"
|
||||
key: "Alt-Shift-n"
|
||||
quickTaskCommand:
|
||||
path: ./template.ts:quickTaskCommand
|
||||
command:
|
||||
name: "Template: Quick Task"
|
||||
key: "Alt-Shift-t"
|
||||
|
||||
instantiateTemplateCommand:
|
||||
path: ./template.ts:instantiateTemplateCommand
|
||||
command:
|
||||
name: "Template: Instantiate for Page"
|
||||
insertToday:
|
||||
path: "./dates.ts:insertToday"
|
||||
name: "Template: Instantiate Page"
|
||||
insertSnippet:
|
||||
path: ./template.ts:insertSnippet
|
||||
command:
|
||||
name: "Template: Insert Snippet"
|
||||
slashCommand:
|
||||
name: snippet
|
||||
description: Insert a snippet
|
||||
insertTodayCommand:
|
||||
path: "./template.ts:insertTemplateText"
|
||||
slashCommand:
|
||||
name: today
|
||||
insertTomorrow:
|
||||
path: "./dates.ts:insertTomorrow"
|
||||
description: Insert today's date
|
||||
value: "{{today}}"
|
||||
insertTomorrowCommand:
|
||||
path: "./template.ts:insertTemplateText"
|
||||
slashCommand:
|
||||
name: tomorrow
|
||||
description: Insert tomorrow's date
|
||||
value: "{{tomorrow}}"
|
||||
|
||||
# Text editing commands
|
||||
quoteSelection:
|
||||
quoteSelectionCommand:
|
||||
path: ./text.ts:quoteSelection
|
||||
command:
|
||||
name: "Text: Quote Selection"
|
||||
@ -165,17 +194,25 @@ functions:
|
||||
command:
|
||||
name: "Text: Number Listify Selection"
|
||||
bold:
|
||||
path: ./text.ts:boldCommand
|
||||
path: ./text.ts:wrapSelection
|
||||
command:
|
||||
name: "Text: Bold"
|
||||
key: "Ctrl-b"
|
||||
mac: "Cmd-b"
|
||||
wrapper: "**"
|
||||
italic:
|
||||
path: ./text.ts:italicCommand
|
||||
path: ./text.ts:wrapSelection
|
||||
command:
|
||||
name: "Text: Italic"
|
||||
key: "Ctrl-i"
|
||||
mac: "Cmd-i"
|
||||
wrapper: "_"
|
||||
marker:
|
||||
path: ./text.ts:wrapSelection
|
||||
command:
|
||||
name: "Text: Marker"
|
||||
key: "Alt-m"
|
||||
wrapper: "=="
|
||||
|
||||
# Plug manager
|
||||
updatePlugsCommand:
|
||||
|
@ -1,15 +1,3 @@
|
||||
import { insertAtCursor } from "@silverbulletmd/plugos-silverbullet-syscall/editor";
|
||||
|
||||
export function niceDate(d: Date): string {
|
||||
return d.toISOString().split("T")[0];
|
||||
}
|
||||
|
||||
export async function insertToday() {
|
||||
await insertAtCursor(niceDate(new Date()));
|
||||
}
|
||||
|
||||
export async function insertTomorrow() {
|
||||
let d = new Date();
|
||||
d.setDate(d.getDate() + 1);
|
||||
await insertAtCursor(niceDate(d));
|
||||
}
|
||||
|
@ -236,9 +236,3 @@ export async function parseIndexTextRepublish({ name, text }: IndexEvent) {
|
||||
tree: await parseMarkdown(text),
|
||||
});
|
||||
}
|
||||
|
||||
export async function insertPageMeta() {
|
||||
let cursorPos = await getCursor();
|
||||
await insertAtCursor("```meta\n\n```");
|
||||
await moveCursor(cursorPos + 8);
|
||||
}
|
||||
|
@ -5,6 +5,9 @@ import {
|
||||
} from "@silverbulletmd/plugos-silverbullet-syscall/space";
|
||||
import {
|
||||
filterBox,
|
||||
getCurrentPage,
|
||||
getCursor,
|
||||
insertAtCursor,
|
||||
moveCursor,
|
||||
navigate,
|
||||
prompt,
|
||||
@ -15,6 +18,7 @@ import { renderToText } from "@silverbulletmd/common/tree";
|
||||
import { niceDate } from "./dates";
|
||||
|
||||
const pageTemplatePrefix = `template/page/`;
|
||||
const snippetPrefix = `snippet/`;
|
||||
|
||||
export async function instantiateTemplateCommand() {
|
||||
let allPages = await listPages();
|
||||
@ -48,12 +52,45 @@ export async function instantiateTemplateCommand() {
|
||||
await navigate(pageName);
|
||||
}
|
||||
|
||||
export async function insertSnippet() {
|
||||
let allPages = await listPages();
|
||||
let cursorPos = await getCursor();
|
||||
let page = await getCurrentPage();
|
||||
let allSnippets = allPages.filter((pageMeta) =>
|
||||
pageMeta.name.startsWith(snippetPrefix)
|
||||
);
|
||||
|
||||
let selectedSnippet = await filterBox(
|
||||
"Snippet",
|
||||
allSnippets,
|
||||
`Select the snippet to insert (listing any page starting with <tt>${snippetPrefix}</tt>)`
|
||||
);
|
||||
|
||||
if (!selectedSnippet) {
|
||||
return;
|
||||
}
|
||||
let { text } = await readPage(selectedSnippet.name);
|
||||
|
||||
let templateText = replaceTemplateVars(text, page);
|
||||
let carretPos = templateText.indexOf("|^|");
|
||||
templateText = templateText.replace("|^|", "");
|
||||
templateText = replaceTemplateVars(templateText, page);
|
||||
await insertAtCursor(templateText);
|
||||
if (carretPos !== -1) {
|
||||
await moveCursor(cursorPos + carretPos);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This should probably be replaced with handlebards somehow?
|
||||
export function replaceTemplateVars(s: string, pageName: string): string {
|
||||
return s.replaceAll(/\{\{([^\}]+)\}\}/g, (match, v) => {
|
||||
switch (v) {
|
||||
case "today":
|
||||
return niceDate(new Date());
|
||||
case "tomorrow":
|
||||
let tomorrow = new Date();
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
return niceDate(tomorrow);
|
||||
case "yesterday":
|
||||
let yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
@ -62,6 +99,8 @@ export function replaceTemplateVars(s: string, pageName: string): string {
|
||||
let lastWeek = new Date();
|
||||
lastWeek.setDate(lastWeek.getDate() - 7);
|
||||
return niceDate(lastWeek);
|
||||
case "page":
|
||||
return pageName;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
@ -75,12 +114,15 @@ export async function quickNoteCommand() {
|
||||
await navigate(pageName);
|
||||
}
|
||||
|
||||
export async function quickTaskCommand() {
|
||||
let isoDate = new Date().toISOString();
|
||||
let [date, time] = isoDate.split("T");
|
||||
time = time.split(".")[0];
|
||||
let pageName = `✅ ${date} ${time}`;
|
||||
await writePage(pageName, "* [ ] ");
|
||||
await navigate(pageName);
|
||||
await moveCursor(6);
|
||||
export async function insertTemplateText(cmdDef: any) {
|
||||
let cursorPos = await getCursor();
|
||||
let page = await getCurrentPage();
|
||||
let templateText: string = cmdDef.value;
|
||||
let carretPos = templateText.indexOf("|^|");
|
||||
templateText = templateText.replace("|^|", "");
|
||||
templateText = replaceTemplateVars(templateText, page);
|
||||
await insertAtCursor(templateText);
|
||||
if (carretPos !== -1) {
|
||||
await moveCursor(cursorPos + carretPos);
|
||||
}
|
||||
}
|
||||
|
@ -56,12 +56,8 @@ export async function numberListifySelection() {
|
||||
await replaceRange(from, selection.to, text);
|
||||
}
|
||||
|
||||
export function boldCommand() {
|
||||
return insertMarker("**");
|
||||
}
|
||||
|
||||
export function italicCommand() {
|
||||
return insertMarker("_");
|
||||
export function wrapSelection(cmdDef: any) {
|
||||
return insertMarker(cmdDef.wrapper);
|
||||
}
|
||||
|
||||
async function insertMarker(marker: string) {
|
||||
|
@ -1,11 +0,0 @@
|
||||
import {
|
||||
getCursor,
|
||||
insertAtCursor,
|
||||
moveCursor,
|
||||
} from "@silverbulletmd/plugos-silverbullet-syscall/editor";
|
||||
|
||||
export async function insertQuery() {
|
||||
let cursorPos = await getCursor();
|
||||
await insertAtCursor(`<!-- #query -->\n\n<!-- /query -->`);
|
||||
await moveCursor(cursorPos + 12);
|
||||
}
|
32
packages/plugs/query/complete.ts
Normal file
32
packages/plugs/query/complete.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { listEvents } from "@plugos/plugos-syscall/event";
|
||||
import { matchBefore } from "@silverbulletmd/plugos-silverbullet-syscall/editor";
|
||||
import { listPages } from "@silverbulletmd/plugos-silverbullet-syscall/space";
|
||||
|
||||
export async function queryComplete() {
|
||||
let prefix = await matchBefore("#query [\\w\\-_]*");
|
||||
|
||||
if (prefix) {
|
||||
let allEvents = await listEvents();
|
||||
// console.log("All events", allEvents);
|
||||
|
||||
return {
|
||||
from: prefix.from + "#query ".length,
|
||||
options: allEvents
|
||||
.filter((eventName) => eventName.startsWith("query:"))
|
||||
.map((source) => ({
|
||||
label: source.substring("query:".length),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
prefix = await matchBefore('render "[^"]*');
|
||||
if (prefix) {
|
||||
let allPages = await listPages();
|
||||
return {
|
||||
from: prefix.from + 'render "'.length,
|
||||
options: allPages.map((pageMeta) => ({
|
||||
label: pageMeta.name,
|
||||
})),
|
||||
};
|
||||
}
|
||||
}
|
@ -19,7 +19,6 @@ import { replaceAsync } from "../lib/util";
|
||||
export async function updateMaterializedQueriesCommand() {
|
||||
const currentPage = await getCurrentPage();
|
||||
await save();
|
||||
// await flashNotification("Updating materialized queries...");
|
||||
if (
|
||||
await invokeFunction(
|
||||
"server",
|
||||
@ -67,8 +66,17 @@ async function updateTemplateInstantiations(
|
||||
export async function updateMaterializedQueriesOnPage(
|
||||
pageName: string
|
||||
): Promise<boolean> {
|
||||
let { text } = await readPage(pageName);
|
||||
|
||||
let text = "";
|
||||
try {
|
||||
text = (await readPage(pageName)).text;
|
||||
} catch {
|
||||
console.warn(
|
||||
"Could not read page",
|
||||
pageName,
|
||||
"perhaps it doesn't yet exist"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
let newText = await updateTemplateInstantiations(text, pageName);
|
||||
newText = await replaceAsync(
|
||||
newText,
|
||||
|
@ -17,7 +17,7 @@ functions:
|
||||
path: ./data.ts:queryProvider
|
||||
events:
|
||||
- query:data
|
||||
insertQueryCommand:
|
||||
path: ./command.ts:insertQuery
|
||||
slashCommand:
|
||||
name: query
|
||||
queryComplete:
|
||||
path: ./complete.ts:queryComplete
|
||||
events:
|
||||
- page:complete
|
||||
|
@ -59,6 +59,7 @@ import { FilterList } from "./components/filter";
|
||||
import { FilterOption, PageMeta } from "@silverbulletmd/common/types";
|
||||
import { syntaxTree } from "@codemirror/language";
|
||||
import sandboxSyscalls from "@plugos/plugos/syscalls/sandbox";
|
||||
import { eventSyscalls } from "@plugos/plugos/syscalls/event";
|
||||
// import globalModules from "../common/dist/global.plug.json";
|
||||
|
||||
class PageState {
|
||||
@ -148,6 +149,7 @@ export class Editor {
|
||||
|
||||
this.system.registerSyscalls(
|
||||
[],
|
||||
eventSyscalls(this.eventHook),
|
||||
editorSyscalls(this),
|
||||
spaceSyscalls(this),
|
||||
indexerSyscalls(this.space),
|
||||
@ -630,9 +632,15 @@ export class Editor {
|
||||
editor.focus();
|
||||
if (cmd) {
|
||||
dispatch({ type: "command-run", command: cmd.command.name });
|
||||
cmd.run().catch((e) => {
|
||||
console.error("Error running command", e.message);
|
||||
});
|
||||
cmd
|
||||
.run()
|
||||
.catch((e) => {
|
||||
console.error("Error running command", e.message);
|
||||
})
|
||||
.then(() => {
|
||||
// Always be focusing the editor after running a command
|
||||
editor.focus();
|
||||
});
|
||||
}
|
||||
}}
|
||||
commands={viewState.commands}
|
||||
|
@ -8,9 +8,11 @@ import {
|
||||
import { slashCommandRegexp } from "../types";
|
||||
import { safeRun } from "../../common/util";
|
||||
import { Editor } from "../editor";
|
||||
import { syntaxTree } from "@codemirror/language";
|
||||
|
||||
export type SlashCommandDef = {
|
||||
name: string;
|
||||
description?: string;
|
||||
};
|
||||
|
||||
export type AppSlashCommand = {
|
||||
@ -43,7 +45,7 @@ export class SlashCommandHook implements Hook<SlashCommandHookT> {
|
||||
this.slashCommands.set(cmd.name, {
|
||||
slashCommand: cmd,
|
||||
run: () => {
|
||||
return plug.invoke(name, []);
|
||||
return plug.invoke(name, [cmd]);
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -59,10 +61,16 @@ export class SlashCommandHook implements Hook<SlashCommandHookT> {
|
||||
return null;
|
||||
}
|
||||
let options: Completion[] = [];
|
||||
|
||||
// No slash commands in comment blocks (queries and such)
|
||||
let currentNode = syntaxTree(ctx.state).resolveInner(ctx.pos);
|
||||
if (currentNode.type.name === "CommentBlock") {
|
||||
return null;
|
||||
}
|
||||
for (let [name, def] of this.slashCommands.entries()) {
|
||||
options.push({
|
||||
label: def.slashCommand.name,
|
||||
detail: name,
|
||||
detail: def.slashCommand.description,
|
||||
apply: () => {
|
||||
// Delete slash command part
|
||||
this.editor.editorView?.dispatch({
|
||||
@ -75,6 +83,7 @@ export class SlashCommandHook implements Hook<SlashCommandHookT> {
|
||||
// Replace with whatever the completion is
|
||||
safeRun(async () => {
|
||||
await def.run();
|
||||
this.editor.focus();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
@ -20,6 +20,7 @@ export default function highlightStyles(mdExtension: MDExt[]) {
|
||||
{ tag: ct.CodeInfoTag, class: "code-info" },
|
||||
{ tag: ct.CommentTag, class: "comment" },
|
||||
{ tag: ct.CommentMarkerTag, class: "comment-marker" },
|
||||
{ tag: ct.Highlight, class: "highlight" },
|
||||
{ tag: t.emphasis, class: "emphasis" },
|
||||
{ tag: t.strong, class: "strong" },
|
||||
{ tag: t.atom, class: "atom" },
|
||||
|
@ -81,6 +81,10 @@
|
||||
background-color: rgba(72, 72, 72, 0.1);
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: rgba(255, 255, 0, 0.5);
|
||||
}
|
||||
|
||||
.line-fenced-code {
|
||||
background-color: rgba(72, 72, 72, 0.1);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user