-
Notifications
You must be signed in to change notification settings - Fork 24
/
main.js
118 lines (104 loc) · 4.48 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
const {Plugin, Notice, debounce} = require("obsidian");
const watchNeeded = window.process.platform !== "darwin" && window.process.platform !== "win32";
module.exports = class HotReload extends Plugin {
statCache = new Map(); // path -> Stat
queue = Promise.resolve();
run(val, err) {
return this.queue = this.queue.then(val, err);
}
reindexPlugins = debounce(() => this.run(() => this.getPluginNames()), 500, true);
requestScan = debounce(() => this.run(() => this.checkVersions()), 250, true);
onload() {
app.workspace.onLayoutReady(async ()=> {
this.pluginReloaders = {};
this.inProgress = null;
await this.getPluginNames();
this.registerEvent( this.app.vault.on("raw", this.requestScan));
this.watch(this.app.plugins.getPluginFolder());
this.requestScan();
this.addCommand({
id: "scan-for-changes",
name: "Check plugins for changes and reload them",
callback: () => this.requestScan()
})
});
}
async watch(path) {
if (this.app.vault.adapter.watchers.hasOwnProperty(path)) return;
if ((await this.app.vault.adapter.stat(path)).type !== "folder") return;
if (watchNeeded || this.isSymlink(path)) this.app.vault.adapter.startWatchPath(path, false);
}
isSymlink = (() => {
try {
const fs = require('fs');
return path => {
const realPath = [this.app.vault.adapter.basePath, path].join("/");
const lstat = fs.lstatSync(realPath, {throwIfNoEntry: false});
return lstat && lstat.isSymbolicLink();
}
} catch (e) {
return () => true;
}
})();
async checkVersions() {
const base = this.app.plugins.getPluginFolder();
for (const dir of Object.keys(this.pluginNames)) {
for (const file of ["manifest.json", "main.js", "styles.css", ".hotreload"]) {
const path = `${base}/${dir}/${file}`;
const stat = await app.vault.adapter.stat(path);
if (stat) {
if (this.statCache.has(path) && stat.mtime !== this.statCache.get(path).mtime) {
this.onFileChange(path);
}
this.statCache.set(path, stat);
}
}
}
}
async getPluginNames() {
const plugins = {}, enabled = new Set();
for (const {id, dir} of Object.values(app.plugins.manifests)) {
this.watch(dir);
plugins[dir.split("/").pop()] = id;
if (
await this.app.vault.exists(dir+"/.git") ||
await this.app.vault.exists(dir+"/.hotreload")
) enabled.add(id);
}
this.pluginNames = plugins;
this.enabledPlugins = enabled;
}
onFileChange(filename) {
if (!filename.startsWith(this.app.plugins.getPluginFolder()+"/")) return;
const path = filename.split("/");
const base = path.pop(), dir = path.pop();
if (path.length === 1 && dir === "plugins") return this.watch(filename);
if (path.length != 2) return;
const plugin = dir && this.pluginNames[dir];
if (base === "manifest.json" || base === ".hotreload" || base === ".git" || !plugin) return this.reindexPlugins();
if (base !== "main.js" && base !== "styles.css") return;
if (!this.enabledPlugins.has(plugin)) return;
const reloader = this.pluginReloaders[plugin] || (
this.pluginReloaders[plugin] = debounce(() => this.run(() => this.reload(plugin), console.error), 750, true)
);
reloader();
}
async reload(plugin) {
const plugins = app.plugins;
// Don't reload disabled plugins
if (!plugins.enabledPlugins.has(plugin)) return;
await plugins.disablePlugin(plugin);
console.debug("disabled", plugin);
// Ensure sourcemaps are loaded (Obsidian 14+)
const oldDebug = localStorage.getItem("debug-plugin");
localStorage.setItem("debug-plugin", "1");
try {
await plugins.enablePlugin(plugin);
} finally {
// Restore previous setting
if (oldDebug === null) localStorage.removeItem("debug-plugin"); else localStorage.setItem("debug-plugin", oldDebug);
}
console.debug("enabled", plugin);
new Notice(`Plugin "${plugin}" has been reloaded`);
}
}