mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Share vault reference providers across chat panels
This commit is contained in:
parent
e9ca2b0448
commit
c0e4fc590c
3 changed files with 109 additions and 0 deletions
|
|
@ -13,6 +13,42 @@ interface EventSource {
|
|||
}
|
||||
|
||||
export class VaultComposerContextReferenceProvider implements ComposerContextReferenceProvider {
|
||||
private readonly shared: SharedComposerContext;
|
||||
private disposed = false;
|
||||
|
||||
constructor(private readonly app: App) {
|
||||
const existing = sharedComposerContexts.get(app);
|
||||
if (existing) {
|
||||
existing.consumers += 1;
|
||||
this.shared = existing;
|
||||
return;
|
||||
}
|
||||
this.shared = { tracker: new VaultComposerContextTracker(app), consumers: 1 };
|
||||
sharedComposerContexts.set(app, this.shared);
|
||||
}
|
||||
|
||||
contextReferences(sourcePath: string): ComposerContextReferences {
|
||||
return this.shared.tracker.contextReferences(sourcePath);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (this.disposed) return;
|
||||
this.disposed = true;
|
||||
this.shared.consumers -= 1;
|
||||
if (this.shared.consumers > 0) return;
|
||||
this.shared.tracker.dispose();
|
||||
sharedComposerContexts.delete(this.app);
|
||||
}
|
||||
}
|
||||
|
||||
interface SharedComposerContext {
|
||||
readonly tracker: VaultComposerContextTracker;
|
||||
consumers: number;
|
||||
}
|
||||
|
||||
const sharedComposerContexts = new WeakMap<App, SharedComposerContext>();
|
||||
|
||||
class VaultComposerContextTracker {
|
||||
private readonly unregisterEvents: (() => void)[] = [];
|
||||
private lastMarkdownView: MarkdownView | null = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,51 @@ interface MetadataCacheWithTags {
|
|||
getTags?: () => unknown;
|
||||
}
|
||||
|
||||
interface SharedCandidateCatalog {
|
||||
readonly catalog: VaultNoteCandidateCatalog;
|
||||
consumers: number;
|
||||
}
|
||||
|
||||
const candidateCatalogs = new WeakMap<App, SharedCandidateCatalog>();
|
||||
|
||||
export class VaultNoteCandidateProvider implements NoteCandidateProvider {
|
||||
private readonly shared: SharedCandidateCatalog;
|
||||
private disposed = false;
|
||||
|
||||
constructor(private readonly app: App) {
|
||||
const existing = candidateCatalogs.get(app);
|
||||
if (existing) {
|
||||
existing.consumers += 1;
|
||||
this.shared = existing;
|
||||
return;
|
||||
}
|
||||
this.shared = { catalog: new VaultNoteCandidateCatalog(app), consumers: 1 };
|
||||
candidateCatalogs.set(app, this.shared);
|
||||
}
|
||||
|
||||
candidates(sourcePath: string): readonly NoteCandidate[] {
|
||||
return this.shared.catalog.candidates(sourcePath);
|
||||
}
|
||||
|
||||
tags(): readonly string[] {
|
||||
return this.shared.catalog.tags();
|
||||
}
|
||||
|
||||
resolveMention(target: string, sourcePath: string): WikiLinkMention | null {
|
||||
return this.shared.catalog.resolveMention(target, sourcePath);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (this.disposed) return;
|
||||
this.disposed = true;
|
||||
this.shared.consumers -= 1;
|
||||
if (this.shared.consumers > 0) return;
|
||||
this.shared.catalog.dispose();
|
||||
candidateCatalogs.delete(this.app);
|
||||
}
|
||||
}
|
||||
|
||||
class VaultNoteCandidateCatalog {
|
||||
private readonly unregisterEvents: (() => void)[] = [];
|
||||
private fileCandidatesCache: FileCandidate[] | null = null;
|
||||
private tagCandidatesCache: string[] | null = null;
|
||||
|
|
|
|||
|
|
@ -147,6 +147,23 @@ describe("VaultNoteCandidateProvider", () => {
|
|||
expect(app.offref).toHaveBeenCalledTimes(6);
|
||||
});
|
||||
|
||||
it("shares candidate caches and event subscriptions across panel providers", () => {
|
||||
const getFiles = vi.fn(() => vaultFiles([{ basename: "Alpha", path: "Alpha.md", stat: { mtime: 1 } }]));
|
||||
const app = appFixture({ getFiles });
|
||||
const first = new VaultNoteCandidateProvider(app);
|
||||
const second = new VaultNoteCandidateProvider(app);
|
||||
|
||||
first.candidates("Inbox.md");
|
||||
second.candidates("Inbox.md");
|
||||
first.dispose();
|
||||
|
||||
expect(getFiles).toHaveBeenCalledOnce();
|
||||
expect(app.offref).not.toHaveBeenCalled();
|
||||
|
||||
second.dispose();
|
||||
expect(app.offref).toHaveBeenCalledTimes(6);
|
||||
});
|
||||
|
||||
it("resolves wikilinks through metadata cache before direct path fallback", () => {
|
||||
const linked = tFile("notes/Alpha.md", "Alpha");
|
||||
const direct = tFile("Alpha.md", "Alpha direct");
|
||||
|
|
@ -218,6 +235,18 @@ describe("VaultNoteCandidateProvider", () => {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("shares active-view event tracking across panel context providers", () => {
|
||||
const app = appFixture();
|
||||
const first = new VaultComposerContextReferenceProvider(app);
|
||||
const second = new VaultComposerContextReferenceProvider(app);
|
||||
|
||||
first.dispose();
|
||||
expect(app.offref).not.toHaveBeenCalled();
|
||||
|
||||
second.dispose();
|
||||
expect(app.offref).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
interface AppFixture extends App {
|
||||
|
|
|
|||
Loading…
Reference in a new issue