Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 93 additions & 18 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { App, debounce, Plugin, PluginSettingTab, Setting, TAbstractFile, TFile, TFolder } from 'obsidian';
import {App, debounce, Plugin, PluginSettingTab, Setting, TAbstractFile, TFile, TFolder, Vault} from 'obsidian';

interface WaypointSettings {
waypointFlag: string
stopScanAtFolderNotes: boolean,
showFolderNotes: boolean,
debugLogging: boolean,
ignoredFolders: string[],
root: string
useWikiLinks: boolean
}

Expand All @@ -13,7 +15,9 @@ const DEFAULT_SETTINGS: WaypointSettings = {
stopScanAtFolderNotes: false,
showFolderNotes: false,
debugLogging: false,
useWikiLinks: true
useWikiLinks: true,
ignoredFolders: ["Templates"],
root: null
}

export default class Waypoint extends Plugin {
Expand All @@ -29,7 +33,8 @@ export default class Waypoint extends Plugin {
// Register events after layout is built to avoid initial wave of 'create' events
this.registerEvent(this.app.vault.on("create", (file) => {
this.log("create " + file.name);
this.foldersWithChanges.add(file.parent);
const folderParent = this.getParentFolder(file.path);
this.foldersWithChanges.add(folderParent);
this.scheduleUpdate();
}));
this.registerEvent(this.app.vault.on("delete", (file) => {
Expand All @@ -42,7 +47,8 @@ export default class Waypoint extends Plugin {
}));
this.registerEvent(this.app.vault.on("rename", (file, oldPath) => {
this.log("rename " + file.name);
this.foldersWithChanges.add(file.parent);
const parentFolderOrigin = this.getParentFolder(file.path);
this.foldersWithChanges.add(parentFolderOrigin);
const parentFolder = this.getParentFolder(oldPath);
if (parentFolder !== null) {
this.foldersWithChanges.add(parentFolder);
Expand All @@ -54,6 +60,17 @@ export default class Waypoint extends Plugin {

// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new WaypointSettingsTab(this.app, this));

// Add in a hotkey to update the waypoint
this.addCommand({
id: "update-waypoint",
name: "Update waypoint in current file",
hotkeys: [{
modifiers: ["Ctrl"],
key: "w"
}],
callback: () => { this.updateWaypoint(this.app.workspace.getActiveFile()) }
})
}

onunload() {
Expand All @@ -74,10 +91,16 @@ export default class Waypoint extends Plugin {
this.log("Found waypoint flag in folder note!");
await this.updateWaypoint(file);
await this.updateParentWaypoint(file.parent, false);
return;
return;
} else if (this.outsideFolderPath(file)) {
await this.updateWaypoint(file);
await this.updateParentWaypoint(this.outsideFolderPath(file), false);
return;
} else if (file.parent.isRoot()) {
this.log("Found waypoint flag in root folder.");
this.printWaypointError(file, `%% Error: Cannot create a waypoint in the root folder of your vault. For more information, check the instructions [here](https://github.com/IdreesInc/Waypoint) %%`);
this.settings.root = file.name;
await this.saveSettings();
await this.updateWaypoint(file);
return;
} else {
this.log("Found waypoint flag in invalid note.");
Expand All @@ -89,6 +112,14 @@ export default class Waypoint extends Plugin {
this.log("No waypoint flags found.");
}

outsideFolderPath(file:TFile) {
const folderNotePath = this.app.vault.getAbstractFileByPath(file.path.replace('.md', ''));
if (folderNotePath && folderNotePath instanceof TFolder) {
return folderNotePath;
}
return null;
}

async printWaypointError(file: TFile, error: string) {
this.log("Creating waypoint error in " + file.path);
const text = await this.app.vault.read(file);
Expand All @@ -114,7 +145,12 @@ export default class Waypoint extends Plugin {
*/
async updateWaypoint(file: TFile) {
this.log("Updating waypoint in " + file.path);
const fileTree = await this.getFileTreeRepresentation(file.parent, 0, true);
const parentFolder = this.getParentFolder(file.path);
let fileTree = await this.getFileTreeRepresentation(parentFolder, 0, true);
if (parentFolder.isRoot()) {
const splitFileTree = fileTree.split("\n");
fileTree = `- **[[${file.basename}]]**\n${splitFileTree.slice(1).join("\n")}`
}
const waypoint = `${Waypoint.BEGIN_WAYPOINT}\n${fileTree}\n\n${Waypoint.END_WAYPOINT}`;
const text = await this.app.vault.read(file);
const lines: string[] = text.split("\n");
Expand Down Expand Up @@ -148,7 +184,8 @@ export default class Waypoint extends Plugin {
async getFileTreeRepresentation(node: TAbstractFile, indentLevel: number, topLevel = false): Promise<string>|null {
const bullet = " ".repeat(indentLevel) + "-";
if (node instanceof TFile) {
if (node.path.endsWith(".md")) {
// Check for the parent being the root because otherwise the "root note" would be included in the tree
if (node.path.endsWith(".md") && !node.parent.isRoot()) {
if (this.settings.useWikiLinks) {
return `${bullet} [[${node.basename}]]`;
} else {
Expand All @@ -157,6 +194,7 @@ export default class Waypoint extends Plugin {
}
return null;
} else if (node instanceof TFolder) {
if (this.settings.ignoredFolders.includes(node.path)) { return null }
let text = `${bullet} **${node.name}**`;
const folderNote = this.app.vault.getAbstractFileByPath(node.path + "/" + node.name + ".md");
if (folderNote instanceof TFile) {
Expand All @@ -183,8 +221,8 @@ export default class Waypoint extends Plugin {
}).filter(child => this.settings.showFolderNotes || child.name !== node.name + ".md");
if (children.length > 0) {
text += "\n" + (await Promise.all(children.map(child => this.getFileTreeRepresentation(child, indentLevel + 1))))
.filter(Boolean)
.join("\n");
.filter(Boolean)
.join("\n");
}
return text;
} else {
Expand Down Expand Up @@ -237,17 +275,29 @@ export default class Waypoint extends Plugin {
async locateParentWaypoint(node: TAbstractFile, includeCurrentNode: boolean): Promise<TFile> {
this.log("Locating parent waypoint of " + node.name);
let folder = includeCurrentNode ? node : node.parent;
while (folder) {
const folderNote = this.app.vault.getAbstractFileByPath(folder.path + "/" + folder.name + ".md");
if (folderNote instanceof TFile) {
this.log("Found folder note: " + folderNote.path);
const text = await this.app.vault.cachedRead(folderNote);
if (node.parent.isRoot() && this.settings.root !== null) {
const file = this.app.vault.getAbstractFileByPath(this.settings.root)
if (file instanceof TFile) {
this.log("Found folder note: " + file.path);
const text = await this.app.vault.cachedRead(file);
if (text.includes(Waypoint.BEGIN_WAYPOINT) || text.includes(this.settings.waypointFlag)) {
this.log("Found parent waypoint!");
return folderNote;
return file;
}
}
folder = folder.parent;
} else {
while (folder) {
const folderNote = this.app.vault.getAbstractFileByPath(folder.path + "/" + folder.name + ".md");
if (folderNote instanceof TFile) {
this.log("Found folder note: " + folderNote.path);
const text = await this.app.vault.cachedRead(folderNote);
if (text.includes(Waypoint.BEGIN_WAYPOINT) || text.includes(this.settings.waypointFlag)) {
this.log("Found parent waypoint!");
return folderNote;
}
}
folder = folder.parent;
}
}
this.log("No parent waypoint found.");
return null;
Expand All @@ -260,16 +310,19 @@ export default class Waypoint extends Plugin {
*/
getParentFolder(path: string): TFolder {
const abstractFile = this.app.vault.getAbstractFileByPath(path.split("/").slice(0, -1).join("/"));
const abstractOutsideFolder = this.app.vault.getAbstractFileByPath(path.replace('.md', ''));
if (abstractFile instanceof TFolder) {
return abstractFile;
} else if (abstractOutsideFolder instanceof TFolder) {
return abstractOutsideFolder;
} else {
return null;
}
}

log(message: string) {
if (this.settings.debugLogging) {
console.log(message);
console.log(message);
}
}

Expand Down Expand Up @@ -340,6 +393,28 @@ class WaypointSettingsTab extends PluginSettingTab {
await this.plugin.saveSettings();
})
);
new Setting(containerEl)
.setName("Ignored folders")
.setDesc("Folders that Waypoint should ignore")
.addText(text => text
.setPlaceholder(DEFAULT_SETTINGS.ignoredFolders.join(","))
.setValue(this.plugin.settings.ignoredFolders.join(", "))
.onChange(async (value) => {
const previous = this.plugin.settings.ignoredFolders;
this.plugin.settings.ignoredFolders = value.split(/\s*,\s*/);
await this.plugin.saveSettings();

// Get a list of all new and old folders that need updating
const allFolders = [...new Set([...previous, ...this.plugin.settings.ignoredFolders])]
for (let i = 0; i < allFolders.length; i++) {
const file = this.app.vault.getAbstractFileByPath(allFolders[i]);
if (file === null) { continue }
await this.plugin.locateParentWaypoint(file, false).then((file) => {
if (file !== null) { this.plugin.updateWaypoint(file) }
})
}
})
);
const postscriptElement = containerEl.createEl("div", {
cls: "setting-item",
});
Expand Down
8 changes: 8 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.