Plugin built.

This commit is contained in:
Caleb Campbell
2024-06-28 11:41:14 +10:00
parent e60294b950
commit 0ffb5f83a1
9 changed files with 1167 additions and 137 deletions

132
main.ts
View File

@@ -1,134 +1,24 @@
import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
import { Plugin } from 'obsidian';
import LocalBibleRefSettingTab from 'src/LocalBibleRefSettingTab';
import { PassageSuggester } from 'src/PassageSuggester';
import { LocalBibleRefSettings } from 'src/config/settings';
// Remember to rename these classes and interfaces!
interface MyPluginSettings {
mySetting: string;
}
const DEFAULT_SETTINGS: MyPluginSettings = {
mySetting: 'default'
}
export default class MyPlugin extends Plugin {
settings: MyPluginSettings;
export default class LocalBibleRefPlugin extends Plugin {
settings: LocalBibleRefSettings;
async onload() {
await this.loadSettings();
// This creates an icon in the left ribbon.
const ribbonIconEl = this.addRibbonIcon('dice', 'Sample Plugin', (evt: MouseEvent) => {
// Called when the user clicks the icon.
new Notice('This is a notice!');
});
// Perform additional things with the ribbon
ribbonIconEl.addClass('my-plugin-ribbon-class');
// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
const statusBarItemEl = this.addStatusBarItem();
statusBarItemEl.setText('Status Bar Text');
// This adds a simple command that can be triggered anywhere
this.addCommand({
id: 'open-sample-modal-simple',
name: 'Open sample modal (simple)',
callback: () => {
new SampleModal(this.app).open();
}
});
// This adds an editor command that can perform some operation on the current editor instance
this.addCommand({
id: 'sample-editor-command',
name: 'Sample editor command',
editorCallback: (editor: Editor, view: MarkdownView) => {
console.log(editor.getSelection());
editor.replaceSelection('Sample Editor Command');
}
});
// This adds a complex command that can check whether the current state of the app allows execution of the command
this.addCommand({
id: 'open-sample-modal-complex',
name: 'Open sample modal (complex)',
checkCallback: (checking: boolean) => {
// Conditions to check
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
if (markdownView) {
// If checking is true, we're simply "checking" if the command can be run.
// If checking is false, then we want to actually perform the operation.
if (!checking) {
new SampleModal(this.app).open();
}
// This command will only show up in Command Palette when the check function returns true
return true;
}
}
});
// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new SampleSettingTab(this.app, this));
// If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
// Using this function will automatically remove the event listener when this plugin is disabled.
this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
console.log('click', evt);
});
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
this.addSettingTab(new LocalBibleRefSettingTab(this.app, this));
this.registerEditorSuggest(new PassageSuggester(this.app, this.settings));
}
onunload() {
}
onunload() {}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
this.settings = await this.loadData();
}
async saveSettings() {
await this.saveData(this.settings);
}
}
class SampleModal extends Modal {
constructor(app: App) {
super(app);
}
onOpen() {
const {contentEl} = this;
contentEl.setText('Woah!');
}
onClose() {
const {contentEl} = this;
contentEl.empty();
}
}
class SampleSettingTab extends PluginSettingTab {
plugin: MyPlugin;
constructor(app: App, plugin: MyPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const {containerEl} = this;
containerEl.empty();
new Setting(containerEl)
.setName('Setting #1')
.setDesc('It\'s a secret')
.addText(text => text
.setPlaceholder('Enter your secret')
.setValue(this.plugin.settings.mySetting)
.onChange(async (value) => {
this.plugin.settings.mySetting = value;
await this.plugin.saveSettings();
}));
}
}
}

View File

@@ -1,11 +1,11 @@
{
"id": "sample-plugin",
"name": "Sample Plugin",
"id": "local-bible-ref",
"name": "Local Bible Ref",
"version": "1.0.0",
"minAppVersion": "0.15.0",
"description": "Demonstrates some of the capabilities of the Obsidian API.",
"author": "Obsidian",
"authorUrl": "https://obsidian.md",
"fundingUrl": "https://obsidian.md/pricing",
"description": "Quickly and easily reference Bible verses stored locally in your Obsidian vault.",
"author": "calebcampbell",
"authorUrl": "https://mastodon.social/@calebcampbell",
"fundingUrl": "",
"isDesktopOnly": false
}

658
package-lock.json generated Normal file
View File

@@ -0,0 +1,658 @@
{
"name": "local-bible-ref",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@esbuild/android-arm": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.3.tgz",
"integrity": "sha512-1Mlz934GvbgdDmt26rTLmf03cAgLg5HyOgJN+ZGCeP3Q9ynYTNMn2/LQxIl7Uy+o4K6Rfi2OuLsr12JQQR8gNg==",
"dev": true,
"optional": true
},
"@esbuild/android-arm64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.3.tgz",
"integrity": "sha512-XvJsYo3dO3Pi4kpalkyMvfQsjxPWHYjoX4MDiB/FUM4YMfWcXa5l4VCwFWVYI1+92yxqjuqrhNg0CZg3gSouyQ==",
"dev": true,
"optional": true
},
"@esbuild/android-x64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.3.tgz",
"integrity": "sha512-nuV2CmLS07Gqh5/GrZLuqkU9Bm6H6vcCspM+zjp9TdQlxJtIe+qqEXQChmfc7nWdyr/yz3h45Utk1tUn8Cz5+A==",
"dev": true,
"optional": true
},
"@esbuild/darwin-arm64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.3.tgz",
"integrity": "sha512-01Hxaaat6m0Xp9AXGM8mjFtqqwDjzlMP0eQq9zll9U85ttVALGCGDuEvra5Feu/NbP5AEP1MaopPwzsTcUq1cw==",
"dev": true,
"optional": true
},
"@esbuild/darwin-x64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.3.tgz",
"integrity": "sha512-Eo2gq0Q/er2muf8Z83X21UFoB7EU6/m3GNKvrhACJkjVThd0uA+8RfKpfNhuMCl1bKRfBzKOk6xaYKQZ4lZqvA==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-arm64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.3.tgz",
"integrity": "sha512-CN62ESxaquP61n1ZjQP/jZte8CE09M6kNn3baos2SeUfdVBkWN5n6vGp2iKyb/bm/x4JQzEvJgRHLGd5F5b81w==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-x64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.3.tgz",
"integrity": "sha512-feq+K8TxIznZE+zhdVurF3WNJ/Sa35dQNYbaqM/wsCbWdzXr5lyq+AaTUSER2cUR+SXPnd/EY75EPRjf4s1SLg==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.3.tgz",
"integrity": "sha512-CLP3EgyNuPcg2cshbwkqYy5bbAgK+VhyfMU7oIYyn+x4Y67xb5C5ylxsNUjRmr8BX+MW3YhVNm6Lq6FKtRTWHQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.3.tgz",
"integrity": "sha512-JHeZXD4auLYBnrKn6JYJ0o5nWJI9PhChA/Nt0G4MvLaMrvXuWnY93R3a7PiXeJQphpL1nYsaMcoV2QtuvRnF/g==",
"dev": true,
"optional": true
},
"@esbuild/linux-ia32": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.3.tgz",
"integrity": "sha512-FyXlD2ZjZqTFh0sOQxFDiWG1uQUEOLbEh9gKN/7pFxck5Vw0qjWSDqbn6C10GAa1rXJpwsntHcmLqydY9ST9ZA==",
"dev": true,
"optional": true
},
"@esbuild/linux-loong64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.3.tgz",
"integrity": "sha512-OrDGMvDBI2g7s04J8dh8/I7eSO+/E7nMDT2Z5IruBfUO/RiigF1OF6xoH33Dn4W/OwAWSUf1s2nXamb28ZklTA==",
"dev": true,
"optional": true
},
"@esbuild/linux-mips64el": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.3.tgz",
"integrity": "sha512-DcnUpXnVCJvmv0TzuLwKBC2nsQHle8EIiAJiJ+PipEVC16wHXaPEKP0EqN8WnBe0TPvMITOUlP2aiL5YMld+CQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-ppc64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.3.tgz",
"integrity": "sha512-BDYf/l1WVhWE+FHAW3FzZPtVlk9QsrwsxGzABmN4g8bTjmhazsId3h127pliDRRu5674k1Y2RWejbpN46N9ZhQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-riscv64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.3.tgz",
"integrity": "sha512-WViAxWYMRIi+prTJTyV1wnqd2mS2cPqJlN85oscVhXdb/ZTFJdrpaqm/uDsZPGKHtbg5TuRX/ymKdOSk41YZow==",
"dev": true,
"optional": true
},
"@esbuild/linux-s390x": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.3.tgz",
"integrity": "sha512-Iw8lkNHUC4oGP1O/KhumcVy77u2s6+KUjieUqzEU3XuWJqZ+AY7uVMrrCbAiwWTkpQHkr00BuXH5RpC6Sb/7Ug==",
"dev": true,
"optional": true
},
"@esbuild/linux-x64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.3.tgz",
"integrity": "sha512-0AGkWQMzeoeAtXQRNB3s4J1/T2XbigM2/Mn2yU1tQSmQRmHIZdkGbVq2A3aDdNslPyhb9/lH0S5GMTZ4xsjBqg==",
"dev": true,
"optional": true
},
"@esbuild/netbsd-x64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.3.tgz",
"integrity": "sha512-4+rR/WHOxIVh53UIQIICryjdoKdHsFZFD4zLSonJ9RRw7bhKzVyXbnRPsWSfwybYqw9sB7ots/SYyufL1mBpEg==",
"dev": true,
"optional": true
},
"@esbuild/openbsd-x64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.3.tgz",
"integrity": "sha512-cVpWnkx9IYg99EjGxa5Gc0XmqumtAwK3aoz7O4Dii2vko+qXbkHoujWA68cqXjhh6TsLaQelfDO4MVnyr+ODeA==",
"dev": true,
"optional": true
},
"@esbuild/sunos-x64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.3.tgz",
"integrity": "sha512-RxmhKLbTCDAY2xOfrww6ieIZkZF+KBqG7S2Ako2SljKXRFi+0863PspK74QQ7JpmWwncChY25JTJSbVBYGQk2Q==",
"dev": true,
"optional": true
},
"@esbuild/win32-arm64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.3.tgz",
"integrity": "sha512-0r36VeEJ4efwmofxVJRXDjVRP2jTmv877zc+i+Pc7MNsIr38NfsjkQj23AfF7l0WbB+RQ7VUb+LDiqC/KY/M/A==",
"dev": true,
"optional": true
},
"@esbuild/win32-ia32": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.3.tgz",
"integrity": "sha512-wgO6rc7uGStH22nur4aLFcq7Wh86bE9cOFmfTr/yxN3BXvDEdCSXyKkO+U5JIt53eTOgC47v9k/C1bITWL/Teg==",
"dev": true,
"optional": true
},
"@esbuild/win32-x64": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.3.tgz",
"integrity": "sha512-FdVl64OIuiKjgXBjwZaJLKp0eaEckifbhn10dXWhysMJkWblg3OEEGKSIyhiD5RSgAya8WzP3DNkngtIg3Nt7g==",
"dev": true,
"optional": true
},
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
}
},
"@nodelib/fs.stat": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"dev": true
},
"@nodelib/fs.walk": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"dev": true,
"requires": {
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
}
},
"@types/codemirror": {
"version": "5.60.8",
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz",
"integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==",
"dev": true,
"requires": {
"@types/tern": "*"
}
},
"@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"dev": true
},
"@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"dev": true
},
"@types/node": {
"version": "16.18.98",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.98.tgz",
"integrity": "sha512-fpiC20NvLpTLAzo3oVBKIqBGR6Fx/8oAK/SSf7G+fydnXMY1x4x9RZ6sBXhqKlCU21g2QapUsbLlhv3+a7wS+Q==",
"dev": true
},
"@types/tern": {
"version": "0.23.9",
"resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz",
"integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==",
"dev": true,
"requires": {
"@types/estree": "*"
}
},
"@typescript-eslint/eslint-plugin": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz",
"integrity": "sha512-kgTsISt9pM53yRFQmLZ4npj99yGl3x3Pl7z4eA66OuTzAGC4bQB5H5fuLwPnqTKU3yyrrg4MIhjF17UYnL4c0w==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.29.0",
"@typescript-eslint/type-utils": "5.29.0",
"@typescript-eslint/utils": "5.29.0",
"debug": "^4.3.4",
"functional-red-black-tree": "^1.0.1",
"ignore": "^5.2.0",
"regexpp": "^3.2.0",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/parser": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.29.0.tgz",
"integrity": "sha512-ruKWTv+x0OOxbzIw9nW5oWlUopvP/IQDjB5ZqmTglLIoDTctLlAJpAQFpNPJP/ZI7hTT9sARBosEfaKbcFuECw==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.29.0",
"@typescript-eslint/types": "5.29.0",
"@typescript-eslint/typescript-estree": "5.29.0",
"debug": "^4.3.4"
}
},
"@typescript-eslint/scope-manager": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.29.0.tgz",
"integrity": "sha512-etbXUT0FygFi2ihcxDZjz21LtC+Eps9V2xVx09zFoN44RRHPrkMflidGMI+2dUs821zR1tDS6Oc9IXxIjOUZwA==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.29.0",
"@typescript-eslint/visitor-keys": "5.29.0"
}
},
"@typescript-eslint/type-utils": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.29.0.tgz",
"integrity": "sha512-JK6bAaaiJozbox3K220VRfCzLa9n0ib/J+FHIwnaV3Enw/TO267qe0pM1b1QrrEuy6xun374XEAsRlA86JJnyg==",
"dev": true,
"requires": {
"@typescript-eslint/utils": "5.29.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/types": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.29.0.tgz",
"integrity": "sha512-X99VbqvAXOMdVyfFmksMy3u8p8yoRGITgU1joBJPzeYa0rhdf5ok9S56/itRoUSh99fiDoMtarSIJXo7H/SnOg==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.29.0.tgz",
"integrity": "sha512-mQvSUJ/JjGBdvo+1LwC+GY2XmSYjK1nAaVw2emp/E61wEVYEyibRHCqm1I1vEKbXCpUKuW4G7u9ZCaZhJbLoNQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.29.0",
"@typescript-eslint/visitor-keys": "5.29.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/utils": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.29.0.tgz",
"integrity": "sha512-3Eos6uP1nyLOBayc/VUdKZikV90HahXE5Dx9L5YlSd/7ylQPXhLk1BYb29SDgnBnTp+jmSZUU0QxUiyHgW4p7A==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.9",
"@typescript-eslint/scope-manager": "5.29.0",
"@typescript-eslint/types": "5.29.0",
"@typescript-eslint/typescript-estree": "5.29.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0"
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.29.0.tgz",
"integrity": "sha512-Hpb/mCWsjILvikMQoZIE3voc9wtQcS0A9FUw3h8bhr9UxBdtI/tw1ZDZUOXHXLOVMedKCH5NxyzATwnU78bWCQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.29.0",
"eslint-visitor-keys": "^3.3.0"
}
},
"array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true
},
"braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"requires": {
"fill-range": "^7.1.1"
}
},
"builtin-modules": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
"integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
"dev": true
},
"debug": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"dev": true,
"requires": {
"ms": "2.1.2"
}
},
"dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
"dev": true,
"requires": {
"path-type": "^4.0.0"
}
},
"esbuild": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.3.tgz",
"integrity": "sha512-9n3AsBRe6sIyOc6kmoXg2ypCLgf3eZSraWFRpnkto+svt8cZNuKTkb1bhQcitBcvIqjNiK7K0J3KPmwGSfkA8g==",
"dev": true,
"requires": {
"@esbuild/android-arm": "0.17.3",
"@esbuild/android-arm64": "0.17.3",
"@esbuild/android-x64": "0.17.3",
"@esbuild/darwin-arm64": "0.17.3",
"@esbuild/darwin-x64": "0.17.3",
"@esbuild/freebsd-arm64": "0.17.3",
"@esbuild/freebsd-x64": "0.17.3",
"@esbuild/linux-arm": "0.17.3",
"@esbuild/linux-arm64": "0.17.3",
"@esbuild/linux-ia32": "0.17.3",
"@esbuild/linux-loong64": "0.17.3",
"@esbuild/linux-mips64el": "0.17.3",
"@esbuild/linux-ppc64": "0.17.3",
"@esbuild/linux-riscv64": "0.17.3",
"@esbuild/linux-s390x": "0.17.3",
"@esbuild/linux-x64": "0.17.3",
"@esbuild/netbsd-x64": "0.17.3",
"@esbuild/openbsd-x64": "0.17.3",
"@esbuild/sunos-x64": "0.17.3",
"@esbuild/win32-arm64": "0.17.3",
"@esbuild/win32-ia32": "0.17.3",
"@esbuild/win32-x64": "0.17.3"
}
},
"eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"dev": true,
"requires": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
}
},
"eslint-utils": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
"integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
"dev": true,
"requires": {
"eslint-visitor-keys": "^2.0.0"
},
"dependencies": {
"eslint-visitor-keys": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
"dev": true
}
}
},
"eslint-visitor-keys": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true
},
"esrecurse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
"requires": {
"estraverse": "^5.2.0"
},
"dependencies": {
"estraverse": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true
}
}
},
"estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"dev": true
},
"fast-glob": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
"glob-parent": "^5.1.2",
"merge2": "^1.3.0",
"micromatch": "^4.0.4"
}
},
"fastq": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
"dev": true,
"requires": {
"reusify": "^1.0.4"
}
},
"fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"functional-red-black-tree": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
"integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
"dev": true
},
"glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
},
"globby": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
"dev": true,
"requires": {
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
"fast-glob": "^3.2.9",
"ignore": "^5.2.0",
"merge2": "^1.4.1",
"slash": "^3.0.0"
}
},
"ignore": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
"integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
"dev": true
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true
},
"is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true
},
"micromatch": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
"dev": true,
"requires": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
}
},
"moment": {
"version": "2.29.4",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
"dev": true
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"obsidian": {
"version": "1.5.7-1",
"resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.5.7-1.tgz",
"integrity": "sha512-T5ZRuQ1FnfXqEoakTTHVDYvzUEEoT8zSPnQCW31PVgYwG4D4tZCQfKHN2hTz1ifnCe8upvwa6mBTAP2WUA5Vng==",
"dev": true,
"requires": {
"@types/codemirror": "5.60.8",
"moment": "2.29.4"
}
},
"path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true
},
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true
},
"queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true
},
"regexpp": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
"integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
"dev": true
},
"reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true
},
"run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
"dev": true,
"requires": {
"queue-microtask": "^1.2.2"
}
},
"semver": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
"integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
"dev": true
},
"slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
},
"tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
"dev": true
},
"tsutils": {
"version": "3.21.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
"integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
"dev": true,
"requires": {
"tslib": "^1.8.1"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
}
}
},
"typescript": {
"version": "4.7.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
"dev": true
}
}
}

View File

@@ -1,7 +1,7 @@
{
"name": "obsidian-sample-plugin",
"name": "local-bible-ref",
"version": "1.0.0",
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
"description": "Quickly and easily reference Bible verses stored locally in your Obsidian vault.",
"main": "main.js",
"scripts": {
"dev": "node esbuild.config.mjs",

View File

@@ -0,0 +1,53 @@
import LocalBibleRefPlugin from "main";
import { App, Notice, PluginSettingTab, Setting } from "obsidian";
export default class LocalBibleRefSettingTab extends PluginSettingTab {
plugin: LocalBibleRefPlugin;
constructor(app: App, plugin: LocalBibleRefPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
this.containerEl.createEl('h1', { text: 'Local Bible Ref' });
let biblesPathTimeout: NodeJS.Timeout;
new Setting(containerEl)
.setName("Bibles Path")
.setDesc("The path to the folder containing your bibles.")
.addText(text => text
.setPlaceholder("e.g. Data/Bibles")
.onChange(async (value) => {
this.plugin.settings.biblesPath = value;
await this.plugin.saveSettings();
clearTimeout(biblesPathTimeout);
biblesPathTimeout = setTimeout(async () => {
const exists = await this.app.vault.adapter.exists(value);
if (!exists) new Notice(`Bibles folder doesn't exist at path: ${value}.`);
}, 500);
}));
let defaultVersionTimeout: NodeJS.Timeout;
new Setting(containerEl)
.setName("Default Version Shorthand")
.setDesc("The version to use by default - shorthand.")
.addText(text => text
.setPlaceholder("e.g. ESV")
.onChange(async (value) => {
this.plugin.settings.defaultVersionShorthand = value;
await this.plugin.saveSettings();
clearTimeout(defaultVersionTimeout);
defaultVersionTimeout = setTimeout(async () => {
const path = `${this.plugin.settings.biblesPath}/${value}`;
const exists = await this.app.vault.adapter.exists(path);
if (!exists) new Notice(`Version folder doesn't exist at path: ${path}.`);
}, 500);
}));
}
}

356
src/PassageSuggester.ts Normal file
View File

@@ -0,0 +1,356 @@
import {
App,
Editor,
EditorPosition,
EditorSuggest,
EditorSuggestContext,
Notice,
TFile
} from "obsidian";
import { BOOKS, Book } from "./data/books";
import { LocalBibleRefSettings } from "./config/settings";
interface ChapterReference {
startChapter: number;
startVerse: number;
endChapter: number;
endVerse: number;
}
interface PassageReference extends ChapterReference {
book: Book;
}
interface PassageSuggestion {
passageRef: string;
suggestText: string;
fullText: string;
}
export class PassageSuggester extends EditorSuggest<PassageSuggestion> {
private settings: LocalBibleRefSettings;
private passageRegex: RegExp;
constructor(app: App, settings: LocalBibleRefSettings) {
super(app);
this.settings = settings;
// builds the book matching regex
let regexString = BOOKS.reduce((string, book) => {
return `${string}${book.name}|${book.aliases.join("|")}|`;
}, "^\\-\\- ?(");
regexString = regexString.slice(0, -1);
regexString += ") ?(\\d{1,3}(?::\\d{1,3})?(?: ?\\- ?\\d{1,3}(?::\\d{1,3})?)?)$";
this.passageRegex = new RegExp(regexString, "i");
}
onTrigger(cursor: EditorPosition, editor: Editor, _: TFile | null) {
// min ref length is 6 ("--gen1")
if (cursor.ch < 6) return null;
// line must start with "--"
const line = editor.getLine(cursor.line);
if (!line.startsWith("--")) return null;
// must be a passage ref
const isPassage = this.passageRegex.test(line);
if (!isPassage) return null;
// trigger info
return { end: cursor, query: line, start: { ch: 0, line: cursor.line } };
}
async getSuggestions(context: EditorSuggestContext): Promise<PassageSuggestion[]> {
const passageRef = this.parsePassageRef(context.query);
if (!passageRef) return [];
// grab all chapters in the range
let chapterTexts = await this.getChapterTexts(passageRef);
console.log(passageRef);
console.log(BOOKS);
if (!chapterTexts) return [];
// split first chapter by start verse
const chapterFromVerse = this.getChapterFromStartVerse(chapterTexts[0], passageRef);
if (!chapterFromVerse) return [];
chapterTexts[0] = chapterFromVerse;
// split last chapter by end verse
const lastIndex = chapterTexts.length - 1;
const chapterToVerse = this.getChapterToEndVerse(chapterTexts[lastIndex], passageRef);
if (!chapterToVerse) return [];
chapterTexts[lastIndex] = chapterToVerse;
// clean up chapter texts
chapterTexts = chapterTexts.map((text, i) => {
text = this.removeHeadings(text);
text = this.removeFootnoteRefs(text);
text = this.removeEOF(text);
const chapter = passageRef.startChapter + i;
if (text.startsWith("> ")) {
const quoteMd = text.match(/^(?:> )+/)![0];
return text.replace(quoteMd, `${quoteMd}**${chapter}.** `);
}
if (text.startsWith("- ")) {
const listMd = text.match(/^(?:- )+/)![0];
return text.replace(listMd, `${listMd}**${chapter}.** `);
}
return text = `**${chapter}.** ${text}`;
});
// suggest
return [{
passageRef: this.encodePassageRef(passageRef),
suggestText: this.generateSuggestText(chapterTexts[0]),
fullText: chapterTexts.join("\n\n")
}];
}
renderSuggestion(item: PassageSuggestion, el: HTMLElement): void {
el.innerText = item.suggestText;
}
selectSuggestion(item: PassageSuggestion, _: MouseEvent | KeyboardEvent): void {
if (!this.context) return;
let text = item.fullText.replace(/\n/gm, "\n> ");
text = `> [!bible]+ ${item.passageRef}\n> ${text}`;
this.context.editor.replaceRange(text, this.context.start, this.context.end);
}
/**
* Parses a passage reference from the given text.
*
* @param text the text to parse.
* @returns a parsed PassageReference or null.
*/
private parsePassageRef(text: string): PassageReference | null {
const passageRefMatch = text.match(this.passageRegex);
if (!passageRefMatch) return null;
let chapterRef = this.parseMultiChapterRef(passageRefMatch[2]);
if (!chapterRef) chapterRef = this.parseMultiPartChapterRef(passageRefMatch[2]);
if (!chapterRef) chapterRef = this.parsePartChapterRef(passageRefMatch[2]);
if (!chapterRef) return null;
const book = this.getBook(passageRefMatch[1]);
if (!book) return null;
return { book, ...chapterRef };
}
/**
* Parses a multi-chapter reference from the given text.
* Reference is in the format: `startChapter[ - endChapter]`.
*
* @param text the text to parse.
* @returns a parsed ChapterReference or null.
*/
private parseMultiChapterRef(text: string): ChapterReference | null {
const regex = /^(\d{1,3})(?: ?- ?(\d{1,3}))?$/i;
const match = text.match(regex);
if (!match) return null;
const startChapter = parseInt(match[1]);
return {
startChapter,
startVerse: 1,
endChapter: match[2] ? parseInt(match[2]) : startChapter,
endVerse: -1,
};
}
/**
* Parses a multi-(part)-chapter reference from the given text.
* Reference is in the format: `startChapter:startVerse - endChapter:endVerse`.
*
* @param text the text to parse.
* @returns a parsed ChapterReference or null.
*/
private parseMultiPartChapterRef(text: string): ChapterReference | null {
const regex = /^(\d{1,3}):(\d{1,3}) ?- ?(\d{1,3}):(\d{1,3})$/i;
const match = text.match(regex);
if (!match) return null;
return {
startChapter: parseInt(match[1]),
startVerse: parseInt(match[2]),
endChapter: parseInt(match[3]),
endVerse: parseInt(match[4]),
};
}
/**
* Parses a part-chapter reference from the given text.
* Reference is in the format: `startChapter:startVerse[-endVerse]`.
*
* @param text the text to parse.
* @returns a parsed ChapterReference or null.
*/
private parsePartChapterRef(text: string): ChapterReference | null {
const regex = /^(\d{1,3}):(\d{1,3})(?: ?- ?(\d{1,3}))?$/i;
const match = text.match(regex);
if (!match) return null;
const startChapter = parseInt(match[1]);
const startVerse = parseInt(match[2]);
return {
startChapter,
startVerse,
endChapter: startChapter,
endVerse: match[3] ? parseInt(match[3]) : startVerse,
};
}
/**
* Retrieves a book based on it's alias.
* @param alias the alias of the book.
* @returns the book object if found, otherwise undefined.
*/
private getBook(alias: string): Book | undefined {
alias = alias.toLowerCase();
return BOOKS.find((book) => {
if (book.name.toLowerCase() === alias) return book;
if (book.aliases.includes(alias)) return book;
})
}
/**
* Retrieves the texts of the chapters within the specified passage reference.
*
* @param ref the passage reference.
* @returns a promise - an array of chapter texts or null.
*/
private async getChapterTexts(ref: PassageReference): Promise<string[] | null> {
let basePath = "";
for (let alias of [ref.book.name, ...ref.book.aliases]) {
console.log(alias);
basePath = [
this.settings.biblesPath,
this.settings.defaultVersionShorthand,
alias
].join("/");
console.log(basePath);
if (await this.app.vault.adapter.exists(basePath)) {
ref.book.aliases.push(ref.book.name);
ref.book.aliases.remove(alias);
ref.book.name = alias;
console.log(ref);
break;
}
}
const chapterTexts: string[] = [];
for (let ch = ref.startChapter; ch <= ref.endChapter; ch++) {
const path = basePath + `/${ref.book.name} ${ch}.md`;
const file = this.app.vault.getFileByPath(path);
if (!file) {
new Notice(`Could not find chapter at: ${path}`);
return null;
}
chapterTexts.push(await this.app.vault.cachedRead(file));
}
return chapterTexts;
}
/**
* Retrieves the text in the chapter from the start verse to the end.
*
* @param text the text to cut.
* @param ref the passage reference.
* @returns the text from the start verse or null.
*/
private getChapterFromStartVerse(text: string, ref: PassageReference): string | null {
const regex = new RegExp(`(?:> |- )*<sup>${ref.startVerse}</sup>`);
const match = text.match(regex);
if (!match) {
const verse = ref.startVerse;
const chapter = ref.startChapter;
const book = ref.book.name;
new Notice(`Could not find verse ${verse} in ${book} ${chapter}.`);
return null;
}
const verseLabel = match[0];
const parts = text.split(regex);
return verseLabel + parts[1];
};
/**
* Retrieves the text in the chapter from the start to the end verse.
*
* @param text the text to cut.
* @param ref the passage reference.
* @returns the text up to the end verse or null.
*/
private getChapterToEndVerse(text: string, ref: PassageReference): string | null {
if (ref.endVerse === -1) return text;
const regex = new RegExp(`(?:^(?:> |- )*)?<sup>${ref.endVerse + 1}</sup>`, "m");
return text.split(regex, 1)[0].trim();
};
/** Removes headings from the given text. */
private removeHeadings(text: string): string {
return text.replace(/^#.*[\n\r\f]*/gm, "");
}
/** Removes footnote refs from the given text. */
private removeFootnoteRefs(text: string): string {
return text.replace(/ \[\^\d{1,4}\]/g, "");
}
/** Removes the end-of-file content from the given text. */
private removeEOF(text: string): string {
// split at chapter divider
let split = text.split(/^\-\-\-$/m);
// split at footnotes
split = split[0].split(/^\[\^\d+\]:/m, 1);
return split[0].trim();
}
/** Generates suggestion text. */
private generateSuggestText(text: string): string {
text = text.split(/<\/sup>/, 2)[1];
text = text.replace(/(?:<sup>\d+<\/sup>|> |- )/g, "");
text = text.replace(/<span style="font-variant: small-caps;">Lord<\/span>/g, "Lord");
text = text.replace(/\n/g, " ");
text = text.replace(/ /g, " ");
return text.slice(0, 45) + "...";
}
/**
* Encodes a PassageReference into a string representation.
*
* @param ref the PassageReference to encode.
* @returns the encoded string representation.
*/
private encodePassageRef(ref: PassageReference): string {
// whole chapter/s ref
if (ref.startVerse === 1 && ref.endVerse === -1) {
if (ref.startChapter === ref.endChapter) {
return `${ref.book.name} ${ref.startChapter}`;
}
return `${ref.book.name} ${ref.startChapter}-${ref.endChapter}`;
}
// part chapter ref
if (ref.startChapter === ref.endChapter) {
if (ref.startVerse === ref.endVerse) {
return `${ref.book.name} ${ref.startChapter}:${ref.startVerse}`;
}
return `${ref.book.name} ${ref.startChapter}:${ref.startVerse}-${ref.endVerse}`;
}
// part chapters ref
const a = `${ref.startChapter}:${ref.startVerse}`;
const b = `${ref.endChapter}:${ref.endVerse}`;
return `${ref.book.name} ${a}-${b}`;
}
}

4
src/config/settings.ts Normal file
View File

@@ -0,0 +1,4 @@
export interface LocalBibleRefSettings {
biblesPath: string;
defaultVersionShorthand: string;
}

73
src/data/books.ts Normal file
View File

@@ -0,0 +1,73 @@
export interface Book {
name: string;
aliases: string[];
}
export const BOOKS: Book[] = [
{ name: "Genesis", aliases: ["gen"] },
{ name: "Exodus", aliases: ["exo"] },
{ name: "Leviticus", aliases: ["lev"] },
{ name: "Numbers", aliases: ["num"] },
{ name: "Deuteronomy", aliases: ["deu"] },
{ name: "Joshua", aliases: ["jos"] },
{ name: "Judges", aliases: ["jdg"] },
{ name: "Ruth", aliases: ["rut"] },
{ name: "1 Samuel", aliases: ["1sa"] },
{ name: "2 Samuel", aliases: ["2sa"] },
{ name: "1 Kings", aliases: ["1ki"] },
{ name: "2 Kings", aliases: ["2ki"] },
{ name: "1 Chronicles", aliases: ["1ch"] },
{ name: "2 Chronicles", aliases: ["2ch"] },
{ name: "Ezra", aliases: ["ezr"] },
{ name: "Nehemiah", aliases: ["neh"] },
{ name: "Esther", aliases: ["est"] },
{ name: "Job", aliases: ["job"] },
{ name: "Psalms", aliases: ["psa"] },
{ name: "Proverbs", aliases: ["pro"] },
{ name: "Ecclesiastes", aliases: ["ecc"] },
{ name: "Song of Songs", aliases: ["sng", "Song of Solomon"] },
{ name: "Isaiah", aliases: ["isa"] },
{ name: "Jeremiah", aliases: ["jer"] },
{ name: "Lamentations", aliases: ["lam"] },
{ name: "Ezekiel", aliases: ["ezk"] },
{ name: "Daniel", aliases: ["dan"] },
{ name: "Hosea", aliases: ["hos"] },
{ name: "Joel", aliases: ["jol"] },
{ name: "Amos", aliases: ["amo"] },
{ name: "Obadiah", aliases: ["oba"] },
{ name: "Jonah", aliases: ["jon"] },
{ name: "Micah", aliases: ["mic"] },
{ name: "Nahum", aliases: ["nam"] },
{ name: "Habakkuk", aliases: ["hab"] },
{ name: "Zephaniah", aliases: ["zep"] },
{ name: "Haggai", aliases: ["hag"] },
{ name: "Zechariah", aliases: ["zec"] },
{ name: "Malachi", aliases: ["mal"] },
{ name: "Matthew", aliases: ["mat"] },
{ name: "Mark", aliases: ["mrk"] },
{ name: "Luke", aliases: ["luk"] },
{ name: "John", aliases: ["jhn"] },
{ name: "Acts", aliases: ["act"] },
{ name: "Romans", aliases: ["rom"] },
{ name: "1 Corinthians", aliases: ["1co"] },
{ name: "2 Corinthians", aliases: ["2co"] },
{ name: "Galatians", aliases: ["gal"] },
{ name: "Ephesians", aliases: ["eph"] },
{ name: "Philippians", aliases: ["php"] },
{ name: "Colossians", aliases: ["col"] },
{ name: "1 Thessalonians", aliases: ["1th"] },
{ name: "2 Thessalonians", aliases: ["2th"] },
{ name: "1 Timothy", aliases: ["1ti"] },
{ name: "2 Timothy", aliases: ["2ti"] },
{ name: "Titus", aliases: ["tit"] },
{ name: "Philemon", aliases: ["phm"] },
{ name: "Hebrews", aliases: ["heb"] },
{ name: "James", aliases: ["jas"] },
{ name: "1 Peter", aliases: ["1pe"] },
{ name: "2 Peter", aliases: ["2pe"] },
{ name: "1 John", aliases: ["1jn"] },
{ name: "2 John", aliases: ["2jn"] },
{ name: "3 John", aliases: ["3jn"] },
{ name: "Jude", aliases: ["jud"] },
{ name: "Revelation", aliases: ["rev"] },
];

View File

@@ -1,8 +1,4 @@
/*
This CSS file will be included with your plugin, and
available in the app when your plugin is enabled.
If your plugin does not need CSS, delete this file.
*/
.callout[data-callout="bible"] {
--callout-color: var(--callout-quote);
--callout-icon: lucide-book-open-text;
}