Add "name" argument to /hide and /unhide. Add default value for unnamed argument

1026e1f8e9675af890bc392583c8e81bc285d6ef

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

4 files changed, +96 -23Showing whitespace changes
public/scripts/chats.js+3 -1
@@ -130,9 +130,10 @@ function getConverter(type) {
130 * @param {number} start Starting message ID130 * @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 */
135export async function hideChatMessageRange(start, end, unhide) {136export 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;
143145
144 message.is_system = hide;146 message.is_system = hide;
145147
public/scripts/slash-commands.js+38 -18
@@ -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}
30363056
3037async function hideMessageCallback(_, arg) {3057async 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 }
30423061
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 };
30443063
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 }
30493068
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}
30533073
3054async function unhideMessageCallback(_, arg) {3074async 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 }
30593078
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 };
30613080
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 }
30663085
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}
30703090
public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js+12 -3
@@ -3,6 +3,7 @@ import { extension_settings } from '../extensions.js';
3import { getGroupMembers, groups } from '../group-chats.js';3import { getGroupMembers, groups } from '../group-chats.js';
4import { power_user } from '../power-user.js';4import { power_user } from '../power-user.js';
5import { searchCharByName, getTagsList, tags, tag_map } from '../tags.js';5import { searchCharByName, getTagsList, tags, tag_map } from '../tags.js';
6import { onlyUnique } from '../utils.js';
6import { world_names } from '../world-info.js';7import { world_names } from '../world-info.js';
7import { SlashCommandClosure } from './SlashCommandClosure.js';8import { SlashCommandClosure } from './SlashCommandClosure.js';
8import { SlashCommandEnumValue, enumTypes } from './SlashCommandEnumValue.js';9import { 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 names252 * @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 },
261263
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 / lorebooks272 * All existing worlds / lorebooks
264 *273 *
265 * @returns {SlashCommandEnumValue[]}274 * @returns {SlashCommandEnumValue[]}
public/scripts/utils.js+43 -1
@@ -6,7 +6,7 @@ import {
6} from '../lib.js';6} from '../lib.js';
77
8import { getContext } from './extensions.js';8import { getContext } from './extensions.js';
9import { characters, getRequestHeaders, this_chid } from '../script.js';9import { characters, getRequestHeaders, this_chid, user_avatar } from '../script.js';
10import { isMobile } from './RossAscends-mods.js';10import { isMobile } from './RossAscends-mods.js';
11import { collapseNewlines, power_user } from './power-user.js';11import { collapseNewlines, power_user } from './power-user.js';
12import { debounce_timeout } from './constants.js';12import { debounce_timeout } from './constants.js';
@@ -2197,6 +2197,48 @@ export async function showFontAwesomePicker(customList = null) {
2197}2197}
21982198
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 */
2212export 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 avatars2242 * Finds a character by name, with optional filtering and precedence for avatars
2201 * @param {object} [options={}] - The options for the search2243 * @param {object} [options={}] - The options for the search
2202 * @param {string?} [options.name=null] - The name to search for2244 * @param {string?} [options.name=null] - The name to search for