mirror of
https://github.com/godotengine/godot-vscode-plugin.git
synced 2025-12-31 13:48:24 +03:00
Implement Godot-in-the-loop test suite and fix debugger errors (#788)
Fixes for get variables issues
1. Same reference but different variable override fix, which resulted in variables being lost
** Now different GodotVariable instances are used for different variables with same reference
** const replacement = {value: rawObject, sub_values: sub_values } as GodotVariable;
2. 'Signal' type handling crash and string representation fix
** value.sub_values()?.map
3. Empty scopes return fix
** if (this.ongoing_inspections.length === 0 && stackVars.remaining == 0)
4. Various splice from findIndex fixes (where findIndex can return -1)
5. Added variables tests
** updated vscode types to version 1.96 to use `onDidChangeActiveStackItem` for breakpoint hit detection in tests
1 & 3 should fix https://github.com/godotengine/godot-vscode-plugin/issues/779
This commit is contained in:
27
.github/workflows/ci.yml
vendored
27
.github/workflows/ci.yml
vendored
@@ -5,6 +5,7 @@ jobs:
|
||||
test:
|
||||
name: Test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -17,9 +18,35 @@ jobs:
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- name: Install Godot (Ubuntu)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
wget https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_linux.x86_64.zip
|
||||
unzip Godot_v4.3-stable_linux.x86_64.zip
|
||||
sudo mv Godot_v4.3-stable_linux.x86_64 /usr/local/bin/godot
|
||||
chmod +x /usr/local/bin/godot
|
||||
|
||||
- name: Install Godot (macOS)
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: |
|
||||
curl -L -o Godot.zip https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_macos.universal.zip
|
||||
unzip Godot.zip
|
||||
sudo mv Godot.app /Applications/Godot.app
|
||||
sudo ln -s /Applications/Godot.app/Contents/MacOS/Godot /usr/local/bin/godot
|
||||
|
||||
- name: Install Godot (Windows)
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
Invoke-WebRequest -Uri "https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_win64.exe.zip" -OutFile "Godot.zip"
|
||||
Expand-Archive -Path "Godot.zip" -DestinationPath "C:\Godot43"
|
||||
"C:\Godot43\Godot_v4.3-stable_win64.exe %*" | Out-File -Encoding ascii -FilePath ([Environment]::SystemDirectory+"\godot.cmd")
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Godot init project
|
||||
run: godot --import test_projects/test-dap-project-godot4/project.godot --headless
|
||||
|
||||
- name: Run headless test
|
||||
uses: coactions/setup-xvfb@v1
|
||||
with:
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,3 +4,5 @@ node_modules
|
||||
.vscode-test
|
||||
workspace.code-workspace
|
||||
.history
|
||||
.godot
|
||||
*.tmp
|
||||
@@ -5,5 +5,7 @@ module.exports = defineConfig(
|
||||
// version: '1.84.0',
|
||||
label: 'unitTests',
|
||||
files: 'out/**/*.test.js',
|
||||
launchArgs: ['--disable-extensions'],
|
||||
workspaceFolder: './test_projects/test-dap-project-godot4',
|
||||
}
|
||||
);
|
||||
|
||||
5
.vscode/extensions.json
vendored
Normal file
5
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"ms-vscode.extension-test-runner"
|
||||
]
|
||||
}
|
||||
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -5,6 +5,7 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "Run Extension",
|
||||
"type": "extensionHost",
|
||||
@@ -22,7 +23,7 @@
|
||||
],
|
||||
"preLaunchTask": "npm: watch",
|
||||
"env": {
|
||||
"VSCODE_DEBUG_MODE": true
|
||||
"VSCODE_DEBUG_MODE": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -33,7 +34,7 @@
|
||||
"args": [
|
||||
"--profile=temp",
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"${workspaceFolder}/workspace.code-workspace"
|
||||
"${workspaceFolder}/test_projects/test-dap-project-godot4"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js"
|
||||
@@ -44,7 +45,7 @@
|
||||
],
|
||||
"preLaunchTask": "npm: watch",
|
||||
"env": {
|
||||
"VSCODE_DEBUG_MODE": true
|
||||
"VSCODE_DEBUG_MODE": "true"
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
207
package-lock.json
generated
207
package-lock.json
generated
@@ -9,8 +9,8 @@
|
||||
"version": "2.3.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vscode/debugadapter": "^1.64.0",
|
||||
"@vscode/debugprotocol": "^1.64.0",
|
||||
"@vscode/debugadapter": "^1.68.0",
|
||||
"@vscode/debugprotocol": "^1.68.0",
|
||||
"await-notify": "^1.0.1",
|
||||
"global": "^4.4.0",
|
||||
"marked": "^4.0.11",
|
||||
@@ -25,11 +25,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.11",
|
||||
"@types/chai-subset": "^1.3.5",
|
||||
"@types/marked": "^4.0.8",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/node": "^18.15.0",
|
||||
"@types/prismjs": "^1.16.8",
|
||||
"@types/vscode": "^1.80.0",
|
||||
"@types/vscode": "^1.96.0",
|
||||
"@types/ws": "^8.5.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
||||
"@typescript-eslint/eslint-plugin-tslint": "^5.57.1",
|
||||
@@ -38,6 +39,7 @@
|
||||
"@vscode/test-electron": "^2.3.8",
|
||||
"@vscode/vsce": "^2.29.0",
|
||||
"chai": "^4.3.10",
|
||||
"chai-subset": "^1.6.0",
|
||||
"esbuild": "^0.17.15",
|
||||
"eslint": "^8.37.0",
|
||||
"mocha": "^10.2.0",
|
||||
@@ -47,7 +49,7 @@
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.80.0"
|
||||
"vscode": "^1.96.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@aashutoshrathi/word-wrap": {
|
||||
@@ -1067,6 +1069,15 @@
|
||||
"integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/chai-subset": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.5.tgz",
|
||||
"integrity": "sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/chai": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz",
|
||||
@@ -1104,9 +1115,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/vscode": {
|
||||
"version": "1.82.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.82.0.tgz",
|
||||
"integrity": "sha512-VSHV+VnpF8DEm8LNrn8OJ8VuUNcBzN3tMvKrNpbhhfuVjFm82+6v44AbDhLvVFgCzn6vs94EJNTp7w8S6+Q1Rw==",
|
||||
"version": "1.96.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.96.0.tgz",
|
||||
"integrity": "sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
@@ -1414,20 +1425,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vscode/debugadapter": {
|
||||
"version": "1.64.0",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/debugadapter/-/debugadapter-1.64.0.tgz",
|
||||
"integrity": "sha512-XygE985qmNCzJExDnam4bErK6FG9Ck8S5TRPDNESwkt7i3OXqw5a3vYb7Dteyhz9YMEf7hwhFoT46Mjc45nJUg==",
|
||||
"version": "1.68.0",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/debugadapter/-/debugadapter-1.68.0.tgz",
|
||||
"integrity": "sha512-D6gk5Fw2y4FV8oYmltoXpj+VAZexxJFopN/mcZ6YcgzQE9dgq2L45Aj3GLxScJOD6GeLILcxJIaA8l3v11esGg==",
|
||||
"dependencies": {
|
||||
"@vscode/debugprotocol": "1.64.0"
|
||||
"@vscode/debugprotocol": "1.68.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@vscode/debugprotocol": {
|
||||
"version": "1.64.0",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.64.0.tgz",
|
||||
"integrity": "sha512-Zhf3KvB+J04M4HPE2yCvEILGVtPixXUQMLBvx4QcAtjhc5lnwlZbbt80LCsZO2B+2BH8RMgVXk3QQ5DEzEne2Q=="
|
||||
"version": "1.68.0",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.68.0.tgz",
|
||||
"integrity": "sha512-2J27dysaXmvnfuhFGhfeuxfHRXunqNPxtBoR3koiTOA9rdxWNDTa1zIFLCFMSHJ9MPTPKFcBeblsyaCJCIlQxg=="
|
||||
},
|
||||
"node_modules/@vscode/test-cli": {
|
||||
"version": "0.0.4",
|
||||
@@ -1892,9 +1903,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-colors": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
|
||||
"integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
|
||||
"integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@@ -2192,9 +2203,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chai": {
|
||||
"version": "4.3.10",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz",
|
||||
"integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==",
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz",
|
||||
"integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"assertion-error": "^1.1.0",
|
||||
@@ -2203,12 +2214,21 @@
|
||||
"get-func-name": "^2.0.2",
|
||||
"loupe": "^2.3.6",
|
||||
"pathval": "^1.1.1",
|
||||
"type-detect": "^4.0.8"
|
||||
"type-detect": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/chai-subset": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chai-subset/-/chai-subset-1.6.0.tgz",
|
||||
"integrity": "sha512-K3d+KmqdS5XKW5DWPd5sgNffL3uxdDe+6GdnJh3AYPhwnBGRY5urfvfcbRtWIvvpz+KxkL9FeBB6MZewLUNwug==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
@@ -2498,12 +2518,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
@@ -4466,32 +4486,31 @@
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/mocha": {
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
|
||||
"integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
|
||||
"version": "10.8.2",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz",
|
||||
"integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-colors": "4.1.1",
|
||||
"browser-stdout": "1.3.1",
|
||||
"chokidar": "3.5.3",
|
||||
"debug": "4.3.4",
|
||||
"diff": "5.0.0",
|
||||
"escape-string-regexp": "4.0.0",
|
||||
"find-up": "5.0.0",
|
||||
"glob": "7.2.0",
|
||||
"he": "1.2.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"log-symbols": "4.1.0",
|
||||
"minimatch": "5.0.1",
|
||||
"ms": "2.1.3",
|
||||
"nanoid": "3.3.3",
|
||||
"serialize-javascript": "6.0.0",
|
||||
"strip-json-comments": "3.1.1",
|
||||
"supports-color": "8.1.1",
|
||||
"workerpool": "6.2.1",
|
||||
"yargs": "16.2.0",
|
||||
"yargs-parser": "20.2.4",
|
||||
"yargs-unparser": "2.0.0"
|
||||
"ansi-colors": "^4.1.3",
|
||||
"browser-stdout": "^1.3.1",
|
||||
"chokidar": "^3.5.3",
|
||||
"debug": "^4.3.5",
|
||||
"diff": "^5.2.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"find-up": "^5.0.0",
|
||||
"glob": "^8.1.0",
|
||||
"he": "^1.2.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"log-symbols": "^4.1.0",
|
||||
"minimatch": "^5.1.6",
|
||||
"ms": "^2.1.3",
|
||||
"serialize-javascript": "^6.0.2",
|
||||
"strip-json-comments": "^3.1.1",
|
||||
"supports-color": "^8.1.1",
|
||||
"workerpool": "^6.5.1",
|
||||
"yargs": "^16.2.0",
|
||||
"yargs-parser": "^20.2.9",
|
||||
"yargs-unparser": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"_mocha": "bin/_mocha",
|
||||
@@ -4499,10 +4518,6 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mochajs"
|
||||
}
|
||||
},
|
||||
"node_modules/mocha/node_modules/argparse": {
|
||||
@@ -4521,9 +4536,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mocha/node_modules/diff": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
|
||||
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
|
||||
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
@@ -4541,6 +4556,26 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/mocha/node_modules/glob": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
|
||||
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
|
||||
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^5.0.1",
|
||||
"once": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/mocha/node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
@@ -4563,9 +4598,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mocha/node_modules/minimatch": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
|
||||
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
@@ -4574,12 +4609,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/mocha/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/mocha/node_modules/strip-json-comments": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||
@@ -4608,9 +4637,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/mute-stream": {
|
||||
@@ -4619,18 +4648,6 @@
|
||||
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
|
||||
"integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/napi-build-utils": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
|
||||
@@ -5247,9 +5264,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/serialize-javascript": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
|
||||
"integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
||||
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"randombytes": "^2.1.0"
|
||||
@@ -5635,9 +5652,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node": {
|
||||
"version": "10.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
|
||||
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
|
||||
"version": "10.9.2",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
|
||||
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@cspotcode/source-map-support": "^0.8.0",
|
||||
@@ -5774,9 +5791,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/type-detect": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
||||
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz",
|
||||
"integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
@@ -5951,9 +5968,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/workerpool": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
|
||||
"integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz",
|
||||
"integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
@@ -6222,9 +6239,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "20.2.4",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
|
||||
"integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
|
||||
"version": "20.2.9",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
|
||||
10
package.json
10
package.json
@@ -15,7 +15,7 @@
|
||||
"author": "The Godot Engine community",
|
||||
"publisher": "geequlim",
|
||||
"engines": {
|
||||
"vscode": "^1.80.0"
|
||||
"vscode": "^1.96.0"
|
||||
},
|
||||
"categories": [
|
||||
"Programming Languages",
|
||||
@@ -866,11 +866,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.11",
|
||||
"@types/chai-subset": "^1.3.5",
|
||||
"@types/marked": "^4.0.8",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/node": "^18.15.0",
|
||||
"@types/prismjs": "^1.16.8",
|
||||
"@types/vscode": "^1.80.0",
|
||||
"@types/vscode": "^1.96.0",
|
||||
"@types/ws": "^8.5.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
||||
"@typescript-eslint/eslint-plugin-tslint": "^5.57.1",
|
||||
@@ -879,6 +880,7 @@
|
||||
"@vscode/test-electron": "^2.3.8",
|
||||
"@vscode/vsce": "^2.29.0",
|
||||
"chai": "^4.3.10",
|
||||
"chai-subset": "^1.6.0",
|
||||
"esbuild": "^0.17.15",
|
||||
"eslint": "^8.37.0",
|
||||
"mocha": "^10.2.0",
|
||||
@@ -888,8 +890,8 @@
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vscode/debugadapter": "^1.64.0",
|
||||
"@vscode/debugprotocol": "^1.64.0",
|
||||
"@vscode/debugadapter": "^1.68.0",
|
||||
"@vscode/debugprotocol": "^1.68.0",
|
||||
"await-notify": "^1.0.1",
|
||||
"global": "^4.4.0",
|
||||
"marked": "^4.0.11",
|
||||
|
||||
@@ -17,7 +17,7 @@ import { AttachRequestArguments, LaunchRequestArguments } from "../debugger";
|
||||
import { SceneTreeProvider } from "../scene_tree_provider";
|
||||
import { is_variable_built_in_type, parse_variable } from "./helpers";
|
||||
import { ServerController } from "./server_controller";
|
||||
import { ObjectId } from "./variables/variants";
|
||||
import { ObjectId, RawObject } from "./variables/variants";
|
||||
|
||||
const log = createLogger("debugger.session", { output: "Godot Debugger" });
|
||||
|
||||
@@ -55,6 +55,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
response: DebugProtocol.InitializeResponse,
|
||||
args: DebugProtocol.InitializeRequestArguments,
|
||||
) {
|
||||
log.info("initializeRequest", args);
|
||||
response.body = response.body || {};
|
||||
|
||||
response.body.supportsConfigurationDoneRequest = true;
|
||||
@@ -83,6 +84,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
protected async launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments) {
|
||||
log.info("launchRequest", args);
|
||||
await this.configuration_done.wait(1000);
|
||||
|
||||
this.mode = "launch";
|
||||
@@ -95,6 +97,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
protected async attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments) {
|
||||
log.info("attachRequest", args);
|
||||
await this.configuration_done.wait(1000);
|
||||
|
||||
this.mode = "attach";
|
||||
@@ -109,11 +112,13 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
response: DebugProtocol.ConfigurationDoneResponse,
|
||||
args: DebugProtocol.ConfigurationDoneArguments,
|
||||
) {
|
||||
log.info("configurationDoneRequest", args);
|
||||
this.configuration_done.notify();
|
||||
this.sendResponse(response);
|
||||
}
|
||||
|
||||
protected continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments) {
|
||||
log.info("continueRequest", args);
|
||||
if (!this.exception) {
|
||||
response.body = { allThreadsContinued: true };
|
||||
this.controller.continue();
|
||||
@@ -122,6 +127,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
protected async evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments) {
|
||||
log.info("evaluateRequest", args);
|
||||
await debug.activeDebugSession.customRequest("scopes", { frameId: 0 });
|
||||
|
||||
if (this.all_scopes) {
|
||||
@@ -149,6 +155,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
protected nextRequest(response: DebugProtocol.NextResponse, args: DebugProtocol.NextArguments) {
|
||||
log.info("nextRequest", args);
|
||||
if (!this.exception) {
|
||||
this.controller.next();
|
||||
this.sendResponse(response);
|
||||
@@ -156,6 +163,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
protected pauseRequest(response: DebugProtocol.PauseResponse, args: DebugProtocol.PauseArguments) {
|
||||
log.info("pauseRequest", args);
|
||||
if (!this.exception) {
|
||||
this.controller.break();
|
||||
this.sendResponse(response);
|
||||
@@ -163,6 +171,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
protected async scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments) {
|
||||
log.info("scopesRequest", args);
|
||||
this.controller.request_stack_frame_vars(args.frameId);
|
||||
await this.got_scope.wait(2000);
|
||||
|
||||
@@ -180,6 +189,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
response: DebugProtocol.SetBreakpointsResponse,
|
||||
args: DebugProtocol.SetBreakpointsArguments,
|
||||
) {
|
||||
log.info("setBreakPointsRequest", args);
|
||||
const path = (args.source.path as string).replace(/\\/g, "/");
|
||||
const client_lines = args.lines || [];
|
||||
|
||||
@@ -216,6 +226,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
protected stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments) {
|
||||
log.info("stackTraceRequest", args);
|
||||
if (this.debug_data.last_frame) {
|
||||
response.body = {
|
||||
totalFrames: this.debug_data.last_frames.length,
|
||||
@@ -234,6 +245,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
protected stepInRequest(response: DebugProtocol.StepInResponse, args: DebugProtocol.StepInArguments) {
|
||||
log.info("stepInRequest", args);
|
||||
if (!this.exception) {
|
||||
this.controller.step();
|
||||
this.sendResponse(response);
|
||||
@@ -241,6 +253,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
protected stepOutRequest(response: DebugProtocol.StepOutResponse, args: DebugProtocol.StepOutArguments) {
|
||||
log.info("stepOutRequest", args);
|
||||
if (!this.exception) {
|
||||
this.controller.step_out();
|
||||
this.sendResponse(response);
|
||||
@@ -248,6 +261,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
protected terminateRequest(response: DebugProtocol.TerminateResponse, args: DebugProtocol.TerminateArguments) {
|
||||
log.info("terminateRequest", args);
|
||||
if (this.mode === "launch") {
|
||||
this.controller.stop();
|
||||
this.sendEvent(new TerminatedEvent());
|
||||
@@ -256,6 +270,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
protected threadsRequest(response: DebugProtocol.ThreadsResponse) {
|
||||
log.info("threadsRequest");
|
||||
response.body = { threads: [new Thread(0, "thread_1")] };
|
||||
this.sendResponse(response);
|
||||
}
|
||||
@@ -264,6 +279,7 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
response: DebugProtocol.VariablesResponse,
|
||||
args: DebugProtocol.VariablesArguments,
|
||||
) {
|
||||
log.info("variablesRequest", args);
|
||||
if (!this.all_scopes) {
|
||||
response.body = {
|
||||
variables: [],
|
||||
@@ -347,41 +363,56 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
|
||||
this.add_to_inspections();
|
||||
|
||||
if (this.ongoing_inspections.length === 0) {
|
||||
if (this.ongoing_inspections.length === 0 && stackVars.remaining == 0) {
|
||||
// in case if stackVars are empty, the this.ongoing_inspections will be empty also
|
||||
// godot 4.3 generates empty stackVars with remaining > 0 on a breakpoint stop
|
||||
// godot will continue sending `stack_frame_vars` until all `stackVars.remaining` are sent
|
||||
// at this moment `stack_frame_vars` will call `set_scopes` again with cumulated stackVars
|
||||
// TODO: godot won't send the recursive variable, see related https://github.com/godotengine/godot/issues/76019
|
||||
// in that case the vscode extension fails to call this.got_scope.notify();
|
||||
// hence the extension needs to be refactored to handle missing `stack_frame_vars` messages
|
||||
this.previous_inspections = [];
|
||||
this.got_scope.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public set_inspection(id: bigint, replacement: GodotVariable) {
|
||||
public set_inspection(id: bigint, rawObject: RawObject, sub_values: GodotVariable[]) {
|
||||
const variables = this.all_scopes.filter((va) => va && va.value instanceof ObjectId && va.value.id === id);
|
||||
|
||||
for (const va of variables) {
|
||||
const index = this.all_scopes.findIndex((va_id) => va_id === va);
|
||||
if (index < 0) {
|
||||
continue;
|
||||
}
|
||||
const old = this.all_scopes.splice(index, 1);
|
||||
// GodotVariable instance will be different for different variables, even if the referenced object id is the same:
|
||||
const replacement = {value: rawObject, sub_values: sub_values } as GodotVariable;
|
||||
replacement.name = old[0].name;
|
||||
replacement.scope_path = old[0].scope_path;
|
||||
this.append_variable(replacement, index);
|
||||
}
|
||||
|
||||
this.ongoing_inspections.splice(
|
||||
this.ongoing_inspections.findIndex((va_id) => va_id === id),
|
||||
1,
|
||||
);
|
||||
const ongoing_inspections_index = this.ongoing_inspections.findIndex((va_id) => va_id === id);
|
||||
if (ongoing_inspections_index >= 0) {
|
||||
this.ongoing_inspections.splice(ongoing_inspections_index, 1);
|
||||
}
|
||||
|
||||
|
||||
this.previous_inspections.push(id);
|
||||
|
||||
// this.add_to_inspections();
|
||||
|
||||
if (this.ongoing_inspections.length === 0) {
|
||||
// the `ongoing_inspections` is not empty, until all scopes are fully resolved
|
||||
// once last inspection is resolved: Notify that we got full scope
|
||||
this.previous_inspections = [];
|
||||
this.got_scope.notify();
|
||||
}
|
||||
}
|
||||
|
||||
private add_to_inspections() {
|
||||
for (const va of this.all_scopes) {
|
||||
if (va && va.value instanceof ObjectId) {
|
||||
const scopes_to_check = this.all_scopes.filter((va) => va && va.value instanceof ObjectId);
|
||||
for (const va of scopes_to_check) {
|
||||
if (
|
||||
!this.ongoing_inspections.includes(va.value.id) &&
|
||||
!this.previous_inspections.includes(va.value.id)
|
||||
@@ -391,7 +422,6 @@ export class GodotDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected get_variable(
|
||||
expression: string,
|
||||
|
||||
359
src/debugger/godot4/debugger_variables.test.ts
Normal file
359
src/debugger/godot4/debugger_variables.test.ts
Normal file
@@ -0,0 +1,359 @@
|
||||
import { promises as fs } from "fs";
|
||||
import * as path from "path";
|
||||
import * as vscode from "vscode";
|
||||
import { DebugProtocol } from "@vscode/debugprotocol";
|
||||
import chai from "chai";
|
||||
import chaiSubset from "chai-subset";
|
||||
|
||||
import { promisify } from "util";
|
||||
import { execFile } from "child_process";
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
chai.use(chaiSubset);
|
||||
const { expect } = chai;
|
||||
|
||||
async function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a path to a script, returns an object where each key is the name of a
|
||||
* breakpoint (delimited by `breakpoint::`) and each value is the line number
|
||||
* where the breakpoint appears in the script.
|
||||
*
|
||||
* @param scriptPath The path to the script to scan.
|
||||
* @returns An object of breakpoint names to line numbers.
|
||||
*/
|
||||
async function getBreakpointLocations(scriptPath: string): Promise<{ [key: string]: vscode.Location }> {
|
||||
const script_content = await fs.readFile(scriptPath, "utf-8");
|
||||
const breakpoints: { [key: string]: vscode.Location } = {};
|
||||
const breakpointRegex = /\b(breakpoint::.*)\b/g;
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = breakpointRegex.exec(script_content)) !== null) {
|
||||
const breakpointName = match[1];
|
||||
const line = match.index ? script_content.substring(0, match.index).split("\n").length : 1;
|
||||
breakpoints[breakpointName] = new vscode.Location(vscode.Uri.file(scriptPath), new vscode.Position(line - 1, 0));
|
||||
}
|
||||
return breakpoints;
|
||||
}
|
||||
|
||||
async function waitForActiveStackItemChange(ms: number = 10000): Promise<vscode.DebugThread | vscode.DebugStackFrame | undefined> {
|
||||
const res = await new Promise<vscode.DebugThread | vscode.DebugStackFrame | undefined>((resolve, reject) => {
|
||||
const debugListener = vscode.debug.onDidChangeActiveStackItem((event) => {
|
||||
debugListener.dispose();
|
||||
resolve(vscode.debug.activeStackItem);
|
||||
});
|
||||
|
||||
// Timeout fallback in case stack item never changes
|
||||
setTimeout(() => {
|
||||
debugListener.dispose();
|
||||
console.warn();
|
||||
reject(new Error(`The ActiveStackItem eventwas not changed within the timeout period of '${ms}'`));
|
||||
}, ms);
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async function getStackFrames(threadId: number = 1): Promise<DebugProtocol.StackFrame[]> {
|
||||
// Ensure there is an active debug session
|
||||
if (!vscode.debug.activeDebugSession) {
|
||||
throw new Error("No active debug session found");
|
||||
}
|
||||
|
||||
// corresponds to file://./debug_session.ts stackTraceRequest(...)
|
||||
const stackTraceResponse = await vscode.debug.activeDebugSession.customRequest("stackTrace", {
|
||||
threadId: threadId,
|
||||
});
|
||||
|
||||
// Extract and return the stack frames
|
||||
return stackTraceResponse.stackFrames || [];
|
||||
}
|
||||
|
||||
async function waitForBreakpoint(breakpoint: vscode.SourceBreakpoint, timeoutMs: number, ctx?: Mocha.Context): Promise<void> {
|
||||
const t0 = performance.now();
|
||||
console.log(fmt(`Waiting for breakpoint ${breakpoint.location.uri.path}:${breakpoint.location.range.start.line}, enabled: ${breakpoint.enabled}`));
|
||||
const res = await waitForActiveStackItemChange(timeoutMs);
|
||||
const t1 = performance.now();
|
||||
console.log(fmt(`Waiting for breakpoint completed ${breakpoint.location.uri.path}:${breakpoint.location.range.start.line}, enabled: ${breakpoint.enabled}, took ${t1 - t0}ms`));
|
||||
const stackFrames = await getStackFrames();
|
||||
if (stackFrames[0].source.path !== breakpoint.location.uri.fsPath || stackFrames[0].line != breakpoint.location.range.start.line+1) {
|
||||
throw new Error(`Wrong breakpoint was hit. Expected: ${breakpoint.location.uri.fsPath}:${breakpoint.location.range.start.line+1}, Got: ${stackFrames[0].source.path}:${stackFrames[0].line}`);
|
||||
}
|
||||
}
|
||||
|
||||
enum VariableScope {
|
||||
Locals = 1,
|
||||
Members = 2,
|
||||
Globals = 3
|
||||
}
|
||||
|
||||
async function getVariablesForScope(scope: VariableScope): Promise<DebugProtocol.Variable[]> {
|
||||
// corresponds to file://./debug_session.ts protected async variablesRequest
|
||||
const variablesResponse = await vscode.debug.activeDebugSession?.customRequest("variables", {
|
||||
variablesReference: scope
|
||||
});
|
||||
return variablesResponse?.variables || [];
|
||||
}
|
||||
|
||||
async function evaluateRequest(scope: VariableScope, expression: string, context = "watch", frameId = 0): Promise<any> {
|
||||
// corresponds to file://./debug_session.ts protected async evaluateRequest
|
||||
const evaluateResponse: DebugProtocol.EvaluateResponse = await vscode.debug.activeDebugSession?.customRequest("evaluate", {
|
||||
context,
|
||||
expression,
|
||||
frameId
|
||||
});
|
||||
return evaluateResponse.body;
|
||||
}
|
||||
|
||||
function formatMs(ms: number): string {
|
||||
const seconds = Math.floor((ms / 1000) % 60);
|
||||
const minutes = Math.floor((ms / (1000 * 60)) % 60);
|
||||
return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}.${(Math.round(ms) % 1000).toString().padStart(3, "0")}`;
|
||||
}
|
||||
|
||||
function formatMessage(this: Mocha.Context, msg: string): string {
|
||||
return `[${formatMs(performance.now()-this.testStart)}] ${msg}`;
|
||||
}
|
||||
|
||||
var fmt: (msg: string) => string; // formatMessage bound to Mocha.Context
|
||||
|
||||
async function startDebugging(scene: "ScopeVars.tscn" | "ExtensiveVars.tscn" | "BuiltInTypes.tscn" = "ScopeVars.tscn"): Promise<void> {
|
||||
const t0 = performance.now();
|
||||
const debugConfig: vscode.DebugConfiguration = {
|
||||
type: "godot",
|
||||
request: "launch",
|
||||
name: "Godot Debug",
|
||||
scene: scene,
|
||||
additional_options: "--headless"
|
||||
};
|
||||
console.log(fmt(`Starting debugger for scene ${scene}`));
|
||||
const res = await vscode.debug.startDebugging(vscode.workspace.workspaceFolders?.[0], debugConfig);
|
||||
const t1 = performance.now();
|
||||
console.log(fmt(`Starting debugger for scene ${scene} completed, took ${t1 - t0}ms`));
|
||||
if (!res) {
|
||||
throw new Error(`Failed to start debugging for scene ${scene}`);
|
||||
}
|
||||
}
|
||||
|
||||
suite("DAP Integration Tests - Variable Scopes", () => {
|
||||
// workspaceFolder should match `.vscode-test.js`::workspaceFolder
|
||||
const workspaceFolder = path.resolve(__dirname, "../../../test_projects/test-dap-project-godot4");
|
||||
|
||||
suiteSetup(async function() {
|
||||
this.timeout(20000); // enough time to do `godot --import`
|
||||
console.log("Environment Variables:");
|
||||
for (const [key, value] of Object.entries(process.env)) {
|
||||
console.log(`${key}: ${value}`);
|
||||
}
|
||||
|
||||
// init the godot project by importing it in godot engine:
|
||||
const config = vscode.workspace.getConfiguration("godotTools");
|
||||
var godot4_path = config.get<string>("editorPath.godot4");
|
||||
// get the path for currently opened project in vscode test instance:
|
||||
var project_path = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
|
||||
console.log("Executing", [godot4_path, "--headless", "--import", project_path]);
|
||||
const exec_res = await execFileAsync(godot4_path, ["--headless", "--import", project_path], {shell: true, cwd: project_path});
|
||||
if (exec_res.stderr !== "") {
|
||||
throw new Error(exec_res.stderr);
|
||||
}
|
||||
console.log(exec_res.stdout);
|
||||
});
|
||||
|
||||
setup(async function() {
|
||||
console.log(`➤ Test '${this?.currentTest.title}' starting`);
|
||||
await vscode.commands.executeCommand("workbench.action.closeAllEditors");
|
||||
if (vscode.debug.breakpoints) {
|
||||
await vscode.debug.removeBreakpoints(vscode.debug.breakpoints);
|
||||
}
|
||||
this.testStart = performance.now();
|
||||
fmt = formatMessage.bind(this);
|
||||
});
|
||||
|
||||
|
||||
teardown(async function() {
|
||||
await sleep(1000);
|
||||
if (vscode.debug.activeDebugSession !== undefined) {
|
||||
console.log("Closing debug session");
|
||||
await vscode.debug.stopDebugging();
|
||||
}
|
||||
console.log(`⬛ Test '${this.currentTest.title}' result: ${this.currentTest.state}, duration: ${performance.now() - this.testStart}ms`);
|
||||
});
|
||||
|
||||
|
||||
test("sample test", async function() {
|
||||
// await sleep(1000);
|
||||
await startDebugging("ScopeVars.tscn");
|
||||
});
|
||||
|
||||
|
||||
test("should return correct scopes", async function() {
|
||||
const breakpointLocations = await getBreakpointLocations(path.join(workspaceFolder, "ScopeVars.gd"));
|
||||
const breakpoint = new vscode.SourceBreakpoint(breakpointLocations["breakpoint::ScopeVars::_ready"]);
|
||||
vscode.debug.addBreakpoints([breakpoint]);
|
||||
|
||||
await startDebugging("ScopeVars.tscn");
|
||||
await waitForBreakpoint(breakpoint, 2000);
|
||||
|
||||
// TODO: current DAP needs a delay before it will return variables
|
||||
console.log("Sleeping for 2 seconds");
|
||||
await sleep(2000);
|
||||
|
||||
// corresponds to file://./debug_session.ts async scopesRequest
|
||||
const res_scopes = await vscode.debug.activeDebugSession.customRequest("scopes", {frameId: 1});
|
||||
|
||||
expect(res_scopes).to.exist;
|
||||
expect(res_scopes.scopes).to.exist;
|
||||
|
||||
const scopes = res_scopes.scopes;
|
||||
expect(scopes.length).to.equal(3, "Expected 3 scopes");
|
||||
expect(scopes[0].name).to.equal(VariableScope[VariableScope.Locals], "Expected Locals scope");
|
||||
expect(scopes[0].variablesReference).to.equal(VariableScope.Locals, "Expected Locals variablesReference");
|
||||
expect(scopes[1].name).to.equal(VariableScope[VariableScope.Members], "Expected Members scope");
|
||||
expect(scopes[1].variablesReference).to.equal(VariableScope.Members, "Expected Members variablesReference");
|
||||
expect(scopes[2].name).to.equal(VariableScope[VariableScope.Globals], "Expected Globals scope");
|
||||
expect(scopes[2].variablesReference).to.equal(VariableScope.Globals, "Expected Globals variablesReference");
|
||||
|
||||
await sleep(1000);
|
||||
await vscode.debug.stopDebugging();
|
||||
})?.timeout(5000);
|
||||
|
||||
test("should return global variables", async function() {
|
||||
const breakpointLocations = await getBreakpointLocations(path.join(workspaceFolder, "ScopeVars.gd"));
|
||||
const breakpoint = new vscode.SourceBreakpoint(breakpointLocations["breakpoint::ScopeVars::_ready"]);
|
||||
vscode.debug.addBreakpoints([breakpoint]);
|
||||
|
||||
await startDebugging("ScopeVars.tscn");
|
||||
await waitForBreakpoint(breakpoint, 2000);
|
||||
|
||||
// TODO: current DAP needs a delay before it will return variables
|
||||
console.log("Sleeping for 2 seconds");
|
||||
await sleep(2000);
|
||||
|
||||
const variables = await getVariablesForScope(VariableScope.Globals);
|
||||
expect(variables).to.containSubset([{name: "GlobalScript"}]);
|
||||
|
||||
await sleep(1000);
|
||||
await vscode.debug.stopDebugging();
|
||||
})?.timeout(7000);
|
||||
|
||||
test("should return local variables", async function() {
|
||||
const breakpointLocations = await getBreakpointLocations(path.join(workspaceFolder, "ScopeVars.gd"));
|
||||
const breakpoint = new vscode.SourceBreakpoint(breakpointLocations["breakpoint::ScopeVars::_ready"]);
|
||||
vscode.debug.addBreakpoints([breakpoint]);
|
||||
|
||||
await startDebugging("ScopeVars.tscn");
|
||||
await waitForBreakpoint(breakpoint, 2000);
|
||||
|
||||
// TODO: current DAP needs a delay before it will return variables
|
||||
console.log("Sleeping for 2 seconds");
|
||||
await sleep(2000);
|
||||
|
||||
const variables = await getVariablesForScope(VariableScope.Locals);
|
||||
expect(variables.length).to.equal(2);
|
||||
expect(variables).to.containSubset([{name: "local1"}]);
|
||||
expect(variables).to.containSubset([{name: "local2"}]);
|
||||
|
||||
await sleep(1000);
|
||||
await vscode.debug.stopDebugging();
|
||||
})?.timeout(5000);
|
||||
|
||||
test("should return member variables", async function() {
|
||||
const breakpointLocations = await getBreakpointLocations(path.join(workspaceFolder, "ScopeVars.gd"));
|
||||
const breakpoint = new vscode.SourceBreakpoint(breakpointLocations["breakpoint::ScopeVars::_ready"]);
|
||||
vscode.debug.addBreakpoints([breakpoint]);
|
||||
|
||||
await startDebugging("ScopeVars.tscn");
|
||||
await waitForBreakpoint(breakpoint, 2000);
|
||||
|
||||
// TODO: current DAP needs a delay before it will return variables
|
||||
console.log("Sleeping for 2 seconds");
|
||||
await sleep(2000);
|
||||
|
||||
const variables = await getVariablesForScope(VariableScope.Members);
|
||||
expect(variables.length).to.equal(2);
|
||||
expect(variables).to.containSubset([{name: "self"}]);
|
||||
expect(variables).to.containSubset([{name: "member1"}]);
|
||||
|
||||
await sleep(1000);
|
||||
await vscode.debug.stopDebugging();
|
||||
})?.timeout(5000);
|
||||
|
||||
test("should retrieve all built-in types correctly", async function() {
|
||||
const breakpointLocations = await getBreakpointLocations(path.join(workspaceFolder, "BuiltInTypes.gd"));
|
||||
const breakpoint = new vscode.SourceBreakpoint(breakpointLocations["breakpoint::BuiltInTypes::_ready"]);
|
||||
vscode.debug.addBreakpoints([breakpoint]);
|
||||
|
||||
await startDebugging("BuiltInTypes.tscn");
|
||||
await waitForBreakpoint(breakpoint, 2000);
|
||||
|
||||
// TODO: current DAP needs a delay before it will return variables
|
||||
console.log("Sleeping for 2 seconds");
|
||||
await sleep(2000);
|
||||
|
||||
const variables = await getVariablesForScope(VariableScope.Locals);
|
||||
|
||||
expect(variables).to.containSubset([{ name: "int_var", value: "42" }]);
|
||||
expect(variables).to.containSubset([{ name: "float_var", value: "3.14" }]);
|
||||
expect(variables).to.containSubset([{ name: "bool_var", value: "true" }]);
|
||||
expect(variables).to.containSubset([{ name: "string_var", value: "Hello, Godot!" }]);
|
||||
expect(variables).to.containSubset([{ name: "nil_var", value: "null" }]);
|
||||
expect(variables).to.containSubset([{ name: "vector2", value: "Vector2(10, 20)" }]);
|
||||
expect(variables).to.containSubset([{ name: "vector3", value: "Vector3(1, 2, 3)" }]);
|
||||
expect(variables).to.containSubset([{ name: "rect2", value: "Rect2((0, 0) - (100, 50))" }]);
|
||||
expect(variables).to.containSubset([{ name: "quaternion", value: "Quat(0, 0, 0, 1)" }]);
|
||||
// expect(variables).to.containSubset([{ name: "simple_array", value: "[1, 2, 3]" }]);
|
||||
expect(variables).to.containSubset([{ name: "simple_array", value: "Array[3]" }]);
|
||||
// expect(variables).to.containSubset([{ name: "nested_dict.nested_key", value: `"Nested Value"` }]);
|
||||
// expect(variables).to.containSubset([{ name: "nested_dict.sub_dict.sub_key", value: "99" }]);
|
||||
expect(variables).to.containSubset([{ name: "nested_dict", value: "Dictionary[2]" }]);
|
||||
// expect(variables).to.containSubset([{ name: "byte_array", value: "[0, 1, 2, 255]" }]);
|
||||
expect(variables).to.containSubset([{ name: "byte_array", value: "Array[4]" }]);
|
||||
// expect(variables).to.containSubset([{ name: "int32_array", value: "[100, 200, 300]" }]);
|
||||
expect(variables).to.containSubset([{ name: "int32_array", value: "Array[3]" }]);
|
||||
expect(variables).to.containSubset([{ name: "color_var", value: "Color(1, 0, 0, 1)" }]);
|
||||
expect(variables).to.containSubset([{ name: "aabb_var", value: "AABB((0, 0, 0), (1, 1, 1))" }]);
|
||||
expect(variables).to.containSubset([{ name: "plane_var", value: "Plane(0, 1, 0, -5)" }]);
|
||||
expect(variables).to.containSubset([{ name: "callable_var", value: "Callable()" }]);
|
||||
expect(variables).to.containSubset([{ name: "signal_var" }]);
|
||||
const signal_var = variables.find(v => v.name === "signal_var");
|
||||
expect(signal_var.value).to.match(/Signal\(member_signal\, <\d+>\)/, "Should be in format of 'Signal(member_signal, <28236055815>)'");
|
||||
|
||||
await sleep(1000);
|
||||
await vscode.debug.stopDebugging();
|
||||
})?.timeout(5000);
|
||||
|
||||
test("should retrieve all complex variables correctly", async function() {
|
||||
const breakpointLocations = await getBreakpointLocations(path.join(workspaceFolder, "ExtensiveVars.gd"));
|
||||
const breakpoint = new vscode.SourceBreakpoint(breakpointLocations["breakpoint::ExtensiveVars::_ready"]);
|
||||
vscode.debug.addBreakpoints([breakpoint]);
|
||||
|
||||
await startDebugging("ExtensiveVars.tscn");
|
||||
await waitForBreakpoint(breakpoint, 2000);
|
||||
|
||||
// TODO: current DAP needs a delay before it will return variables
|
||||
console.log("Sleeping for 2 seconds");
|
||||
await sleep(2000);
|
||||
|
||||
const memberVariables = await getVariablesForScope(VariableScope.Members);
|
||||
|
||||
expect(memberVariables.length).to.equal(3);
|
||||
expect(memberVariables).to.containSubset([{name: "self"}]);
|
||||
expect(memberVariables).to.containSubset([{name: "self_var"}]);
|
||||
const self = memberVariables.find(v => v.name === "self");
|
||||
const self_var = memberVariables.find(v => v.name === "self_var");
|
||||
expect(self.value).to.deep.equal(self_var.value);
|
||||
|
||||
const localVariables = await getVariablesForScope(VariableScope.Locals);
|
||||
expect(localVariables.length).to.equal(4);
|
||||
expect(localVariables).to.containSubset([
|
||||
{ name: "local_label", value: "Label" },
|
||||
{ name: "local_self_var_through_label", value: "Node2D" },
|
||||
{ name: "local_classA", value: "RefCounted" },
|
||||
{ name: "local_classB", value: "RefCounted" }
|
||||
]);
|
||||
|
||||
await sleep(1000);
|
||||
await vscode.debug.stopDebugging();
|
||||
})?.timeout(15000);
|
||||
});
|
||||
@@ -36,12 +36,11 @@ export function is_variable_built_in_type(va: GodotVariable) {
|
||||
return ["number", "bigint", "boolean", "string"].some(x => x == type);
|
||||
}
|
||||
|
||||
export function build_sub_values(va: GodotVariable) {
|
||||
const value = va.value;
|
||||
|
||||
export function get_sub_values(value: any) {
|
||||
let subValues: GodotVariable[] = undefined;
|
||||
|
||||
if (value && Array.isArray(value)) {
|
||||
if (value) {
|
||||
if (Array.isArray(value)) {
|
||||
subValues = value.map((va, i) => {
|
||||
return { name: `${i}`, value: va } as GodotVariable;
|
||||
});
|
||||
@@ -59,15 +58,18 @@ export function build_sub_values(va: GodotVariable) {
|
||||
} as GodotVariable;
|
||||
}
|
||||
});
|
||||
} else if (value && typeof value["sub_values"] === "function") {
|
||||
subValues = value.sub_values().map((sva) => {
|
||||
} else if (typeof value["sub_values"] === "function") {
|
||||
subValues = value.sub_values()?.map((sva) => {
|
||||
return { name: sva.name, value: sva.value } as GodotVariable;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
va.sub_values = subValues;
|
||||
for (let i = 0; i < subValues?.length; i++) {
|
||||
subValues[i].sub_values = get_sub_values(subValues[i].value);
|
||||
}
|
||||
|
||||
subValues?.forEach(build_sub_values);
|
||||
return subValues;
|
||||
}
|
||||
|
||||
export function parse_variable(va: GodotVariable, i?: number) {
|
||||
@@ -103,7 +105,11 @@ export function parse_variable(va: GodotVariable, i?: number) {
|
||||
array_type = "named";
|
||||
reference = i ? i : 0;
|
||||
} else {
|
||||
try {
|
||||
rendered_value = `${value.type_name()}${value.stringify_value()}`;
|
||||
} catch (e) {
|
||||
rendered_value = `${value}`;
|
||||
}
|
||||
reference = i ? i : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import { killSubProcesses, subProcess } from "../../utils/subspawn";
|
||||
import { GodotStackFrame, GodotStackVars, GodotVariable } from "../debug_runtime";
|
||||
import { AttachRequestArguments, LaunchRequestArguments, pinnedScene } from "../debugger";
|
||||
import { GodotDebugSession } from "./debug_session";
|
||||
import { build_sub_values, parse_next_scene_node, split_buffers } from "./helpers";
|
||||
import { get_sub_values, parse_next_scene_node, split_buffers } from "./helpers";
|
||||
import { VariantDecoder } from "./variables/variant_decoder";
|
||||
import { VariantEncoder } from "./variables/variant_encoder";
|
||||
import { RawObject } from "./variables/variants";
|
||||
@@ -395,13 +395,15 @@ export class ServerController {
|
||||
for (const prop of properties) {
|
||||
rawObject.set(prop[0], prop[5]);
|
||||
}
|
||||
const inspectedVariable = { name: "", value: rawObject };
|
||||
build_sub_values(inspectedVariable);
|
||||
if (this.session.inspect_callbacks.has(BigInt(id))) {
|
||||
this.session.inspect_callbacks.get(BigInt(id))(inspectedVariable.name, inspectedVariable);
|
||||
const sub_values = get_sub_values(rawObject);
|
||||
|
||||
const inspect_callback = this.session.inspect_callbacks.get(BigInt(id));
|
||||
if (inspect_callback !== undefined) {
|
||||
const inspectedVariable = { name: "", value: rawObject, sub_values: sub_values } as GodotVariable;
|
||||
inspect_callback(inspectedVariable.name, inspectedVariable);
|
||||
this.session.inspect_callbacks.delete(BigInt(id));
|
||||
}
|
||||
this.session.set_inspection(id, inspectedVariable);
|
||||
this.session.set_inspection(id, rawObject, sub_values);
|
||||
break;
|
||||
}
|
||||
case "stack_dump": {
|
||||
@@ -641,8 +643,8 @@ export class ServerController {
|
||||
throw new Error("More stack frame variables were sent than expected.");
|
||||
}
|
||||
|
||||
const variable: GodotVariable = { name, value, type };
|
||||
build_sub_values(variable);
|
||||
const sub_values = get_sub_values(value);
|
||||
const variable = { name, value, type, sub_values } as GodotVariable;
|
||||
|
||||
const scopeName = ["locals", "members", "globals"][scope];
|
||||
this.partialStackVars[scopeName].push(variable);
|
||||
|
||||
@@ -471,7 +471,7 @@ export class Signal implements GDObject {
|
||||
constructor(public name: string, public oid: ObjectId) {}
|
||||
|
||||
public stringify_value(): string {
|
||||
return `${this.name}() ${this.oid.stringify_value()}`;
|
||||
return `(${this.name}, ${this.oid.stringify_value()})`;
|
||||
}
|
||||
|
||||
public sub_values(): GodotVariable[] {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
ProviderResult,
|
||||
TreeItem,
|
||||
TreeItemCollapsibleState,
|
||||
Uri
|
||||
} from "vscode";
|
||||
import path = require("path");
|
||||
import { get_extension_uri } from "../utils";
|
||||
@@ -81,8 +82,8 @@ export class SceneNode extends TreeItem {
|
||||
const iconName = class_name + ".svg";
|
||||
|
||||
this.iconPath = {
|
||||
light: path.join(iconDir, "light", iconName),
|
||||
dark: path.join(iconDir, "dark", iconName),
|
||||
light: Uri.file(path.join(iconDir, "light", iconName)),
|
||||
dark: Uri.file(path.join(iconDir, "dark", iconName)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +138,10 @@ function parse_test_file(content: string): Test[] {
|
||||
suite("GDScript Formatter Tests", () => {
|
||||
const testFiles = fs.readdirSync(snapshotsFolderPath, { withFileTypes: true, recursive: true });
|
||||
|
||||
teardown(async () => {
|
||||
await vscode.commands.executeCommand("workbench.action.closeAllEditors");
|
||||
});
|
||||
|
||||
for (const file of testFiles.filter((f) => f.isFile())) {
|
||||
if (["in.gd", "out.gd"].includes(file.name) || !file.name.endsWith(".gd")) {
|
||||
continue;
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
TreeItem,
|
||||
TreeItemCollapsibleState,
|
||||
MarkdownString,
|
||||
Uri
|
||||
} from "vscode";
|
||||
import * as path from "path";
|
||||
import { get_extension_uri } from "../utils";
|
||||
@@ -31,8 +32,8 @@ export class SceneNode extends TreeItem {
|
||||
const iconName = className + ".svg";
|
||||
|
||||
this.iconPath = {
|
||||
light: path.join(iconDir, "light", iconName),
|
||||
dark: path.join(iconDir, "dark", iconName),
|
||||
light: Uri.file(path.join(iconDir, "light", iconName)),
|
||||
dark: Uri.file(path.join(iconDir, "dark", iconName)),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
40
test_projects/test-dap-project-godot4/.vscode/launch.json
vendored
Normal file
40
test_projects/test-dap-project-godot4/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "GDScript: Launch ScopeVars.tscn",
|
||||
"type": "godot",
|
||||
"request": "launch",
|
||||
"project": "${workspaceFolder}",
|
||||
"scene": "ScopeVars.tscn"
|
||||
// "debug_collisions": false,
|
||||
// "debug_paths": false,
|
||||
// "debug_navigation": false,
|
||||
// "additional_options": ""
|
||||
},
|
||||
{
|
||||
"name": "GDScript: Launch ExtensiveVars.tscn",
|
||||
"type": "godot",
|
||||
"request": "launch",
|
||||
"project": "${workspaceFolder}",
|
||||
"scene": "ExtensiveVars.tscn"
|
||||
},
|
||||
{
|
||||
"name": "GDScript: Launch BuiltInTypes.tscn",
|
||||
"type": "godot",
|
||||
"request": "launch",
|
||||
"project": "${workspaceFolder}",
|
||||
"scene": "BuiltInTypes.tscn"
|
||||
},
|
||||
{
|
||||
"name": "GDScript: Launch NodeVars.tscn",
|
||||
"type": "godot",
|
||||
"request": "launch",
|
||||
"project": "${workspaceFolder}",
|
||||
"scene": "NodeVars.tscn"
|
||||
}
|
||||
]
|
||||
}
|
||||
39
test_projects/test-dap-project-godot4/BuiltInTypes.gd
Normal file
39
test_projects/test-dap-project-godot4/BuiltInTypes.gd
Normal file
@@ -0,0 +1,39 @@
|
||||
extends Node
|
||||
|
||||
signal member_signal
|
||||
signal member_signal_with_parameters(my_param1: String)
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
var int_var = 42
|
||||
var float_var = 3.14
|
||||
var bool_var = true
|
||||
var string_var = "Hello, Godot!"
|
||||
var nil_var = null
|
||||
var vector2 = Vector2(10, 20)
|
||||
var vector3 = Vector3(1, 2, 3)
|
||||
var rect2 = Rect2(0, 0, 100, 50)
|
||||
var quaternion = Quaternion(0, 0, 0, 1)
|
||||
var simple_array = [1, 2, 3]
|
||||
var nested_dict = {
|
||||
"nested_key": "Nested Value",
|
||||
"sub_dict": {"sub_key": 99}
|
||||
}
|
||||
var byte_array = PackedByteArray([0, 1, 2, 255])
|
||||
var int32_array = PackedInt32Array([100, 200, 300])
|
||||
var color_var = Color(1, 0, 0, 1) # Red color
|
||||
var aabb_var = AABB(Vector3(0, 0, 0), Vector3(1, 1, 1))
|
||||
var plane_var = Plane(Vector3(0, 1, 0), -5)
|
||||
|
||||
var callable_var = self.my_callable_func
|
||||
|
||||
var signal_var = member_signal
|
||||
member_signal.connect(singal_connected_func)
|
||||
|
||||
print("breakpoint::BuiltInTypes::_ready")
|
||||
|
||||
func my_callable_func():
|
||||
pass
|
||||
|
||||
func singal_connected_func():
|
||||
pass
|
||||
11
test_projects/test-dap-project-godot4/BuiltInTypes.tscn
Normal file
11
test_projects/test-dap-project-godot4/BuiltInTypes.tscn
Normal file
@@ -0,0 +1,11 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://d0ovhv6f38jj4"]
|
||||
|
||||
[ext_resource type="Script" path="res://BuiltInTypes.gd" id="1_2dpge"]
|
||||
|
||||
[node name="BuiltInTypes" type="Node"]
|
||||
script = ExtResource("1_2dpge")
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
offset_right = 40.0
|
||||
offset_bottom = 23.0
|
||||
text = "Built-in types"
|
||||
38
test_projects/test-dap-project-godot4/ExtensiveVars.gd
Normal file
38
test_projects/test-dap-project-godot4/ExtensiveVars.gd
Normal file
@@ -0,0 +1,38 @@
|
||||
extends Node2D
|
||||
|
||||
var self_var := self
|
||||
@onready var label: ExtensiveVars_Label = $Label
|
||||
|
||||
class ClassA:
|
||||
var member_classB
|
||||
var member_self := self
|
||||
|
||||
class ClassB:
|
||||
var member_classA
|
||||
|
||||
func _ready() -> void:
|
||||
var local_label := label
|
||||
var local_self_var_through_label := label.parent_var
|
||||
|
||||
var local_classA = ClassA.new()
|
||||
var local_classB = ClassB.new()
|
||||
local_classA.member_classB = local_classB
|
||||
local_classB.member_classA = local_classA
|
||||
|
||||
# Circular reference.
|
||||
# Note: that causes the godot engine to omit this variable, since stack_frame_var cannot be completed and sent
|
||||
# https://github.com/godotengine/godot/issues/76019
|
||||
# var dict = {}
|
||||
# dict["self_ref"] = dict
|
||||
|
||||
print("breakpoint::ExtensiveVars::_ready")
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
var local_label := label
|
||||
var local_self_var_through_label := label.parent_var
|
||||
|
||||
var local_classA = ClassA.new()
|
||||
var local_classB = ClassB.new()
|
||||
local_classA.member_classB = local_classB
|
||||
local_classB.member_classA = local_classA
|
||||
pass
|
||||
12
test_projects/test-dap-project-godot4/ExtensiveVars.tscn
Normal file
12
test_projects/test-dap-project-godot4/ExtensiveVars.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://bsonfthpqa3dx"]
|
||||
|
||||
[ext_resource type="Script" path="res://ExtensiveVars.gd" id="1_fnilr"]
|
||||
[ext_resource type="Script" path="res://ExtensiveVars_Label.gd" id="2_jijf2"]
|
||||
|
||||
[node name="ExtensiveVars" type="Node2D"]
|
||||
script = ExtResource("1_fnilr")
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
text = "Extensive Vars scene"
|
||||
script = ExtResource("2_jijf2")
|
||||
metadata/_edit_use_anchors_ = true
|
||||
14
test_projects/test-dap-project-godot4/ExtensiveVars_Label.gd
Normal file
14
test_projects/test-dap-project-godot4/ExtensiveVars_Label.gd
Normal file
@@ -0,0 +1,14 @@
|
||||
extends Label
|
||||
|
||||
class_name ExtensiveVars_Label
|
||||
|
||||
@onready var parent_var: Node2D = $".."
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(delta: float) -> void:
|
||||
pass
|
||||
3
test_projects/test-dap-project-godot4/GlobalScript.gd
Normal file
3
test_projects/test-dap-project-godot4/GlobalScript.gd
Normal file
@@ -0,0 +1,3 @@
|
||||
extends Node
|
||||
|
||||
var globalMember := "global member"
|
||||
8
test_projects/test-dap-project-godot4/Node1.gd
Normal file
8
test_projects/test-dap-project-godot4/Node1.gd
Normal file
@@ -0,0 +1,8 @@
|
||||
extends Node
|
||||
|
||||
@onready var parent_node: Node2D = $".."
|
||||
@onready var sibling_node2: Node = $"../node2"
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
pass # Replace with function body.
|
||||
9
test_projects/test-dap-project-godot4/NodeVars.gd
Normal file
9
test_projects/test-dap-project-godot4/NodeVars.gd
Normal file
@@ -0,0 +1,9 @@
|
||||
extends Node2D
|
||||
|
||||
@onready var node_1: Node = $node1
|
||||
@onready var node_2: Node = $node2
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
print("breakpoint::NodeVars::_ready")
|
||||
pass
|
||||
17
test_projects/test-dap-project-godot4/NodeVars.tscn
Normal file
17
test_projects/test-dap-project-godot4/NodeVars.tscn
Normal file
@@ -0,0 +1,17 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://xrjtth0d2nc5"]
|
||||
|
||||
[ext_resource type="Script" path="res://NodeVars.gd" id="1_6eeca"]
|
||||
[ext_resource type="Script" path="res://Node1.gd" id="2_bl41t"]
|
||||
|
||||
[node name="NodeVars" type="Node2D"]
|
||||
script = ExtResource("1_6eeca")
|
||||
|
||||
[node name="node1" type="Node" parent="."]
|
||||
script = ExtResource("2_bl41t")
|
||||
|
||||
[node name="node2" type="Node" parent="."]
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
offset_right = 40.0
|
||||
offset_bottom = 23.0
|
||||
text = "NodeVars"
|
||||
8
test_projects/test-dap-project-godot4/ScopeVars.gd
Normal file
8
test_projects/test-dap-project-godot4/ScopeVars.gd
Normal file
@@ -0,0 +1,8 @@
|
||||
extends Node
|
||||
|
||||
var member1 := TestClassA.new()
|
||||
|
||||
func _ready() -> void:
|
||||
var local1 := TestClassA.new()
|
||||
var local2 = GlobalScript.globalMember
|
||||
print("breakpoint::ScopeVars::_ready")
|
||||
11
test_projects/test-dap-project-godot4/ScopeVars.tscn
Normal file
11
test_projects/test-dap-project-godot4/ScopeVars.tscn
Normal file
@@ -0,0 +1,11 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://g5gqewj2i2xs"]
|
||||
|
||||
[ext_resource type="Script" path="res://ScopeVars.gd" id="1_wtcpp"]
|
||||
|
||||
[node name="RootNode" type="Node"]
|
||||
script = ExtResource("1_wtcpp")
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
offset_right = 40.0
|
||||
offset_bottom = 23.0
|
||||
text = "Godot test project"
|
||||
5
test_projects/test-dap-project-godot4/TestClassA.gd
Normal file
5
test_projects/test-dap-project-godot4/TestClassA.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
class_name TestClassA
|
||||
|
||||
var testclassa_member1 := "member1"
|
||||
|
||||
var testclassa_member2: Node
|
||||
19
test_projects/test-dap-project-godot4/project.godot
Normal file
19
test_projects/test-dap-project-godot4/project.godot
Normal file
@@ -0,0 +1,19 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=5
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Test DAP project godot4"
|
||||
run/main_scene="res://ScopeVars.tscn"
|
||||
config/features=PackedStringArray("4.3", "Forward Plus")
|
||||
|
||||
[autoload]
|
||||
|
||||
GlobalScript="*res://GlobalScript.gd"
|
||||
@@ -14,7 +14,8 @@
|
||||
"rootDir": "src",
|
||||
"strict": false,
|
||||
"skipLibCheck": true,
|
||||
"allowJs": true
|
||||
"allowJs": true,
|
||||
"strictBindCallApply": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
||||
Reference in New Issue
Block a user