From 3834916065bd1095df835b0f2cabad9c79db662c Mon Sep 17 00:00:00 2001 From: PJ Date: Thu, 28 Jul 2022 19:41:57 -0400 Subject: [PATCH] Add commands to open plugins' settings and hotkeys (Also, fix an issue with the "Core plugins" tab not rendering properly.) --- README.md | 1 + manifest.json | 2 +- pnpm-lock.yaml | 8 ++-- src/hotkey-helper.ts | 86 +++++++++++++++++++++++++++++++-------- src/obsidian-internals.ts | 4 +- versions.json | 2 +- 6 files changed, 79 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index abacbb8..f033813 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ > New in... > +> * 0.3.13: Commands to let you open hotkeys or settings by typing the plugin name > * 0.3.12: Jump to edit a hotkey with Ctrl- or Cmd-Enter from the command palette! > * 0.3.8: Hit enter while typing in the community plugin search box to open the plugin catalog with that search > * 0.3.5: Plugin searches are saved and carry through when browsing the plugin catalog diff --git a/manifest.json b/manifest.json index 1fa7e64..d1ccca7 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "hotkey-helper", "name": "Hotkey Helper", - "version": "0.3.12", + "version": "0.3.13", "minAppVersion": "0.15.9", "description": "Easily see and access any plugin's settings or hotkey assignments (and conflicts) from the Community Plugins tab", "author": "PJ Eby", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9af5ce3..371b660 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,7 +9,7 @@ specifiers: devDependencies: '@ophidian/build': 1.0.0 - '@ophidian/core': github.com/ophidian-lib/core/2d905e2c17822ff73eb57ff830823d21e244fff9 + '@ophidian/core': github.com/ophidian-lib/core/65ad44e4d0039aa026e12e32e772a36b8bf2650a i18next: 20.6.1 monkey-around: 2.3.0 obsidian: 0.15.4 @@ -854,10 +854,10 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - github.com/ophidian-lib/core/2d905e2c17822ff73eb57ff830823d21e244fff9: - resolution: {tarball: https://codeload.github.com/ophidian-lib/core/tar.gz/2d905e2c17822ff73eb57ff830823d21e244fff9} + github.com/ophidian-lib/core/65ad44e4d0039aa026e12e32e772a36b8bf2650a: + resolution: {tarball: https://codeload.github.com/ophidian-lib/core/tar.gz/65ad44e4d0039aa026e12e32e772a36b8bf2650a} name: '@ophidian/core' - version: 0.0.10 + version: 0.0.11 dependencies: monkey-around: 2.3.0 obsidian: 0.15.4 diff --git a/src/hotkey-helper.ts b/src/hotkey-helper.ts index 25a17e7..7373ea4 100644 --- a/src/hotkey-helper.ts +++ b/src/hotkey-helper.ts @@ -3,7 +3,7 @@ import { ExtraButtonComponent, Hotkey, Command, SearchComponent } from "obsidian"; import {around, serialize} from "monkey-around"; -import {defer, onElement} from "@ophidian/core"; +import {defer, modalSelect, onElement} from "@ophidian/core"; import "./obsidian-internals"; function hotkeyToString(hotkey: Hotkey) { @@ -204,6 +204,52 @@ export default class HotkeyHelper extends Plugin { name: "Browse or search the Community Plugins catalog", callback: () => this.gotoPlugin() }) + const alphaSort = new Intl.Collator(undefined, {usage: "sort", sensitivity: "base", numeric: true}).compare; + this.addCommand({ + id: "open-settings", + name: "Open settings for plugin...", + callback: async () => { + const {item} = await modalSelect( + app.setting.pluginTabs.concat(app.setting.settingTabs).sort((a, b) => alphaSort(a.name, b.name)), + t => t.name, + "Select a plugin to open its settings...", + ); + if (item) { + app.setting.open() + app.setting.openTabById(item.id); + } + } + }); + this.addCommand({ + id: "open-hotkeys", + name: "Open hotkeys for plugin...", + callback: async () => { + const commandsByPlugin = this.refreshCommands(); + const plugins = Object.values(app.plugins.plugins) + .map(p => p.manifest as Partial) + .concat( + Object.entries(app.internalPlugins.plugins) + .map( + ([id, {instance: {name}, _loaded:enabled}]) => {return {id, name, enabled};} + ) + .filter(p => p.enabled) + ) + .concat([ + {id: "app", name: "App"}, + {id: "editor", name: this.getSettingsTab("editor")?.name || "Editor"}, + {id: "workspace", name: this.getSettingsTab("file")?.name || "Files & Links"} + ]) + .filter(m => commandsByPlugin[m.id]?.length); + ; + const {item} = await modalSelect( + plugins.sort((a, b) => alphaSort(a.name, b.name)), + t => t.name, + "Select a plugin to open its hotkeys..."); + if (item) { + this.showHotkeysFor(item.id+":"); + } + } + }); } createExtraButtons(setting: Setting, manifest: {id: string, name: string}, enabled: boolean) { @@ -390,12 +436,12 @@ export default class HotkeyHelper extends Plugin { let manifests: {id: string, name: string, enabled?: boolean}[]; if (tabId === "plugins") { manifests = Object.entries(app.internalPlugins.plugins).map( - ([id, {instance: {name}, _loaded:enabled}]) => {return {id, name, enabled};} - ); + ([id, {instance: {name, hiddenFromList}, _loaded:enabled}]) => {return !hiddenFromList && {id, name, enabled};} + ).filter(m => m); } else { manifests = Object.values(app.plugins.manifests); - manifests.sort((e, t) => e.name.localeCompare(t.name)); } + manifests.sort((e, t) => e.name.localeCompare(t.name)); let which = 0; // Trap the addition of the "uninstall" buttons next to each plugin @@ -487,24 +533,30 @@ export default class HotkeyHelper extends Plugin { return app.internalPlugins.plugins[id]?._loaded || app.plugins.plugins[id]; } - refreshButtons(force=false) { - // Don't refresh when not displaying, unless rendering is in progress - if (!pluginSettingsAreOpen() && !force) return; + commandsByPlugin = {} as Record; + assignedKeyCount = {} as Record; + refreshCommands() { const hkm = app.hotkeyManager; - const assignedKeyCount = {} as Record; - - // Get a list of commands by plugin - const commands = Object.values(this.app.commands.commands).reduce((cmds, cmd)=>{ + this.assignedKeyCount = {}; + return this.commandsByPlugin = Object.values(app.commands.commands).reduce((cmds, cmd)=>{ const pid = cmd.id.split(":",2).shift(); const hotkeys = (hkm.getHotkeys(cmd.id) || hkm.getDefaultHotkeys(cmd.id) || []).map(hotkeyToString); - hotkeys.forEach(k => assignedKeyCount[k] = 1 + (assignedKeyCount[k]||0)); + hotkeys.forEach(k => this.assignedKeyCount[k] = 1 + (this.assignedKeyCount[k]||0)); (cmds[pid] || (cmds[pid]=[])).push({hotkeys, cmd}); return cmds; }, {} as Record); + } + + refreshButtons(force=false) { + // Don't refresh when not displaying, unless rendering is in progress + if (!pluginSettingsAreOpen() && !force) return; + + // Get a list of commands by plugin + this.refreshCommands(); // Plugin setting tabs by plugin - const tabs = Object.values(this.app.setting.pluginTabs).reduce((tabs, tab)=> { + const tabs = Object.values(app.setting.pluginTabs).reduce((tabs, tab)=> { tabs[tab.id] = tab; return tabs }, {} as Record); tabs["workspace"] = tabs["editor"] = true; @@ -520,16 +572,16 @@ export default class HotkeyHelper extends Plugin { for(const id of Object.keys(this.hotkeyButtons || {})) { const btn = this.hotkeyButtons[id]; - if (!commands[id]) { + if (!this.commandsByPlugin[id]) { // Plugin is disabled or has no commands btn.extraSettingsEl.hide(); continue; } - const assigned = commands[id].filter(info => info.hotkeys.length); - const conflicts = assigned.filter(info => info.hotkeys.filter(k => assignedKeyCount[k]>1).length).length; + const assigned = this.commandsByPlugin[id].filter(info => info.hotkeys.length); + const conflicts = assigned.filter(info => info.hotkeys.filter(k => this.assignedKeyCount[k]>1).length).length; btn.setTooltip( - `Configure hotkeys${"\n"}(${assigned.length}/${commands[id].length} assigned${ + `Configure hotkeys${"\n"}(${assigned.length}/${this.commandsByPlugin[id].length} assigned${ conflicts ? "; "+conflicts+" conflicting" : "" })` ); diff --git a/src/obsidian-internals.ts b/src/obsidian-internals.ts index d53dca3..c291038 100644 --- a/src/obsidian-internals.ts +++ b/src/obsidian-internals.ts @@ -49,6 +49,7 @@ declare module "obsidian" { interface SettingTab { id: string + name: string searchInputEl?: HTMLInputElement; // XXX should be subtypes for hotkey and plugin tabs updateHotkeyVisibility?(): void; } @@ -59,7 +60,7 @@ declare module "obsidian" { interface Plugins { manifests: Record; - plugins: Record; + plugins: Record; enablePlugin(pluginId: string): Promise; disblePlugin(pluginId: string): Promise; @@ -82,6 +83,7 @@ declare module "obsidian" { type InternalPluginInstance = T & { name: string + hiddenFromList: boolean } type ViewFactory = (leaf: WorkspaceLeaf) => View diff --git a/versions.json b/versions.json index 2780d74..1842c6b 100644 --- a/versions.json +++ b/versions.json @@ -1,5 +1,5 @@ { - "0.3.12": "0.15.9", + "0.3.13": "0.15.9", "0.3.11": "0.13.19", "0.3.8": "0.12.3", "0.3.0": "0.12.1",