add cite reference command

This commit is contained in:
Jacob Williams 2025-02-05 11:52:15 -08:00
parent 7c3302944c
commit 61766f9fe1
2 changed files with 75 additions and 2 deletions

62
main.ts
View file

@ -1,5 +1,5 @@
import { Editor, MarkdownView, Plugin, TFile, parseYaml, Notice } from 'obsidian';
import { parseQuote, Quote, replaceDoubleQuotes, guessCiteId, CslReference } from 'src/quotes';
import { Editor, MarkdownView, Plugin, TFile, parseYaml, Notice, FuzzySuggestModal, App, FuzzyMatch } from 'obsidian';
import { parseQuote, Quote, replaceDoubleQuotes, guessCiteId, CslReference, cslReferenceSummary } from 'src/quotes';
export default class PasteQuotePlugin extends Plugin {
async onload() {
@ -14,6 +14,12 @@ export default class PasteQuotePlugin extends Plugin {
name: 'Paste CSL YAML',
editorCallback: this.pasteCslYaml.bind(this),
});
this.addCommand({
id: 'cite-reference',
name: 'Cite Reference',
editorCallback: this.citeReference.bind(this),
});
}
async pasteQuote(editor: Editor, view: MarkdownView) {
@ -123,7 +129,59 @@ export default class PasteQuotePlugin extends Plugin {
});
}
async citeReference(editor: Editor, view: MarkdownView) {
if (!view.file) {
return;
}
const fileCache = this.app.metadataCache.getFileCache(view.file);
const references = fileCache?.frontmatter?.references || [];
if (!references || references.length === 0) {
new Notice('Cite Reference failed: no references found in front matter');
return;
}
const modal = new ReferenceSuggestModal(this.app, references, (citeId) => {
const citation = `[@${citeId}]`;
const cursorPosition = editor.getCursor();
editor.replaceRange(citation, cursorPosition);
// move cursor to just before the closing bracket
editor.setCursor(editor.offsetToPos(editor.posToOffset(cursorPosition) + citation.length - 1));
});
modal.open();
}
onunload() {
}
}
interface SearchableReference {
id: string,
text: string,
}
class ReferenceSuggestModal extends FuzzySuggestModal<SearchableReference> {
private references: CslReference[];
private onChooseReference: (id: string) => void;
constructor(app: App, references: CslReference[], onChooseReference: (id: string) => void) {
super(app);
this.references = references;
this.onChooseReference = onChooseReference;
}
getItemText(item: SearchableReference): string {
return item.text;
}
getItems(): SearchableReference[] {
return this.references.map(r => ({id: r.id, text: cslReferenceSummary(r)}));
}
onChooseItem(item: SearchableReference, evt: MouseEvent | KeyboardEvent): void {
this.onChooseReference(item.id);
}
}

View file

@ -15,6 +15,12 @@ export interface CslReference {
id: string,
title?: string,
author?: CslAuthor[],
editor?: CslAuthor[],
issued?: CslDate[],
}
export interface CslDate {
year?: number,
}
export function parseQuote(raw: string): Quote {
@ -78,3 +84,12 @@ export function guessCiteId(title: string, refs: CslReference[]): string | null
const st = searchableTitle(title);
return refs.find((ref) => searchableTitle(ref.title || "") === st)?.id || null;
}
export function cslReferenceSummary(ref: CslReference): string {
let authors = [...(ref.editor || []), ...(ref.author || [])];
authors = authors.slice(0, 4);
let authorString = authors.map(a => a.family || a.given).join(' ');
let dateString = (ref.issued && ref.issued.length > 0 && ref.issued[0].year) ? ref.issued[0].year : '';
let titleString = ref.title || '';
return [authorString, dateString, titleString].join(' ');
}