Major mini editor refactoring (#225)
Replaces most editing components with CM components, enabling vim mode and completions everywhere Fixes #205 Fixes #221 Fixes #222 Fixes #223
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { collectNodesOfType } from "$sb/lib/tree.ts";
|
||||
import { editor, index } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import type { IndexTreeEvent } from "$sb/app_event.ts";
|
||||
import type { CompleteEvent, IndexTreeEvent } from "$sb/app_event.ts";
|
||||
import { removeQueries } from "$sb/lib/query.ts";
|
||||
|
||||
// Key space
|
||||
@@ -21,13 +21,13 @@ export async function indexAnchors({ name: pageName, tree }: IndexTreeEvent) {
|
||||
await index.batchSet(pageName, anchors);
|
||||
}
|
||||
|
||||
export async function anchorComplete() {
|
||||
const prefix = await editor.matchBefore("\\[\\[[^\\]@:]*@[\\w\\.\\-\\/]*");
|
||||
if (!prefix) {
|
||||
export async function anchorComplete(completeEvent: CompleteEvent) {
|
||||
const match = /\[\[([^\]@:]*@[\w\.\-\/]*)$/.exec(completeEvent.linePrefix);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
const [pageRefPrefix, anchorRef] = prefix.text.split("@");
|
||||
let pageRef = pageRefPrefix.substring(2);
|
||||
|
||||
let [pageRef, anchorRef] = match[1].split("@");
|
||||
if (!pageRef) {
|
||||
pageRef = await editor.getCurrentPage();
|
||||
}
|
||||
@@ -35,7 +35,7 @@ export async function anchorComplete() {
|
||||
`a:${pageRef}:${anchorRef}`,
|
||||
);
|
||||
return {
|
||||
from: prefix.from + pageRefPrefix.length + 1,
|
||||
from: completeEvent.pos - anchorRef.length,
|
||||
options: allAnchors.map((a) => ({
|
||||
label: a.key.split(":")[2],
|
||||
type: "anchor",
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { editor, system } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import { system } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import { CompleteEvent } from "../../plug-api/app_event.ts";
|
||||
|
||||
export async function commandComplete() {
|
||||
const prefix = await editor.matchBefore("\\{\\[[^\\]]*");
|
||||
if (!prefix) {
|
||||
export async function commandComplete(completeEvent: CompleteEvent) {
|
||||
const match = /\{\[([^\]]*)$/.exec(completeEvent.linePrefix);
|
||||
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
const allCommands = await system.listCommands();
|
||||
|
||||
return {
|
||||
from: prefix.from + 2,
|
||||
from: completeEvent.pos - match[1].length,
|
||||
options: Object.keys(allCommands).map((commandName) => ({
|
||||
label: commandName,
|
||||
type: "command",
|
||||
|
||||
@@ -26,6 +26,10 @@ functions:
|
||||
path: "./editor.ts:toggleVimMode"
|
||||
command:
|
||||
name: "Editor: Toggle Vim Mode"
|
||||
toggleDarkMode:
|
||||
path: "./editor.ts:toggleDarkMode"
|
||||
command:
|
||||
name: "Editor: Toggle Dark Mode"
|
||||
|
||||
clearPageIndex:
|
||||
path: "./page.ts:clearPageIndex"
|
||||
@@ -82,13 +86,13 @@ functions:
|
||||
pageComplete:
|
||||
path: "./page.ts:pageComplete"
|
||||
events:
|
||||
- page:complete
|
||||
- editor:complete
|
||||
|
||||
# Commands
|
||||
commandComplete:
|
||||
path: "./command.ts:commandComplete"
|
||||
events:
|
||||
- page:complete
|
||||
- editor:complete
|
||||
|
||||
# Item indexing
|
||||
indexItem:
|
||||
@@ -126,7 +130,7 @@ functions:
|
||||
tagComplete:
|
||||
path: "./tags.ts:tagComplete"
|
||||
events:
|
||||
- page:complete
|
||||
- editor:complete
|
||||
tagProvider:
|
||||
path: "./tags.ts:tagProvider"
|
||||
events:
|
||||
@@ -140,7 +144,7 @@ functions:
|
||||
anchorComplete:
|
||||
path: "./anchor.ts:anchorComplete"
|
||||
events:
|
||||
- page:complete
|
||||
- editor:complete
|
||||
|
||||
# Full text search
|
||||
searchIndex:
|
||||
|
||||
+12
-2
@@ -17,13 +17,23 @@ export async function toggleReadOnlyMode() {
|
||||
// Run on "editor:init"
|
||||
export async function setEditorMode() {
|
||||
if (await clientStore.get("vimMode")) {
|
||||
await editor.setVimEnabled(true);
|
||||
await editor.setUiOption("vimMode", true);
|
||||
}
|
||||
if (await clientStore.get("darkMode")) {
|
||||
await editor.setUiOption("darkMode", true);
|
||||
}
|
||||
}
|
||||
|
||||
export async function toggleVimMode() {
|
||||
let vimMode = await clientStore.get("vimMode");
|
||||
vimMode = !vimMode;
|
||||
await editor.setVimEnabled(vimMode);
|
||||
await editor.setUiOption("vimMode", vimMode);
|
||||
await clientStore.set("vimMode", vimMode);
|
||||
}
|
||||
|
||||
export async function toggleDarkMode() {
|
||||
let darkMode = await clientStore.get("darkMode");
|
||||
darkMode = !darkMode;
|
||||
await editor.setUiOption("darkMode", darkMode);
|
||||
await clientStore.set("darkMode", darkMode);
|
||||
}
|
||||
|
||||
+25
-5
@@ -1,4 +1,5 @@
|
||||
import type {
|
||||
CompleteEvent,
|
||||
IndexEvent,
|
||||
IndexTreeEvent,
|
||||
QueryProviderEvent,
|
||||
@@ -101,10 +102,29 @@ export async function renamePage(cmdDef: any) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("New name", newName);
|
||||
|
||||
if (newName.trim() === oldName.trim()) {
|
||||
// Nothing to do here
|
||||
console.log("Name unchanged, exiting");
|
||||
return;
|
||||
}
|
||||
console.log("New name", newName);
|
||||
|
||||
try {
|
||||
// This throws an error if the page does not exist, which we expect to be the case
|
||||
await space.getPageMeta(newName);
|
||||
// So when we get to this point, we error out
|
||||
throw new Error(
|
||||
`Page ${newName} already exists, cannot rename to existing page.`,
|
||||
);
|
||||
} catch (e: any) {
|
||||
if (e.message.includes("not found")) {
|
||||
// Expected not found error, so we can continue
|
||||
} else {
|
||||
await editor.flashNotification(e.message, "error");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
const pagesToUpdate = await getBackLinks(oldName);
|
||||
console.log("All pages containing backlinks", pagesToUpdate);
|
||||
@@ -209,14 +229,14 @@ export async function reindexCommand() {
|
||||
}
|
||||
|
||||
// Completion
|
||||
export async function pageComplete() {
|
||||
const prefix = await editor.matchBefore("\\[\\[[^\\]@:]*");
|
||||
if (!prefix) {
|
||||
export async function pageComplete(completeEvent: CompleteEvent) {
|
||||
const match = /\[\[([^\]@:]*)$/.exec(completeEvent.linePrefix);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
const allPages = await space.listPages();
|
||||
return {
|
||||
from: prefix.from + 2,
|
||||
from: completeEvent.pos - match[1].length,
|
||||
options: allPages.map((pageMeta) => ({
|
||||
label: pageMeta.name,
|
||||
boost: pageMeta.lastModified,
|
||||
|
||||
+11
-7
@@ -1,6 +1,10 @@
|
||||
import { collectNodesOfType } from "$sb/lib/tree.ts";
|
||||
import { editor, index } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import type { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
||||
import type {
|
||||
CompleteEvent,
|
||||
IndexTreeEvent,
|
||||
QueryProviderEvent,
|
||||
} from "$sb/app_event.ts";
|
||||
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
||||
|
||||
// Key space
|
||||
@@ -18,15 +22,15 @@ export async function indexTags({ name, tree }: IndexTreeEvent) {
|
||||
);
|
||||
}
|
||||
|
||||
export async function tagComplete() {
|
||||
const prefix = await editor.matchBefore("#[^#\\s]+");
|
||||
// console.log("Running tag complete", prefix);
|
||||
if (!prefix) {
|
||||
export async function tagComplete(completeEvent: CompleteEvent) {
|
||||
const match = /#[^#\s]+$/.exec(completeEvent.linePrefix);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
const allTags = await index.queryPrefix(`tag:${prefix.text}`);
|
||||
const tagPrefix = match[0];
|
||||
const allTags = await index.queryPrefix(`tag:${tagPrefix}`);
|
||||
return {
|
||||
from: prefix.from,
|
||||
from: completeEvent.pos - tagPrefix.length,
|
||||
options: allTags.map((tag) => ({
|
||||
label: tag.value,
|
||||
type: "tag",
|
||||
|
||||
Reference in New Issue
Block a user