/* * Vencord, a modification for Discord's desktop app * Copyright (c) 2023 Vendicated and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import { definePluginSettings } from "@api/Settings"; import { Divider } from "@components/Divider"; import { Flex } from "@components/Flex"; import { HeadingTertiary } from "@components/Heading"; import { DeleteIcon } from "@components/Icons"; import { Devs, EquicordDevs } from "@utils/constants"; import { Logger } from "@utils/Logger"; import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Message } from "@vencord/discord-types"; import { Button, React, Select, TextInput, UserStore, useState } from "@webpack/common"; type Rule = Record<"find" | "replace" | "onlyIfIncludes" | "scope", string>; interface TextReplaceProps { title: string; rulesArray: Rule[]; } const makeEmptyRule: () => Rule = () => ({ find: "", replace: "", onlyIfIncludes: "", scope: "myMessages" }); const makeEmptyRuleArray = () => [makeEmptyRule()]; const settings = definePluginSettings({ replace: { type: OptionType.COMPONENT, component: () => { const { stringRules, regexRules } = settings.use(["stringRules", "regexRules"]); return ( <> ); } }, stringRules: { type: OptionType.CUSTOM, default: makeEmptyRuleArray(), description: t("vencord.textReplace.stringRules") }, regexRules: { type: OptionType.CUSTOM, default: makeEmptyRuleArray(), description: t("vencord.textReplace.regexRules") } }); function stringToRegex(str: string) { const match = str.match(/^(\/)?(.+?)(?:\/([gimsuyv]*))?$/); // Regex to match regex return match ? new RegExp( match[2], // Pattern match[3] ?.split("") // Remove duplicate flags .filter((char, pos, flagArr) => flagArr.indexOf(char) === pos) .join("") ?? "g" ) : new RegExp(str); // Not a regex, return string } function renderFindError(find: string) { try { stringToRegex(find); return null; } catch (e) { return ( {String(e)} ); } } function Input({ initialValue, onChange, placeholder }: { placeholder: string; initialValue: string; onChange(value: string): void; }) { const [value, setValue] = useState(initialValue); return ( value !== initialValue && onChange(value)} /> ); } function TextReplace({ title, rulesArray }: TextReplaceProps) { const isRegexRules = title === t("vencord.textReplace.usingRegex"); async function onClickRemove(index: number) { if (index === rulesArray.length - 1) return; rulesArray.splice(index, 1); } async function onChange(e: string, index: number, key: string) { if (index === rulesArray.length - 1) { rulesArray.push(makeEmptyRule()); } rulesArray[index][key] = e; if (rulesArray[index].find === "" && rulesArray[index].replace === "" && rulesArray[index].onlyIfIncludes === "" && index !== rulesArray.length - 1) { rulesArray.splice(index, 1); } } const scopeOptions = [ { label: t("vencord.textReplace.scope.myMessages"), value: "myMessages" }, { label: t("vencord.textReplace.scope.othersMessages"), value: "othersMessages" }, { label: t("vencord.textReplace.scope.allMessages"), value: "allMessages" } ]; return ( <> {title} { rulesArray.map((rule, index) => onChange(e, index, "find")} /> onChange(e, index, "replace")} /> onChange(e, index, "onlyIfIncludes")} /> {(index !== rulesArray.length - 1) &&