Add "name" argument to /hide and /unhide. Add default value for unnamed argument
| @@ -130,9 +130,10 @@ function getConverter(type) { | |||
| 130 | * @param {number} start Starting message ID | 130 | * @param {number} start Starting message ID |
| 131 | * @param {number} end Ending message ID (inclusive) | 131 | * @param {number} end Ending message ID (inclusive) |
| 132 | * @param {boolean} unhide If true, unhide the messages instead. | 132 | * @param {boolean} unhide If true, unhide the messages instead. |
| 133 | * @param {string} nameFitler Optional name filter | ||
| 133 | * @returns {Promise<void>} | 134 | * @returns {Promise<void>} |
| 134 | */ | 135 | */ |
| 135 | export async function hideChatMessageRange(start, end, unhide) { | 136 | export async function hideChatMessageRange(start, end, unhide, nameFitler = null) { |
| 136 | if (isNaN(start)) return; | 137 | if (isNaN(start)) return; |
| 137 | if (!end) end = start; | 138 | if (!end) end = start; |
| 138 | const hide = !unhide; | 139 | const hide = !unhide; |
| @@ -140,6 +141,7 @@ export async function hideChatMessageRange(start, end, unhide) { | |||
| 140 | for (let messageId = start; messageId <= end; messageId++) { | 141 | for (let messageId = start; messageId <= end; messageId++) { |
| 141 | const message = chat[messageId]; | 142 | const message = chat[messageId]; |
| 142 | if (!message) continue; | 143 | if (!message) continue; |
| 144 | if (nameFitler && message.name !== nameFitler) continue; | ||
| 143 | 145 | ||
| 144 | message.is_system = hide; | 146 | message.is_system = hide; |
| 145 | 147 | ||
| @@ -667,11 +667,21 @@ export function initDefaultSlashCommands() { | |||
| 667 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 667 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 668 | name: 'hide', | 668 | name: 'hide', |
| 669 | callback: hideMessageCallback, | 669 | callback: hideMessageCallback, |
| 670 | namedArgumentList: [ | ||
| 671 | SlashCommandNamedArgument.fromProps({ | ||
| 672 | name: 'name', | ||
| 673 | description: 'only hide messages from a certain character or persona', | ||
| 674 | typeList: [ARGUMENT_TYPE.STRING], | ||
| 675 | enumProvider: commonEnumProviders.messageNames, | ||
| 676 | isRequired: false, | ||
| 677 | acceptsMultiple: false, | ||
| 678 | }), | ||
| 679 | ], | ||
| 670 | unnamedArgumentList: [ | 680 | unnamedArgumentList: [ |
| 671 | SlashCommandArgument.fromProps({ | 681 | SlashCommandArgument.fromProps({ |
| 672 | description: 'message index (starts with 0) or range', | 682 | description: 'message index (starts with 0) or range, defaults to the last message index if not provided', |
| 673 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], | 683 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], |
| 674 | isRequired: true, | 684 | isRequired: false, |
| 675 | enumProvider: commonEnumProviders.messages(), | 685 | enumProvider: commonEnumProviders.messages(), |
| 676 | }), | 686 | }), |
| 677 | ], | 687 | ], |
| @@ -680,11 +690,21 @@ export function initDefaultSlashCommands() { | |||
| 680 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 690 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 681 | name: 'unhide', | 691 | name: 'unhide', |
| 682 | callback: unhideMessageCallback, | 692 | callback: unhideMessageCallback, |
| 693 | namedArgumentList: [ | ||
| 694 | SlashCommandNamedArgument.fromProps({ | ||
| 695 | name: 'name', | ||
| 696 | description: 'only unhide messages from a certain character or persona', | ||
| 697 | typeList: [ARGUMENT_TYPE.STRING], | ||
| 698 | enumProvider: commonEnumProviders.messageNames, | ||
| 699 | isRequired: false, | ||
| 700 | acceptsMultiple: false, | ||
| 701 | }), | ||
| 702 | ], | ||
| 683 | unnamedArgumentList: [ | 703 | unnamedArgumentList: [ |
| 684 | SlashCommandArgument.fromProps({ | 704 | SlashCommandArgument.fromProps({ |
| 685 | description: 'message index (starts with 0) or range', | 705 | description: 'message index (starts with 0) or range, defaults to the last message index if not provided', |
| 686 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], | 706 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], |
| 687 | isRequired: true, | 707 | isRequired: false, |
| 688 | enumProvider: commonEnumProviders.messages(), | 708 | enumProvider: commonEnumProviders.messages(), |
| 689 | }), | 709 | }), |
| 690 | ], | 710 | ], |
| @@ -3034,37 +3054,37 @@ async function askCharacter(args, text) { | |||
| 3034 | return await slashCommandReturnHelper.doReturn(args.return ?? 'pipe', message, { objectToStringFunc: x => x.mes }); | 3054 | return await slashCommandReturnHelper.doReturn(args.return ?? 'pipe', message, { objectToStringFunc: x => x.mes }); |
| 3035 | } | 3055 | } |
| 3036 | 3056 | ||
| 3037 | async function hideMessageCallback(_, arg) { | 3057 | async function hideMessageCallback(args, value) { |
| 3038 | if (!arg) { | 3058 | if (!value) { |
| 3039 | console.warn('WARN: No argument provided for /hide command'); | 3059 | console.log('No range provided. Hiding the last message.'); |
| 3040 | return ''; | ||
| 3041 | } | 3060 | } |
| 3042 | 3061 | ||
| 3043 | const range = stringToRange(arg, 0, chat.length - 1); | 3062 | const range = value ? stringToRange(value, 0, chat.length - 1) : { start: chat.length - 1, end: chat.length - 1 }; |
| 3044 | 3063 | ||
| 3045 | if (!range) { | 3064 | if (!range) { |
| 3046 | console.warn(`WARN: Invalid range provided for /hide command: ${arg}`); | 3065 | console.warn(`WARN: Invalid range provided for /hide command: ${value}`); |
| 3047 | return ''; | 3066 | return ''; |
| 3048 | } | 3067 | } |
| 3049 | 3068 | ||
| 3050 | await hideChatMessageRange(range.start, range.end, false); | 3069 | const nameFilter = String(args.name ?? '').trim(); |
| 3070 | await hideChatMessageRange(range.start, range.end, false, nameFilter); | ||
| 3051 | return ''; | 3071 | return ''; |
| 3052 | } | 3072 | } |
| 3053 | 3073 | ||
| 3054 | async function unhideMessageCallback(_, arg) { | 3074 | async function unhideMessageCallback(args, value) { |
| 3055 | if (!arg) { | 3075 | if (!value) { |
| 3056 | console.warn('WARN: No argument provided for /unhide command'); | 3076 | console.log('No range provided. Unhiding the last message'); |
| 3057 | return ''; | ||
| 3058 | } | 3077 | } |
| 3059 | 3078 | ||
| 3060 | const range = stringToRange(arg, 0, chat.length - 1); | 3079 | const range = value ? stringToRange(value, 0, chat.length - 1) : { start: chat.length - 1, end: chat.length - 1 }; |
| 3061 | 3080 | ||
| 3062 | if (!range) { | 3081 | if (!range) { |
| 3063 | console.warn(`WARN: Invalid range provided for /unhide command: ${arg}`); | 3082 | console.warn(`WARN: Invalid range provided for /unhide command: ${value}`); |
| 3064 | return ''; | 3083 | return ''; |
| 3065 | } | 3084 | } |
| 3066 | 3085 | ||
| 3067 | await hideChatMessageRange(range.start, range.end, true); | 3086 | const nameFilter = String(args.name ?? '').trim(); |
| 3087 | await hideChatMessageRange(range.start, range.end, true, nameFilter); | ||
| 3068 | return ''; | 3088 | return ''; |
| 3069 | } | 3089 | } |
| 3070 | 3090 | ||
| @@ -3,6 +3,7 @@ import { extension_settings } from '../extensions.js'; | |||
| 3 | import { getGroupMembers, groups } from '../group-chats.js'; | 3 | import { getGroupMembers, groups } from '../group-chats.js'; |
| 4 | import { power_user } from '../power-user.js'; | 4 | import { power_user } from '../power-user.js'; |
| 5 | import { searchCharByName, getTagsList, tags, tag_map } from '../tags.js'; | 5 | import { searchCharByName, getTagsList, tags, tag_map } from '../tags.js'; |
| 6 | import { onlyUnique } from '../utils.js'; | ||
| 6 | import { world_names } from '../world-info.js'; | 7 | import { world_names } from '../world-info.js'; |
| 7 | import { SlashCommandClosure } from './SlashCommandClosure.js'; | 8 | import { SlashCommandClosure } from './SlashCommandClosure.js'; |
| 8 | import { SlashCommandEnumValue, enumTypes } from './SlashCommandEnumValue.js'; | 9 | import { SlashCommandEnumValue, enumTypes } from './SlashCommandEnumValue.js'; |
| @@ -251,15 +252,23 @@ export const commonEnumProviders = { | |||
| 251 | * @param {boolean} [options.allowVars=false] - Whether to add enum option for variable names | 252 | * @param {boolean} [options.allowVars=false] - Whether to add enum option for variable names |
| 252 | * @returns {(executor:SlashCommandExecutor, scope:SlashCommandScope) => SlashCommandEnumValue[]} | 253 | * @returns {(executor:SlashCommandExecutor, scope:SlashCommandScope) => SlashCommandEnumValue[]} |
| 253 | */ | 254 | */ |
| 254 | messages: ({ allowIdAfter = false, allowVars = false } = {}) => (_, scope) => { | 255 | messages: ({ allowIdAfter = false, allowVars = false } = {}) => (executor, scope) => { |
| 256 | const nameFilter = executor.namedArgumentList.find(it => it.name == 'name')?.value || ''; | ||
| 255 | return [ | 257 | return [ |
| 256 | ...chat.map((message, index) => new SlashCommandEnumValue(String(index), `${message.name}: ${message.mes}`, enumTypes.number, message.is_user ? enumIcons.user : message.is_system ? enumIcons.system : enumIcons.assistant)), | 258 | ...chat.map((message, index) => new SlashCommandEnumValue(String(index), `${message.name}: ${message.mes}`, enumTypes.number, message.is_user ? enumIcons.user : message.is_system ? enumIcons.system : enumIcons.assistant)).filter(value => !nameFilter || value.description.startsWith(`${nameFilter}:`)), |
| 257 | ...allowIdAfter ? [new SlashCommandEnumValue(String(chat.length), '>> After Last Message >>', enumTypes.enum, '➕')] : [], | 259 | ...allowIdAfter ? [new SlashCommandEnumValue(String(chat.length), '>> After Last Message >>', enumTypes.enum, '➕')] : [], |
| 258 | ...allowVars ? commonEnumProviders.variables('all')(_, scope) : [], | 260 | ...allowVars ? commonEnumProviders.variables('all')(executor, scope) : [], |
| 259 | ]; | 261 | ]; |
| 260 | }, | 262 | }, |
| 261 | 263 | ||
| 262 | /** | 264 | /** |
| 265 | * All names used in the current chat. | ||
| 266 | * | ||
| 267 | * @returns {SlashCommandEnumValue[]} | ||
| 268 | */ | ||
| 269 | messageNames: () => chat.map((message) => message.name).filter(onlyUnique).sort(Intl.Collator().compare).map(name => new SlashCommandEnumValue(name)), | ||
| 270 | |||
| 271 | /** | ||
| 263 | * All existing worlds / lorebooks | 272 | * All existing worlds / lorebooks |
| 264 | * | 273 | * |
| 265 | * @returns {SlashCommandEnumValue[]} | 274 | * @returns {SlashCommandEnumValue[]} |
| @@ -6,7 +6,7 @@ import { | |||
| 6 | } from '../lib.js'; | 6 | } from '../lib.js'; |
| 7 | 7 | ||
| 8 | import { getContext } from './extensions.js'; | 8 | import { getContext } from './extensions.js'; |
| 9 | import { characters, getRequestHeaders, this_chid } from '../script.js'; | 9 | import { characters, getRequestHeaders, this_chid, user_avatar } from '../script.js'; |
| 10 | import { isMobile } from './RossAscends-mods.js'; | 10 | import { isMobile } from './RossAscends-mods.js'; |
| 11 | import { collapseNewlines, power_user } from './power-user.js'; | 11 | import { collapseNewlines, power_user } from './power-user.js'; |
| 12 | import { debounce_timeout } from './constants.js'; | 12 | import { debounce_timeout } from './constants.js'; |
| @@ -2197,6 +2197,48 @@ export async function showFontAwesomePicker(customList = null) { | |||
| 2197 | } | 2197 | } |
| 2198 | 2198 | ||
| 2199 | /** | 2199 | /** |
| 2200 | * Finds a persona by name, with optional filtering and precedence for avatars | ||
| 2201 | * @param {object} [options={}] - The options for the search | ||
| 2202 | * @param {string?} [options.name=null] - The name to search for | ||
| 2203 | * @param {boolean} [options.allowAvatar=true] - Whether to allow searching by avatar | ||
| 2204 | * @param {boolean} [options.insensitive=true] - Whether the search should be case insensitive | ||
| 2205 | * @param {boolean} [options.preferCurrentPersona=true] - Whether to prefer the current persona(s) | ||
| 2206 | * @param {boolean} [options.quiet=false] - Whether to suppress warnings | ||
| 2207 | * @returns {PersonaViewModel} The persona object | ||
| 2208 | * @typedef {object} PersonaViewModel | ||
| 2209 | * @property {string} avatar - The avatar of the persona | ||
| 2210 | * @property {string} name - The name of the persona | ||
| 2211 | */ | ||
| 2212 | export function findPersona({ name = null, allowAvatar = true, insensitive = true, preferCurrentPersona = true, quiet = false } = {}) { | ||
| 2213 | /** @type {PersonaViewModel[]} */ | ||
| 2214 | const personas = Object.entries(power_user.personas).map(([avatar, name]) => ({ avatar, name })); | ||
| 2215 | const matches = (/** @type {PersonaViewModel} */ persona) => !name || (allowAvatar && persona.avatar === name) || (insensitive ? equalsIgnoreCaseAndAccents(persona.name, name) : persona.name === name); | ||
| 2216 | |||
| 2217 | // If we have a current persona and prefer it, return that if it matches | ||
| 2218 | const currentPersona = personas.find(a => a.avatar === user_avatar); | ||
| 2219 | if (preferCurrentPersona && currentPersona && matches(currentPersona)) { | ||
| 2220 | return currentPersona; | ||
| 2221 | } | ||
| 2222 | |||
| 2223 | // If allowAvatar is true, search by avatar first | ||
| 2224 | if (allowAvatar && name) { | ||
| 2225 | const personaByAvatar = personas.find(a => a.avatar === name); | ||
| 2226 | if (personaByAvatar && matches(personaByAvatar)) { | ||
| 2227 | return personaByAvatar; | ||
| 2228 | } | ||
| 2229 | } | ||
| 2230 | |||
| 2231 | // Search for matching personas by name | ||
| 2232 | const matchingPersonas = personas.filter(a => matches(a)); | ||
| 2233 | if (matchingPersonas.length > 1) { | ||
| 2234 | if (!quiet) toastr.warning('Multiple personas found for given conditions.'); | ||
| 2235 | else console.warn('Multiple personas found for given conditions. Returning the first match.'); | ||
| 2236 | } | ||
| 2237 | |||
| 2238 | return matchingPersonas[0] || null; | ||
| 2239 | } | ||
| 2240 | |||
| 2241 | /** | ||
| 2200 | * Finds a character by name, with optional filtering and precedence for avatars | 2242 | * Finds a character by name, with optional filtering and precedence for avatars |
| 2201 | * @param {object} [options={}] - The options for the search | 2243 | * @param {object} [options={}] - The options for the search |
| 2202 | * @param {string?} [options.name=null] - The name to search for | 2244 | * @param {string?} [options.name=null] - The name to search for |