import { FileManager, Notice, TAbstractFile, TFile, TFolder, Vault, } from "obsidian"; import { basename, dirname } from "path"; import FNCore from "../fnc-main"; import { afOp, getRenamedPath, isMd } from "../misc"; import { NoteLoc } from "../typings/api"; export default class VaultHandler { // @ts-ignore private on: Vault["on"] = (...args) => this.plugin.app.vault.on(...args); private delete: Vault["delete"] = (...args) => this.plugin.app.vault.delete(...args); private rename: FileManager["renameFile"] = (...args) => this.plugin.app.fileManager.renameFile(...args); private get settings() { return this.plugin.settings; } private get finder() { return this.plugin.resolver; } plugin: FNCore; constructor(plugin: FNCore) { this.plugin = plugin; } registerEvent = () => { this.plugin.registerEvent(this.on("create", this.onChange)); this.plugin.registerEvent(this.on("rename", this.onChange)); this.plugin.registerEvent(this.on("delete", this.onDelete)); }; private shouldRename(af: TAbstractFile, oldPath?: string): oldPath is string { if (!this.settings.autoRename || !oldPath) return false; const renameOnly = this.settings.folderNotePref !== NoteLoc.Index && dirname(af.path) === dirname(oldPath) // rename only, same loc ? true : false; // sync loc is enabled in folder renames only const syncLoc = af instanceof TFolder && this.settings.folderNotePref === NoteLoc.Outside && dirname(af.path) !== dirname(oldPath) ? true : false; return renameOnly || syncLoc; } onChange = (af: TAbstractFile, oldPath?: string) => { const { getFolderNote, getFolderFromNote, getFolderNotePath } = this.finder; function getOldLinked(af: TFile): TFolder | null; function getOldLinked(af: TFolder): TFile | null; function getOldLinked(af: TAbstractFile): TFile | TFolder | null; // eslint-disable-next-line prefer-arrow/prefer-arrow-functions function getOldLinked(af: TAbstractFile): TFile | TFolder | null { if (af instanceof TFolder) { return oldPath ? getFolderNote(oldPath) : null; } else if (af instanceof TFile) { return oldPath && isMd(oldPath) ? getFolderFromNote(oldPath) : null; } else return null; } function getLinked(af: TFile): TFolder | null; function getLinked(af: TFolder): TFile | null; // eslint-disable-next-line prefer-arrow/prefer-arrow-functions function getLinked(af: TAbstractFile): TFile | TFolder | null { if (af instanceof TFolder) { return getFolderNote(af); } else if (af instanceof TFile) { return getFolderFromNote(af); } else return null; } // markdown <-> non-md if (oldPath && af instanceof TFile && isMd(oldPath) !== isMd(af)) { const oldLinked = getOldLinked(af); if (oldLinked) { // folder note -> non-md this.plugin.trigger("folder-note:delete", af, oldLinked); } else { // non-md -> md, check if folder note const nowLinked = getFolderFromNote(af); if (nowLinked) this.plugin.trigger("folder-note:create", af, nowLinked); } } else { // check if new location contains matched folder and mark if exists let newExists = false, linked; afOp( af, (file) => { linked = getLinked(file); if (linked) { newExists = true; this.plugin.trigger("folder-note:create", file, linked); } }, (folder) => { linked = getLinked(folder); if (linked) { newExists = true; this.plugin.trigger("folder-note:create", linked, folder); } }, ); // onRename, check if oldPath has any folder note/linked folder const oldLinked = getOldLinked(af); if (!oldLinked) return; const renameTo = af instanceof TFolder ? getFolderNotePath(af)?.path ?? "" : af instanceof TFile ? getRenamedPath(oldLinked, af.basename) ?? "" : ""; if (this.shouldRename(af, oldPath)) if (!newExists && renameTo) { this.rename(oldLinked, renameTo); afOp( af, (f) => this.plugin.trigger( "folder-note:rename", [f, oldPath], [oldLinked as TFolder, renameTo], ), (f) => this.plugin.trigger( "folder-note:rename", [oldLinked as TFile, renameTo], [f, oldPath], ), ); return; } else { const target = oldLinked instanceof TFile ? "folder note" : "linked folder", baseMessage = `Failed to sync name of ${target}: `, errorMessage = newExists ? `${target} ${basename(renameTo)} already exists` : "check console for more details"; new Notice(baseMessage + errorMessage); } // reset old linked folder note/folder mark when no rename is performed afOp( af, (f) => this.plugin.trigger("folder-note:delete", f, oldLinked as TFolder), (f) => this.plugin.trigger("folder-note:delete", oldLinked as TFile, f), ); } }; onDelete = (af: TAbstractFile) => { const { getFolderNote, getFolderFromNote } = this.finder; if (af instanceof TFolder) { const oldNote = getFolderNote(af); if (!(this.settings.folderNotePref === NoteLoc.Outside && oldNote)) return; if (this.settings.deleteOutsideNoteWithFolder) { this.delete(oldNote); } else this.plugin.trigger("folder-note:delete", oldNote, af); } else if (af instanceof TFile && isMd(af)) { const oldFolder = getFolderFromNote(af); if (oldFolder) this.plugin.trigger("folder-note:delete", af, oldFolder); } }; }