Skip to content

Commit

Permalink
feat: add settings presets
Browse files Browse the repository at this point in the history
fix #12
  • Loading branch information
aviskase committed Nov 28, 2020
1 parent 2683048 commit 2be757a
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 87 deletions.
262 changes: 176 additions & 86 deletions src/main.ts
@@ -1,5 +1,5 @@
import deepmerge from 'deepmerge';
import { Plugin, PluginSettingTab, Setting, Vault, normalizePath, TFile, getLinkpath, ReferenceCache } from 'obsidian';
import { Plugin, PluginSettingTab, Setting, Vault, normalizePath, TFile, getLinkpath, ReferenceCache, Notice } from 'obsidian';

interface IndexNode {
count: number;
Expand All @@ -13,69 +13,118 @@ export default class LinkIndexer extends Plugin {
onInit() {}

async onload() {
this.settings = deepmerge(new LinkIndexerSettings(), (await this.loadData()));
this.addSettingTab(new LinkIndexerSettingTab(this.app, this));
const loadedSettings = await this.loadData();
if (loadedSettings) {
this.settings = deepmerge(new LinkIndexerSettings(), loadedSettings);
this.settings.usedLinks = [];
loadedSettings.usedLinks?.forEach((r: UsedLinks) => {
this.settings.usedLinks.push(deepmerge(new UsedLinks(), r))
});
} else {
this.settings = new LinkIndexerSettings();
}
this.reloadSettings();

this.addCommand({
id: 'link-indexer:all-used-links',
name: 'All used links',
callback: async () => await this.generateAllUsedLinksIndex()
});
this.addSettingTab(new LinkIndexerSettingTab(this.app, this));

}

async onunload() {
await this.saveData(this.settings);
}

async generateAllUsedLinksIndex() {
reloadSettings() {
this.removeOwnCommands();
this.settings.usedLinks.forEach((r: UsedLinks) => {
this.addCommand({
id: `link-indexer:used-links:${r.name}`,
name: `Used links - ${r.name}`,
callback: async () => await this.generateAllUsedLinksIndex(getPresetByName(this.settings.usedLinks, r.name)),
});
});
}

removeOwnCommands() {
// @ts-ignore
this.app.commands.listCommands().map((c) => c.id).filter((c) => c.startsWith(this.manifest.id)).forEach((c: string) => {
// @ts-ignore
this.app.commands.removeCommand(c);
});
}

async generateAllUsedLinksIndex(preset: UsedLinks) {
if (!preset) {
return new Notice(`${preset} was not found. Try reloading Obsidian.`);
}
const uniqueLinks: Record<string, IndexNode> = {};

const files = this.app.vault.getMarkdownFiles();
files.forEach((f) => {
this.grabLinks(uniqueLinks, f, this.app.metadataCache.getFileCache(f).links)
if (this.settings.includeEmbeds) {
this.grabLinks(uniqueLinks, f, this.app.metadataCache.getFileCache(f).embeds)
if (this.isExcludedFrom(f)) return;
this.grabLinks(uniqueLinks, f, this.app.metadataCache.getFileCache(f).links, preset)
if (preset.includeEmbeds) {
this.grabLinks(uniqueLinks, f, this.app.metadataCache.getFileCache(f).embeds, preset)
}
});
const sortedLinks = Object.entries(uniqueLinks).sort((a, b) => b[1].count - a[1].count);
const separator = this.settings.strictLineBreaks ? '\n\n' : '\n';
const separator = preset.strictLineBreaks ? '\n\n' : '\n';
const content = sortedLinks.map((l) => `${l[1].count} ${l[1].link}`).join(separator);
const exist = await this.app.vault.adapter.exists(normalizePath(this.settings.allUsedLinksPath), false);
const exist = await this.app.vault.adapter.exists(normalizePath(preset.path), false);
if (exist) {
const p = this.app.vault.getAbstractFileByPath(normalizePath(this.settings.allUsedLinksPath));
this.app.vault.adapter.write(normalizePath(this.settings.allUsedLinksPath), content);
const p = this.app.vault.getAbstractFileByPath(normalizePath(preset.path));
this.app.vault.adapter.write(normalizePath(preset.path), content);
} else {
this.app.vault.create(this.settings.allUsedLinksPath, content);
this.app.vault.create(preset.path, content);
}
}

grabLinks(uniqueLinks: Record<string, IndexNode>, f: TFile, links: ReferenceCache[]) {
isExcludedFrom(f: TFile) {
return this.settings.usedLinks.map((r) => r.path).includes(f.path);
}

grabLinks(uniqueLinks: Record<string, IndexNode>, f: TFile, links: ReferenceCache[], preset: UsedLinks) {
links?.forEach((l) => {
const link = getLinkpath(l.link);
const originFile = this.app.metadataCache.getFirstLinkpathDest(link, f.path);
if (this.settings.nonexistentOnly && originFile) {
if (preset.nonexistentOnly && originFile) {
return;
}
const origin = originFile ? originFile.path : link;
if (uniqueLinks[origin]) {
uniqueLinks[origin].count += 1;
} else {
const rawLink = originFile ? this.app.metadataCache.fileToLinktext(originFile, this.settings.allUsedLinksPath, true) : link;
const rawLink = originFile ? this.app.metadataCache.fileToLinktext(originFile, preset.path, true) : link;
uniqueLinks[origin] = {
count: 1,
link: this.settings.linkToFiles ? `[[${rawLink}]]` : rawLink
link: preset.linkToFiles ? `[[${rawLink}]]` : rawLink
};
}
});
}
}

class LinkIndexerSettings {
allUsedLinksPath = './all_used_links.md';
class UsedLinks {
name: string;
path: string;
strictLineBreaks = true;
includeEmbeds = true;
linkToFiles = true;
nonexistentOnly = false;

constructor() {
this.name = Date.now().toString();
this.path = `./used_links${this.name}.md`;
}
}

class LinkIndexerSettings {
usedLinks: UsedLinks[] = [];
}

type Preset = UsedLinks;

function getPresetByName(presets: Preset[], name: string): Preset {
return presets.find((r) => r.name === name);
}

class LinkIndexerSettingTab extends PluginSettingTab {
Expand All @@ -85,68 +134,109 @@ class LinkIndexerSettingTab extends PluginSettingTab {

containerEl.empty();

containerEl.createEl('h2', {text: 'Link indexer settings'});

new Setting(containerEl)
.setName('All used links')
.setDesc('Path to the note that will contain all found links sorted by their occurrences')
.addText((text) =>
text
.setPlaceholder(plugin.settings.allUsedLinksPath)
.setValue(plugin.settings.allUsedLinksPath)
.onChange(async (value) => {
plugin.settings.allUsedLinksPath = value;
await plugin.saveData(plugin.settings);
})
);

new Setting(containerEl)
.setName('Include embeds')
.setDesc('When disabled, only direct links are counted. Enable to include embedded (trascluded) links.')
.addToggle((value) =>
value
.setValue(plugin.settings.includeEmbeds)
.onChange(async (value) => {
plugin.settings.includeEmbeds = value;
await plugin.saveData(plugin.settings);
})
);

new Setting(containerEl)
.setName('Nonexistent files only')
.setDesc('When disabled, links to both existing and nonexisting files are counted.')
.addToggle((value) =>
value
.setValue(plugin.settings.nonexistentOnly)
.onChange(async (value) => {
plugin.settings.nonexistentOnly = value;
await plugin.saveData(plugin.settings);
})
);


new Setting(containerEl)
.setName('Strict line breaks')
.setDesc('Corresponds to the same Editor setting: "off" = one line break, "on" = two line breaks.')
.addToggle((value) =>
value
.setValue(plugin.settings.strictLineBreaks)
.onChange(async (value) => {
plugin.settings.strictLineBreaks = value;
await plugin.saveData(plugin.settings);
})
);

new Setting(containerEl)
.setName('Link to files')
.setDesc('When "on" the output file will use wiki-links to files. Disable if you don\'t want to pollute graph with it.')
.addToggle((value) =>
value
.setValue(plugin.settings.linkToFiles)
.onChange(async (value) => {
plugin.settings.linkToFiles = value;
await plugin.saveData(plugin.settings);
})
);
containerEl.createEl('h2', {text: 'Used links'});

plugin.settings.usedLinks.forEach((report) => {
new Setting(containerEl)
.setName('Preset name')
.setDesc('Allowed characters: ASCII letters, digits, underscores, spaces')
.addText((text) =>
text.setPlaceholder(report.name)
.setPlaceholder(report.name)
.setValue(report.name)
.onChange(async (value: string) => {
report.name = value;
await this.saveData({ refreshUI: false });
})
);
new Setting(containerEl)
.setName('All used links')
.setDesc('Path to the note that will contain all found links sorted by their occurrences')
.addText((text) =>
text
.setPlaceholder(report.path)
.setValue(report.path)
.onChange(async (value) => {
report.path = value;
await this.saveData({ refreshUI: false });
})
);

new Setting(containerEl)
.setName('Include embeds')
.setDesc('When disabled, only direct links are counted. Enable to include embedded (trascluded) links.')
.addToggle((value) =>
value
.setValue(report.includeEmbeds)
.onChange(async (value) => {
report.includeEmbeds = value;
await this.saveData({ refreshUI: false });
})
);

new Setting(containerEl)
.setName('Nonexistent files only')
.setDesc('When disabled, links to both existing and nonexisting files are counted.')
.addToggle((value) =>
value
.setValue(report.nonexistentOnly)
.onChange(async (value) => {
report.nonexistentOnly = value;
await this.saveData({ refreshUI: false });
})
);


new Setting(containerEl)
.setName('Strict line breaks')
.setDesc('Corresponds to the same Editor setting: "off" = one line break, "on" = two line breaks.')
.addToggle((value) =>
value
.setValue(report.strictLineBreaks)
.onChange(async (value) => {
report.strictLineBreaks = value;
await this.saveData({ refreshUI: false });
})
);

new Setting(containerEl)
.setName('Link to files')
.setDesc('When "on" the output file will use wiki-links to files. Disable if you don\'t want to pollute graph with it.')
.addToggle((value) =>
value
.setValue(report.linkToFiles)
.onChange(async (value) => {
report.linkToFiles = value;
await this.saveData({ refreshUI: false });
})
);
const deleteButton = new Setting(containerEl).addButton((extra) => {
return extra.setButtonText('Delete preset').onClick(async() => {
const index = plugin.settings.usedLinks.findIndex((r) => r.name === report.name);
if (index > -1) {
plugin.settings.usedLinks.splice(index, 1);
await this.saveData();
}
});
});
deleteButton.settingEl.style.borderBottom = '1px solid var(--text-accent)';
});

const addButton = new Setting(containerEl).addButton((button) => {
return button.setButtonText('Add preset').onClick(async () => {
plugin.settings.usedLinks.push(new UsedLinks());
await this.saveData();
});
});

addButton.infoEl.remove();
addButton.settingEl.style.justifyContent = 'center';
}

async saveData(options = { refreshUI: true }) {
const plugin: LinkIndexer = (this as any).plugin;
await plugin.saveData(plugin.settings);
plugin.reloadSettings();
if (options.refreshUI) this.display();
}
}
3 changes: 2 additions & 1 deletion versions.json
@@ -1,3 +1,4 @@
{
"0.0.1": "0.9.12"
"0.0.1": "0.9.12",
"0.1.0": "0.9.17"
}

0 comments on commit 2be757a

Please sign in to comment.