From b5afae26e3503059d95acb7cadfad9b458a6f0ae Mon Sep 17 00:00:00 2001 From: Ross Keenan Date: Sat, 4 Dec 2021 18:55:47 +0200 Subject: [PATCH] feat(Hierarchy Note): :sparkles: Hierarchy Note Adjuster! (#143) --- src/Components/ModifyHNItemComp.svelte | 120 +++++++++++++++++++++ src/DownView.ts | 4 +- src/HierNoteModal.ts | 52 +++++++++ src/HierarchyNoteManipulator.ts | 140 +++++++++++++++++++++++++ src/ModifyHierItemModal.ts | 52 +++++++++ src/main.ts | 7 ++ 6 files changed, 373 insertions(+), 2 deletions(-) create mode 100644 src/Components/ModifyHNItemComp.svelte create mode 100644 src/HierNoteModal.ts create mode 100644 src/HierarchyNoteManipulator.ts create mode 100644 src/ModifyHierItemModal.ts diff --git a/src/Components/ModifyHNItemComp.svelte b/src/Components/ModifyHNItemComp.svelte new file mode 100644 index 00000000..acf5d9da --- /dev/null +++ b/src/Components/ModifyHNItemComp.svelte @@ -0,0 +1,120 @@ + + +
Add an {ARROW_DIRECTIONS[rel]} to {dropWikilinks(hnItem.line)}
+
+ {#if rel === "up"} + {#if hnItem.depth === 0} +
Can't add parent to top level item, choose another direction
+ {:else} +
+
+          {buildNewItem(newItem, hnItem.depth - 4, true)}
+        
+
+ {/if} + {/if} +
+
+        {buildNewItem(dropWikilinks(hnItem.line), hnItem.depth, true)}
+    
+
+ {#if rel === "same"} +
+
+        {buildNewItem(newItem, hnItem.depth, true)}
+    
+
+ {:else if rel === "down"} +
+
+        {buildNewItem(newItem, hnItem.depth + 4, true)}
+    
+
+ {/if} + + + + + + + +
+ + diff --git a/src/DownView.ts b/src/DownView.ts index 9610091d..46a245fa 100644 --- a/src/DownView.ts +++ b/src/DownView.ts @@ -1,8 +1,8 @@ import { ItemView, WorkspaceLeaf } from "obsidian"; +import { addFeatherIcon } from "obsidian-community-lib"; +import Down from "./Components/Down.svelte"; import { DOWN_VIEW } from "./constants"; import type BCPlugin from "./main"; -import Down from "./Components/Down.svelte"; -import { addFeatherIcon } from "obsidian-community-lib"; export default class DownView extends ItemView { private plugin: BCPlugin; diff --git a/src/HierNoteModal.ts b/src/HierNoteModal.ts new file mode 100644 index 00000000..af3e71ac --- /dev/null +++ b/src/HierNoteModal.ts @@ -0,0 +1,52 @@ +import { App, FuzzyMatch, FuzzySuggestModal, Notice } from "obsidian"; +import { HierarchyNoteManipulator } from "./HierarchyNoteManipulator"; +import type { BCSettings } from "./interfaces"; +import type BCPlugin from "./main"; + +export class HierarchyNoteSelectorModal extends FuzzySuggestModal { + app: App; + plugin: BCPlugin; + settings: BCSettings; + + constructor(app: App, plugin: BCPlugin) { + super(app); + this.app = app; + this.plugin = plugin; + this.settings = this.plugin.settings; + } + + onOpen(): void { + this.setPlaceholder("HN Chooser"); + const { hierarchyNotes } = this.settings; + if (hierarchyNotes.length === 0) { + this.close(); + new Notice("No hierarchy notes found"); + } else if (hierarchyNotes.length === 1) { + this.close(); + new HierarchyNoteManipulator( + this.app, + this.plugin, + hierarchyNotes[0] + ).open(); + } else { + super.onOpen(); + } + } + + getItems(): string[] { + return this.settings.hierarchyNotes; + } + + getItemText(item: string): string { + return `${item}`; + } + + renderSuggestion(item: FuzzyMatch, el: HTMLElement) { + super.renderSuggestion(item, el); + } + + onChooseItem(item: string, evt: MouseEvent | KeyboardEvent): void { + new HierarchyNoteManipulator(this.app, this.plugin, item).open(); + this.close(); + } +} diff --git a/src/HierarchyNoteManipulator.ts b/src/HierarchyNoteManipulator.ts new file mode 100644 index 00000000..afe744f8 --- /dev/null +++ b/src/HierarchyNoteManipulator.ts @@ -0,0 +1,140 @@ +import { error } from "loglevel"; +import { + App, + FuzzyMatch, + FuzzySuggestModal, + ListItemCache, + MarkdownView, + Notice, + TFile, +} from "obsidian"; +import { ModifyHierItemModal } from "./ModifyHierItemModal"; +import type { BCSettings } from "./interfaces"; +import type BCPlugin from "./main"; +import { dropWikilinks } from "./sharedFunctions"; + +interface HNItem { + depth: number; + line: string; + lineNo: number; +} + +export class HierarchyNoteManipulator extends FuzzySuggestModal { + app: App; + plugin: BCPlugin; + settings: BCSettings; + hierNoteName: string; + lines: string[]; + listItems: ListItemCache[]; + file: TFile; + + constructor(app: App, plugin: BCPlugin, hierNoteName: string) { + super(app); + this.app = app; + this.plugin = plugin; + this.settings = this.plugin.settings; + this.hierNoteName = hierNoteName; + + const chooseOverride = (evt: KeyboardEvent) => { + // @ts-ignore + this.chooser.useSelectedItem(evt); + return false; + }; + this.scope.register([], "Delete", chooseOverride); + this.scope.register(["Shift"], "ArrowUp", chooseOverride); + this.scope.register(["Shift"], "ArrowRight", chooseOverride); + this.scope.register(["Shift"], "ArrowDown", chooseOverride); + } + + async onOpen(): Promise { + this.setPlaceholder("HN Manipulator"); + this.setInstructions([ + { command: "Enter/Click", purpose: "Jump to item" }, + { command: "Shift + ↑", purpose: "Add parent" }, + { command: "Shift + →", purpose: "Add sibling" }, + { command: "Shift + ↓", purpose: "Add child" }, + { command: "Delete", purpose: "Delete item" }, + ]); + + this.file = this.app.metadataCache.getFirstLinkpathDest( + this.hierNoteName, + "" + ); + if (!this.file) this.lines = []; + const content = await this.app.vault.cachedRead(this.file); + this.lines = content.split("\n"); + + this.listItems = this.app.metadataCache.getFileCache(this.file).listItems; + + super.onOpen(); + } + + getItems(): HNItem[] { + const items = this.listItems + .map((item) => { + const i = item.position.start.line; + return { i, line: this.lines[i] }; + }) + .map((item) => { + const splits = item.line.split("- "); + const depth = splits[0].length; + const line = splits.slice(1).join("- "); + + return { depth, line, lineNo: item.i }; + }); + + return items; + } + + getItemText(item: HNItem): string { + return `${" ".repeat(item.depth)}- ${dropWikilinks(item.line)}`; + } + + renderSuggestion(item: FuzzyMatch, el: HTMLElement) { + super.renderSuggestion(item, el); + el.innerText = `${" ".repeat(item.item.depth)}- ${dropWikilinks( + item.item.line + )}`; + } + + async deleteItem(item: HNItem): Promise { + try { + this.lines.splice(item.lineNo, 1); + this.listItems.splice(item.lineNo, 1); + await this.app.vault.modify(this.file, this.lines.join("\n")); + new Notice("Item deleted Succesfully"); + } catch (err) { + error(err); + new Notice("An error occured. Please check the console"); + } + } + + onChooseItem(item: HNItem, evt: MouseEvent | KeyboardEvent): void { + if (evt instanceof KeyboardEvent && evt.key === "Delete") { + this.deleteItem(item); + } else if (evt instanceof KeyboardEvent && evt.shiftKey) { + const rel = + evt.key === "ArrowUp" + ? "up" + : evt.key === "ArrowDown" + ? "down" + : "same"; + + new ModifyHierItemModal( + this.app, + this.plugin, + item, + this.file, + rel + ).open(); + this.close(); + } else { + const view = this.app.workspace.getActiveViewOfType(MarkdownView); + const { editor } = view ?? {}; + if (!editor) return; + //@ts-ignore + view.leaf.openFile(this.file, { active: true, mode: "source" }); + editor.setCursor({ line: item.lineNo, ch: item.depth + 2 }); + } + } +} diff --git a/src/ModifyHierItemModal.ts b/src/ModifyHierItemModal.ts new file mode 100644 index 00000000..b6e26905 --- /dev/null +++ b/src/ModifyHierItemModal.ts @@ -0,0 +1,52 @@ +import { App, Modal, TFile } from "obsidian"; +import ModifyHNItemComp from "./Components/ModifyHNItemComp.svelte"; +import type BCPlugin from "./main"; + +interface HNItem { + depth: number; + line: string; + lineNo: number; +} + +export class ModifyHierItemModal extends Modal { + plugin: BCPlugin; + modal: ModifyHierItemModal; + hnItem: HNItem; + file: TFile; + rel: "up" | "same" | "down"; + + constructor( + app: App, + plugin: BCPlugin, + hnItem: HNItem, + file: TFile, + rel: "up" | "same" | "down" + ) { + super(app); + this.plugin = plugin; + this.modal = this; + this.hnItem = hnItem; + this.file = file; + this.rel = rel; + } + + onOpen() { + const { contentEl } = this; + contentEl.empty(); + + new ModifyHNItemComp({ + target: contentEl, + props: { + modal: this, + settings: this.plugin.settings, + hnItem: this.hnItem, + file: this.file, + rel: this.rel, + }, + }); + } + + onClose() { + this.contentEl.empty(); + } +} diff --git a/src/main.ts b/src/main.ts index 31704bcd..6cb742df 100644 --- a/src/main.ts +++ b/src/main.ts @@ -89,6 +89,7 @@ import { splitAtYaml, } from "./sharedFunctions"; import { VisModal } from "./VisModal"; +import { HierarchyNoteSelectorModal } from "./HierNoteModal"; export default class BCPlugin extends Plugin { settings: BCSettings; @@ -276,6 +277,12 @@ export default class BCPlugin extends Plugin { }, }); + this.addCommand({ + id: "manipulate-hierarchy-notes", + name: "Adjust Hierarchy Notes", + callback: () => new HierarchyNoteSelectorModal(this.app, this).open(), + }); + this.addCommand({ id: "Refresh-Breadcrumbs-Index", name: "Refresh Breadcrumbs Index",