feat(equation-cache): NO VAULT WIDE scans at startup; remove EquationCache and integrate equation processing directly in LatexLinkProvider

This commit is contained in:
JK 2026-04-20 00:12:52 +02:00
parent bd877592c0
commit bcc862731a
3 changed files with 21 additions and 95 deletions

View file

@ -1,71 +0,0 @@
import { TFile } from 'obsidian';
import LatexReferencer from 'main';
import { EquationBlock } from 'types';
import { processActiveNoteEquations } from 'features/equations/numbering';
export class EquationCache {
private cache: Map<string, Map<string, EquationBlock>> = new Map();
constructor(private plugin: LatexReferencer) { }
/**
* Synchronously gets a cached equation block for a given file path and block ID.
* @param filePath The path of the file to look in.
* @param blockId The block ID of the equation (e.g., 'eq-1234abcd').
* @returns The cached EquationBlock or undefined if not found.
*/
get(filePath: string, blockId: string): EquationBlock | undefined {
return this.cache.get(filePath)?.get(blockId);
}
getEquationsForFile(filePath: string): Map<string, EquationBlock> | undefined {
return this.cache.get(filePath);
}
/**
* Asynchronously reads a file, processes its equations, and updates the cache.
* @param file The file to process.
*/
async updateFile(file: TFile) {
const content = await this.plugin.app.vault.cachedRead(file);
const equations = processActiveNoteEquations(this.plugin, file, content);
if (equations.size > 0) {
this.cache.set(file.path, equations);
} else {
// If there are no equations, ensure the file is removed from the cache
this.cache.delete(file.path);
}
}
/**
* Updates the cache when a file is renamed.
* @param file The file with the new name.
* @param oldPath The previous path of the file.
*/
renameFile(file: TFile, oldPath: string) {
const fileCache = this.cache.get(oldPath);
if (fileCache) {
this.cache.set(file.path, fileCache);
this.cache.delete(oldPath);
}
}
/**
* Removes a file from the cache.
* @param file The file to remove.
*/
removeFile(file: TFile) {
this.cache.delete(file.path);
}
/**
* Builds the entire vault cache at startup.
*/
async buildCache() {
console.log("Latex Referencer: Building equation cache...");
this.cache.clear();
const promises = this.plugin.app.vault.getMarkdownFiles().map(file => this.updateFile(file));
await Promise.all(promises);
console.log(`Latex Referencer: Cache built successfully. Found equations in ${this.cache.size} files.`);
}
}

View file

@ -22,14 +22,21 @@ export class LatexLinkProvider extends Provider {
}
const subpath = parsedLinktext.subpath.substring(2); // remove #^
const subpathMatch = subpath.match(/^(eq-[\w]+)(?:-(\d+))?$/);
const subpathMatch = subpath.match(/^(eq-[\w-]+)(?:-(\d+))?$/);
if (!subpathMatch) return null;
const [, blockId, subIndexStr] = subpathMatch;
const subIndex = subIndexStr ? parseInt(subIndexStr) : undefined;
// Use the cache instead of parsing the file content manually
const targetEquation = this.plugin.equationCache.get(targetFile.path, blockId);
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
const activeFile = activeView?.file;
const activeContent = typeof activeView?.getViewData === 'function' ? activeView.getViewData() : null;
if (!activeFile || activeContent === null || targetFile.path !== activeFile.path) {
return null;
}
const equations = processActiveNoteEquations(this.plugin, activeFile, activeContent);
const targetEquation = equations.get(blockId);
if (targetEquation?.$printName) {
let result: string;

View file

@ -22,7 +22,7 @@ import { EquationBlock } from 'types';
// ADDED: Import our new internal patcher function
import { patchSuggesterWithQuickPreview } from 'features/quick-preview/patcher';
import { EquationCache } from './features/cache/equation-cache';
import { processActiveNoteEquations } from './features/equations/numbering';
import { ExportConfigModal } from "./features/export-pdf/modal";
import { checkAndFixCalloutMath } from 'utils/fixer';
import { traverseFolder } from "./features/export-pdf/utils";
@ -35,29 +35,11 @@ export default class LatexReferencer extends Plugin {
settings: PluginSettings;
editorExtensions: Extension[];
internalProviders: Provider[] = [];
equationCache: EquationCache;
snippetManager: SnippetManager;
async onload() {
await this.loadSettings();
// Caching
this.equationCache = new EquationCache(this);
this.app.workspace.onLayoutReady(async () => {
await this.equationCache.buildCache();
});
// Register event handlers to keep the cache up-to-date
this.registerEvent(this.app.metadataCache.on('changed', async (file) => {
await this.equationCache.updateFile(file);
}));
this.registerEvent(this.app.vault.on('rename', async (file, oldPath) => {
if (file instanceof TFile) this.equationCache.renameFile(file, oldPath);
}));
this.registerEvent(this.app.vault.on('delete', async (file) => {
if (file instanceof TFile) this.equationCache.removeFile(file);
}));
this.internalProviders.push(new LatexLinkProvider(this));
// Snippets
@ -241,8 +223,16 @@ export default class LatexReferencer extends Plugin {
const targetFile = plugin.app.metadataCache.getFirstLinkpathDest(path, sourcePath);
if (targetFile instanceof TFile) {
// Perform a SYNCHRONOUS lookup in our cache
const targetEquation = plugin.equationCache.get(targetFile.path, blockId);
const activeView = plugin.app.workspace.getActiveViewOfType(MarkdownView);
const activeFile = activeView?.file;
const activeContent = typeof activeView?.getViewData === 'function' ? activeView.getViewData() : null;
if (!activeFile || targetFile.path !== activeFile.path || activeContent === null) {
return old.call(this, hoverParent, targetEl, linktext, sourcePath, state);
}
const equations = processActiveNoteEquations(plugin, activeFile, activeContent);
const targetEquation = equations.get(blockId);
if (targetEquation) {
const line = targetEquation.$position.start;