mirror of
https://github.com/open-goal/opengoal-vscode.git
synced 2024-10-19 20:47:37 -04:00
decomp: add tooling to semi-automatically add casts (#40)
This commit is contained in:
parent
aa6cdb2739
commit
8d01d8b7bd
91
package-lock.json
generated
91
package-lock.json
generated
|
@ -9,6 +9,7 @@
|
||||||
"version": "0.0.2",
|
"version": "0.0.2",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"comment-json": "^4.2.2",
|
||||||
"follow-redirects": "^1.15.1",
|
"follow-redirects": "^1.15.1",
|
||||||
"glob": "^8.0.3",
|
"glob": "^8.0.3",
|
||||||
"open": "^8.4.0",
|
"open": "^8.4.0",
|
||||||
|
@ -397,6 +398,11 @@
|
||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/array-timsort": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ=="
|
||||||
|
},
|
||||||
"node_modules/array-union": {
|
"node_modules/array-union": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||||
|
@ -475,11 +481,31 @@
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/comment-json": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-H8T+kl3nZesZu41zO2oNXIJWojNeK3mHxCLrsBNu6feksBXsgb+PtYz5daP5P86A0F3sz3840KVYehr04enISQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"array-timsort": "^1.0.3",
|
||||||
|
"core-util-is": "^1.0.3",
|
||||||
|
"esprima": "^4.0.1",
|
||||||
|
"has-own-prop": "^2.0.0",
|
||||||
|
"repeat-string": "^1.6.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/concat-map": {
|
"node_modules/concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
},
|
},
|
||||||
|
"node_modules/core-util-is": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
@ -698,6 +724,18 @@
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/esprima": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||||
|
"bin": {
|
||||||
|
"esparse": "bin/esparse.js",
|
||||||
|
"esvalidate": "bin/esvalidate.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/esquery": {
|
"node_modules/esquery": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
|
||||||
|
@ -979,6 +1017,14 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/has-own-prop": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
|
||||||
|
@ -1329,6 +1375,14 @@
|
||||||
"url": "https://github.com/sponsors/mysticatea"
|
"url": "https://github.com/sponsors/mysticatea"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/repeat-string": {
|
||||||
|
"version": "1.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
|
||||||
|
"integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/resolve-from": {
|
"node_modules/resolve-from": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||||
|
@ -1892,6 +1946,11 @@
|
||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"array-timsort": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ=="
|
||||||
|
},
|
||||||
"array-union": {
|
"array-union": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||||
|
@ -1952,11 +2011,28 @@
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"comment-json": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-H8T+kl3nZesZu41zO2oNXIJWojNeK3mHxCLrsBNu6feksBXsgb+PtYz5daP5P86A0F3sz3840KVYehr04enISQ==",
|
||||||
|
"requires": {
|
||||||
|
"array-timsort": "^1.0.3",
|
||||||
|
"core-util-is": "^1.0.3",
|
||||||
|
"esprima": "^4.0.1",
|
||||||
|
"has-own-prop": "^2.0.0",
|
||||||
|
"repeat-string": "^1.6.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
},
|
},
|
||||||
|
"core-util-is": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||||
|
},
|
||||||
"cross-spawn": {
|
"cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
@ -2117,6 +2193,11 @@
|
||||||
"eslint-visitor-keys": "^3.3.0"
|
"eslint-visitor-keys": "^3.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"esprima": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||||
|
},
|
||||||
"esquery": {
|
"esquery": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
|
||||||
|
@ -2332,6 +2413,11 @@
|
||||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"has-own-prop": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ=="
|
||||||
|
},
|
||||||
"ignore": {
|
"ignore": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
|
||||||
|
@ -2578,6 +2664,11 @@
|
||||||
"integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
|
"integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"repeat-string": {
|
||||||
|
"version": "1.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
|
||||||
|
"integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w=="
|
||||||
|
},
|
||||||
"resolve-from": {
|
"resolve-from": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||||
|
|
44
package.json
44
package.json
|
@ -36,9 +36,9 @@
|
||||||
"typescript": "^4.6.3"
|
"typescript": "^4.6.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"comment-json": "^4.2.2",
|
||||||
"follow-redirects": "^1.15.1",
|
"follow-redirects": "^1.15.1",
|
||||||
"glob": "^8.0.3",
|
"glob": "^8.0.3",
|
||||||
"open": "^8.4.0",
|
|
||||||
"vscode-languageclient": "^8.0.1"
|
"vscode-languageclient": "^8.0.1"
|
||||||
},
|
},
|
||||||
"activationEvents": [
|
"activationEvents": [
|
||||||
|
@ -52,7 +52,11 @@
|
||||||
"onCommand:opengoal.decomp.decompileCurrentFile",
|
"onCommand:opengoal.decomp.decompileCurrentFile",
|
||||||
"onCommand:opengoal.decomp.toggleAutoDecompilation",
|
"onCommand:opengoal.decomp.toggleAutoDecompilation",
|
||||||
"onCommand:opengoal.decomp.updateSourceFile",
|
"onCommand:opengoal.decomp.updateSourceFile",
|
||||||
"onCommand:opengoal.decomp.updateReferenceTest"
|
"onCommand:opengoal.decomp.updateReferenceTest",
|
||||||
|
"opengoal.decomp.casts.repeatLast",
|
||||||
|
"opengoal.decomp.casts.labelCastSelection",
|
||||||
|
"opengoal.decomp.casts.stackCastSelection",
|
||||||
|
"opengoal.decomp.casts.typeCastSelection"
|
||||||
],
|
],
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"commands": [
|
"commands": [
|
||||||
|
@ -88,6 +92,26 @@
|
||||||
"command": "opengoal.decomp.updateReferenceTest",
|
"command": "opengoal.decomp.updateReferenceTest",
|
||||||
"title": "OpenGOAL - Copy Decompilation to Reference Tests"
|
"title": "OpenGOAL - Copy Decompilation to Reference Tests"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "opengoal.decomp.casts.repeatLast",
|
||||||
|
"title": "OpenGOAL - Casts - Repeat Last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "opengoal.decomp.casts.castSelection",
|
||||||
|
"title": "OpenGOAL - Casts - Add Cast to Selection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "opengoal.decomp.casts.labelCastSelection",
|
||||||
|
"title": "OpenGOAL - Casts - Add Label Cast to Selection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "opengoal.decomp.casts.stackCastSelection",
|
||||||
|
"title": "OpenGOAL - Casts - Add Stack Cast to Selection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "opengoal.decomp.casts.typeCastSelection",
|
||||||
|
"title": "OpenGOAL - Casts - Add Type Cast to Selection"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "opengoal.lsp.start",
|
"command": "opengoal.lsp.start",
|
||||||
"title": "OpenGOAL - LSP - Start"
|
"title": "OpenGOAL - LSP - Start"
|
||||||
|
@ -150,6 +174,22 @@
|
||||||
],
|
],
|
||||||
"default": null,
|
"default": null,
|
||||||
"description": "Config to use for decompiling jak 2 related files"
|
"description": "Config to use for decompiling jak 2 related files"
|
||||||
|
},
|
||||||
|
"opengoal.decompilerJak1ConfigDirectory": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"default": null,
|
||||||
|
"description": "Directory containing cast files to use for decompiling jak 1 related files"
|
||||||
|
},
|
||||||
|
"opengoal.decompilerJak2ConfigDirectory": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"default": null,
|
||||||
|
"description": "Directory containing cast files to use for decompiling jak 2 related files"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,6 +12,12 @@ export function getConfig() {
|
||||||
decompilerPath: configOptions.get<string>("decompilerPath"),
|
decompilerPath: configOptions.get<string>("decompilerPath"),
|
||||||
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"
|
||||||
|
),
|
||||||
|
decompilerJak2ConfigDirectory: configOptions.get<string>(
|
||||||
|
"decompilerJak2ConfigDirectory"
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,3 +65,21 @@ export async function updateJak2DecompConfig(config: string) {
|
||||||
vscode.ConfigurationTarget.Global
|
vscode.ConfigurationTarget.Global
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function updateJak1DecompConfigDirectory(dir: string) {
|
||||||
|
const userConfig = vscode.workspace.getConfiguration();
|
||||||
|
await userConfig.update(
|
||||||
|
"opengoal.decompilerJak1ConfigDirectory",
|
||||||
|
dir,
|
||||||
|
vscode.ConfigurationTarget.Global
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateJak2DecompConfigDirectory(dir: string) {
|
||||||
|
const userConfig = vscode.workspace.getConfiguration();
|
||||||
|
await userConfig.update(
|
||||||
|
"opengoal.decompilerJak2ConfigDirectory",
|
||||||
|
dir,
|
||||||
|
vscode.ConfigurationTarget.Global
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { execFile } from "child_process";
|
import { 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 { openFile } from "../utils/FileUtils";
|
import { determineGameFromPath, GameName, openFile } 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 {
|
||||||
|
@ -81,22 +81,6 @@ function defaultDecompPath() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum GameName {
|
|
||||||
Jak1,
|
|
||||||
Jak2,
|
|
||||||
}
|
|
||||||
|
|
||||||
async function determineGameFromPath(
|
|
||||||
path: vscode.Uri
|
|
||||||
): Promise<GameName | undefined> {
|
|
||||||
if (path.fsPath.includes("jak1")) {
|
|
||||||
return GameName.Jak1;
|
|
||||||
} else if (path.fsPath.includes("jak2")) {
|
|
||||||
return GameName.Jak2;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function promptUserToSelectConfig(
|
async function promptUserToSelectConfig(
|
||||||
projectRoot: vscode.Uri
|
projectRoot: vscode.Uri
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
|
|
584
src/decomp/type-caster.ts
Normal file
584
src/decomp/type-caster.ts
Normal file
|
@ -0,0 +1,584 @@
|
||||||
|
// [inclusive, exclusive]
|
||||||
|
|
||||||
|
import { getExtensionContext } from "../context";
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
import { basename, join } from "path";
|
||||||
|
import { getWorkspaceFolderByName } from "../utils/workspace";
|
||||||
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
||||||
|
import { parse, stringify } from "comment-json";
|
||||||
|
import {
|
||||||
|
getConfig,
|
||||||
|
updateJak1DecompConfigDirectory,
|
||||||
|
updateJak2DecompConfigDirectory,
|
||||||
|
} from "../config/config";
|
||||||
|
import {
|
||||||
|
determineGameFromPath,
|
||||||
|
GameName,
|
||||||
|
getDirectoriesInDir,
|
||||||
|
} from "../utils/file-utils";
|
||||||
|
|
||||||
|
enum CastKind {
|
||||||
|
Label,
|
||||||
|
Stack,
|
||||||
|
TypeCast,
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastCastKind: CastKind | undefined;
|
||||||
|
let lastLabelCastType: string | undefined;
|
||||||
|
let lastLabelCastSize: number | undefined;
|
||||||
|
let lastStackCastType: string | undefined;
|
||||||
|
let lastTypeCastRegister: string | undefined;
|
||||||
|
let lastTypeCastType: string | undefined;
|
||||||
|
|
||||||
|
const opNumRegex = /.*;; \[\s*(\d+)\]/g;
|
||||||
|
const registerRegex = /[a|s|t|v]\d|gp|fp|r0|ra/g;
|
||||||
|
const funcNameRegex = /; \.function (.*).*/g;
|
||||||
|
const stackOffsetRegex = /sp, (\d+)/g;
|
||||||
|
const labelRefRegex = /(L\d+).*;;/g;
|
||||||
|
|
||||||
|
class CastContext {
|
||||||
|
startOp: number;
|
||||||
|
endOp: number | undefined;
|
||||||
|
constructor(start: number, end?: number) {
|
||||||
|
this.startOp = start;
|
||||||
|
this.endOp = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function promptUserToSelectConfigDirectory(
|
||||||
|
projectRoot: vscode.Uri
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
// Get all `.jsonc` files in ./decompiler/config
|
||||||
|
const dirs = await getDirectoriesInDir(
|
||||||
|
vscode.Uri.joinPath(projectRoot, "decompiler/config").fsPath
|
||||||
|
);
|
||||||
|
return await vscode.window.showQuickPick(dirs, {
|
||||||
|
title: "Config?",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getDecompilerConfigDirectory(
|
||||||
|
activeFile: vscode.Uri
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
const projectRoot = getWorkspaceFolderByName("jak-project");
|
||||||
|
if (projectRoot === undefined) {
|
||||||
|
vscode.window.showErrorMessage(
|
||||||
|
"OpenGOAL - Unable to locate 'jak-project' workspace folder"
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = getConfig();
|
||||||
|
const gameName = await determineGameFromPath(activeFile);
|
||||||
|
if (gameName == GameName.Jak1) {
|
||||||
|
if (
|
||||||
|
config.decompilerJak1ConfigDirectory === undefined ||
|
||||||
|
!existsSync(config.decompilerJak1ConfigDirectory)
|
||||||
|
) {
|
||||||
|
const selection = await promptUserToSelectConfigDirectory(projectRoot);
|
||||||
|
if (selection === undefined) {
|
||||||
|
vscode.window.showErrorMessage(
|
||||||
|
"OpenGOAL - Can't cast without knowing where to store them!"
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
await updateJak1DecompConfigDirectory(selection);
|
||||||
|
return vscode.Uri.joinPath(projectRoot, "decompiler/config/", selection)
|
||||||
|
.fsPath;
|
||||||
|
} else {
|
||||||
|
return vscode.Uri.joinPath(
|
||||||
|
projectRoot,
|
||||||
|
"decompiler/config/",
|
||||||
|
config.decompilerJak1ConfigDirectory
|
||||||
|
).fsPath;
|
||||||
|
}
|
||||||
|
} else if (gameName == GameName.Jak2) {
|
||||||
|
if (
|
||||||
|
config.decompilerJak2ConfigDirectory === undefined ||
|
||||||
|
!existsSync(config.decompilerJak2ConfigDirectory)
|
||||||
|
) {
|
||||||
|
const selection = await promptUserToSelectConfigDirectory(projectRoot);
|
||||||
|
if (selection === undefined) {
|
||||||
|
vscode.window.showErrorMessage(
|
||||||
|
"OpenGOAL - Can't cast without knowing where to store them!"
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
await updateJak2DecompConfigDirectory(selection);
|
||||||
|
return vscode.Uri.joinPath(projectRoot, "decompiler/config/", selection)
|
||||||
|
.fsPath;
|
||||||
|
} else {
|
||||||
|
return vscode.Uri.joinPath(
|
||||||
|
projectRoot,
|
||||||
|
"decompiler/config/",
|
||||||
|
config.decompilerJak2ConfigDirectory
|
||||||
|
).fsPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getOpNumber(line: string): Promise<number | undefined> {
|
||||||
|
const matches = [...line.matchAll(opNumRegex)];
|
||||||
|
if (matches.length == 1) {
|
||||||
|
return parseInt(matches[0][1].toString());
|
||||||
|
}
|
||||||
|
await vscode.window.showErrorMessage("Couldn't determine operation number");
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFuncName(
|
||||||
|
document: vscode.TextDocument,
|
||||||
|
selection: vscode.Selection
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
for (let i = selection.start.line; i >= 0; i--) {
|
||||||
|
const line = document.lineAt(i).text;
|
||||||
|
const matches = [...line.matchAll(funcNameRegex)];
|
||||||
|
if (matches.length == 1) {
|
||||||
|
return matches[0][1].toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await vscode.window.showErrorMessage(
|
||||||
|
"Couldn't determine function or method name"
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getLabelReference(line: string): Promise<string | undefined> {
|
||||||
|
const matches = [...line.matchAll(labelRefRegex)];
|
||||||
|
if (matches.length == 1) {
|
||||||
|
return matches[0][1].toString();
|
||||||
|
}
|
||||||
|
await vscode.window.showErrorMessage("Couldn't determine label reference");
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function applyLabelCast(
|
||||||
|
editor: vscode.TextEditor,
|
||||||
|
objectName: string,
|
||||||
|
labelRef: string,
|
||||||
|
castToType: string,
|
||||||
|
pointerSize?: number
|
||||||
|
) {
|
||||||
|
const configDir = await getDecompilerConfigDirectory(editor.document.uri);
|
||||||
|
if (configDir === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const filePath = join(configDir, "label_types.jsonc");
|
||||||
|
|
||||||
|
const json: any = parse(readFileSync(filePath).toString());
|
||||||
|
// Add our new entry
|
||||||
|
if (objectName in json) {
|
||||||
|
if (pointerSize === undefined) {
|
||||||
|
json[objectName].push([labelRef, castToType]);
|
||||||
|
} else {
|
||||||
|
json[objectName].push([labelRef, castToType, pointerSize]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pointerSize === undefined) {
|
||||||
|
json[objectName] = [[labelRef, castToType]];
|
||||||
|
} else {
|
||||||
|
json[objectName] = [[labelRef, castToType, pointerSize]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileSync(filePath, stringify(json, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function validActiveFile(editor: vscode.TextEditor): Promise<boolean> {
|
||||||
|
if (!editor.document === undefined) {
|
||||||
|
await vscode.window.showErrorMessage(
|
||||||
|
"No active file open, can't decompile!"
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileName = basename(editor.document.fileName);
|
||||||
|
if (!fileName.match(/.*_ir2\.asm/)) {
|
||||||
|
await vscode.window.showErrorMessage(
|
||||||
|
"Current file is not a valid IR2 file."
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function labelCastSelection() {
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (editor === undefined || !validActiveFile(editor)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectName = basename(editor.document.fileName).split("_ir2.asm")[0];
|
||||||
|
|
||||||
|
// Get the stack index
|
||||||
|
const labelRef = await getLabelReference(
|
||||||
|
editor.document.lineAt(editor.selection.start.line).text
|
||||||
|
);
|
||||||
|
if (labelRef === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get what we should cast to
|
||||||
|
const castToType = await vscode.window.showInputBox({
|
||||||
|
title: "Cast to Type?",
|
||||||
|
});
|
||||||
|
if (castToType === undefined) {
|
||||||
|
await vscode.window.showErrorMessage("Can't cast if no type is provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the label is a pointer, ask for a size
|
||||||
|
let pointerSize = undefined;
|
||||||
|
if (castToType.includes("pointer")) {
|
||||||
|
pointerSize = await vscode.window.showInputBox({
|
||||||
|
title: "Pointer Size?",
|
||||||
|
});
|
||||||
|
if (pointerSize === undefined) {
|
||||||
|
await vscode.window.showErrorMessage("Provide a pointer size!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pointerSize = parseInt(pointerSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, do the cast!
|
||||||
|
await applyLabelCast(editor, objectName, labelRef, castToType, pointerSize);
|
||||||
|
|
||||||
|
lastCastKind = CastKind.Label;
|
||||||
|
lastLabelCastType = castToType;
|
||||||
|
lastLabelCastSize = pointerSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getStackOffset(line: string): Promise<number | undefined> {
|
||||||
|
const matches = [...line.matchAll(stackOffsetRegex)];
|
||||||
|
if (matches.length == 1) {
|
||||||
|
return parseInt(matches[0][1].toString());
|
||||||
|
}
|
||||||
|
await vscode.window.showErrorMessage("Couldn't determine stack offset");
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function applyStackCast(
|
||||||
|
editor: vscode.TextEditor,
|
||||||
|
funcName: string,
|
||||||
|
stackOffset: number,
|
||||||
|
castToType: string
|
||||||
|
) {
|
||||||
|
const configDir = await getDecompilerConfigDirectory(editor.document.uri);
|
||||||
|
if (configDir === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const filePath = join(configDir, "stack_structures.jsonc");
|
||||||
|
|
||||||
|
const json: any = parse(readFileSync(filePath).toString());
|
||||||
|
// Add our new entry
|
||||||
|
if (funcName in json) {
|
||||||
|
json[funcName].push([stackOffset, castToType]);
|
||||||
|
} else {
|
||||||
|
json[funcName] = [[stackOffset, castToType]];
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileSync(filePath, stringify(json, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function stackCastSelection() {
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (editor === undefined || !validActiveFile(editor)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the relevant function/method name
|
||||||
|
const funcName = await getFuncName(editor.document, editor.selection);
|
||||||
|
if (funcName === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the stack index
|
||||||
|
const stackOffset = await getStackOffset(
|
||||||
|
editor.document.lineAt(editor.selection.start.line).text
|
||||||
|
);
|
||||||
|
if (stackOffset === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get what we should cast to
|
||||||
|
const castToType = await vscode.window.showInputBox({
|
||||||
|
title: "Cast to Type?",
|
||||||
|
});
|
||||||
|
if (castToType === undefined) {
|
||||||
|
await vscode.window.showErrorMessage("Can't cast if no type is provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, do the cast!
|
||||||
|
await applyStackCast(editor, funcName, stackOffset, castToType);
|
||||||
|
|
||||||
|
lastCastKind = CastKind.Stack;
|
||||||
|
lastStackCastType = castToType;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRegisters(
|
||||||
|
document: vscode.TextDocument,
|
||||||
|
selection: vscode.Selection
|
||||||
|
): string[] {
|
||||||
|
const regSet = new Set<string>();
|
||||||
|
for (let i = selection.start.line; i <= selection.end.line; i++) {
|
||||||
|
const line = document.lineAt(i).text;
|
||||||
|
const regs = [...line.matchAll(registerRegex)];
|
||||||
|
regs.forEach((regMatch) => regSet.add(regMatch.toString()));
|
||||||
|
}
|
||||||
|
return Array.from(regSet).sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function applyTypeCast(
|
||||||
|
editor: vscode.TextEditor,
|
||||||
|
funcName: string,
|
||||||
|
castContext: CastContext,
|
||||||
|
registerSelection: string,
|
||||||
|
castToType: string
|
||||||
|
) {
|
||||||
|
const configDir = await getDecompilerConfigDirectory(editor.document.uri);
|
||||||
|
if (configDir === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const filePath = join(configDir, "type_casts.jsonc");
|
||||||
|
|
||||||
|
const json: any = parse(readFileSync(filePath).toString());
|
||||||
|
// Add our new entry
|
||||||
|
if (funcName in json) {
|
||||||
|
if (castContext.endOp === undefined) {
|
||||||
|
json[funcName].push([castContext.startOp, registerSelection, castToType]);
|
||||||
|
} else {
|
||||||
|
json[funcName].push([
|
||||||
|
[castContext.startOp, castContext.endOp],
|
||||||
|
registerSelection,
|
||||||
|
castToType,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (castContext.endOp === undefined) {
|
||||||
|
json[funcName] = [[castContext.startOp, registerSelection, castToType]];
|
||||||
|
} else {
|
||||||
|
json[funcName] = [
|
||||||
|
[
|
||||||
|
[castContext.startOp, castContext.endOp],
|
||||||
|
registerSelection,
|
||||||
|
castToType,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileSync(filePath, stringify(json, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function typeCastSelection() {
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (editor === undefined || !validActiveFile(editor)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the range of the selection
|
||||||
|
const startOpNum = await getOpNumber(
|
||||||
|
editor.document.lineAt(editor.selection.start.line).text
|
||||||
|
);
|
||||||
|
if (startOpNum === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const castContext = new CastContext(startOpNum);
|
||||||
|
if (!editor.selection.isSingleLine) {
|
||||||
|
const endOpNum = await getOpNumber(
|
||||||
|
editor.document.lineAt(editor.selection.end.line).text
|
||||||
|
);
|
||||||
|
if (endOpNum === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
castContext.endOp = endOpNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the relevant function/method name
|
||||||
|
const funcName = await getFuncName(editor.document, editor.selection);
|
||||||
|
if (funcName === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all possible registers in the given range (in this case, just the line)
|
||||||
|
const registers = getRegisters(editor.document, editor.selection);
|
||||||
|
if (registers.length == 0) {
|
||||||
|
await vscode.window.showErrorMessage(
|
||||||
|
"Found no registers to cast in that selection"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get what register should be casted
|
||||||
|
const registerSelection = await vscode.window.showQuickPick(registers, {
|
||||||
|
title: "Register to Cast?",
|
||||||
|
});
|
||||||
|
if (registerSelection === undefined) {
|
||||||
|
await vscode.window.showErrorMessage(
|
||||||
|
"Can't cast if no register is provided"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get what we should cast to
|
||||||
|
const castToType = await vscode.window.showInputBox({
|
||||||
|
title: "Cast to Type?",
|
||||||
|
});
|
||||||
|
if (castToType === undefined) {
|
||||||
|
await vscode.window.showErrorMessage("Can't cast if no type is provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, do the cast!
|
||||||
|
await applyTypeCast(
|
||||||
|
editor,
|
||||||
|
funcName,
|
||||||
|
castContext,
|
||||||
|
registerSelection,
|
||||||
|
castToType
|
||||||
|
);
|
||||||
|
|
||||||
|
lastCastKind = CastKind.TypeCast;
|
||||||
|
lastTypeCastRegister = registerSelection;
|
||||||
|
lastTypeCastType = castToType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the same cast as last time (same type, same register) just on a different selection
|
||||||
|
async function repeatLastCast() {
|
||||||
|
if (lastCastKind === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (editor === undefined || !validActiveFile(editor)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastCastKind === CastKind.Label) {
|
||||||
|
const objectName = basename(editor.document.fileName).split("_ir2.asm")[0];
|
||||||
|
const labelRef = await getLabelReference(
|
||||||
|
editor.document.lineAt(editor.selection.start.line).text
|
||||||
|
);
|
||||||
|
if (labelRef === undefined || lastLabelCastType === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await applyLabelCast(
|
||||||
|
editor,
|
||||||
|
objectName,
|
||||||
|
labelRef,
|
||||||
|
lastLabelCastType,
|
||||||
|
lastLabelCastSize
|
||||||
|
);
|
||||||
|
} else if (lastCastKind === CastKind.Stack) {
|
||||||
|
const funcName = await getFuncName(editor.document, editor.selection);
|
||||||
|
if (funcName === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the stack index
|
||||||
|
const stackOffset = await getStackOffset(
|
||||||
|
editor.document.lineAt(editor.selection.start.line).text
|
||||||
|
);
|
||||||
|
if (stackOffset === undefined || lastStackCastType === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await applyStackCast(editor, funcName, stackOffset, lastStackCastType);
|
||||||
|
} else if (lastCastKind === CastKind.TypeCast) {
|
||||||
|
const funcName = await getFuncName(editor.document, editor.selection);
|
||||||
|
if (funcName === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const startOpNum = await getOpNumber(
|
||||||
|
editor.document.lineAt(editor.selection.start.line).text
|
||||||
|
);
|
||||||
|
if (startOpNum === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const castContext = new CastContext(startOpNum);
|
||||||
|
if (!editor.selection.isSingleLine) {
|
||||||
|
const endOpNum = await getOpNumber(
|
||||||
|
editor.document.lineAt(editor.selection.end.line).text
|
||||||
|
);
|
||||||
|
if (endOpNum === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
castContext.endOp = endOpNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastTypeCastRegister === undefined || lastTypeCastType === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await applyTypeCast(
|
||||||
|
editor,
|
||||||
|
funcName,
|
||||||
|
castContext,
|
||||||
|
lastTypeCastRegister,
|
||||||
|
lastTypeCastType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function activateTypeCastTools() {
|
||||||
|
getExtensionContext().subscriptions.push(
|
||||||
|
vscode.commands.registerCommand(
|
||||||
|
"opengoal.decomp.casts.labelCastSelection",
|
||||||
|
labelCastSelection
|
||||||
|
)
|
||||||
|
);
|
||||||
|
getExtensionContext().subscriptions.push(
|
||||||
|
vscode.commands.registerCommand(
|
||||||
|
"opengoal.decomp.casts.stackCastSelection",
|
||||||
|
stackCastSelection
|
||||||
|
)
|
||||||
|
);
|
||||||
|
getExtensionContext().subscriptions.push(
|
||||||
|
vscode.commands.registerCommand(
|
||||||
|
"opengoal.decomp.casts.typeCastSelection",
|
||||||
|
typeCastSelection
|
||||||
|
)
|
||||||
|
);
|
||||||
|
getExtensionContext().subscriptions.push(
|
||||||
|
vscode.commands.registerCommand(
|
||||||
|
"opengoal.decomp.casts.repeatLast",
|
||||||
|
repeatLastCast
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - better handling around upserting casts
|
||||||
|
// this requires properly handling the CommentArray type instead of building raw arrays so comments are preserved
|
||||||
|
// const finalEntries = [];
|
||||||
|
// if (relevantJson !== undefined) {
|
||||||
|
// // prepare the entry for the upcoming update
|
||||||
|
// // remove any identical casts / range casts that effect it
|
||||||
|
// for (const entry of relevantJson) {
|
||||||
|
// if (entry[1] === registerSelection) {
|
||||||
|
// if (entry[0] instanceof Array) {
|
||||||
|
// const [start, end] = entry[0];
|
||||||
|
// if (castContext.endOp === undefined) {
|
||||||
|
// if (castContext.startOp >= start && castContext.startOp < end) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// } else if (
|
||||||
|
// (castContext.startOp >= start && castContext.startOp < end) ||
|
||||||
|
// (castContext.endOp > start && castContext.endOp < end) ||
|
||||||
|
// (castContext.startOp >= start && castContext.endOp < end)
|
||||||
|
// ) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// } else if (castContext.startOp == entry[0]) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// finalEntries.push(entry);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // Add our new entry
|
||||||
|
// // TODO - sort by op number (annoying because of the ranges...)
|
||||||
|
// if (castContext.endOp === undefined) {
|
||||||
|
// finalEntries.push([castContext.startOp, registerSelection, castToType]);
|
||||||
|
// } else {
|
||||||
|
// finalEntries.push([[castContext.startOp, castContext.endOp], registerSelection, castToType]);
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -5,10 +5,11 @@ import {
|
||||||
setVSIconAssociations,
|
setVSIconAssociations,
|
||||||
} from "./config/user-settings";
|
} from "./config/user-settings";
|
||||||
import { PdfCustomProvider } from "./vendor/vscode-pdfviewer/pdfProvider";
|
import { PdfCustomProvider } from "./vendor/vscode-pdfviewer/pdfProvider";
|
||||||
import { switchFile } from "./utils/FileUtils";
|
import { switchFile } from "./utils/file-utils";
|
||||||
import { activateDecompTools } from "./decomp/decomp-tools";
|
import { activateDecompTools } from "./decomp/decomp-tools";
|
||||||
import { initContext } from "./context";
|
import { initContext } from "./context";
|
||||||
import { IRFoldingRangeProvider } from "./languages/ir2-folder";
|
import { IRFoldingRangeProvider } from "./languages/ir2-folder";
|
||||||
|
import { activateTypeCastTools } from "./decomp/type-caster";
|
||||||
|
|
||||||
export async function activate(context: vscode.ExtensionContext) {
|
export async function activate(context: vscode.ExtensionContext) {
|
||||||
// Init Context
|
// Init Context
|
||||||
|
@ -23,6 +24,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||||
);
|
);
|
||||||
|
|
||||||
activateDecompTools();
|
activateDecompTools();
|
||||||
|
activateTypeCastTools();
|
||||||
|
|
||||||
// Customized PDF Viewer
|
// Customized PDF Viewer
|
||||||
const provider = new PdfCustomProvider(
|
const provider = new PdfCustomProvider(
|
||||||
|
@ -41,6 +43,8 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO - disposable stuff?
|
||||||
|
|
||||||
// Language Customizations
|
// Language Customizations
|
||||||
vscode.languages.registerFoldingRangeProvider(
|
vscode.languages.registerFoldingRangeProvider(
|
||||||
{ scheme: "file", language: "opengoal-ir" },
|
{ scheme: "file", language: "opengoal-ir" },
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
import { promises as fs } from "fs";
|
||||||
|
|
||||||
// TODO - remove "most recent ir2 file, and wire it up here when in an `all-types.gc` file"
|
// TODO - remove "most recent ir2 file, and wire it up here when in an `all-types.gc` file"
|
||||||
|
|
||||||
|
export enum GameName {
|
||||||
|
Jak1,
|
||||||
|
Jak2,
|
||||||
|
}
|
||||||
|
|
||||||
const fileSwitchingAssoc = {
|
const fileSwitchingAssoc = {
|
||||||
"_ir2.asm": "_disasm.gc",
|
"_ir2.asm": "_disasm.gc",
|
||||||
"_disasm.gc": "_ir2.asm",
|
"_disasm.gc": "_ir2.asm",
|
||||||
|
@ -32,3 +38,21 @@ export function openFile(filePath: string | undefined) {
|
||||||
}
|
}
|
||||||
vscode.window.showTextDocument(vscode.Uri.file(filePath));
|
vscode.window.showTextDocument(vscode.Uri.file(filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function determineGameFromPath(
|
||||||
|
path: vscode.Uri
|
||||||
|
): Promise<GameName | undefined> {
|
||||||
|
if (path.fsPath.includes("jak1")) {
|
||||||
|
return GameName.Jak1;
|
||||||
|
} else if (path.fsPath.includes("jak2")) {
|
||||||
|
return GameName.Jak2;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getDirectoriesInDir(dir: string) {
|
||||||
|
const dirs = await fs.readdir(dir, { withFileTypes: true });
|
||||||
|
return dirs
|
||||||
|
.filter((dirent) => dirent.isDirectory())
|
||||||
|
.map((dirent) => dirent.name);
|
||||||
|
}
|
Loading…
Reference in a new issue