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:
Zef Hemel
2022-12-21 14:55:24 +01:00
committed by GitHub
parent 6897111cf9
commit 3545d00d46
31 changed files with 1158 additions and 745 deletions
+7 -7
View File
@@ -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",
+7 -5
View File
@@ -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",
+8 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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",