More instant page navigator
This commit is contained in:
parent
8a181145ad
commit
3350c7f076
@ -97,11 +97,6 @@ export async function extractFrontmatter(
|
||||
return undefined;
|
||||
});
|
||||
|
||||
if (data.name) {
|
||||
data.displayName = data.name;
|
||||
delete data.name;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -46,31 +46,31 @@ export async function pageComplete(completeEvent: CompleteEvent) {
|
||||
const completions: any[] = [];
|
||||
if (pageMeta.displayName) {
|
||||
completions.push({
|
||||
label: pageMeta.displayName,
|
||||
boost: pageMeta.lastModified,
|
||||
label: `${pageMeta.displayName}`,
|
||||
boost: new Date(pageMeta.lastModified).getTime(),
|
||||
apply: isInTemplateContext
|
||||
? pageMeta.name
|
||||
: `${pageMeta.name}|${pageMeta.displayName}`,
|
||||
detail: "alias",
|
||||
detail: `displayName: ${pageMeta.name}`,
|
||||
type: "page",
|
||||
});
|
||||
}
|
||||
if (Array.isArray(pageMeta.aliases)) {
|
||||
for (const alias of pageMeta.aliases) {
|
||||
completions.push({
|
||||
label: alias,
|
||||
boost: pageMeta.lastModified,
|
||||
label: `${alias}`,
|
||||
boost: new Date(pageMeta.lastModified).getTime(),
|
||||
apply: isInTemplateContext
|
||||
? pageMeta.name
|
||||
: `${pageMeta.name}|${alias}`,
|
||||
detail: "alias",
|
||||
detail: `alias: ${pageMeta.name}`,
|
||||
type: "page",
|
||||
});
|
||||
}
|
||||
}
|
||||
completions.push({
|
||||
label: pageMeta.name,
|
||||
boost: pageMeta.lastModified,
|
||||
label: `${pageMeta.name}`,
|
||||
boost: new Date(pageMeta.lastModified).getTime(),
|
||||
type: "page",
|
||||
});
|
||||
return completions;
|
||||
|
@ -137,7 +137,7 @@ export class ServerSystem {
|
||||
);
|
||||
|
||||
this.listInterval = setInterval(() => {
|
||||
space.updatePageListCache().catch(console.error);
|
||||
space.updatePageList().catch(console.error);
|
||||
}, fileListInterval);
|
||||
|
||||
eventHook.addLocalListener("file:changed", (path, localChange) => {
|
||||
|
@ -107,6 +107,9 @@ export class Client {
|
||||
spaceDataStore!: DataStore;
|
||||
mq!: DataStoreMQ;
|
||||
|
||||
// Used by the "wiki link" highlighter to check if a page exists
|
||||
public allKnownPages = new Set<string>();
|
||||
|
||||
constructor(
|
||||
private parent: Element,
|
||||
public syncMode = false,
|
||||
@ -226,6 +229,8 @@ export class Client {
|
||||
console.error("Interval sync error", e);
|
||||
}
|
||||
}, pageSyncInterval);
|
||||
|
||||
this.updatePageListCache().catch(console.error);
|
||||
}
|
||||
|
||||
private initSync() {
|
||||
@ -235,7 +240,7 @@ export class Client {
|
||||
// console.log("Operations", operations);
|
||||
if (operations > 0) {
|
||||
// Update the page list
|
||||
await this.space.updatePageListCache();
|
||||
await this.space.updatePageList();
|
||||
}
|
||||
if (operations !== undefined) {
|
||||
// "sync:success" is called with a number of operations only from syncSpace(), not from syncing individual pages
|
||||
@ -499,6 +504,28 @@ export class Client {
|
||||
},
|
||||
);
|
||||
|
||||
// Caching a list of known pages for the wiki_link highlighter (that checks if a page exists)
|
||||
this.eventHook.addLocalListener("page:saved", (pageName: string) => {
|
||||
// Make sure this page is in the list of known pages
|
||||
this.allKnownPages.add(pageName);
|
||||
});
|
||||
|
||||
this.eventHook.addLocalListener("page:deleted", (pageName: string) => {
|
||||
this.allKnownPages.delete(pageName);
|
||||
});
|
||||
|
||||
this.eventHook.addLocalListener(
|
||||
"file:listed",
|
||||
(allFiles: FileMeta[]) => {
|
||||
// Update list of known pages
|
||||
this.allKnownPages = new Set(
|
||||
allFiles.filter((f) => f.name.endsWith(".md")).map((f) =>
|
||||
f.name.slice(0, -3)
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
this.space.watch();
|
||||
|
||||
return localSpacePrimitives;
|
||||
@ -582,11 +609,19 @@ export class Client {
|
||||
);
|
||||
}
|
||||
|
||||
async startPageNavigate() {
|
||||
// Fetch all pages from the index
|
||||
const pages = await this.system.queryObjects<PageMeta>("page", {});
|
||||
startPageNavigate() {
|
||||
// Then show the page navigator
|
||||
this.ui.viewDispatch({ type: "start-navigate", pages });
|
||||
this.ui.viewDispatch({ type: "start-navigate" });
|
||||
this.updatePageListCache().catch(console.error);
|
||||
}
|
||||
|
||||
async updatePageListCache() {
|
||||
console.log("Updating page list cache");
|
||||
const allPages = await this.system.queryObjects<PageMeta>("page", {});
|
||||
this.ui.viewDispatch({
|
||||
type: "update-page-list",
|
||||
allPages,
|
||||
});
|
||||
}
|
||||
|
||||
private progressTimeout?: number;
|
||||
@ -744,6 +779,7 @@ export class Client {
|
||||
actualResult = result;
|
||||
}
|
||||
}
|
||||
// console.log("Compeltion result", actualResult);
|
||||
return actualResult;
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ import { resolvePath } from "$sb/lib/resolve.ts";
|
||||
/**
|
||||
* Plugin to hide path prefix when the cursor is not inside.
|
||||
*/
|
||||
export function cleanWikiLinkPlugin(editor: Client) {
|
||||
export function cleanWikiLinkPlugin(client: Client) {
|
||||
return decoratorStateField((state) => {
|
||||
const widgets: any[] = [];
|
||||
// let parentRange: [number, number];
|
||||
@ -28,21 +28,20 @@ export function cleanWikiLinkPlugin(editor: Client) {
|
||||
if (!match) return;
|
||||
const [_fullMatch, page, pipePart, alias] = match;
|
||||
|
||||
const allPages = editor.space.listPages();
|
||||
let pageExists = !editor.fullSyncCompleted;
|
||||
let pageExists = !client.fullSyncCompleted;
|
||||
let cleanPage = page;
|
||||
cleanPage = page.split(/[@$]/)[0];
|
||||
cleanPage = resolvePath(editor.currentPage!, cleanPage);
|
||||
cleanPage = resolvePath(client.currentPage!, cleanPage);
|
||||
const lowerCasePageName = cleanPage.toLowerCase();
|
||||
for (const pageMeta of allPages) {
|
||||
if (pageMeta.name.toLowerCase() === lowerCasePageName) {
|
||||
for (const pageName of client.allKnownPages) {
|
||||
if (pageName.toLowerCase() === lowerCasePageName) {
|
||||
pageExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (
|
||||
cleanPage === "" ||
|
||||
editor.plugSpaceRemotePrimitives.isLikelyHandled(cleanPage)
|
||||
client.plugSpaceRemotePrimitives.isLikelyHandled(cleanPage)
|
||||
) {
|
||||
// Empty page name with local @anchor use or a link to a page that dynamically generated by a plug
|
||||
pageExists = true;
|
||||
@ -90,19 +89,19 @@ export function cleanWikiLinkPlugin(editor: Client) {
|
||||
callback: (e) => {
|
||||
if (e.altKey) {
|
||||
// Move cursor into the link
|
||||
return editor.editorView.dispatch({
|
||||
return client.editorView.dispatch({
|
||||
selection: { anchor: from + 2 },
|
||||
});
|
||||
}
|
||||
// Dispatch click event to navigate there without moving the cursor
|
||||
const clickEvent: ClickEvent = {
|
||||
page: editor.currentPage!,
|
||||
page: client.currentPage!,
|
||||
ctrlKey: e.ctrlKey,
|
||||
metaKey: e.metaKey,
|
||||
altKey: e.altKey,
|
||||
pos: from,
|
||||
};
|
||||
editor.dispatchAppEvent("page:click", clickEvent).catch(
|
||||
client.dispatchAppEvent("page:click", clickEvent).catch(
|
||||
console.error,
|
||||
);
|
||||
},
|
||||
|
@ -57,7 +57,7 @@ export function createEditorState(
|
||||
// Keyboard shortcuts from SETTINGS take precedense
|
||||
if (client.settings?.keyboardShortcuts) {
|
||||
for (const shortcut of client.settings.keyboardShortcuts) {
|
||||
console.info("Configuring keyboard shortcut", shortcut);
|
||||
// console.info("Configuring keyboard shortcut", shortcut);
|
||||
commandKeyBindings.push({
|
||||
key: shortcut.key,
|
||||
mac: shortcut.mac,
|
||||
@ -215,7 +215,7 @@ export function createEditorState(
|
||||
key: "Ctrl-k",
|
||||
mac: "Cmd-k",
|
||||
run: (): boolean => {
|
||||
client.startPageNavigate().catch(console.error);
|
||||
client.startPageNavigate();
|
||||
return true;
|
||||
},
|
||||
},
|
||||
|
@ -44,7 +44,7 @@ export class MainUI {
|
||||
if (ev.touches.length === 2) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
client.startPageNavigate().catch(console.error);
|
||||
client.startPageNavigate();
|
||||
}
|
||||
// Launch the command palette using a three-finger tap
|
||||
if (ev.touches.length === 3) {
|
||||
@ -251,7 +251,7 @@ export class MainUI {
|
||||
icon: BookIcon,
|
||||
description: `Open page (${isMacLike() ? "Cmd-k" : "Ctrl-k"})`,
|
||||
callback: () => {
|
||||
client.startPageNavigate().catch(console.error);
|
||||
client.startPageNavigate();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -45,20 +45,26 @@ export default function reducer(
|
||||
...state,
|
||||
syncFailures: action.syncSuccess ? 0 : state.syncFailures + 1,
|
||||
};
|
||||
case "start-navigate": {
|
||||
case "update-page-list": {
|
||||
// Let's move over any "lastOpened" times to the "allPages" list
|
||||
const oldPageMeta = new Map(
|
||||
[...state.allPages].map((pm) => [pm.name, pm]),
|
||||
);
|
||||
for (const pageMeta of action.pages) {
|
||||
for (const pageMeta of action.allPages) {
|
||||
const oldPageMetaItem = oldPageMeta.get(pageMeta.name);
|
||||
if (oldPageMetaItem && oldPageMetaItem.lastOpened) {
|
||||
pageMeta.lastOpened = oldPageMetaItem.lastOpened;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
allPages: action.allPages,
|
||||
};
|
||||
}
|
||||
case "start-navigate": {
|
||||
return {
|
||||
...state,
|
||||
allPages: action.pages,
|
||||
showPageNavigator: true,
|
||||
showCommandPalette: false,
|
||||
showFilterBox: false,
|
||||
|
26
web/space.ts
26
web/space.ts
@ -14,9 +14,6 @@ export class Space {
|
||||
imageHeightCache = new LimitedMap<number>(100); // url -> height
|
||||
widgetHeightCache = new LimitedMap<number>(100); // bodytext -> height
|
||||
|
||||
// Note: this is "clean" PageMeta, it doesn't contain custom attributes (it's fetched from the store)
|
||||
private cachedPageList: PageMeta[] = [];
|
||||
|
||||
debouncedImageCacheFlush = throttle(() => {
|
||||
this.ds.set(["cache", "imageHeight"], this.imageHeightCache).catch(
|
||||
console.error,
|
||||
@ -72,25 +69,18 @@ export class Space {
|
||||
this.widgetHeightCache = new LimitedMap(100, widgetCache);
|
||||
}
|
||||
});
|
||||
// eventHook.addLocalListener("file:listed", (files: FileMeta[]) => {
|
||||
// // console.log("Files listed", files);
|
||||
// this.cachedPageList = files.filter(this.isListedPage).map(
|
||||
// fileMetaToPageMeta,
|
||||
// );
|
||||
// });
|
||||
eventHook.addLocalListener("page:deleted", (pageName: string) => {
|
||||
if (this.watchedPages.has(pageName)) {
|
||||
// Stop watching deleted pages already
|
||||
this.watchedPages.delete(pageName);
|
||||
}
|
||||
});
|
||||
this.updatePageListCache().catch(console.error);
|
||||
this.updatePageList().catch(console.error);
|
||||
}
|
||||
|
||||
public async updatePageListCache() {
|
||||
console.log("Updating page list cache");
|
||||
// This will trigger appropriate events automatically
|
||||
this.cachedPageList = await this.fetchPageList();
|
||||
public async updatePageList() {
|
||||
// The only reason to do this is to trigger events
|
||||
await this.fetchPageList();
|
||||
}
|
||||
|
||||
async deletePage(name: string): Promise<void> {
|
||||
@ -104,10 +94,6 @@ export class Space {
|
||||
);
|
||||
}
|
||||
|
||||
listPages(): PageMeta[] {
|
||||
return this.cachedPageList;
|
||||
}
|
||||
|
||||
async listPlugs(): Promise<FileMeta[]> {
|
||||
const files = await this.deduplicatedFileList();
|
||||
return files
|
||||
@ -139,10 +125,6 @@ export class Space {
|
||||
selfUpdate,
|
||||
),
|
||||
);
|
||||
if (!this.cachedPageList.find((page) => page.name === pageMeta.name)) {
|
||||
// New page, let's cache it
|
||||
this.cachedPageList.push(pageMeta);
|
||||
}
|
||||
// Note: we don't do very elaborate cache invalidation work here, quite quickly the cache will be flushed anyway
|
||||
return pageMeta;
|
||||
} finally {
|
||||
|
@ -382,7 +382,7 @@ export class NoSyncSyncService implements ISyncService {
|
||||
start() {
|
||||
setInterval(() => {
|
||||
// Trigger a page upload for change events
|
||||
this.space.updatePageListCache().catch(console.error);
|
||||
this.space.updatePageList().catch(console.error);
|
||||
}, spaceSyncInterval);
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,8 @@ export type Action =
|
||||
| { type: "page-changed" }
|
||||
| { type: "page-saved" }
|
||||
| { type: "sync-change"; syncSuccess: boolean }
|
||||
| { type: "start-navigate"; pages: PageMeta[] }
|
||||
| { type: "update-page-list"; allPages: PageMeta[] }
|
||||
| { type: "start-navigate" }
|
||||
| { type: "stop-navigate" }
|
||||
| {
|
||||
type: "update-commands";
|
||||
|
Loading…
Reference in New Issue
Block a user