From bdca2c610f4f9f138eda1b1df87594459cd5ccd3 Mon Sep 17 00:00:00 2001 From: Rosemary1812 Date: Wed, 6 May 2026 00:37:45 +0800 Subject: [PATCH] fix(excerpt): fix excerpt deletion and dedupe --- DualLinkManager.ts | 135 ++++++++++++++++++++++++++++++++------------- SidecarView.ts | 9 +-- main.js | 8 +-- settings.ts | 1 + 4 files changed, 106 insertions(+), 47 deletions(-) diff --git a/DualLinkManager.ts b/DualLinkManager.ts index 491be40..852ab10 100644 --- a/DualLinkManager.ts +++ b/DualLinkManager.ts @@ -31,13 +31,15 @@ export class DualLinkManager implements SidecarViewController { private rightLeaf: WorkspaceLeaf | null = null; private view: SidecarView | null = null; private leftEditor: Editor | null = null; - private pendingQuotes = new Set(); private saveTimer: ReturnType | null = null; private syncTimer: ReturnType | null = null; private reconcileTimer: ReturnType | null = null; private excerptMode = true; private isClosingLeaf = false; private autoOpenSuspended = false; + private lastCaptureKey: string | null = null; + private lastCaptureAt = 0; + private sourceMutationQueue: Promise = Promise.resolve(); private onBoundMouseUp = () => this.syncSelection(); private onBoundKeyUp = () => this.syncSelection(); @@ -130,7 +132,17 @@ export class DualLinkManager implements SidecarViewController { const entry = workbench?.entries.find((item) => item.id === id); if (!entry) return; - Object.assign(entry, patch); + if (typeof patch.quote === "string") { + const nextQuote = patch.quote.trim(); + if (nextQuote) { + entry.quote = nextQuote; + } + } + + if (typeof patch.note === "string") { + entry.note = patch.note; + } + this.queueSave(); } @@ -152,11 +164,14 @@ export class DualLinkManager implements SidecarViewController { if (!entry) return; if (entry.kind === "excerpt") { - await this.revertExcerptMarkupInSource(entry); + const reverted = await this.revertExcerptMarkupInSource(entry); + if (!reverted) { + new Notice("Could not remove the source highlight for this excerpt."); + return; + } } workbench.entries = workbench.entries.filter((item) => item.id !== id); - this.pendingQuotes.delete(id); this.view?.removeEntry(id); this.queueSave(); } @@ -201,7 +216,8 @@ export class DualLinkManager implements SidecarViewController { this.rightLeaf = null; this.view = null; this.leftEditor = null; - this.pendingQuotes.clear(); + this.lastCaptureKey = null; + this.lastCaptureAt = 0; if (options.suspendAutoOpen) { this.autoOpenSuspended = true; } @@ -309,34 +325,40 @@ export class DualLinkManager implements SidecarViewController { const trimmed = selection.trim(); if (!trimmed) return; + const workbench = this.getCurrentWorkbench(); + if (!workbench) return; + if (!this.shouldCaptureSelection(trimmed)) return; + + const entry = this.createEntry(trimmed, "excerpt"); + workbench.entries.push(entry); + this.view?.addEntry(entry); + this.queueSave(); + this.markSelectionCaptured(trimmed); + const formatted = this.formatSelection(trimmed); if (formatted !== selection) { this.leftEditor.replaceSelection(formatted); } - - this.addExcerptFromSelection(trimmed); - } - - private addExcerptFromSelection(quote: string): void { - const workbench = this.getCurrentWorkbench(); - if (!workbench) return; - - const normalized = quote.trim(); - if (!normalized || this.pendingQuotes.has(normalized)) return; - if (workbench.entries.some((entry) => entry.quote.trim() === normalized)) return; - - this.pendingQuotes.add(normalized); - const entry = this.createEntry(normalized, "excerpt"); - workbench.entries.push(entry); - this.view?.addEntry(entry); - this.queueSave(); - this.pendingQuotes.delete(normalized); } private formatSelection(selection: string): string { return this.applySourceFormat(selection, this.data.settings.leftExcerptFormat); } + private shouldCaptureSelection(selection: string): boolean { + if (!this.sourceFile) return false; + + const key = `${this.sourceFile.path}::${selection.trim()}`; + return !(this.lastCaptureKey === key && Date.now() - this.lastCaptureAt < 250); + } + + private markSelectionCaptured(selection: string): void { + if (!this.sourceFile) return; + + this.lastCaptureKey = `${this.sourceFile.path}::${selection.trim()}`; + this.lastCaptureAt = Date.now(); + } + private applySourceFormat(selection: string, format: LeftExcerptFormat): string { const lines = selection .split("\n") @@ -383,6 +405,7 @@ export class DualLinkManager implements SidecarViewController { id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, kind, quote, + sourceQuote: kind === "excerpt" ? quote : undefined, note: "", noteOpen: kind === "note", sourceFormat: kind === "excerpt" ? this.data.settings.leftExcerptFormat : undefined, @@ -565,16 +588,28 @@ export class DualLinkManager implements SidecarViewController { return path.replace(/\.md$/i, ""); } - private async revertExcerptMarkupInSource(entry: ExcerptEntry): Promise { - if (!this.sourceFile || entry.kind !== "excerpt") return; + private async revertExcerptMarkupInSource(entry: ExcerptEntry): Promise { + if (!this.sourceFile || entry.kind !== "excerpt") return false; - await this.app.vault.process(this.sourceFile, (content) => { - const formattedQuote = this.findSourceExcerptVariant(content, entry); - if (!formattedQuote || formattedQuote === entry.quote) return content; + return this.runSourceMutation(async () => { + let reverted = false; - const index = content.indexOf(formattedQuote); - if (index === -1) return content; - return `${content.slice(0, index)}${entry.quote}${content.slice(index + formattedQuote.length)}`; + await this.app.vault.process(this.sourceFile as TFile, (content) => { + const formattedQuote = this.findSourceExcerptVariant(content, entry); + const sourceQuote = entry.sourceQuote ?? entry.quote; + if (!formattedQuote || formattedQuote === sourceQuote) { + reverted = formattedQuote === sourceQuote; + return content; + } + + const index = content.indexOf(formattedQuote); + if (index === -1) return content; + + reverted = true; + return `${content.slice(0, index)}${sourceQuote}${content.slice(index + formattedQuote.length)}`; + }); + + return reverted; }); } @@ -606,22 +641,47 @@ export class DualLinkManager implements SidecarViewController { } private findSourceExcerptVariant(sourceContent: string, entry: ExcerptEntry): string | null { + const match = this.findSourceExcerptVariantForQuote( + sourceContent, + entry.sourceQuote ?? entry.quote, + entry.sourceFormat + ); + if (!match) { + return null; + } + + entry.sourceFormat = match.format; + return match.text; + } + + private findSourceExcerptVariantForQuote( + sourceContent: string, + quote: string, + preferredFormat?: LeftExcerptFormat + ): { text: string; format: LeftExcerptFormat } | null { const formats: LeftExcerptFormat[] = ["highlight", "bold", "italic", "none"]; - const preferred = entry.sourceFormat; - const candidates = preferred - ? [preferred, ...formats.filter((format) => format !== preferred)] + const candidates = preferredFormat + ? [preferredFormat, ...formats.filter((format) => format !== preferredFormat)] : formats; for (const format of candidates) { - const variant = this.applySourceFormat(entry.quote, format); + const variant = this.applySourceFormat(quote, format); if (sourceContent.includes(variant)) { - entry.sourceFormat = format; - return variant; + return { + text: variant, + format, + }; } } return null; } + + private runSourceMutation(task: () => Promise): Promise { + const next = this.sourceMutationQueue.then(task, task); + this.sourceMutationQueue = next.then(() => undefined, () => undefined); + return next; + } } export function normalizePluginData(raw: unknown): SidecarPluginData { @@ -640,6 +700,7 @@ export function normalizePluginData(raw: unknown): SidecarPluginData { for (const entry of workbench.entries) { entry.kind = entry.kind ?? (entry.quote.trim() ? "excerpt" : "note"); entry.noteOpen = entry.noteOpen ?? entry.kind === "note"; + entry.sourceQuote = entry.kind === "excerpt" ? (entry.sourceQuote ?? entry.quote) : undefined; entry.sourceFormat = entry.kind === "excerpt" ? entry.sourceFormat : undefined; } } diff --git a/SidecarView.ts b/SidecarView.ts index 9cd4fb4..d86dc92 100644 --- a/SidecarView.ts +++ b/SidecarView.ts @@ -214,8 +214,7 @@ export class SidecarView extends ItemView { cls: "sidecar-editor-button sidecar-editor-button--primary", text: "Save", }).addEventListener("click", () => { - entry.quote = textarea.value; - this.controller?.updateEntry(entry.id, { quote: entry.quote }); + void this.controller?.updateEntry(entry.id, { quote: textarea.value }); this.editingQuotes.delete(entry.id); this.renderEntryList(); }); @@ -292,9 +291,8 @@ export class SidecarView extends ItemView { cls: "sidecar-editor-button sidecar-editor-button--primary", text: "Save", }).addEventListener("click", () => { - entry.note = textarea.value; entry.noteOpen = false; - this.controller?.updateEntry(entry.id, { note: entry.note }); + void this.controller?.updateEntry(entry.id, { note: textarea.value }); this.editingNotes.delete(entry.id); this.renderEntryList(); }); @@ -350,8 +348,7 @@ export class SidecarView extends ItemView { cls: "sidecar-editor-button sidecar-editor-button--primary", text: "Save", }).addEventListener("click", () => { - entry.note = noteTextarea?.value ?? ""; - this.controller?.updateEntry(entry.id, { note: entry.note }); + void this.controller?.updateEntry(entry.id, { note: noteTextarea?.value ?? "" }); this.editingNotes.delete(entry.id); this.renderEntryList(); }); diff --git a/main.js b/main.js index 82c41f7..435f6a6 100644 --- a/main.js +++ b/main.js @@ -1,9 +1,9 @@ -"use strict";var S=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var P=(s,i)=>{for(var e in i)S(s,e,{get:i[e],enumerable:!0})},W=(s,i,e,t)=>{if(i&&typeof i=="object"||typeof i=="function")for(let r of M(i))!C.call(s,r)&&r!==e&&S(s,r,{get:()=>i[r],enumerable:!(t=D(i,r))||t.enumerable});return s};var N=s=>W(S({},"__esModule",{value:!0}),s);var A={};P(A,{default:()=>y});module.exports=N(A);var w=require("obsidian");var a=require("obsidian");var p=require("obsidian"),h="sidecar-excerpt-workbench",u=class extends p.ItemView{constructor(e){super(e);this.controller=null;this.workbench={entries:[]};this.settings=null;this.title="Sidecar Notes";this.excerptMode=!0;this.listEl=null;this.modeButton=null;this.emptyEl=null;this.entryEls=new Map;this.editingQuotes=new Set;this.editingNotes=new Set;this.expandedQuotes=new Set}getViewType(){return h}getDisplayText(){return this.title}getIcon(){return"quote"}setController(e){this.controller=e}setWorkbench(e,t,r,n){this.workbench=e,this.title=t,this.excerptMode=r,this.settings=n,this.render()}applySettings(e){this.settings=e,this.contentEl.style.setProperty("--sidecar-preview-font-size",`${e.summaryFontSize}px`)}addEntry(e){this.workbench.entries.some(t=>t.id===e.id)||this.workbench.entries.push(e),e.kind==="note"&&!e.note.trim()&&this.editingNotes.add(e.id),this.appendEntry(e),this.updateEmptyState()}updateExcerptMode(e){this.excerptMode=e,this.updateModeButton()}removeEntry(e){this.entryEls.get(e)?.root.remove(),this.entryEls.delete(e),this.editingQuotes.delete(e),this.editingNotes.delete(e),this.expandedQuotes.delete(e),this.workbench.entries=this.workbench.entries.filter(t=>t.id!==e),this.updateEmptyState()}onOpen(){return this.render(),Promise.resolve()}onClose(){return this.controller?.handleWorkbenchClosed(),this.entryEls.clear(),this.editingQuotes.clear(),this.editingNotes.clear(),this.expandedQuotes.clear(),Promise.resolve()}render(){let{contentEl:e}=this;e.empty(),e.addClass("sidecar-workbench"),this.settings&&this.applySettings(this.settings);let t=e.createDiv({cls:"sidecar-workbench__header"}),r=t.createDiv({cls:"sidecar-workbench__title-group"});r.createEl("span",{cls:"sidecar-workbench__eyebrow",text:"Excerpt workbench"}),r.createEl("h2",{text:this.title});let n=t.createDiv({cls:"sidecar-workbench__actions"});this.modeButton=n.createEl("button",{cls:"sidecar-mode-button"}),this.modeButton.addEventListener("click",()=>{this.controller?.setExcerptMode(!this.excerptMode)}),this.updateModeButton(),n.createEl("button",{cls:"sidecar-command-button",text:"Sync"}).addEventListener("click",()=>{this.controller?.exportMarkdown()}),n.createEl("button",{cls:"sidecar-command-button",text:"+ note"}).addEventListener("click",()=>{this.controller?.addNoteEntry()}),this.emptyEl=e.createDiv({cls:"sidecar-workbench__empty",text:"Turn on excerpt mode, then select text in the source note."}),this.listEl=e.createDiv({cls:"sidecar-workbench__list"}),this.renderEntryList()}renderEntryList(){if(this.listEl){this.listEl.empty(),this.entryEls.clear();for(let e of this.workbench.entries)this.appendEntry(e);this.updateEmptyState()}}appendEntry(e){if(this.listEl){if(e.kind==="note"){this.appendNoteEntry(e);return}this.appendExcerptEntry(e)}}appendExcerptEntry(e){if(!this.listEl)return;let t=this.listEl.createDiv({cls:"sidecar-entry sidecar-entry--excerpt"});t.dataset.entryId=e.id;let r=this.renderExcerptSection(t,e),n=this.renderExcerptNoteSection(t,e);this.entryEls.set(e.id,{root:t,quoteTextarea:r,noteTextarea:n})}renderExcerptSection(e,t){let r=e.createDiv({cls:"sidecar-section sidecar-section--excerpt"}),n=r.createDiv({cls:"sidecar-section__header"});n.createEl("span",{cls:"sidecar-section__label",text:"Excerpt"});let o=n.createDiv({cls:"sidecar-icon-actions"});if(this.editingQuotes.has(t.id)){let k=r.createEl("textarea",{cls:"sidecar-entry__editor",text:t.quote});k.rows=5;let b=r.createDiv({cls:"sidecar-editor-actions"});return b.createEl("button",{cls:"sidecar-editor-button sidecar-editor-button--primary",text:"Save"}).addEventListener("click",()=>{t.quote=k.value,this.controller?.updateEntry(t.id,{quote:t.quote}),this.editingQuotes.delete(t.id),this.renderEntryList()}),b.createEl("button",{cls:"sidecar-editor-button",text:"Cancel"}).addEventListener("click",()=>{this.editingQuotes.delete(t.id),this.renderEntryList()}),k}this.createIconButton(o,"pencil","Edit excerpt").addEventListener("click",()=>{this.editingQuotes.add(t.id),this.renderEntryList()}),this.createIconButton(o,"trash-2","Delete excerpt").addEventListener("click",()=>{this.controller?.deleteEntry(t.id)});let g=this.isLongQuote(t.quote),d=this.expandedQuotes.has(t.id),v=r.createDiv({cls:g&&!d?"sidecar-entry__preview sidecar-entry__preview--collapsed":"sidecar-entry__preview"});return this.renderMarkdown(v,t.quote),g&&r.createEl("button",{cls:"sidecar-expand-button",text:d?"Less":"More"}).addEventListener("click",()=>{this.expandedQuotes.has(t.id)?this.expandedQuotes.delete(t.id):this.expandedQuotes.add(t.id),this.renderEntryList()}),null}renderExcerptNoteSection(e,t){if(!t.note.trim()&&!this.editingNotes.has(t.id))return e.createEl("button",{cls:"sidecar-add-note-button",text:"+ add note"}).addEventListener("click",()=>{this.editingNotes.add(t.id),this.renderEntryList()}),null;let r=e.createDiv({cls:"sidecar-section sidecar-section--note"}),n=r.createDiv({cls:"sidecar-section__header"});n.createEl("span",{cls:"sidecar-section__label",text:"Note"});let o=n.createDiv({cls:"sidecar-icon-actions"});if(this.editingNotes.has(t.id)){let d=r.createEl("textarea",{cls:"sidecar-entry__editor",text:t.note});d.rows=6;let v=r.createDiv({cls:"sidecar-editor-actions"});return v.createEl("button",{cls:"sidecar-editor-button sidecar-editor-button--primary",text:"Save"}).addEventListener("click",()=>{t.note=d.value,t.noteOpen=!1,this.controller?.updateEntry(t.id,{note:t.note}),this.editingNotes.delete(t.id),this.renderEntryList()}),v.createEl("button",{cls:"sidecar-editor-button",text:"Cancel"}).addEventListener("click",()=>{this.editingNotes.delete(t.id),this.renderEntryList()}),d}this.createIconButton(o,"pencil","Edit note").addEventListener("click",()=>{this.editingNotes.add(t.id),this.renderEntryList()}),this.createIconButton(o,"trash-2","Delete note").addEventListener("click",()=>{t.note="",t.noteOpen=!1,this.controller?.deleteNote(t.id),this.renderEntryList()});let g=r.createDiv({cls:"sidecar-entry__preview"});return this.renderMarkdown(g,t.note),null}appendNoteEntry(e){if(!this.listEl)return;let t=this.listEl.createDiv({cls:"sidecar-entry sidecar-entry--note"});t.dataset.entryId=e.id;let r=t.createDiv({cls:"sidecar-section sidecar-section--standalone-note"}),n=r.createDiv({cls:"sidecar-section__header"});n.createEl("span",{cls:"sidecar-section__label",text:"Note"});let o=n.createDiv({cls:"sidecar-icon-actions"}),l=null;if(this.editingNotes.has(e.id)){l=r.createEl("textarea",{cls:"sidecar-entry__editor",text:e.note}),l.rows=7;let m=r.createDiv({cls:"sidecar-editor-actions"});m.createEl("button",{cls:"sidecar-editor-button sidecar-editor-button--primary",text:"Save"}).addEventListener("click",()=>{e.note=l?.value??"",this.controller?.updateEntry(e.id,{note:e.note}),this.editingNotes.delete(e.id),this.renderEntryList()}),m.createEl("button",{cls:"sidecar-editor-button",text:"Cancel"}).addEventListener("click",()=>{this.editingNotes.delete(e.id),e.note.trim()?this.renderEntryList():this.controller?.deleteEntry(e.id)})}else{this.createIconButton(o,"pencil","Edit note").addEventListener("click",()=>{this.editingNotes.add(e.id),this.renderEntryList()}),this.createIconButton(o,"trash-2","Delete note").addEventListener("click",()=>{this.controller?.deleteEntry(e.id)});let d=r.createDiv({cls:"sidecar-entry__preview"});this.renderMarkdown(d,e.note)}this.entryEls.set(e.id,{root:t,quoteTextarea:null,noteTextarea:l})}async renderMarkdown(e,t){e.empty();let r=this.app.workspace.getActiveFile()?.path??"";await p.MarkdownRenderer.render(this.app,t.trim()||" ",e,r,this)}createIconButton(e,t,r){let n=e.createEl("button",{cls:"sidecar-icon-button",attr:{"aria-label":r,title:r}});return(0,p.setIcon)(n,t),n}isLongQuote(e){return e.length>900||e.split(` -`).length>16}updateModeButton(){this.modeButton&&(this.modeButton.setText(this.excerptMode?"Excerpt mode: On":"Excerpt mode: Off"),this.modeButton.toggleClass("is-active",this.excerptMode))}updateEmptyState(){this.emptyEl&&this.emptyEl.toggle(this.workbench.entries.length===0)}};var f={leftExcerptFormat:"highlight",autoOpenSidecar:!0,autoSaveSummaryFile:!0,addBidirectionalLinks:!1,summaryFontSize:14,exportFormat:"quote",exportCalloutType:"quote",exportFolder:"Sidecar Exports"};function T(){return{entries:[]}}var E=class{constructor(i,e,t){this.isActiveFlag=!1;this.isActivatingFlag=!1;this.sourceFile=null;this.rightLeaf=null;this.view=null;this.leftEditor=null;this.pendingQuotes=new Set;this.saveTimer=null;this.syncTimer=null;this.reconcileTimer=null;this.excerptMode=!0;this.isClosingLeaf=!1;this.autoOpenSuspended=!1;this.onBoundMouseUp=()=>this.syncSelection();this.onBoundKeyUp=()=>this.syncSelection();this.app=i,this.data=e,this.writeData=t}isActive(){return this.isActiveFlag}isActivating(){return this.isActivatingFlag}getSettings(){return this.data.settings}async updateSettings(i){this.data.settings={...this.data.settings,...i},this.view?.applySettings(this.data.settings),await this.saveNow(),this.sourceFile&&this.data.settings.autoSaveSummaryFile&&await this.syncSummaryFile()}async toggle(){this.isActiveFlag?this.deactivate({closeLeaf:!0,suspendAutoOpen:!0}):(this.autoOpenSuspended=!1,await this.activate())}async activateForCurrentFile(){this.isActiveFlag||this.isActivatingFlag||await this.activate()}getWorkbenchTitle(){return this.sourceFile?`${this.sourceFile.basename} Notes`:"Sidecar Notes"}isExcerptMode(){return this.excerptMode}setExcerptMode(i){this.excerptMode=i,this.view?.updateExcerptMode(i)}handleWorkbenchClosed(){if(this.isClosingLeaf){this.isClosingLeaf=!1;return}this.deactivate({suspendAutoOpen:!0})}isAutoOpenSuspended(){return this.autoOpenSuspended}addNoteEntry(){let i=this.getCurrentWorkbench();if(!i){new a.Notice("Open a source note before adding a note.");return}let e=this.createEntry("","note");e.noteOpen=!0,i.entries.push(e),this.view?.addEntry(e),this.queueSave()}updateEntry(i,e){let r=this.getCurrentWorkbench()?.entries.find(n=>n.id===i);r&&(Object.assign(r,e),this.queueSave())}deleteNote(i){let t=this.getCurrentWorkbench()?.entries.find(r=>r.id===i);t&&(t.note="",t.noteOpen=!1,this.queueSave())}async deleteEntry(i){let e=this.getCurrentWorkbench();if(!e)return;let t=e.entries.find(r=>r.id===i);t&&(t.kind==="excerpt"&&await this.revertExcerptMarkupInSource(t),e.entries=e.entries.filter(r=>r.id!==i),this.pendingQuotes.delete(i),this.view?.removeEntry(i),this.queueSave())}handleSourceFileModified(i){!this.sourceFile||i.path!==this.sourceFile.path||(this.reconcileTimer!==null&&globalThis.clearTimeout(this.reconcileTimer),this.reconcileTimer=globalThis.setTimeout(()=>{this.reconcileTimer=null,this.reconcileWorkbenchWithSource()},250))}async exportMarkdown(){if(!this.sourceFile){new a.Notice("Open a source note before exporting.");return}let i=this.getCurrentWorkbench();if(!i||i.entries.length===0){new a.Notice("There are no excerpts to export.");return}let e=await this.syncSummaryFile();new a.Notice(`Synced sidecar notes to ${e}`)}deactivate(i={}){let e=i.closeLeaf?this.rightLeaf:null;this.unregisterListeners(),this.flushQueuedSave(),this.flushQueuedSync(),this.flushQueuedReconcile(),this.isActiveFlag=!1,this.sourceFile=null,this.rightLeaf=null,this.view=null,this.leftEditor=null,this.pendingQuotes.clear(),i.suspendAutoOpen&&(this.autoOpenSuspended=!0),e&&(this.isClosingLeaf=!0,e.detach())}async activate(){if(!this.isActivatingFlag){this.isActivatingFlag=!0;try{let i=this.app.workspace.getActiveFile();if(!i){new a.Notice("No active file to link.");return}let e=this.getLeftEditor();if(!e){new a.Notice("Could not get left editor.");return}this.unregisterListeners(),this.sourceFile=i,this.leftEditor=e,this.excerptMode=!0;let t=this.ensureWorkbench(i);this.rightLeaf=await this.openWorkbenchLeaf();let r=this.rightLeaf.view;if(!(r instanceof u)){new a.Notice("Could not open sidecar workbench.");return}this.view=r,this.view.setController(this),this.view.setWorkbench(t,this.getWorkbenchTitle(),this.excerptMode,this.data.settings),this.registerListeners(),this.isActiveFlag=!0,this.queueSummarySync(),new a.Notice("Sidecar workbench activated.")}finally{this.isActivatingFlag=!1}}}getLeftEditor(){let i=this.app.workspace.activeEditor;if(i?.editor)return i.editor;let e=this.app.workspace.getActiveViewOfType(a.MarkdownView);return e?.editor?e.editor:null}getEditorDom(i){let e=i;return e.cm6?e.cm6.dom:e.cm?.dom?e.cm.dom:e.containerEl??null}async openWorkbenchLeaf(){let e=this.app.workspace.getLeavesOfType(h)[0]??this.app.workspace.getLeaf("split","vertical");return await e.setViewState({type:h,active:!0}),this.app.workspace.revealLeaf(e),e}registerListeners(){if(!this.leftEditor)return;let i=this.getEditorDom(this.leftEditor);i&&(i.addEventListener("mouseup",this.onBoundMouseUp),i.addEventListener("keyup",this.onBoundKeyUp))}unregisterListeners(){if(!this.leftEditor)return;let i=this.getEditorDom(this.leftEditor);i&&(i.removeEventListener("mouseup",this.onBoundMouseUp),i.removeEventListener("keyup",this.onBoundKeyUp))}syncSelection(){if(!this.leftEditor||!this.excerptMode)return;let i=this.leftEditor.getSelection(),e=i.trim();if(!e)return;let t=this.formatSelection(e);t!==i&&this.leftEditor.replaceSelection(t),this.addExcerptFromSelection(e)}addExcerptFromSelection(i){let e=this.getCurrentWorkbench();if(!e)return;let t=i.trim();if(!t||this.pendingQuotes.has(t)||e.entries.some(n=>n.quote.trim()===t))return;this.pendingQuotes.add(t);let r=this.createEntry(t,"excerpt");e.entries.push(r),this.view?.addEntry(r),this.queueSave(),this.pendingQuotes.delete(t)}formatSelection(i){return this.applySourceFormat(i,this.data.settings.leftExcerptFormat)}applySourceFormat(i,e){let t=i.split(` +"use strict";var S=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var M=Object.prototype.hasOwnProperty;var P=(s,i)=>{for(var e in i)S(s,e,{get:i[e],enumerable:!0})},W=(s,i,e,t)=>{if(i&&typeof i=="object"||typeof i=="function")for(let r of C(i))!M.call(s,r)&&r!==e&&S(s,r,{get:()=>i[r],enumerable:!(t=D(i,r))||t.enumerable});return s};var N=s=>W(S({},"__esModule",{value:!0}),s);var B={};P(B,{default:()=>y});module.exports=N(B);var w=require("obsidian");var a=require("obsidian");var p=require("obsidian"),h="sidecar-excerpt-workbench",u=class extends p.ItemView{constructor(e){super(e);this.controller=null;this.workbench={entries:[]};this.settings=null;this.title="Sidecar Notes";this.excerptMode=!0;this.listEl=null;this.modeButton=null;this.emptyEl=null;this.entryEls=new Map;this.editingQuotes=new Set;this.editingNotes=new Set;this.expandedQuotes=new Set}getViewType(){return h}getDisplayText(){return this.title}getIcon(){return"quote"}setController(e){this.controller=e}setWorkbench(e,t,r,n){this.workbench=e,this.title=t,this.excerptMode=r,this.settings=n,this.render()}applySettings(e){this.settings=e,this.contentEl.style.setProperty("--sidecar-preview-font-size",`${e.summaryFontSize}px`)}addEntry(e){this.workbench.entries.some(t=>t.id===e.id)||this.workbench.entries.push(e),e.kind==="note"&&!e.note.trim()&&this.editingNotes.add(e.id),this.appendEntry(e),this.updateEmptyState()}updateExcerptMode(e){this.excerptMode=e,this.updateModeButton()}removeEntry(e){this.entryEls.get(e)?.root.remove(),this.entryEls.delete(e),this.editingQuotes.delete(e),this.editingNotes.delete(e),this.expandedQuotes.delete(e),this.workbench.entries=this.workbench.entries.filter(t=>t.id!==e),this.updateEmptyState()}onOpen(){return this.render(),Promise.resolve()}onClose(){return this.controller?.handleWorkbenchClosed(),this.entryEls.clear(),this.editingQuotes.clear(),this.editingNotes.clear(),this.expandedQuotes.clear(),Promise.resolve()}render(){let{contentEl:e}=this;e.empty(),e.addClass("sidecar-workbench"),this.settings&&this.applySettings(this.settings);let t=e.createDiv({cls:"sidecar-workbench__header"}),r=t.createDiv({cls:"sidecar-workbench__title-group"});r.createEl("span",{cls:"sidecar-workbench__eyebrow",text:"Excerpt workbench"}),r.createEl("h2",{text:this.title});let n=t.createDiv({cls:"sidecar-workbench__actions"});this.modeButton=n.createEl("button",{cls:"sidecar-mode-button"}),this.modeButton.addEventListener("click",()=>{this.controller?.setExcerptMode(!this.excerptMode)}),this.updateModeButton(),n.createEl("button",{cls:"sidecar-command-button",text:"Sync"}).addEventListener("click",()=>{this.controller?.exportMarkdown()}),n.createEl("button",{cls:"sidecar-command-button",text:"+ note"}).addEventListener("click",()=>{this.controller?.addNoteEntry()}),this.emptyEl=e.createDiv({cls:"sidecar-workbench__empty",text:"Turn on excerpt mode, then select text in the source note."}),this.listEl=e.createDiv({cls:"sidecar-workbench__list"}),this.renderEntryList()}renderEntryList(){if(this.listEl){this.listEl.empty(),this.entryEls.clear();for(let e of this.workbench.entries)this.appendEntry(e);this.updateEmptyState()}}appendEntry(e){if(this.listEl){if(e.kind==="note"){this.appendNoteEntry(e);return}this.appendExcerptEntry(e)}}appendExcerptEntry(e){if(!this.listEl)return;let t=this.listEl.createDiv({cls:"sidecar-entry sidecar-entry--excerpt"});t.dataset.entryId=e.id;let r=this.renderExcerptSection(t,e),n=this.renderExcerptNoteSection(t,e);this.entryEls.set(e.id,{root:t,quoteTextarea:r,noteTextarea:n})}renderExcerptSection(e,t){let r=e.createDiv({cls:"sidecar-section sidecar-section--excerpt"}),n=r.createDiv({cls:"sidecar-section__header"});n.createEl("span",{cls:"sidecar-section__label",text:"Excerpt"});let o=n.createDiv({cls:"sidecar-icon-actions"});if(this.editingQuotes.has(t.id)){let k=r.createEl("textarea",{cls:"sidecar-entry__editor",text:t.quote});k.rows=5;let b=r.createDiv({cls:"sidecar-editor-actions"});return b.createEl("button",{cls:"sidecar-editor-button sidecar-editor-button--primary",text:"Save"}).addEventListener("click",()=>{this.controller?.updateEntry(t.id,{quote:k.value}),this.editingQuotes.delete(t.id),this.renderEntryList()}),b.createEl("button",{cls:"sidecar-editor-button",text:"Cancel"}).addEventListener("click",()=>{this.editingQuotes.delete(t.id),this.renderEntryList()}),k}this.createIconButton(o,"pencil","Edit excerpt").addEventListener("click",()=>{this.editingQuotes.add(t.id),this.renderEntryList()}),this.createIconButton(o,"trash-2","Delete excerpt").addEventListener("click",()=>{this.controller?.deleteEntry(t.id)});let g=this.isLongQuote(t.quote),d=this.expandedQuotes.has(t.id),v=r.createDiv({cls:g&&!d?"sidecar-entry__preview sidecar-entry__preview--collapsed":"sidecar-entry__preview"});return this.renderMarkdown(v,t.quote),g&&r.createEl("button",{cls:"sidecar-expand-button",text:d?"Less":"More"}).addEventListener("click",()=>{this.expandedQuotes.has(t.id)?this.expandedQuotes.delete(t.id):this.expandedQuotes.add(t.id),this.renderEntryList()}),null}renderExcerptNoteSection(e,t){if(!t.note.trim()&&!this.editingNotes.has(t.id))return e.createEl("button",{cls:"sidecar-add-note-button",text:"+ add note"}).addEventListener("click",()=>{this.editingNotes.add(t.id),this.renderEntryList()}),null;let r=e.createDiv({cls:"sidecar-section sidecar-section--note"}),n=r.createDiv({cls:"sidecar-section__header"});n.createEl("span",{cls:"sidecar-section__label",text:"Note"});let o=n.createDiv({cls:"sidecar-icon-actions"});if(this.editingNotes.has(t.id)){let d=r.createEl("textarea",{cls:"sidecar-entry__editor",text:t.note});d.rows=6;let v=r.createDiv({cls:"sidecar-editor-actions"});return v.createEl("button",{cls:"sidecar-editor-button sidecar-editor-button--primary",text:"Save"}).addEventListener("click",()=>{t.noteOpen=!1,this.controller?.updateEntry(t.id,{note:d.value}),this.editingNotes.delete(t.id),this.renderEntryList()}),v.createEl("button",{cls:"sidecar-editor-button",text:"Cancel"}).addEventListener("click",()=>{this.editingNotes.delete(t.id),this.renderEntryList()}),d}this.createIconButton(o,"pencil","Edit note").addEventListener("click",()=>{this.editingNotes.add(t.id),this.renderEntryList()}),this.createIconButton(o,"trash-2","Delete note").addEventListener("click",()=>{t.note="",t.noteOpen=!1,this.controller?.deleteNote(t.id),this.renderEntryList()});let g=r.createDiv({cls:"sidecar-entry__preview"});return this.renderMarkdown(g,t.note),null}appendNoteEntry(e){if(!this.listEl)return;let t=this.listEl.createDiv({cls:"sidecar-entry sidecar-entry--note"});t.dataset.entryId=e.id;let r=t.createDiv({cls:"sidecar-section sidecar-section--standalone-note"}),n=r.createDiv({cls:"sidecar-section__header"});n.createEl("span",{cls:"sidecar-section__label",text:"Note"});let o=n.createDiv({cls:"sidecar-icon-actions"}),l=null;if(this.editingNotes.has(e.id)){l=r.createEl("textarea",{cls:"sidecar-entry__editor",text:e.note}),l.rows=7;let m=r.createDiv({cls:"sidecar-editor-actions"});m.createEl("button",{cls:"sidecar-editor-button sidecar-editor-button--primary",text:"Save"}).addEventListener("click",()=>{this.controller?.updateEntry(e.id,{note:l?.value??""}),this.editingNotes.delete(e.id),this.renderEntryList()}),m.createEl("button",{cls:"sidecar-editor-button",text:"Cancel"}).addEventListener("click",()=>{this.editingNotes.delete(e.id),e.note.trim()?this.renderEntryList():this.controller?.deleteEntry(e.id)})}else{this.createIconButton(o,"pencil","Edit note").addEventListener("click",()=>{this.editingNotes.add(e.id),this.renderEntryList()}),this.createIconButton(o,"trash-2","Delete note").addEventListener("click",()=>{this.controller?.deleteEntry(e.id)});let d=r.createDiv({cls:"sidecar-entry__preview"});this.renderMarkdown(d,e.note)}this.entryEls.set(e.id,{root:t,quoteTextarea:null,noteTextarea:l})}async renderMarkdown(e,t){e.empty();let r=this.app.workspace.getActiveFile()?.path??"";await p.MarkdownRenderer.render(this.app,t.trim()||" ",e,r,this)}createIconButton(e,t,r){let n=e.createEl("button",{cls:"sidecar-icon-button",attr:{"aria-label":r,title:r}});return(0,p.setIcon)(n,t),n}isLongQuote(e){return e.length>900||e.split(` +`).length>16}updateModeButton(){this.modeButton&&(this.modeButton.setText(this.excerptMode?"Excerpt mode: On":"Excerpt mode: Off"),this.modeButton.toggleClass("is-active",this.excerptMode))}updateEmptyState(){this.emptyEl&&this.emptyEl.toggle(this.workbench.entries.length===0)}};var f={leftExcerptFormat:"highlight",autoOpenSidecar:!0,autoSaveSummaryFile:!0,addBidirectionalLinks:!1,summaryFontSize:14,exportFormat:"quote",exportCalloutType:"quote",exportFolder:"Sidecar Exports"};function T(){return{entries:[]}}var E=class{constructor(i,e,t){this.isActiveFlag=!1;this.isActivatingFlag=!1;this.sourceFile=null;this.rightLeaf=null;this.view=null;this.leftEditor=null;this.saveTimer=null;this.syncTimer=null;this.reconcileTimer=null;this.excerptMode=!0;this.isClosingLeaf=!1;this.autoOpenSuspended=!1;this.lastCaptureKey=null;this.lastCaptureAt=0;this.sourceMutationQueue=Promise.resolve();this.onBoundMouseUp=()=>this.syncSelection();this.onBoundKeyUp=()=>this.syncSelection();this.app=i,this.data=e,this.writeData=t}isActive(){return this.isActiveFlag}isActivating(){return this.isActivatingFlag}getSettings(){return this.data.settings}async updateSettings(i){this.data.settings={...this.data.settings,...i},this.view?.applySettings(this.data.settings),await this.saveNow(),this.sourceFile&&this.data.settings.autoSaveSummaryFile&&await this.syncSummaryFile()}async toggle(){this.isActiveFlag?this.deactivate({closeLeaf:!0,suspendAutoOpen:!0}):(this.autoOpenSuspended=!1,await this.activate())}async activateForCurrentFile(){this.isActiveFlag||this.isActivatingFlag||await this.activate()}getWorkbenchTitle(){return this.sourceFile?`${this.sourceFile.basename} Notes`:"Sidecar Notes"}isExcerptMode(){return this.excerptMode}setExcerptMode(i){this.excerptMode=i,this.view?.updateExcerptMode(i)}handleWorkbenchClosed(){if(this.isClosingLeaf){this.isClosingLeaf=!1;return}this.deactivate({suspendAutoOpen:!0})}isAutoOpenSuspended(){return this.autoOpenSuspended}addNoteEntry(){let i=this.getCurrentWorkbench();if(!i){new a.Notice("Open a source note before adding a note.");return}let e=this.createEntry("","note");e.noteOpen=!0,i.entries.push(e),this.view?.addEntry(e),this.queueSave()}updateEntry(i,e){let r=this.getCurrentWorkbench()?.entries.find(n=>n.id===i);if(r){if(typeof e.quote=="string"){let n=e.quote.trim();n&&(r.quote=n)}typeof e.note=="string"&&(r.note=e.note),this.queueSave()}}deleteNote(i){let t=this.getCurrentWorkbench()?.entries.find(r=>r.id===i);t&&(t.note="",t.noteOpen=!1,this.queueSave())}async deleteEntry(i){let e=this.getCurrentWorkbench();if(!e)return;let t=e.entries.find(r=>r.id===i);if(t){if(t.kind==="excerpt"&&!await this.revertExcerptMarkupInSource(t)){new a.Notice("Could not remove the source highlight for this excerpt.");return}e.entries=e.entries.filter(r=>r.id!==i),this.view?.removeEntry(i),this.queueSave()}}handleSourceFileModified(i){!this.sourceFile||i.path!==this.sourceFile.path||(this.reconcileTimer!==null&&globalThis.clearTimeout(this.reconcileTimer),this.reconcileTimer=globalThis.setTimeout(()=>{this.reconcileTimer=null,this.reconcileWorkbenchWithSource()},250))}async exportMarkdown(){if(!this.sourceFile){new a.Notice("Open a source note before exporting.");return}let i=this.getCurrentWorkbench();if(!i||i.entries.length===0){new a.Notice("There are no excerpts to export.");return}let e=await this.syncSummaryFile();new a.Notice(`Synced sidecar notes to ${e}`)}deactivate(i={}){let e=i.closeLeaf?this.rightLeaf:null;this.unregisterListeners(),this.flushQueuedSave(),this.flushQueuedSync(),this.flushQueuedReconcile(),this.isActiveFlag=!1,this.sourceFile=null,this.rightLeaf=null,this.view=null,this.leftEditor=null,this.lastCaptureKey=null,this.lastCaptureAt=0,i.suspendAutoOpen&&(this.autoOpenSuspended=!0),e&&(this.isClosingLeaf=!0,e.detach())}async activate(){if(!this.isActivatingFlag){this.isActivatingFlag=!0;try{let i=this.app.workspace.getActiveFile();if(!i){new a.Notice("No active file to link.");return}let e=this.getLeftEditor();if(!e){new a.Notice("Could not get left editor.");return}this.unregisterListeners(),this.sourceFile=i,this.leftEditor=e,this.excerptMode=!0;let t=this.ensureWorkbench(i);this.rightLeaf=await this.openWorkbenchLeaf();let r=this.rightLeaf.view;if(!(r instanceof u)){new a.Notice("Could not open sidecar workbench.");return}this.view=r,this.view.setController(this),this.view.setWorkbench(t,this.getWorkbenchTitle(),this.excerptMode,this.data.settings),this.registerListeners(),this.isActiveFlag=!0,this.queueSummarySync(),new a.Notice("Sidecar workbench activated.")}finally{this.isActivatingFlag=!1}}}getLeftEditor(){let i=this.app.workspace.activeEditor;if(i?.editor)return i.editor;let e=this.app.workspace.getActiveViewOfType(a.MarkdownView);return e?.editor?e.editor:null}getEditorDom(i){let e=i;return e.cm6?e.cm6.dom:e.cm?.dom?e.cm.dom:e.containerEl??null}async openWorkbenchLeaf(){let e=this.app.workspace.getLeavesOfType(h)[0]??this.app.workspace.getLeaf("split","vertical");return await e.setViewState({type:h,active:!0}),this.app.workspace.revealLeaf(e),e}registerListeners(){if(!this.leftEditor)return;let i=this.getEditorDom(this.leftEditor);i&&(i.addEventListener("mouseup",this.onBoundMouseUp),i.addEventListener("keyup",this.onBoundKeyUp))}unregisterListeners(){if(!this.leftEditor)return;let i=this.getEditorDom(this.leftEditor);i&&(i.removeEventListener("mouseup",this.onBoundMouseUp),i.removeEventListener("keyup",this.onBoundKeyUp))}syncSelection(){if(!this.leftEditor||!this.excerptMode)return;let i=this.leftEditor.getSelection(),e=i.trim();if(!e)return;let t=this.getCurrentWorkbench();if(!t||!this.shouldCaptureSelection(e))return;let r=this.createEntry(e,"excerpt");t.entries.push(r),this.view?.addEntry(r),this.queueSave(),this.markSelectionCaptured(e);let n=this.formatSelection(e);n!==i&&this.leftEditor.replaceSelection(n)}formatSelection(i){return this.applySourceFormat(i,this.data.settings.leftExcerptFormat)}shouldCaptureSelection(i){if(!this.sourceFile)return!1;let e=`${this.sourceFile.path}::${i.trim()}`;return!(this.lastCaptureKey===e&&Date.now()-this.lastCaptureAt<250)}markSelectionCaptured(i){this.sourceFile&&(this.lastCaptureKey=`${this.sourceFile.path}::${i.trim()}`,this.lastCaptureAt=Date.now())}applySourceFormat(i,e){let t=i.split(` `).map(r=>r.trim()).filter(r=>r.length>0);if(t.length===0)return i;switch(e){case"bold":return t.map(r=>`**${r}**`).join(` `);case"italic":return t.map(r=>`*${r}*`).join(` `);case"none":return i;case"highlight":default:return t.map(r=>`==${r}==`).join(` -`)}}ensureWorkbench(i){let e=this.getWorkbenchKey(i),t=this.data.workbenches[e];if(t)return t;let r=T();return this.data.workbenches[e]=r,this.queueSave(),r}getCurrentWorkbench(){return this.sourceFile?this.data.workbenches[this.getWorkbenchKey(this.sourceFile)]??null:null}getWorkbenchKey(i){return i.path}createEntry(i,e){return{id:`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`,kind:e,quote:i,note:"",noteOpen:e==="note",sourceFormat:e==="excerpt"?this.data.settings.leftExcerptFormat:void 0}}queueSave(){this.saveTimer!==null&&globalThis.clearTimeout(this.saveTimer),this.saveTimer=globalThis.setTimeout(()=>{this.saveNow()},300),this.queueSummarySync()}flushQueuedSave(){this.saveTimer!==null&&(globalThis.clearTimeout(this.saveTimer),this.saveTimer=null,this.saveNow())}async saveNow(){this.saveTimer!==null&&(globalThis.clearTimeout(this.saveTimer),this.saveTimer=null),await this.writeData(this.data)}queueSummarySync(){!this.sourceFile||!this.data.settings.autoSaveSummaryFile||(this.syncTimer!==null&&globalThis.clearTimeout(this.syncTimer),this.syncTimer=globalThis.setTimeout(()=>{this.syncSummaryFile()},500))}flushQueuedSync(){this.syncTimer!==null&&(globalThis.clearTimeout(this.syncTimer),this.syncTimer=null,this.syncSummaryFile())}flushQueuedReconcile(){this.reconcileTimer!==null&&(globalThis.clearTimeout(this.reconcileTimer),this.reconcileTimer=null)}renderExport(i){let e=this.data.settings.exportFormat;return`${i.entries.map(r=>{if(r.kind==="note")return r.note.trim();let n=this.renderQuoteMarkdown(r.quote,e),o=r.note.trim();return o?`${n} +`)}}ensureWorkbench(i){let e=this.getWorkbenchKey(i),t=this.data.workbenches[e];if(t)return t;let r=T();return this.data.workbenches[e]=r,this.queueSave(),r}getCurrentWorkbench(){return this.sourceFile?this.data.workbenches[this.getWorkbenchKey(this.sourceFile)]??null:null}getWorkbenchKey(i){return i.path}createEntry(i,e){return{id:`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`,kind:e,quote:i,sourceQuote:e==="excerpt"?i:void 0,note:"",noteOpen:e==="note",sourceFormat:e==="excerpt"?this.data.settings.leftExcerptFormat:void 0}}queueSave(){this.saveTimer!==null&&globalThis.clearTimeout(this.saveTimer),this.saveTimer=globalThis.setTimeout(()=>{this.saveNow()},300),this.queueSummarySync()}flushQueuedSave(){this.saveTimer!==null&&(globalThis.clearTimeout(this.saveTimer),this.saveTimer=null,this.saveNow())}async saveNow(){this.saveTimer!==null&&(globalThis.clearTimeout(this.saveTimer),this.saveTimer=null),await this.writeData(this.data)}queueSummarySync(){!this.sourceFile||!this.data.settings.autoSaveSummaryFile||(this.syncTimer!==null&&globalThis.clearTimeout(this.syncTimer),this.syncTimer=globalThis.setTimeout(()=>{this.syncSummaryFile()},500))}flushQueuedSync(){this.syncTimer!==null&&(globalThis.clearTimeout(this.syncTimer),this.syncTimer=null,this.syncSummaryFile())}flushQueuedReconcile(){this.reconcileTimer!==null&&(globalThis.clearTimeout(this.reconcileTimer),this.reconcileTimer=null)}renderExport(i){let e=this.data.settings.exportFormat;return`${i.entries.map(r=>{if(r.kind==="note")return r.note.trim();let n=this.renderQuoteMarkdown(r.quote,e),o=r.note.trim();return o?`${n} ${o}`:n}).join(` @@ -18,4 +18,4 @@ ${o}`:n}).join(` `)?"":` `;return`${r}${n} Sidecar notes: ${t} -`})}wikilinkForFile(i,e){return`[[${this.stripMdExtension(i)}|${e}]]`}wikilinkForPath(i){let e=this.stripMdExtension(i),t=e.split("/").pop()??e;return`[[${e}|${t}]]`}stripMdExtension(i){return i.replace(/\.md$/i,"")}async revertExcerptMarkupInSource(i){!this.sourceFile||i.kind!=="excerpt"||await this.app.vault.process(this.sourceFile,e=>{let t=this.findSourceExcerptVariant(e,i);if(!t||t===i.quote)return e;let r=e.indexOf(t);return r===-1?e:`${e.slice(0,r)}${i.quote}${e.slice(r+t.length)}`})}async reconcileWorkbenchWithSource(){if(!this.sourceFile)return;let i=this.getCurrentWorkbench();if(!i)return;let e=await this.app.vault.cachedRead(this.sourceFile),t=i.entries.filter(n=>n.kind!=="excerpt"?!1:!this.sourceContainsExcerpt(e,n));if(t.length===0)return;let r=new Set(t.map(n=>n.id));i.entries=i.entries.filter(n=>!r.has(n.id));for(let n of t)this.view?.removeEntry(n.id);this.queueSave()}sourceContainsExcerpt(i,e){return this.findSourceExcerptVariant(i,e)!==null}findSourceExcerptVariant(i,e){let t=["highlight","bold","italic","none"],r=e.sourceFormat,n=r?[r,...t.filter(o=>o!==r)]:t;for(let o of n){let l=this.applySourceFormat(e.quote,o);if(i.includes(l))return e.sourceFormat=o,l}return null}};function F(s){let i=s,e={...f,...i?.settings??{}};e.summaryFontSize=B(e.summaryFontSize),O(e.exportCalloutType)||(e.exportCalloutType=f.exportCalloutType);let t=i?.workbenches??{};for(let r of Object.values(t))for(let n of r.entries)n.kind=n.kind??(n.quote.trim()?"excerpt":"note"),n.noteOpen=n.noteOpen??n.kind==="note",n.sourceFormat=n.kind==="excerpt"?n.sourceFormat:void 0;return{settings:{...e},workbenches:t}}function O(s){return typeof s=="string"&&["quote","note","abstract","info","todo","tip","success","question","warning","failure","danger","bug","example"].includes(s)}function B(s){return typeof s!="number"||Number.isNaN(s)?f.summaryFontSize:Math.min(20,Math.max(12,Math.round(s)))}var c=require("obsidian"),x=class extends c.PluginSettingTab{constructor(i,e){super(i,e),this.plugin=e}display(){let{containerEl:i}=this,e=this.plugin.manager?.getSettings();if(i.empty(),!e){i.createEl("p",{text:"Sidecar settings are not available."});return}new c.Setting(i).setName("Left excerpt format").setDesc("How selected source text is rewritten after capture.").addDropdown(t=>{t.addOption("highlight","Highlight").addOption("italic","Italic").addOption("bold","Bold").addOption("none","No formatting").setValue(e.leftExcerptFormat).onChange(async r=>{await this.plugin.manager?.updateSettings({leftExcerptFormat:r})})}),new c.Setting(i).setName("Auto-open sidecar").setDesc("Open the excerpt workbench automatically when a Markdown note is opened.").addToggle(t=>{t.setValue(e.autoOpenSidecar).onChange(async r=>{await this.plugin.manager?.updateSettings({autoOpenSidecar:r})})}),new c.Setting(i).setName("Auto-save summary file").setDesc("Keep a Markdown summary file updated while editing excerpts and notes.").addToggle(t=>{t.setValue(e.autoSaveSummaryFile).onChange(async r=>{await this.plugin.manager?.updateSettings({autoSaveSummaryFile:r})})}),new c.Setting(i).setName("Add bidirectional links").setDesc("Add a link from the source note to the summary file and a source link in the summary file.").addToggle(t=>{t.setValue(e.addBidirectionalLinks).onChange(async r=>{await this.plugin.manager?.updateSettings({addBidirectionalLinks:r})})}),new c.Setting(i).setName("Summary font size").setDesc("Font size used for excerpt and note previews in the right-side workbench.").addSlider(t=>{t.setLimits(12,20,1).setValue(e.summaryFontSize).setDynamicTooltip().onChange(async r=>{await this.plugin.manager?.updateSettings({summaryFontSize:r})})}),new c.Setting(i).setName("Export excerpt format").setDesc("Markdown style used for excerpts in exported notes.").addDropdown(t=>{t.addOption("quote","Quote block").addOption("callout","Callout").setValue(e.exportFormat).onChange(async r=>{await this.plugin.manager?.updateSettings({exportFormat:r})})}),new c.Setting(i).setName("Export callout style").setDesc("Callout type used when export excerpt format is callout.").addDropdown(t=>{t.addOption("quote","Quote").addOption("note","Note").addOption("abstract","Abstract").addOption("info","Info").addOption("todo","Todo").addOption("tip","Tip").addOption("success","Success").addOption("question","Question").addOption("warning","Warning").addOption("failure","Failure").addOption("danger","Danger").addOption("bug","Bug").addOption("example","Example").setValue(e.exportCalloutType).onChange(async r=>{await this.plugin.manager?.updateSettings({exportCalloutType:r})})}),new c.Setting(i).setName("Summary folder").setDesc("Folder where Markdown summary files are created and updated.").addText(t=>{t.setPlaceholder("Sidecar exports").setValue(e.exportFolder).onChange(async r=>{await this.plugin.manager?.updateSettings({exportFolder:r})})})}};function L(s,i){let e={id:"sidecar-notes-toggle",name:"Toggle excerpt workbench",callback:()=>{i.toggle()}},t={id:"sidecar-notes-export-markdown",name:"Export excerpts to Markdown",callback:()=>{i.exportMarkdown()}};return s.addCommand(e),s.addCommand(t),{toggle:e,exportMarkdown:t}}var y=class extends w.Plugin{constructor(){super(...arguments);this.manager=null;this.data=null}async onload(){this.data=F(await this.loadData()),this.manager=new E(this.app,this.data,async e=>{this.data=e,await this.saveData(e)}),this.registerView(h,e=>new u(e)),L(this,this.manager),this.addRibbonIcon("quote","Toggle sidecar workbench",()=>{this.manager?.toggle()}),this.addSettingTab(new x(this.app,this)),this.registerEvent(this.app.workspace.on("file-open",e=>{this.handleFileOpen(e)})),this.registerEvent(this.app.vault.on("modify",e=>{e instanceof w.TFile&&this.manager?.handleSourceFileModified(e)}))}onunload(){this.manager?.deactivate(),this.manager=null,this.data=null}async handleFileOpen(e){if(!(!this.manager||!e)&&e.extension==="md"&&this.manager.getSettings().autoOpenSidecar&&!this.manager.isAutoOpenSuspended()&&!(this.manager.isActive()||this.manager.isActivating()))try{await this.manager.activateForCurrentFile()}catch(t){console.error("[Sidecar Notes] Failed to auto-open workbench",t)}}}; +`})}wikilinkForFile(i,e){return`[[${this.stripMdExtension(i)}|${e}]]`}wikilinkForPath(i){let e=this.stripMdExtension(i),t=e.split("/").pop()??e;return`[[${e}|${t}]]`}stripMdExtension(i){return i.replace(/\.md$/i,"")}async revertExcerptMarkupInSource(i){return!this.sourceFile||i.kind!=="excerpt"?!1:this.runSourceMutation(async()=>{let e=!1;return await this.app.vault.process(this.sourceFile,t=>{let r=this.findSourceExcerptVariant(t,i),n=i.sourceQuote??i.quote;if(!r||r===n)return e=r===n,t;let o=t.indexOf(r);return o===-1?t:(e=!0,`${t.slice(0,o)}${n}${t.slice(o+r.length)}`)}),e})}async reconcileWorkbenchWithSource(){if(!this.sourceFile)return;let i=this.getCurrentWorkbench();if(!i)return;let e=await this.app.vault.cachedRead(this.sourceFile),t=i.entries.filter(n=>n.kind!=="excerpt"?!1:!this.sourceContainsExcerpt(e,n));if(t.length===0)return;let r=new Set(t.map(n=>n.id));i.entries=i.entries.filter(n=>!r.has(n.id));for(let n of t)this.view?.removeEntry(n.id);this.queueSave()}sourceContainsExcerpt(i,e){return this.findSourceExcerptVariant(i,e)!==null}findSourceExcerptVariant(i,e){let t=this.findSourceExcerptVariantForQuote(i,e.sourceQuote??e.quote,e.sourceFormat);return t?(e.sourceFormat=t.format,t.text):null}findSourceExcerptVariantForQuote(i,e,t){let r=["highlight","bold","italic","none"],n=t?[t,...r.filter(o=>o!==t)]:r;for(let o of n){let l=this.applySourceFormat(e,o);if(i.includes(l))return{text:l,format:o}}return null}runSourceMutation(i){let e=this.sourceMutationQueue.then(i,i);return this.sourceMutationQueue=e.then(()=>{},()=>{}),e}};function F(s){let i=s,e={...f,...i?.settings??{}};e.summaryFontSize=O(e.summaryFontSize),A(e.exportCalloutType)||(e.exportCalloutType=f.exportCalloutType);let t=i?.workbenches??{};for(let r of Object.values(t))for(let n of r.entries)n.kind=n.kind??(n.quote.trim()?"excerpt":"note"),n.noteOpen=n.noteOpen??n.kind==="note",n.sourceQuote=n.kind==="excerpt"?n.sourceQuote??n.quote:void 0,n.sourceFormat=n.kind==="excerpt"?n.sourceFormat:void 0;return{settings:{...e},workbenches:t}}function A(s){return typeof s=="string"&&["quote","note","abstract","info","todo","tip","success","question","warning","failure","danger","bug","example"].includes(s)}function O(s){return typeof s!="number"||Number.isNaN(s)?f.summaryFontSize:Math.min(20,Math.max(12,Math.round(s)))}var c=require("obsidian"),x=class extends c.PluginSettingTab{constructor(i,e){super(i,e),this.plugin=e}display(){let{containerEl:i}=this,e=this.plugin.manager?.getSettings();if(i.empty(),!e){i.createEl("p",{text:"Sidecar settings are not available."});return}new c.Setting(i).setName("Left excerpt format").setDesc("How selected source text is rewritten after capture.").addDropdown(t=>{t.addOption("highlight","Highlight").addOption("italic","Italic").addOption("bold","Bold").addOption("none","No formatting").setValue(e.leftExcerptFormat).onChange(async r=>{await this.plugin.manager?.updateSettings({leftExcerptFormat:r})})}),new c.Setting(i).setName("Auto-open sidecar").setDesc("Open the excerpt workbench automatically when a Markdown note is opened.").addToggle(t=>{t.setValue(e.autoOpenSidecar).onChange(async r=>{await this.plugin.manager?.updateSettings({autoOpenSidecar:r})})}),new c.Setting(i).setName("Auto-save summary file").setDesc("Keep a Markdown summary file updated while editing excerpts and notes.").addToggle(t=>{t.setValue(e.autoSaveSummaryFile).onChange(async r=>{await this.plugin.manager?.updateSettings({autoSaveSummaryFile:r})})}),new c.Setting(i).setName("Add bidirectional links").setDesc("Add a link from the source note to the summary file and a source link in the summary file.").addToggle(t=>{t.setValue(e.addBidirectionalLinks).onChange(async r=>{await this.plugin.manager?.updateSettings({addBidirectionalLinks:r})})}),new c.Setting(i).setName("Summary font size").setDesc("Font size used for excerpt and note previews in the right-side workbench.").addSlider(t=>{t.setLimits(12,20,1).setValue(e.summaryFontSize).setDynamicTooltip().onChange(async r=>{await this.plugin.manager?.updateSettings({summaryFontSize:r})})}),new c.Setting(i).setName("Export excerpt format").setDesc("Markdown style used for excerpts in exported notes.").addDropdown(t=>{t.addOption("quote","Quote block").addOption("callout","Callout").setValue(e.exportFormat).onChange(async r=>{await this.plugin.manager?.updateSettings({exportFormat:r})})}),new c.Setting(i).setName("Export callout style").setDesc("Callout type used when export excerpt format is callout.").addDropdown(t=>{t.addOption("quote","Quote").addOption("note","Note").addOption("abstract","Abstract").addOption("info","Info").addOption("todo","Todo").addOption("tip","Tip").addOption("success","Success").addOption("question","Question").addOption("warning","Warning").addOption("failure","Failure").addOption("danger","Danger").addOption("bug","Bug").addOption("example","Example").setValue(e.exportCalloutType).onChange(async r=>{await this.plugin.manager?.updateSettings({exportCalloutType:r})})}),new c.Setting(i).setName("Summary folder").setDesc("Folder where Markdown summary files are created and updated.").addText(t=>{t.setPlaceholder("Sidecar exports").setValue(e.exportFolder).onChange(async r=>{await this.plugin.manager?.updateSettings({exportFolder:r})})})}};function L(s,i){let e={id:"sidecar-notes-toggle",name:"Toggle excerpt workbench",callback:()=>{i.toggle()}},t={id:"sidecar-notes-export-markdown",name:"Export excerpts to Markdown",callback:()=>{i.exportMarkdown()}};return s.addCommand(e),s.addCommand(t),{toggle:e,exportMarkdown:t}}var y=class extends w.Plugin{constructor(){super(...arguments);this.manager=null;this.data=null}async onload(){this.data=F(await this.loadData()),this.manager=new E(this.app,this.data,async e=>{this.data=e,await this.saveData(e)}),this.registerView(h,e=>new u(e)),L(this,this.manager),this.addRibbonIcon("quote","Toggle sidecar workbench",()=>{this.manager?.toggle()}),this.addSettingTab(new x(this.app,this)),this.registerEvent(this.app.workspace.on("file-open",e=>{this.handleFileOpen(e)})),this.registerEvent(this.app.vault.on("modify",e=>{e instanceof w.TFile&&this.manager?.handleSourceFileModified(e)}))}onunload(){this.manager?.deactivate(),this.manager=null,this.data=null}async handleFileOpen(e){if(!(!this.manager||!e)&&e.extension==="md"&&this.manager.getSettings().autoOpenSidecar&&!this.manager.isAutoOpenSuspended()&&!(this.manager.isActive()||this.manager.isActivating()))try{await this.manager.activateForCurrentFile()}catch(t){console.error("[Sidecar Notes] Failed to auto-open workbench",t)}}}; diff --git a/settings.ts b/settings.ts index 07a6064..461b1ec 100644 --- a/settings.ts +++ b/settings.ts @@ -30,6 +30,7 @@ export interface ExcerptEntry { id: string; kind: "excerpt" | "note"; quote: string; + sourceQuote?: string; note: string; noteOpen: boolean; sourceFormat?: LeftExcerptFormat;