@lapis-notes/api 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +193 -0
- package/README.md +19 -0
- package/dist/__tests__/fixtures/indexed-mutations.json +6862 -0
- package/dist/__tests__/fixtures/memory-storage.json +309 -0
- package/dist/__tests__/fixtures/native-facade-contract.json +3224 -0
- package/dist/__tests__/fixtures/projection-query.json +195 -0
- package/dist/__tests__/fixtures/projection-values.json +60 -0
- package/dist/__tests__/fixtures/search-preparation.json +1513 -0
- package/dist/__tests__/fixtures/search-retrieval.json +15409 -0
- package/dist/__tests__/fixtures/search-semantic-model.json +3691 -0
- package/dist/__tests__/fixtures/search-semantic-retrieval.json +6603 -0
- package/dist/__tests__/fixtures/search-storage.json +409 -0
- package/dist/__tests__/fixtures/task-projection.json +428 -0
- package/dist/__tests__/indexed-mutation-support.js +262 -0
- package/dist/__tests__/projection-query-support.js +40 -0
- package/dist/__tests__/search-retrieval-support.js +47 -0
- package/dist/app-database-host.d.ts +1 -0
- package/dist/app-shell-plugin-persistence.d.ts +3 -2
- package/dist/app-shell-plugin-persistence.js +37 -3
- package/dist/cache.svelte.d.ts +8 -1
- package/dist/cache.svelte.js +103 -5
- package/dist/command.svelte.js +29 -2
- package/dist/components/editor/editor.css +4 -0
- package/dist/components/editor/editor.svelte +21 -9
- package/dist/components/editor/embedded-editor-surface.js +3 -1
- package/dist/components/editor/inline-title-alignment.d.ts +3 -0
- package/dist/components/editor/inline-title-alignment.js +57 -0
- package/dist/configuration.svelte.d.ts +270 -206
- package/dist/configuration.svelte.js +161 -86
- package/dist/context.svelte.d.ts +21 -3
- package/dist/context.svelte.js +63 -20
- package/dist/diagnostics.d.ts +8 -0
- package/dist/diagnostics.js +6 -0
- package/dist/editor-save-context.d.ts +12 -1
- package/dist/editor-save-context.js +32 -1
- package/dist/editor-view-registry.d.ts +10 -0
- package/dist/editor-view-registry.js +44 -4
- package/dist/editor.svelte.js +128 -37
- package/dist/embed-registry.d.ts +10 -0
- package/dist/embed-registry.js +15 -0
- package/dist/file-editing-failures.d.ts +2 -0
- package/dist/file-editing-failures.js +29 -0
- package/dist/file-editing-native-issues.d.ts +19 -0
- package/dist/file-editing-native-issues.js +65 -0
- package/dist/file-editing-sessions.d.ts +56 -8
- package/dist/file-editing-sessions.js +185 -15
- package/dist/file-manager.d.ts +8 -1
- package/dist/file-manager.js +37 -3
- package/dist/file-state-store.d.ts +5 -0
- package/dist/file-state-store.js +34 -0
- package/dist/file-text-conflicts.d.ts +25 -0
- package/dist/file-text-conflicts.js +35 -0
- package/dist/file-text-mutation.d.ts +13 -0
- package/dist/file-text-mutation.js +100 -0
- package/dist/file-text-persistence.d.ts +36 -0
- package/dist/file-text-persistence.js +234 -0
- package/dist/file-text-state-writer.d.ts +34 -0
- package/dist/file-text-state-writer.js +183 -0
- package/dist/files-configuration.d.ts +20 -0
- package/dist/files-configuration.js +47 -0
- package/dist/generated/plugin-host-modules.schema.generated.d.ts +87 -37
- package/dist/generated/plugin-host-modules.schema.generated.js +102 -37
- package/dist/glob.d.ts +3 -0
- package/dist/glob.js +2 -1
- package/dist/icons/changes.d.ts +3 -0
- package/dist/icons/changes.js +16 -0
- package/dist/icons/index.d.ts +5 -1
- package/dist/icons/index.js +44 -3
- package/dist/icons/registry.d.ts +35 -0
- package/dist/icons/registry.js +154 -0
- package/dist/icons/safe-svg.d.ts +2 -0
- package/dist/icons/safe-svg.js +44 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/lapis-extension.d.ts +6 -2
- package/dist/lapis-extension.js +2 -0
- package/dist/metadata.svelte.js +45 -2
- package/dist/native-background-indexing.d.ts +48 -0
- package/dist/native-background-indexing.js +208 -0
- package/dist/native-database-protocol.d.ts +29 -0
- package/dist/native-database-protocol.js +1 -0
- package/dist/native-editing-intent-lease.d.ts +17 -0
- package/dist/native-editing-intent-lease.js +188 -0
- package/dist/native-editing-intents-protocol.d.ts +70 -0
- package/dist/native-editing-intents-protocol.js +1 -0
- package/dist/native-editing-intents.d.ts +8 -0
- package/dist/native-editing-intents.js +1 -0
- package/dist/native-editing-problems.d.ts +3 -0
- package/dist/native-editing-problems.js +180 -0
- package/dist/native-editing-recovery.d.ts +24 -0
- package/dist/native-editing-recovery.js +198 -0
- package/dist/native-editing-session.d.ts +51 -0
- package/dist/native-editing-session.js +251 -0
- package/dist/native-history-index-protocol.d.ts +80 -0
- package/dist/native-history-index-protocol.js +1 -0
- package/dist/native-history-index.d.ts +6 -0
- package/dist/native-history-index.js +1 -0
- package/dist/native-indexing-protocol.d.ts +63 -0
- package/dist/native-indexing-protocol.js +1 -0
- package/dist/native-participant-protocol.d.ts +67 -0
- package/dist/native-participant-protocol.js +3 -0
- package/dist/native-queue-protocol.d.ts +73 -0
- package/dist/native-queue-protocol.js +3 -0
- package/dist/native-tasks-protocol.d.ts +264 -0
- package/dist/native-tasks-protocol.js +1 -0
- package/dist/native-tasks.d.ts +35 -0
- package/dist/native-tasks.js +79 -0
- package/dist/native-turn-protocol.d.ts +81 -0
- package/dist/native-turn-protocol.js +1 -0
- package/dist/native-turns.d.ts +29 -0
- package/dist/native-turns.js +2 -0
- package/dist/plugin-asset-server.js +3 -2
- package/dist/plugin-dependency-resolver.d.ts +1 -1
- package/dist/plugin-distribution/compatibility.d.ts +1 -1
- package/dist/plugin-distribution/compatibility.js +10 -5
- package/dist/plugin-distribution/installed-plugin-state.js +2 -1
- package/dist/plugin-distribution/installer.d.ts +6 -0
- package/dist/plugin-distribution/installer.js +90 -37
- package/dist/plugin-distribution/manager.d.ts +4 -1
- package/dist/plugin-distribution/manager.js +12 -5
- package/dist/plugin-distribution/registry-cache.js +2 -1
- package/dist/plugin-distribution/registry-source-state.js +2 -1
- package/dist/plugin-distribution/schemas.d.ts +26 -8
- package/dist/plugin-distribution/schemas.js +2 -1
- package/dist/plugin-distribution/types.d.ts +4 -0
- package/dist/plugin-manager.d.ts +20 -4
- package/dist/plugin-manager.js +228 -64
- package/dist/plugin-runtime-entry.d.ts +1 -1
- package/dist/plugin-runtime-entry.js +16 -0
- package/dist/plugin.d.ts +18 -2
- package/dist/plugin.js +93 -39
- package/dist/registry-schema/catalog-v1.d.ts +60 -9
- package/dist/registry-schema/catalog-v1.js +2 -1
- package/dist/registry-schema/catalog-v2.d.ts +60 -9
- package/dist/registry-schema/catalog-v2.js +1 -1
- package/dist/search-result-provider.d.ts +95 -0
- package/dist/search-result-provider.js +42 -0
- package/dist/status-bar.svelte.d.ts +26 -20
- package/dist/status-bar.svelte.js +1 -0
- package/dist/storage/app-database.d.ts +6 -2
- package/dist/storage/app-database.js +41 -34
- package/dist/storage/desktop-native.d.ts +5 -3
- package/dist/storage/desktop-native.js +59 -6
- package/dist/storage/directory-watcher.d.ts +27 -0
- package/dist/storage/directory-watcher.js +201 -0
- package/dist/storage/fs.d.ts +14 -27
- package/dist/storage/fs.js +2 -168
- package/dist/storage/index-projection.js +33 -15
- package/dist/storage/memory-vault-adapter.d.ts +2 -0
- package/dist/storage/memory-vault-adapter.js +14 -1
- package/dist/storage/path.d.ts +6 -2
- package/dist/storage/path.js +8 -2
- package/dist/storage/projection-query-candidates.d.ts +3 -0
- package/dist/storage/projection-query-candidates.js +69 -0
- package/dist/storage/remote-app-database.d.ts +2 -2
- package/dist/storage/remote-app-database.js +1 -1
- package/dist/storage/runtime.d.ts +3 -0
- package/dist/storage/runtime.js +3 -0
- package/dist/storage/search-embedding-record.d.ts +3 -0
- package/dist/storage/search-embedding-record.js +18 -0
- package/dist/storage/turso-app-database.d.ts +2 -0
- package/dist/storage/turso-app-database.js +67 -30
- package/dist/storage/vault-listing.d.ts +3 -0
- package/dist/storage/vault-listing.js +36 -0
- package/dist/storage/vault-reconciliation.d.ts +19 -0
- package/dist/storage/vault-reconciliation.js +137 -0
- package/dist/storage/vault-session.d.ts +8 -0
- package/dist/storage/vault-session.js +10 -2
- package/dist/storage/vault.svelte.d.ts +53 -4
- package/dist/storage/vault.svelte.js +223 -87
- package/dist/sync-host.d.ts +12 -3
- package/dist/sync-host.js +5 -1
- package/dist/vault-change-views.d.ts +4 -0
- package/dist/vault-change-views.js +43 -0
- package/dist/vault-changes.d.ts +37 -0
- package/dist/vault-changes.js +228 -0
- package/dist/view.svelte.d.ts +182 -149
- package/dist/view.svelte.js +11 -2
- package/dist/workspace-close-guard.d.ts +3 -0
- package/dist/workspace-close-guard.js +35 -0
- package/dist/workspace-host-internal.js +10 -2
- package/dist/workspace-layout-normalizer.d.ts +4 -2
- package/dist/workspace-layout-normalizer.js +5 -5
- package/dist/workspace-view-document.d.ts +3 -0
- package/dist/workspace-view-document.js +12 -0
- package/dist/workspace.svelte.d.ts +13 -2
- package/dist/workspace.svelte.js +371 -82
- package/package.json +45 -8
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { connect } from "@tursodatabase/database";
|
|
2
|
+
import fixture from "./fixtures/projection-query.json";
|
|
3
|
+
import { MemoryAppDatabase } from "../storage/app-database";
|
|
4
|
+
import { TursoAppDatabase, } from "../storage/turso-app-database";
|
|
5
|
+
export async function database(native, edges = []) {
|
|
6
|
+
const db = native
|
|
7
|
+
? new TursoAppDatabase("projection-query-contract", {
|
|
8
|
+
kind: "turso-native",
|
|
9
|
+
transport: "native",
|
|
10
|
+
connectionFactory: async () => (await connect(":memory:", {
|
|
11
|
+
experimental: ["index_method"],
|
|
12
|
+
})),
|
|
13
|
+
})
|
|
14
|
+
: new MemoryAppDatabase("projection-query-contract");
|
|
15
|
+
await db.open();
|
|
16
|
+
await db.registerProjectionDefinition({
|
|
17
|
+
projectionId: fixture.projectionId,
|
|
18
|
+
ownerPluginId: "books",
|
|
19
|
+
schemaVersion: 1,
|
|
20
|
+
configHash: "fixture-1",
|
|
21
|
+
visibility: "public",
|
|
22
|
+
fields: {
|
|
23
|
+
title: { type: "string", sortable: true },
|
|
24
|
+
rank: { type: "number", sortable: true },
|
|
25
|
+
optional: { type: "string", indexed: true },
|
|
26
|
+
"literal.key": { type: "string", indexed: true },
|
|
27
|
+
},
|
|
28
|
+
active: true,
|
|
29
|
+
updatedAt: 1,
|
|
30
|
+
});
|
|
31
|
+
for (const row of fixture.rows)
|
|
32
|
+
await db.replaceProjectionSource({
|
|
33
|
+
projectionId: fixture.projectionId,
|
|
34
|
+
sourcePath: `${row.id}.md`,
|
|
35
|
+
sourceHash: "fixture-hash",
|
|
36
|
+
rows: [{ id: row.id, kind: "book", data: row }],
|
|
37
|
+
edges: edges.filter((edge) => edge.sourceRowId === row.id),
|
|
38
|
+
});
|
|
39
|
+
return db;
|
|
40
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { connect } from "@tursodatabase/database";
|
|
2
|
+
import { MemoryAppDatabase, } from "../storage/app-database";
|
|
3
|
+
import { TursoAppDatabase, } from "../storage/turso-app-database";
|
|
4
|
+
import input from "./fixtures/search-retrieval.json";
|
|
5
|
+
export const fixture = input;
|
|
6
|
+
export async function database(native) {
|
|
7
|
+
const db = native
|
|
8
|
+
? new TursoAppDatabase("retrieval", {
|
|
9
|
+
kind: "turso-native",
|
|
10
|
+
transport: "native",
|
|
11
|
+
connectionFactory: async () => (await connect(":memory:", {
|
|
12
|
+
experimental: ["index_method"],
|
|
13
|
+
})),
|
|
14
|
+
})
|
|
15
|
+
: new MemoryAppDatabase("retrieval");
|
|
16
|
+
await db.open();
|
|
17
|
+
for (const { document, properties } of fixture.records) {
|
|
18
|
+
const file = {
|
|
19
|
+
path: document.path,
|
|
20
|
+
normalizedPath: document.path,
|
|
21
|
+
extension: "md",
|
|
22
|
+
mtime: 1,
|
|
23
|
+
size: 1,
|
|
24
|
+
hash: "reference",
|
|
25
|
+
indexed: true,
|
|
26
|
+
};
|
|
27
|
+
await db.upsertIndexedFile({
|
|
28
|
+
file,
|
|
29
|
+
metadata: {
|
|
30
|
+
path: file.path,
|
|
31
|
+
hash: file.hash,
|
|
32
|
+
parserVersion: "fixture",
|
|
33
|
+
metadata: {},
|
|
34
|
+
},
|
|
35
|
+
links: [],
|
|
36
|
+
tags: [],
|
|
37
|
+
properties: Object.entries(properties).map(([name, value]) => ({
|
|
38
|
+
path: file.path,
|
|
39
|
+
name,
|
|
40
|
+
value,
|
|
41
|
+
inferredType: typeof value,
|
|
42
|
+
})),
|
|
43
|
+
});
|
|
44
|
+
await db.upsertSearchDocument(document);
|
|
45
|
+
}
|
|
46
|
+
return db;
|
|
47
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import type { App } from "./context.svelte";
|
|
2
|
+
export declare const APP_SHELL_PLUGINS_PATH: string;
|
|
2
3
|
export interface AppShellPluginPersistenceVault {
|
|
3
4
|
mkpath?(path: string): Promise<unknown>;
|
|
4
5
|
adapter?: {
|
|
@@ -12,4 +13,4 @@ export interface AppShellPluginEnablementPersistence {
|
|
|
12
13
|
load(): Promise<unknown | null>;
|
|
13
14
|
save(enabledById: Record<string, boolean>): Promise<void>;
|
|
14
15
|
}
|
|
15
|
-
export declare function createAppShellPluginPersistence(vault: AppShellPluginPersistenceVaultSource): AppShellPluginEnablementPersistence;
|
|
16
|
+
export declare function createAppShellPluginPersistence(vault: AppShellPluginPersistenceVaultSource, app?: App, apply?: (enabled: Record<string, boolean>) => Promise<void>): AppShellPluginEnablementPersistence;
|
|
@@ -1,17 +1,42 @@
|
|
|
1
|
-
|
|
1
|
+
import { appStatePath, DEFAULT_APP_STATE_DIRECTORY } from "./storage/path";
|
|
2
|
+
import { readFileState, saveFileState } from "./file-state-store";
|
|
3
|
+
export const APP_SHELL_PLUGINS_PATH = appStatePath("app-shell-plugins.json");
|
|
2
4
|
function resolvePluginPersistenceVault(source) {
|
|
3
5
|
if (typeof source === "function") {
|
|
4
6
|
return source() ?? undefined;
|
|
5
7
|
}
|
|
6
8
|
return source ?? undefined;
|
|
7
9
|
}
|
|
8
|
-
export function createAppShellPluginPersistence(vault) {
|
|
10
|
+
export function createAppShellPluginPersistence(vault, app, apply) {
|
|
11
|
+
let resetting = false;
|
|
12
|
+
let snapshot = {};
|
|
13
|
+
const reset = async (text) => {
|
|
14
|
+
const value = JSON.parse(text || "{}");
|
|
15
|
+
if (!value ||
|
|
16
|
+
typeof value !== "object" ||
|
|
17
|
+
Array.isArray(value) ||
|
|
18
|
+
Object.values(value).some((enabled) => typeof enabled !== "boolean"))
|
|
19
|
+
throw new Error("Invalid App Shell plugin configuration");
|
|
20
|
+
resetting = true;
|
|
21
|
+
try {
|
|
22
|
+
await apply?.(value);
|
|
23
|
+
snapshot = value;
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
resetting = false;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
9
29
|
return {
|
|
10
30
|
async load() {
|
|
11
31
|
const adapter = resolvePluginPersistenceVault(vault)?.adapter;
|
|
12
32
|
if (!adapter?.read)
|
|
13
33
|
return null;
|
|
14
34
|
try {
|
|
35
|
+
if (app?.vault.supportsConditionalTextWrites) {
|
|
36
|
+
const raw = await readFileState(app, APP_SHELL_PLUGINS_PATH, reset);
|
|
37
|
+
snapshot = raw ? JSON.parse(raw) : {};
|
|
38
|
+
return raw ? snapshot : null;
|
|
39
|
+
}
|
|
15
40
|
if (adapter.exists && !(await adapter.exists(APP_SHELL_PLUGINS_PATH))) {
|
|
16
41
|
return null;
|
|
17
42
|
}
|
|
@@ -23,11 +48,20 @@ export function createAppShellPluginPersistence(vault) {
|
|
|
23
48
|
}
|
|
24
49
|
},
|
|
25
50
|
async save(enabledById) {
|
|
51
|
+
if (resetting)
|
|
52
|
+
return;
|
|
53
|
+
if (app?.vault.supportsConditionalTextWrites) {
|
|
54
|
+
snapshot = { ...snapshot, ...enabledById };
|
|
55
|
+
await saveFileState(app, APP_SHELL_PLUGINS_PATH, `${JSON.stringify(snapshot, null, 2)}\n`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
26
58
|
const resolved = resolvePluginPersistenceVault(vault);
|
|
27
59
|
const adapter = resolved?.adapter;
|
|
28
60
|
if (!adapter?.write)
|
|
29
61
|
return;
|
|
30
|
-
await resolved
|
|
62
|
+
await resolved
|
|
63
|
+
?.mkpath?.(DEFAULT_APP_STATE_DIRECTORY)
|
|
64
|
+
.catch(() => undefined);
|
|
31
65
|
await adapter.write(APP_SHELL_PLUGINS_PATH, `${JSON.stringify(enabledById, null, 2)}\n`);
|
|
32
66
|
},
|
|
33
67
|
};
|
package/dist/cache.svelte.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ContributionStatus } from "./native-indexing-protocol";
|
|
2
|
+
import type { IndexProjectionRegistration } from "./storage/index-projection";
|
|
1
3
|
import type { App } from "./context.svelte";
|
|
2
4
|
import { EventDispatcher } from "./events";
|
|
3
5
|
import {
|
|
@@ -310,6 +312,7 @@ export declare class MetadataCache extends EventDispatcher<{
|
|
|
310
312
|
readonly logger: import("./logging").Logger;
|
|
311
313
|
private readonly saveSnapshotDebounced;
|
|
312
314
|
constructor(app: App);
|
|
315
|
+
get backgroundIndexing(): import("./native-background-indexing").NativeBackgroundIndexingObserver | undefined;
|
|
313
316
|
get metadataCache(): Record<string, CachedMetadata>;
|
|
314
317
|
get resolvedLinks(): Record<string, Record<string, number>>;
|
|
315
318
|
get unresolvedLinks(): Record<string, Record<string, number>>;
|
|
@@ -552,7 +555,11 @@ export declare class MetadataCache extends EventDispatcher<{
|
|
|
552
555
|
getFirstLinkpathDest(linkpath: string, sourcePath: string): TFile | null;
|
|
553
556
|
fileToLinktext(file: TFile, sourcePath: string, omitMdExtension?: boolean): string;
|
|
554
557
|
rebuild(): Promise<void>;
|
|
555
|
-
|
|
558
|
+
registerNativeProjection(owner: string, id: string, registration: IndexProjectionRegistration): void;
|
|
559
|
+
finishNativeContributions(owner: string): Promise<void>;
|
|
560
|
+
disableNativeContributions(owner: string): Promise<void>;
|
|
561
|
+
get nativeContributionStatuses(): ContributionStatus[];
|
|
562
|
+
addProcessor(ext: string, processor: MetadataProcessor, owner?: string): void;
|
|
556
563
|
removeProcessor(ext: string, processor: MetadataProcessor): boolean;
|
|
557
564
|
addIndexedProjectionContributor(contributor: IndexedProjectionContributor): void;
|
|
558
565
|
removeIndexedProjectionContributor(contributor: IndexedProjectionContributor): boolean;
|
package/dist/cache.svelte.js
CHANGED
|
@@ -5,6 +5,7 @@ import { defaultLinkSettings, getLinkPath, normalizeVaultPath, } from "./links";
|
|
|
5
5
|
import { basename, TFile, } from "./storage";
|
|
6
6
|
import { debounce } from "lodash-es";
|
|
7
7
|
import { dirname, resolvePath } from "./storage/path";
|
|
8
|
+
import { NativeBackgroundIndexingSession, } from "./native-background-indexing";
|
|
8
9
|
export const METADATA_CACHE_BACKUP_PATH = ".lapis/cache/metadata-cache.json";
|
|
9
10
|
export const METADATA_CACHE_HOT_LIMIT = 512;
|
|
10
11
|
const METADATA_RECONCILE_CHECKPOINT_KEY = "metadata-cache.reconcile-checkpoint.v1";
|
|
@@ -226,6 +227,7 @@ export class MetadataCache extends EventDispatcher {
|
|
|
226
227
|
#unresolvedLinks = $state({});
|
|
227
228
|
logger = logging.getLogger("cache");
|
|
228
229
|
disposed = false;
|
|
230
|
+
nativeIndexing;
|
|
229
231
|
didLoad = false;
|
|
230
232
|
loadPromise = null;
|
|
231
233
|
disposePromise = null;
|
|
@@ -249,11 +251,17 @@ export class MetadataCache extends EventDispatcher {
|
|
|
249
251
|
constructor(app) {
|
|
250
252
|
super();
|
|
251
253
|
this.app = app;
|
|
254
|
+
const port = app.session?.backgroundIndexing;
|
|
255
|
+
if (port)
|
|
256
|
+
this.nativeIndexing = new NativeBackgroundIndexingSession(app, port);
|
|
252
257
|
app.vault.on("all", this.handleVaultChange);
|
|
253
258
|
app.vault.on("rename", this.handleVaultRename);
|
|
254
259
|
this.databaseChangeUnsubscribe =
|
|
255
260
|
app.appDatabase.subscribeToChanges?.((change) => this.handleDatabaseChange(change)) ?? null;
|
|
256
261
|
}
|
|
262
|
+
get backgroundIndexing() {
|
|
263
|
+
return this.nativeIndexing;
|
|
264
|
+
}
|
|
257
265
|
get metadataCache() {
|
|
258
266
|
return this.#metadataCache;
|
|
259
267
|
}
|
|
@@ -281,7 +289,7 @@ export class MetadataCache extends EventDispatcher {
|
|
|
281
289
|
return map;
|
|
282
290
|
}
|
|
283
291
|
scheduleSnapshotSave() {
|
|
284
|
-
if (this.disposed || this.snapshotLeaseCount === 0)
|
|
292
|
+
if (this.nativeIndexing || this.disposed || this.snapshotLeaseCount === 0)
|
|
285
293
|
return;
|
|
286
294
|
this.saveSnapshotDebounced();
|
|
287
295
|
}
|
|
@@ -292,7 +300,9 @@ export class MetadataCache extends EventDispatcher {
|
|
|
292
300
|
async dispose(options = {}) {
|
|
293
301
|
if (this.disposePromise)
|
|
294
302
|
return this.disposePromise;
|
|
303
|
+
const nativeTasksDetached = this.app.nativeTasks?.detach();
|
|
295
304
|
this.disposed = true;
|
|
305
|
+
this.nativeIndexing?.dispose();
|
|
296
306
|
this.app.vault.off("all", this.handleVaultChange);
|
|
297
307
|
this.app.vault.off("rename", this.handleVaultRename);
|
|
298
308
|
this.databaseChangeUnsubscribe?.();
|
|
@@ -302,13 +312,20 @@ export class MetadataCache extends EventDispatcher {
|
|
|
302
312
|
this.snapshotLeaseValue = null;
|
|
303
313
|
this.saveSnapshotDebounced.cancel();
|
|
304
314
|
this.disposePromise = (async () => {
|
|
315
|
+
if (nativeTasksDetached)
|
|
316
|
+
await nativeTasksDetached;
|
|
317
|
+
if (this.nativeIndexing)
|
|
318
|
+
return;
|
|
305
319
|
await Promise.allSettled([...this.pendingOperations]);
|
|
306
|
-
|
|
320
|
+
if (!this.nativeIndexing)
|
|
321
|
+
await this.persistReconcileCheckpoint({ allowDisposed: true });
|
|
307
322
|
void options;
|
|
308
323
|
})();
|
|
309
324
|
return this.disposePromise;
|
|
310
325
|
}
|
|
311
326
|
async saveSnapshotNow(_options = {}) {
|
|
327
|
+
if (this.nativeIndexing)
|
|
328
|
+
return;
|
|
312
329
|
const snapshot = await this.buildCompatibilitySnapshot();
|
|
313
330
|
try {
|
|
314
331
|
await this.app.appDatabase.saveMetadataSnapshot(snapshot);
|
|
@@ -345,6 +362,14 @@ export class MetadataCache extends EventDispatcher {
|
|
|
345
362
|
return this.loadPromise;
|
|
346
363
|
}
|
|
347
364
|
async performLoad() {
|
|
365
|
+
if (this.nativeIndexing) {
|
|
366
|
+
await this.nativeIndexing.load();
|
|
367
|
+
if (this.disposed)
|
|
368
|
+
return;
|
|
369
|
+
this.didLoad = true;
|
|
370
|
+
this.trigger("loaded");
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
348
373
|
try {
|
|
349
374
|
await this.app.telemetry.measureAsync("metadata.cache.load", async (loadSpan) => this.app.notifications.withProgress({
|
|
350
375
|
title: "Loading metadata cache",
|
|
@@ -585,8 +610,8 @@ export class MetadataCache extends EventDispatcher {
|
|
|
585
610
|
}
|
|
586
611
|
/**
|
|
587
612
|
* Return the current vault/parser manifest fingerprint used to validate the
|
|
588
|
-
* durable metadata index and disposable indexed-consumer snapshots.
|
|
589
|
-
*
|
|
613
|
+
* durable metadata index and disposable indexed-consumer snapshots. Consumers
|
|
614
|
+
* may restrict the fingerprint to their accepted metadata files.
|
|
590
615
|
*/
|
|
591
616
|
getReconciliationFingerprint(acceptsFile) {
|
|
592
617
|
const fingerprint = new StreamingManifestFingerprint();
|
|
@@ -887,6 +912,8 @@ export class MetadataCache extends EventDispatcher {
|
|
|
887
912
|
}, vaultIndex);
|
|
888
913
|
}
|
|
889
914
|
rebuild(progress) {
|
|
915
|
+
if (this.nativeIndexing)
|
|
916
|
+
return this.nativeIndexing.refresh(true);
|
|
890
917
|
if (progress) {
|
|
891
918
|
return this.performRebuild(progress);
|
|
892
919
|
}
|
|
@@ -945,7 +972,19 @@ export class MetadataCache extends EventDispatcher {
|
|
|
945
972
|
this.markReconcileCheckpointDirty();
|
|
946
973
|
await this.persistReconcileCheckpoint();
|
|
947
974
|
}
|
|
948
|
-
|
|
975
|
+
registerNativeProjection(owner, id, registration) {
|
|
976
|
+
this.nativeIndexing?.registerProjection(owner, id, registration);
|
|
977
|
+
}
|
|
978
|
+
async finishNativeContributions(owner) {
|
|
979
|
+
await this.nativeIndexing?.ready(owner);
|
|
980
|
+
}
|
|
981
|
+
async disableNativeContributions(owner) {
|
|
982
|
+
await this.nativeIndexing?.disable(owner);
|
|
983
|
+
}
|
|
984
|
+
get nativeContributionStatuses() {
|
|
985
|
+
return this.nativeIndexing?.getContributionStatuses() ?? [];
|
|
986
|
+
}
|
|
987
|
+
addProcessor(ext, processor, owner) {
|
|
949
988
|
if (!ext?.trim())
|
|
950
989
|
return;
|
|
951
990
|
ext = ext.trim().toLowerCase();
|
|
@@ -953,6 +992,7 @@ export class MetadataCache extends EventDispatcher {
|
|
|
953
992
|
this.processors.set(ext, new Set());
|
|
954
993
|
}
|
|
955
994
|
this.processors.get(ext).add(processor);
|
|
995
|
+
this.nativeIndexing?.registerProcessor(owner ?? "application", ext);
|
|
956
996
|
}
|
|
957
997
|
removeProcessor(ext, processor) {
|
|
958
998
|
if (!ext?.trim())
|
|
@@ -1064,6 +1104,13 @@ export class MetadataCache extends EventDispatcher {
|
|
|
1064
1104
|
handleDatabaseChange(change) {
|
|
1065
1105
|
if (this.disposed)
|
|
1066
1106
|
return;
|
|
1107
|
+
if (this.nativeIndexing) {
|
|
1108
|
+
this.trackOperation(this.observeNativeChange(change).finally(() => {
|
|
1109
|
+
if (!this.disposed)
|
|
1110
|
+
this.trigger("index-changed", change);
|
|
1111
|
+
}));
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1067
1114
|
if (this.snapshotLeaseCount > 0) {
|
|
1068
1115
|
this.trackOperation(this.refreshCompatibilitySnapshot(change));
|
|
1069
1116
|
}
|
|
@@ -1086,6 +1133,41 @@ export class MetadataCache extends EventDispatcher {
|
|
|
1086
1133
|
}
|
|
1087
1134
|
this.trigger("index-changed", change);
|
|
1088
1135
|
}
|
|
1136
|
+
async observeNativeChange(change) {
|
|
1137
|
+
if (change.reset) {
|
|
1138
|
+
if (this.snapshotLeaseCount > 0)
|
|
1139
|
+
await this.refreshCompatibilitySnapshot(change);
|
|
1140
|
+
else
|
|
1141
|
+
for (const path of [...this.hotPathOrder.keys()])
|
|
1142
|
+
this.evictHotPath(path);
|
|
1143
|
+
}
|
|
1144
|
+
if (change.domains.includes("metadata")) {
|
|
1145
|
+
for (const path of change.paths) {
|
|
1146
|
+
await this.observeNativeFile(path);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
async observeNativeFile(path) {
|
|
1151
|
+
if (this.disposed)
|
|
1152
|
+
return;
|
|
1153
|
+
const row = await this.app.appDatabase.getIndexedFile(path);
|
|
1154
|
+
if (this.disposed)
|
|
1155
|
+
return;
|
|
1156
|
+
this.evictHotPath(path);
|
|
1157
|
+
const file = this.app.vault.getFileByPath(path);
|
|
1158
|
+
if (!row?.metadata)
|
|
1159
|
+
return;
|
|
1160
|
+
this.cacheDatabaseRow(row);
|
|
1161
|
+
if (!file)
|
|
1162
|
+
return;
|
|
1163
|
+
const text = await this.app.vault.read(file);
|
|
1164
|
+
if (this.disposed ||
|
|
1165
|
+
file.path !== path ||
|
|
1166
|
+
!this.app.vault.getFileByPath(path) ||
|
|
1167
|
+
md5(text) !== row.metadata.hash)
|
|
1168
|
+
return;
|
|
1169
|
+
this.trigger("changed", file, text, row.metadata.metadata);
|
|
1170
|
+
}
|
|
1089
1171
|
deferReconcileIndexChange(change) {
|
|
1090
1172
|
if (!this.deferredReconcileIndexChange) {
|
|
1091
1173
|
this.deferredReconcileIndexChange = cloneAppDatabaseChange(change);
|
|
@@ -1187,6 +1269,16 @@ export class MetadataCache extends EventDispatcher {
|
|
|
1187
1269
|
return;
|
|
1188
1270
|
if (!(file instanceof TFile))
|
|
1189
1271
|
return;
|
|
1272
|
+
if (this.nativeIndexing) {
|
|
1273
|
+
if (event === "delete") {
|
|
1274
|
+
this.trigger("deleted", file, this.getCache(file.path));
|
|
1275
|
+
this.evictHotPath(file.path);
|
|
1276
|
+
}
|
|
1277
|
+
else if (event === "create" || event === "modify") {
|
|
1278
|
+
this.trackOperation(this.observeNativeFile(file.path));
|
|
1279
|
+
}
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1190
1282
|
switch (event) {
|
|
1191
1283
|
case "create":
|
|
1192
1284
|
case "modify":
|
|
@@ -1207,6 +1299,12 @@ export class MetadataCache extends EventDispatcher {
|
|
|
1207
1299
|
return;
|
|
1208
1300
|
if (!(file instanceof TFile))
|
|
1209
1301
|
return;
|
|
1302
|
+
if (this.nativeIndexing) {
|
|
1303
|
+
this.evictHotPath(oldPath);
|
|
1304
|
+
this.evictHotPath(file.path);
|
|
1305
|
+
this.trackOperation(this.observeNativeFile(file.path));
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1210
1308
|
const existing = this.fileCache[oldPath];
|
|
1211
1309
|
if (existing) {
|
|
1212
1310
|
this.fileCache[file.path] = {
|
package/dist/command.svelte.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { appStatePath, DEFAULT_APP_STATE_DIRECTORY, normalizePath, } from "./storage/path";
|
|
1
2
|
import { EventDispatcher } from "./events";
|
|
3
|
+
import { TFile as VaultFile } from "./storage/fs";
|
|
4
|
+
import { FileTextStateWriter } from "./file-text-state-writer";
|
|
2
5
|
import { resolveApplication } from "./application-compatibility";
|
|
3
|
-
const HOTKEYS_PATH = "
|
|
6
|
+
const HOTKEYS_PATH = "/" + appStatePath("hotkeys.json");
|
|
4
7
|
const MODIFIER_ORDER = ["Mod", "Ctrl", "Meta", "Alt", "Shift"];
|
|
5
8
|
const WORKSPACE_ROOT_COMMAND_HOST_ID = "root";
|
|
6
9
|
function isModifierValue(value) {
|
|
@@ -63,6 +66,8 @@ export class CommandManager extends EventDispatcher {
|
|
|
63
66
|
editorCommands = $state({});
|
|
64
67
|
bindings = $state({});
|
|
65
68
|
hotkeyOverrides = $state({});
|
|
69
|
+
hotkeysBaseline = null;
|
|
70
|
+
hotkeysWriter;
|
|
66
71
|
constructor(app) {
|
|
67
72
|
super();
|
|
68
73
|
this.app = app;
|
|
@@ -157,13 +162,21 @@ export class CommandManager extends EventDispatcher {
|
|
|
157
162
|
return deduped;
|
|
158
163
|
}
|
|
159
164
|
async loadHotkeys() {
|
|
165
|
+
if (this.hotkeysWriter?.dirty)
|
|
166
|
+
return;
|
|
160
167
|
const file = this.readHotkeyOverrideFile();
|
|
161
168
|
if (!file) {
|
|
169
|
+
this.hotkeysBaseline = null;
|
|
170
|
+
if (this.hotkeysWriter && !this.hotkeysWriter.acceptBaseline(null))
|
|
171
|
+
return;
|
|
162
172
|
this.replaceHotkeyOverrides({});
|
|
163
173
|
return;
|
|
164
174
|
}
|
|
165
175
|
try {
|
|
166
176
|
const raw = await this.app.vault.read(file);
|
|
177
|
+
if (this.hotkeysWriter && !this.hotkeysWriter.acceptBaseline(raw))
|
|
178
|
+
return;
|
|
179
|
+
this.hotkeysBaseline = raw;
|
|
167
180
|
this.replaceHotkeyOverrides(this.normalizeOverrides(JSON.parse(raw)));
|
|
168
181
|
}
|
|
169
182
|
catch (error) {
|
|
@@ -173,14 +186,24 @@ export class CommandManager extends EventDispatcher {
|
|
|
173
186
|
}
|
|
174
187
|
async saveHotkeys() {
|
|
175
188
|
const data = JSON.stringify(this.hotkeyOverrides, null, 2);
|
|
189
|
+
if (this.app.vault.supportsConditionalTextWrites)
|
|
190
|
+
return this.getHotkeysWriter().set(data);
|
|
176
191
|
const file = this.readHotkeyOverrideFile();
|
|
177
192
|
if (file) {
|
|
178
193
|
await this.app.vault.modify(file, data);
|
|
179
194
|
return;
|
|
180
195
|
}
|
|
181
|
-
await this.app.vault.mkpath("
|
|
196
|
+
await this.app.vault.mkpath("/" + DEFAULT_APP_STATE_DIRECTORY);
|
|
182
197
|
await this.app.vault.create(HOTKEYS_PATH, data);
|
|
183
198
|
}
|
|
199
|
+
getHotkeysWriter() {
|
|
200
|
+
if (this.hotkeysWriter)
|
|
201
|
+
return this.hotkeysWriter;
|
|
202
|
+
const file = this.readHotkeyOverrideFile() ??
|
|
203
|
+
new VaultFile(normalizePath(HOTKEYS_PATH), { ctime: 0, mtime: 0, size: 0 }, null);
|
|
204
|
+
this.hotkeysWriter = new FileTextStateWriter(this.app, file, this.hotkeysBaseline, (text) => this.replaceHotkeyOverrides(this.normalizeOverrides(JSON.parse(text || "{}"))));
|
|
205
|
+
return this.hotkeysWriter;
|
|
206
|
+
}
|
|
184
207
|
replaceHotkeyOverrides(overrides) {
|
|
185
208
|
for (const id of Object.keys(this.hotkeyOverrides)) {
|
|
186
209
|
delete this.hotkeyOverrides[id];
|
|
@@ -206,6 +229,8 @@ export class CommandManager extends EventDispatcher {
|
|
|
206
229
|
return this.hasHotkeyOverride(commandId);
|
|
207
230
|
}
|
|
208
231
|
async setHotkeys(commandId, hotkeys) {
|
|
232
|
+
if (this.app.vault.supportsConditionalTextWrites)
|
|
233
|
+
this.getHotkeysWriter().assertEditable();
|
|
209
234
|
this.hotkeyOverrides[commandId] = this.dedupeHotkeys(hotkeys);
|
|
210
235
|
this.rebuildBindings();
|
|
211
236
|
this.emit("hotkeys-updated", {
|
|
@@ -225,6 +250,8 @@ export class CommandManager extends EventDispatcher {
|
|
|
225
250
|
await this.setHotkeys(commandId, this.getEffectiveHotkeys(commandId).filter((candidate) => keyId(candidate) !== removeId));
|
|
226
251
|
}
|
|
227
252
|
async resetHotkeys(commandId) {
|
|
253
|
+
if (this.app.vault.supportsConditionalTextWrites)
|
|
254
|
+
this.getHotkeysWriter().assertEditable();
|
|
228
255
|
delete this.hotkeyOverrides[commandId];
|
|
229
256
|
this.rebuildBindings();
|
|
230
257
|
this.emit("hotkeys-updated", {
|
|
@@ -101,6 +101,8 @@
|
|
|
101
101
|
*/
|
|
102
102
|
[data-ui-component="editor"] .inline-title,
|
|
103
103
|
[data-ui-component="editor"] .cm-editor-inline-title {
|
|
104
|
+
box-sizing: border-box;
|
|
105
|
+
padding-inline-start: var(--ui-editor-inline-title-inset, 0px);
|
|
104
106
|
color: var(--ui-editor-inline-title-color);
|
|
105
107
|
font-family: var(--ui-editor-inline-title-font);
|
|
106
108
|
font-size: var(--ui-editor-inline-title-size);
|
|
@@ -112,12 +114,14 @@
|
|
|
112
114
|
margin-block-end: var(--ui-editor-inline-title-margin-bottom);
|
|
113
115
|
width: 100%;
|
|
114
116
|
white-space: pre-wrap;
|
|
117
|
+
overflow-wrap: anywhere;
|
|
115
118
|
border: none;
|
|
116
119
|
outline: none;
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
[data-ui-component="editor"]
|
|
120
123
|
.cm-editor-inline-title[data-mobile-inline-title="true"] {
|
|
124
|
+
padding-inline-start: 0;
|
|
121
125
|
text-align: center;
|
|
122
126
|
}
|
|
123
127
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { dirname } from "../../storage/path";
|
|
5
5
|
import { WorkspaceLeaf } from "../../workspace.svelte";
|
|
6
6
|
import { editorConfig } from "./editor";
|
|
7
|
+
import { syncInlineTitleAlignment } from "./inline-title-alignment";
|
|
7
8
|
import { ScrollArea } from "@lapismd/design-core/shadcn/scroll-area";
|
|
8
9
|
import { cn } from "../../utils";
|
|
9
10
|
import type { App } from "../../context.svelte";
|
|
@@ -53,10 +54,11 @@
|
|
|
53
54
|
const codeMirror = (node: HTMLDivElement) => {
|
|
54
55
|
let focusTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
55
56
|
const root = node.getRootNode();
|
|
56
|
-
if (root
|
|
57
|
-
editor.view.setRoot(root);
|
|
57
|
+
if (root.nodeType === 9 || root.nodeType === 11) {
|
|
58
|
+
editor.view.setRoot(root as Document | ShadowRoot);
|
|
58
59
|
}
|
|
59
60
|
node.append(editor.view.dom);
|
|
61
|
+
const stopTitleAlignment = syncInlineTitleAlignment(editor.view, node);
|
|
60
62
|
focusTimeout = setTimeout(() => {
|
|
61
63
|
editor.view.focus();
|
|
62
64
|
});
|
|
@@ -64,6 +66,7 @@
|
|
|
64
66
|
return {
|
|
65
67
|
update(qs: string) {},
|
|
66
68
|
destroy() {
|
|
69
|
+
stopTitleAlignment();
|
|
67
70
|
if (focusTimeout !== null) {
|
|
68
71
|
clearTimeout(focusTimeout);
|
|
69
72
|
focusTimeout = null;
|
|
@@ -93,9 +96,20 @@
|
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
98
|
|
|
99
|
+
function titleText(node: HTMLDivElement, name: string) {
|
|
100
|
+
const update = (value: string) => {
|
|
101
|
+
// Native contenteditable input can replace Svelte's original text node.
|
|
102
|
+
// Project committed filenames onto the element, including after renames.
|
|
103
|
+
if (node.textContent !== value) node.textContent = value;
|
|
104
|
+
};
|
|
105
|
+
update(name);
|
|
106
|
+
return { update };
|
|
107
|
+
}
|
|
108
|
+
|
|
96
109
|
function renameDone(evt: KeyboardEvent) {
|
|
97
110
|
if (evt.key == "Enter") {
|
|
98
|
-
|
|
111
|
+
// Focusing the editor commits through onfocusout. Starting another rename
|
|
112
|
+
// here races that same file operation against its original source path.
|
|
99
113
|
editor.view.focus();
|
|
100
114
|
evt.preventDefault();
|
|
101
115
|
}
|
|
@@ -122,6 +136,7 @@
|
|
|
122
136
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
123
137
|
{#if shouldShowDesktopInlineTitle && file}
|
|
124
138
|
<div
|
|
139
|
+
use:titleText={file?.name ?? ""}
|
|
125
140
|
onkeydown={renameDone}
|
|
126
141
|
onfocusout={(evt) =>
|
|
127
142
|
renameFile((evt.target as HTMLDivElement).getText())}
|
|
@@ -131,13 +146,12 @@
|
|
|
131
146
|
autocapitalize="on"
|
|
132
147
|
tabindex="-1"
|
|
133
148
|
enterkeyhint="done"
|
|
134
|
-
>
|
|
135
|
-
{file?.name}
|
|
136
|
-
</div>
|
|
149
|
+
></div>
|
|
137
150
|
{/if}
|
|
138
151
|
{#if shouldShowMobileInlineTitle && file}
|
|
139
152
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
140
153
|
<div
|
|
154
|
+
use:titleText={file?.name ?? ""}
|
|
141
155
|
onkeydown={renameDone}
|
|
142
156
|
onfocusout={(evt) =>
|
|
143
157
|
renameFile((evt.target as HTMLDivElement).getText())}
|
|
@@ -150,9 +164,7 @@
|
|
|
150
164
|
autocapitalize="on"
|
|
151
165
|
tabindex="-1"
|
|
152
166
|
enterkeyhint="done"
|
|
153
|
-
>
|
|
154
|
-
{file?.name}
|
|
155
|
-
</div>
|
|
167
|
+
></div>
|
|
156
168
|
{/if}
|
|
157
169
|
<div use:codeMirror class="cm-editor-content"></div>
|
|
158
170
|
</div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { untrack } from "svelte";
|
|
1
2
|
import { markupEditor } from "./editor";
|
|
2
3
|
export function embeddedEditorContext(options) {
|
|
3
4
|
return {
|
|
@@ -18,5 +19,6 @@ export function resolveEmbeddedEditorExtensions(app, options) {
|
|
|
18
19
|
];
|
|
19
20
|
}
|
|
20
21
|
export function applyEmbeddedEditorExtensions(app, editor, options) {
|
|
21
|
-
|
|
22
|
+
const extensions = resolveEmbeddedEditorExtensions(app, options);
|
|
23
|
+
untrack(() => editor.updateExtensions(extensions));
|
|
22
24
|
}
|