Merge pull request #3292 from SillyTavern/macrosparser

40d29bd4536565a041cc6514392ef416f0457b9b

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
2 files changed, +36 -1Ignore whitespace
public/scripts/macros.js+30 -1
@@ -26,6 +26,12 @@ Handlebars.registerHelper('helperMissing', function () {
2626 * @typedef {(nonce: string) => string} MacroFunction
2727 */
2828
29+/**
30+ * @typedef {Object} CustomMacro
31+ * @property {string} key - Macro name (key)
32+ * @property {string} description - Optional description of the macro
33+ */
34+
2935export class MacrosParser {
3036 /**
3137 * A map of registered macros.
@@ -34,11 +40,28 @@ export class MacrosParser {
3440 static #macros = new Map();
3541
3642 /**
43+ * A map of macro descriptions.
44+ * @type {Map<string, string>}
45+ */
46+ static #descriptions = new Map();
47+
48+ /**
49+ * Returns an iterator over all registered macros.
50+ * @returns {IterableIterator<CustomMacro>}
51+ */
52+ static [Symbol.iterator] = function* () {
53+ for (const macro of MacrosParser.#macros.keys()) {
54+ yield { key: macro, description: MacrosParser.#descriptions.get(macro) };
55+ }
56+ };
57+
58+ /**
3759 * Registers a global macro that can be used anywhere where substitution is allowed.
3860 * @param {string} key Macro name (key)
3961 * @param {string|MacroFunction} value A string or a function that returns a string
62+ * @param {string} [description] Optional description of the macro
4063 */
4164 static registerMacro(key, value, description = '') {
4265 if (typeof key !== 'string') {
4366 throw new Error('Macro key must be a string');
4467 }
@@ -64,6 +87,10 @@ export class MacrosParser {
6487 }
6588
6689 this.#macros.set(key, value);
90+
91+ if (typeof description === 'string' && description) {
92+ this.#descriptions.set(key, description);
93+ }
6794 }
6895
6996 /**
@@ -88,6 +115,8 @@ export class MacrosParser {
88115 if (!deleted) {
89116 console.warn(`Macro ${key} was not registered`);
90117 }
118+
119+ this.#descriptions.delete(key);
91120 }
92121
93122 /**
public/scripts/slash-commands/SlashCommandParser.js+6 -0
@@ -22,6 +22,8 @@ import { SlashCommandBreakPoint } from './SlashCommandBreakPoint.js';
2222import { SlashCommandDebugController } from './SlashCommandDebugController.js';
2323import { commonEnumProviders } from './SlashCommandCommonEnumsProvider.js';
2424import { SlashCommandBreak } from './SlashCommandBreak.js';
25+import { MacrosParser } from '../macros.js';
26+import { t } from '../i18n.js';
2527
2628/** @typedef {import('./SlashCommand.js').NamedArgumentsCapture} NamedArgumentsCapture */
2729/** @typedef {import('./SlashCommand.js').NamedArguments} NamedArguments */
@@ -494,6 +496,10 @@ export class SlashCommandParser {
494496 li.querySelector('tt').textContent,
495497 (li.querySelector('tt').remove(),li.innerHTML),
496498 ));
499+ for (const macro of MacrosParser) {
500+ if (options.find(it => it.name === macro.key)) continue;
501+ options.push(new MacroAutoCompleteOption(macro.key, `{{${macro.key}}}`, macro.description || t`No description provided`));
502+ }
497503 const result = new AutoCompleteNameResult(
498504 macro.name,
499505 macro.start + 2,