mirror of
https://github.com/andy-stack/vaultkeeper-ai.git
synced 2026-07-22 06:42:03 +00:00
Move replaceCopy function from Copy enum to Helpers module to improve separation of concerns. Add splitFrontmatter and mergeTagsIntoFrontmatter utilities for YAML frontmatter manipulation. Remove unused Beautify prompt and QuickActionsService. Add timeout support to Semaphore.wait(). Remove unused Event.QuickActionsSettingsChanged. Update all imports across AI classes, prompts, services, and tests.
195 lines
No EOL
6.4 KiB
TypeScript
195 lines
No EOL
6.4 KiB
TypeScript
import type VaultkeeperAIPlugin from "main";
|
|
import { Resolve } from "./DependencyService";
|
|
import { Services } from "./Services";
|
|
import type { VaultService } from "./VaultService";
|
|
import { FileEvent } from "Enums/FileEvent";
|
|
import { getAllTags, MetadataCache, TFile, TFolder } from "obsidian";
|
|
import { FileTagMapping } from "Helpers/FileTagMapping";
|
|
import * as fuzzysort from "fuzzysort";
|
|
import { Path } from "Enums/Path";
|
|
import { WikiLinks } from "Helpers/WikiLinks";
|
|
|
|
// Note that 'files' actually refers to both directories and files (Obsidian naming)
|
|
|
|
export class VaultCacheService {
|
|
|
|
public tags: Set<string> = new Set();
|
|
public wikiLinks: WikiLinks = new WikiLinks();
|
|
|
|
private readonly fuzzysortOptions = {
|
|
limit: 10,
|
|
all: false,
|
|
key: "prepared"
|
|
};
|
|
|
|
private readonly plugin: VaultkeeperAIPlugin;
|
|
private readonly vaultService: VaultService;
|
|
private readonly metaDataCache: MetadataCache;
|
|
|
|
private files: Map<string, TFile> = new Map();
|
|
private folders: Map<string, TFolder> = new Map();
|
|
private mapping: FileTagMapping = new FileTagMapping();
|
|
|
|
private preparedTags: { prepared: Fuzzysort.Prepared, tag: string }[] = [];
|
|
private preparedFiles: { prepared: Fuzzysort.Prepared, file: TFile }[] = [];
|
|
private preparedFolders: { prepared: Fuzzysort.Prepared, folder: TFolder }[] = [];
|
|
|
|
private initialised = false;
|
|
|
|
public constructor() {
|
|
this.plugin = Resolve<VaultkeeperAIPlugin>(Services.VaultkeeperAIPlugin);
|
|
this.vaultService = Resolve<VaultService>(Services.VaultService);
|
|
this.metaDataCache = this.plugin.app.metadataCache;
|
|
this.registerFileEvents();
|
|
|
|
this.plugin.app.metadataCache.on("resolved", async () => {
|
|
if (!this.initialised) {
|
|
await this.setupCaches();
|
|
this.initialised = true;
|
|
}
|
|
});
|
|
}
|
|
|
|
public matchTag(input: string): Fuzzysort.KeyResults<{ prepared: Fuzzysort.Prepared, tag: string }> {
|
|
return fuzzysort.go(input.toLowerCase(), this.preparedTags, this.fuzzysortOptions);
|
|
}
|
|
|
|
public matchFile(input: string): Fuzzysort.KeyResults<{ prepared: Fuzzysort.Prepared, file: TFile }> {
|
|
return fuzzysort.go(input.toLowerCase(), this.preparedFiles, this.fuzzysortOptions);
|
|
}
|
|
|
|
public matchFolder(input: string): Fuzzysort.KeyResults<{ prepared: Fuzzysort.Prepared, folder: TFolder }> {
|
|
return fuzzysort.go(input.toLowerCase(), this.preparedFolders, this.fuzzysortOptions);
|
|
}
|
|
|
|
private registerFileEvents() {
|
|
this.vaultService.registerFileEvents((event, file, args) => {
|
|
const shouldCacheNewPath = this.shouldBeCached(file.path);
|
|
const shouldCacheOldPath = args.oldPath ? this.shouldBeCached(args.oldPath) : false;
|
|
|
|
if (!shouldCacheNewPath && !shouldCacheOldPath) {
|
|
return;
|
|
}
|
|
|
|
if (file instanceof TFile) {
|
|
switch (event) {
|
|
case FileEvent.Create:
|
|
if (shouldCacheNewPath) {
|
|
this.wikiLinks.addWikiLink(file);
|
|
this.files.set(file.path, file);
|
|
this.cacheTags(file);
|
|
}
|
|
break;
|
|
|
|
case FileEvent.Modify:
|
|
if (shouldCacheNewPath) {
|
|
const newTags = this.getTags(file);
|
|
const removedTags = this.mapping.updateMapping(file.path, newTags);
|
|
removedTags.forEach(tag => this.tags.delete(tag));
|
|
this.cacheTags(file, newTags);
|
|
}
|
|
break;
|
|
|
|
case FileEvent.Rename:
|
|
if (shouldCacheOldPath) {
|
|
this.wikiLinks.removeWikiLink(args.oldPath);
|
|
this.files.delete(args.oldPath);
|
|
const orphanedTags = this.mapping.deleteFromMapping(args.oldPath);
|
|
orphanedTags.forEach(tag => this.tags.delete(tag));
|
|
}
|
|
if (shouldCacheNewPath) {
|
|
this.wikiLinks.addWikiLink(file);
|
|
this.mapping.renameKey(args.oldPath, file.path);
|
|
this.files.set(file.path, file);
|
|
this.cacheTags(file);
|
|
}
|
|
break;
|
|
|
|
case FileEvent.Delete:
|
|
this.wikiLinks.removeWikiLink(file);
|
|
this.files.delete(file.path);
|
|
this.mapping.deleteFromMapping(file.path).forEach(tag => this.tags.delete(tag));
|
|
break;
|
|
}
|
|
this.fuzzySortPrepareTags();
|
|
this.fuzzySortPrepareFiles();
|
|
} else if (file instanceof TFolder) {
|
|
switch (event) {
|
|
case FileEvent.Create:
|
|
if (shouldCacheNewPath) {
|
|
this.folders.set(file.path, file);
|
|
}
|
|
break;
|
|
|
|
case FileEvent.Rename:
|
|
if (shouldCacheOldPath) {
|
|
this.folders.delete(args.oldPath);
|
|
}
|
|
if (shouldCacheNewPath) {
|
|
this.folders.set(file.path, file);
|
|
}
|
|
break;
|
|
|
|
case FileEvent.Delete:
|
|
this.folders.delete(file.path);
|
|
break;
|
|
|
|
case FileEvent.Modify:
|
|
break; // ignore modifications for folders
|
|
}
|
|
this.fuzzySortPrepareFolders();
|
|
}
|
|
});
|
|
}
|
|
|
|
private async setupCaches() {
|
|
(await this.vaultService.listDirectoryContents(Path.Root)).forEach(file => {
|
|
if (file instanceof TFile) {
|
|
this.wikiLinks.addWikiLink(file);
|
|
this.files.set(file.path, file);
|
|
this.cacheTags(file);
|
|
} else if (file instanceof TFolder) {
|
|
this.folders.set(file.path, file);
|
|
}
|
|
});
|
|
this.fuzzySortPrepareTags();
|
|
this.fuzzySortPrepareFiles();
|
|
this.fuzzySortPrepareFolders();
|
|
}
|
|
|
|
private cacheTags(file: TFile, fileTags?: string[]) {
|
|
const tags = fileTags ?? this.getTags(file);
|
|
tags.forEach(tag => this.tags.add(tag));
|
|
this.mapping.set(file.path, tags);
|
|
}
|
|
|
|
private getTags(file: TFile): string[] {
|
|
const metaData = this.metaDataCache.getCache(file.path);
|
|
return metaData ? (getAllTags(metaData) ?? []) : [];
|
|
}
|
|
|
|
private fuzzySortPrepareTags() {
|
|
this.preparedTags = [];
|
|
this.tags.forEach(tag => {
|
|
this.preparedTags.push({ prepared: fuzzysort.prepare(tag), tag: tag });
|
|
});
|
|
}
|
|
|
|
private fuzzySortPrepareFiles() {
|
|
this.preparedFiles = [];
|
|
this.files.forEach(file => {
|
|
this.preparedFiles.push({ prepared: fuzzysort.prepare(file.basename), file: file });
|
|
});
|
|
}
|
|
|
|
private fuzzySortPrepareFolders() {
|
|
this.preparedFolders = [];
|
|
this.folders.forEach(folder => {
|
|
this.preparedFolders.push({ prepared: fuzzysort.prepare(folder.path), folder: folder });
|
|
});
|
|
}
|
|
|
|
private shouldBeCached(path: string) {
|
|
return !this.vaultService.isExclusion(path, false);
|
|
}
|
|
} |