chchar slash cmd (#4916) * Add an additional slash command to change a message's character and avatar. * Refactor message character change command to update message sender's name * Fix default value * Allow setting unbound message names --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | import { Fuse, DOMPurify } from '../lib.js'; |
| 2 | 2 | import { canUseNegativeLookbehind, copyText, findPersona, flashHighlight } from './utils.js'; |
| 3 | 3 | |
| 4 | 4 | import { |
| 5 | 5 | Generate, |
| @@ -7,6 +7,7 @@ import { | ||
| 7 | 7 | addOneMessage, |
| 8 | 8 | characters, |
| 9 | 9 | chat, |
| 10 | + chatElement, | |
| 10 | 11 | chat_metadata, |
| 11 | 12 | comment_avatar, |
| 12 | 13 | deactivateSendButtons, |
| @@ -765,6 +766,50 @@ export function initDefaultSlashCommands() { | ||
| 765 | 766 | `, |
| 766 | 767 | })); |
| 767 | 768 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 769 | + name: 'message-name', | |
| 770 | + callback: changeMessageName, | |
| 771 | + returns: 'The updated name of the message sender', | |
| 772 | + namedArgumentList: [ | |
| 773 | + SlashCommandNamedArgument.fromProps({ | |
| 774 | + name: 'at', | |
| 775 | + description: 'the ID of the message to modify (index-based, corresponding to message id). If omitted, the last message is chosen.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will modify the message right before the last message in chat. At must be nonzero.', | |
| 776 | + typeList: [ARGUMENT_TYPE.NUMBER], | |
| 777 | + defaultValue: '', | |
| 778 | + enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), | |
| 779 | + }), | |
| 780 | + ], | |
| 781 | + unnamedArgumentList: [ | |
| 782 | + SlashCommandArgument.fromProps({ | |
| 783 | + description: 'Persona name, character name, or unique character identifier (avatar key)', | |
| 784 | + typeList: [ARGUMENT_TYPE.STRING], | |
| 785 | + isRequired: true, | |
| 786 | + enumProvider: (executor) => { | |
| 787 | + let modifyAt = Number(executor.namedArgumentList.find(arg => arg.name === 'at')?.value ?? (chat.length - 1)); | |
| 788 | + if (!isNaN(modifyAt) && (modifyAt < 0 || Object.is(modifyAt, -0))) { | |
| 789 | + modifyAt = chat.length + modifyAt; | |
| 790 | + } | |
| 791 | + return chat[modifyAt]?.is_user | |
| 792 | + ? commonEnumProviders.personas() | |
| 793 | + : commonEnumProviders.characters('character')(); | |
| 794 | + }, | |
| 795 | + }), | |
| 796 | + ], | |
| 797 | + helpString: ` | |
| 798 | + <div> | |
| 799 | + Changes the name of a message sender to one of your choice. | |
| 800 | + </div> | |
| 801 | + <div> | |
| 802 | + <strong>Example:</strong> | |
| 803 | + <ul> | |
| 804 | + <li> | |
| 805 | + <pre><code>/message-name at=-2 "Chloe"</code></pre> | |
| 806 | + Will change the third message from the bottom to be sent by "Chloe". | |
| 807 | + </li> | |
| 808 | + </ul> | |
| 809 | + </div> | |
| 810 | + `, | |
| 811 | + })); | |
| 812 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 768 | 813 | name: 'sendas', |
| 769 | 814 | rawQuotes: true, |
| 770 | 815 | callback: sendMessageAs, |
| @@ -4510,6 +4555,72 @@ export function getNameAndAvatarForMessage(character, name = null) { | ||
| 4510 | 4555 | }; |
| 4511 | 4556 | } |
| 4512 | 4557 | |
| 4558 | +/** | |
| 4559 | + * Changes the character name on a message at a given index. | |
| 4560 | + * @param {object?} args - Named arguments | |
| 4561 | + * @param {string} name - Name to change to. | |
| 4562 | + * | |
| 4563 | + * @returns {Promise<string>} The updated message name. | |
| 4564 | + */ | |
| 4565 | +export async function changeMessageName(args, name) { | |
| 4566 | + name = String(name ?? '').trim(); | |
| 4567 | + if (!name) { | |
| 4568 | + toastr.warning(t`You must provide a name to change the message to.`); | |
| 4569 | + return ''; | |
| 4570 | + } | |
| 4571 | + | |
| 4572 | + let modifyAt = Number(args?.at ?? (chat.length - 1)); | |
| 4573 | + // Convert possible depth parameter to index | |
| 4574 | + if (!isNaN(modifyAt) && (modifyAt < 0 || Object.is(modifyAt, -0))) { | |
| 4575 | + // Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7) | |
| 4576 | + modifyAt = chat.length + modifyAt; | |
| 4577 | + } | |
| 4578 | + | |
| 4579 | + const message = chat[modifyAt]; | |
| 4580 | + if (!message) { | |
| 4581 | + toastr.warning(t`No message found at the specified index.`); | |
| 4582 | + return ''; | |
| 4583 | + } | |
| 4584 | + | |
| 4585 | + let newName = ''; | |
| 4586 | + | |
| 4587 | + if (message.is_user) { | |
| 4588 | + const persona = findPersona({ name: name }); | |
| 4589 | + if (persona) { | |
| 4590 | + message.name = newName = persona.name; | |
| 4591 | + message.force_avatar = getThumbnailUrl('persona', persona.avatar); | |
| 4592 | + message.original_avatar = persona.avatar; | |
| 4593 | + } else { | |
| 4594 | + message.name = newName = name; | |
| 4595 | + message.force_avatar = default_avatar; | |
| 4596 | + message.original_avatar = default_avatar; | |
| 4597 | + } | |
| 4598 | + } else { | |
| 4599 | + const character = findChar({ name: name }); | |
| 4600 | + if (character) { | |
| 4601 | + const characterInfo = getNameAndAvatarForMessage(character, name); | |
| 4602 | + message.name = newName = characterInfo.name; | |
| 4603 | + message.force_avatar = characterInfo.force_avatar; | |
| 4604 | + message.original_avatar = characterInfo.original_avatar; | |
| 4605 | + } else { | |
| 4606 | + message.name = newName = name; | |
| 4607 | + message.force_avatar = default_avatar; | |
| 4608 | + message.original_avatar = default_avatar; | |
| 4609 | + } | |
| 4610 | + } | |
| 4611 | + | |
| 4612 | + await eventSource.emit(event_types.MESSAGE_EDITED, modifyAt); | |
| 4613 | + const existingMessage = chatElement.find(`.mes[mesid="${modifyAt}"]`); | |
| 4614 | + if (existingMessage.length) { | |
| 4615 | + addOneMessage(message, { forceId: modifyAt, insertAfter: modifyAt, scroll: false }); | |
| 4616 | + existingMessage.remove(); | |
| 4617 | + } | |
| 4618 | + await eventSource.emit(event_types.MESSAGE_UPDATED, modifyAt); | |
| 4619 | + await saveChatConditional(); | |
| 4620 | + | |
| 4621 | + return newName; | |
| 4622 | +} | |
| 4623 | + | |
| 4513 | 4624 | export async function sendMessageAs(args, text) { |
| 4514 | 4625 | let name = args.name?.trim(); |
| 4515 | 4626 | |