diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/PluginSettings/index.tsx | 14 | ||||
-rw-r--r-- | src/globals.d.ts | 1 | ||||
-rw-r--r-- | src/utils/logger.ts | 20 | ||||
-rw-r--r-- | src/webpack/patchWebpack.ts | 58 |
4 files changed, 79 insertions, 14 deletions
diff --git a/src/components/PluginSettings/index.tsx b/src/components/PluginSettings/index.tsx index 6ad9750..1a2e78f 100644 --- a/src/components/PluginSettings/index.tsx +++ b/src/components/PluginSettings/index.tsx @@ -145,7 +145,19 @@ function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLe onChange={toggleEnabled} disabled={disabled} value={isEnabled()} - note={<Text variant="text-md/normal" style={{ height: 40, overflow: "hidden" }}>{plugin.description}</Text>} + note={<Text variant="text-md/normal" style={{ + height: 40, + overflow: "hidden", + // mfw css is so bad you need whatever this is to get multi line overflow ellipsis to work + textOverflow: "ellipsis", + display: "-webkit-box", // firefox users will cope (it doesn't support it) + WebkitLineClamp: 2, + lineClamp: 2, + WebkitBoxOrient: "vertical", + boxOrient: "vertical" + }}> + {plugin.description} + </Text>} hideBorder={true} > <Flex style={{ marginTop: "auto", width: "100%", height: "100%", alignItems: "center" }}> diff --git a/src/globals.d.ts b/src/globals.d.ts index 071bca2..2872f62 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -32,6 +32,7 @@ declare global { * replace: `${IS_WEB}?foo:bar` */ export var IS_WEB: boolean; + export var IS_DEV: boolean; export var IS_STANDALONE: boolean; export var VencordNative: typeof import("./VencordNative").default; diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 309f4db..24cd2c8 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -17,11 +17,23 @@ */ export default class Logger { + /** + * Returns the console format args for a title with the specified background colour and black text + * @param color Background colour + * @param title Text + * @returns Array. Destructure this into {@link Logger}.errorCustomFmt or console.log + * + * @example logger.errorCustomFmt(...Logger.makeTitleElements("white", "Hello"), "World"); + */ + static makeTitle(color: string, title: string): [string, ...string[]] { + return ["%c %c %s ", "", `background: ${color}; color: black; font-weight: bold; border-radius: 5px;`, title]; + } + constructor(public name: string, public color: string) { } - private _log(level: "log" | "error" | "warn" | "info" | "debug", levelColor: string, args: any[]) { + private _log(level: "log" | "error" | "warn" | "info" | "debug", levelColor: string, args: any[], customFmt = "") { console[level]( - `%c Vencord %c %c ${this.name} `, + `%c Vencord %c %c ${this.name} ${customFmt}`, `background: ${levelColor}; color: black; font-weight: bold; border-radius: 5px;`, "", `background: ${this.color}; color: black; font-weight: bold; border-radius: 5px;` @@ -41,6 +53,10 @@ export default class Logger { this._log("error", "#e78284", args); } + public errorCustomFmt(fmt: string, ...args: any[]) { + this._log("error", "#e78284", args, fmt); + } + public warn(...args: any[]) { this._log("warn", "#e5c890", args); } diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index f679f3a..5596730 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -41,7 +41,7 @@ Object.defineProperty(window, WEBPACK_CHUNK, { }); function patchPush() { - function handlePush(chunk) { + function handlePush(chunk: any) { try { const modules = chunk[1]; const { subscriptions, listeners } = Vencord.Webpack; @@ -56,7 +56,7 @@ function patchPush() { // Additionally, `[actual newline]` is one less char than "\n", so if Discord // ever targets newer browsers, the minifier could potentially use this trick and // cause issues. - let code = mod.toString().replaceAll("\n", ""); + let code: string = mod.toString().replaceAll("\n", ""); const originalMod = mod; const patchedBy = new Set(); @@ -90,6 +90,7 @@ function patchPush() { logger.error("Error in webpack listener", err); } } + for (const [filter, callback] of subscriptions) { try { if (filter(exports)) { @@ -113,45 +114,80 @@ function patchPush() { } } }; + modules[id].toString = () => mod.toString(); modules[id].original = originalMod; for (let i = 0; i < patches.length; i++) { const patch = patches[i]; if (patch.predicate && !patch.predicate()) continue; + if (code.includes(patch.find)) { patchedBy.add(patch.plugin); + // @ts-ignore we change all patch.replacement to array in plugins/index for (const replacement of patch.replacement) { const lastMod = mod; const lastCode = code; + try { const newCode = code.replace(replacement.match, replacement.replace); if (newCode === code) { - logger.warn(`Patch by ${patch.plugin} had no effect: ${replacement.match}`); - logger.debug("Function Source:\n", code); + logger.warn(`Patch by ${patch.plugin} had no effect (Module id is ${id}): ${replacement.match}`); + if (IS_DEV) { + logger.debug("Function Source:\n", code); + } } else { code = newCode; mod = (0, eval)(`// Webpack Module ${id} - Patched by ${[...patchedBy].join(", ")}\n${newCode}\n//# sourceURL=WebpackModule${id}`); } } catch (err) { - // TODO - More meaningful errors. This probably means moving away from string.replace - // in favour of manual matching. Then cut out the context and log some sort of - // diff - logger.error("Failed to apply patch of", patch.plugin, err); - logger.debug("Original Source\n", lastCode); - logger.debug("Patched Source\n", code); + logger.error(`Failed to apply patch ${replacement.match} of ${patch.plugin} to ${id}:\n`, err); + + if (IS_DEV) { + const changeSize = code.length - lastCode.length; + const match = lastCode.match(replacement.match)!; + + // Use 200 surrounding characters of context + const start = Math.max(0, match.index! - 200); + const end = Math.min(lastCode.length, match.index! + match[0].length + 200); + // (changeSize may be negative) + const endPatched = end + changeSize; + + const context = lastCode.slice(start, end); + const patchedContext = code.slice(start, endPatched); + + // inline require to avoid including it in !IS_DEV builds + const diff = (require("diff") as typeof import("diff")).diffWordsWithSpace(context, patchedContext); + let fmt = "%c %s "; + const elements = [] as string[]; + for (const d of diff) { + const color = d.removed + ? "red" + : d.added + ? "lime" + : "grey"; + fmt += "%c%s"; + elements.push("color:" + color, d.value); + } + + logger.errorCustomFmt(...Logger.makeTitle("white", "Before"), context); + logger.errorCustomFmt(...Logger.makeTitle("white", "After"), context); + const [titleFmt, ...titleElements] = Logger.makeTitle("white", "Diff"); + logger.errorCustomFmt(titleFmt + fmt, ...titleElements, ...elements); + } code = lastCode; mod = lastMod; patchedBy.delete(patch.plugin); } } + if (!patch.all) patches.splice(i--, 1); } } } } catch (err) { - logger.error("oopsie", err); + logger.error("Error in handlePush", err); } return handlePush.original.call(window[WEBPACK_CHUNK], chunk); |