mirror of
https://github.com/open-goal/opengoal-vscode.git
synced 2024-10-19 20:47:37 -04:00
decomp: pre-populated list of possible types (#181)
This commit is contained in:
parent
08851637e2
commit
040e941857
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,3 +5,4 @@ out/
|
||||||
*.exe
|
*.exe
|
||||||
*.bin
|
*.bin
|
||||||
lsp-metadata.json
|
lsp-metadata.json
|
||||||
|
*-types.json
|
||||||
|
|
|
@ -222,6 +222,14 @@
|
||||||
"default": null,
|
"default": null,
|
||||||
"description": "File path to the decompiler executable"
|
"description": "File path to the decompiler executable"
|
||||||
},
|
},
|
||||||
|
"opengoal.typeSearcherPath": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"default": null,
|
||||||
|
"description": "File path to the type searcher executable"
|
||||||
|
},
|
||||||
"opengoal.decompilerJak1Config": {
|
"opengoal.decompilerJak1Config": {
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
|
|
|
@ -14,6 +14,7 @@ export function getConfig() {
|
||||||
eeManPagePath: configOptions.get<string>("eeManPagePath"),
|
eeManPagePath: configOptions.get<string>("eeManPagePath"),
|
||||||
vuManPagePath: configOptions.get<string>("vuManPagePath"),
|
vuManPagePath: configOptions.get<string>("vuManPagePath"),
|
||||||
decompilerPath: configOptions.get<string>("decompilerPath"),
|
decompilerPath: configOptions.get<string>("decompilerPath"),
|
||||||
|
typeSearcherPath: configOptions.get<string>("typeSearcherPath"),
|
||||||
jak1DecompConfig: configOptions.get<string>("decompilerJak1Config"),
|
jak1DecompConfig: configOptions.get<string>("decompilerJak1Config"),
|
||||||
jak2DecompConfig: configOptions.get<string>("decompilerJak2Config"),
|
jak2DecompConfig: configOptions.get<string>("decompilerJak2Config"),
|
||||||
decompilerJak1ConfigDirectory: configOptions.get<string>(
|
decompilerJak1ConfigDirectory: configOptions.get<string>(
|
||||||
|
@ -75,6 +76,15 @@ export async function updateDecompilerPath(path: string) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function updateTypeSearcherPath(path: string) {
|
||||||
|
const userConfig = vscode.workspace.getConfiguration();
|
||||||
|
await userConfig.update(
|
||||||
|
"opengoal.typeSearcherPath",
|
||||||
|
path,
|
||||||
|
vscode.ConfigurationTarget.Global
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export async function updateJak1DecompConfig(config: string) {
|
export async function updateJak1DecompConfig(config: string) {
|
||||||
const userConfig = vscode.workspace.getConfiguration();
|
const userConfig = vscode.workspace.getConfiguration();
|
||||||
await userConfig.update(
|
await userConfig.update(
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
|
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { RecentFiles } from "./RecentFiles";
|
import { RecentFiles } from "./RecentFiles";
|
||||||
|
import { getWorkspaceFolderByName } from "./utils/workspace";
|
||||||
|
|
||||||
const channel = vscode.window.createOutputChannel("OpenGOAL");
|
const channel = vscode.window.createOutputChannel("OpenGOAL");
|
||||||
let extensionContext: vscode.ExtensionContext;
|
let extensionContext: vscode.ExtensionContext;
|
||||||
let recentFiles: RecentFiles;
|
let recentFiles: RecentFiles;
|
||||||
|
let projectRoot: vscode.Uri | undefined = undefined;
|
||||||
|
|
||||||
export function initContext(extContext: vscode.ExtensionContext) {
|
export function initContext(extContext: vscode.ExtensionContext) {
|
||||||
extensionContext = extContext;
|
extensionContext = extContext;
|
||||||
|
@ -27,3 +29,17 @@ export function getExtensionContext() {
|
||||||
export function getMainChannel() {
|
export function getMainChannel() {
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getProjectRoot(): vscode.Uri {
|
||||||
|
if (projectRoot === undefined) {
|
||||||
|
projectRoot = getWorkspaceFolderByName("jak-project");
|
||||||
|
// if it's still undefined, throw an error
|
||||||
|
if (projectRoot === undefined) {
|
||||||
|
vscode.window.showErrorMessage(
|
||||||
|
"OpenGOAL - Unable to locate 'jak-project' workspace folder"
|
||||||
|
);
|
||||||
|
throw new Error("unable to locate 'jak-project' workspace folder");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return projectRoot;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { exec, execFile } from "child_process";
|
import { exec, execFile } from "child_process";
|
||||||
import { existsSync, promises as fs } from "fs";
|
import { existsSync, promises as fs } from "fs";
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { determineGameFromPath, GameName, openFile } from "../utils/file-utils";
|
import { determineGameFromPath, GameName } from "../utils/file-utils";
|
||||||
import { open_in_pdf } from "./man-page";
|
import { open_in_pdf } from "./man-page";
|
||||||
import * as util from "util";
|
import * as util from "util";
|
||||||
import {
|
import {
|
||||||
|
@ -12,22 +12,19 @@ import {
|
||||||
} from "../config/config";
|
} from "../config/config";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import * as glob from "glob";
|
import * as glob from "glob";
|
||||||
import { getExtensionContext, getRecentFiles } from "../context";
|
import { getExtensionContext, getProjectRoot } from "../context";
|
||||||
import {
|
import {
|
||||||
getFileNamesFromUris,
|
getFileNamesFromUris,
|
||||||
getUrisFromTabs,
|
getUrisFromTabs,
|
||||||
getWorkspaceFolderByName,
|
|
||||||
truncateFileNameEndings,
|
truncateFileNameEndings,
|
||||||
} from "../utils/workspace";
|
} from "../utils/workspace";
|
||||||
import { activateDecompTypeSearcher } from "./type-searcher/type-searcher";
|
import { activateDecompTypeSearcher } from "./type-searcher/type-searcher";
|
||||||
|
import { updateTypeCastSuggestions } from "./type-caster";
|
||||||
|
|
||||||
const globAsync = util.promisify(glob);
|
const globAsync = util.promisify(glob);
|
||||||
const execFileAsync = util.promisify(execFile);
|
const execFileAsync = util.promisify(execFile);
|
||||||
const execAsync = util.promisify(exec);
|
const execAsync = util.promisify(exec);
|
||||||
|
|
||||||
// Put some of this stuff into the context
|
|
||||||
let projectRoot: vscode.Uri | undefined = undefined;
|
|
||||||
|
|
||||||
let channel: vscode.OutputChannel;
|
let channel: vscode.OutputChannel;
|
||||||
let fsWatcher: vscode.FileSystemWatcher | undefined;
|
let fsWatcher: vscode.FileSystemWatcher | undefined;
|
||||||
|
|
||||||
|
@ -102,27 +99,19 @@ async function promptUserToSelectConfig(
|
||||||
async function getDecompilerConfig(
|
async function getDecompilerConfig(
|
||||||
gameName: GameName
|
gameName: GameName
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
if (projectRoot === undefined) {
|
|
||||||
projectRoot = getWorkspaceFolderByName("jak-project");
|
|
||||||
if (projectRoot === undefined) {
|
|
||||||
vscode.window.showErrorMessage(
|
|
||||||
"OpenGOAL - Unable to locate 'jak-project' workspace folder"
|
|
||||||
);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
if (gameName == GameName.Jak1) {
|
if (gameName == GameName.Jak1) {
|
||||||
const decompConfig = config.jak1DecompConfig;
|
const decompConfig = config.jak1DecompConfig;
|
||||||
if (
|
if (
|
||||||
decompConfig === undefined ||
|
decompConfig === undefined ||
|
||||||
!existsSync(
|
!existsSync(
|
||||||
vscode.Uri.joinPath(projectRoot, `decompiler/config/${decompConfig}`)
|
vscode.Uri.joinPath(
|
||||||
.fsPath
|
getProjectRoot(),
|
||||||
|
`decompiler/config/${decompConfig}`
|
||||||
|
).fsPath
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const config = await promptUserToSelectConfig(projectRoot);
|
const config = await promptUserToSelectConfig(getProjectRoot());
|
||||||
if (config === undefined) {
|
if (config === undefined) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -137,11 +126,13 @@ async function getDecompilerConfig(
|
||||||
if (
|
if (
|
||||||
decompConfig === undefined ||
|
decompConfig === undefined ||
|
||||||
!existsSync(
|
!existsSync(
|
||||||
vscode.Uri.joinPath(projectRoot, `decompiler/config/${decompConfig}`)
|
vscode.Uri.joinPath(
|
||||||
.fsPath
|
getProjectRoot(),
|
||||||
|
`decompiler/config/${decompConfig}`
|
||||||
|
).fsPath
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const config = await promptUserToSelectConfig(projectRoot);
|
const config = await promptUserToSelectConfig(getProjectRoot());
|
||||||
if (config === undefined) {
|
if (config === undefined) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -156,16 +147,6 @@ async function getDecompilerConfig(
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkDecompilerPath(): Promise<string | undefined> {
|
async function checkDecompilerPath(): Promise<string | undefined> {
|
||||||
if (projectRoot === undefined) {
|
|
||||||
projectRoot = getWorkspaceFolderByName("jak-project");
|
|
||||||
if (projectRoot === undefined) {
|
|
||||||
vscode.window.showErrorMessage(
|
|
||||||
"OpenGOAL - Unable to locate 'jak-project' workspace folder"
|
|
||||||
);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let decompilerPath = getConfig().decompilerPath;
|
let decompilerPath = getConfig().decompilerPath;
|
||||||
|
|
||||||
// Look for the decompiler if the path isn't set or the file is now missing
|
// Look for the decompiler if the path isn't set or the file is now missing
|
||||||
|
@ -173,7 +154,10 @@ async function checkDecompilerPath(): Promise<string | undefined> {
|
||||||
return decompilerPath;
|
return decompilerPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const potentialPath = vscode.Uri.joinPath(projectRoot, defaultDecompPath());
|
const potentialPath = vscode.Uri.joinPath(
|
||||||
|
getProjectRoot(),
|
||||||
|
defaultDecompPath()
|
||||||
|
);
|
||||||
if (existsSync(potentialPath.fsPath)) {
|
if (existsSync(potentialPath.fsPath)) {
|
||||||
decompilerPath = potentialPath.fsPath;
|
decompilerPath = potentialPath.fsPath;
|
||||||
} else {
|
} else {
|
||||||
|
@ -221,7 +205,7 @@ async function decompFiles(decompConfig: string, fileNames: string[]) {
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
encoding: "utf8",
|
encoding: "utf8",
|
||||||
cwd: projectRoot?.fsPath,
|
cwd: getProjectRoot()?.fsPath,
|
||||||
timeout: 20000,
|
timeout: 20000,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -239,16 +223,9 @@ async function decompFiles(decompConfig: string, fileNames: string[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getValidObjectNames(gameName: string) {
|
async function getValidObjectNames(gameName: string) {
|
||||||
if (projectRoot === undefined) {
|
|
||||||
projectRoot = getWorkspaceFolderByName("jak-project");
|
|
||||||
if (projectRoot === undefined) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for the `all_objs.json` file
|
// Look for the `all_objs.json` file
|
||||||
const objsPath = path.join(
|
const objsPath = path.join(
|
||||||
projectRoot.fsPath,
|
getProjectRoot().fsPath,
|
||||||
"goal_src",
|
"goal_src",
|
||||||
gameName,
|
gameName,
|
||||||
"build",
|
"build",
|
||||||
|
@ -415,7 +392,14 @@ function toggleAutoDecompilation() {
|
||||||
fsWatcher = vscode.workspace.createFileSystemWatcher(
|
fsWatcher = vscode.workspace.createFileSystemWatcher(
|
||||||
"**/decompiler/config/**/*.{jsonc,json,gc}"
|
"**/decompiler/config/**/*.{jsonc,json,gc}"
|
||||||
);
|
);
|
||||||
fsWatcher.onDidChange(() => decompAllActiveFiles());
|
fsWatcher.onDidChange((uri: vscode.Uri) => {
|
||||||
|
decompAllActiveFiles();
|
||||||
|
// Also update list of types for that game
|
||||||
|
const gameName = determineGameFromPath(uri);
|
||||||
|
if (gameName !== undefined) {
|
||||||
|
updateTypeCastSuggestions(gameName);
|
||||||
|
}
|
||||||
|
});
|
||||||
fsWatcher.onDidCreate(() => decompAllActiveFiles());
|
fsWatcher.onDidCreate(() => decompAllActiveFiles());
|
||||||
fsWatcher.onDidDelete(() => decompAllActiveFiles());
|
fsWatcher.onDidDelete(() => decompAllActiveFiles());
|
||||||
} else {
|
} else {
|
||||||
|
@ -434,16 +418,6 @@ async function updateSourceFile() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectRoot === undefined) {
|
|
||||||
projectRoot = getWorkspaceFolderByName("jak-project");
|
|
||||||
if (projectRoot === undefined) {
|
|
||||||
vscode.window.showErrorMessage(
|
|
||||||
"OpenGOAL - Unable to locate 'jak-project' workspace folder"
|
|
||||||
);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let fileName = path.basename(editor.document.fileName);
|
let fileName = path.basename(editor.document.fileName);
|
||||||
let disasmFilePath = "";
|
let disasmFilePath = "";
|
||||||
if (fileName.match(/.*_ir2\.asm/)) {
|
if (fileName.match(/.*_ir2\.asm/)) {
|
||||||
|
@ -468,7 +442,7 @@ async function updateSourceFile() {
|
||||||
`python ./scripts/gsrc/update-from-decomp.py --game ${gameName} --file ${fileName}`,
|
`python ./scripts/gsrc/update-from-decomp.py --game ${gameName} --file ${fileName}`,
|
||||||
{
|
{
|
||||||
encoding: "utf8",
|
encoding: "utf8",
|
||||||
cwd: projectRoot?.fsPath,
|
cwd: getProjectRoot()?.fsPath,
|
||||||
timeout: 20000,
|
timeout: 20000,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -486,16 +460,6 @@ async function updateReferenceTest() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectRoot === undefined) {
|
|
||||||
projectRoot = getWorkspaceFolderByName("jak-project");
|
|
||||||
if (projectRoot === undefined) {
|
|
||||||
vscode.window.showErrorMessage(
|
|
||||||
"OpenGOAL - Unable to locate 'jak-project' workspace folder"
|
|
||||||
);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO - duplication with above
|
// TODO - duplication with above
|
||||||
|
|
||||||
let fileName = path.basename(editor.document.fileName);
|
let fileName = path.basename(editor.document.fileName);
|
||||||
|
@ -518,7 +482,7 @@ async function updateReferenceTest() {
|
||||||
gameName = "jak2";
|
gameName = "jak2";
|
||||||
}
|
}
|
||||||
const folderToSearch = vscode.Uri.joinPath(
|
const folderToSearch = vscode.Uri.joinPath(
|
||||||
projectRoot,
|
getProjectRoot(),
|
||||||
`goal_src/${gameName}`
|
`goal_src/${gameName}`
|
||||||
);
|
);
|
||||||
const files = await globAsync(`**/${fileName}.gc`, {
|
const files = await globAsync(`**/${fileName}.gc`, {
|
||||||
|
@ -530,7 +494,7 @@ async function updateReferenceTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const refTestPath = vscode.Uri.joinPath(
|
const refTestPath = vscode.Uri.joinPath(
|
||||||
projectRoot,
|
getProjectRoot(),
|
||||||
`test/decompiler/reference/${gameName}/${files[0].replace(
|
`test/decompiler/reference/${gameName}/${files[0].replace(
|
||||||
".gc",
|
".gc",
|
||||||
"_REF.gc"
|
"_REF.gc"
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
import { getExtensionContext } from "../context";
|
import { getExtensionContext, getProjectRoot } from "../context";
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { basename, join } from "path";
|
import { basename, join } from "path";
|
||||||
import { readFileSync, writeFileSync } from "fs";
|
import { fstat, readFileSync, writeFileSync } from "fs";
|
||||||
import { parse, stringify } from "comment-json";
|
import { parse, stringify } from "comment-json";
|
||||||
import { getFuncNameFromSelection } from "../languages/ir2/ir2-utils";
|
import { getFuncNameFromSelection } from "../languages/ir2/ir2-utils";
|
||||||
import { getDecompilerConfigDirectory } from "./utils";
|
import { getDecompilerConfigDirectory } from "./utils";
|
||||||
|
import { determineGameFromPath, GameName } from "../utils/file-utils";
|
||||||
|
import { getConfig, updateTypeSearcherPath } from "../config/config";
|
||||||
|
import { existsSync } from "fs";
|
||||||
|
import * as util from "util";
|
||||||
|
import { execFile } from "child_process";
|
||||||
|
const execFileAsync = util.promisify(execFile);
|
||||||
|
|
||||||
enum CastKind {
|
enum CastKind {
|
||||||
Label,
|
Label,
|
||||||
|
@ -33,6 +39,81 @@ class CastContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const typeCastSuggestions = new Map<GameName, string[]>();
|
||||||
|
const recentLabelCasts = new Map<GameName, string[]>();
|
||||||
|
const recentTypeCasts = new Map<GameName, string[]>();
|
||||||
|
const recentStackCasts = new Map<GameName, string[]>();
|
||||||
|
|
||||||
|
function defaultTypeSearcherPath() {
|
||||||
|
const platform = process.platform;
|
||||||
|
if (platform == "win32") {
|
||||||
|
return "out/build/Release/bin/type_searcher.exe";
|
||||||
|
} else {
|
||||||
|
return "build/tools/type_searcher";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkTypeSearcherPath(): Promise<string | undefined> {
|
||||||
|
let typeSearcherPath = getConfig().typeSearcherPath;
|
||||||
|
|
||||||
|
// Look for the decompiler if the path isn't set or the file is now missing
|
||||||
|
if (typeSearcherPath !== undefined && existsSync(typeSearcherPath)) {
|
||||||
|
return typeSearcherPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const potentialPath = vscode.Uri.joinPath(
|
||||||
|
getProjectRoot(),
|
||||||
|
defaultTypeSearcherPath()
|
||||||
|
);
|
||||||
|
if (existsSync(potentialPath.fsPath)) {
|
||||||
|
typeSearcherPath = potentialPath.fsPath;
|
||||||
|
} else {
|
||||||
|
// Ask the user to find it cause we have no idea
|
||||||
|
const path = await vscode.window.showOpenDialog({
|
||||||
|
canSelectMany: false,
|
||||||
|
openLabel: "Select Type Searcher",
|
||||||
|
title: "Provide the type searcher executable's path",
|
||||||
|
});
|
||||||
|
if (path === undefined || path.length == 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
typeSearcherPath = path[0].fsPath;
|
||||||
|
}
|
||||||
|
updateTypeSearcherPath(typeSearcherPath);
|
||||||
|
return typeSearcherPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateTypeCastSuggestions(gameName: GameName) {
|
||||||
|
const typeSearcherPath = await checkTypeSearcherPath();
|
||||||
|
if (!typeSearcherPath) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const jsonPath = vscode.Uri.joinPath(
|
||||||
|
getExtensionContext().extensionUri,
|
||||||
|
`${gameName.toString()}-types.json`
|
||||||
|
).fsPath;
|
||||||
|
await execFileAsync(
|
||||||
|
typeSearcherPath,
|
||||||
|
[`--game`, gameName.toString(), `--output-path`, jsonPath, `--all`],
|
||||||
|
{
|
||||||
|
encoding: "utf8",
|
||||||
|
cwd: getProjectRoot().fsPath,
|
||||||
|
timeout: 20000,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (existsSync(jsonPath)) {
|
||||||
|
const result = readFileSync(jsonPath, { encoding: "utf-8" });
|
||||||
|
typeCastSuggestions.set(gameName, JSON.parse(result));
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
vscode.window.showErrorMessage(
|
||||||
|
"Couldn't get a list of all types to use for casting suggestions"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function getOpNumber(line: string): Promise<number | undefined> {
|
async function getOpNumber(line: string): Promise<number | undefined> {
|
||||||
const matches = [...line.matchAll(opNumRegex)];
|
const matches = [...line.matchAll(opNumRegex)];
|
||||||
if (matches.length == 1) {
|
if (matches.length == 1) {
|
||||||
|
@ -109,6 +190,51 @@ async function validActiveFile(editor: vscode.TextEditor): Promise<boolean> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateCastSelectionItems(
|
||||||
|
fullList: string[] | undefined,
|
||||||
|
recentList: string[] | undefined
|
||||||
|
): vscode.QuickPickItem[] {
|
||||||
|
const items: vscode.QuickPickItem[] = [];
|
||||||
|
if (recentList !== undefined && recentList.length > 0) {
|
||||||
|
items.push({
|
||||||
|
label: "Recent Casts",
|
||||||
|
kind: vscode.QuickPickItemKind.Separator,
|
||||||
|
});
|
||||||
|
for (const name of recentList) {
|
||||||
|
items.push({
|
||||||
|
label: name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fullList !== undefined && fullList.length > 0) {
|
||||||
|
items.push({
|
||||||
|
label: "All Types",
|
||||||
|
kind: vscode.QuickPickItemKind.Separator,
|
||||||
|
});
|
||||||
|
for (const name of fullList) {
|
||||||
|
items.push({
|
||||||
|
label: name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initTypeCastSuggestions(gameName: GameName | undefined) {
|
||||||
|
if (gameName !== undefined && typeCastSuggestions.size === 0) {
|
||||||
|
await updateTypeCastSuggestions(gameName);
|
||||||
|
if (recentLabelCasts.get(gameName) === undefined) {
|
||||||
|
recentLabelCasts.set(gameName, []);
|
||||||
|
}
|
||||||
|
if (recentTypeCasts.get(gameName) === undefined) {
|
||||||
|
recentTypeCasts.set(gameName, []);
|
||||||
|
}
|
||||||
|
if (recentStackCasts.get(gameName) === undefined) {
|
||||||
|
recentStackCasts.set(gameName, []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function labelCastSelection() {
|
async function labelCastSelection() {
|
||||||
const editor = vscode.window.activeTextEditor;
|
const editor = vscode.window.activeTextEditor;
|
||||||
if (editor === undefined || !validActiveFile(editor)) {
|
if (editor === undefined || !validActiveFile(editor)) {
|
||||||
|
@ -126,14 +252,34 @@ async function labelCastSelection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get what we should cast to
|
// Get what we should cast to
|
||||||
const castToType = await vscode.window.showInputBox({
|
const gameName = determineGameFromPath(editor.document.uri);
|
||||||
|
await initTypeCastSuggestions(gameName);
|
||||||
|
if (gameName === undefined) {
|
||||||
|
await vscode.window.showErrorMessage("Couldn't determine game version");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = generateCastSelectionItems(
|
||||||
|
typeCastSuggestions.get(gameName),
|
||||||
|
recentLabelCasts.get(gameName)
|
||||||
|
);
|
||||||
|
let castToType;
|
||||||
|
if (items.length > 0) {
|
||||||
|
castToType = (
|
||||||
|
await vscode.window.showQuickPick(items, {
|
||||||
|
title: "Cast to Type?",
|
||||||
|
})
|
||||||
|
)?.label;
|
||||||
|
} else {
|
||||||
|
castToType = await vscode.window.showInputBox({
|
||||||
title: "Cast to Type?",
|
title: "Cast to Type?",
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (castToType === undefined || castToType.trim() === "") {
|
if (castToType === undefined || castToType.trim() === "") {
|
||||||
await vscode.window.showErrorMessage("Can't cast if no type is provided");
|
await vscode.window.showErrorMessage("Can't cast if no type is provided");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the label is a pointer, ask for a size
|
// If the label is a pointer, ask for a size
|
||||||
let pointerSize = undefined;
|
let pointerSize = undefined;
|
||||||
if (castToType.includes("pointer")) {
|
if (castToType.includes("pointer")) {
|
||||||
|
@ -159,6 +305,7 @@ async function labelCastSelection() {
|
||||||
lastCastKind = CastKind.Label;
|
lastCastKind = CastKind.Label;
|
||||||
lastLabelCastType = castToType;
|
lastLabelCastType = castToType;
|
||||||
lastLabelCastSize = pointerSize;
|
lastLabelCastSize = pointerSize;
|
||||||
|
recentLabelCasts.get(gameName)?.unshift(castToType);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getStackOffset(line: string): Promise<number | undefined> {
|
async function getStackOffset(line: string): Promise<number | undefined> {
|
||||||
|
@ -217,9 +364,30 @@ async function stackCastSelection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get what we should cast to
|
// Get what we should cast to
|
||||||
const castToType = await vscode.window.showInputBox({
|
const gameName = determineGameFromPath(editor.document.uri);
|
||||||
|
await initTypeCastSuggestions(gameName);
|
||||||
|
if (gameName === undefined) {
|
||||||
|
await vscode.window.showErrorMessage("Couldn't determine game version");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = generateCastSelectionItems(
|
||||||
|
typeCastSuggestions.get(gameName),
|
||||||
|
recentStackCasts.get(gameName)
|
||||||
|
);
|
||||||
|
let castToType;
|
||||||
|
if (items.length > 0) {
|
||||||
|
castToType = (
|
||||||
|
await vscode.window.showQuickPick(items, {
|
||||||
|
title: "Cast to Type?",
|
||||||
|
})
|
||||||
|
)?.label;
|
||||||
|
} else {
|
||||||
|
castToType = await vscode.window.showInputBox({
|
||||||
title: "Cast to Type?",
|
title: "Cast to Type?",
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (castToType === undefined || castToType.trim() === "") {
|
if (castToType === undefined || castToType.trim() === "") {
|
||||||
await vscode.window.showErrorMessage("Can't cast if no type is provided");
|
await vscode.window.showErrorMessage("Can't cast if no type is provided");
|
||||||
return;
|
return;
|
||||||
|
@ -230,6 +398,7 @@ async function stackCastSelection() {
|
||||||
|
|
||||||
lastCastKind = CastKind.Stack;
|
lastCastKind = CastKind.Stack;
|
||||||
lastStackCastType = castToType;
|
lastStackCastType = castToType;
|
||||||
|
recentStackCasts.get(gameName)?.unshift(castToType);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRegisters(
|
function getRegisters(
|
||||||
|
@ -341,9 +510,29 @@ async function typeCastSelection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get what we should cast to
|
// Get what we should cast to
|
||||||
const castToType = await vscode.window.showInputBox({
|
const gameName = determineGameFromPath(editor.document.uri);
|
||||||
|
await initTypeCastSuggestions(gameName);
|
||||||
|
if (gameName === undefined) {
|
||||||
|
await vscode.window.showErrorMessage("Couldn't determine game version");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = generateCastSelectionItems(
|
||||||
|
typeCastSuggestions.get(gameName),
|
||||||
|
recentTypeCasts.get(gameName)
|
||||||
|
);
|
||||||
|
let castToType;
|
||||||
|
if (items.length > 0) {
|
||||||
|
castToType = (
|
||||||
|
await vscode.window.showQuickPick(items, {
|
||||||
|
title: "Cast to Type?",
|
||||||
|
})
|
||||||
|
)?.label;
|
||||||
|
} else {
|
||||||
|
castToType = await vscode.window.showInputBox({
|
||||||
title: "Cast to Type?",
|
title: "Cast to Type?",
|
||||||
});
|
});
|
||||||
|
}
|
||||||
if (castToType === undefined || castToType.trim() === "") {
|
if (castToType === undefined || castToType.trim() === "") {
|
||||||
await vscode.window.showErrorMessage("Can't cast if no type is provided");
|
await vscode.window.showErrorMessage("Can't cast if no type is provided");
|
||||||
return;
|
return;
|
||||||
|
@ -361,6 +550,7 @@ async function typeCastSelection() {
|
||||||
lastCastKind = CastKind.TypeCast;
|
lastCastKind = CastKind.TypeCast;
|
||||||
lastTypeCastRegister = registerSelection;
|
lastTypeCastRegister = registerSelection;
|
||||||
lastTypeCastType = castToType;
|
lastTypeCastType = castToType;
|
||||||
|
recentTypeCasts.get(gameName)?.unshift(castToType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the same cast as last time (same type, same register) just on a different selection
|
// Execute the same cast as last time (same type, same register) just on a different selection
|
||||||
|
|
|
@ -4,8 +4,8 @@ import { promises as fs } from "fs";
|
||||||
import { getRecentFiles } from "../context";
|
import { getRecentFiles } from "../context";
|
||||||
|
|
||||||
export enum GameName {
|
export enum GameName {
|
||||||
Jak1,
|
Jak1 = "jak1",
|
||||||
Jak2,
|
Jak2 = "jak2",
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileSwitchingAssoc = {
|
const fileSwitchingAssoc = {
|
||||||
|
|
Loading…
Reference in a new issue