From f78fbf9c1cfc6887ec5e4bf49aeaaabc0ed98667 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 18:57:27 +0000 Subject: [PATCH] feat: move citation cleanup from file-open to a manual command Agent-Logs-Url: https://github.com/joey-kilgore/logos-refs/sessions/383f55cb-7f1b-4c03-b186-272b194aad0a Co-authored-by: joey-kilgore <22432499+joey-kilgore@users.noreply.github.com> --- README.md | 20 +++++++++++++++++++- src/main.ts | 54 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index b373605..9a18bed 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,15 @@ Copy a passage from Logos Bible Software and paste it directly into your Obsidia - Handles page numbers intelligently (single page vs. page ranges) - Assigns unique block IDs for precise reference tracking - Maintains a citation counter for each note -- Automatically removes stale citation backlinks from reference notes when opened - Customizable citation callout type - **Backward compatible** with existing BibTeX code block format +### ๐Ÿงน Clean Stale Citation Backlinks +Remove broken citation entries from reference notes with a single command: +- Checks every backlink in a reference note's `## Citations` section +- Removes entries whose source block no longer exists in the linked note +- Only available when the active note is a reference note (in your refs folder or has a `citekey` frontmatter field) + ### ๐Ÿ“š Generate Bibliography Automatically compile all BibTeX references from your current note into a formatted bibliography: - Scans all links in your document for BibTeX references @@ -209,6 +214,19 @@ After building your reference library, you can export all references to a single This file can be used directly with LaTeX documents or imported into citation managers like Zotero or Mendeley. +### Cleaning Stale Citation Backlinks + +Over time, you may delete or edit citations in your notes, leaving orphaned backlinks in the corresponding reference notes. To clean these up: + +1. Open the reference note you want to clean (e.g., `refs/Wright2013.md`) +2. Use the command palette (Ctrl/Cmd+P) and run **"Clean stale citation backlinks"** +3. The plugin will: + - Check every backlink in the `## Citations` section + - Remove any entry whose source block no longer exists in the linked note + - Show a notice with how many stale entries were removed + +> **Note:** This command is only available when the active note is a reference note (located in your configured refs folder or containing a `citekey` frontmatter field). + ## File Structure & Organization diff --git a/src/main.ts b/src/main.ts index 9d53718..516305c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,30 +26,40 @@ export default class LogosReferencePlugin extends Plugin { async onload() { await this.loadSettings(); - this.registerEvent(this.app.workspace.on('file-open', async (file) => { - if (!(file instanceof TFile) || file.extension !== 'md') { - return; - } - - const folder = this.settings.bibFolder.trim().replace(/\/+$/, ''); - const inReferenceFolder = folder ? file.path.startsWith(`${folder}/`) : false; - const cache = this.app.metadataCache.getFileCache(file); - const hasCitekey = typeof cache?.frontmatter?.citekey === 'string'; - - if (!inReferenceFolder && !hasCitekey) { - return; - } - - try { - const removedCount = await cleanStaleCitationBacklinks(this.app, file); - if (removedCount > 0) { - const pluralSuffix = removedCount === 1 ? '' : 's'; - new Notice(`Cleaned ${removedCount} stale citation backlink${pluralSuffix}.`); + this.addCommand({ + id: 'clean-reference-citations', + name: 'Clean stale citation backlinks', + checkCallback: (checking: boolean) => { + const file = this.app.workspace.getActiveFile(); + if (!(file instanceof TFile)) { + return false; } - } catch (error) { - console.error(`Error cleaning stale citation backlinks for ${file.path}`, error); + const folder = this.settings.bibFolder.trim().replace(/\/+$/, ''); + const inReferenceFolder = folder ? file.path.startsWith(`${folder}/`) : false; + const cache = this.app.metadataCache.getFileCache(file); + const hasCitekey = typeof cache?.frontmatter?.citekey === 'string'; + + if (!inReferenceFolder && !hasCitekey) { + return false; + } + + if (!checking) { + cleanStaleCitationBacklinks(this.app, file).then((removedCount) => { + if (removedCount > 0) { + const pluralSuffix = removedCount === 1 ? '' : 's'; + new Notice(`Cleaned ${removedCount} stale citation backlink${pluralSuffix}.`); + } else { + new Notice('No stale citation backlinks found.'); + } + }).catch((error) => { + console.error(`Error cleaning stale citation backlinks for ${file.path}`, error); + new Notice('Error cleaning citation backlinks. See console for details.'); + }); + } + + return true; } - })); + }); this.addCommand({ id: 'paste-logos-reference',