equicord-companion
Version:
Equicord Companion is a vscode extension to test Equicord patches & webpack finds right from the comfort of your IDE
363 lines (328 loc) • 14 kB
text/typescript
import { onEditCallback, onOpenCallback } from "@ast/vencord/diagnostics";
import { I18nHover } from "@ast/vencord/hover";
import { PatchCodeLensProvider, PluginDefCodeLensProvider, WebpackCodeLensProvider } from "@ast/vencord/lenses";
import { PartialModuleJumpCodeLensProvider } from "@ast/webpack/lenses";
import { DefinitionProvider, ReferenceProvider } from "@ast/webpack/lsp";
import { outputChannel } from "@modules/logging";
import { PatchHelper } from "@modules/PatchHelper";
import { handleDiffPayload, handleExtractPayload, moduleCache, sendAndGetData, startWebSocketServer, stopWebSocketServer } from "@server";
import { treeDataProvider } from "@sidebar";
import { SourcePatch } from "@type/ast";
import { Discriminate } from "@type/server";
import { DisablePluginData, FindData, OutgoingMessage, PatchData } from "@type/server/send";
import { startReporter } from "./reporter";
import { commands, ExtensionContext, languages, QuickPickItem, TextDocument, Uri, window as vscWindow, window, workspace } from "vscode";
export let extensionUri: Uri;
export let extensionPath: string;
export function activate(context: ExtensionContext) {
extensionUri = context.extensionUri;
extensionPath = context.extensionPath;
startWebSocketServer();
context.subscriptions.push(
window.registerTreeDataProvider("equicordSettings", new treeDataProvider()),
workspace.onDidChangeTextDocument(onEditCallback),
workspace.onDidOpenTextDocument(onOpenCallback),
workspace.onDidCloseTextDocument(PatchHelper.onCloseDocument),
workspace.onDidChangeTextDocument(PatchHelper.changeDocument),
window.onDidChangeActiveTextEditor(PatchHelper.changeActiveEditor),
window.tabGroups.onDidChangeTabs(PatchHelper.onTabClose),
languages.registerCodeLensProvider(
{ pattern: "**/{plugins,userplugins,equicordplugins,plugins/_*,equicordplugins/_*}/{*.ts,*.tsx,**/index.ts,**/index.tsx}" },
new PluginDefCodeLensProvider(),
),
languages.registerCodeLensProvider(
{ pattern: "**/{plugins,userplugins,equicordplugins,plugins/_*,equicordplugins/_*}/{*.ts,*.tsx,**/index.ts,**/index.tsx}" },
new PatchCodeLensProvider(),
),
languages.registerDefinitionProvider({ language: "javascript" }, new DefinitionProvider()),
languages.registerReferenceProvider({ language: "javascript" }, new ReferenceProvider()),
languages.registerCodeLensProvider({ language: "typescript" }, WebpackCodeLensProvider),
languages.registerCodeLensProvider({ language: "typescriptreact" }, WebpackCodeLensProvider),
languages.registerCodeLensProvider({ language: "javascript" }, new PartialModuleJumpCodeLensProvider()),
languages.registerHoverProvider({ language: "typescript" }, new I18nHover()),
languages.registerHoverProvider({ language: "typescriptreact" }, new I18nHover()),
workspace.registerTextDocumentContentProvider("equicord-patchhelper", PatchHelper),
workspace.registerTextDocumentContentProvider("equicord-companion", {
provideTextDocumentContent(uri) {
// FIXME: full uri shows up in title bar
const newLocal = Buffer.from(uri.path.substring(1, uri.path.lastIndexOf("/")), "base64url");
return newLocal.toString();
},
}),
commands.registerCommand("equicord-companion.openPatchHelper", async (doc: TextDocument, patch: SourcePatch) => {
if (!doc) {
outputChannel.warn("Could not find source document");
window.showErrorMessage("Could not find source document");
return;
}
const helper = await PatchHelper.create(doc, patch);
helper.openModuleWindow();
}),
commands.registerCommand("equicord-companion.runReporter", startReporter),
commands.registerCommand("equicord-companion.diffModule", async (args) => {
if (args) {
try {
const r = await sendAndGetData<"diff">({
type: "diff",
data: {
extractType: "id",
idOrSearch: args,
},
});
handleDiffPayload(r);
} catch (e) {
outputChannel.error(String(e));
window.showErrorMessage(String(e));
}
return;
}
// FIXME: refactor to generic quicpick class with these features
const quickPick = window.createQuickPick();
quickPick.placeholder = "module ID";
quickPick.canSelectMany = false;
const items: QuickPickItem[] = [
{
label: "",
alwaysShow: false,
},
{
label: "",
kind: -1,
},
...moduleCache.map((m) => ({ label: m })),
];
quickPick.items = items;
quickPick.onDidChangeValue(() => {
if (!moduleCache.includes(quickPick.value)) {
items[0].label = quickPick.value;
items[0].alwaysShow = true;
} else {
items[0].alwaysShow = false;
}
quickPick.items = items;
});
quickPick.show();
quickPick.onDidAccept(async () => {
const modId = quickPick.value;
quickPick.dispose();
if (!modId || isNaN(+modId))
return vscWindow.showErrorMessage("No Module ID provided");
try {
const r = await sendAndGetData<"diff">({
type: "diff",
data: {
extractType: "id",
idOrSearch: +modId,
},
});
handleDiffPayload(r);
} catch (error) {
outputChannel.error(String(error));
vscWindow.showErrorMessage(String(error));
}
});
}),
commands.registerCommand("equicord-companion.diffModuleSearch", async (args: string, findType: "string" | "regex") => {
if (args) {
try {
const r = await sendAndGetData<"diff">({
type: "diff",
data: {
extractType: "search",
findType,
idOrSearch: args,
},
});
handleDiffPayload(r);
} catch (e) {
outputChannel.error(String(e));
window.showErrorMessage(String(e));
}
return;
}
const input = await window.showInputBox();
if (!input) {
outputChannel.warn("No Input Provided");
return window.showErrorMessage("No Input Provided");
}
try {
const r = await sendAndGetData<"diff">({
type: "diff",
data: {
extractType: "search",
findType: "string",
idOrSearch: input,
},
});
handleDiffPayload(r);
} catch (e) {
outputChannel.error(String(e));
vscWindow.showErrorMessage(String(e));
}
}),
commands.registerCommand("equicord-companion.extractFind", async (args: Discriminate<OutgoingMessage, "extract">) => {
if (!args) {
outputChannel.warn("No Data Provided");
vscWindow.showErrorMessage("No Data Provided");
return;
}
try {
const r = await sendAndGetData<"extract">(args);
handleExtractPayload(r);
} catch (e) {
outputChannel.error(String(e));
vscWindow.showErrorMessage(String(e));
}
}),
commands.registerCommand("equicord-companion.extract", async (args: number) => {
if (args) {
try {
const r = await sendAndGetData<"extract">({
type: "extract",
data: {
extractType: "id",
idOrSearch: args,
usePatched: null,
},
});
handleExtractPayload(r);
} catch (e) {
outputChannel.error(String(e));
window.showErrorMessage(String(e));
}
return;
}
const quickPick = window.createQuickPick();
quickPick.placeholder = "module ID";
quickPick.canSelectMany = false;
const items: QuickPickItem[] = [
{
label: "",
alwaysShow: false,
},
{
label: "",
kind: -1,
},
...moduleCache.map((m) => {
return { label: m };
}),
];
quickPick.items = items;
quickPick.onDidChangeValue(() => {
if (!moduleCache.includes(quickPick.value)) {
items[0].label = quickPick.value;
items[0].alwaysShow = true;
} else {
items[0].alwaysShow = false;
}
quickPick.items = items;
});
quickPick.show();
quickPick.onDidAccept(async () => {
const modId = quickPick.value;
quickPick.dispose();
if (!modId || isNaN(+modId))
return vscWindow.showErrorMessage("No Module ID provided");
try {
const r = await sendAndGetData<"extract">({
type: "extract",
data: {
extractType: "id",
idOrSearch: +modId,
usePatched: null,
},
});
handleExtractPayload(r);
} catch (e) {
outputChannel.error(String(e));
vscWindow.showErrorMessage(String(e));
}
});
}),
commands.registerCommand("equicord-companion.extractSearch", async (args: string, findType: "string" | "regex") => {
if (args) {
try {
const r = await sendAndGetData<"extract">({
type: "extract",
data: {
extractType: "search",
findType,
idOrSearch: args,
usePatched: null,
},
});
handleExtractPayload(r);
} catch (e) {
outputChannel.error(String(e));
window.showErrorMessage(String(e));
}
return;
}
const input = await window.showInputBox();
if (!input)
return window.showErrorMessage("No Input Provided");
try {
const r = await sendAndGetData<"extract">({
type: "extract",
data: {
extractType: "search",
findType: "string",
idOrSearch: input,
usePatched: null,
},
});
handleExtractPayload(r);
} catch (e) {
outputChannel.error(String(e));
vscWindow.showErrorMessage(String(e));
}
}),
commands.registerCommand("equicord-companion.disablePlugin", async (data: DisablePluginData) => {
try {
if (!data)
throw new Error("No args passed.");
await sendAndGetData({
type: "disable",
data,
});
} catch (e) {
outputChannel.error(String(e));
vscWindow.showErrorMessage(String(e));
}
}),
commands.registerCommand("equicord-companion.testPatch", async (patch: PatchData) => {
try {
await sendAndGetData({
type: "testPatch",
data: patch,
});
vscWindow.showInformationMessage("Patch OK!");
} catch (e) {
outputChannel.info(`Patch failed: ${e}`);
vscWindow.showErrorMessage(`Patch failed: ${e}`);
}
}),
commands.registerCommand("equicord-companion.testFind", async (find: FindData) => {
try {
await sendAndGetData({
type: "testFind",
data: find,
});
vscWindow.showInformationMessage("Find OK!");
} catch (e) {
outputChannel.info(`Find bad: ${e}`);
vscWindow.showErrorMessage(`Find bad: ${e}`);
}
}),
);
if (window.activeTextEditor) {
onOpenCallback(window.activeTextEditor.document);
}
}
export function deactivate() {
stopWebSocketServer();
}
export {
outputChannel,
};