diff --git a/.vscode/launch.json b/.vscode/launch.json
index c7691e1..02afd39 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -9,7 +9,7 @@
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceRoot}",
- "${workspaceFolder}/sample"
+ "${workspaceFolder}/sample/project"
],
"preLaunchTask": {
"type": "npm",
@@ -33,7 +33,9 @@
"--extensionTestsPath=${workspaceRoot}/dist/client/out/test/index",
"${workspaceRoot}/test/fixtures"
],
- "outFiles": ["${workspaceRoot}/dist/client/out/test/**/*.js"]
+ "outFiles": [
+ "${workspaceRoot}/dist/client/out/test/**/*.js"
+ ]
},
{
"name": "Run Web Extension in VS Code",
@@ -84,16 +86,21 @@
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
- "--extensionDevelopmentPath=${workspaceFolder}",
- "--extensionTestsPath=${workspaceFolder}/dist/client/out/test/index"
+ "--extensionDevelopmentPath=${workspaceFolder}",
+ "--extensionTestsPath=${workspaceFolder}/dist/client/out/test/index"
],
- "outFiles": ["${workspaceFolder}/dist/client/out/test/**/*.test.js"]
+ "outFiles": [
+ "${workspaceFolder}/dist/client/out/test/**/*.test.js"
+ ]
}
],
"compounds": [
{
"name": "Client + Server",
- "configurations": ["Launch Client", "Attach to Server"]
+ "configurations": [
+ "Launch Client",
+ "Attach to Server"
+ ]
}
]
-}
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 06efa67..535b248 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,23 @@ Provides Visual Basic for Applications (VBA) language support in Visual Studio C
1Currently full document `Shift+Alt+F` formatting only.
+### *PREVIEW* Definition Provider
+
+This extension now supports definitions, i.e., following a name to a declaration. Pressing F12 will jump you to the relevant method or variable declaration.
+
+This is a preview feature and may not work 100% as expected. If bugs are encountered, please take the time to raise an issue on the repo.
+
+### *PREVIEW* Code Refactoring
+
+This extension now supports Rename requests, i.e., using F2 to rename an element. It will find the all instances of the name throughout the workspace and rename it.
+
+### Preview Limitations
+
+Known limitations:
+ - Method attributes (yet) aren't renamed when you rename a function or sub.
+ - Public methods still producing diagnostics when there's a similarly named method in another module.
+ - Can't yet rename classes with this functionality.
+
### Web Support
The VBA Pro Extension offers limited support for web environments (e.g. vscode-dev).
@@ -75,6 +92,7 @@ End Property
## Coming Soon
* Hovers
+* Completion
## Installation
diff --git a/client/package-lock.json b/client/package-lock.json
index 6691ff1..9d8b06d 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -12,31 +12,31 @@
"vscode-languageclient": "^9.0.1"
},
"devDependencies": {
- "@types/vscode": "^1.99.0",
- "@vscode/test-electron": "^2.4.1"
+ "@types/vscode": "^1.100.0",
+ "@vscode/test-electron": "^2.5.2"
},
"engines": {
"vscode": "^1.63.0"
}
},
"node_modules/@types/vscode": {
- "version": "1.99.0",
- "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.99.0.tgz",
- "integrity": "sha512-30sjmas1hQ0gVbX68LAWlm/YYlEqUErunPJJKLpEl+xhK0mKn+jyzlCOpsdTwfkZfPy4U6CDkmygBLC3AB8W9Q==",
+ "version": "1.100.0",
+ "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.100.0.tgz",
+ "integrity": "sha512-4uNyvzHoraXEeCamR3+fzcBlh7Afs4Ifjs4epINyUX/jvdk0uzLnwiDY35UKDKnkCHP5Nu3dljl2H8lR6s+rQw==",
"dev": true,
"license": "MIT"
},
"node_modules/@vscode/test-electron": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.1.tgz",
- "integrity": "sha512-Gc6EdaLANdktQ1t+zozoBVRynfIsMKMc94Svu1QreOBC8y76x4tvaK32TljrLi1LI2+PK58sDVbL7ALdqf3VRQ==",
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz",
+ "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==",
"dev": true,
"license": "MIT",
"dependencies": {
"http-proxy-agent": "^7.0.2",
"https-proxy-agent": "^7.0.5",
"jszip": "^3.10.1",
- "ora": "^7.0.1",
+ "ora": "^8.1.0",
"semver": "^7.6.2"
},
"engines": {
@@ -72,54 +72,6 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
- "node_modules/base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
- "node_modules/bl": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz",
- "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "buffer": "^6.0.3",
- "inherits": "^2.0.4",
- "readable-stream": "^3.4.0"
- }
- },
- "node_modules/bl/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
@@ -129,31 +81,6 @@
"balanced-match": "^1.0.0"
}
},
- "node_modules/buffer": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
- "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.2.1"
- }
- },
"node_modules/chalk": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
@@ -168,16 +95,16 @@
}
},
"node_modules/cli-cursor": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
- "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+ "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "restore-cursor": "^4.0.0"
+ "restore-cursor": "^5.0.0"
},
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -204,9 +131,9 @@
"license": "MIT"
},
"node_modules/debug": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
- "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -221,13 +148,6 @@
}
}
},
- "node_modules/eastasianwidth": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
- "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/emoji-regex": {
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
@@ -235,6 +155,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/get-east-asian-width": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz",
+ "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/http-proxy-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
@@ -263,27 +196,6 @@
"node": ">= 14"
}
},
- "node_modules/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "BSD-3-Clause"
- },
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
@@ -312,13 +224,13 @@
}
},
"node_modules/is-unicode-supported": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
- "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=12"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -355,15 +267,28 @@
}
},
"node_modules/log-symbols": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz",
- "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz",
+ "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "chalk": "^5.0.0",
- "is-unicode-supported": "^1.1.0"
+ "chalk": "^5.3.0",
+ "is-unicode-supported": "^1.3.0"
},
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-symbols/node_modules/is-unicode-supported": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+ "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+ "dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -371,14 +296,17 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "node_modules/mimic-function": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=6"
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/minimatch": {
@@ -401,40 +329,40 @@
"license": "MIT"
},
"node_modules/onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+ "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "mimic-fn": "^2.1.0"
+ "mimic-function": "^5.0.0"
},
"engines": {
- "node": ">=6"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ora": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz",
- "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==",
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz",
+ "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
- "cli-cursor": "^4.0.0",
- "cli-spinners": "^2.9.0",
+ "cli-cursor": "^5.0.0",
+ "cli-spinners": "^2.9.2",
"is-interactive": "^2.0.0",
- "is-unicode-supported": "^1.3.0",
- "log-symbols": "^5.1.0",
- "stdin-discarder": "^0.1.0",
- "string-width": "^6.1.0",
+ "is-unicode-supported": "^2.0.0",
+ "log-symbols": "^6.0.0",
+ "stdin-discarder": "^0.2.2",
+ "string-width": "^7.2.0",
"strip-ansi": "^7.1.0"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -471,17 +399,17 @@
}
},
"node_modules/restore-cursor": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
- "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+ "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2"
+ "onetime": "^7.0.0",
+ "signal-exit": "^4.1.0"
},
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -495,9 +423,9 @@
"license": "MIT"
},
"node_modules/semver": {
- "version": "7.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
- "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -514,23 +442,26 @@
"license": "MIT"
},
"node_modules/signal-exit": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
- "license": "ISC"
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
},
"node_modules/stdin-discarder": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz",
- "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==",
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
+ "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "bl": "^5.0.0"
- },
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -547,18 +478,18 @@
}
},
"node_modules/string-width": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz",
- "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "eastasianwidth": "^0.2.0",
- "emoji-regex": "^10.2.1",
- "strip-ansi": "^7.0.1"
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
diff --git a/client/package.json b/client/package.json
index 6d4c7c4..58575bb 100644
--- a/client/package.json
+++ b/client/package.json
@@ -16,7 +16,7 @@
"vscode-languageclient": "^9.0.1"
},
"devDependencies": {
- "@types/vscode": "^1.99.0",
- "@vscode/test-electron": "^2.4.1"
+ "@types/vscode": "^1.100.0",
+ "@vscode/test-electron": "^2.5.2"
}
}
diff --git a/client/src/extension.ts b/client/src/extension.ts
index 62ff40c..ee6357a 100644
--- a/client/src/extension.ts
+++ b/client/src/extension.ts
@@ -71,3 +71,12 @@ export function deactivate(): Thenable | undefined {
}
return client.stop();
}
+
+export function isExtensionInDebugMode(): boolean {
+ // process.execArgv contains arguments specific to the Node.js executable itself.
+ // When debugging, VS Code launches the extension host with flags like
+ // '--inspect-brk' or '--inspect'.
+ return process.execArgv.some(arg =>
+ arg.startsWith('--inspect') || arg.startsWith('--debug') // '--debug' is older, but good to include
+ );
+}
diff --git a/client/src/logger.ts b/client/src/logger.ts
index 01a261c..bd2e1e1 100644
--- a/client/src/logger.ts
+++ b/client/src/logger.ts
@@ -1,4 +1,5 @@
import * as vscode from 'vscode';
+import { isExtensionInDebugMode } from './extension';
enum LogLevel {
error = 1,
@@ -15,23 +16,20 @@ export interface LogMessage {
}
export class VscodeLogger {
- private static _outputChannel: vscode.OutputChannel;
+ private static _outputChannel: vscode.OutputChannel | undefined;
private static get outputChannel(): vscode.OutputChannel {
if (!VscodeLogger._outputChannel) {
- VscodeLogger._outputChannel = vscode.window.createOutputChannel('VBAPro Output');
- VscodeLogger._outputChannel.show();
+ VscodeLogger.initialiseOutputChannel();
}
return VscodeLogger._outputChannel;
}
+
private static get configuredLevel(): LogLevel {
const config = vscode.workspace.getConfiguration('vbaLanguageServer');
const levelString = config.get('logLevel.outputChannel', 'warning');
return LogLevel[levelString as keyof typeof LogLevel];
}
- static info = (msg: string, lvl?: number) => this.log(LogLevel.info, msg, lvl)
- static debug = (msg: string, lvl?: number) => this.log(LogLevel.debug, msg, lvl)
-
static logMessage(params: LogMessage): void {
this.log(params.type, params.message, params.level);
}
@@ -44,18 +42,26 @@ export class VscodeLogger {
VscodeLogger.outputChannel.appendLine(`${t} [${LogLevel[type]}] ${i}${msg}`);
}
+ private static initialiseOutputChannel(): void {
+ const channel = vscode.window.createOutputChannel('VBAPro Output');
+ if (isExtensionInDebugMode) {
+ channel.show();
+ }
+ VscodeLogger._outputChannel = channel;
+ }
+
private static getFormattedTimestamp(): string {
const now = new Date();
-
+
const year = now.getFullYear();
const month = (now.getMonth() + 1).toString().padStart(2, "0");
const day = now.getDate().toString().padStart(2, "0");
-
+
const hours = now.getHours().toString().padStart(2, "0");
const minutes = now.getMinutes().toString().padStart(2, "0");
const seconds = now.getSeconds().toString().padStart(2, "0");
const milliseconds = now.getMilliseconds().toString().padStart(3, "0");
-
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
}
}
diff --git a/client/src/test/codeActions.test.ts b/client/src/test/codeActions.test.ts
index 07c78b5..6412459 100644
--- a/client/src/test/codeActions.test.ts
+++ b/client/src/test/codeActions.test.ts
@@ -8,7 +8,7 @@ import * as assert from 'assert';
import { getDocUri, activate, runOnActivate } from './helper';
import { toRange } from './util';
-suite('Should get code actions', () => {
+suite('Should get module code actions', () => {
test('actions.module.missingOptionExplicitCodeAction', async () => {
const docUri = getDocUri('EmptyModule.bas');
const edits = new vscode.WorkspaceEdit();
diff --git a/client/src/test/diagnostics.test.ts b/client/src/test/diagnostics.test.ts
index 18f1ebf..203cddb 100644
--- a/client/src/test/diagnostics.test.ts
+++ b/client/src/test/diagnostics.test.ts
@@ -8,18 +8,12 @@ import * as assert from 'assert';
import { getDocUri, activate, runOnActivate } from './helper';
import { toRange } from './util';
-suite('Should get diagnostics', () => {
- test('diagnostics.class.missingNameAttributeError', async () => {
- await testDiagnostics(getDocUri('DiagnosticsMissingAttributeClass.cls'), [
- {
- message: 'Module missing attribute VB_NAME.',
- range: toRange(4, 3, 4, 3),
- severity: vscode.DiagnosticSeverity.Error,
- source: 'ex'
- }
- ]);
- });
+enum DiagnosticTag {
+ Unnecessary = 1,
+ Deprecated = 2
+}
+suite('Should get module diagnostics', () => {
test('diagnostics.module.missingNameAttributeError', async () => {
await testDiagnostics(getDocUri('DiagnosticsMissingAttributeModule.bas'), [
{
@@ -31,23 +25,12 @@ suite('Should get diagnostics', () => {
]);
});
- test('diagnostics.class.noOptionExplicitWarning', async () => {
- await testDiagnostics(getDocUri('EmptyClass.cls'), [
- {
- message: 'Option Explicit is missing from module header.',
- range: toRange(11, 1, 11, 1),
- severity: vscode.DiagnosticSeverity.Warning,
- source: 'ex'
- }
- ]);
- });
-
test('diagnostics.module.noOptionExplicitWarning', async () => {
await testDiagnostics(getDocUri('EmptyModule.bas'), [
{
message: 'Option Explicit is missing from module header.',
range: toRange(2, 1, 2, 1),
- severity: vscode.DiagnosticSeverity.Warning,
+ severity: vscode.DiagnosticSeverity.Hint,
source: 'ex'
}
]);
@@ -63,15 +46,15 @@ suite('Should get diagnostics', () => {
source: 'ex'
},
{
- message: 'Unknown attribute \'VB_Creatable\' will be ignored.',
+ message: 'Unknown attribute \'VB_Creatable\'.',
range: toRange(3, 0, 3, 30),
- severity: vscode.DiagnosticSeverity.Warning,
+ severity: vscode.DiagnosticSeverity.Error,
source: 'ex'
},
{
- message: 'Unknown attribute \'VB_Foo\' will be ignored.',
+ message: 'Unknown attribute \'VB_Foo\'.',
range: toRange(4, 0, 4, 24),
- severity: vscode.DiagnosticSeverity.Warning,
+ severity: vscode.DiagnosticSeverity.Error,
source: 'ex'
},
{
@@ -92,6 +75,27 @@ suite('Should get diagnostics', () => {
severity: vscode.DiagnosticSeverity.Error,
source: 'ex'
},
+ {
+ message: 'Enum1 is declared but its value is never read.',
+ range: toRange(29, 4, 29, 9),
+ severity: vscode.DiagnosticSeverity.Hint,
+ tags: [DiagnosticTag.Unnecessary],
+ source: 'ex'
+ },
+ {
+ message: 'Enum2 is declared but its value is never read.',
+ range: toRange(30, 4, 30, 9),
+ severity: vscode.DiagnosticSeverity.Hint,
+ tags: [DiagnosticTag.Unnecessary],
+ source: 'ex'
+ },
+ {
+ message: 'Enum3 is declared but its value is never read.',
+ range: toRange(31, 4, 31, 9),
+ severity: vscode.DiagnosticSeverity.Hint,
+ tags: [DiagnosticTag.Unnecessary],
+ source: 'ex'
+ },
{
message: 'Invalid syntax: InvalidSubCall(arg)',
range: toRange(43, 4, 43, 23),
@@ -100,6 +104,30 @@ suite('Should get diagnostics', () => {
}
]);
});
+});
+
+suite('Should get class diagnostics', () => {
+ test('diagnostics.class.missingNameAttributeError', async () => {
+ await testDiagnostics(getDocUri('DiagnosticsMissingAttributeClass.cls'), [
+ {
+ message: 'Module missing attribute VB_NAME.',
+ range: toRange(4, 3, 4, 3),
+ severity: vscode.DiagnosticSeverity.Error,
+ source: 'ex'
+ }
+ ]);
+ });
+
+ test('diagnostics.class.noOptionExplicitWarning', async () => {
+ await testDiagnostics(getDocUri('EmptyClass.cls'), [
+ {
+ message: 'Option Explicit is missing from module header.',
+ range: toRange(11, 1, 11, 1),
+ severity: vscode.DiagnosticSeverity.Hint,
+ source: 'ex'
+ }
+ ]);
+ });
test('diagnostics.class.generalDiagnostics', async () => {
// Don't seem to be able to sort these. Good luck!
@@ -117,15 +145,22 @@ suite('Should get diagnostics', () => {
source: 'ex'
},
{
- message: 'Unknown attribute \'VB_Exxposed\' will be ignored.',
+ message: 'Unknown attribute \'VB_Exxposed\'.',
range: toRange(12, 0, 12, 29),
- severity: vscode.DiagnosticSeverity.Warning,
+ severity: vscode.DiagnosticSeverity.Error,
source: 'ex'
},
{
- message: 'Unknown attribute \'VB_Exxposed\' will be ignored.',
+ message: 'Unknown attribute \'VB_Exxposed\'.',
range: toRange(13, 0, 13, 29),
- severity: vscode.DiagnosticSeverity.Warning,
+ severity: vscode.DiagnosticSeverity.Error,
+ source: 'ex'
+ },
+ {
+ message: 'SmkfeiondFoo is declared but its value is never read.',
+ range: toRange(17, 11, 17, 23),
+ severity: vscode.DiagnosticSeverity.Hint,
+ tags: [DiagnosticTag.Unnecessary],
source: 'ex'
},
{
@@ -140,11 +175,46 @@ suite('Should get diagnostics', () => {
severity: vscode.DiagnosticSeverity.Error,
source: 'ex'
},
+ {
+ message: 'GkiofseiFoo is declared but its value is never read.',
+ range: toRange(25, 4, 25, 15),
+ severity: vscode.DiagnosticSeverity.Hint,
+ tags: [DiagnosticTag.Unnecessary],
+ source: 'ex'
+ },
{
message: 'Enum declarations cannot appear below a Sub, Function, or Property declaration.',
range: toRange(37, 7, 41, 8),
severity: vscode.DiagnosticSeverity.Error,
source: 'ex'
+ },
+ {
+ message: 'PewmfoiawFoo is declared but its value is never read.',
+ range: toRange(37, 12, 37, 24),
+ severity: vscode.DiagnosticSeverity.Hint,
+ tags: [DiagnosticTag.Unnecessary],
+ source: 'ex'
+ },
+ {
+ message: 'Enum1 is declared but its value is never read.',
+ range: toRange(38, 4, 38, 9),
+ severity: vscode.DiagnosticSeverity.Hint,
+ tags: [DiagnosticTag.Unnecessary],
+ source: 'ex'
+ },
+ {
+ message: 'Enum2 is declared but its value is never read.',
+ range: toRange(39, 4, 39, 9),
+ severity: vscode.DiagnosticSeverity.Hint,
+ tags: [DiagnosticTag.Unnecessary],
+ source: 'ex'
+ },
+ {
+ message: 'Enum3 is declared but its value is never read.',
+ range: toRange(40, 4, 40, 9),
+ severity: vscode.DiagnosticSeverity.Hint,
+ tags: [DiagnosticTag.Unnecessary],
+ source: 'ex'
}
]);
});
@@ -165,5 +235,6 @@ async function testDiagnostics(docUri: vscode.Uri, expectedDiagnostics: vscode.D
assert.equal(actualDiagnostic.message, expectedDiagnostic.message, `Message: expected '${expectedDiagnostic.message}' got '${actualDiagnostic.message}'.`);
assert.deepEqual(actualDiagnostic.range, expectedDiagnostic.range, `Range: expected '${JSON.stringify(expectedDiagnostic.range)}' got '${JSON.stringify(actualDiagnostic.range)}'.`);
assert.equal(actualDiagnostic.severity, expectedDiagnostic.severity, `Severity: expected '${expectedDiagnostic.severity}' got '${actualDiagnostic.severity}'.`);
+ assert.deepEqual(actualDiagnostic.tags, expectedDiagnostic.tags, `Tags: expected '${JSON.stringify(expectedDiagnostic.tags)}' got '${JSON.stringify(actualDiagnostic.tags)}'.`);
});
}
\ No newline at end of file
diff --git a/client/src/test/foldingRanges.test.ts b/client/src/test/foldingRanges.test.ts
index 6b80841..835841e 100644
--- a/client/src/test/foldingRanges.test.ts
+++ b/client/src/test/foldingRanges.test.ts
@@ -2,7 +2,7 @@ import * as vscode from 'vscode';
import * as assert from 'assert';
import { getDocUri, activate, runOnActivate } from './helper';
-suite('Should get folding ranges', () => {
+suite('Should get class folding ranges', () => {
test('formatting.class.template', async () => {
const subFoo = {start: 23, end: 42};
const subBar = {start: 44, end: 58};
diff --git a/client/src/test/formatting.test.ts b/client/src/test/formatting.test.ts
index ce539d1..40443d4 100644
--- a/client/src/test/formatting.test.ts
+++ b/client/src/test/formatting.test.ts
@@ -3,7 +3,7 @@ import * as assert from 'assert';
import { getDocUri, activate, runOnActivate } from './helper';
import { toRange } from './util';
-suite('Should get text edits', () => {
+suite('Should get class text edits', () => {
test('formatting.class.template', async () => {
await testTextEdits(getDocUri('FormatTemplateClass.cls'), [
{range: toRange(3, 0, 3, 0), newText: ' '},
@@ -12,7 +12,9 @@ suite('Should get text edits', () => {
{range: toRange(8, 0, 8, 8), newText: ''}
]);
});
+});
+suite('Should get module text edits', () => {
test('formatting.module.directives', async () => {
await testTextEdits(getDocUri('FormatPrecompilerDirectives.bas'), [
// Staggered (half) indentation.
diff --git a/client/src/test/helper.ts b/client/src/test/helper.ts
index 8168979..7fca652 100644
--- a/client/src/test/helper.ts
+++ b/client/src/test/helper.ts
@@ -10,7 +10,7 @@ export let doc: vscode.TextDocument;
export let editor: vscode.TextEditor;
export let documentEol: string;
export let platformEol: string;
-const TIMEOUTMS = 5000;
+const TIMEOUTMS = 10000;
/**
* Activates the vscode.lsp-sample extension
@@ -35,10 +35,10 @@ async function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
-export async function runOnActivate(action: () => T|Thenable, test: (result: T) => boolean): Promise {
+export async function runOnActivate(action: () => T | Thenable, test: (result: T) => boolean): Promise {
const timeout = getTimeout();
while (Date.now() < timeout) {
- const result = await action();
+ const result = await action();
if (test(result)) {
return result;
}
diff --git a/icons/theme-seti/.vscodeignore b/icons/theme-seti/.vscodeignore
new file mode 100644
index 0000000..25699ef
--- /dev/null
+++ b/icons/theme-seti/.vscodeignore
@@ -0,0 +1,4 @@
+build/**
+cgmanifest.json
+icons/preview.html
+CONTRIBUTING.md
diff --git a/icons/theme-seti/README.md b/icons/theme-seti/README.md
new file mode 100644
index 0000000..2c4d721
--- /dev/null
+++ b/icons/theme-seti/README.md
@@ -0,0 +1,32 @@
+# theme-seti
+
+This is an icon theme that uses the icons from a fork of [`seti-ui`](https://github.com/jesseweed/seti-ui).
+
+## Updating icons
+
+There is script that can be used to update icons, [./build/update-icon-theme.js](build/update-icon-theme.js).
+
+To run this script, run `npm run update` from the `theme-seti` directory.
+
+This can be run in one of two ways: looking at a local copy of `seti-ui` for icons, or getting them straight from GitHub.
+
+If you want to run it from a local copy of `seti-ui`, first clone [`seti-ui`](https://github.com/jesseweed/seti-ui) to the folder next to your `vscode` repo (from the `theme-seti` directory, `../../`).
+Then, inside the `set-ui` directory, run `npm install` followed by `npm run prepublishOnly`. This will generate updated icons.
+
+If you want to download the icons straight from GitHub, change the `FROM_DISK` variable to `false` inside of `update-icon-theme.js`.
+
+### Languages not shipped with `vscode`
+
+Languages that are not shipped with `vscode` must be added to the `nonBuiltInLanguages` object inside of `update-icon-theme.js`.
+
+These should match [the file mapping in `seti-ui`](https://github.com/jesseweed/seti-ui/blob/master/styles/components/icons/mapping.less).
+
+Please try and keep this list in alphabetical order! Thank you.
+
+## Previewing icons
+
+There is a [`./icons/preview.html`](./icons/preview.html) file that can be opened to see all of the icons included in the theme.
+Note that to view this, it needs to be hosted by a web server.
+
+When updating icons, it is always a good idea to make sure that they work properly by looking at this page.
+When submitting a PR that updates these icons, a screenshot of the preview page should accompany it.
diff --git a/icons/theme-seti/ThirdPartyNotices.txt b/icons/theme-seti/ThirdPartyNotices.txt
new file mode 100644
index 0000000..6a495c8
--- /dev/null
+++ b/icons/theme-seti/ThirdPartyNotices.txt
@@ -0,0 +1,32 @@
+
+THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
+For VBA-LanguageServer vscode-theme-seti
+
+This theme is based on or incorporates material from the projects listed below ("Third Party OSS"). The original copyright
+notice and the license under which VBA-LanguageServer received such Third Party OSS, are set forth below. Such licenses and notice
+are provided for informational purposes only. VBA-LanguageServer licenses the Third Party OSS to you under the licensing terms for
+the VBA-LanguageServer product or service. VBA-LanguageServer reserves all other rights not expressly granted under this agreement, whether
+by implication, estoppel or otherwise.†
+
+1. Seti UI - A subtle dark colored UI theme for Atom. (https://github.com/jesseweed/seti-ui)
+
+Copyright (c) 2014 Jesse Weed
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/icons/theme-seti/build/update-icon-theme.js b/icons/theme-seti/build/update-icon-theme.js
new file mode 100644
index 0000000..bd7f518
--- /dev/null
+++ b/icons/theme-seti/build/update-icon-theme.js
@@ -0,0 +1,475 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+//@ts-nocheck
+
+'use strict';
+
+const path = require('path');
+const fs = require('fs');
+const https = require('https');
+const url = require('url');
+const minimatch = require('minimatch');
+
+// list of languagesId not shipped with VSCode. The information is used to associate an icon with a language association
+// Please try and keep this list in alphabetical order! Thank you.
+const nonBuiltInLanguages = { // { fileNames, extensions }
+ "argdown": { extensions: ['ad', 'adown', 'argdown', 'argdn'] },
+ "bicep": { extensions: ['bicep'] },
+ "elixir": { extensions: ['ex'] },
+ "elm": { extensions: ['elm'] },
+ "erb": { extensions: ['erb', 'rhtml', 'html.erb'] },
+ "github-issues": { extensions: ['github-issues'] },
+ "gradle": { extensions: ['gradle'] },
+ "godot": { extensions: ['gd', 'godot', 'tres', 'tscn'] },
+ "haml": { extensions: ['haml'] },
+ "haskell": { extensions: ['hs'] },
+ "haxe": { extensions: ['hx'] },
+ "jinja": { extensions: ['jinja'] },
+ "kotlin": { extensions: ['kt'] },
+ "mustache": { extensions: ['mustache', 'mst', 'mu', 'stache'] },
+ "nunjucks": { extensions: ['nunjucks', 'nunjs', 'nunj', 'nj', 'njk', 'tmpl', 'tpl'] },
+ "ocaml": { extensions: ['ml', 'mli', 'mll', 'mly', 'eliom', 'eliomi'] },
+ "puppet": { extensions: ['puppet'] },
+ "r": { extensions: ['r', 'rhistory', 'rprofile', 'rt'] },
+ "rescript": { extensions: ['res', 'resi'] },
+ "sass": { extensions: ['sass'] },
+ "stylus": { extensions: ['styl'] },
+ "terraform": { extensions: ['tf', 'tfvars', 'hcl'] },
+ "todo": { fileNames: ['todo'] },
+ "vala": { extensions: ['vala'] },
+ "vue": { extensions: ['vue'] }
+};
+
+// list of languagesId that inherit the icon from another language
+const inheritIconFromLanguage = {
+ "jsonc": 'json',
+ "jsonl": 'json',
+ "postcss": 'css',
+ "django-html": 'html',
+ "blade": 'php'
+};
+
+const ignoreExtAssociation = {
+ "properties": true
+};
+
+const FROM_DISK = false; // set to true to take content from a repo checked out next to the vscode repo
+
+let font, fontMappingsFile, fileAssociationFile, colorsFile;
+if (!FROM_DISK) {
+ font = 'https://raw.githubusercontent.com/DecimalTurn/seti-ui/vba/styles/_fonts/seti/seti.woff';
+ fontMappingsFile = 'https://raw.githubusercontent.com/DecimalTurn/seti-ui/vba/styles/_fonts/seti.less';
+ fileAssociationFile = 'https://raw.githubusercontent.com/DecimalTurn/seti-ui/vba/styles/components/icons/mapping.less';
+ colorsFile = 'https://raw.githubusercontent.com/DecimalTurn/seti-ui/vba/styles/ui-variables.less';
+} else {
+ font = '../../../seti-ui/styles/_fonts/seti/seti.woff';
+ fontMappingsFile = '../../../seti-ui/styles/_fonts/seti.less';
+ fileAssociationFile = '../../../seti-ui/styles/components/icons/mapping.less';
+ colorsFile = '../../../seti-ui/styles/ui-variables.less';
+}
+
+function getCommitSha(repoId) {
+ const commitInfo = 'https://api.github.com/repos/' + repoId + '/commits/vba';
+ return download(commitInfo).then(function (content) {
+ try {
+ const lastCommit = JSON.parse(content);
+ return Promise.resolve({
+ commitSha: lastCommit.sha,
+ commitDate: lastCommit.commit.author.date
+ });
+ } catch (e) {
+ console.error('Failed parsing ' + content);
+ return Promise.resolve(null);
+ }
+ }, function () {
+ console.error('Failed loading ' + commitInfo);
+ return Promise.resolve(null);
+ });
+}
+
+function download(source) {
+ if (source.startsWith('.')) {
+ return readFile(source);
+ }
+ return new Promise((c, e) => {
+ const _url = url.parse(source);
+ const options = { host: _url.host, port: _url.port, path: _url.path, headers: { 'User-Agent': 'NodeJS' } };
+ let content = '';
+ https.get(options, function (response) {
+ response.on('data', function (data) {
+ content += data.toString();
+ }).on('end', function () {
+ c(content);
+ });
+ }).on('error', function (err) {
+ e(err.message);
+ });
+ });
+}
+
+function readFile(fileName) {
+ return new Promise((c, e) => {
+ fs.readFile(fileName, function (err, data) {
+ if (err) {
+ e(err);
+ } else {
+ c(data.toString());
+ }
+ });
+ });
+}
+
+function downloadBinary(source, dest) {
+ if (source.startsWith('.')) {
+ return copyFile(source, dest);
+ }
+
+ return new Promise((c, e) => {
+ https.get(source, function (response) {
+ switch (response.statusCode) {
+ case 200: {
+ const file = fs.createWriteStream(dest);
+ response.on('data', function (chunk) {
+ file.write(chunk);
+ }).on('end', function () {
+ file.end();
+ c(null);
+ }).on('error', function (err) {
+ fs.unlink(dest);
+ e(err.message);
+ });
+ break;
+ }
+ case 301:
+ case 302:
+ case 303:
+ case 307:
+ console.log('redirect to ' + response.headers.location);
+ downloadBinary(response.headers.location, dest).then(c, e);
+ break;
+ default:
+ e(new Error('Server responded with status code ' + response.statusCode));
+ }
+ });
+ });
+}
+
+function copyFile(fileName, dest) {
+ return new Promise((c, e) => {
+ let cbCalled = false;
+ function handleError(err) {
+ if (!cbCalled) {
+ e(err);
+ cbCalled = true;
+ }
+ }
+ const rd = fs.createReadStream(fileName);
+ rd.on("error", handleError);
+ const wr = fs.createWriteStream(dest);
+ wr.on("error", handleError);
+ wr.on("close", function () {
+ if (!cbCalled) {
+ c();
+ cbCalled = true;
+ }
+ });
+ rd.pipe(wr);
+ });
+}
+
+function darkenColor(color) {
+ let res = '#';
+ for (let i = 1; i < 7; i += 2) {
+ const newVal = Math.round(parseInt('0x' + color.substr(i, 2), 16) * 0.9);
+ const hex = newVal.toString(16);
+ if (hex.length === 1) {
+ res += '0';
+ }
+ res += hex;
+ }
+ return res;
+}
+
+function mergeMapping(to, from, property) {
+ if (from[property]) {
+ if (to[property]) {
+ to[property].push(...from[property]);
+ } else {
+ to[property] = from[property];
+ }
+ }
+}
+
+function getLanguageMappings() {
+ const langMappings = {};
+ const allExtensions = fs.readdirSync('..');
+ for (let i = 0; i < allExtensions.length; i++) {
+ const dirPath = path.join('..', allExtensions[i], 'package.json');
+ if (fs.existsSync(dirPath)) {
+ const content = fs.readFileSync(dirPath).toString();
+ const jsonContent = JSON.parse(content);
+ const languages = jsonContent.contributes && jsonContent.contributes.languages;
+ if (Array.isArray(languages)) {
+ for (let k = 0; k < languages.length; k++) {
+ const languageId = languages[k].id;
+ if (languageId) {
+ const extensions = languages[k].extensions;
+ const mapping = {};
+ if (Array.isArray(extensions)) {
+ mapping.extensions = extensions.map(function (e) { return e.substr(1).toLowerCase(); });
+ }
+ const filenames = languages[k].filenames;
+ if (Array.isArray(filenames)) {
+ mapping.fileNames = filenames.map(function (f) { return f.toLowerCase(); });
+ }
+ const filenamePatterns = languages[k].filenamePatterns;
+ if (Array.isArray(filenamePatterns)) {
+ mapping.filenamePatterns = filenamePatterns.map(function (f) { return f.toLowerCase(); });
+ }
+ const existing = langMappings[languageId];
+
+ if (existing) {
+ // multiple contributions to the same language
+ // give preference to the contribution wth the configuration
+ if (languages[k].configuration) {
+ mergeMapping(mapping, existing, 'extensions');
+ mergeMapping(mapping, existing, 'fileNames');
+ mergeMapping(mapping, existing, 'filenamePatterns');
+ langMappings[languageId] = mapping;
+ } else {
+ mergeMapping(existing, mapping, 'extensions');
+ mergeMapping(existing, mapping, 'fileNames');
+ mergeMapping(existing, mapping, 'filenamePatterns');
+ }
+ } else {
+ langMappings[languageId] = mapping;
+ }
+ }
+ }
+ }
+ }
+ }
+ for (const languageId in nonBuiltInLanguages) {
+ langMappings[languageId] = nonBuiltInLanguages[languageId];
+ }
+ return langMappings;
+}
+
+exports.copyFont = function () {
+ return downloadBinary(font, './icons/seti.woff');
+};
+
+exports.update = function () {
+
+ console.log('Reading from ' + fontMappingsFile);
+ const def2Content = {};
+ const ext2Def = {};
+ const fileName2Def = {};
+ const def2ColorId = {};
+ const colorId2Value = {};
+ const lang2Def = {};
+
+ function writeFileIconContent(info) {
+ const iconDefinitions = {};
+ const allDefs = Object.keys(def2Content).sort();
+
+ for (let i = 0; i < allDefs.length; i++) {
+ const def = allDefs[i];
+ const entry = { fontCharacter: def2Content[def] };
+ const colorId = def2ColorId[def];
+ if (colorId) {
+ const colorValue = colorId2Value[colorId];
+ if (colorValue) {
+ entry.fontColor = colorValue;
+
+ const entryInverse = { fontCharacter: entry.fontCharacter, fontColor: darkenColor(colorValue) };
+ iconDefinitions[def + '_light'] = entryInverse;
+ }
+ }
+ iconDefinitions[def] = entry;
+ }
+
+ function getInvertSet(input) {
+ const result = {};
+ for (const assoc in input) {
+ const invertDef = input[assoc] + '_light';
+ if (iconDefinitions[invertDef]) {
+ result[assoc] = invertDef;
+ }
+ }
+ return result;
+ }
+
+ const res = {
+ information_for_contributors: [
+ 'This file has been generated from data in https://github.com/DecimalTurn/seti-ui',
+ '- icon definitions: https://github.com/DecimalTurn/seti-ui/blob/vba/styles/_fonts/seti.less',
+ '- icon colors: https://github.com/DecimalTurn/seti-ui/blob/vba/styles/ui-variables.less',
+ '- file associations: https://github.com/DecimalTurn/seti-ui/blob/vba/styles/components/icons/mapping.less',
+ 'If you want to provide a fix or improvement, please create a pull request against the DecimalTurn/seti-ui repository.',
+ 'Once accepted there, we are happy to receive an update request.',
+ ],
+ fonts: [{
+ id: "seti",
+ src: [{ "path": "./seti.woff", "format": "woff" }],
+ weight: "normal",
+ style: "normal",
+ size: "150%"
+ }],
+ iconDefinitions: iconDefinitions,
+ // folder: "_folder",
+ file: "_default",
+ fileExtensions: ext2Def,
+ fileNames: fileName2Def,
+ languageIds: lang2Def,
+ light: {
+ file: "_default_light",
+ fileExtensions: getInvertSet(ext2Def),
+ languageIds: getInvertSet(lang2Def),
+ fileNames: getInvertSet(fileName2Def)
+ },
+ version: 'https://github.com/DecimalTurn/seti-ui/commit/' + info.commitSha,
+ };
+
+ const path = './icons/vs-seti-icon-theme.json';
+ fs.writeFileSync(path, JSON.stringify(res, null, '\t'));
+ console.log('written ' + path);
+ }
+
+
+ let match;
+
+ return download(fontMappingsFile).then(function (content) {
+ const regex = /@([\w-]+):\s*'(\\E[0-9A-F]+)';/g;
+ const contents = {};
+ while ((match = regex.exec(content)) !== null) {
+ contents[match[1]] = match[2];
+ }
+
+ return download(fileAssociationFile).then(function (content) {
+ const regex2 = /\.icon-(?:set|partial)\(['"]([\w-\.+]+)['"],\s*['"]([\w-]+)['"],\s*(@[\w-]+)\)/g;
+ while ((match = regex2.exec(content)) !== null) {
+ const pattern = match[1];
+ let def = '_' + match[2];
+ const colorId = match[3];
+ let storedColorId = def2ColorId[def];
+ let i = 1;
+ while (storedColorId && colorId !== storedColorId) { // different colors for the same def?
+ def = `_${match[2]}_${i}`;
+ storedColorId = def2ColorId[def];
+ i++;
+ }
+ if (!def2ColorId[def]) {
+ def2ColorId[def] = colorId;
+ def2Content[def] = contents[match[2]];
+ }
+
+ if (def === '_default') {
+ continue; // no need to assign default color.
+ }
+ if (pattern[0] === '.') {
+ ext2Def[pattern.substr(1).toLowerCase()] = def;
+ } else {
+ fileName2Def[pattern.toLowerCase()] = def;
+ }
+ }
+ // replace extensions for languageId
+ const langMappings = getLanguageMappings();
+ for (let lang in langMappings) {
+ const mappings = langMappings[lang];
+ const exts = mappings.extensions || [];
+ const fileNames = mappings.fileNames || [];
+ const filenamePatterns = mappings.filenamePatterns || [];
+ let preferredDef = null;
+ // use the first file extension association for the preferred definition
+ for (let i1 = 0; i1 < exts.length && !preferredDef; i1++) {
+ preferredDef = ext2Def[exts[i1]];
+ }
+ // use the first file name association for the preferred definition, if not availbale
+ for (let i1 = 0; i1 < fileNames.length && !preferredDef; i1++) {
+ preferredDef = fileName2Def[fileNames[i1]];
+ }
+ for (let i1 = 0; i1 < filenamePatterns.length && !preferredDef; i1++) {
+ let pattern = filenamePatterns[i1];
+ for (const name in fileName2Def) {
+ if (minimatch(name, pattern)) {
+ preferredDef = fileName2Def[name];
+ break;
+ }
+ }
+ }
+ if (preferredDef) {
+ lang2Def[lang] = preferredDef;
+ if (!nonBuiltInLanguages[lang] && !inheritIconFromLanguage[lang]) {
+ for (let i2 = 0; i2 < exts.length; i2++) {
+ // remove the extension association, unless it is different from the preferred
+ if (ext2Def[exts[i2]] === preferredDef || ignoreExtAssociation[exts[i2]]) {
+ delete ext2Def[exts[i2]];
+ }
+ }
+ for (let i2 = 0; i2 < fileNames.length; i2++) {
+ // remove the fileName association, unless it is different from the preferred
+ if (fileName2Def[fileNames[i2]] === preferredDef) {
+ delete fileName2Def[fileNames[i2]];
+ }
+ }
+ for (let i2 = 0; i2 < filenamePatterns.length; i2++) {
+ let pattern = filenamePatterns[i2];
+ // remove the filenamePatterns association, unless it is different from the preferred
+ for (const name in fileName2Def) {
+ if (minimatch(name, pattern) && fileName2Def[name] === preferredDef) {
+ delete fileName2Def[name];
+ }
+ }
+ }
+ }
+ }
+ }
+ for (const lang in inheritIconFromLanguage) {
+ const superLang = inheritIconFromLanguage[lang];
+ const def = lang2Def[superLang];
+ if (def) {
+ lang2Def[lang] = def;
+ } else {
+ console.log('skipping icon def for ' + lang + ': no icon for ' + superLang + ' defined');
+ }
+
+ }
+
+
+ return download(colorsFile).then(function (content) {
+ const regex3 = /(@[\w-]+):\s*(#[0-9a-z]+)/g;
+ while ((match = regex3.exec(content)) !== null) {
+ colorId2Value[match[1]] = match[2];
+ }
+ return getCommitSha('DecimalTurn/seti-ui').then(function (info) {
+ try {
+ writeFileIconContent(info);
+
+ const cgmanifestPath = './cgmanifest.json';
+ const cgmanifest = fs.readFileSync(cgmanifestPath).toString();
+ const cgmanifestContent = JSON.parse(cgmanifest);
+ cgmanifestContent['registrations'][0]['component']['git']['commitHash'] = info.commitSha;
+ fs.writeFileSync(cgmanifestPath, JSON.stringify(cgmanifestContent, null, '\t'));
+ console.log('updated ' + cgmanifestPath);
+
+ console.log('Updated to DecimalTurn/seti-ui@' + info.commitSha.substr(0, 7) + ' (' + info.commitDate.substr(0, 10) + ')');
+
+ } catch (e) {
+ console.error(e);
+ }
+ });
+ });
+ });
+ }, console.error);
+};
+
+if (path.basename(process.argv[1]) === 'update-icon-theme.js') {
+ exports.copyFont().then(() => exports.update());
+}
+
+
+
diff --git a/icons/theme-seti/cgmanifest.json b/icons/theme-seti/cgmanifest.json
new file mode 100644
index 0000000..cd70a9f
--- /dev/null
+++ b/icons/theme-seti/cgmanifest.json
@@ -0,0 +1,16 @@
+{
+ "registrations": [
+ {
+ "component": {
+ "type": "git",
+ "git": {
+ "name": "seti-ui",
+ "repositoryUrl": "https://github.com/DecimalTurn/seti-ui",
+ "commitHash": "7a8d51ccb32737be812549fe1c31fae8276b284f"
+ }
+ },
+ "version": "0.1.0"
+ }
+ ],
+ "version": 1
+}
\ No newline at end of file
diff --git a/icons/theme-seti/icons/preview.html b/icons/theme-seti/icons/preview.html
new file mode 100644
index 0000000..84b5166
--- /dev/null
+++ b/icons/theme-seti/icons/preview.html
@@ -0,0 +1,104 @@
+
+
+
+
+
+ seti font preview
+
+
+
+
+
+
+
+
diff --git a/icons/theme-seti/icons/seti-circular-128x128.png b/icons/theme-seti/icons/seti-circular-128x128.png
new file mode 100644
index 0000000..fbe533b
Binary files /dev/null and b/icons/theme-seti/icons/seti-circular-128x128.png differ
diff --git a/icons/theme-seti/icons/seti.woff b/icons/theme-seti/icons/seti.woff
new file mode 100644
index 0000000..b20123e
Binary files /dev/null and b/icons/theme-seti/icons/seti.woff differ
diff --git a/icons/theme-seti/icons/vs-seti-icon-theme.json b/icons/theme-seti/icons/vs-seti-icon-theme.json
new file mode 100644
index 0000000..7a69ca3
--- /dev/null
+++ b/icons/theme-seti/icons/vs-seti-icon-theme.json
@@ -0,0 +1,2496 @@
+{
+ "information_for_contributors": [
+ "This file has been generated from data in https://github.com/DecimalTurn/seti-ui",
+ "- icon definitions: https://github.com/DecimalTurn/seti-ui/blob/vba/styles/_fonts/seti.less",
+ "- icon colors: https://github.com/DecimalTurn/seti-ui/blob/vba/styles/ui-variables.less",
+ "- file associations: https://github.com/DecimalTurn/seti-ui/blob/vba/styles/components/icons/mapping.less",
+ "If you want to provide a fix or improvement, please create a pull request against the DecimalTurn/seti-ui repository.",
+ "Once accepted there, we are happy to receive an update request."
+ ],
+ "fonts": [
+ {
+ "id": "seti",
+ "src": [
+ {
+ "path": "./seti.woff",
+ "format": "woff"
+ }
+ ],
+ "weight": "normal",
+ "style": "normal",
+ "size": "150%"
+ }
+ ],
+ "iconDefinitions": {
+ "_R_light": {
+ "fontCharacter": "\\E07B",
+ "fontColor": "#498ba7"
+ },
+ "_R": {
+ "fontCharacter": "\\E07B",
+ "fontColor": "#519aba"
+ },
+ "_argdown_light": {
+ "fontCharacter": "\\E002",
+ "fontColor": "#498ba7"
+ },
+ "_argdown": {
+ "fontCharacter": "\\E002",
+ "fontColor": "#519aba"
+ },
+ "_asm_light": {
+ "fontCharacter": "\\E003",
+ "fontColor": "#b8383d"
+ },
+ "_asm": {
+ "fontCharacter": "\\E003",
+ "fontColor": "#cc3e44"
+ },
+ "_audio_light": {
+ "fontCharacter": "\\E004",
+ "fontColor": "#9068b0"
+ },
+ "_audio": {
+ "fontCharacter": "\\E004",
+ "fontColor": "#a074c4"
+ },
+ "_babel_light": {
+ "fontCharacter": "\\E005",
+ "fontColor": "#b7b73b"
+ },
+ "_babel": {
+ "fontCharacter": "\\E005",
+ "fontColor": "#cbcb41"
+ },
+ "_bazel_light": {
+ "fontCharacter": "\\E006",
+ "fontColor": "#7fae42"
+ },
+ "_bazel": {
+ "fontCharacter": "\\E006",
+ "fontColor": "#8dc149"
+ },
+ "_bazel_1_light": {
+ "fontCharacter": "\\E006",
+ "fontColor": "#455155"
+ },
+ "_bazel_1": {
+ "fontCharacter": "\\E006",
+ "fontColor": "#4d5a5e"
+ },
+ "_bicep_light": {
+ "fontCharacter": "\\E007",
+ "fontColor": "#498ba7"
+ },
+ "_bicep": {
+ "fontCharacter": "\\E007",
+ "fontColor": "#519aba"
+ },
+ "_bower_light": {
+ "fontCharacter": "\\E008",
+ "fontColor": "#cc6d2e"
+ },
+ "_bower": {
+ "fontCharacter": "\\E008",
+ "fontColor": "#e37933"
+ },
+ "_bsl_light": {
+ "fontCharacter": "\\E009",
+ "fontColor": "#b8383d"
+ },
+ "_bsl": {
+ "fontCharacter": "\\E009",
+ "fontColor": "#cc3e44"
+ },
+ "_c_light": {
+ "fontCharacter": "\\E00B",
+ "fontColor": "#498ba7"
+ },
+ "_c": {
+ "fontCharacter": "\\E00B",
+ "fontColor": "#519aba"
+ },
+ "_c-sharp_light": {
+ "fontCharacter": "\\E00A",
+ "fontColor": "#498ba7"
+ },
+ "_c-sharp": {
+ "fontCharacter": "\\E00A",
+ "fontColor": "#519aba"
+ },
+ "_c_1_light": {
+ "fontCharacter": "\\E00B",
+ "fontColor": "#9068b0"
+ },
+ "_c_1": {
+ "fontCharacter": "\\E00B",
+ "fontColor": "#a074c4"
+ },
+ "_c_2_light": {
+ "fontCharacter": "\\E00B",
+ "fontColor": "#b7b73b"
+ },
+ "_c_2": {
+ "fontCharacter": "\\E00B",
+ "fontColor": "#cbcb41"
+ },
+ "_cake_light": {
+ "fontCharacter": "\\E00C",
+ "fontColor": "#b8383d"
+ },
+ "_cake": {
+ "fontCharacter": "\\E00C",
+ "fontColor": "#cc3e44"
+ },
+ "_cake_php_light": {
+ "fontCharacter": "\\E00D",
+ "fontColor": "#b8383d"
+ },
+ "_cake_php": {
+ "fontCharacter": "\\E00D",
+ "fontColor": "#cc3e44"
+ },
+ "_clock_light": {
+ "fontCharacter": "\\E011",
+ "fontColor": "#498ba7"
+ },
+ "_clock": {
+ "fontCharacter": "\\E011",
+ "fontColor": "#519aba"
+ },
+ "_clock_1_light": {
+ "fontCharacter": "\\E011",
+ "fontColor": "#627379"
+ },
+ "_clock_1": {
+ "fontCharacter": "\\E011",
+ "fontColor": "#6d8086"
+ },
+ "_clojure_light": {
+ "fontCharacter": "\\E012",
+ "fontColor": "#7fae42"
+ },
+ "_clojure": {
+ "fontCharacter": "\\E012",
+ "fontColor": "#8dc149"
+ },
+ "_clojure_1_light": {
+ "fontCharacter": "\\E012",
+ "fontColor": "#498ba7"
+ },
+ "_clojure_1": {
+ "fontCharacter": "\\E012",
+ "fontColor": "#519aba"
+ },
+ "_code-climate_light": {
+ "fontCharacter": "\\E013",
+ "fontColor": "#7fae42"
+ },
+ "_code-climate": {
+ "fontCharacter": "\\E013",
+ "fontColor": "#8dc149"
+ },
+ "_code-search_light": {
+ "fontCharacter": "\\E014",
+ "fontColor": "#9068b0"
+ },
+ "_code-search": {
+ "fontCharacter": "\\E014",
+ "fontColor": "#a074c4"
+ },
+ "_coffee_light": {
+ "fontCharacter": "\\E015",
+ "fontColor": "#b7b73b"
+ },
+ "_coffee": {
+ "fontCharacter": "\\E015",
+ "fontColor": "#cbcb41"
+ },
+ "_coldfusion_light": {
+ "fontCharacter": "\\E017",
+ "fontColor": "#498ba7"
+ },
+ "_coldfusion": {
+ "fontCharacter": "\\E017",
+ "fontColor": "#519aba"
+ },
+ "_config_light": {
+ "fontCharacter": "\\E018",
+ "fontColor": "#627379"
+ },
+ "_config": {
+ "fontCharacter": "\\E018",
+ "fontColor": "#6d8086"
+ },
+ "_cpp_light": {
+ "fontCharacter": "\\E019",
+ "fontColor": "#498ba7"
+ },
+ "_cpp": {
+ "fontCharacter": "\\E019",
+ "fontColor": "#519aba"
+ },
+ "_cpp_1_light": {
+ "fontCharacter": "\\E019",
+ "fontColor": "#9068b0"
+ },
+ "_cpp_1": {
+ "fontCharacter": "\\E019",
+ "fontColor": "#a074c4"
+ },
+ "_cpp_2_light": {
+ "fontCharacter": "\\E019",
+ "fontColor": "#b7b73b"
+ },
+ "_cpp_2": {
+ "fontCharacter": "\\E019",
+ "fontColor": "#cbcb41"
+ },
+ "_crystal_light": {
+ "fontCharacter": "\\E01A",
+ "fontColor": "#bfc2c1"
+ },
+ "_crystal": {
+ "fontCharacter": "\\E01A",
+ "fontColor": "#d4d7d6"
+ },
+ "_crystal_embedded_light": {
+ "fontCharacter": "\\E01B",
+ "fontColor": "#bfc2c1"
+ },
+ "_crystal_embedded": {
+ "fontCharacter": "\\E01B",
+ "fontColor": "#d4d7d6"
+ },
+ "_css_light": {
+ "fontCharacter": "\\E01C",
+ "fontColor": "#498ba7"
+ },
+ "_css": {
+ "fontCharacter": "\\E01C",
+ "fontColor": "#519aba"
+ },
+ "_csv_light": {
+ "fontCharacter": "\\E01D",
+ "fontColor": "#7fae42"
+ },
+ "_csv": {
+ "fontCharacter": "\\E01D",
+ "fontColor": "#8dc149"
+ },
+ "_cu_light": {
+ "fontCharacter": "\\E01E",
+ "fontColor": "#7fae42"
+ },
+ "_cu": {
+ "fontCharacter": "\\E01E",
+ "fontColor": "#8dc149"
+ },
+ "_cu_1_light": {
+ "fontCharacter": "\\E01E",
+ "fontColor": "#9068b0"
+ },
+ "_cu_1": {
+ "fontCharacter": "\\E01E",
+ "fontColor": "#a074c4"
+ },
+ "_d_light": {
+ "fontCharacter": "\\E01F",
+ "fontColor": "#b8383d"
+ },
+ "_d": {
+ "fontCharacter": "\\E01F",
+ "fontColor": "#cc3e44"
+ },
+ "_dart_light": {
+ "fontCharacter": "\\E020",
+ "fontColor": "#498ba7"
+ },
+ "_dart": {
+ "fontCharacter": "\\E020",
+ "fontColor": "#519aba"
+ },
+ "_db_light": {
+ "fontCharacter": "\\E021",
+ "fontColor": "#dd4b78"
+ },
+ "_db": {
+ "fontCharacter": "\\E021",
+ "fontColor": "#f55385"
+ },
+ "_db_1_light": {
+ "fontCharacter": "\\E021",
+ "fontColor": "#498ba7"
+ },
+ "_db_1": {
+ "fontCharacter": "\\E021",
+ "fontColor": "#519aba"
+ },
+ "_default_light": {
+ "fontCharacter": "\\E022",
+ "fontColor": "#bfc2c1"
+ },
+ "_default": {
+ "fontCharacter": "\\E022",
+ "fontColor": "#d4d7d6"
+ },
+ "_docker_light": {
+ "fontCharacter": "\\E024",
+ "fontColor": "#498ba7"
+ },
+ "_docker": {
+ "fontCharacter": "\\E024",
+ "fontColor": "#519aba"
+ },
+ "_docker_1_light": {
+ "fontCharacter": "\\E024",
+ "fontColor": "#455155"
+ },
+ "_docker_1": {
+ "fontCharacter": "\\E024",
+ "fontColor": "#4d5a5e"
+ },
+ "_docker_2_light": {
+ "fontCharacter": "\\E024",
+ "fontColor": "#7fae42"
+ },
+ "_docker_2": {
+ "fontCharacter": "\\E024",
+ "fontColor": "#8dc149"
+ },
+ "_docker_3_light": {
+ "fontCharacter": "\\E024",
+ "fontColor": "#dd4b78"
+ },
+ "_docker_3": {
+ "fontCharacter": "\\E024",
+ "fontColor": "#f55385"
+ },
+ "_ejs_light": {
+ "fontCharacter": "\\E026",
+ "fontColor": "#b7b73b"
+ },
+ "_ejs": {
+ "fontCharacter": "\\E026",
+ "fontColor": "#cbcb41"
+ },
+ "_elixir_light": {
+ "fontCharacter": "\\E027",
+ "fontColor": "#9068b0"
+ },
+ "_elixir": {
+ "fontCharacter": "\\E027",
+ "fontColor": "#a074c4"
+ },
+ "_elixir_script_light": {
+ "fontCharacter": "\\E028",
+ "fontColor": "#9068b0"
+ },
+ "_elixir_script": {
+ "fontCharacter": "\\E028",
+ "fontColor": "#a074c4"
+ },
+ "_elm_light": {
+ "fontCharacter": "\\E029",
+ "fontColor": "#498ba7"
+ },
+ "_elm": {
+ "fontCharacter": "\\E029",
+ "fontColor": "#519aba"
+ },
+ "_eslint_light": {
+ "fontCharacter": "\\E02B",
+ "fontColor": "#9068b0"
+ },
+ "_eslint": {
+ "fontCharacter": "\\E02B",
+ "fontColor": "#a074c4"
+ },
+ "_eslint_1_light": {
+ "fontCharacter": "\\E02B",
+ "fontColor": "#455155"
+ },
+ "_eslint_1": {
+ "fontCharacter": "\\E02B",
+ "fontColor": "#4d5a5e"
+ },
+ "_ethereum_light": {
+ "fontCharacter": "\\E02C",
+ "fontColor": "#498ba7"
+ },
+ "_ethereum": {
+ "fontCharacter": "\\E02C",
+ "fontColor": "#519aba"
+ },
+ "_f-sharp_light": {
+ "fontCharacter": "\\E02D",
+ "fontColor": "#498ba7"
+ },
+ "_f-sharp": {
+ "fontCharacter": "\\E02D",
+ "fontColor": "#519aba"
+ },
+ "_favicon_light": {
+ "fontCharacter": "\\E02E",
+ "fontColor": "#b7b73b"
+ },
+ "_favicon": {
+ "fontCharacter": "\\E02E",
+ "fontColor": "#cbcb41"
+ },
+ "_firebase_light": {
+ "fontCharacter": "\\E02F",
+ "fontColor": "#cc6d2e"
+ },
+ "_firebase": {
+ "fontCharacter": "\\E02F",
+ "fontColor": "#e37933"
+ },
+ "_firefox_light": {
+ "fontCharacter": "\\E030",
+ "fontColor": "#cc6d2e"
+ },
+ "_firefox": {
+ "fontCharacter": "\\E030",
+ "fontColor": "#e37933"
+ },
+ "_font_light": {
+ "fontCharacter": "\\E032",
+ "fontColor": "#b8383d"
+ },
+ "_font": {
+ "fontCharacter": "\\E032",
+ "fontColor": "#cc3e44"
+ },
+ "_git_light": {
+ "fontCharacter": "\\E033",
+ "fontColor": "#3b4b52"
+ },
+ "_git": {
+ "fontCharacter": "\\E033",
+ "fontColor": "#41535b"
+ },
+ "_github_light": {
+ "fontCharacter": "\\E034",
+ "fontColor": "#bfc2c1"
+ },
+ "_github": {
+ "fontCharacter": "\\E034",
+ "fontColor": "#d4d7d6"
+ },
+ "_gitlab_light": {
+ "fontCharacter": "\\E035",
+ "fontColor": "#cc6d2e"
+ },
+ "_gitlab": {
+ "fontCharacter": "\\E035",
+ "fontColor": "#e37933"
+ },
+ "_go_light": {
+ "fontCharacter": "\\E038",
+ "fontColor": "#498ba7"
+ },
+ "_go": {
+ "fontCharacter": "\\E038",
+ "fontColor": "#519aba"
+ },
+ "_go2_light": {
+ "fontCharacter": "\\E039",
+ "fontColor": "#498ba7"
+ },
+ "_go2": {
+ "fontCharacter": "\\E039",
+ "fontColor": "#519aba"
+ },
+ "_godot_light": {
+ "fontCharacter": "\\E03A",
+ "fontColor": "#498ba7"
+ },
+ "_godot": {
+ "fontCharacter": "\\E03A",
+ "fontColor": "#519aba"
+ },
+ "_godot_1_light": {
+ "fontCharacter": "\\E03A",
+ "fontColor": "#b8383d"
+ },
+ "_godot_1": {
+ "fontCharacter": "\\E03A",
+ "fontColor": "#cc3e44"
+ },
+ "_godot_2_light": {
+ "fontCharacter": "\\E03A",
+ "fontColor": "#b7b73b"
+ },
+ "_godot_2": {
+ "fontCharacter": "\\E03A",
+ "fontColor": "#cbcb41"
+ },
+ "_godot_3_light": {
+ "fontCharacter": "\\E03A",
+ "fontColor": "#9068b0"
+ },
+ "_godot_3": {
+ "fontCharacter": "\\E03A",
+ "fontColor": "#a074c4"
+ },
+ "_gradle_light": {
+ "fontCharacter": "\\E03B",
+ "fontColor": "#498ba7"
+ },
+ "_gradle": {
+ "fontCharacter": "\\E03B",
+ "fontColor": "#519aba"
+ },
+ "_grails_light": {
+ "fontCharacter": "\\E03C",
+ "fontColor": "#7fae42"
+ },
+ "_grails": {
+ "fontCharacter": "\\E03C",
+ "fontColor": "#8dc149"
+ },
+ "_graphql_light": {
+ "fontCharacter": "\\E03D",
+ "fontColor": "#dd4b78"
+ },
+ "_graphql": {
+ "fontCharacter": "\\E03D",
+ "fontColor": "#f55385"
+ },
+ "_grunt_light": {
+ "fontCharacter": "\\E03E",
+ "fontColor": "#cc6d2e"
+ },
+ "_grunt": {
+ "fontCharacter": "\\E03E",
+ "fontColor": "#e37933"
+ },
+ "_gulp_light": {
+ "fontCharacter": "\\E03F",
+ "fontColor": "#b8383d"
+ },
+ "_gulp": {
+ "fontCharacter": "\\E03F",
+ "fontColor": "#cc3e44"
+ },
+ "_hacklang_light": {
+ "fontCharacter": "\\E040",
+ "fontColor": "#cc6d2e"
+ },
+ "_hacklang": {
+ "fontCharacter": "\\E040",
+ "fontColor": "#e37933"
+ },
+ "_haml_light": {
+ "fontCharacter": "\\E041",
+ "fontColor": "#b8383d"
+ },
+ "_haml": {
+ "fontCharacter": "\\E041",
+ "fontColor": "#cc3e44"
+ },
+ "_happenings_light": {
+ "fontCharacter": "\\E042",
+ "fontColor": "#498ba7"
+ },
+ "_happenings": {
+ "fontCharacter": "\\E042",
+ "fontColor": "#519aba"
+ },
+ "_haskell_light": {
+ "fontCharacter": "\\E043",
+ "fontColor": "#9068b0"
+ },
+ "_haskell": {
+ "fontCharacter": "\\E043",
+ "fontColor": "#a074c4"
+ },
+ "_haxe_light": {
+ "fontCharacter": "\\E044",
+ "fontColor": "#cc6d2e"
+ },
+ "_haxe": {
+ "fontCharacter": "\\E044",
+ "fontColor": "#e37933"
+ },
+ "_haxe_1_light": {
+ "fontCharacter": "\\E044",
+ "fontColor": "#b7b73b"
+ },
+ "_haxe_1": {
+ "fontCharacter": "\\E044",
+ "fontColor": "#cbcb41"
+ },
+ "_haxe_2_light": {
+ "fontCharacter": "\\E044",
+ "fontColor": "#498ba7"
+ },
+ "_haxe_2": {
+ "fontCharacter": "\\E044",
+ "fontColor": "#519aba"
+ },
+ "_haxe_3_light": {
+ "fontCharacter": "\\E044",
+ "fontColor": "#9068b0"
+ },
+ "_haxe_3": {
+ "fontCharacter": "\\E044",
+ "fontColor": "#a074c4"
+ },
+ "_heroku_light": {
+ "fontCharacter": "\\E045",
+ "fontColor": "#9068b0"
+ },
+ "_heroku": {
+ "fontCharacter": "\\E045",
+ "fontColor": "#a074c4"
+ },
+ "_hex_light": {
+ "fontCharacter": "\\E046",
+ "fontColor": "#b8383d"
+ },
+ "_hex": {
+ "fontCharacter": "\\E046",
+ "fontColor": "#cc3e44"
+ },
+ "_html_light": {
+ "fontCharacter": "\\E047",
+ "fontColor": "#498ba7"
+ },
+ "_html": {
+ "fontCharacter": "\\E047",
+ "fontColor": "#519aba"
+ },
+ "_html_1_light": {
+ "fontCharacter": "\\E047",
+ "fontColor": "#7fae42"
+ },
+ "_html_1": {
+ "fontCharacter": "\\E047",
+ "fontColor": "#8dc149"
+ },
+ "_html_2_light": {
+ "fontCharacter": "\\E047",
+ "fontColor": "#b7b73b"
+ },
+ "_html_2": {
+ "fontCharacter": "\\E047",
+ "fontColor": "#cbcb41"
+ },
+ "_html_3_light": {
+ "fontCharacter": "\\E047",
+ "fontColor": "#cc6d2e"
+ },
+ "_html_3": {
+ "fontCharacter": "\\E047",
+ "fontColor": "#e37933"
+ },
+ "_html_erb_light": {
+ "fontCharacter": "\\E048",
+ "fontColor": "#b8383d"
+ },
+ "_html_erb": {
+ "fontCharacter": "\\E048",
+ "fontColor": "#cc3e44"
+ },
+ "_ignored_light": {
+ "fontCharacter": "\\E049",
+ "fontColor": "#3b4b52"
+ },
+ "_ignored": {
+ "fontCharacter": "\\E049",
+ "fontColor": "#41535b"
+ },
+ "_illustrator_light": {
+ "fontCharacter": "\\E04A",
+ "fontColor": "#b7b73b"
+ },
+ "_illustrator": {
+ "fontCharacter": "\\E04A",
+ "fontColor": "#cbcb41"
+ },
+ "_image_light": {
+ "fontCharacter": "\\E04B",
+ "fontColor": "#9068b0"
+ },
+ "_image": {
+ "fontCharacter": "\\E04B",
+ "fontColor": "#a074c4"
+ },
+ "_info_light": {
+ "fontCharacter": "\\E04C",
+ "fontColor": "#498ba7"
+ },
+ "_info": {
+ "fontCharacter": "\\E04C",
+ "fontColor": "#519aba"
+ },
+ "_ionic_light": {
+ "fontCharacter": "\\E04D",
+ "fontColor": "#498ba7"
+ },
+ "_ionic": {
+ "fontCharacter": "\\E04D",
+ "fontColor": "#519aba"
+ },
+ "_jade_light": {
+ "fontCharacter": "\\E04E",
+ "fontColor": "#b8383d"
+ },
+ "_jade": {
+ "fontCharacter": "\\E04E",
+ "fontColor": "#cc3e44"
+ },
+ "_java_light": {
+ "fontCharacter": "\\E04F",
+ "fontColor": "#b8383d"
+ },
+ "_java": {
+ "fontCharacter": "\\E04F",
+ "fontColor": "#cc3e44"
+ },
+ "_java_1_light": {
+ "fontCharacter": "\\E04F",
+ "fontColor": "#498ba7"
+ },
+ "_java_1": {
+ "fontCharacter": "\\E04F",
+ "fontColor": "#519aba"
+ },
+ "_javascript_light": {
+ "fontCharacter": "\\E050",
+ "fontColor": "#b7b73b"
+ },
+ "_javascript": {
+ "fontCharacter": "\\E050",
+ "fontColor": "#cbcb41"
+ },
+ "_javascript_1_light": {
+ "fontCharacter": "\\E050",
+ "fontColor": "#cc6d2e"
+ },
+ "_javascript_1": {
+ "fontCharacter": "\\E050",
+ "fontColor": "#e37933"
+ },
+ "_javascript_2_light": {
+ "fontCharacter": "\\E050",
+ "fontColor": "#498ba7"
+ },
+ "_javascript_2": {
+ "fontCharacter": "\\E050",
+ "fontColor": "#519aba"
+ },
+ "_jenkins_light": {
+ "fontCharacter": "\\E051",
+ "fontColor": "#b8383d"
+ },
+ "_jenkins": {
+ "fontCharacter": "\\E051",
+ "fontColor": "#cc3e44"
+ },
+ "_jinja_light": {
+ "fontCharacter": "\\E052",
+ "fontColor": "#b8383d"
+ },
+ "_jinja": {
+ "fontCharacter": "\\E052",
+ "fontColor": "#cc3e44"
+ },
+ "_json_light": {
+ "fontCharacter": "\\E053",
+ "fontColor": "#b7b73b"
+ },
+ "_json": {
+ "fontCharacter": "\\E053",
+ "fontColor": "#cbcb41"
+ },
+ "_json_1_light": {
+ "fontCharacter": "\\E053",
+ "fontColor": "#7fae42"
+ },
+ "_json_1": {
+ "fontCharacter": "\\E053",
+ "fontColor": "#8dc149"
+ },
+ "_julia_light": {
+ "fontCharacter": "\\E055",
+ "fontColor": "#9068b0"
+ },
+ "_julia": {
+ "fontCharacter": "\\E055",
+ "fontColor": "#a074c4"
+ },
+ "_karma_light": {
+ "fontCharacter": "\\E056",
+ "fontColor": "#7fae42"
+ },
+ "_karma": {
+ "fontCharacter": "\\E056",
+ "fontColor": "#8dc149"
+ },
+ "_kotlin_light": {
+ "fontCharacter": "\\E057",
+ "fontColor": "#cc6d2e"
+ },
+ "_kotlin": {
+ "fontCharacter": "\\E057",
+ "fontColor": "#e37933"
+ },
+ "_less_light": {
+ "fontCharacter": "\\E058",
+ "fontColor": "#498ba7"
+ },
+ "_less": {
+ "fontCharacter": "\\E058",
+ "fontColor": "#519aba"
+ },
+ "_license_light": {
+ "fontCharacter": "\\E059",
+ "fontColor": "#b7b73b"
+ },
+ "_license": {
+ "fontCharacter": "\\E059",
+ "fontColor": "#cbcb41"
+ },
+ "_license_1_light": {
+ "fontCharacter": "\\E059",
+ "fontColor": "#cc6d2e"
+ },
+ "_license_1": {
+ "fontCharacter": "\\E059",
+ "fontColor": "#e37933"
+ },
+ "_license_2_light": {
+ "fontCharacter": "\\E059",
+ "fontColor": "#b8383d"
+ },
+ "_license_2": {
+ "fontCharacter": "\\E059",
+ "fontColor": "#cc3e44"
+ },
+ "_liquid_light": {
+ "fontCharacter": "\\E05A",
+ "fontColor": "#7fae42"
+ },
+ "_liquid": {
+ "fontCharacter": "\\E05A",
+ "fontColor": "#8dc149"
+ },
+ "_livescript_light": {
+ "fontCharacter": "\\E05B",
+ "fontColor": "#498ba7"
+ },
+ "_livescript": {
+ "fontCharacter": "\\E05B",
+ "fontColor": "#519aba"
+ },
+ "_lock_light": {
+ "fontCharacter": "\\E05C",
+ "fontColor": "#7fae42"
+ },
+ "_lock": {
+ "fontCharacter": "\\E05C",
+ "fontColor": "#8dc149"
+ },
+ "_lua_light": {
+ "fontCharacter": "\\E05D",
+ "fontColor": "#498ba7"
+ },
+ "_lua": {
+ "fontCharacter": "\\E05D",
+ "fontColor": "#519aba"
+ },
+ "_makefile_light": {
+ "fontCharacter": "\\E05E",
+ "fontColor": "#cc6d2e"
+ },
+ "_makefile": {
+ "fontCharacter": "\\E05E",
+ "fontColor": "#e37933"
+ },
+ "_makefile_1_light": {
+ "fontCharacter": "\\E05E",
+ "fontColor": "#9068b0"
+ },
+ "_makefile_1": {
+ "fontCharacter": "\\E05E",
+ "fontColor": "#a074c4"
+ },
+ "_makefile_2_light": {
+ "fontCharacter": "\\E05E",
+ "fontColor": "#627379"
+ },
+ "_makefile_2": {
+ "fontCharacter": "\\E05E",
+ "fontColor": "#6d8086"
+ },
+ "_makefile_3_light": {
+ "fontCharacter": "\\E05E",
+ "fontColor": "#498ba7"
+ },
+ "_makefile_3": {
+ "fontCharacter": "\\E05E",
+ "fontColor": "#519aba"
+ },
+ "_markdown_light": {
+ "fontCharacter": "\\E05F",
+ "fontColor": "#498ba7"
+ },
+ "_markdown": {
+ "fontCharacter": "\\E05F",
+ "fontColor": "#519aba"
+ },
+ "_maven_light": {
+ "fontCharacter": "\\E060",
+ "fontColor": "#b8383d"
+ },
+ "_maven": {
+ "fontCharacter": "\\E060",
+ "fontColor": "#cc3e44"
+ },
+ "_mdo_light": {
+ "fontCharacter": "\\E061",
+ "fontColor": "#b8383d"
+ },
+ "_mdo": {
+ "fontCharacter": "\\E061",
+ "fontColor": "#cc3e44"
+ },
+ "_mustache_light": {
+ "fontCharacter": "\\E062",
+ "fontColor": "#cc6d2e"
+ },
+ "_mustache": {
+ "fontCharacter": "\\E062",
+ "fontColor": "#e37933"
+ },
+ "_nim_light": {
+ "fontCharacter": "\\E064",
+ "fontColor": "#b7b73b"
+ },
+ "_nim": {
+ "fontCharacter": "\\E064",
+ "fontColor": "#cbcb41"
+ },
+ "_notebook_light": {
+ "fontCharacter": "\\E065",
+ "fontColor": "#498ba7"
+ },
+ "_notebook": {
+ "fontCharacter": "\\E065",
+ "fontColor": "#519aba"
+ },
+ "_npm_light": {
+ "fontCharacter": "\\E066",
+ "fontColor": "#3b4b52"
+ },
+ "_npm": {
+ "fontCharacter": "\\E066",
+ "fontColor": "#41535b"
+ },
+ "_npm_1_light": {
+ "fontCharacter": "\\E066",
+ "fontColor": "#b8383d"
+ },
+ "_npm_1": {
+ "fontCharacter": "\\E066",
+ "fontColor": "#cc3e44"
+ },
+ "_npm_ignored_light": {
+ "fontCharacter": "\\E067",
+ "fontColor": "#3b4b52"
+ },
+ "_npm_ignored": {
+ "fontCharacter": "\\E067",
+ "fontColor": "#41535b"
+ },
+ "_nunjucks_light": {
+ "fontCharacter": "\\E068",
+ "fontColor": "#7fae42"
+ },
+ "_nunjucks": {
+ "fontCharacter": "\\E068",
+ "fontColor": "#8dc149"
+ },
+ "_ocaml_light": {
+ "fontCharacter": "\\E069",
+ "fontColor": "#cc6d2e"
+ },
+ "_ocaml": {
+ "fontCharacter": "\\E069",
+ "fontColor": "#e37933"
+ },
+ "_odata_light": {
+ "fontCharacter": "\\E06A",
+ "fontColor": "#cc6d2e"
+ },
+ "_odata": {
+ "fontCharacter": "\\E06A",
+ "fontColor": "#e37933"
+ },
+ "_pddl_light": {
+ "fontCharacter": "\\E06B",
+ "fontColor": "#9068b0"
+ },
+ "_pddl": {
+ "fontCharacter": "\\E06B",
+ "fontColor": "#a074c4"
+ },
+ "_pdf_light": {
+ "fontCharacter": "\\E06C",
+ "fontColor": "#b8383d"
+ },
+ "_pdf": {
+ "fontCharacter": "\\E06C",
+ "fontColor": "#cc3e44"
+ },
+ "_perl_light": {
+ "fontCharacter": "\\E06D",
+ "fontColor": "#498ba7"
+ },
+ "_perl": {
+ "fontCharacter": "\\E06D",
+ "fontColor": "#519aba"
+ },
+ "_photoshop_light": {
+ "fontCharacter": "\\E06E",
+ "fontColor": "#498ba7"
+ },
+ "_photoshop": {
+ "fontCharacter": "\\E06E",
+ "fontColor": "#519aba"
+ },
+ "_php_light": {
+ "fontCharacter": "\\E06F",
+ "fontColor": "#9068b0"
+ },
+ "_php": {
+ "fontCharacter": "\\E06F",
+ "fontColor": "#a074c4"
+ },
+ "_pipeline_light": {
+ "fontCharacter": "\\E070",
+ "fontColor": "#cc6d2e"
+ },
+ "_pipeline": {
+ "fontCharacter": "\\E070",
+ "fontColor": "#e37933"
+ },
+ "_plan_light": {
+ "fontCharacter": "\\E071",
+ "fontColor": "#7fae42"
+ },
+ "_plan": {
+ "fontCharacter": "\\E071",
+ "fontColor": "#8dc149"
+ },
+ "_platformio_light": {
+ "fontCharacter": "\\E072",
+ "fontColor": "#cc6d2e"
+ },
+ "_platformio": {
+ "fontCharacter": "\\E072",
+ "fontColor": "#e37933"
+ },
+ "_powershell_light": {
+ "fontCharacter": "\\E073",
+ "fontColor": "#498ba7"
+ },
+ "_powershell": {
+ "fontCharacter": "\\E073",
+ "fontColor": "#519aba"
+ },
+ "_prisma_light": {
+ "fontCharacter": "\\E074",
+ "fontColor": "#498ba7"
+ },
+ "_prisma": {
+ "fontCharacter": "\\E074",
+ "fontColor": "#519aba"
+ },
+ "_prolog_light": {
+ "fontCharacter": "\\E076",
+ "fontColor": "#cc6d2e"
+ },
+ "_prolog": {
+ "fontCharacter": "\\E076",
+ "fontColor": "#e37933"
+ },
+ "_pug_light": {
+ "fontCharacter": "\\E077",
+ "fontColor": "#b8383d"
+ },
+ "_pug": {
+ "fontCharacter": "\\E077",
+ "fontColor": "#cc3e44"
+ },
+ "_puppet_light": {
+ "fontCharacter": "\\E078",
+ "fontColor": "#b7b73b"
+ },
+ "_puppet": {
+ "fontCharacter": "\\E078",
+ "fontColor": "#cbcb41"
+ },
+ "_purescript_light": {
+ "fontCharacter": "\\E079",
+ "fontColor": "#bfc2c1"
+ },
+ "_purescript": {
+ "fontCharacter": "\\E079",
+ "fontColor": "#d4d7d6"
+ },
+ "_python_light": {
+ "fontCharacter": "\\E07A",
+ "fontColor": "#498ba7"
+ },
+ "_python": {
+ "fontCharacter": "\\E07A",
+ "fontColor": "#519aba"
+ },
+ "_react_light": {
+ "fontCharacter": "\\E07D",
+ "fontColor": "#498ba7"
+ },
+ "_react": {
+ "fontCharacter": "\\E07D",
+ "fontColor": "#519aba"
+ },
+ "_react_1_light": {
+ "fontCharacter": "\\E07D",
+ "fontColor": "#cc6d2e"
+ },
+ "_react_1": {
+ "fontCharacter": "\\E07D",
+ "fontColor": "#e37933"
+ },
+ "_reasonml_light": {
+ "fontCharacter": "\\E07E",
+ "fontColor": "#b8383d"
+ },
+ "_reasonml": {
+ "fontCharacter": "\\E07E",
+ "fontColor": "#cc3e44"
+ },
+ "_rescript_light": {
+ "fontCharacter": "\\E07F",
+ "fontColor": "#b8383d"
+ },
+ "_rescript": {
+ "fontCharacter": "\\E07F",
+ "fontColor": "#cc3e44"
+ },
+ "_rescript_1_light": {
+ "fontCharacter": "\\E07F",
+ "fontColor": "#dd4b78"
+ },
+ "_rescript_1": {
+ "fontCharacter": "\\E07F",
+ "fontColor": "#f55385"
+ },
+ "_rollup_light": {
+ "fontCharacter": "\\E080",
+ "fontColor": "#b8383d"
+ },
+ "_rollup": {
+ "fontCharacter": "\\E080",
+ "fontColor": "#cc3e44"
+ },
+ "_ruby_light": {
+ "fontCharacter": "\\E081",
+ "fontColor": "#b8383d"
+ },
+ "_ruby": {
+ "fontCharacter": "\\E081",
+ "fontColor": "#cc3e44"
+ },
+ "_rust_light": {
+ "fontCharacter": "\\E082",
+ "fontColor": "#627379"
+ },
+ "_rust": {
+ "fontCharacter": "\\E082",
+ "fontColor": "#6d8086"
+ },
+ "_salesforce_light": {
+ "fontCharacter": "\\E083",
+ "fontColor": "#498ba7"
+ },
+ "_salesforce": {
+ "fontCharacter": "\\E083",
+ "fontColor": "#519aba"
+ },
+ "_sass_light": {
+ "fontCharacter": "\\E084",
+ "fontColor": "#dd4b78"
+ },
+ "_sass": {
+ "fontCharacter": "\\E084",
+ "fontColor": "#f55385"
+ },
+ "_sbt_light": {
+ "fontCharacter": "\\E085",
+ "fontColor": "#498ba7"
+ },
+ "_sbt": {
+ "fontCharacter": "\\E085",
+ "fontColor": "#519aba"
+ },
+ "_scala_light": {
+ "fontCharacter": "\\E086",
+ "fontColor": "#b8383d"
+ },
+ "_scala": {
+ "fontCharacter": "\\E086",
+ "fontColor": "#cc3e44"
+ },
+ "_shell_light": {
+ "fontCharacter": "\\E089",
+ "fontColor": "#7fae42"
+ },
+ "_shell": {
+ "fontCharacter": "\\E089",
+ "fontColor": "#8dc149"
+ },
+ "_slim_light": {
+ "fontCharacter": "\\E08A",
+ "fontColor": "#cc6d2e"
+ },
+ "_slim": {
+ "fontCharacter": "\\E08A",
+ "fontColor": "#e37933"
+ },
+ "_smarty_light": {
+ "fontCharacter": "\\E08B",
+ "fontColor": "#b7b73b"
+ },
+ "_smarty": {
+ "fontCharacter": "\\E08B",
+ "fontColor": "#cbcb41"
+ },
+ "_spring_light": {
+ "fontCharacter": "\\E08C",
+ "fontColor": "#7fae42"
+ },
+ "_spring": {
+ "fontCharacter": "\\E08C",
+ "fontColor": "#8dc149"
+ },
+ "_stylelint_light": {
+ "fontCharacter": "\\E08D",
+ "fontColor": "#bfc2c1"
+ },
+ "_stylelint": {
+ "fontCharacter": "\\E08D",
+ "fontColor": "#d4d7d6"
+ },
+ "_stylelint_1_light": {
+ "fontCharacter": "\\E08D",
+ "fontColor": "#455155"
+ },
+ "_stylelint_1": {
+ "fontCharacter": "\\E08D",
+ "fontColor": "#4d5a5e"
+ },
+ "_stylus_light": {
+ "fontCharacter": "\\E08E",
+ "fontColor": "#7fae42"
+ },
+ "_stylus": {
+ "fontCharacter": "\\E08E",
+ "fontColor": "#8dc149"
+ },
+ "_sublime_light": {
+ "fontCharacter": "\\E08F",
+ "fontColor": "#cc6d2e"
+ },
+ "_sublime": {
+ "fontCharacter": "\\E08F",
+ "fontColor": "#e37933"
+ },
+ "_svelte_light": {
+ "fontCharacter": "\\E090",
+ "fontColor": "#b8383d"
+ },
+ "_svelte": {
+ "fontCharacter": "\\E090",
+ "fontColor": "#cc3e44"
+ },
+ "_svg_light": {
+ "fontCharacter": "\\E091",
+ "fontColor": "#9068b0"
+ },
+ "_svg": {
+ "fontCharacter": "\\E091",
+ "fontColor": "#a074c4"
+ },
+ "_svg_1_light": {
+ "fontCharacter": "\\E091",
+ "fontColor": "#498ba7"
+ },
+ "_svg_1": {
+ "fontCharacter": "\\E091",
+ "fontColor": "#519aba"
+ },
+ "_swift_light": {
+ "fontCharacter": "\\E092",
+ "fontColor": "#cc6d2e"
+ },
+ "_swift": {
+ "fontCharacter": "\\E092",
+ "fontColor": "#e37933"
+ },
+ "_terraform_light": {
+ "fontCharacter": "\\E093",
+ "fontColor": "#9068b0"
+ },
+ "_terraform": {
+ "fontCharacter": "\\E093",
+ "fontColor": "#a074c4"
+ },
+ "_tex_light": {
+ "fontCharacter": "\\E094",
+ "fontColor": "#498ba7"
+ },
+ "_tex": {
+ "fontCharacter": "\\E094",
+ "fontColor": "#519aba"
+ },
+ "_tex_1_light": {
+ "fontCharacter": "\\E094",
+ "fontColor": "#b7b73b"
+ },
+ "_tex_1": {
+ "fontCharacter": "\\E094",
+ "fontColor": "#cbcb41"
+ },
+ "_tex_2_light": {
+ "fontCharacter": "\\E094",
+ "fontColor": "#cc6d2e"
+ },
+ "_tex_2": {
+ "fontCharacter": "\\E094",
+ "fontColor": "#e37933"
+ },
+ "_tex_3_light": {
+ "fontCharacter": "\\E094",
+ "fontColor": "#bfc2c1"
+ },
+ "_tex_3": {
+ "fontCharacter": "\\E094",
+ "fontColor": "#d4d7d6"
+ },
+ "_todo": {
+ "fontCharacter": "\\E096"
+ },
+ "_tsconfig_light": {
+ "fontCharacter": "\\E097",
+ "fontColor": "#498ba7"
+ },
+ "_tsconfig": {
+ "fontCharacter": "\\E097",
+ "fontColor": "#519aba"
+ },
+ "_twig_light": {
+ "fontCharacter": "\\E098",
+ "fontColor": "#7fae42"
+ },
+ "_twig": {
+ "fontCharacter": "\\E098",
+ "fontColor": "#8dc149"
+ },
+ "_typescript_light": {
+ "fontCharacter": "\\E099",
+ "fontColor": "#498ba7"
+ },
+ "_typescript": {
+ "fontCharacter": "\\E099",
+ "fontColor": "#519aba"
+ },
+ "_typescript_1_light": {
+ "fontCharacter": "\\E099",
+ "fontColor": "#cc6d2e"
+ },
+ "_typescript_1": {
+ "fontCharacter": "\\E099",
+ "fontColor": "#e37933"
+ },
+ "_vala_light": {
+ "fontCharacter": "\\E09A",
+ "fontColor": "#627379"
+ },
+ "_vala": {
+ "fontCharacter": "\\E09A",
+ "fontColor": "#6d8086"
+ },
+ "_vba_light": {
+ "fontCharacter": "\\E09B",
+ "fontColor": "#9068b0"
+ },
+ "_vba": {
+ "fontCharacter": "\\E09B",
+ "fontColor": "#a074c4"
+ },
+ "_vba_1_light": {
+ "fontCharacter": "\\E09B",
+ "fontColor": "#7fae42"
+ },
+ "_vba_1": {
+ "fontCharacter": "\\E09B",
+ "fontColor": "#8dc149"
+ },
+ "_vba_2_light": {
+ "fontCharacter": "\\E09B",
+ "fontColor": "#b7b73b"
+ },
+ "_vba_2": {
+ "fontCharacter": "\\E09B",
+ "fontColor": "#cbcb41"
+ },
+ "_video_light": {
+ "fontCharacter": "\\E09C",
+ "fontColor": "#dd4b78"
+ },
+ "_video": {
+ "fontCharacter": "\\E09C",
+ "fontColor": "#f55385"
+ },
+ "_vite_light": {
+ "fontCharacter": "\\E09D",
+ "fontColor": "#b7b73b"
+ },
+ "_vite": {
+ "fontCharacter": "\\E09D",
+ "fontColor": "#cbcb41"
+ },
+ "_vue_light": {
+ "fontCharacter": "\\E09E",
+ "fontColor": "#7fae42"
+ },
+ "_vue": {
+ "fontCharacter": "\\E09E",
+ "fontColor": "#8dc149"
+ },
+ "_wasm_light": {
+ "fontCharacter": "\\E09F",
+ "fontColor": "#9068b0"
+ },
+ "_wasm": {
+ "fontCharacter": "\\E09F",
+ "fontColor": "#a074c4"
+ },
+ "_wat_light": {
+ "fontCharacter": "\\E0A0",
+ "fontColor": "#9068b0"
+ },
+ "_wat": {
+ "fontCharacter": "\\E0A0",
+ "fontColor": "#a074c4"
+ },
+ "_webpack_light": {
+ "fontCharacter": "\\E0A1",
+ "fontColor": "#498ba7"
+ },
+ "_webpack": {
+ "fontCharacter": "\\E0A1",
+ "fontColor": "#519aba"
+ },
+ "_wgt_light": {
+ "fontCharacter": "\\E0A2",
+ "fontColor": "#498ba7"
+ },
+ "_wgt": {
+ "fontCharacter": "\\E0A2",
+ "fontColor": "#519aba"
+ },
+ "_windows_light": {
+ "fontCharacter": "\\E0A3",
+ "fontColor": "#498ba7"
+ },
+ "_windows": {
+ "fontCharacter": "\\E0A3",
+ "fontColor": "#519aba"
+ },
+ "_word_light": {
+ "fontCharacter": "\\E0A4",
+ "fontColor": "#498ba7"
+ },
+ "_word": {
+ "fontCharacter": "\\E0A4",
+ "fontColor": "#519aba"
+ },
+ "_xls_light": {
+ "fontCharacter": "\\E0A5",
+ "fontColor": "#7fae42"
+ },
+ "_xls": {
+ "fontCharacter": "\\E0A5",
+ "fontColor": "#8dc149"
+ },
+ "_xml_light": {
+ "fontCharacter": "\\E0A6",
+ "fontColor": "#cc6d2e"
+ },
+ "_xml": {
+ "fontCharacter": "\\E0A6",
+ "fontColor": "#e37933"
+ },
+ "_yarn_light": {
+ "fontCharacter": "\\E0A7",
+ "fontColor": "#498ba7"
+ },
+ "_yarn": {
+ "fontCharacter": "\\E0A7",
+ "fontColor": "#519aba"
+ },
+ "_yml_light": {
+ "fontCharacter": "\\E0A8",
+ "fontColor": "#9068b0"
+ },
+ "_yml": {
+ "fontCharacter": "\\E0A8",
+ "fontColor": "#a074c4"
+ },
+ "_zig_light": {
+ "fontCharacter": "\\E0A9",
+ "fontColor": "#cc6d2e"
+ },
+ "_zig": {
+ "fontCharacter": "\\E0A9",
+ "fontColor": "#e37933"
+ },
+ "_zip_light": {
+ "fontCharacter": "\\E0AA",
+ "fontColor": "#b8383d"
+ },
+ "_zip": {
+ "fontCharacter": "\\E0AA",
+ "fontColor": "#cc3e44"
+ },
+ "_zip_1_light": {
+ "fontCharacter": "\\E0AA",
+ "fontColor": "#627379"
+ },
+ "_zip_1": {
+ "fontCharacter": "\\E0AA",
+ "fontColor": "#6d8086"
+ }
+ },
+ "file": "_default",
+ "fileExtensions": {
+ "bsl": "_bsl",
+ "mdo": "_mdo",
+ "apex": "_salesforce",
+ "asm": "_asm",
+ "s": "_asm",
+ "bicep": "_bicep",
+ "bzl": "_bazel",
+ "bazel": "_bazel",
+ "build": "_bazel",
+ "workspace": "_bazel",
+ "bazelignore": "_bazel",
+ "bazelversion": "_bazel",
+ "c": "_c",
+ "h": "_c_1",
+ "m": "_c_2",
+ "cs": "_c-sharp",
+ "cshtml": "_html",
+ "aspx": "_html",
+ "ascx": "_html_1",
+ "asax": "_html_2",
+ "master": "_html_2",
+ "cc": "_cpp",
+ "cpp": "_cpp",
+ "cxx": "_cpp",
+ "c++": "_cpp",
+ "hh": "_cpp_1",
+ "hpp": "_cpp_1",
+ "hxx": "_cpp_1",
+ "h++": "_cpp_1",
+ "mm": "_cpp_2",
+ "clj": "_clojure",
+ "cljs": "_clojure",
+ "cljc": "_clojure",
+ "edn": "_clojure_1",
+ "cfc": "_coldfusion",
+ "cfm": "_coldfusion",
+ "coffee": "_coffee",
+ "litcoffee": "_coffee",
+ "config": "_config",
+ "cfg": "_config",
+ "conf": "_config",
+ "cr": "_crystal",
+ "ecr": "_crystal_embedded",
+ "slang": "_crystal_embedded",
+ "cson": "_json",
+ "css": "_css",
+ "css.map": "_css",
+ "sss": "_css",
+ "csv": "_csv",
+ "xla": "_xls",
+ "xlam": "_xls",
+ "xls": "_xls",
+ "xlsb": "_xls",
+ "xlsm": "_xls",
+ "xlsx": "_xls",
+ "xlt": "_xls",
+ "xltm": "_xls",
+ "cu": "_cu",
+ "cuh": "_cu_1",
+ "hu": "_cu_1",
+ "cake": "_cake",
+ "ctp": "_cake_php",
+ "d": "_d",
+ "doc": "_word",
+ "docx": "_word",
+ "dot": "_word",
+ "dotm": "_word",
+ "ejs": "_ejs",
+ "ex": "_elixir",
+ "exs": "_elixir_script",
+ "elm": "_elm",
+ "ico": "_favicon",
+ "fs": "_f-sharp",
+ "fsx": "_f-sharp",
+ "gitignore": "_git",
+ "gitconfig": "_git",
+ "gitkeep": "_git",
+ "gitattributes": "_git",
+ "gitmodules": "_git",
+ "go": "_go2",
+ "slide": "_go",
+ "article": "_go",
+ "gd": "_godot",
+ "godot": "_godot_1",
+ "tres": "_godot_2",
+ "tscn": "_godot_3",
+ "gradle": "_gradle",
+ "groovy": "_grails",
+ "gsp": "_grails",
+ "gql": "_graphql",
+ "graphql": "_graphql",
+ "graphqls": "_graphql",
+ "hack": "_hacklang",
+ "haml": "_haml",
+ "handlebars": "_mustache",
+ "hbs": "_mustache",
+ "hjs": "_mustache",
+ "hs": "_haskell",
+ "lhs": "_haskell",
+ "hx": "_haxe",
+ "hxs": "_haxe_1",
+ "hxp": "_haxe_2",
+ "hxml": "_haxe_3",
+ "html": "_html_3",
+ "jade": "_jade",
+ "java": "_java",
+ "class": "_java_1",
+ "classpath": "_java",
+ "properties": "_java",
+ "js": "_javascript",
+ "js.map": "_javascript",
+ "cjs": "_javascript",
+ "cjs.map": "_javascript",
+ "mjs": "_javascript",
+ "mjs.map": "_javascript",
+ "spec.js": "_javascript_1",
+ "spec.cjs": "_javascript_1",
+ "spec.mjs": "_javascript_1",
+ "test.js": "_javascript_1",
+ "test.cjs": "_javascript_1",
+ "test.mjs": "_javascript_1",
+ "es": "_javascript",
+ "es5": "_javascript",
+ "es6": "_javascript",
+ "es7": "_javascript",
+ "jinja": "_jinja",
+ "jinja2": "_jinja",
+ "json": "_json",
+ "jl": "_julia",
+ "kt": "_kotlin",
+ "kts": "_kotlin",
+ "dart": "_dart",
+ "less": "_less",
+ "liquid": "_liquid",
+ "ls": "_livescript",
+ "lua": "_lua",
+ "markdown": "_markdown",
+ "md": "_markdown",
+ "argdown": "_argdown",
+ "ad": "_argdown",
+ "mustache": "_mustache",
+ "stache": "_mustache",
+ "nim": "_nim",
+ "nims": "_nim",
+ "github-issues": "_github",
+ "ipynb": "_notebook",
+ "njk": "_nunjucks",
+ "nunjucks": "_nunjucks",
+ "nunjs": "_nunjucks",
+ "nunj": "_nunjucks",
+ "njs": "_nunjucks",
+ "nj": "_nunjucks",
+ "npm-debug.log": "_npm",
+ "npmignore": "_npm_1",
+ "npmrc": "_npm_1",
+ "ml": "_ocaml",
+ "mli": "_ocaml",
+ "cmx": "_ocaml",
+ "cmxa": "_ocaml",
+ "odata": "_odata",
+ "pl": "_perl",
+ "php": "_php",
+ "php.inc": "_php",
+ "pipeline": "_pipeline",
+ "pddl": "_pddl",
+ "plan": "_plan",
+ "happenings": "_happenings",
+ "ps1": "_powershell",
+ "psd1": "_powershell",
+ "psm1": "_powershell",
+ "prisma": "_prisma",
+ "pug": "_pug",
+ "pp": "_puppet",
+ "epp": "_puppet",
+ "purs": "_purescript",
+ "py": "_python",
+ "jsx": "_react",
+ "spec.jsx": "_react_1",
+ "test.jsx": "_react_1",
+ "cjsx": "_react",
+ "tsx": "_react",
+ "spec.tsx": "_react_1",
+ "test.tsx": "_react_1",
+ "re": "_reasonml",
+ "res": "_rescript",
+ "resi": "_rescript_1",
+ "r": "_R",
+ "rmd": "_R",
+ "rb": "_ruby",
+ "erb": "_html_erb",
+ "erb.html": "_html_erb",
+ "html.erb": "_html_erb",
+ "rs": "_rust",
+ "sass": "_sass",
+ "scss": "_sass",
+ "springbeans": "_spring",
+ "slim": "_slim",
+ "smarty.tpl": "_smarty",
+ "tpl": "_smarty",
+ "sbt": "_sbt",
+ "scala": "_scala",
+ "sol": "_ethereum",
+ "styl": "_stylus",
+ "svelte": "_svelte",
+ "swift": "_swift",
+ "sql": "_db",
+ "soql": "_db_1",
+ "tf": "_terraform",
+ "tf.json": "_terraform",
+ "tfvars": "_terraform",
+ "tfvars.json": "_terraform",
+ "tex": "_tex",
+ "sty": "_tex_1",
+ "dtx": "_tex_2",
+ "ins": "_tex_3",
+ "toml": "_config",
+ "twig": "_twig",
+ "ts": "_typescript",
+ "spec.ts": "_typescript_1",
+ "test.ts": "_typescript_1",
+ "vala": "_vala",
+ "vapi": "_vala",
+ "bas": "_vba",
+ "cls": "_vba_1",
+ "frm": "_vba_2",
+ "component": "_html_3",
+ "vue": "_vue",
+ "wasm": "_wasm",
+ "wat": "_wat",
+ "xml": "_xml",
+ "yml": "_yml",
+ "yaml": "_yml",
+ "pro": "_prolog",
+ "zig": "_zig",
+ "jar": "_zip",
+ "zip": "_zip_1",
+ "wgt": "_wgt",
+ "ai": "_illustrator",
+ "psd": "_photoshop",
+ "pdf": "_pdf",
+ "eot": "_font",
+ "ttf": "_font",
+ "woff": "_font",
+ "woff2": "_font",
+ "otf": "_font",
+ "avif": "_image",
+ "gif": "_image",
+ "jpg": "_image",
+ "jpeg": "_image",
+ "png": "_image",
+ "pxm": "_image",
+ "svg": "_svg",
+ "svgx": "_image",
+ "tiff": "_image",
+ "webp": "_image",
+ "sublime-project": "_sublime",
+ "sublime-workspace": "_sublime",
+ "code-search": "_code-search",
+ "sh": "_shell",
+ "zsh": "_shell",
+ "fish": "_shell",
+ "zshrc": "_shell",
+ "bashrc": "_shell",
+ "mov": "_video",
+ "ogv": "_video",
+ "webm": "_video",
+ "avi": "_video",
+ "mpg": "_video",
+ "mp4": "_video",
+ "mp3": "_audio",
+ "ogg": "_audio",
+ "wav": "_audio",
+ "flac": "_audio",
+ "3ds": "_svg_1",
+ "3dm": "_svg_1",
+ "stl": "_svg_1",
+ "obj": "_svg_1",
+ "dae": "_svg_1",
+ "bat": "_windows",
+ "cmd": "_windows",
+ "babelrc": "_babel",
+ "babelrc.js": "_babel",
+ "babelrc.cjs": "_babel",
+ "bazelrc": "_bazel_1",
+ "bowerrc": "_bower",
+ "dockerignore": "_docker_1",
+ "codeclimate.yml": "_code-climate",
+ "eslintrc": "_eslint",
+ "eslintrc.js": "_eslint",
+ "eslintrc.cjs": "_eslint",
+ "eslintrc.yaml": "_eslint",
+ "eslintrc.yml": "_eslint",
+ "eslintrc.json": "_eslint",
+ "eslintignore": "_eslint_1",
+ "firebaserc": "_firebase",
+ "gitlab-ci.yml": "_gitlab",
+ "jshintrc": "_javascript_2",
+ "jscsrc": "_javascript_2",
+ "stylelintrc": "_stylelint",
+ "stylelintrc.json": "_stylelint",
+ "stylelintrc.yaml": "_stylelint",
+ "stylelintrc.yml": "_stylelint",
+ "stylelintrc.js": "_stylelint",
+ "stylelintignore": "_stylelint_1",
+ "direnv": "_config",
+ "env": "_config",
+ "static": "_config",
+ "editorconfig": "_config",
+ "slugignore": "_config",
+ "tmp": "_clock_1",
+ "htaccess": "_config",
+ "key": "_lock",
+ "cert": "_lock",
+ "cer": "_lock",
+ "crt": "_lock",
+ "pem": "_lock",
+ "ds_store": "_ignored"
+ },
+ "fileNames": {
+ "mix": "_hex",
+ "commit_editmsg": "_git",
+ "merge_msg": "_git",
+ "karma.conf.js": "_karma",
+ "karma.conf.cjs": "_karma",
+ "karma.conf.mjs": "_karma",
+ "karma.conf.coffee": "_karma",
+ "readme.md": "_info",
+ "readme.txt": "_info",
+ "readme": "_info",
+ "changelog.md": "_clock",
+ "changelog.txt": "_clock",
+ "changelog": "_clock",
+ "changes.md": "_clock",
+ "changes.txt": "_clock",
+ "changes": "_clock",
+ "version.md": "_clock",
+ "version.txt": "_clock",
+ "version": "_clock",
+ "mvnw": "_maven",
+ "pom.xml": "_maven",
+ "gemfile": "_ruby",
+ "tsconfig.json": "_tsconfig",
+ "vite.config.js": "_vite",
+ "vite.config.ts": "_vite",
+ "vite.config.mjs": "_vite",
+ "vite.config.mts": "_vite",
+ "vite.config.cjs": "_vite",
+ "vite.config.cts": "_vite",
+ "swagger.json": "_json_1",
+ "swagger.yml": "_json_1",
+ "swagger.yaml": "_json_1",
+ "mime.types": "_config",
+ "jenkinsfile": "_jenkins",
+ "babel.config.js": "_babel",
+ "babel.config.json": "_babel",
+ "babel.config.cjs": "_babel",
+ "build": "_bazel",
+ "build.bazel": "_bazel",
+ "workspace": "_bazel",
+ "workspace.bazel": "_bazel",
+ "bower.json": "_bower",
+ "dockerfile": "_docker",
+ "docker-healthcheck": "_docker_2",
+ "docker-compose.yml": "_docker_3",
+ "docker-compose.yaml": "_docker_3",
+ "docker-compose.override.yml": "_docker_3",
+ "docker-compose.override.yaml": "_docker_3",
+ "eslint.config.js": "_eslint",
+ "firebase.json": "_firebase",
+ "geckodriver": "_firefox",
+ "gruntfile.js": "_grunt",
+ "gruntfile.babel.js": "_grunt",
+ "gruntfile.coffee": "_grunt",
+ "gulpfile": "_gulp",
+ "gulpfile.js": "_gulp",
+ "ionic.config.json": "_ionic",
+ "ionic.project": "_ionic",
+ "platformio.ini": "_platformio",
+ "rollup.config.js": "_rollup",
+ "sass-lint.yml": "_sass",
+ "stylelint.config.js": "_stylelint",
+ "stylelint.config.cjs": "_stylelint",
+ "stylelint.config.mjs": "_stylelint",
+ "yarn.clean": "_yarn",
+ "yarn.lock": "_yarn",
+ "webpack.config.js": "_webpack",
+ "webpack.config.cjs": "_webpack",
+ "webpack.config.mjs": "_webpack",
+ "webpack.config.ts": "_webpack",
+ "webpack.config.build.js": "_webpack",
+ "webpack.config.build.cjs": "_webpack",
+ "webpack.config.build.mjs": "_webpack",
+ "webpack.config.build.ts": "_webpack",
+ "webpack.common.js": "_webpack",
+ "webpack.common.cjs": "_webpack",
+ "webpack.common.mjs": "_webpack",
+ "webpack.common.ts": "_webpack",
+ "webpack.dev.js": "_webpack",
+ "webpack.dev.cjs": "_webpack",
+ "webpack.dev.mjs": "_webpack",
+ "webpack.dev.ts": "_webpack",
+ "webpack.prod.js": "_webpack",
+ "webpack.prod.cjs": "_webpack",
+ "webpack.prod.mjs": "_webpack",
+ "webpack.prod.ts": "_webpack",
+ "license": "_license",
+ "licence": "_license",
+ "license.txt": "_license",
+ "licence.txt": "_license",
+ "license.md": "_license",
+ "licence.md": "_license",
+ "copying": "_license",
+ "copying.txt": "_license",
+ "copying.md": "_license",
+ "compiling": "_license_1",
+ "compiling.txt": "_license_1",
+ "compiling.md": "_license_1",
+ "contributing": "_license_2",
+ "contributing.txt": "_license_2",
+ "contributing.md": "_license_2",
+ "makefile": "_makefile",
+ "qmakefile": "_makefile_1",
+ "omakefile": "_makefile_2",
+ "cmakelists.txt": "_makefile_3",
+ "procfile": "_heroku",
+ "todo": "_todo",
+ "todo.txt": "_todo",
+ "todo.md": "_todo",
+ "npm-debug.log": "_npm_ignored"
+ },
+ "languageIds": {
+ "argdown": "_argdown",
+ "bicep": "_bicep",
+ "elixir": "_elixir",
+ "elm": "_elm",
+ "erb": "_html_erb",
+ "github-issues": "_github",
+ "gradle": "_gradle",
+ "godot": "_godot",
+ "haml": "_haml",
+ "haskell": "_haskell",
+ "haxe": "_haxe",
+ "jinja": "_jinja",
+ "kotlin": "_kotlin",
+ "mustache": "_mustache",
+ "nunjucks": "_nunjucks",
+ "ocaml": "_ocaml",
+ "r": "_R",
+ "rescript": "_rescript",
+ "sass": "_sass",
+ "stylus": "_stylus",
+ "terraform": "_terraform",
+ "todo": "_todo",
+ "vala": "_vala",
+ "vue": "_vue"
+ },
+ "light": {
+ "file": "_default_light",
+ "fileExtensions": {
+ "bsl": "_bsl_light",
+ "mdo": "_mdo_light",
+ "apex": "_salesforce_light",
+ "asm": "_asm_light",
+ "s": "_asm_light",
+ "bicep": "_bicep_light",
+ "bzl": "_bazel_light",
+ "bazel": "_bazel_light",
+ "build": "_bazel_light",
+ "workspace": "_bazel_light",
+ "bazelignore": "_bazel_light",
+ "bazelversion": "_bazel_light",
+ "c": "_c_light",
+ "h": "_c_1_light",
+ "m": "_c_2_light",
+ "cs": "_c-sharp_light",
+ "cshtml": "_html_light",
+ "aspx": "_html_light",
+ "ascx": "_html_1_light",
+ "asax": "_html_2_light",
+ "master": "_html_2_light",
+ "cc": "_cpp_light",
+ "cpp": "_cpp_light",
+ "cxx": "_cpp_light",
+ "c++": "_cpp_light",
+ "hh": "_cpp_1_light",
+ "hpp": "_cpp_1_light",
+ "hxx": "_cpp_1_light",
+ "h++": "_cpp_1_light",
+ "mm": "_cpp_2_light",
+ "clj": "_clojure_light",
+ "cljs": "_clojure_light",
+ "cljc": "_clojure_light",
+ "edn": "_clojure_1_light",
+ "cfc": "_coldfusion_light",
+ "cfm": "_coldfusion_light",
+ "coffee": "_coffee_light",
+ "litcoffee": "_coffee_light",
+ "config": "_config_light",
+ "cfg": "_config_light",
+ "conf": "_config_light",
+ "cr": "_crystal_light",
+ "ecr": "_crystal_embedded_light",
+ "slang": "_crystal_embedded_light",
+ "cson": "_json_light",
+ "css": "_css_light",
+ "css.map": "_css_light",
+ "sss": "_css_light",
+ "csv": "_csv_light",
+ "xla": "_xls_light",
+ "xlam": "_xls_light",
+ "xls": "_xls_light",
+ "xlsb": "_xls_light",
+ "xlsm": "_xls_light",
+ "xlsx": "_xls_light",
+ "xlt": "_xls_light",
+ "xltm": "_xls_light",
+ "cu": "_cu_light",
+ "cuh": "_cu_1_light",
+ "hu": "_cu_1_light",
+ "cake": "_cake_light",
+ "ctp": "_cake_php_light",
+ "d": "_d_light",
+ "doc": "_word_light",
+ "docx": "_word_light",
+ "dot": "_word_light",
+ "dotm": "_word_light",
+ "ejs": "_ejs_light",
+ "ex": "_elixir_light",
+ "exs": "_elixir_script_light",
+ "elm": "_elm_light",
+ "ico": "_favicon_light",
+ "fs": "_f-sharp_light",
+ "fsx": "_f-sharp_light",
+ "gitignore": "_git_light",
+ "gitconfig": "_git_light",
+ "gitkeep": "_git_light",
+ "gitattributes": "_git_light",
+ "gitmodules": "_git_light",
+ "go": "_go2_light",
+ "slide": "_go_light",
+ "article": "_go_light",
+ "gd": "_godot_light",
+ "godot": "_godot_1_light",
+ "tres": "_godot_2_light",
+ "tscn": "_godot_3_light",
+ "gradle": "_gradle_light",
+ "groovy": "_grails_light",
+ "gsp": "_grails_light",
+ "gql": "_graphql_light",
+ "graphql": "_graphql_light",
+ "graphqls": "_graphql_light",
+ "hack": "_hacklang_light",
+ "haml": "_haml_light",
+ "handlebars": "_mustache_light",
+ "hbs": "_mustache_light",
+ "hjs": "_mustache_light",
+ "hs": "_haskell_light",
+ "lhs": "_haskell_light",
+ "hx": "_haxe_light",
+ "hxs": "_haxe_1_light",
+ "hxp": "_haxe_2_light",
+ "hxml": "_haxe_3_light",
+ "html": "_html_3_light",
+ "jade": "_jade_light",
+ "java": "_java_light",
+ "class": "_java_1_light",
+ "classpath": "_java_light",
+ "properties": "_java_light",
+ "js": "_javascript_light",
+ "js.map": "_javascript_light",
+ "cjs": "_javascript_light",
+ "cjs.map": "_javascript_light",
+ "mjs": "_javascript_light",
+ "mjs.map": "_javascript_light",
+ "spec.js": "_javascript_1_light",
+ "spec.cjs": "_javascript_1_light",
+ "spec.mjs": "_javascript_1_light",
+ "test.js": "_javascript_1_light",
+ "test.cjs": "_javascript_1_light",
+ "test.mjs": "_javascript_1_light",
+ "es": "_javascript_light",
+ "es5": "_javascript_light",
+ "es6": "_javascript_light",
+ "es7": "_javascript_light",
+ "jinja": "_jinja_light",
+ "jinja2": "_jinja_light",
+ "json": "_json_light",
+ "jl": "_julia_light",
+ "kt": "_kotlin_light",
+ "kts": "_kotlin_light",
+ "dart": "_dart_light",
+ "less": "_less_light",
+ "liquid": "_liquid_light",
+ "ls": "_livescript_light",
+ "lua": "_lua_light",
+ "markdown": "_markdown_light",
+ "md": "_markdown_light",
+ "argdown": "_argdown_light",
+ "ad": "_argdown_light",
+ "mustache": "_mustache_light",
+ "stache": "_mustache_light",
+ "nim": "_nim_light",
+ "nims": "_nim_light",
+ "github-issues": "_github_light",
+ "ipynb": "_notebook_light",
+ "njk": "_nunjucks_light",
+ "nunjucks": "_nunjucks_light",
+ "nunjs": "_nunjucks_light",
+ "nunj": "_nunjucks_light",
+ "njs": "_nunjucks_light",
+ "nj": "_nunjucks_light",
+ "npm-debug.log": "_npm_light",
+ "npmignore": "_npm_1_light",
+ "npmrc": "_npm_1_light",
+ "ml": "_ocaml_light",
+ "mli": "_ocaml_light",
+ "cmx": "_ocaml_light",
+ "cmxa": "_ocaml_light",
+ "odata": "_odata_light",
+ "pl": "_perl_light",
+ "php": "_php_light",
+ "php.inc": "_php_light",
+ "pipeline": "_pipeline_light",
+ "pddl": "_pddl_light",
+ "plan": "_plan_light",
+ "happenings": "_happenings_light",
+ "ps1": "_powershell_light",
+ "psd1": "_powershell_light",
+ "psm1": "_powershell_light",
+ "prisma": "_prisma_light",
+ "pug": "_pug_light",
+ "pp": "_puppet_light",
+ "epp": "_puppet_light",
+ "purs": "_purescript_light",
+ "py": "_python_light",
+ "jsx": "_react_light",
+ "spec.jsx": "_react_1_light",
+ "test.jsx": "_react_1_light",
+ "cjsx": "_react_light",
+ "tsx": "_react_light",
+ "spec.tsx": "_react_1_light",
+ "test.tsx": "_react_1_light",
+ "re": "_reasonml_light",
+ "res": "_rescript_light",
+ "resi": "_rescript_1_light",
+ "r": "_R_light",
+ "rmd": "_R_light",
+ "rb": "_ruby_light",
+ "erb": "_html_erb_light",
+ "erb.html": "_html_erb_light",
+ "html.erb": "_html_erb_light",
+ "rs": "_rust_light",
+ "sass": "_sass_light",
+ "scss": "_sass_light",
+ "springbeans": "_spring_light",
+ "slim": "_slim_light",
+ "smarty.tpl": "_smarty_light",
+ "tpl": "_smarty_light",
+ "sbt": "_sbt_light",
+ "scala": "_scala_light",
+ "sol": "_ethereum_light",
+ "styl": "_stylus_light",
+ "svelte": "_svelte_light",
+ "swift": "_swift_light",
+ "sql": "_db_light",
+ "soql": "_db_1_light",
+ "tf": "_terraform_light",
+ "tf.json": "_terraform_light",
+ "tfvars": "_terraform_light",
+ "tfvars.json": "_terraform_light",
+ "tex": "_tex_light",
+ "sty": "_tex_1_light",
+ "dtx": "_tex_2_light",
+ "ins": "_tex_3_light",
+ "toml": "_config_light",
+ "twig": "_twig_light",
+ "ts": "_typescript_light",
+ "spec.ts": "_typescript_1_light",
+ "test.ts": "_typescript_1_light",
+ "vala": "_vala_light",
+ "vapi": "_vala_light",
+ "bas": "_vba_light",
+ "cls": "_vba_1_light",
+ "frm": "_vba_2_light",
+ "component": "_html_3_light",
+ "vue": "_vue_light",
+ "wasm": "_wasm_light",
+ "wat": "_wat_light",
+ "xml": "_xml_light",
+ "yml": "_yml_light",
+ "yaml": "_yml_light",
+ "pro": "_prolog_light",
+ "zig": "_zig_light",
+ "jar": "_zip_light",
+ "zip": "_zip_1_light",
+ "wgt": "_wgt_light",
+ "ai": "_illustrator_light",
+ "psd": "_photoshop_light",
+ "pdf": "_pdf_light",
+ "eot": "_font_light",
+ "ttf": "_font_light",
+ "woff": "_font_light",
+ "woff2": "_font_light",
+ "otf": "_font_light",
+ "avif": "_image_light",
+ "gif": "_image_light",
+ "jpg": "_image_light",
+ "jpeg": "_image_light",
+ "png": "_image_light",
+ "pxm": "_image_light",
+ "svg": "_svg_light",
+ "svgx": "_image_light",
+ "tiff": "_image_light",
+ "webp": "_image_light",
+ "sublime-project": "_sublime_light",
+ "sublime-workspace": "_sublime_light",
+ "code-search": "_code-search_light",
+ "sh": "_shell_light",
+ "zsh": "_shell_light",
+ "fish": "_shell_light",
+ "zshrc": "_shell_light",
+ "bashrc": "_shell_light",
+ "mov": "_video_light",
+ "ogv": "_video_light",
+ "webm": "_video_light",
+ "avi": "_video_light",
+ "mpg": "_video_light",
+ "mp4": "_video_light",
+ "mp3": "_audio_light",
+ "ogg": "_audio_light",
+ "wav": "_audio_light",
+ "flac": "_audio_light",
+ "3ds": "_svg_1_light",
+ "3dm": "_svg_1_light",
+ "stl": "_svg_1_light",
+ "obj": "_svg_1_light",
+ "dae": "_svg_1_light",
+ "bat": "_windows_light",
+ "cmd": "_windows_light",
+ "babelrc": "_babel_light",
+ "babelrc.js": "_babel_light",
+ "babelrc.cjs": "_babel_light",
+ "bazelrc": "_bazel_1_light",
+ "bowerrc": "_bower_light",
+ "dockerignore": "_docker_1_light",
+ "codeclimate.yml": "_code-climate_light",
+ "eslintrc": "_eslint_light",
+ "eslintrc.js": "_eslint_light",
+ "eslintrc.cjs": "_eslint_light",
+ "eslintrc.yaml": "_eslint_light",
+ "eslintrc.yml": "_eslint_light",
+ "eslintrc.json": "_eslint_light",
+ "eslintignore": "_eslint_1_light",
+ "firebaserc": "_firebase_light",
+ "gitlab-ci.yml": "_gitlab_light",
+ "jshintrc": "_javascript_2_light",
+ "jscsrc": "_javascript_2_light",
+ "stylelintrc": "_stylelint_light",
+ "stylelintrc.json": "_stylelint_light",
+ "stylelintrc.yaml": "_stylelint_light",
+ "stylelintrc.yml": "_stylelint_light",
+ "stylelintrc.js": "_stylelint_light",
+ "stylelintignore": "_stylelint_1_light",
+ "direnv": "_config_light",
+ "env": "_config_light",
+ "static": "_config_light",
+ "editorconfig": "_config_light",
+ "slugignore": "_config_light",
+ "tmp": "_clock_1_light",
+ "htaccess": "_config_light",
+ "key": "_lock_light",
+ "cert": "_lock_light",
+ "cer": "_lock_light",
+ "crt": "_lock_light",
+ "pem": "_lock_light",
+ "ds_store": "_ignored_light"
+ },
+ "languageIds": {
+ "argdown": "_argdown_light",
+ "bicep": "_bicep_light",
+ "elixir": "_elixir_light",
+ "elm": "_elm_light",
+ "erb": "_html_erb_light",
+ "github-issues": "_github_light",
+ "gradle": "_gradle_light",
+ "godot": "_godot_light",
+ "haml": "_haml_light",
+ "haskell": "_haskell_light",
+ "haxe": "_haxe_light",
+ "jinja": "_jinja_light",
+ "kotlin": "_kotlin_light",
+ "mustache": "_mustache_light",
+ "nunjucks": "_nunjucks_light",
+ "ocaml": "_ocaml_light",
+ "r": "_R_light",
+ "rescript": "_rescript_light",
+ "sass": "_sass_light",
+ "stylus": "_stylus_light",
+ "terraform": "_terraform_light",
+ "vala": "_vala_light",
+ "vue": "_vue_light"
+ },
+ "fileNames": {
+ "mix": "_hex_light",
+ "commit_editmsg": "_git_light",
+ "merge_msg": "_git_light",
+ "karma.conf.js": "_karma_light",
+ "karma.conf.cjs": "_karma_light",
+ "karma.conf.mjs": "_karma_light",
+ "karma.conf.coffee": "_karma_light",
+ "readme.md": "_info_light",
+ "readme.txt": "_info_light",
+ "readme": "_info_light",
+ "changelog.md": "_clock_light",
+ "changelog.txt": "_clock_light",
+ "changelog": "_clock_light",
+ "changes.md": "_clock_light",
+ "changes.txt": "_clock_light",
+ "changes": "_clock_light",
+ "version.md": "_clock_light",
+ "version.txt": "_clock_light",
+ "version": "_clock_light",
+ "mvnw": "_maven_light",
+ "pom.xml": "_maven_light",
+ "gemfile": "_ruby_light",
+ "tsconfig.json": "_tsconfig_light",
+ "vite.config.js": "_vite_light",
+ "vite.config.ts": "_vite_light",
+ "vite.config.mjs": "_vite_light",
+ "vite.config.mts": "_vite_light",
+ "vite.config.cjs": "_vite_light",
+ "vite.config.cts": "_vite_light",
+ "swagger.json": "_json_1_light",
+ "swagger.yml": "_json_1_light",
+ "swagger.yaml": "_json_1_light",
+ "mime.types": "_config_light",
+ "jenkinsfile": "_jenkins_light",
+ "babel.config.js": "_babel_light",
+ "babel.config.json": "_babel_light",
+ "babel.config.cjs": "_babel_light",
+ "build": "_bazel_light",
+ "build.bazel": "_bazel_light",
+ "workspace": "_bazel_light",
+ "workspace.bazel": "_bazel_light",
+ "bower.json": "_bower_light",
+ "dockerfile": "_docker_light",
+ "docker-healthcheck": "_docker_2_light",
+ "docker-compose.yml": "_docker_3_light",
+ "docker-compose.yaml": "_docker_3_light",
+ "docker-compose.override.yml": "_docker_3_light",
+ "docker-compose.override.yaml": "_docker_3_light",
+ "eslint.config.js": "_eslint_light",
+ "firebase.json": "_firebase_light",
+ "geckodriver": "_firefox_light",
+ "gruntfile.js": "_grunt_light",
+ "gruntfile.babel.js": "_grunt_light",
+ "gruntfile.coffee": "_grunt_light",
+ "gulpfile": "_gulp_light",
+ "gulpfile.js": "_gulp_light",
+ "ionic.config.json": "_ionic_light",
+ "ionic.project": "_ionic_light",
+ "platformio.ini": "_platformio_light",
+ "rollup.config.js": "_rollup_light",
+ "sass-lint.yml": "_sass_light",
+ "stylelint.config.js": "_stylelint_light",
+ "stylelint.config.cjs": "_stylelint_light",
+ "stylelint.config.mjs": "_stylelint_light",
+ "yarn.clean": "_yarn_light",
+ "yarn.lock": "_yarn_light",
+ "webpack.config.js": "_webpack_light",
+ "webpack.config.cjs": "_webpack_light",
+ "webpack.config.mjs": "_webpack_light",
+ "webpack.config.ts": "_webpack_light",
+ "webpack.config.build.js": "_webpack_light",
+ "webpack.config.build.cjs": "_webpack_light",
+ "webpack.config.build.mjs": "_webpack_light",
+ "webpack.config.build.ts": "_webpack_light",
+ "webpack.common.js": "_webpack_light",
+ "webpack.common.cjs": "_webpack_light",
+ "webpack.common.mjs": "_webpack_light",
+ "webpack.common.ts": "_webpack_light",
+ "webpack.dev.js": "_webpack_light",
+ "webpack.dev.cjs": "_webpack_light",
+ "webpack.dev.mjs": "_webpack_light",
+ "webpack.dev.ts": "_webpack_light",
+ "webpack.prod.js": "_webpack_light",
+ "webpack.prod.cjs": "_webpack_light",
+ "webpack.prod.mjs": "_webpack_light",
+ "webpack.prod.ts": "_webpack_light",
+ "license": "_license_light",
+ "licence": "_license_light",
+ "license.txt": "_license_light",
+ "licence.txt": "_license_light",
+ "license.md": "_license_light",
+ "licence.md": "_license_light",
+ "copying": "_license_light",
+ "copying.txt": "_license_light",
+ "copying.md": "_license_light",
+ "compiling": "_license_1_light",
+ "compiling.txt": "_license_1_light",
+ "compiling.md": "_license_1_light",
+ "contributing": "_license_2_light",
+ "contributing.txt": "_license_2_light",
+ "contributing.md": "_license_2_light",
+ "makefile": "_makefile_light",
+ "qmakefile": "_makefile_1_light",
+ "omakefile": "_makefile_2_light",
+ "cmakelists.txt": "_makefile_3_light",
+ "procfile": "_heroku_light",
+ "npm-debug.log": "_npm_ignored_light"
+ }
+ },
+ "version": "https://github.com/DecimalTurn/seti-ui/commit/7a8d51ccb32737be812549fe1c31fae8276b284f"
+}
\ No newline at end of file
diff --git a/icons/theme-seti/package.json b/icons/theme-seti/package.json
new file mode 100644
index 0000000..64b61ce
--- /dev/null
+++ b/icons/theme-seti/package.json
@@ -0,0 +1,37 @@
+{
+ "name": "vscode-theme-seti-vba",
+ "private": true,
+ "version": "1.1.0-vba",
+ "displayName": "%displayName%",
+ "description": "%description%",
+ "publisher": "vscode",
+ "license": "MIT",
+ "icon": "icons/seti-circular-128x128.png",
+ "scripts": {
+ "update": "node ./build/update-icon-theme.js",
+ "build": "vsce package"
+ },
+ "engines": {
+ "vscode": "*"
+ },
+ "categories": [
+ "Themes"
+ ],
+ "contributes": {
+ "iconThemes": [
+ {
+ "id": "vs-seti-vba",
+ "label": "%themeLabel%",
+ "path": "./icons/vs-seti-icon-theme.json"
+ }
+ ]
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/microsoft/vscode.git"
+ },
+ "devDependencies": {
+ "minimatch": "^3.0.4",
+ "vsce": "^2.15.0"
+ }
+}
diff --git a/icons/theme-seti/package.nls.json b/icons/theme-seti/package.nls.json
new file mode 100644
index 0000000..3b95693
--- /dev/null
+++ b/icons/theme-seti/package.nls.json
@@ -0,0 +1,5 @@
+{
+ "displayName": "Seti File Icon Theme + VBA",
+ "description": "A file icon theme made out of the Seti UI file icons + VBA icons.",
+ "themeLabel": "Seti + VBA"
+}
diff --git a/package-lock.json b/package-lock.json
index 0feb940..4cc0006 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,32 +1,32 @@
{
"name": "vba-lsp",
- "version": "1.5.13",
+ "version": "1.7.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "vba-lsp",
- "version": "1.5.13",
+ "version": "1.7.1",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"antlr4ng": "^3.0.16",
"reflect-metadata": "^0.2.2",
- "tsyringe": "^4.9.1",
- "typescript-eslint": "^8.29.1"
+ "tsyringe": "^4.10.0",
+ "typescript-eslint": "^8.32.1"
},
"devDependencies": {
"@types/mocha": "^10.0.10",
- "@types/node": "^22.14.0",
+ "@types/node": "^22.15.21",
"@typescript-eslint/eslint-plugin": "^8.29.0",
"@typescript-eslint/parser": "^8.29.0",
"@vscode/test-cli": "^0.0.10",
- "@vscode/test-electron": "^2.4.1",
+ "@vscode/test-electron": "^2.5.2",
"antlr4ng-cli": "^2.0.0",
- "esbuild": "^0.25.2",
- "eslint": "^9.24.0",
+ "esbuild": "^0.25.4",
+ "eslint": "^9.27.0",
"js-yaml": "^4.1.0",
- "mocha": "^11.1.0",
+ "mocha": "^11.5.0",
"npm-run-all": "^4.1.5",
"typescript": "^5.8.3",
"vscode-tmgrammar-test": "^0.1.3"
@@ -43,9 +43,9 @@
"license": "MIT"
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz",
- "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz",
+ "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==",
"cpu": [
"ppc64"
],
@@ -60,9 +60,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz",
- "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz",
+ "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==",
"cpu": [
"arm"
],
@@ -77,9 +77,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz",
- "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz",
+ "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==",
"cpu": [
"arm64"
],
@@ -94,9 +94,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz",
- "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz",
+ "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==",
"cpu": [
"x64"
],
@@ -111,9 +111,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz",
- "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz",
+ "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==",
"cpu": [
"arm64"
],
@@ -128,9 +128,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz",
- "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz",
+ "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==",
"cpu": [
"x64"
],
@@ -145,9 +145,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz",
- "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz",
+ "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==",
"cpu": [
"arm64"
],
@@ -162,9 +162,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz",
- "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz",
+ "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==",
"cpu": [
"x64"
],
@@ -179,9 +179,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz",
- "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz",
+ "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==",
"cpu": [
"arm"
],
@@ -196,9 +196,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz",
- "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz",
+ "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==",
"cpu": [
"arm64"
],
@@ -213,9 +213,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz",
- "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz",
+ "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==",
"cpu": [
"ia32"
],
@@ -230,9 +230,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz",
- "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz",
+ "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==",
"cpu": [
"loong64"
],
@@ -247,9 +247,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz",
- "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz",
+ "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==",
"cpu": [
"mips64el"
],
@@ -264,9 +264,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz",
- "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz",
+ "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==",
"cpu": [
"ppc64"
],
@@ -281,9 +281,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz",
- "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz",
+ "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==",
"cpu": [
"riscv64"
],
@@ -298,9 +298,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz",
- "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz",
+ "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==",
"cpu": [
"s390x"
],
@@ -315,9 +315,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz",
- "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz",
+ "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==",
"cpu": [
"x64"
],
@@ -332,9 +332,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz",
- "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz",
+ "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==",
"cpu": [
"arm64"
],
@@ -349,9 +349,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz",
- "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz",
+ "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==",
"cpu": [
"x64"
],
@@ -366,9 +366,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz",
- "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz",
+ "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==",
"cpu": [
"arm64"
],
@@ -383,9 +383,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz",
- "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz",
+ "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==",
"cpu": [
"x64"
],
@@ -400,9 +400,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz",
- "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz",
+ "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==",
"cpu": [
"x64"
],
@@ -417,9 +417,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz",
- "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz",
+ "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==",
"cpu": [
"arm64"
],
@@ -434,9 +434,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz",
- "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz",
+ "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==",
"cpu": [
"ia32"
],
@@ -451,9 +451,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz",
- "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz",
+ "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==",
"cpu": [
"x64"
],
@@ -468,9 +468,9 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz",
- "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==",
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
+ "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
"license": "MIT",
"dependencies": {
"eslint-visitor-keys": "^3.4.3"
@@ -531,18 +531,18 @@
}
},
"node_modules/@eslint/config-helpers": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz",
- "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==",
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz",
+ "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==",
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/core": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
- "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==",
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz",
+ "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==",
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
@@ -584,6 +584,15 @@
"concat-map": "0.0.1"
}
},
+ "node_modules/@eslint/eslintrc/node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -597,12 +606,15 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.24.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz",
- "integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==",
+ "version": "9.27.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz",
+ "integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==",
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
}
},
"node_modules/@eslint/object-schema": {
@@ -615,30 +627,18 @@
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.2.8",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz",
- "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==",
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz",
+ "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==",
"license": "Apache-2.0",
"dependencies": {
- "@eslint/core": "^0.13.0",
+ "@eslint/core": "^0.14.0",
"levn": "^0.4.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
- "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
- "version": "0.13.0",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz",
- "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==",
- "license": "Apache-2.0",
- "dependencies": {
- "@types/json-schema": "^7.0.15"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
"node_modules/@humanfs/core": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
@@ -688,9 +688,9 @@
}
},
"node_modules/@humanwhocodes/retry": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz",
- "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==",
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
"license": "Apache-2.0",
"engines": {
"node": ">=18.18"
@@ -829,9 +829,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "22.14.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz",
- "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==",
+ "version": "22.15.21",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz",
+ "integrity": "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -839,20 +839,20 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.29.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.1.tgz",
- "integrity": "sha512-ba0rr4Wfvg23vERs3eB+P3lfj2E+2g3lhWcCVukUuhtcdUx5lSIFZlGFEBHKr+3zizDa/TvZTptdNHVZWAkSBg==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz",
+ "integrity": "sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==",
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.29.1",
- "@typescript-eslint/type-utils": "8.29.1",
- "@typescript-eslint/utils": "8.29.1",
- "@typescript-eslint/visitor-keys": "8.29.1",
+ "@typescript-eslint/scope-manager": "8.32.1",
+ "@typescript-eslint/type-utils": "8.32.1",
+ "@typescript-eslint/utils": "8.32.1",
+ "@typescript-eslint/visitor-keys": "8.32.1",
"graphemer": "^1.4.0",
- "ignore": "^5.3.1",
+ "ignore": "^7.0.0",
"natural-compare": "^1.4.0",
- "ts-api-utils": "^2.0.1"
+ "ts-api-utils": "^2.1.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -868,15 +868,15 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.29.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.29.1.tgz",
- "integrity": "sha512-zczrHVEqEaTwh12gWBIJWj8nx+ayDcCJs06yoNMY0kwjMWDM6+kppljY+BxWI06d2Ja+h4+WdufDcwMnnMEWmg==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz",
+ "integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==",
"license": "MIT",
"dependencies": {
- "@typescript-eslint/scope-manager": "8.29.1",
- "@typescript-eslint/types": "8.29.1",
- "@typescript-eslint/typescript-estree": "8.29.1",
- "@typescript-eslint/visitor-keys": "8.29.1",
+ "@typescript-eslint/scope-manager": "8.32.1",
+ "@typescript-eslint/types": "8.32.1",
+ "@typescript-eslint/typescript-estree": "8.32.1",
+ "@typescript-eslint/visitor-keys": "8.32.1",
"debug": "^4.3.4"
},
"engines": {
@@ -892,13 +892,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.29.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.1.tgz",
- "integrity": "sha512-2nggXGX5F3YrsGN08pw4XpMLO1Rgtnn4AzTegC2MDesv6q3QaTU5yU7IbS1tf1IwCR0Hv/1EFygLn9ms6LIpDA==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.1.tgz",
+ "integrity": "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==",
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.29.1",
- "@typescript-eslint/visitor-keys": "8.29.1"
+ "@typescript-eslint/types": "8.32.1",
+ "@typescript-eslint/visitor-keys": "8.32.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -909,15 +909,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.29.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.29.1.tgz",
- "integrity": "sha512-DkDUSDwZVCYN71xA4wzySqqcZsHKic53A4BLqmrWFFpOpNSoxX233lwGu/2135ymTCR04PoKiEEEvN1gFYg4Tw==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.1.tgz",
+ "integrity": "sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==",
"license": "MIT",
"dependencies": {
- "@typescript-eslint/typescript-estree": "8.29.1",
- "@typescript-eslint/utils": "8.29.1",
+ "@typescript-eslint/typescript-estree": "8.32.1",
+ "@typescript-eslint/utils": "8.32.1",
"debug": "^4.3.4",
- "ts-api-utils": "^2.0.1"
+ "ts-api-utils": "^2.1.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -932,9 +932,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.29.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.1.tgz",
- "integrity": "sha512-VT7T1PuJF1hpYC3AGm2rCgJBjHL3nc+A/bhOp9sGMKfi5v0WufsX/sHCFBfNTx2F+zA6qBc/PD0/kLRLjdt8mQ==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.1.tgz",
+ "integrity": "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==",
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -945,19 +945,19 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.29.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.29.1.tgz",
- "integrity": "sha512-l1enRoSaUkQxOQnbi0KPUtqeZkSiFlqrx9/3ns2rEDhGKfTa+88RmXqedC1zmVTOWrLc2e6DEJrTA51C9iLH5g==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.1.tgz",
+ "integrity": "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==",
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.29.1",
- "@typescript-eslint/visitor-keys": "8.29.1",
+ "@typescript-eslint/types": "8.32.1",
+ "@typescript-eslint/visitor-keys": "8.32.1",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
"minimatch": "^9.0.4",
"semver": "^7.6.0",
- "ts-api-utils": "^2.0.1"
+ "ts-api-utils": "^2.1.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -971,15 +971,15 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.29.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.1.tgz",
- "integrity": "sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.1.tgz",
+ "integrity": "sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==",
"license": "MIT",
"dependencies": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "8.29.1",
- "@typescript-eslint/types": "8.29.1",
- "@typescript-eslint/typescript-estree": "8.29.1"
+ "@eslint-community/eslint-utils": "^4.7.0",
+ "@typescript-eslint/scope-manager": "8.32.1",
+ "@typescript-eslint/types": "8.32.1",
+ "@typescript-eslint/typescript-estree": "8.32.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -994,12 +994,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.29.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.1.tgz",
- "integrity": "sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.1.tgz",
+ "integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==",
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.29.1",
+ "@typescript-eslint/types": "8.32.1",
"eslint-visitor-keys": "^4.2.0"
},
"engines": {
@@ -1068,6 +1068,16 @@
"wrap-ansi": "^7.0.0"
}
},
+ "node_modules/@vscode/test-cli/node_modules/diff": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
+ "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/@vscode/test-cli/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -1237,16 +1247,16 @@
}
},
"node_modules/@vscode/test-electron": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.1.tgz",
- "integrity": "sha512-Gc6EdaLANdktQ1t+zozoBVRynfIsMKMc94Svu1QreOBC8y76x4tvaK32TljrLi1LI2+PK58sDVbL7ALdqf3VRQ==",
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz",
+ "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==",
"dev": true,
"license": "MIT",
"dependencies": {
"http-proxy-agent": "^7.0.2",
"https-proxy-agent": "^7.0.5",
"jszip": "^3.10.1",
- "ora": "^7.0.1",
+ "ora": "^8.1.0",
"semver": "^7.6.2"
},
"engines": {
@@ -1446,27 +1456,6 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
- "node_modules/base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@@ -1480,33 +1469,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/bl": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz",
- "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "buffer": "^6.0.3",
- "inherits": "^2.0.4",
- "readable-stream": "^3.4.0"
- }
- },
- "node_modules/bl/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/bottleneck": {
"version": "2.19.5",
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
@@ -1542,31 +1504,6 @@
"dev": true,
"license": "ISC"
},
- "node_modules/buffer": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
- "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.2.1"
- }
- },
"node_modules/c8": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/c8/-/c8-9.1.0.tgz",
@@ -1719,16 +1656,16 @@
}
},
"node_modules/cli-cursor": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
- "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+ "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "restore-cursor": "^4.0.0"
+ "restore-cursor": "^5.0.0"
},
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -1942,9 +1879,9 @@
}
},
"node_modules/debug": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
- "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -2014,9 +1951,9 @@
}
},
"node_modules/diff": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
- "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz",
+ "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
@@ -2077,9 +2014,9 @@
}
},
"node_modules/es-abstract": {
- "version": "1.23.9",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz",
- "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==",
+ "version": "1.23.10",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.10.tgz",
+ "integrity": "sha512-MtUbM072wlJNyeYAe0mhzrD+M6DIJa96CZAOBBrhDbgKnB4MApIKefcyAB1eOdYn8cUNZgvwBvEzdoAYsxgEIw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2087,18 +2024,18 @@
"arraybuffer.prototype.slice": "^1.0.4",
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
+ "call-bound": "^1.0.4",
"data-view-buffer": "^1.0.2",
"data-view-byte-length": "^1.0.2",
"data-view-byte-offset": "^1.0.1",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
+ "es-object-atoms": "^1.1.1",
"es-set-tostringtag": "^2.1.0",
"es-to-primitive": "^1.3.0",
"function.prototype.name": "^1.1.8",
- "get-intrinsic": "^1.2.7",
- "get-proto": "^1.0.0",
+ "get-intrinsic": "^1.3.0",
+ "get-proto": "^1.0.1",
"get-symbol-description": "^1.1.0",
"globalthis": "^1.0.4",
"gopd": "^1.2.0",
@@ -2114,13 +2051,13 @@
"is-shared-array-buffer": "^1.0.4",
"is-string": "^1.1.1",
"is-typed-array": "^1.1.15",
- "is-weakref": "^1.1.0",
+ "is-weakref": "^1.1.1",
"math-intrinsics": "^1.1.0",
- "object-inspect": "^1.13.3",
+ "object-inspect": "^1.13.4",
"object-keys": "^1.1.1",
"object.assign": "^4.1.7",
"own-keys": "^1.0.1",
- "regexp.prototype.flags": "^1.5.3",
+ "regexp.prototype.flags": "^1.5.4",
"safe-array-concat": "^1.1.3",
"safe-push-apply": "^1.0.0",
"safe-regex-test": "^1.1.0",
@@ -2133,7 +2070,7 @@
"typed-array-byte-offset": "^1.0.4",
"typed-array-length": "^1.0.7",
"unbox-primitive": "^1.1.0",
- "which-typed-array": "^1.1.18"
+ "which-typed-array": "^1.1.19"
},
"engines": {
"node": ">= 0.4"
@@ -2210,9 +2147,9 @@
}
},
"node_modules/esbuild": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz",
- "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz",
+ "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -2223,31 +2160,31 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.25.2",
- "@esbuild/android-arm": "0.25.2",
- "@esbuild/android-arm64": "0.25.2",
- "@esbuild/android-x64": "0.25.2",
- "@esbuild/darwin-arm64": "0.25.2",
- "@esbuild/darwin-x64": "0.25.2",
- "@esbuild/freebsd-arm64": "0.25.2",
- "@esbuild/freebsd-x64": "0.25.2",
- "@esbuild/linux-arm": "0.25.2",
- "@esbuild/linux-arm64": "0.25.2",
- "@esbuild/linux-ia32": "0.25.2",
- "@esbuild/linux-loong64": "0.25.2",
- "@esbuild/linux-mips64el": "0.25.2",
- "@esbuild/linux-ppc64": "0.25.2",
- "@esbuild/linux-riscv64": "0.25.2",
- "@esbuild/linux-s390x": "0.25.2",
- "@esbuild/linux-x64": "0.25.2",
- "@esbuild/netbsd-arm64": "0.25.2",
- "@esbuild/netbsd-x64": "0.25.2",
- "@esbuild/openbsd-arm64": "0.25.2",
- "@esbuild/openbsd-x64": "0.25.2",
- "@esbuild/sunos-x64": "0.25.2",
- "@esbuild/win32-arm64": "0.25.2",
- "@esbuild/win32-ia32": "0.25.2",
- "@esbuild/win32-x64": "0.25.2"
+ "@esbuild/aix-ppc64": "0.25.4",
+ "@esbuild/android-arm": "0.25.4",
+ "@esbuild/android-arm64": "0.25.4",
+ "@esbuild/android-x64": "0.25.4",
+ "@esbuild/darwin-arm64": "0.25.4",
+ "@esbuild/darwin-x64": "0.25.4",
+ "@esbuild/freebsd-arm64": "0.25.4",
+ "@esbuild/freebsd-x64": "0.25.4",
+ "@esbuild/linux-arm": "0.25.4",
+ "@esbuild/linux-arm64": "0.25.4",
+ "@esbuild/linux-ia32": "0.25.4",
+ "@esbuild/linux-loong64": "0.25.4",
+ "@esbuild/linux-mips64el": "0.25.4",
+ "@esbuild/linux-ppc64": "0.25.4",
+ "@esbuild/linux-riscv64": "0.25.4",
+ "@esbuild/linux-s390x": "0.25.4",
+ "@esbuild/linux-x64": "0.25.4",
+ "@esbuild/netbsd-arm64": "0.25.4",
+ "@esbuild/netbsd-x64": "0.25.4",
+ "@esbuild/openbsd-arm64": "0.25.4",
+ "@esbuild/openbsd-x64": "0.25.4",
+ "@esbuild/sunos-x64": "0.25.4",
+ "@esbuild/win32-arm64": "0.25.4",
+ "@esbuild/win32-ia32": "0.25.4",
+ "@esbuild/win32-x64": "0.25.4"
}
},
"node_modules/escalade": {
@@ -2273,19 +2210,19 @@
}
},
"node_modules/eslint": {
- "version": "9.24.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.24.0.tgz",
- "integrity": "sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==",
+ "version": "9.27.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz",
+ "integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==",
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.20.0",
- "@eslint/config-helpers": "^0.2.0",
- "@eslint/core": "^0.12.0",
+ "@eslint/config-helpers": "^0.2.1",
+ "@eslint/core": "^0.14.0",
"@eslint/eslintrc": "^3.3.1",
- "@eslint/js": "9.24.0",
- "@eslint/plugin-kit": "^0.2.7",
+ "@eslint/js": "9.27.0",
+ "@eslint/plugin-kit": "^0.3.1",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.2",
@@ -2394,6 +2331,15 @@
"node": ">=10.13.0"
}
},
+ "node_modules/eslint/node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/eslint/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -2695,6 +2641,19 @@
"node": "6.* || 8.* || >= 10.*"
}
},
+ "node_modules/get-east-asian-width": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz",
+ "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -2985,31 +2944,10 @@
"node": ">= 14"
}
},
- "node_modules/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "BSD-3-Clause"
- },
"node_modules/ignore": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
- "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz",
+ "integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==",
"license": "MIT",
"engines": {
"node": ">= 4"
@@ -3803,14 +3741,17 @@
"node": ">=8.6"
}
},
- "node_modules/mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "node_modules/mimic-function": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=6"
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/minimatch": {
@@ -3839,25 +3780,25 @@
}
},
"node_modules/mocha": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz",
- "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==",
+ "version": "11.5.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.5.0.tgz",
+ "integrity": "sha512-VKDjhy6LMTKm0WgNEdlY77YVsD49LZnPSXJAaPNL9NRYQADxvORsyG1DIQY6v53BKTnlNbEE2MbVCDbnxr4K3w==",
"dev": true,
"license": "MIT",
"dependencies": {
- "ansi-colors": "^4.1.3",
"browser-stdout": "^1.3.1",
- "chokidar": "^3.5.3",
+ "chokidar": "^4.0.1",
"debug": "^4.3.5",
- "diff": "^5.2.0",
+ "diff": "^7.0.0",
"escape-string-regexp": "^4.0.0",
"find-up": "^5.0.0",
"glob": "^10.4.5",
"he": "^1.2.0",
"js-yaml": "^4.1.0",
"log-symbols": "^4.1.0",
- "minimatch": "^5.1.6",
+ "minimatch": "^9.0.5",
"ms": "^2.1.3",
+ "picocolors": "^1.1.1",
"serialize-javascript": "^6.0.2",
"strip-json-comments": "^3.1.1",
"supports-color": "^8.1.1",
@@ -3874,17 +3815,34 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
- "node_modules/mocha/node_modules/minimatch": {
- "version": "5.1.6",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
- "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "node_modules/mocha/node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dev": true,
- "license": "ISC",
+ "license": "MIT",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "readdirp": "^4.0.1"
},
"engines": {
- "node": ">=10"
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/mocha/node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
}
},
"node_modules/mocha/node_modules/supports-color": {
@@ -4211,16 +4169,16 @@
}
},
"node_modules/onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+ "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "mimic-fn": "^2.1.0"
+ "mimic-function": "^5.0.0"
},
"engines": {
- "node": ">=6"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -4244,24 +4202,24 @@
}
},
"node_modules/ora": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz",
- "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==",
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz",
+ "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
- "cli-cursor": "^4.0.0",
- "cli-spinners": "^2.9.0",
+ "cli-cursor": "^5.0.0",
+ "cli-spinners": "^2.9.2",
"is-interactive": "^2.0.0",
- "is-unicode-supported": "^1.3.0",
- "log-symbols": "^5.1.0",
- "stdin-discarder": "^0.1.0",
- "string-width": "^6.1.0",
+ "is-unicode-supported": "^2.0.0",
+ "log-symbols": "^6.0.0",
+ "stdin-discarder": "^0.2.2",
+ "string-width": "^7.2.0",
"strip-ansi": "^7.1.0"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -4288,28 +4246,41 @@
"license": "MIT"
},
"node_modules/ora/node_modules/is-unicode-supported": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
- "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=12"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ora/node_modules/log-symbols": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz",
- "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz",
+ "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "chalk": "^5.0.0",
- "is-unicode-supported": "^1.1.0"
+ "chalk": "^5.3.0",
+ "is-unicode-supported": "^1.3.0"
},
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+ "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+ "dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -4318,18 +4289,18 @@
}
},
"node_modules/ora/node_modules/string-width": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz",
- "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "eastasianwidth": "^0.2.0",
- "emoji-regex": "^10.2.1",
- "strip-ansi": "^7.0.1"
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -4488,6 +4459,13 @@
"node": ">=4"
}
},
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -4723,29 +4701,22 @@
}
},
"node_modules/restore-cursor": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
- "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+ "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2"
+ "onetime": "^7.0.0",
+ "signal-exit": "^4.1.0"
},
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/restore-cursor/node_modules/signal-exit": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/reusify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@@ -4856,9 +4827,9 @@
}
},
"node_modules/semver": {
- "version": "7.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
- "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -5093,16 +5064,13 @@
"license": "CC0-1.0"
},
"node_modules/stdin-discarder": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz",
- "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==",
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
+ "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "bl": "^5.0.0"
- },
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -5349,9 +5317,9 @@
}
},
"node_modules/tapable": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
- "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
+ "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -5450,9 +5418,9 @@
"license": "0BSD"
},
"node_modules/tsyringe": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.9.1.tgz",
- "integrity": "sha512-dJCWk0RolAnGk0j839M0lcuS/PtNUPaMsnBosn+wg5N16xy0tofcVuvsidMs0JuRbaJ0wVIT7RsuHWbVIZ5Rcg==",
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz",
+ "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==",
"license": "MIT",
"dependencies": {
"tslib": "^1.9.3"
@@ -5565,14 +5533,14 @@
}
},
"node_modules/typescript-eslint": {
- "version": "8.29.1",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.29.1.tgz",
- "integrity": "sha512-f8cDkvndhbQMPcysk6CUSGBWV+g1utqdn71P5YKwMumVMOG/5k7cHq0KyG4O52nB0oKS4aN2Tp5+wB4APJGC+w==",
+ "version": "8.32.1",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.32.1.tgz",
+ "integrity": "sha512-D7el+eaDHAmXvrZBy1zpzSNIRqnCOrkwTgZxTu3MUqRWk8k0q9m9Ho4+vPf7iHtgUfrK/o8IZaEApsxPlHTFCg==",
"license": "MIT",
"dependencies": {
- "@typescript-eslint/eslint-plugin": "8.29.1",
- "@typescript-eslint/parser": "8.29.1",
- "@typescript-eslint/utils": "8.29.1"
+ "@typescript-eslint/eslint-plugin": "8.32.1",
+ "@typescript-eslint/parser": "8.32.1",
+ "@typescript-eslint/utils": "8.32.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
diff --git a/package.json b/package.json
index 3b51272..3d929c6 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"icon": "images/vba-lsp-icon.png",
"author": "SSlinky",
"license": "MIT",
- "version": "1.5.13",
+ "version": "1.7.1",
"repository": {
"type": "git",
"url": "https://github.com/SSlinky/VBA-LanguageServer"
@@ -49,9 +49,9 @@
],
"iconThemes": [
{
- "id": "vba-lsp",
- "label": "VBA Icons",
- "path": "icon-theme.json"
+ "id": "vs-seti-vba",
+ "label": "Seti + VBA",
+ "path": "icons/theme-seti/icons/vs-seti-icon-theme.json"
}
],
"configurationDefaults": {
@@ -170,21 +170,21 @@
"dependencies": {
"antlr4ng": "^3.0.16",
"reflect-metadata": "^0.2.2",
- "tsyringe": "^4.9.1",
- "typescript-eslint": "^8.29.1"
+ "tsyringe": "^4.10.0",
+ "typescript-eslint": "^8.32.1"
},
"devDependencies": {
"@types/mocha": "^10.0.10",
- "@types/node": "^22.14.0",
+ "@types/node": "^22.15.21",
"@typescript-eslint/eslint-plugin": "^8.29.0",
"@typescript-eslint/parser": "^8.29.0",
"@vscode/test-cli": "^0.0.10",
- "@vscode/test-electron": "^2.4.1",
+ "@vscode/test-electron": "^2.5.2",
"antlr4ng-cli": "^2.0.0",
- "esbuild": "^0.25.2",
- "eslint": "^9.24.0",
+ "esbuild": "^0.25.4",
+ "eslint": "^9.27.0",
"js-yaml": "^4.1.0",
- "mocha": "^11.1.0",
+ "mocha": "^11.5.0",
"npm-run-all": "^4.1.5",
"typescript": "^5.8.3",
"vscode-tmgrammar-test": "^0.1.3"
diff --git a/server/src/antlr/vba.g4 b/server/src/antlr/vba.g4
index 7122bf2..399378c 100644
--- a/server/src/antlr/vba.g4
+++ b/server/src/antlr/vba.g4
@@ -861,7 +861,7 @@ identifierStatementLabel
: ambiguousIdentifier
;
-resetNumberLable
+resetNumberLabel
: MINUS INTEGERLITERAL
;
@@ -1312,7 +1312,7 @@ onErrorStatement
errorBehavior
: RESUME wsc NEXT
| GOTO wsc? statementLabel
- | GOTO wsc? resetNumberLable
+ | GOTO wsc? resetNumberLabel
;
// 5.4.4.2 Resume Statement
@@ -2062,11 +2062,6 @@ reservedTypeIdentifierB
| VARIANT_B
;
-typeableReservedName
- : DATE
- | STRING
- ;
-
literalIdentifier
: booleanLiteralIdentifier
| objectLiteralIdentifier
@@ -2135,7 +2130,6 @@ builtinType
// This probably could be turned into a token
typedName
: ambiguousIdentifier typeSuffix
- | typeableReservedName typeSuffix
;
typeSuffix
diff --git a/server/src/capabilities/capabilities.ts b/server/src/capabilities/capabilities.ts
index 23b0839..dea7f41 100644
--- a/server/src/capabilities/capabilities.ts
+++ b/server/src/capabilities/capabilities.ts
@@ -1,9 +1,9 @@
// Core
import {
- Diagnostic,
+ DiagnosticSeverity,
+ LocationLink,
+ Position,
Range,
- SemanticTokenModifiers,
- SemanticTokenTypes,
SymbolInformation,
SymbolKind
} from 'vscode-languageserver';
@@ -12,11 +12,12 @@ import {
import { ParserRuleContext, TerminalNode } from 'antlr4ng';
// Project
-import { SemanticToken } from '../capabilities/semanticTokens';
+import { SemanticToken, SemanticTokenModifiers, SemanticTokenTypes } from '../capabilities/semanticTokens';
import { FoldingRange, FoldingRangeKind } from '../capabilities/folding';
import { BaseRuleSyntaxElement, BaseIdentifyableSyntaxElement, BaseSyntaxElement, Context, HasSemanticTokenCapability } from '../project/elements/base';
-import { BaseDiagnostic, DuplicateDeclarationDiagnostic, MethodVariableIsPublicDiagnostic, ShadowDeclarationDiagnostic, SubOrFunctionNotDefinedDiagnostic, VariableNotDefinedDiagnostic } from './diagnostics';
+import { AmbiguousNameDiagnostic, BaseDiagnostic, DuplicateDeclarationDiagnostic, ShadowDeclarationDiagnostic, SubOrFunctionNotDefinedDiagnostic, UnusedDiagnostic, VariableNotDefinedDiagnostic } from './diagnostics';
import { Services } from '../injection/services';
+import { isPositionInsideRange } from '../utils/helpers';
abstract class BaseCapability {
@@ -55,10 +56,10 @@ export class FoldingRangeCapability extends BaseCapability {
export class DiagnosticCapability extends BaseCapability {
- diagnostics: Diagnostic[] = [];
- evaluate: (...args: any[]) => Diagnostic[];
+ diagnostics: BaseDiagnostic[] = [];
+ evaluate: (...args: any[]) => BaseDiagnostic[];
- constructor(element: BaseSyntaxElement, evaluate?: (...args: any[]) => Diagnostic[]) {
+ constructor(element: BaseSyntaxElement, evaluate?: (...args: any[]) => BaseDiagnostic[]) {
super(element);
this.evaluate = evaluate ?? (() => this.diagnostics);
}
@@ -66,11 +67,6 @@ export class DiagnosticCapability extends BaseCapability {
export class SemanticTokenCapability extends BaseCapability {
- private tokenType: SemanticTokenTypes;
- private tokenModifiers: SemanticTokenModifiers[];
- private overrideRange?: Range;
- private overrideLength?: number;
-
get semanticToken(): SemanticToken {
const element = this.element as BaseRuleSyntaxElement & HasSemanticTokenCapability;
const context = element.identifierCapability
@@ -92,19 +88,17 @@ export class SemanticTokenCapability extends BaseCapability {
);
}
- constructor(element: BaseRuleSyntaxElement & HasSemanticTokenCapability, tokenType: SemanticTokenTypes, tokenModifiers: SemanticTokenModifiers[], overrideRange?: Range, overrideLength?: number) {
+ constructor(element: BaseRuleSyntaxElement,
+ private tokenType: SemanticTokenTypes,
+ private tokenModifiers: SemanticTokenModifiers[],
+ private overrideRange?: Range,
+ private overrideLength?: number) {
super(element);
- this.tokenType = tokenType;
- this.tokenModifiers = tokenModifiers;
- this.overrideRange = overrideRange;
- this.overrideLength = overrideLength;
}
}
export class SymbolInformationCapability extends BaseCapability {
- private symbolKind: SymbolKind;
-
get SymbolInformation(): SymbolInformation {
const element = this.element as BaseIdentifyableSyntaxElement;
return SymbolInformation.create(
@@ -115,55 +109,69 @@ export class SymbolInformationCapability extends BaseCapability {
);
}
- constructor(element: BaseIdentifyableSyntaxElement, symbolKind: SymbolKind) {
+ constructor(element: BaseIdentifyableSyntaxElement, private symbolKind: SymbolKind) {
super(element);
- this.symbolKind = symbolKind;
}
}
-interface IdentifierArgs {
- element: BaseRuleSyntaxElement,
- getNameContext?: () => ParserRuleContext | TerminalNode | null | undefined,
- formatName?: (name: string) => string,
- defaultName?: string;
- defaultRange?: () => Range;
-}
-
export class IdentifierCapability extends BaseCapability {
- nameContext: ParserRuleContext | TerminalNode;
- range: Range;
- name: string;
- isDefaultMode: boolean;
-
- constructor(args: IdentifierArgs) {
- super(args.element);
+ private get unformattedName(): string {
+ const nameCtx = this.getNameContext ? this.getNameContext() : this.nameContext;
+ return nameCtx?.getText() ?? this.defaultName ?? "Unknown Element";
+ }
- this.nameContext = ((args.getNameContext ?? (() => args.element.context.rule))() ?? args.element.context.rule);
- this.isDefaultMode = !(!!args.getNameContext && !!args.getNameContext());
+ get name(): string {
+ return this.formatName
+ ? this.formatName(this.unformattedName)
+ : this.unformattedName;
+ }
- if (!this.isDefaultMode) {
- // Use the context to set the values.
- this.name = (args.formatName ?? ((name: string) => name))(this.nameContext.getText());
- this.range = this.nameContext.toRange(args.element.context.document);
- } else {
- // Use the defaults to set the values.
- if (!args.defaultRange) throw new Error("Default range not optional where name context not found.");
- this.name = (args.defaultName ?? "Unknown Element");
- this.range = args.defaultRange ? args.defaultRange() : args.element.context.range;
+ get range(): Range {
+ if (this.getNameContext) {
+ const ctx = this.getNameContext();
+ if (ctx) {
+ return ctx.toRange(this.element.context.document);
+ } else if (this.defaultRange) {
+ return this.defaultRange();
+ }
+ Services.logger.warn(`Unable to get name context or default for ${this.name}`);
}
+ return this.element.context.range;
+ }
+
+ get nameContext(): ParserRuleContext | TerminalNode {
+ return this.getNameContext
+ ? this.getNameContext() ?? this.element.context.rule
+ : this.element.context.rule;
+ }
+
+ get isDefaultMode(): boolean {
+ return !(!!this.getNameContext && !!this.getNameContext());
+ }
+
+ constructor(
+ readonly element: BaseRuleSyntaxElement,
+ private getNameContext?: () => ParserRuleContext | TerminalNode | null | undefined,
+ private formatName?: (name: string) => string,
+ private defaultName?: string,
+ private defaultRange?: () => Range
+ ) {
+ super(element);
}
}
-export enum ItemType {
+export enum ScopeType {
/** Base language. */
VBA,
/** Application model. */
APPLICATION,
/** The user's project. */
PROJECT,
- /** Class/Module/Form. */
+ /** Class/Form. */
+ CLASS,
+ /** Module. */
MODULE,
/** Function declaration. */
FUNCTION,
@@ -175,6 +183,8 @@ export enum ItemType {
TYPE,
/** Variable declaration. */
VARIABLE,
+ /** A variable declaration in a signature */
+ PARAMETER,
/** Any reference type that isn't a declaration. */
REFERENCE
}
@@ -184,7 +194,8 @@ export enum AssignmentType {
GET = 1 << 0,
LET = 1 << 1,
SET = 1 << 2,
- CALL = 1 << 3
+ CALL = 1 << 3,
+ CONST = 1 << 4
}
export class ScopeItemCapability {
@@ -198,30 +209,74 @@ export class ScopeItemCapability {
setters?: Map,
letters?: Map
};
+ parameters?: Map;
references?: Map;
+ // Special scope references for easier resolution of names.
+ implicitDeclarations?: Map;
+
// Links
link?: ScopeItemCapability;
- backLinks?: ScopeItemCapability[];
+ backlinks?: ScopeItemCapability[];
// Technical
isDirty: boolean = true;
- private get isMethodScope(): boolean {
- return [
- ItemType.SUBROUTINE,
- ItemType.FUNCTION,
- ItemType.PROPERTY,
- ].includes(this.type);
+ isInvalidated = false;
+
+ get maps() {
+ const result: Map[] = [];
+ const addToResult = (map: Map | undefined) => {
+ if (map) result.push(map);
+ };
+ addToResult(this.types);
+ addToResult(this.modules);
+ addToResult(this.functions);
+ addToResult(this.subroutines);
+ addToResult(this.properties?.getters);
+ addToResult(this.properties?.letters);
+ addToResult(this.properties?.setters);
+ addToResult(this.references);
+
+ return result;
+ }
+
+ get explicitDeclarations() {
+ const result: Map[] = [];
+ const addToResult = (map: Map | undefined) => {
+ if (map) result.push(map);
+ };
+ addToResult(this.types);
+ addToResult(this.modules);
+ addToResult(this.functions);
+ addToResult(this.subroutines);
+
+ return result;
+ }
+
+ get hasScopeBody(): boolean {
+ return this.type !== ScopeType.VARIABLE
+ && this.type !== ScopeType.REFERENCE
+ && this.type !== ScopeType.PARAMETER;
+ }
+
+ get assignmentTypeText(): string {
+ const enumNamesAndValues = Object.values(AssignmentType);
+ const enumValues = enumNamesAndValues.slice(enumNamesAndValues.length / 2 + 1);
+ const result = `${enumValues.map(x => AssignmentType[this.assignmentType & x as number]).filter(x => x !== 'NONE').join('|')}`;
+
+ return result === '' ? 'NONE' : result;
}
// Item Properties
- explicitSetName?: string;
- isPublicScope = false;
- visibilityModifierContext?: ParserRuleContext;
+ locationUri?: string;
+ isPublicScope?: boolean;
+ accessMembers?: ParserRuleContext[];
+ isOptionExplicitScope = false;
+ classTypeName?: string;
constructor(
readonly element?: BaseRuleSyntaxElement,
- public type: ItemType = ItemType.REFERENCE,
+ public type: ScopeType = ScopeType.REFERENCE,
public assignmentType: AssignmentType = AssignmentType.NONE,
public parent?: ScopeItemCapability,
) { }
@@ -230,27 +285,41 @@ export class ScopeItemCapability {
* Recursively build from this node down.
*/
build(): void {
- if (this.type === ItemType.REFERENCE) {
+ this.deleteInvalidatedScopes();
+ this.cleanInvalidatedLinks();
+
+ // Don't build self if invalidated.
+ if (this.isInvalidated) {
+ return;
+ }
+
+ if (this.type === ScopeType.REFERENCE) {
// Link to declaration if it exists.
this.resolveLinks();
+ const abc = 0;
if (!this.link) {
// TODO:
// References to variables should get a diagnostic if they aren't declared.
- // -- No option explicit: gets a hint with code action to declare.
- // -- Option explicit: gets an error with code action to declare.
+ // -- No option explicit: Hint with code action to declare.
+ // GET before declared gets a warning.
+ // -- Option explicit: Error with code action to declare.
// -- Subsequent explicit declaration should raise duplicate declaration (current bahaviour).
+ // -- All declarations with no GET references get a warning.
// References to function or sub calls should raise an error if they aren't declared.
// -- Must always throw even when option explicit not present.
// -- Nothing required on first reference as declaration may come later.
- const diagnosticType = this.assignmentType & AssignmentType.CALL
- ? SubOrFunctionNotDefinedDiagnostic
- : VariableNotDefinedDiagnostic;
- this.pushDiagnostic(diagnosticType);
+ const severity = this.isOptionExplicitScope
+ ? DiagnosticSeverity.Error
+ : DiagnosticSeverity.Hint;
+ const _ = this.assignmentType & AssignmentType.CALL
+ ? this.pushDiagnostic(SubOrFunctionNotDefinedDiagnostic, this, this.name)
+ : this.pushDiagnostic(VariableNotDefinedDiagnostic, this, this.name, severity);
}
} else {
// Diagnostic checks on declarations.
- this.resolveDuplicateDeclarations();
- this.resolveShadowedDeclarations();
+ const ancestors = this.getParentChain();
+ this.resolveDuplicateDeclarations(ancestors);
+ this.resolveShadowedDeclarations(ancestors);
}
// Call build on children.
@@ -261,14 +330,66 @@ export class ScopeItemCapability {
this.properties?.getters?.forEach(items => items.forEach(item => item.build()));
this.properties?.letters?.forEach(items => items.forEach(item => item.build()));
this.properties?.setters?.forEach(items => items.forEach(item => item.build()));
+ this.references?.forEach(items => items.forEach(item => item.build()));
this.isDirty = false;
}
+ resolveUnused(): void {
+ // Don't diagnose projects, classes or modules.
+ // Don't diagnose publically declared items.
+ // Don't diagnose if we have backlinks.
+ const isUsed: boolean = this.type === ScopeType.CLASS
+ || this.type === ScopeType.MODULE
+ || this.isPublicScope
+ || (!!this.backlinks && this.backlinks.length > 0)
+ || !this.element
+ || !this.element.identifierCapability;
+
+ if (!isUsed) {
+ const identifier = this.element?.identifierCapability;
+ const diagnostics = this.element?.diagnosticCapability?.diagnostics;
+ if (identifier && diagnostics) {
+ diagnostics.push(new UnusedDiagnostic(identifier.range, identifier.name));
+ }
+ }
+
+ if (!this.hasScopeBody) {
+ return;
+ }
+
+ // Recursively call this method on child declarations.
+ this.types?.forEach(items => items.forEach(item => item.resolveUnused()));
+ this.modules?.forEach(items => items.forEach(item => item.resolveUnused()));
+ this.functions?.forEach(items => items.forEach(item => item.resolveUnused()));
+ this.subroutines?.forEach(items => items.forEach(item => item.resolveUnused()));
+ this.properties?.getters?.forEach(items => items.forEach(item => item.resolveUnused()));
+ this.properties?.letters?.forEach(items => items.forEach(item => item.resolveUnused()));
+ this.properties?.setters?.forEach(items => items.forEach(item => item.resolveUnused()));
+ }
+
+ /** Returns the chain of parents for bottom up name resolution. */
+ getParentChain(items: ScopeItemCapability[] = []): ScopeItemCapability[] {
+ items.push(this);
+ return this.parent?.getParentChain(items) ?? items;
+ }
+
+ /** Prints the hierarchy of scopes from this node down. */
+ printToDebug(level: number = 0) {
+ const p = this.isPublicScope ? '[P] ' : ' ';
+ Services.logger.debug(`${p}${this.name}`, level);
+
+ this.maps.forEach(
+ maps => maps.forEach(
+ items => items.forEach(
+ item => item.printToDebug(level + 1)
+ )));
+ }
+
/** Resolves for the current scope, i.e., children of the current item. */
- private resolveDuplicateDeclarations() {
+ private resolveDuplicateDeclarations(ancestors: ScopeItemCapability[]) {
// Reference types are never relevant.
- if (this.type == ItemType.REFERENCE) {
+ if (this.type == ScopeType.REFERENCE) {
return;
}
@@ -340,87 +461,99 @@ export class ScopeItemCapability {
});
}
- private resolveShadowedDeclaration(item: ScopeItemCapability | undefined): void {
- if (item) {
- const diagnostic = this.pushDiagnostic(ShadowDeclarationDiagnostic);
- this.addDiagnosticReference(diagnostic, item);
+ private resolveShadowedDeclarations(ancestors: ScopeItemCapability[]) {
+ // Don't check for shadowed declarations if we're above project level.
+ if (ancestors.length < 3) {
+ return;
}
- }
- private resolveShadowedDeclarations() {
- // Get the parent of the scope where this element is registered.
- const parent = this.parent?.parent;
- if (!parent) {
- return;
+ for (let i = 2; i < ancestors.length; i++) {
+ const ancestor = ancestors[i];
+ const shadowing = ancestor
+ .getAccessibleScopes(this.name)
+ .filter(item => item.parent?.name !== this.parent?.name);
+
+ if (shadowing.length > 0) {
+ const diagnostic = this.pushDiagnostic(ShadowDeclarationDiagnostic, this, this.name);
+ if (diagnostic === undefined) {
+ continue;
+ }
+ shadowing.forEach(item => this.addDiagnosticReference(diagnostic, item));
+ }
}
+ }
- // All declaration types check for modules.
- this.resolveShadowedDeclaration(parent.findType(this.identifier));
- this.resolveShadowedDeclaration(parent.findModule(this.identifier));
- this.resolveShadowedDeclaration(parent.findFunction(this.identifier));
- this.resolveShadowedDeclaration(parent.findSubroutine(this.identifier));
+ private resolveLinks() {
- // Properties care about everything except properties that
- // aren't the same type. Everything else cares about everything.
+ // Resolve where we have no member access names.
+ if (!this.accessMembers || this.accessMembers.length === 0) {
+ const declarations = this.findDeclarations(this.identifier, this.assignmentType);
+ if (declarations === undefined || declarations.length === 0) {
+ return;
+ }
- // ToDo:
- // Variables are registered as props so should also squash their
- // get/set/let diagnostics into one single diagnostic.
+ if (declarations.length > 1) {
+ const diagnostic = this.pushDiagnostic(AmbiguousNameDiagnostic, this, this.identifier);
+ this.addScopesAsRelatedInformation(diagnostic, declarations);
+ return;
+ }
- // Check get properties.
- if (this.assignmentType & AssignmentType.GET) {
- this.resolveShadowedDeclaration(parent.findPropertyGetter(this.identifier));
+ this.linkThisToItem(declarations[0]);
+ return;
}
- // Check let properties.
- if (this.assignmentType & AssignmentType.LET) {
- this.resolveShadowedDeclaration(parent.findPropertyLetter(this.identifier));
- }
+ // Resolve for member accessed names.
+ let foundDeclarations: ScopeItemCapability[] = [];
+ for (const [i, ctx] of this.accessMembers.entries()) {
+ // Get the scope item to search and exit if we don't have anything.
+ const searchScope = i === 0 ? this
+ : foundDeclarations.length === 0
+ ? this.project
+ : foundDeclarations[0];
+
+ // Can't do anything more if we don't have a scope to search.
+ if (searchScope === undefined) {
+ return;
+ }
- // Check set properties.
- if (this.assignmentType & AssignmentType.SET) {
- this.resolveShadowedDeclaration(parent.findPropertySetter(this.identifier));
- }
- }
+ // Get the details of what we're searching for.
+ const name = ctx.getText();
+ const assignmentType = i < this.accessMembers.length - 1
+ ? AssignmentType.GET
+ : this.assignmentType;
- private resolveLinks() {
- /**
- * Call Foo(bar)
- * ^^^ NONE
- * ^^^ GET
- *
- * Let foo = bar
- * ^^^ LET
- * ^^^ GET
- *
- * Set foo = bar
- * ^^^ SET
- * ^^^ GET
- */
-
- // Handle calls that aren't assignments.
- if (this.assignmentType === AssignmentType.CALL) {
- this.linkThisToItem(this.findFunction(this.identifier));
- this.linkThisToItem(this.findSubroutine(this.identifier));
- return;
- }
+ // Search the immediate scope hierarchy if this is the first member.
+ foundDeclarations = searchScope.findDeclarations(name, assignmentType) ?? [];
- // Handle get/set/let relationships.
- if (this.assignmentType & AssignmentType.GET) {
- this.linkThisToItem(this.findFunction(this.identifier));
- this.linkThisToItem(this.findPropertyGetter(this.identifier));
- return;
- }
+ // If we didn't find anything, try searching the type.
+ if (foundDeclarations.length === 0 && searchScope.classTypeName !== undefined) {
+ foundDeclarations = this.project?.findDeclarations(searchScope.classTypeName, assignmentType) ?? [];
+ foundDeclarations = foundDeclarations[0]?.findDeclarations(name, assignmentType) ?? [];
+ }
- if (this.assignmentType & AssignmentType.LET) {
- this.linkThisToItem(this.findPropertyLetter(this.identifier));
- return;
- }
+ // Exactly one means we found something.
+ if (foundDeclarations.length === 1) {
+ continue;
+ }
- if (this.assignmentType & AssignmentType.SET) {
- this.linkThisToItem(this.findPropertySetter(this.identifier));
- return;
+ // Nothing found means we can't continue.
+ if (foundDeclarations.length === 0) {
+ return;
+ }
+
+ // More than one declaration is ambiguous.
+ if (foundDeclarations.length > 1) {
+ const document = this.element?.context.document;
+ if (document) {
+ const diagnostic = new AmbiguousNameDiagnostic(ctx.toRange(document), '');
+ this.addScopesAsRelatedInformation(diagnostic, foundDeclarations);
+ }
+ return;
+ }
}
+
+ // If we get here, we have resolved the member access name.
+ this.linkThisToItem(foundDeclarations[0]);
}
private linkThisToItem(linkItem?: ScopeItemCapability): void {
@@ -429,22 +562,67 @@ export class ScopeItemCapability {
}
this.link = linkItem;
- linkItem.backLinks ??= [];
- linkItem.backLinks.push(this);
+ linkItem.backlinks ??= [];
+ linkItem.backlinks.push(this);
}
- private removeBacklink(backlinkedItem: ScopeItemCapability): void {
- if (!this.backLinks) {
- return;
+ private deleteInvalidatedScopes() {
+ const removeInvalidatedScopes = (map: Map | undefined) => {
+ if (!map) return;
+
+ const result = new Map();
+ for (const [name, scopes] of map) {
+ const filteredScopes = scopes.filter(x => !x.isInvalidated);
+ if (filteredScopes.length > 0) {
+ result.set(name, filteredScopes);
+ }
+ }
+ if (result.size !== 0) {
+ return result;
+ }
+ };
+
+ this.types = removeInvalidatedScopes(this.types);
+ this.modules = removeInvalidatedScopes(this.modules);
+ this.functions = removeInvalidatedScopes(this.functions);
+ this.subroutines = removeInvalidatedScopes(this.subroutines);
+ if (this.properties) {
+ this.properties.getters = removeInvalidatedScopes(this.properties?.getters);
+ this.properties.setters = removeInvalidatedScopes(this.properties?.setters);
+ this.properties.letters = removeInvalidatedScopes(this.properties?.letters);
}
+ this.parameters = removeInvalidatedScopes(this.parameters);
+ this.references = removeInvalidatedScopes(this.references);
+ this.implicitDeclarations = removeInvalidatedScopes(this.implicitDeclarations);
+ }
+
+ private cleanInvalidatedLinks() {
+ const removeLinks = (map: Map | undefined) => {
+ map?.forEach((scopes) => scopes.forEach(scope => {
+ if (scope.link && scope.link.isInvalidated) {
+ scope.link = undefined;
+ }
+ if (scope.backlinks) {
+ scope.backlinks = scope.backlinks.filter(link => !link.isInvalidated);
+ if (scope.backlinks.length === 0) scope.backlinks = undefined;
+ }
+ }));
+ };
- const keep = this.backLinks.filter(x => x !== backlinkedItem);
- this.backLinks = keep.length === 0 ? undefined : keep;
+ removeLinks(this.types);
+ removeLinks(this.modules);
+ removeLinks(this.functions);
+ removeLinks(this.subroutines);
+ removeLinks(this.properties?.getters);
+ removeLinks(this.properties?.setters);
+ removeLinks(this.properties?.letters);
+ removeLinks(this.parameters);
+ removeLinks(this.references);
}
/** Returns the module this scope item falls under */
get module(): ScopeItemCapability | undefined {
- if (this.type == ItemType.MODULE) {
+ if (this.type === ScopeType.MODULE || this.type === ScopeType.CLASS) {
return this;
}
return this.parent?.module;
@@ -452,23 +630,57 @@ export class ScopeItemCapability {
/** Returns the project this scope item falls under */
get project(): ScopeItemCapability | undefined {
- if (this.type == ItemType.PROJECT) {
+ if (this.type == ScopeType.PROJECT) {
return this;
}
return this.parent?.project;
}
get identifier(): string {
- if (this.type === ItemType.PROPERTY) {
+ if (this.type === ScopeType.PROPERTY) {
return this.name.split(' ')[1];
}
return this.name;
}
get name(): string {
- return this.explicitSetName
- ?? this.element?.identifierCapability?.name
- ?? 'Unknown';
+ return this.element?.identifierCapability?.name ?? 'Unknown';
+ }
+
+ has(identifier: string): boolean {
+ for (const map of this.maps) {
+ if (map.has(identifier)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Get accessible declarations */
+ getAccessibleScopes(identifier: string, results: ScopeItemCapability[] = []): ScopeItemCapability[] {
+ // Add any non-public items we find at this level.
+ this.maps.forEach(map => {
+ map.get(identifier)?.forEach(item => {
+ if (!item.isPublicScope) {
+ results.push(item);
+ }
+ });
+ });
+
+ // Get all public scope types if we're at the project level.
+ if (this.type === ScopeType.PROJECT) {
+ this.modules?.forEach(modules => modules.forEach(
+ module => module.maps.forEach(map => {
+ map.get(identifier)?.forEach(item => {
+ if (item.isPublicScope) {
+ results.push(item);
+ }
+ });
+ })
+ ));
+ }
+
+ return this.parent?.getAccessibleScopes(identifier, results) ?? results;
}
findType(identifier: string): ScopeItemCapability | undefined {
@@ -506,77 +718,125 @@ export class ScopeItemCapability {
?? this.parent?.findPropertySetter(identifier);
}
+ findDeclarations(identifier: string, assignmentType: AssignmentType): ScopeItemCapability[] | undefined {
+ const explicitResult = this.explicitDeclarations
+ .map(x => x.get(identifier))
+ .filter(x => !!x)
+ .flat();
+
+ if (assignmentType & AssignmentType.GET) {
+ this.properties?.getters?.get(identifier)?.forEach(x =>
+ explicitResult.push(x)
+ );
+ }
+
+ if (assignmentType & AssignmentType.SET) {
+ this.properties?.setters?.get(identifier)?.forEach(x =>
+ explicitResult.push(x)
+ );
+ }
+
+ if (assignmentType & AssignmentType.LET) {
+ this.properties?.letters?.get(identifier)?.forEach(x =>
+ explicitResult.push(x)
+ );
+ }
+
+ if (explicitResult.length > 0) {
+ return explicitResult;
+ }
+
+ const implicitResult = this.implicitDeclarations
+ ?.get(identifier);
+
+ if (implicitResult && implicitResult.length > 0) {
+ return implicitResult;
+ }
+
+ return this.parent?.findDeclarations(identifier, assignmentType);
+ }
+
/**
* Registers a scope and returns the new current scope.
* @param item The scope item to register.
* @returns The current scope.
*/
registerScopeItem(item: ScopeItemCapability): ScopeItemCapability {
- // ToDo: Get the parent based on visibility.
- // Public scoped elements should get the project.
- // Check pub/priv declares in same document treated as duplicate instead of shadowed.
-
- /**
- * Visibility on a method-scoped variable does nothing but isn't invalid.
- * These should declare as if they're private and raise a warning.
- */
-
- const getParent = (item: ScopeItemCapability): ScopeItemCapability =>
- (item.isPublicScope ? this.project : this) ?? this;
-
- // Method-scoped variables are always private.
- if (this.isMethodScope && item.type === ItemType.VARIABLE && item.isPublicScope) {
- item.isPublicScope = false;
- if (item.visibilityModifierContext && item.element) {
- const ctx = item.visibilityModifierContext;
- const diagnostic = new MethodVariableIsPublicDiagnostic(
- ctx.toRange(item.element.context.document),
- ItemType[this.type]
- );
- item.element?.diagnosticCapability?.diagnostics.push(diagnostic);
- }
+ // Immediately invalidate if we're an Unknown Module
+ if (item.type === ScopeType.MODULE && item.name === 'Unknown Module') {
+ item.isInvalidated = true;
}
// Set the parent for the item.
- item.parent = getParent(item);
+ item.parent = this; // getParent(item);
item.parent.isDirty = true;
+ // Set the URI from the parent if we don't have one.
+ if (item.locationUri === undefined) {
+ item.locationUri = item.parent.locationUri;
+ }
+
// Get the scope level for logging.
const getAncestorLevel = (item: ScopeItemCapability, level: number): number =>
item.parent ? getAncestorLevel(item.parent, level + 1) : level;
+
+
+ item.isPublicScope = this.getVisibility(item);
+ const visibility = item.isPublicScope ? 'public' : 'private';
+ const assignment = item.assignmentTypeText;
const ancestorLevel = getAncestorLevel(this, 0);
- Services.logger.debug(`Registering [${item.isPublicScope ? 'public' : 'private'} ${ItemType[item.type]}] ${item.name}`, ancestorLevel);
+ Services.logger.debug(`Registering [${visibility} ${ScopeType[item.type]} ${assignment}] ${item.name}`, ancestorLevel);
+
+ // Inherit option explicit property.
+ if (item.parent.isOptionExplicitScope) {
+ this.isOptionExplicitScope = true;
+ }
// Reference types are not declarations.
- if (item.type === ItemType.REFERENCE) {
+ if (item.type === ScopeType.REFERENCE) {
item.parent.references ??= new Map();
item.parent.addItem(item.parent.references, item);
return this;
}
+ // Add implicitly accessible names to the project scope.
+ if (item.isPublicScope && this.project) {
+ this.project.implicitDeclarations ??= new Map();
+ this.addItem(this.project.implicitDeclarations, item, item.name);
+ }
+
// Register functions.
- if (item.type === ItemType.FUNCTION) {
+ if (item.type === ScopeType.FUNCTION) {
item.parent.functions ??= new Map();
item.parent.addItem(item.parent.functions, item);
return item;
}
// Register subroutine.
- if (item.type === ItemType.SUBROUTINE) {
+ if (item.type === ScopeType.SUBROUTINE) {
item.parent.subroutines ??= new Map();
item.parent.addItem(item.parent.subroutines, item);
return item;
}
// Register enum or type.
- if (item.type === ItemType.TYPE) {
+ if (item.type === ScopeType.TYPE) {
item.parent.types ??= new Map();
item.parent.addItem(item.parent.types, item);
return item;
}
+ // Register parameters.
+ if (item.type === ScopeType.PARAMETER) {
+ item.parent.parameters ??= new Map();
+ item.parent.addItem(item.parent.parameters, item);
+ }
+
// Register properties and variables.
- if (item.type === ItemType.PROPERTY || item.type === ItemType.VARIABLE) {
+ const isGetSetLetType = item.type === ScopeType.PROPERTY
+ || item.type === ScopeType.VARIABLE
+ || item.type === ScopeType.PARAMETER;
+ if (isGetSetLetType) {
item.parent.properties ??= {};
if (item.assignmentType & AssignmentType.GET) {
item.parent.properties.getters ??= new Map();
@@ -590,11 +850,11 @@ export class ScopeItemCapability {
item.parent.properties.setters ??= new Map();
item.parent.addItem(item.parent.properties.setters, item);
}
- return item.type === ItemType.PROPERTY ? item : this;
+ return item.type === ScopeType.PROPERTY ? item : this;
}
// Handle module registration
- if (item.type === ItemType.MODULE) {
+ if (item.type === ScopeType.MODULE || item.type === ScopeType.CLASS) {
item.parent.modules ??= new Map();
item.parent.addItem(item.parent.modules, item);
return item;
@@ -604,70 +864,166 @@ export class ScopeItemCapability {
return item;
}
- // Would be relatively simple to also do this via a "dirty" flag.
- /** Removes all elements with references to the document uri. */
- invalidate(uri: string): void {
- const unlink = (item: ScopeItemCapability): void => {
- // Remove backlink from linked item.
- item.link?.removeBacklink(item);
- // Remove link from any backlinked items.
- item.backLinks?.forEach(node => node.link = undefined);
- };
+ invalidateModule(uri: string): void {
+ const module = this.findModuleByUri(uri);
+ module?.invalidate();
+ }
- const scan = (map: Map | undefined, uri: string) => {
- if (map === undefined) {
- return;
- }
+ invalidate(): void {
+ this.isInvalidated = true;
+ this.maps.forEach(
+ map => map.forEach(
+ scopes => scopes.forEach(
+ scope => scope.invalidate()
+ )));
+ }
+
+ /** Returns true for public and false for private */
+ private getVisibility(item: ScopeItemCapability): boolean {
+ // Classes and modules are always public.
+ if (item.parent?.type === ScopeType.PROJECT) {
+ return true;
+ }
+
+ // Module members can explicitly set their access or default
+ // to private. TODO: multi-project requires another scope layer
+ // to control access between projects.
+ // Public members of Option Private Modules are scoped to project.
+ if (item.parent?.type === ScopeType.MODULE) {
+ // Variables default to private, everything else deafults public.
+ return item.isPublicScope ?? item.type !== ScopeType.VARIABLE;
+ }
+
+ // Everything else is private.
+ return false;
+ }
- const keys = Array.from(map.keys());
- keys.forEach(key => {
- const items = map.get(key)!;
- const keep = items.filter(item => item.element?.context.document.uri !== uri);
- const remove = items.filter(item => item.element?.context.document.uri === uri);
+ private findModuleByUri(uri: string): ScopeItemCapability | undefined {
+ const moduleName = uri.split('/').at(-1)?.split('.').slice(0, -1).join('.');
+ if (!moduleName) {
+ Services.logger.error(`Bad URI or name: ${moduleName} from ${uri}`);
+ return;
+ }
- // Sever links for items to be removed.
- remove.forEach(x => unlink(x));
+ const modules = this.modules?.get(moduleName);
+ if (!modules) {
+ Services.logger.error(`No such module: ${moduleName}`);
+ return;
+ }
- // Update the map.
- if (keep.length === 0) {
- map.delete(key);
- } else {
- map.set(key, keep);
+ if (modules.length > 1) {
+ Services.logger.error(`Module name ambiguity: ${modules.length} found.`);
+ return;
+ }
+
+ return modules[0];
+ }
+
+ private getItemsIdentifiedAtPosition(position: Position, results: ScopeItemCapability[] = [], searchItems: ScopeItemCapability[] = []): void {
+ while (searchItems.length > 0) {
+ const scope = searchItems.pop();
+
+ // Check all items for whether they have a name overlap or a scope overlap.
+ scope?.maps.forEach(map => map.forEach(items => items.forEach(item => {
+ const elementRange = item.element?.context.range;
+ const identifierRange = item.element?.identifierCapability?.range;
+ if (identifierRange && isPositionInsideRange(position, identifierRange)) {
+ // Position is inside the identifier, push to results.
+ results.push(item);
+ } else if (elementRange && isPositionInsideRange(position, elementRange)) {
+ // Position is inside element, queue to be searched.
+ searchItems.push(item);
}
- });
- };
+ })));
+ }
+ }
+
+ getRenameItems(uri: string, position: Position): ScopeItemCapability[] {
+ const module = this.findModuleByUri(uri);
+ if (!module) {
+ return [];
+ }
+
+ const itemsAtPosition: ScopeItemCapability[] = [];
+ this.getItemsIdentifiedAtPosition(position, itemsAtPosition, [module]);
+ if (itemsAtPosition.length === 0) {
+ Services.logger.warn(`Nothing to rename.`);
+ return [];
+ }
+
+ // Switch to the linked declaration if we have one.
+ const swapRefsForDeclarations = itemsAtPosition.map(
+ item => item.link ? item.link : item);
+
+ // Replace property items with all properties of same name.
+ const propertyIncludedItems = swapRefsForDeclarations.map(item =>
+ item.type === ScopeType.PROPERTY && item.parent?.properties
+ ? [
+ item.parent.properties.getters?.get(item.identifier),
+ item.parent.properties.setters?.get(item.identifier),
+ item.parent.properties.letters?.get(item.identifier)
+ ]
+ : item
+ ).flat().flat().flat().filter(x => !!x);
+
+ // Add backlinks for each item.
+ const addedBacklinks = propertyIncludedItems.map(item =>
+ item.backlinks ? [item, ...item.backlinks] : item
+ ).flat().flat();
+
+ const uniqueItemsAtPosition = this.removeDuplicatesByRange(addedBacklinks);
+ return uniqueItemsAtPosition;
+ }
+
+ getDeclarationLocation(uri: string, position: Position): LocationLink[] | undefined {
+ const module = this.findModuleByUri(uri);
+ if (!module) {
+ return;
+ }
+
+ const itemsAtPosition: ScopeItemCapability[] = [];
+ this.getItemsIdentifiedAtPosition(position, itemsAtPosition, [module]);
+ return itemsAtPosition.map(x => x.toLocationLink()).filter(x => !!x);
+ }
+
+ toLocationLink(): LocationLink | undefined {
+ const link = this.link;
+
+ if (!link || !link.locationUri || !link.element || !link.element.identifierCapability) {
+ return;
+ }
+
+ return LocationLink.create(
+ link.locationUri,
+ link.element.context.range,
+ link.element.identifierCapability.range,
+ this.element?.context.range
+ );
+ }
- // Invalidate and unlink items.
- scan(this.types, uri);
- scan(this.modules, uri);
- scan(this.functions, uri);
- scan(this.subroutines, uri);
- if (this.properties !== undefined) {
- scan(this.properties.getters, uri);
- scan(this.properties.letters, uri);
- scan(this.properties.setters, uri);
- }
- scan(this.references, uri);
-
- // Call invalidate on children.
- this.types?.forEach(items => items.forEach(item => item.invalidate(uri)));
- this.modules?.forEach(items => items.forEach(item => item.invalidate(uri)));
- this.functions?.forEach(items => items.forEach(item => item.invalidate(uri)));
- this.subroutines?.forEach(items => items.forEach(item => item.invalidate(uri)));
- this.properties?.getters?.forEach(items => items.forEach(item => item.invalidate(uri)));
- this.properties?.letters?.forEach(items => items.forEach(item => item.invalidate(uri)));
- this.properties?.setters?.forEach(items => items.forEach(item => item.invalidate(uri)));
- }
-
- private addItem(target: Map, item: ScopeItemCapability): void {
+ private addItem(target: Map, item: ScopeItemCapability, name?: string): void {
const items = target.get(item.identifier) ?? [];
items.push(item);
- target.set(item.identifier, items);
+ target.set(name ?? item.identifier, items);
+ }
+
+ private hasDiagnostic(diagnostic: BaseDiagnostic): boolean {
+ const diagnostics = this.element?.diagnosticCapability?.diagnostics;
+ if (!diagnostics || diagnostics.length === 0) {
+ return false;
+ }
+
+ for (const pushedDiagnostic of diagnostics) {
+ if (diagnostic.equals(pushedDiagnostic)) {
+ return true;
+ }
+ }
+ return false;
}
/**
* Generates and pushes a diagnostic to the underlying element on the scope item.
- * No diagnostic is created unless we have both a range and the capability on the element.
+ * No diagnostic is created unless we have a range, the capability on the element, and no duplicate exists.
* Range is automatically injected into the constructor but arguments can't be verified at compile time, so it's on you to check.
* @param ctor The diagnostic we're creating.
* @param item The scope item to get the range from.
@@ -679,8 +1035,42 @@ export class ScopeItemCapability {
const diagnostics = (item ?? this).element?.diagnosticCapability?.diagnostics;
if (range && diagnostics) {
const diagnostic = new ctor(...[range, args].flat());
+ if (this.hasDiagnostic(diagnostic)) {
+ return;
+ }
diagnostics.push(diagnostic);
return diagnostic;
}
}
+
+ private addScopesAsRelatedInformation(diagnostic: BaseDiagnostic | undefined, items: ScopeItemCapability[]): void {
+ if (diagnostic === undefined) {
+ return;
+ }
+
+ items.forEach(item => {
+ const ctx = item.element?.context;
+ if (ctx === undefined) {
+ return;
+ }
+ diagnostic.addRelatedInformation({
+ message: "Related Information",
+ location: {
+ uri: ctx.document.uri,
+ range: ctx.range
+ }
+ });
+ });
+ }
+
+ private removeDuplicatesByRange(results: ScopeItemCapability[]): ScopeItemCapability[] {
+ const rangeString = (r: Range | undefined): string => {
+ if (!r) return 'null';
+ return `${r.start.line}.${r.start.character}:${r.end.line}.${r.end.character}`;
+ };
+
+ const m = new Map();
+ results.forEach(s => m.set(rangeString(s.element?.context.range), s));
+ return Array.from(m.values());
+ }
}
\ No newline at end of file
diff --git a/server/src/capabilities/codeActions.ts b/server/src/capabilities/codeActions.ts
index 3c3dde3..b668f89 100644
--- a/server/src/capabilities/codeActions.ts
+++ b/server/src/capabilities/codeActions.ts
@@ -1,4 +1,7 @@
+// Core
import { CodeAction, Command, Diagnostic } from "vscode-languageserver";
+
+// Project
import { BaseDiagnostic } from "./diagnostics";
import { Services } from "../injection/services";
@@ -33,19 +36,19 @@ export class CodeActionsRegistry {
// Example params that are related to a diagnostic.
const onCodeActionParams = {
- "textDocument":{
- "uri":"file:///c%3A/Repos/vba-LanguageServer/sample/b.bas"
+ "textDocument": {
+ "uri": "file:///c%3A/Repos/vba-LanguageServer/sample/b.bas"
},
- "range":{"start":{"line":4,"character":1},"end":{"line":4,"character":1}},
- "context":{
- "diagnostics":[{
- "range":{"start":{"line":4,"character":1},"end":{"line":4,"character":1}},
- "message":"Option Explicit is missing from module header.",
- "data":{"uri":"file:///c%3A/Repos/vba-LanguageServer/sample/b.bas"},
- "code":"W001",
- "severity":2
+ "range": { "start": { "line": 4, "character": 1 }, "end": { "line": 4, "character": 1 } },
+ "context": {
+ "diagnostics": [{
+ "range": { "start": { "line": 4, "character": 1 }, "end": { "line": 4, "character": 1 } },
+ "message": "Option Explicit is missing from module header.",
+ "data": { "uri": "file:///c%3A/Repos/vba-LanguageServer/sample/b.bas" },
+ "code": "W001",
+ "severity": 2
}],
- "only":["quickfix"],
- "triggerKind":1
+ "only": ["quickfix"],
+ "triggerKind": 1
}
};
diff --git a/server/src/capabilities/diagnostics.ts b/server/src/capabilities/diagnostics.ts
index 4dd28d8..309a70c 100644
--- a/server/src/capabilities/diagnostics.ts
+++ b/server/src/capabilities/diagnostics.ts
@@ -32,6 +32,15 @@ export abstract class BaseDiagnostic implements Diagnostic {
}
this.relatedInformation.push(information);
}
+
+ equals(diagnostic: Diagnostic) {
+ return this.severity === diagnostic.severity
+ && this.message === diagnostic.message
+ && this.range.end.line === diagnostic.range.end.line
+ && this.range.start.line === diagnostic.range.start.line
+ && this.range.end.character === diagnostic.range.end.character
+ && this.range.start.character === diagnostic.range.start.character;
+ }
}
@@ -78,28 +87,37 @@ export class DuplicateDeclarationDiagnostic extends BaseDiagnostic {
}
+// test
+export class AmbiguousNameDiagnostic extends BaseDiagnostic {
+ severity = DiagnosticSeverity.Error;
+ constructor(range: Range, message: string) {
+ super(range);
+ this.message = `Ambiguous name detected: '${message}'.`;
+ }
+}
+
+
// test
export class ShadowDeclarationDiagnostic extends BaseDiagnostic {
- message = "Declaration is shadowed in the local scope.";
severity = DiagnosticSeverity.Warning;
- constructor(range: Range) {
+ constructor(range: Range, message: string) {
super(range);
+ this.message = `${message} is shadowed in the local scope.`;
}
}
export class VariableNotDefinedDiagnostic extends BaseDiagnostic {
- message = "Variable not defined.";
- severity = DiagnosticSeverity.Error;
- constructor(range: Range) {
+ constructor(range: Range, message: string, public severity: DiagnosticSeverity) {
super(range);
+ this.message = `Variable ${message} not defined.`;
}
}
export class SubOrFunctionNotDefinedDiagnostic extends BaseDiagnostic {
- message = "Sub or Function not defined.";
severity = DiagnosticSeverity.Error;
- constructor(range: Range) {
+ constructor(range: Range, message: string) {
super(range);
+ this.message = `Method ${message} not defined.`;
}
}
@@ -123,10 +141,9 @@ export class MethodVariableIsPublicDiagnostic extends BaseDiagnostic {
// test
export class UnexpectedLineEndingDiagnostic extends BaseDiagnostic {
- message = "Unexpected line ending.";
severity = DiagnosticSeverity.Error;
constructor(range: Range) {
- super(range);
+ super(range, 'Unexpected line ending.');
}
}
@@ -135,22 +152,31 @@ export class UnreachableCodeDiagnostic extends BaseDiagnostic {
severity = DiagnosticSeverity.Hint;
tags = [DiagnosticTag.Unnecessary];
constructor(range: Range) {
- super(range);
+ super(range, 'Unreachable code detected.');
+ }
+}
+
+// test
+export class UnusedDiagnostic extends BaseDiagnostic {
+ severity = DiagnosticSeverity.Hint;
+ tags = [DiagnosticTag.Unnecessary];
+ constructor(range: Range, message: string) {
+ super(range, `${message} is declared but its value is never read.`);
}
}
-export class IgnoredAttributeDiagnostic extends BaseDiagnostic {
- severity = DiagnosticSeverity.Warning;
+export class UnknownAttributeDiagnostic extends BaseDiagnostic {
+ severity = DiagnosticSeverity.Error;
constructor(range: Range, attributeName: string) {
- super(range, `Unknown attribute '${attributeName}' will be ignored.`);
+ super(range, `Unknown attribute '${attributeName}'.`);
}
}
export class MissingOptionExplicitDiagnostic extends BaseDiagnostic {
message = "Option Explicit is missing from module header.";
- severity = DiagnosticSeverity.Warning;
+ severity = DiagnosticSeverity.Hint;
constructor(range: Range) {
super(range);
@@ -159,10 +185,14 @@ export class MissingOptionExplicitDiagnostic extends BaseDiagnostic {
this.actionFactory = (diagnostic: Diagnostic, uri: string) =>
CodeAction.create(
"Insert Option Explicit",
- { changes: { [uri]: [{
- range: diagnostic.range,
- newText: "\nOption Explicit"
- }]}},
+ {
+ changes: {
+ [uri]: [{
+ range: diagnostic.range,
+ newText: "\nOption Explicit"
+ }]
+ }
+ },
CodeActionKind.QuickFix
);
diff --git a/server/src/capabilities/folding.ts b/server/src/capabilities/folding.ts
index 2456032..922a1df 100644
--- a/server/src/capabilities/folding.ts
+++ b/server/src/capabilities/folding.ts
@@ -1,3 +1,4 @@
+// Core
import { FoldingRange as VscFoldingRange, Range } from 'vscode-languageserver';
/**
diff --git a/server/src/capabilities/semanticTokens.ts b/server/src/capabilities/semanticTokens.ts
index c6ddc8f..1f2abe4 100644
--- a/server/src/capabilities/semanticTokens.ts
+++ b/server/src/capabilities/semanticTokens.ts
@@ -2,8 +2,6 @@
import {
InitializeResult,
Range,
- SemanticTokenModifiers,
- SemanticTokenTypes,
uinteger,
SemanticTokens
} from 'vscode-languageserver';
@@ -14,6 +12,45 @@ import { ParserRuleContext } from 'antlr4ng/dist/ParserRuleContext';
// Project
import { BaseRuleSyntaxElement, HasSemanticTokenCapability } from '../project/elements/base';
+export enum SemanticTokenTypes {
+ namespace = "namespace",
+ type = "type",
+ class = "class",
+ enum = "enum",
+ interface = "interface",
+ struct = "struct",
+ typeParameter = "typeParameter",
+ parameter = "parameter",
+ variable = "variable",
+ property = "property",
+ enumMember = "enumMember",
+ event = "event",
+ function = "function",
+ method = "method",
+ macro = "macro",
+ keyword = "keyword",
+ modifier = "modifier",
+ comment = "comment",
+ string = "string",
+ number = "number",
+ regexp = "regexp",
+ operator = "operator",
+ decorator = "decorator"
+}
+
+export enum SemanticTokenModifiers {
+ declaration = "declaration",
+ definition = "definition",
+ readonly = "readonly",
+ static = "static",
+ deprecated = "deprecated",
+ abstract = "abstract",
+ async = "async",
+ modification = "modification",
+ documentation = "documentation",
+ defaultLibrary = "defaultLibrary"
+}
+
const registeredTokenTypes = new Map((Object.keys(SemanticTokenTypes) as (keyof typeof SemanticTokenTypes)[]).map((k, i) => ([k, i])));
const registeredTokenModifiers = new Map((Object.keys(SemanticTokenModifiers) as (keyof typeof SemanticTokenModifiers)[]).map((k, i) => ([k, 2 ** i])));
@@ -33,18 +70,17 @@ type SemanticElementType = HasSemanticTokenCapability
& BaseRuleSyntaxElement;
export class SemanticToken {
- line: uinteger;
- char: uinteger;
- length: uinteger;
tokenType: uinteger;
tokenModifiers: uinteger = 0;
- element: SemanticElementType;
- constructor(element: SemanticElementType, line: uinteger, startChar: uinteger, length: uinteger, tokenType: SemanticTokenTypes, tokenModifiers: SemanticTokenModifiers[]) {
- this.element = element;
- this.line = line;
- this.char = startChar;
- this.length = length;
+ constructor(
+ public element: SemanticElementType,
+ public line: uinteger,
+ public char: uinteger,
+ public length: uinteger,
+ tokenType: SemanticTokenTypes,
+ tokenModifiers: SemanticTokenModifiers[]
+ ) {
this.tokenType = registeredTokenTypes.get(tokenType)!;
tokenModifiers.forEach((x) => this.tokenModifiers += registeredTokenModifiers.get(x) ?? 0);
}
diff --git a/server/src/extensions/antlrCoreExtensions.ts b/server/src/extensions/antlrCoreExtensions.ts
new file mode 100644
index 0000000..d067897
--- /dev/null
+++ b/server/src/extensions/antlrCoreExtensions.ts
@@ -0,0 +1,153 @@
+// Core
+import { Range } from 'vscode-languageserver';
+import { TextDocument } from 'vscode-languageserver-textdocument';
+
+// Antlr
+import { ParserRuleContext, TerminalNode } from 'antlr4ng';
+
+// Project
+import {
+ EndOfStatementContext,
+ EndOfStatementNoWsContext,
+ ProcedureTailContext
+} from '../antlr/out/vbaParser';
+import { LineEndingContext } from '../antlr/out/vbafmtParser';
+
+
+declare module 'antlr4ng' {
+ interface ParserRuleContext {
+ /** Convert the node to a range. */
+ toRange(doc: TextDocument): Range;
+ startIndex(): number;
+ stopIndex(): number;
+ hasPositionOf(ctx: ParserRuleContext): boolean;
+ endsWithLineEnding: boolean;
+ countTrailingLineEndings(): number;
+ }
+
+ interface TerminalNode {
+ /** Convert the node to a range. */
+ toRange(doc: TextDocument): Range;
+ startIndex(): number;
+ stopIndex(): number;
+ }
+}
+
+ParserRuleContext.prototype.toRange = function (doc: TextDocument): Range {
+ const startIndex = this.start?.start ?? 0;
+ const stopIndex = this.stop?.stop ?? startIndex;
+ return Range.create(
+ doc.positionAt(startIndex),
+ doc.positionAt(stopIndex + 1)
+ );
+};
+
+ParserRuleContext.prototype.startIndex = function (): number {
+ return this.start?.start ?? 0;
+};
+
+ParserRuleContext.prototype.stopIndex = function (): number {
+ return this.stop?.stop ?? this.startIndex();
+};
+
+ParserRuleContext.prototype.hasPositionOf = function (ctx: ParserRuleContext): boolean {
+ return this.startIndex() === ctx.startIndex() && this.stopIndex() === ctx.stopIndex();
+};
+
+Object.defineProperty(ParserRuleContext.prototype, 'endsWithLineEnding', {
+ get: function endsWithLineEnding() {
+ // Ensure we have a context.
+ if (!(this instanceof ParserRuleContext))
+ return false;
+
+ // Check last child is a line ending.
+ const child = this.children.at(-1);
+ if (!child)
+ return false;
+
+ // Check the various line ending contexts.
+ if (child instanceof LineEndingContext)
+ return true;
+ if (child instanceof EndOfStatementContext)
+ return true;
+ if (child instanceof EndOfStatementNoWsContext)
+ return true;
+ if (child instanceof ProcedureTailContext)
+ return true;
+
+ // Run it again!
+ if (child.getChildCount() > 0)
+ return (child as ParserRuleContext).endsWithLineEnding;
+
+ // Not a line ending and no more children.
+ return false;
+ }
+});
+
+interface LineEndingParserRuleContext {
+ NEWLINE(): TerminalNode | null;
+}
+
+function isLineEndingParserRuleContext(ctx: unknown): ctx is LineEndingParserRuleContext {
+ return typeof ctx === 'object'
+ && ctx !== null
+ && typeof (ctx as any).NEWLINE === 'function';
+}
+
+function countTrailingLineEndings(ctx: ParserRuleContext): number {
+ // This function recursively loops through last child of
+ // the context to find one that has a NEWLINE terminal node.
+
+ // Check if we have a NEWLINE node.
+ if (isLineEndingParserRuleContext(ctx)) {
+ const lines = ctx.NEWLINE()?.getText();
+ if (!lines) {
+ return 0;
+ }
+
+ let i = 0;
+ let result = 0;
+ while (i < lines.length) {
+ const char = lines[i];
+
+ if (char === '\r') {
+ result++;
+ i += lines[i + 1] === '\n' ? 2 : 1;
+ } else if (char === '\n') {
+ result++;
+ i++;
+ }
+ }
+
+ return result;
+ }
+
+ // Recursive call on last child.
+ const lastChild = ctx.children.at(-1);
+ if (lastChild instanceof ParserRuleContext) {
+ return countTrailingLineEndings(lastChild);
+ }
+
+ // If we get here, we have no trailing lines.
+ return 0;
+}
+
+ParserRuleContext.prototype.countTrailingLineEndings = function (): number {
+ return countTrailingLineEndings(this);
+};
+
+
+TerminalNode.prototype.toRange = function (doc: TextDocument): Range {
+ return Range.create(
+ doc.positionAt(this.startIndex()),
+ doc.positionAt(this.stopIndex() + 1)
+ );
+};
+
+TerminalNode.prototype.startIndex = function (): number {
+ return this.getPayload()?.start ?? 0;
+};
+
+TerminalNode.prototype.stopIndex = function (): number {
+ return this.getPayload()?.stop ?? this.startIndex();
+};
\ No newline at end of file
diff --git a/server/src/extensions/antlrVbaParserExtensions.ts b/server/src/extensions/antlrVbaParserExtensions.ts
new file mode 100644
index 0000000..f4c37b7
--- /dev/null
+++ b/server/src/extensions/antlrVbaParserExtensions.ts
@@ -0,0 +1,288 @@
+// Core
+import { SymbolKind } from 'vscode-languageserver';
+
+// Project
+import {
+ AmbiguousIdentifierContext,
+ ArrayClauseContext,
+ ArrayDesignatorContext,
+ ArrayDimContext,
+ AsClauseContext,
+ ConstItemContext,
+ LowerBoundContext,
+ PositionalParamContext,
+ TypeExpressionContext,
+ TypeSuffixContext,
+ UpperBoundContext,
+ VariableDclContext,
+ WitheventsVariableDclContext
+} from '../antlr/out/vbaParser';
+import { ParserRuleContext } from 'antlr4ng';
+
+export type ArrayDimension = {
+ lowerBound: number;
+ upperBound: number;
+}
+
+declare module '../antlr/out/vbaParser' {
+
+ interface ConstItemContext {
+ /** Shortcut to get the type context */
+ typeContext(): ParserRuleContext | undefined;
+ /** Extension method to get the symbol kind. */
+ toSymbolKind(): SymbolKind;
+ }
+
+ interface VariableDclContext {
+ /** Shortcut the identifier as we know it will always exist. */
+ ambiguousIdentifier(): AmbiguousIdentifierContext;
+ /** Shortcut to get the type context */
+ typeContext(): ParserRuleContext | undefined;
+ /** Extension method to get the symbol kind. */
+ toSymbolKind(): SymbolKind;
+ }
+
+ interface WitheventsVariableDclContext {
+ /** Shortcut the identifier as we know it will always exist. */
+ ambiguousIdentifier(): AmbiguousIdentifierContext;
+ /** Shortcut to get the type context */
+ typeContext(): ParserRuleContext | undefined;
+ /** Extension method to get the symbol kind. */
+ toSymbolKind(): SymbolKind;
+ }
+
+ interface PositionalParamContext {
+ /** Shortcut the identifier as we know it will always exist. */
+ ambiguousIdentifier(): AmbiguousIdentifierContext;
+ /** Shortcut to get the type context */
+ typeContext(): ParserRuleContext | undefined;
+ /** Extension method to get the symbol kind. */
+ toSymbolKind(): SymbolKind;
+ }
+
+ interface AsClauseContext {
+ isObject: boolean;
+ isVariant: boolean;
+ isPrimative: boolean;
+ classTypeName: string | undefined;
+ }
+
+ interface TypeExpressionContext {
+ isObject: boolean;
+ isVariant: boolean;
+ isPrimative: boolean;
+ classTypeName: string | undefined;
+ }
+
+ interface TypeSuffixContext {
+ isObject: boolean;
+ isVariant: boolean;
+ isPrimative: boolean;
+ classTypeName: string | undefined;
+ }
+
+ interface ArrayDesignatorContext {
+ isResizable: boolean;
+ getDimensions(): ArrayDimension[] | undefined;
+ }
+
+ interface ArrayDimContext {
+ isResizable: boolean;
+ getDimensions(): ArrayDimension[] | undefined;
+ }
+}
+
+ConstItemContext.prototype.typeContext = function (): ParserRuleContext | undefined {
+ return this.typeSuffix()
+ ?? this.constAsClause()?.builtinType();
+};
+
+VariableDclContext.prototype.ambiguousIdentifier = function (): AmbiguousIdentifierContext {
+ // A variable will always be typed or untyped.
+ return this.typedVariableDcl()?.typedName().ambiguousIdentifier()
+ ?? this.untypedVariableDcl()!.ambiguousIdentifier();
+};
+
+
+VariableDclContext.prototype.typeContext = function (): ParserRuleContext | undefined {
+ return this.typedVariableDcl()?.typedName().typeSuffix()
+ ?? this.untypedVariableDcl()?.asClause()?.asType()?.typeSpec()
+ ?? this.untypedVariableDcl()?.asClause()?.asAutoObject()?.classTypeName();
+};
+
+PositionalParamContext.prototype.ambiguousIdentifier = function (): AmbiguousIdentifierContext {
+ return this.paramDcl().untypedNameParamDcl()?.ambiguousIdentifier()
+ ?? this.paramDcl().typedNameParamDcl()!.typedName().ambiguousIdentifier()!;
+};
+
+PositionalParamContext.prototype.typeContext = function (): ParserRuleContext | undefined {
+ return this.paramDcl().untypedNameParamDcl()?.parameterType()?.typeExpression()
+ ?? this.paramDcl().typedNameParamDcl()?.typedName().typeSuffix();
+};
+
+
+// Type Properties
+
+Object.defineProperty(TypeExpressionContext.prototype, "isPrimative", {
+ get: function (this: TypeExpressionContext): boolean {
+ return !!this.builtinType() && !this.isVariant;
+ }
+});
+
+Object.defineProperty(TypeExpressionContext.prototype, "isVariant", {
+ get: function (this: TypeExpressionContext): boolean {
+ return !!this.builtinType()?.reservedTypeIdentifier()?.VARIANT()
+ || !!this.builtinType()?.reservedTypeIdentifierB()?.VARIANT_B();
+ }
+});
+
+Object.defineProperty(TypeExpressionContext.prototype, "isObject", {
+ get: function (this: TypeExpressionContext): boolean {
+ return !this.isPrimative && !this.isVariant;
+ }
+});
+
+Object.defineProperty(TypeExpressionContext.prototype, "classTypeName", {
+ get: function (this: TypeExpressionContext): string | undefined {
+ return this.definedTypeExpression()?.getText();
+ }
+});
+
+Object.defineProperty(TypeSuffixContext.prototype, "isPrimative", {
+ get: function (this: TypeSuffixContext): boolean {
+ return true;
+ }
+});
+
+Object.defineProperty(TypeSuffixContext.prototype, "isVariant", {
+ get: function (this: TypeSuffixContext): boolean {
+ return false;
+ }
+});
+
+Object.defineProperty(TypeSuffixContext.prototype, "isObject", {
+ get: function (this: TypeSuffixContext): boolean {
+ return false;
+ }
+});
+
+Object.defineProperty(TypeSuffixContext.prototype, "classTypeName", {
+ get: function (this: TypeSuffixContext): string | undefined {
+ return undefined;
+ }
+});
+
+Object.defineProperty(AsClauseContext.prototype, "isPrimative", {
+ get: function (this: AsClauseContext): boolean {
+ const typeSpecContext = this.asType()?.typeSpec();
+ return !!(typeSpecContext
+ && (typeSpecContext.fixedLengthStringSpec() || typeSpecContext.typeExpression()?.isPrimative)
+ );
+ }
+});
+
+Object.defineProperty(AsClauseContext.prototype, "isVariant", {
+ get: function (this: AsClauseContext): boolean {
+ return this.asType()?.typeSpec().typeExpression()?.isVariant ?? false;
+ }
+});
+
+Object.defineProperty(AsClauseContext.prototype, "isObject", {
+ get: function (this: AsClauseContext): boolean {
+ const isAutoObject = !!this.asAutoObject();
+ const isTypeExprObject = !!(this.asType()?.typeSpec().typeExpression() ?? false);
+ return isAutoObject || isTypeExprObject;
+ }
+});
+
+Object.defineProperty(AsClauseContext.prototype, "classTypeName", {
+ get: function (this: AsClauseContext): string | undefined {
+ return this.isObject
+ ? this.asType()?.typeSpec().getText()
+ ?? this.asAutoObject()?.classTypeName().getText()
+ : undefined;
+ }
+});
+
+Object.defineProperty(ArrayDesignatorContext.prototype, "isResizable", {
+ get: function (this: ArrayDesignatorContext): boolean {
+ return false;
+ }
+});
+
+ArrayDesignatorContext.prototype.getDimensions = function (): ArrayDimension[] | undefined {
+ return undefined;
+};
+
+Object.defineProperty(ArrayClauseContext.prototype, "isResizable", {
+ get: function (this: ArrayClauseContext): boolean {
+ return !!this.arrayDim().boundsList();
+ }
+});
+
+ArrayDimContext.prototype.getDimensions = function (): ArrayDimension[] | undefined {
+ const boundsListCtx = this.boundsList();
+ const getNum = (boundCtx: LowerBoundContext | UpperBoundContext | null): number => {
+ const FIXME_DEFAULT = 0;
+ const n = boundCtx?.constantExpression().expression().literalExpression()?.INTEGERLITERAL()?.getText();
+ return n === undefined ? FIXME_DEFAULT : Number.parseInt(n);
+ };
+ return !boundsListCtx ? undefined : boundsListCtx.dimSpec().map(dimensionCtx => {
+ return {
+ lowerBound: getNum(dimensionCtx.lowerBound()),
+ upperBound: getNum(dimensionCtx.upperBound())
+ };
+ });
+};
+
+
+// SymbolKind
+
+ConstItemContext.prototype.toSymbolKind = function (): SymbolKind {
+ return toSymbolKind(this.typeContext());
+};
+
+
+WitheventsVariableDclContext.prototype.toSymbolKind = function (): SymbolKind {
+ return toSymbolKind(this.typeContext());
+};
+
+
+VariableDclContext.prototype.toSymbolKind = function (): SymbolKind {
+ return toSymbolKind(this.typeContext());
+};
+
+PositionalParamContext.prototype.toSymbolKind = function (): SymbolKind {
+ return toSymbolKind(this.typeContext());
+};
+
+
+function toSymbolKind(context: ParserRuleContext | undefined): SymbolKind {
+ switch (context?.getText().toLocaleLowerCase()) {
+ case undefined:
+ return SymbolKind.Class;
+ case 'boolean':
+ return SymbolKind.Boolean;
+ case '$': // string
+ case 'byte':
+ case 'string':
+ return SymbolKind.String;
+ case '%': // integer
+ case '&': // long
+ case '^': // longlong
+ case '@': // decimal
+ case '!': // single
+ case '#': // double
+ case 'double':
+ case 'currency':
+ case 'integer':
+ case 'long':
+ case 'longPtr':
+ case 'longLong':
+ return SymbolKind.Number;
+ case 'object':
+ return SymbolKind.Object;
+ default:
+ return SymbolKind.Class;
+ }
+}
diff --git a/server/src/extensions/antlrVbaPreParserExtensions.ts b/server/src/extensions/antlrVbaPreParserExtensions.ts
new file mode 100644
index 0000000..992afbb
--- /dev/null
+++ b/server/src/extensions/antlrVbaPreParserExtensions.ts
@@ -0,0 +1,17 @@
+// Project
+import { CompilerConditionalStatementContext } from '../antlr/out/vbapreParser';
+
+
+declare module '../antlr/out/vbapreParser' {
+ interface CompilerConditionalStatementContext {
+ vbaExpression(): string;
+ }
+}
+
+
+CompilerConditionalStatementContext.prototype.vbaExpression = function (): string {
+ return (this.compilerIfStatement() ?? this.compilerElseIfStatement())!
+ .booleanExpression()
+ .getText()
+ .toLowerCase();
+};
diff --git a/server/src/extensions/parserExtensions.ts b/server/src/extensions/parserExtensions.ts
deleted file mode 100644
index 482da9e..0000000
--- a/server/src/extensions/parserExtensions.ts
+++ /dev/null
@@ -1,301 +0,0 @@
-// Core
-import { Range, SymbolKind } from 'vscode-languageserver';
-import { TextDocument } from 'vscode-languageserver-textdocument';
-
-// Antlr
-import { ParserRuleContext, TerminalNode } from 'antlr4ng';
-
-// Project
-import { CompilerConditionalStatementContext } from '../antlr/out/vbapreParser';
-import {
- AmbiguousIdentifierContext,
- BuiltinTypeContext,
- ClassTypeNameContext,
- ConstItemContext,
- EndOfStatementContext,
- EndOfStatementNoWsContext,
- ProcedureTailContext,
- TypeSpecContext,
- TypeSuffixContext,
- VariableDclContext,
- WitheventsVariableDclContext
-} from '../antlr/out/vbaParser';
-import { LineEndingContext } from '../antlr/out/vbafmtParser';
-
-
-declare module 'antlr4ng' {
- interface ParserRuleContext {
- /** Convert the node to a range. */
- toRange(doc: TextDocument): Range;
- startIndex(): number;
- stopIndex(): number;
- hasPositionOf(ctx: ParserRuleContext): boolean;
- endsWithLineEnding: boolean;
- countTrailingLineEndings(): number;
- }
-
- interface TerminalNode {
- /** Convert the node to a range. */
- toRange(doc: TextDocument): Range;
- startIndex(): number;
- stopIndex(): number;
- }
-}
-
-
-declare module '../antlr/out/vbapreParser' {
- interface CompilerConditionalStatementContext {
- vbaExpression(): string;
- }
-}
-
-
-declare module '../antlr/out/vbaParser' {
-
- interface ConstItemContext {
- /** Shortcut the identifier as we know it will always exist. */
- ambiguousIdentifier(): AmbiguousIdentifierContext;
- /** Shortcut to get the type context */
- typeContext(): BuiltinTypeContext | TypeSuffixContext | undefined;
- /** Extension method to get the symbol kind. */
- toSymbolKind(): SymbolKind;
- }
-
- interface VariableDclContext {
- /** Shortcut the identifier as we know it will always exist. */
- ambiguousIdentifier(): AmbiguousIdentifierContext;
- /** Shortcut to get the type context */
- typeContext(): TypeSpecContext | TypeSuffixContext | ClassTypeNameContext | undefined;
- /** Extension method to get the symbol kind. */
- toSymbolKind(): SymbolKind;
- }
-
- interface WitheventsVariableDclContext {
- /** Shortcut the identifier as we know it will always exist. */
- ambiguousIdentifier(): AmbiguousIdentifierContext;
- /** Shortcut to get the type context */
- typeContext(): TypeSpecContext | TypeSuffixContext | ClassTypeNameContext | undefined;
- /** Extension method to get the symbol kind. */
- toSymbolKind(): SymbolKind;
- }
-}
-
-
-ParserRuleContext.prototype.toRange = function (doc: TextDocument): Range {
- const startIndex = this.start?.start ?? 0;
- const stopIndex = this.stop?.stop ?? startIndex;
- return Range.create(
- doc.positionAt(startIndex),
- doc.positionAt(stopIndex + 1)
- );
-};
-
-ParserRuleContext.prototype.startIndex = function (): number {
- return this.start?.start ?? 0;
-};
-
-ParserRuleContext.prototype.stopIndex = function (): number {
- return this.stop?.stop ?? this.startIndex();
-};
-
-ParserRuleContext.prototype.hasPositionOf = function (ctx: ParserRuleContext): boolean {
- return this.startIndex() === ctx.startIndex() && this.stopIndex() === ctx.stopIndex();
-};
-
-Object.defineProperty(ParserRuleContext.prototype, 'endsWithLineEnding', {
- get: function endsWithLineEnding() {
- // Ensure we have a context.
- if (!(this instanceof ParserRuleContext))
- return false;
-
- // Check last child is a line ending.
- const child = this.children.at(-1);
- if (!child)
- return false;
-
- // Check the various line ending contexts.
- if (child instanceof LineEndingContext)
- return true;
- if (child instanceof EndOfStatementContext)
- return true;
- if (child instanceof EndOfStatementNoWsContext)
- return true;
- if (child instanceof ProcedureTailContext)
- return true;
-
- // Run it again!
- if (child.getChildCount() > 0)
- return (child as ParserRuleContext).endsWithLineEnding;
-
- // Not a line ending and no more children.
- return false;
- }
-});
-
-interface LineEndingParserRuleContext {
- NEWLINE(): TerminalNode | null;
-}
-
-function isLineEndingParserRuleContext(ctx: unknown): ctx is LineEndingParserRuleContext {
- return typeof ctx === 'object'
- && ctx !== null
- && typeof (ctx as any).NEWLINE === 'function';
-}
-
-function countTrailingLineEndings(ctx: ParserRuleContext): number {
- // This function recursively loops through last child of
- // the context to find one that has a NEWLINE terminal node.
-
- // Check if we have a NEWLINE node.
- if (isLineEndingParserRuleContext(ctx)) {
- const lines = ctx.NEWLINE()?.getText();
- if (!lines) {
- return 0;
- }
-
- let i = 0;
- let result = 0;
- while (i < lines.length) {
- const char = lines[i];
-
- if (char === '\r') {
- result++;
- i += lines[i + 1] === '\n' ? 2 : 1;
- } else if (char === '\n') {
- result++;
- i++;
- }
- }
-
- return result;
- }
-
- // Recursive call on last child.
- const lastChild = ctx.children.at(-1);
- if (lastChild instanceof ParserRuleContext) {
- return countTrailingLineEndings(lastChild);
- }
-
- // If we get here, we have no trailing lines.
- return 0;
-}
-
-ParserRuleContext.prototype.countTrailingLineEndings = function (): number {
- return countTrailingLineEndings(this);
-};
-
-
-TerminalNode.prototype.toRange = function (doc: TextDocument): Range {
- return Range.create(
- doc.positionAt(this.startIndex()),
- doc.positionAt(this.stopIndex() + 1)
- );
-};
-
-TerminalNode.prototype.startIndex = function (): number {
- return this.getPayload()?.start ?? 0;
-};
-
-TerminalNode.prototype.stopIndex = function (): number {
- return this.getPayload()?.stop ?? this.startIndex();
-};
-
-
-CompilerConditionalStatementContext.prototype.vbaExpression = function (): string {
- return (this.compilerIfStatement() ?? this.compilerElseIfStatement())!
- .booleanExpression()
- .getText()
- .toLowerCase();
-};
-
-
-
-VariableDclContext.prototype.ambiguousIdentifier = function (): AmbiguousIdentifierContext {
- // A variable will always be typed or untyped.
- return this.typedVariableDcl()?.typedName().ambiguousIdentifier()
- ?? this.untypedVariableDcl()!.ambiguousIdentifier();
-};
-
-
-VariableDclContext.prototype.typeContext = function (): TypeSpecContext | TypeSuffixContext | ClassTypeNameContext | undefined {
- return this.typedVariableDcl()?.typedName().typeSuffix()
- ?? this.untypedVariableDcl()?.asClause()?.asType()?.typeSpec()
- ?? this.untypedVariableDcl()?.asClause()?.asAutoObject()?.classTypeName();
-};
-
-
-// SymbolKind
-
-ConstItemContext.prototype.toSymbolKind = function (): SymbolKind {
- return toSymbolKind(this.typeContext());
-};
-
-
-WitheventsVariableDclContext.prototype.toSymbolKind = function (): SymbolKind {
- return toSymbolKind(this.typeContext());
-};
-
-
-VariableDclContext.prototype.toSymbolKind = function (): SymbolKind {
- return toSymbolKind(this.typeContext());
-};
-
-
-function toSymbolKind(context: BuiltinTypeContext | TypeSuffixContext | TypeSpecContext | ClassTypeNameContext | undefined): SymbolKind {
- switch (context?.getText().toLocaleLowerCase()) {
- case undefined:
- return SymbolKind.Class;
- case 'boolean':
- return SymbolKind.Boolean;
- case '$': // string
- case 'byte':
- case 'string':
- return SymbolKind.String;
- case '%': // integer
- case '&': // long
- case '^': // longlong
- case '@': // decimal
- case '!': // single
- case '#': // double
- case 'double':
- case 'currency':
- case 'integer':
- case 'long':
- case 'longPtr':
- case 'longLong':
- return SymbolKind.Number;
- case 'object':
- return SymbolKind.Object;
- default:
- return SymbolKind.Class;
- }
-}
-
-/**
- * const File: 1;
- const Module: 2;
- const Namespace: 3;
- const Package: 4;
- const Class: 5;
- const Method: 6;
- const Property: 7;
- const Field: 8;
- const Constructor: 9;
- const Enum: 10;
- const Interface: 11;
- const Function: 12;
- const Variable: 13;
- const Constant: 14;
- const String: 15;
- const Number: 16;
- const Boolean: 17;
- const Array: 18;
- const Object: 19;
- const Key: 20;
- const Null: 21;
- const EnumMember: 22;
- const Struct: 23;
- const Event: 24;
- const Operator: 25;
- const TypeParameter: 26;
- */
\ No newline at end of file
diff --git a/server/src/extensions/stringExtensions.ts b/server/src/extensions/stringExtensions.ts
index f8fb6fb..7f48100 100644
--- a/server/src/extensions/stringExtensions.ts
+++ b/server/src/extensions/stringExtensions.ts
@@ -1,9 +1,27 @@
-interface String {
- stripQuotes(): string;
-}
+// Core
+import { fileURLToPath, pathToFileURL } from "url";
+declare global {
+ interface String {
+ stripQuotes(): string;
+ toFilePath(): string;
+ toFileUri(): string;
+ }
+}
String.prototype.stripQuotes = function (): string {
const exp = /^"?(.*?)"?$/;
return exp.exec(this.toString())![1];
};
+
+String.prototype.toFilePath = function (): string {
+ return this.startsWith('file://')
+ ? fileURLToPath(this.toString())
+ : this.toString();
+};
+
+String.prototype.toFileUri = function (): string {
+ return !this.startsWith('file://')
+ ? pathToFileURL(this.toString()).href
+ : this.toString();
+};
diff --git a/server/src/injection/interface.ts b/server/src/injection/interface.ts
index 5e11959..3ff1ce3 100644
--- a/server/src/injection/interface.ts
+++ b/server/src/injection/interface.ts
@@ -1,15 +1,19 @@
+// Core
+import { TextDocument } from 'vscode-languageserver-textdocument';
+import { CancellationToken, WorkspaceFolder } from 'vscode-languageserver';
+
+// Project
import { LanguageServerConfiguration } from '../server';
import { BaseProjectDocument } from '../project/document';
-import { TextDocument } from 'vscode-languageserver-textdocument';
import { VbaFmtListener } from '../project/parser/vbaListener';
-import { CancellationToken } from 'vscode-languageserver';
+
export interface Logger {
- error(msg: string, lvl?: number): void;
- warn(msg: string, lvl?: number): void;
- info(msg: string, lvl?: number): void;
- log(msg: string, lvl?: number): void;
- debug(msg: string, lvl?: number): void;
+ error(msg: string, lvl?: number, e?: unknown): void;
+ warn(msg: string, lvl?: number, e?: unknown): void;
+ info(msg: string, lvl?: number, e?: unknown): void;
+ log(msg: string, lvl?: number, e?: unknown): void;
+ debug(msg: string, lvl?: number, e?: unknown): void;
stack(e: Error): void;
}
@@ -40,4 +44,5 @@ export interface IWorkspace {
parseDocument(projectDocument: BaseProjectDocument): Promise;
openDocument(document: TextDocument): void;
closeDocument(document: TextDocument): void;
+ addWorkspaceFolder(params: WorkspaceFolder): void;
}
\ No newline at end of file
diff --git a/server/src/injection/services.ts b/server/src/injection/services.ts
index 8cf22a0..39ecdd9 100644
--- a/server/src/injection/services.ts
+++ b/server/src/injection/services.ts
@@ -1,9 +1,12 @@
+// Core
import { container, InjectionToken } from 'tsyringe';
-import { Logger, IWorkspace, ILanguageServer } from './interface';
-import { LspLogger } from '../utils/logger';
import { _Connection, createConnection, ProposedFeatures } from 'vscode-languageserver/node';
-import { ScopeItemCapability } from '../capabilities/capabilities';
+
+// Project
+import { LspLogger } from '../utils/logger';
+import { Logger, IWorkspace, ILanguageServer } from './interface';
import { CodeActionsRegistry } from '../capabilities/codeActions';
+import { ScopeItemCapability } from '../capabilities/capabilities';
export class Services {
diff --git a/server/src/project/document.ts b/server/src/project/document.ts
index 31d3458..fb6a941 100644
--- a/server/src/project/document.ts
+++ b/server/src/project/document.ts
@@ -6,31 +6,30 @@ import { CancellationToken, Diagnostic, SymbolInformation, SymbolKind } from 'vs
import { ParserRuleContext } from 'antlr4ng';
// Project
+import { Services } from '../injection/services';
+import { IWorkspace } from '../injection/interface';
import { Dictionary } from '../utils/helpers';
import { SyntaxParser } from './parser/vbaParser';
import { FoldingRange } from '../capabilities/folding';
+import { VbaFmtListener } from './parser/vbaListener';
+import { BaseDiagnostic } from '../capabilities/diagnostics';
import { SemanticTokensManager } from '../capabilities/semanticTokens';
+import { ScopeItemCapability } from '../capabilities/capabilities';
import {
BaseRuleSyntaxElement,
BaseSyntaxElement,
- DeclarableElement,
HasDiagnosticCapability,
HasFoldingRangeCapability,
HasScopeItemCapability,
HasSemanticTokenCapability,
HasSymbolInformationCapability
} from './elements/base';
-
import {
PropertyDeclarationElement,
PropertyGetDeclarationElement,
PropertyLetDeclarationElement,
PropertySetDeclarationElement
} from './elements/procedure';
-import { VbaFmtListener } from './parser/vbaListener';
-import { Services } from '../injection/services';
-import { IWorkspace } from '../injection/interface';
-import { ScopeItemCapability } from '../capabilities/capabilities';
// TODO ---------------------------------------------
@@ -78,35 +77,6 @@ export abstract class BaseProjectDocument {
return this.subtractTextFromRanges(this.redactedElements.map(x => x.context.range));
}
- // async getDocumentConfiguration(): Promise {
- // // Get the stored configuration.
- // if (this.documentConfiguration) {
- // return this.documentConfiguration;
- // }
-
- // // Get the configuration from the client.
- // if (this.workspace.hasConfigurationCapability) {
- // this.documentConfiguration = await this.workspace.requestDocumentSettings(this.textDocument.uri);
- // if (this.documentConfiguration) {
- // return this.documentConfiguration;
- // }
- // }
-
- // // Use the defaults.
- // this.documentConfiguration = {
- // maxDocumentLines: 1500,
- // maxNumberOfProblems: 100,
- // doWarnOptionExplicitMissing: true,
- // environment: {
- // os: "Win64",
- // version: "Vba7"
- // }
- // };
- // return this.documentConfiguration;
- // }
-
- // clearDocumentConfiguration = () => this.documentConfiguration = undefined;
-
constructor(name: string, document: TextDocument) {
this.textDocument = document;
this.workspace = Services.workspace;
@@ -164,23 +134,27 @@ export abstract class BaseProjectDocument {
// };
// }
languageServerDiagnostics() {
+ const diagnostics = this.isClosed ? [] : this.diagnostics;
+ Services.logger.debug(`Sending diagnostics for ${this.textDocument.uri}`);
+ Services.logger.debug(JSON.stringify(diagnostics));
+
return {
uri: this.textDocument.uri,
version: this.version,
- diagnostics: this.isClosed ? [] : this.diagnostics
+ diagnostics: diagnostics
};
}
async formatParseVisit(token: CancellationToken): Promise {
try {
- return await (new SyntaxParser(Services.logger)).formatParseAsync(token, this);
+ return await (new SyntaxParser(Services.logger)).formatParse(token, this);
} catch (e) {
Services.logger.debug('caught doc');
throw e;
}
}
- async parseAsync(token: CancellationToken): Promise {
+ async parse(token: CancellationToken): Promise {
// Don't parse oversize documents.
if (await this.isOversize) {
Services.logger.debug(`Document oversize: ${this.textDocument.lineCount} lines.`);
@@ -190,20 +164,29 @@ export abstract class BaseProjectDocument {
}
// Parse the document.
- await (new SyntaxParser(Services.logger)).parseAsync(token, this);
+ await (new SyntaxParser(Services.logger)).parse(token, this);
const projectScope = this.currentScope.project;
const buildScope = projectScope?.isDirty ? projectScope : this.currentScope;
buildScope.build();
+ buildScope.resolveUnused();
// Evaluate the diagnostics.
- this.diagnostics = this.hasDiagnosticElements
+ const diagnostics = this.hasDiagnosticElements
.map(e => e.diagnosticCapability.evaluate())
.flat();
+ // Ensure diagnostics aren't reported twice.
+ // TODO: Redesign diagnostics so this isn't required.
+ diagnostics.forEach(diagnostic => {
+ if (!this.hasDiagnostic(diagnostic)) {
+ this.diagnostics.push(diagnostic);
+ }
+ });
+
this._isBusy = false;
};
- async formatParseAsync(token: CancellationToken): Promise {
+ async formatParse(token: CancellationToken): Promise {
// Don't parse oversize documents.
if (await this.isOversize) {
Services.logger.debug(`Document oversize: ${this.textDocument.lineCount} lines.`);
@@ -212,7 +195,7 @@ export abstract class BaseProjectDocument {
}
// Parse the document.
- return await (new SyntaxParser(Services.logger)).formatParseAsync(token, this);
+ return await (new SyntaxParser(Services.logger)).formatParse(token, this);
}
/**
@@ -316,6 +299,15 @@ export abstract class BaseProjectDocument {
return result.join('\r\n');
}
}
+
+ private hasDiagnostic(diagnostic: BaseDiagnostic): boolean {
+ for (const pushedDiagnostic of this.diagnostics) {
+ if (diagnostic.equals(pushedDiagnostic)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/server/src/project/elements/base.ts b/server/src/project/elements/base.ts
index 1026e0f..0a053db 100644
--- a/server/src/project/elements/base.ts
+++ b/server/src/project/elements/base.ts
@@ -3,7 +3,7 @@ import { Position, Range } from 'vscode-languageserver';
import { TextDocument } from 'vscode-languageserver-textdocument';
// Antlr
-import { Parser, ParserRuleContext, TerminalNode } from 'antlr4ng';
+import { ParserRuleContext, TerminalNode } from 'antlr4ng';
// Project
import {
@@ -33,7 +33,7 @@ export abstract class BaseSyntaxElement {
*/
constructor() {
let x: TerminalNode | ParserRuleContext;
-
+
}
}
diff --git a/server/src/project/elements/flow.ts b/server/src/project/elements/flow.ts
index 1228cc1..4d00190 100644
--- a/server/src/project/elements/flow.ts
+++ b/server/src/project/elements/flow.ts
@@ -9,7 +9,7 @@ import { DiagnosticCapability, FoldingRangeCapability } from '../../capabilities
import { BaseRuleSyntaxElement, HasDiagnosticCapability } from './base';
import { MultipleOperatorsDiagnostic, WhileWendDeprecatedDiagnostic } from '../../capabilities/diagnostics';
-export class IfElseBlock extends BaseRuleSyntaxElement {
+export class IfElseBlockElement extends BaseRuleSyntaxElement {
constructor(context: IfStatementContext, document: TextDocument) {
super(context, document);
this.foldingRangeCapability = new FoldingRangeCapability(this);
diff --git a/server/src/project/elements/generic.ts b/server/src/project/elements/generic.ts
index 57e9b5d..3e66dab 100644
--- a/server/src/project/elements/generic.ts
+++ b/server/src/project/elements/generic.ts
@@ -2,10 +2,10 @@
import { TextDocument } from 'vscode-languageserver-textdocument';
// Antlr
-import { ErrorNode, ParserRuleContext, TerminalNode } from 'antlr4ng';
+import { ErrorNode, TerminalNode } from 'antlr4ng';
// Project
-import { BaseRuleSyntaxElement, BaseSyntaxElement, Context } from './base';
+import { BaseSyntaxElement, Context } from './base';
import { DiagnosticCapability } from '../../capabilities/capabilities';
import { ParserErrorDiagnostic } from '../../capabilities/diagnostics';
diff --git a/server/src/project/elements/module.ts b/server/src/project/elements/module.ts
index c8bdc2f..6277b78 100644
--- a/server/src/project/elements/module.ts
+++ b/server/src/project/elements/module.ts
@@ -3,7 +3,7 @@ import { TextDocument } from 'vscode-languageserver-textdocument';
import { Diagnostic, Range, SymbolKind } from 'vscode-languageserver';
// Antlr
-import { ParserRuleContext } from 'antlr4ng';
+import { ParserRuleContext, TerminalNode } from 'antlr4ng';
import {
ClassModuleCodeElementContext,
ClassModuleContext,
@@ -17,8 +17,8 @@ import {
// Project
import { BaseRuleSyntaxElement, BaseIdentifyableSyntaxElement, HasDiagnosticCapability } from './base';
-import { DiagnosticCapability, IdentifierCapability, ItemType, ScopeItemCapability, SymbolInformationCapability } from '../../capabilities/capabilities';
-import { DuplicateAttributeDiagnostic, IgnoredAttributeDiagnostic, MissingAttributeDiagnostic, MissingOptionExplicitDiagnostic } from '../../capabilities/diagnostics';
+import { DiagnosticCapability, IdentifierCapability, ScopeType, ScopeItemCapability, SymbolInformationCapability } from '../../capabilities/capabilities';
+import { DuplicateAttributeDiagnostic, UnknownAttributeDiagnostic, MissingAttributeDiagnostic, MissingOptionExplicitDiagnostic } from '../../capabilities/diagnostics';
interface DocumentSettings {
@@ -29,7 +29,7 @@ interface DocumentSettings {
abstract class BaseModuleElement extends BaseIdentifyableSyntaxElement {
abstract attrubutes: ParserRuleContext[];
abstract diagnosticCapability: DiagnosticCapability;
- abstract hasOptionExplicit: boolean;
+ abstract scopeItemCapability: ScopeItemCapability;
settings: DocumentSettings;
symbolInformationCapability: SymbolInformationCapability;
@@ -38,7 +38,6 @@ abstract class BaseModuleElement extends BaseIdenti
super(ctx, doc);
this.settings = documentSettings;
this.symbolInformationCapability = new SymbolInformationCapability(this, symbolKind);
- this.scopeItemCapability = new ScopeItemCapability(this, ItemType.MODULE);
}
// Helpers
@@ -60,7 +59,7 @@ abstract class BaseModuleElement extends BaseIdenti
}
protected addOptionExplicitMissingDiagnostic(diagnostics: Diagnostic[], header: ClassModuleHeaderContext | ProceduralModuleHeaderContext): void {
- if (this.settings.doWarnOptionExplicitMissing && !this.hasOptionExplicit) {
+ if (this.settings.doWarnOptionExplicitMissing && !this.scopeItemCapability.isOptionExplicitScope) {
const startLine = header.stop?.line ?? 0 + 1;
diagnostics.push(new MissingOptionExplicitDiagnostic(
Range.create(startLine, 1, startLine, 1)
@@ -104,32 +103,38 @@ abstract class BaseModuleElement extends BaseIdenti
export class ModuleElement extends BaseModuleElement {
diagnosticCapability: DiagnosticCapability;
identifierCapability: IdentifierCapability;
+ scopeItemCapability: ScopeItemCapability;
attrubutes: ParserRuleContext[];
- hasOptionExplicit: boolean;
constructor(ctx: ProceduralModuleContext, doc: TextDocument, documentSettings: DocumentSettings) {
super(ctx, doc, documentSettings, SymbolKind.File);
this.attrubutes = ctx.proceduralModuleHeader().proceduralModuleAttr();
this.diagnosticCapability = new DiagnosticCapability(this);
+ this.scopeItemCapability = new ScopeItemCapability(this, ScopeType.MODULE);
+ this.scopeItemCapability.locationUri = doc.uri.toFileUri();
- this.hasOptionExplicit = this.evaluateHasOptionExplicit(ctx
+ this.scopeItemCapability.isOptionExplicitScope = this.evaluateHasOptionExplicit(ctx
.proceduralModuleBody()
.proceduralModuleCode()
.proceduralModuleCodeElement());
- this.identifierCapability = new IdentifierCapability({
- element: this,
- formatName: (x: string) => x.stripQuotes(),
- defaultName: 'Unknown Module',
- defaultRange: () => Range.create(this.context.range.start, this.context.range.start),
- getNameContext: () => ctx
- .proceduralModuleHeader()
- .proceduralModuleAttr()
- .map(x => x.nameAttr())
- .filter(x => !!x)[0]
- ?.STRINGLITERAL()
- });
+ const getIdentifierNameContext = () => this.context.rule
+ .proceduralModuleHeader()
+ .proceduralModuleAttr()
+ .map(x => x.nameAttr())
+ .filter(x => !!x)[0]
+ ?.STRINGLITERAL();
+ const getIdentifierFormattedName = (x: string) => x.stripQuotes();
+ const getIdentifierDefaultRange = () => Range.create(this.context.range.start, this.context.range.start);
+
+ this.identifierCapability = new IdentifierCapability(
+ this,
+ getIdentifierNameContext,
+ getIdentifierFormattedName,
+ 'Unknown Module',
+ getIdentifierDefaultRange
+ );
this.resolveConfiguration(
this.diagnosticCapability.diagnostics,
@@ -142,9 +147,9 @@ export class ModuleElement extends BaseModuleElement {
export class ClassElement extends BaseModuleElement {
diagnosticCapability: DiagnosticCapability;
identifierCapability: IdentifierCapability;
+ scopeItemCapability: ScopeItemCapability;
attrubutes: ParserRuleContext[];
- hasOptionExplicit: boolean;
constructor(ctx: ClassModuleContext, doc: TextDocument, documentSettings: DocumentSettings) {
super(ctx, doc, documentSettings, SymbolKind.File);
@@ -154,26 +159,31 @@ export class ClassElement extends BaseModuleElement {
ctx.classModuleHeader().ignoredClassAttr()
].flat();
this.diagnosticCapability = new DiagnosticCapability(this);
+ this.scopeItemCapability = new ScopeItemCapability(this, ScopeType.CLASS);
+ this.scopeItemCapability.locationUri = doc.uri.toFileUri();
- this.hasOptionExplicit = this.evaluateHasOptionExplicit(ctx
+ this.scopeItemCapability.isOptionExplicitScope = this.evaluateHasOptionExplicit(ctx
.classModuleBody()
.classModuleCode()
.classModuleCodeElement());
- let nameContextGetter;
+ let getIdentifierNameContext = (): TerminalNode | undefined => undefined;
if (ctx.classModuleHeader().nameAttr().length > 0) {
- nameContextGetter = () => ctx
+ getIdentifierNameContext = () => ctx
.classModuleHeader()
.nameAttr()[0]
.STRINGLITERAL();
}
- this.identifierCapability = new IdentifierCapability({
- element: this,
- formatName: (x: string) => x.stripQuotes(),
- defaultName: 'Unknown Class',
- defaultRange: () => Range.create(this.context.range.start, this.context.range.start),
- getNameContext: nameContextGetter
- });
+ const getIdentifierFormattedName = (x: string) => x.stripQuotes();
+ const getIdentifierDefaultRange = () => Range.create(this.context.range.start, this.context.range.start);
+
+ this.identifierCapability = new IdentifierCapability(
+ this,
+ getIdentifierNameContext,
+ getIdentifierFormattedName,
+ 'Unknown Class',
+ getIdentifierDefaultRange
+ );
this.resolveConfiguration(
this.diagnosticCapability.diagnostics,
@@ -189,7 +199,7 @@ export class ModuleIgnoredAttributeElement extends BaseRuleSyntaxElement {
- this.diagnosticCapability.diagnostics.push(new IgnoredAttributeDiagnostic(
+ this.diagnosticCapability.diagnostics.push(new UnknownAttributeDiagnostic(
this.context.range, this.context.text.split(' ')[1]
));
return this.diagnosticCapability.diagnostics;
diff --git a/server/src/project/elements/naming.ts b/server/src/project/elements/naming.ts
new file mode 100644
index 0000000..81f7fc3
--- /dev/null
+++ b/server/src/project/elements/naming.ts
@@ -0,0 +1,84 @@
+// Core
+import { TextDocument } from "vscode-languageserver-textdocument";
+
+// Antlr
+import { ParserRuleContext } from "antlr4ng";
+import {
+ AmbiguousIdentifierContext,
+ DictionaryAccessExpressionContext,
+ IndexExpressionContext,
+ LExpressionContext,
+ MemberAccessExpressionContext,
+ PositionalParamContext,
+ SimpleNameExpressionContext,
+ UnrestrictedNameContext,
+ WithMemberAccessExpressionContext,
+ WithStatementContext
+} from "../../antlr/out/vbaParser";
+
+// Project
+import { BaseRuleSyntaxElement } from "./base";
+import { AssignmentType, IdentifierCapability, ScopeType, ScopeItemCapability } from "../../capabilities/capabilities";
+
+
+export class WithStatementElement extends BaseRuleSyntaxElement {
+ nameExpressionElement?: NameExpressionElement;
+
+ get nameStack(): ParserRuleContext[] {
+ return this.nameExpressionElement?.nameStack ?? [];
+ }
+
+ constructor(ctx: WithStatementContext, doc: TextDocument) {
+ super(ctx, doc);
+ }
+}
+
+
+export type NameExpressionContext = LExpressionContext
+ | SimpleNameExpressionContext
+ | MemberAccessExpressionContext
+ | PositionalParamContext
+ | IndexExpressionContext
+ | WithMemberAccessExpressionContext
+ | DictionaryAccessExpressionContext;
+
+export class NameExpressionElement extends BaseRuleSyntaxElement {
+ scopeItemCapability: ScopeItemCapability;
+ identifierCapability: IdentifierCapability;
+
+ nameContexts: (SimpleNameExpressionContext | UnrestrictedNameContext | AmbiguousIdentifierContext)[] = [];
+ withStatementElement?: WithStatementElement;
+
+ get hasNames(): boolean {
+ return this.nameContexts.length > 0;
+ }
+
+ get nameStack(): ParserRuleContext[] {
+ return [(this.withStatementElement?.nameStack ?? []), this.nameContexts].flat();
+ }
+
+ get accessMembers(): ParserRuleContext[] | undefined {
+ const names = this.nameStack;
+ if (names.length > 1) {
+ return names;
+ }
+ }
+
+ constructor(ctx: NameExpressionContext, doc: TextDocument) {
+ super(ctx, doc);
+ this.identifierCapability = new IdentifierCapability(this, () => this.nameStack.at(-1));
+ this.scopeItemCapability = new ScopeItemCapability(this, ScopeType.REFERENCE, AssignmentType.GET);
+ }
+
+ setAsCallType = () => this.scopeItemCapability.assignmentType = AssignmentType.CALL;
+ setAsLetType = () => this.scopeItemCapability.assignmentType = AssignmentType.LET;
+ setAsSetType = () => this.scopeItemCapability.assignmentType = AssignmentType.SET;
+
+ addName = (ctx: SimpleNameExpressionContext | UnrestrictedNameContext | AmbiguousIdentifierContext) => {
+ this.nameContexts.push(ctx);
+ };
+
+ evaluateNameStack(): void {
+ this.scopeItemCapability.accessMembers = this.accessMembers;
+ }
+}
\ No newline at end of file
diff --git a/server/src/project/elements/procedure.ts b/server/src/project/elements/procedure.ts
index 769ebf4..a55473c 100644
--- a/server/src/project/elements/procedure.ts
+++ b/server/src/project/elements/procedure.ts
@@ -16,7 +16,7 @@ import {
// Project
import { BaseRuleSyntaxElement, HasDiagnosticCapability, HasSymbolInformationCapability } from './base';
-import { AssignmentType, DiagnosticCapability, FoldingRangeCapability, IdentifierCapability, ItemType, ScopeItemCapability, SymbolInformationCapability } from '../../capabilities/capabilities';
+import { AssignmentType, DiagnosticCapability, FoldingRangeCapability, IdentifierCapability, ScopeType, ScopeItemCapability, SymbolInformationCapability } from '../../capabilities/capabilities';
interface HasProcedureScope {
procedureScope(): ProcedureScopeContext | null
@@ -55,16 +55,12 @@ export class SubDeclarationElement extends BaseProcedureElement ctx.subroutineName()?.ambiguousIdentifier(),
- // For some reason the IdentifierCapability throws if no default is given
- // despite it not actually ever needing it. Most unusual.
- defaultRange: () => this.context.range
- });
+
+ const getIdentifierNameContext = () => ctx.subroutineName()?.ambiguousIdentifier();
+ this.identifierCapability = new IdentifierCapability(this, getIdentifierNameContext);
this.foldingRangeCapability.openWord = `Sub ${this.identifierCapability.name}`;
this.foldingRangeCapability.closeWord = 'End Sub';
- this.scopeItemCapability.type = ItemType.SUBROUTINE;
+ this.scopeItemCapability.type = ScopeType.SUBROUTINE;
}
}
@@ -74,13 +70,11 @@ export class FunctionDeclarationElement extends BaseProcedureElement ctx.functionName()?.ambiguousIdentifier(),
- });
+ const getIdentifierNameContext = () => ctx.functionName()?.ambiguousIdentifier();
+ this.identifierCapability = new IdentifierCapability(this, getIdentifierNameContext);
this.foldingRangeCapability.openWord = `Function ${this.identifierCapability.name}`;
this.foldingRangeCapability.closeWord = 'End Function';
- this.scopeItemCapability.type = ItemType.FUNCTION;
+ this.scopeItemCapability.type = ScopeType.FUNCTION;
}
}
@@ -117,11 +111,13 @@ abstract class BasePropertyDeclarationElement this.nameContext,
- formatName: (x: string) => `${this.propertyType} ${x}`
- });
+ const getIdentifierNameContext = () => this.nameContext;
+ const getIdentifierFormattedName = (x: string) => `${this.propertyType} ${x}`;
+ this.identifierCapability = new IdentifierCapability(
+ this,
+ getIdentifierNameContext,
+ getIdentifierFormattedName
+ );
}
}
@@ -131,7 +127,7 @@ export class PropertyGetDeclarationElement extends BasePropertyDeclarationElemen
super(ctx, doc, 'Get', ctx.functionName()?.ambiguousIdentifier() ?? undefined);
this.foldingRangeCapability.openWord = `Get Property ${this.identifierCapability.name}`;
this.foldingRangeCapability.closeWord = 'End Property';
- this.scopeItemCapability.type = ItemType.PROPERTY;
+ this.scopeItemCapability.type = ScopeType.PROPERTY;
this.scopeItemCapability.assignmentType = AssignmentType.GET;
}
}
@@ -142,7 +138,7 @@ export class PropertySetDeclarationElement extends BasePropertyDeclarationElemen
super(ctx, doc, 'Set', ctx.subroutineName()?.ambiguousIdentifier() ?? undefined);
this.foldingRangeCapability.openWord = `Set Property ${this.identifierCapability.name}`;
this.foldingRangeCapability.closeWord = 'End Property';
- this.scopeItemCapability.type = ItemType.PROPERTY;
+ this.scopeItemCapability.type = ScopeType.PROPERTY;
this.scopeItemCapability.assignmentType = AssignmentType.SET;
}
}
@@ -153,7 +149,7 @@ export class PropertyLetDeclarationElement extends BasePropertyDeclarationElemen
super(ctx, doc, 'Let', ctx.subroutineName()?.ambiguousIdentifier() ?? undefined);
this.foldingRangeCapability.openWord = `Let Property ${this.identifierCapability.name}`;
this.foldingRangeCapability.closeWord = 'End Property';
- this.scopeItemCapability.type = ItemType.PROPERTY;
+ this.scopeItemCapability.type = ScopeType.PROPERTY;
this.scopeItemCapability.assignmentType = AssignmentType.LET;
}
}
\ No newline at end of file
diff --git a/server/src/project/elements/typing.ts b/server/src/project/elements/typing.ts
index 667af9f..ebb6a5e 100644
--- a/server/src/project/elements/typing.ts
+++ b/server/src/project/elements/typing.ts
@@ -1,18 +1,21 @@
// Core
import { TextDocument } from 'vscode-languageserver-textdocument';
-import { SemanticTokenModifiers, SemanticTokenTypes, SymbolKind } from 'vscode-languageserver';
+import { SymbolKind } from 'vscode-languageserver';
// Antlr
import { ParserRuleContext } from 'antlr4ng';
import {
+ ArrayDesignatorContext,
ArrayDimContext,
AsClauseContext,
ConstDeclarationContext,
ConstItemContext,
EnumDeclarationContext,
EnumMemberContext,
+ PositionalParamContext,
PublicEnumDeclarationContext,
PublicTypeDeclarationContext,
+ TypeExpressionContext,
TypeSuffixContext,
UdtDeclarationContext,
UnrestrictedNameContext,
@@ -22,9 +25,10 @@ import {
} from '../../antlr/out/vbaParser';
// Project
-import { ElementOutOfPlaceDiagnostic, LegacyFunctionalityDiagnostic } from '../../capabilities/diagnostics';
+import { ElementOutOfPlaceDiagnostic, LegacyFunctionalityDiagnostic, UnusedDiagnostic } from '../../capabilities/diagnostics';
import { BaseRuleSyntaxElement, HasDiagnosticCapability, HasSemanticTokenCapability, HasSymbolInformationCapability } from './base';
-import { AssignmentType, DiagnosticCapability, IdentifierCapability, ItemType, ScopeItemCapability, SemanticTokenCapability, SymbolInformationCapability } from '../../capabilities/capabilities';
+import { AssignmentType, DiagnosticCapability, IdentifierCapability, ScopeType, ScopeItemCapability, SemanticTokenCapability, SymbolInformationCapability } from '../../capabilities/capabilities';
+import { SemanticTokenModifiers, SemanticTokenTypes } from '../../capabilities/semanticTokens';
abstract class BaseTypeDeclarationElement extends BaseRuleSyntaxElement implements HasDiagnosticCapability, HasSymbolInformationCapability, HasSemanticTokenCapability {
@@ -42,7 +46,7 @@ abstract class BaseTypeDeclarationElement extends B
this.semanticTokenCapability = new SemanticTokenCapability(this, tokenType, tokenModifiers ?? []);
// An enum is public unless explicitly set to private.
- this.scopeItemCapability = new ScopeItemCapability(this, ItemType.TYPE);
+ this.scopeItemCapability = new ScopeItemCapability(this, ScopeType.TYPE);
this.scopeItemCapability.isPublicScope = this.isPublicScope;
}
@@ -61,10 +65,9 @@ export class EnumDeclarationElement extends BaseTypeDeclarationElement ctx.untypedName().ambiguousIdentifier()
- });
+
+ const getIdentifierNameContext = () => ctx.untypedName().ambiguousIdentifier();
+ this.identifierCapability = new IdentifierCapability(this, getIdentifierNameContext);
if (isAfterProcedure) this.diagnosticCapability.diagnostics.push(
new ElementOutOfPlaceDiagnostic(this.context.range, "Enum declaration")
);
@@ -81,11 +84,9 @@ export class EnumMemberDeclarationElement extends BaseRuleSyntaxElement ctx.untypedName()
- });
- this.scopeItemCapability = new ScopeItemCapability(this, ItemType.VARIABLE, AssignmentType.GET);
+ const getIdentifierNameContext = () => ctx.untypedName();
+ this.identifierCapability = new IdentifierCapability(this, getIdentifierNameContext);
+ this.scopeItemCapability = new ScopeItemCapability(this, ScopeType.VARIABLE, AssignmentType.GET);
}
}
@@ -99,10 +100,8 @@ export class TypeDeclarationElement extends BaseTypeDeclarationElement ctx.untypedName()
- });
+ const getIdentifierNameContext = () => ctx.untypedName();
+ this.identifierCapability = new IdentifierCapability(this, getIdentifierNameContext);
}
}
@@ -129,7 +128,7 @@ export class VariableDeclarationStatementElement extends BaseRuleSyntaxElement ctx.ambiguousIdentifier() });
-
+ this.identifierCapability = new IdentifierCapability(this, () => ctx.ambiguousIdentifier());
+
// VariableDcl > TypedVariableDcl > TypedName > TypeSuffix
// > UntypedVariableDcl > AsClause
@@ -186,29 +185,18 @@ export class VariableDeclarationElement extends BaseRuleSyntaxElement {
+class VariableTypeInformation extends BaseRuleSyntaxElement {
get isObjectType(): boolean {
- // Type hints are never an object.
- const ctx = this.context.rule;
- if (ctx instanceof TypeSuffixContext) {
- return false;
- }
+ return this.context.rule.isObject;
+ }
- // Check builtins for variant type.
- const builtin = ctx.asType()?.typeSpec().typeExpression()?.builtinType();
- if (builtin?.reservedTypeIdentifier()?.VARIANT() || builtin?.reservedTypeIdentifierB()?.VARIANT_B()) {
- return true;
- }
+ get isPrimativeType(): boolean {
+ return this.context.rule.isPrimative;
+ }
- // Don't trust anything else. Just check not a primative.
- return !this.isPrimativeType;
+ get isVariantType(): boolean {
+ return this.context.rule.isVariant;
}
- get isPrimativeType(): boolean {
- // Type hints are always primitive.
- const ctx = this.context.rule;
- if (ctx instanceof TypeSuffixContext) {
- return true;
- }
+ // TODO:
+ // - Variables in array bounds should validate they are constants or literals.
+ // - Build the capability to evaluate constant expressions.
+ get isResizable(): boolean {
+ return this.arrayCtx?.isResizable ?? false;
+ }
- // A newed object is always an object.
- if (ctx.asAutoObject()) {
- return false;
- }
+ get classTypeName(): string | undefined {
+ return this.context.rule.classTypeName;
+ }
- // Fixed length strings are primative.
- const typeSpec = ctx.asType()!.typeSpec();
- if (typeSpec.fixedLengthStringSpec()) {
- return true;
- }
+ constructor(ctx: TypeContext, doc: TextDocument, private readonly arrayCtx?: ArrayDimContext | ArrayDesignatorContext) {
+ super(ctx, doc);
+ }
+}
- // Built ins are primative (or can be in Variant's case) unless object.
- const builtin = typeSpec.typeExpression()?.builtinType();
- if (builtin?.reservedTypeIdentifier() || builtin?.reservedTypeIdentifierB()) {
- return true;
- } else if (builtin?.OBJECT() || builtin?.OBJECT_B()) {
- return false;
- }
+export class PositionalParamElement extends BaseRuleSyntaxElement {
+ identifierCapability: IdentifierCapability;
+ diagnosticCapability: DiagnosticCapability;
+
+ private variableTypeInformation?: VariableTypeInformation;
+
+ constructor(ctx: PositionalParamContext, doc: TextDocument) {
+ super(ctx, doc);
- // Defined names can be all sorts of things but if we got here, we're an object.
- const definedType = typeSpec.typeExpression()?.definedTypeExpression();
- if (definedType?.simpleNameExpression()) {
- return false;
+ const typeCtx = ctx.paramDcl().untypedNameParamDcl()?.parameterType()?.typeExpression()
+ ?? ctx.paramDcl().typedNameParamDcl()?.typedName().typeSuffix();
+
+ const arrayCtx = ctx.paramDcl().untypedNameParamDcl()?.parameterType()?.arrayDesignator()
+ ?? ctx.paramDcl().typedNameParamDcl()?.arrayDesignator()
+ ?? undefined;
+
+ if (typeCtx) {
+ this.variableTypeInformation = new VariableTypeInformation(typeCtx, doc, arrayCtx);
}
- // If we have a member accessed type, we need to do more digging...
- const memberAccessed = definedType?.memberAccessExpression()?.unrestrictedName();
- const isPrimativeMember = (ctx: UnrestrictedNameContext | undefined): boolean => !!memberAccessed?.reservedIdentifier()?.reservedTypeIdentifier();
- const isTypeSuffixMember = (ctx: UnrestrictedNameContext | undefined): boolean => !!memberAccessed?.name()?.typedName();
- return isPrimativeMember(memberAccessed) || isTypeSuffixMember(memberAccessed);
+ const identifierCtx = ctx.paramDcl().untypedNameParamDcl()?.ambiguousIdentifier()
+ ?? ctx.paramDcl().typedNameParamDcl()?.typedName().ambiguousIdentifier();
+ this.identifierCapability = new IdentifierCapability(this, () => identifierCtx);
+ this.diagnosticCapability = new DiagnosticCapability(this);
+ this.scopeItemCapability = new ScopeItemCapability(this, ScopeType.PARAMETER,);
+ this.scopeItemCapability.assignmentType = AssignmentType.GET
+ | (this.hasLetAccessor ? AssignmentType.LET : AssignmentType.NONE)
+ | (this.hasSetAccessor ? AssignmentType.SET : AssignmentType.NONE);
}
- get isFixedArrayType(): boolean {
- return !this.arrayCtx?.boundsList();
+ get hasLetAccessor(): boolean {
+ return this.variableTypeInformation?.isPrimativeType ?? true;
}
- constructor(ctx: TypeSuffixContext | AsClauseContext, doc: TextDocument, private readonly arrayCtx?: ArrayDimContext) {
- super(ctx, doc);
+ get hasSetAccessor(): boolean {
+ return this.variableTypeInformation?.isObjectType ?? true;
}
}
diff --git a/server/src/project/formatter.ts b/server/src/project/formatter.ts
index 9e6b564..132f089 100644
--- a/server/src/project/formatter.ts
+++ b/server/src/project/formatter.ts
@@ -1,6 +1,8 @@
// Core
import { Range, TextEdit } from 'vscode-languageserver';
import { TextDocument } from 'vscode-languageserver-textdocument';
+
+// Project
import { VbaFmtListener } from './parser/vbaListener';
diff --git a/server/src/project/parser/vbaAntlr.ts b/server/src/project/parser/vbaAntlr.ts
index 0204663..ba58c13 100644
--- a/server/src/project/parser/vbaAntlr.ts
+++ b/server/src/project/parser/vbaAntlr.ts
@@ -97,7 +97,6 @@ export class VbaErrorHandler extends DefaultErrorStrategy {
const inputStream = recognizer.inputStream;
if (inputStream.LA(1) !== Token.EOF) {
const intervalSet = this.getErrorRecoverySet(recognizer);
- console.log(`recover consuming ${recognizer.getCurrentToken()}`);
inputStream.consume();
// this.consumeUntil(recognizer, intervalSet);
}
@@ -108,12 +107,12 @@ export class VbaErrorHandler extends DefaultErrorStrategy {
// Attempt to recover using token deletion.
const matchedSymbol = this.singleTokenDeletion(recognizer);
if (matchedSymbol) {
- recognizer.consume();
- return matchedSymbol;
+ recognizer.consume();
+ return matchedSymbol;
}
// Attempt to recover using token insertion.
if (this.singleTokenInsertion(recognizer)) {
- return this.getMissingSymbol(recognizer);
+ return this.getMissingSymbol(recognizer);
}
// When we don't know what could come next, invalidate the entire line.
@@ -123,13 +122,11 @@ export class VbaErrorHandler extends DefaultErrorStrategy {
const invalidTokens: Token[] = [];
while (![vbaLexer.NEWLINE, vbaLexer.EOF].includes(stream.LA(1))) {
invalidTokens.push(stream.LT(1)!);
- console.log(`inline consuming ${recognizer.getCurrentToken()}`);
recognizer.consume();
}
if (invalidTokens.length > 0) {
const missingToken = this.createErrorToken(recognizer, invalidTokens);
this.reportMatch(recognizer);
- console.log(`inline consuming ${recognizer.getCurrentToken()}`);
recognizer.consume();
return missingToken;
}
diff --git a/server/src/project/parser/vbaListener.ts b/server/src/project/parser/vbaListener.ts
index f33080f..479e4a4 100644
--- a/server/src/project/parser/vbaListener.ts
+++ b/server/src/project/parser/vbaListener.ts
@@ -8,24 +8,40 @@ import { vbapreListener } from '../../antlr/out/vbapreListener';
import { vbafmtListener } from '../../antlr/out/vbafmtListener';
import { CompilerIfBlockContext } from '../../antlr/out/vbapreParser';
import {
+ AmbiguousIdentifierContext,
AnyOperatorContext,
+ ArgumentListContext,
+ CallStatementContext,
ClassModuleContext,
+ DictionaryAccessExpressionContext,
EnumDeclarationContext,
EnumMemberContext,
FunctionDeclarationContext,
IfStatementContext,
IgnoredClassAttrContext,
IgnoredProceduralAttrContext,
+ LetStatementContext,
+ LExpressionContext,
+ MemberAccessExpressionContext,
+ OptionalParamContext,
+ ParamArrayContext,
+ PositionalParamContext,
ProceduralModuleContext,
ProcedureDeclarationContext,
PropertyGetDeclarationContext,
PropertySetDeclarationContext,
+ SetStatementContext,
+ SimpleNameExpressionContext,
SubroutineDeclarationContext,
TypeSuffixContext,
UdtDeclarationContext,
UnexpectedEndOfLineContext,
+ UnrestrictedNameContext,
VariableDeclarationContext,
- WhileStatementContext
+ WhileStatementContext,
+ WithExpressionContext,
+ WithMemberAccessExpressionContext,
+ WithStatementContext
} from '../../antlr/out/vbaParser';
import {
AttributeStatementContext,
@@ -48,16 +64,39 @@ import {
} from '../../antlr/out/vbafmtParser';
// Project
+import { Services } from '../../injection/services';
+import { ExtensionConfiguration } from '../workspace';
+import { ErrorRuleElement } from '../elements/generic';
import { CompilerLogicalBlock } from '../elements/precompiled';
import { UnexpectedEndOfLineElement } from '../elements/utils';
-import { DuplicateOperatorElement, IfElseBlock as IfStatementElement, WhileLoopElement } from '../elements/flow';
import { VbaClassDocument, VbaModuleDocument } from '../document';
+import { DuplicateOperatorElement, IfElseBlockElement, WhileLoopElement } from '../elements/flow';
import { ClassElement, ModuleElement, ModuleIgnoredAttributeElement } from '../elements/module';
-import { VariableDeclarationStatementElement, EnumDeclarationElement, EnumMemberDeclarationElement, TypeDeclarationElement, TypeSuffixElement } from '../elements/typing';
-import { FunctionDeclarationElement, PropertyGetDeclarationElement, PropertyLetDeclarationElement, PropertySetDeclarationElement, SubDeclarationElement } from '../elements/procedure';
-import { ExtensionConfiguration } from '../workspace';
-import { Services } from '../../injection/services';
-import { ErrorRuleElement } from '../elements/generic';
+import { NameExpressionContext, NameExpressionElement, WithStatementElement } from '../elements/naming';
+import {
+ TypeSuffixElement,
+ EnumDeclarationElement,
+ TypeDeclarationElement,
+ PositionalParamElement,
+ EnumMemberDeclarationElement,
+ VariableDeclarationStatementElement,
+} from '../elements/typing';
+import {
+ SubDeclarationElement,
+ FunctionDeclarationElement,
+ PropertyGetDeclarationElement,
+ PropertyLetDeclarationElement,
+ PropertySetDeclarationElement,
+} from '../elements/procedure';
+
+
+enum ParserAssignmentState {
+ NONE,
+ LET,
+ SET,
+ CALL
+}
+
export class CommonParserCapability {
document: VbaClassDocument | VbaModuleDocument;
@@ -80,18 +119,50 @@ export class CommonParserCapability {
}
}
+type ParserState = {
+ inCallExp: boolean
+ isWithExp: boolean;
+ isWithStmt: boolean;
+ isDictAccess: boolean;
+ assignment: ParserAssignmentState;
+ nameElements: NameExpressionElement[];
+ callMembers?: number;
+};
export class VbaListener extends vbaListener {
document: VbaClassDocument | VbaModuleDocument;
protected documentSettings?: ExtensionConfiguration;
protected isAfterMethodDeclaration = false;
+ private withStatementStack: WithStatementElement[] = [];
+ private parserStateStack: ParserState[] = [];
+
+ private readonly verbose = false;
+
+ private get parserState(): ParserState {
+ if (this.parserStateStack.length === 0) {
+ Services.logger.error('State stack is empty.');
+ this.pushNewState();
+ }
+ return this.parserStateStack.at(-1)!;
+ }
+
+ private pushNewState = () =>
+ this.parserStateStack.push({
+ inCallExp: false,
+ isWithExp: false,
+ isWithStmt: false,
+ isDictAccess: false,
+ nameElements: [],
+ assignment: ParserAssignmentState.NONE
+ });
constructor(document: VbaClassDocument | VbaModuleDocument) {
super();
+ this.pushNewState();
this.document = document;
}
- static async createAsync(document: VbaClassDocument | VbaModuleDocument): Promise {
+ static async create(document: VbaClassDocument | VbaModuleDocument): Promise {
const result = new VbaListener(document);
await result.ensureHasSettingsAsync();
return result;
@@ -126,7 +197,7 @@ export class VbaListener extends vbaListener {
};
enterIfStatement = (ctx: IfStatementContext) =>
- this.document.registerElement(new IfStatementElement(ctx, this.document.textDocument));
+ this.document.registerElement(new IfElseBlockElement(ctx, this.document.textDocument));
enterIgnoredClassAttr = (ctx: IgnoredClassAttrContext) => this.registerIgnoredAttribute(ctx);
enterIgnoredProceduralAttr = (ctx: IgnoredProceduralAttrContext) => this.registerIgnoredAttribute(ctx);
@@ -171,6 +242,227 @@ export class VbaListener extends vbaListener {
this.document.registerElement(element);
};
+ enterArgumentList = (_: ArgumentListContext) => this.pushNewState();
+ exitArgumentList = (_: ArgumentListContext) => this.parserStateStack.pop();
+
+ enterLetStatement = (_: LetStatementContext) => {
+ if (this.verbose) Services.logger.debug(`enterLetStatement`, this.parserStateStack.length);
+ this.parserState.assignment = ParserAssignmentState.LET;
+ };
+
+ enterSetStatement = (_: SetStatementContext) => {
+ if (this.verbose) Services.logger.debug(`enterSetStatement`, this.parserStateStack.length);
+ this.parserState.assignment = ParserAssignmentState.SET;
+ };
+
+ enterCallStatement = (ctx: CallStatementContext) => {
+ if (this.verbose) Services.logger.debug(`enterCallStatement: ${ctx.getText()}`, this.parserStateStack.length);
+ this.parserState.inCallExp = true;
+
+ // Sometimes a call statement does not have the normal trigger context to add a name expression.
+ const simpleNameCtx = ctx.simpleNameExpression();
+ if (!ctx.memberAccessExpression() && !ctx.indexExpression() && simpleNameCtx) {
+ this.pushNameElement(simpleNameCtx);
+ }
+ };
+
+ exitCallStatement = (ctx: CallStatementContext) => {
+ if (this.verbose) Services.logger.debug(`exitCallStatement: ${ctx.getText()}`, this.parserStateStack.length);
+
+ // Sometimes a call statement does not have the normal trigger context to exit a name expression.
+ const simpleNameCtx = ctx.simpleNameExpression();
+ if (!ctx.memberAccessExpression() && !ctx.indexExpression() && simpleNameCtx) {
+ this.parserState.assignment = ParserAssignmentState.CALL;
+ this.registerNameElement();
+ }
+ this.parserState.inCallExp = false;
+ };
+
+ enterMemberAccessExpression = (ctx: MemberAccessExpressionContext) => {
+ if (this.verbose) Services.logger.debug(`enterMemberAccessExpression: ${ctx.getText()}`, this.parserStateStack.length);
+ this.pushNameElement(ctx);
+ };
+
+ enterDictionaryAccessExpression = (ctx: DictionaryAccessExpressionContext) => {
+ if (this.verbose) Services.logger.debug(`enterDictionaryAccessExpression: ${ctx.getText()}`, this.parserStateStack.length);
+ this.parserState.isDictAccess = true;
+ this.pushNameElement(ctx);
+ };
+
+ exitDictionaryAccessExpression = (ctx: DictionaryAccessExpressionContext) => {
+ if (this.verbose) Services.logger.debug(`exitDictionaryAccessExpression`, this.parserStateStack.length);
+ this.parserState.isDictAccess = false;
+ };
+
+ enterWithMemberAccessExpression = (ctx: WithMemberAccessExpressionContext) => {
+ if (this.verbose) Services.logger.debug(`enterWithMemberAccessExpression: ${ctx.getText()}`, this.parserStateStack.length);
+ this.pushNameElement(ctx);
+ };
+
+ exitMemberAccessExpression = (ctx: MemberAccessExpressionContext) => {
+ if (this.verbose) Services.logger.debug(`exitMemberAccessExpression: ${ctx.getText()}`, this.parserStateStack.length);
+ if (this.parserState.inCallExp) this.parserState.assignment = ParserAssignmentState.CALL;
+ this.registerNameElement();
+ };
+
+ enterLExpression = (ctx: LExpressionContext) => {
+ if (this.verbose) Services.logger.debug(`enterLExpression: ${ctx.getText()}`, this.parserStateStack.length);
+ if (ctx.LPAREN()) {
+ // FIXME: Will need to track function calls properly when we have types... maybe.
+ return;
+ }
+
+ // Will be handled by the WithExpression.
+ if (ctx.withExpression()) {
+ return;
+ }
+ this.pushNameElement(ctx);
+ };
+
+ exitLExpression = (ctx: LExpressionContext) => {
+ if (this.verbose) Services.logger.debug(`exitLExpression: ${ctx.getText()}`, this.parserStateStack.length);
+ if (ctx.LPAREN()) {
+ return;
+ }
+ // Was handled by the WithExpression.
+ if (ctx.withExpression()) {
+ return;
+ }
+ this.registerNameElement();
+ };
+
+ enterPositionalParam = (ctx: PositionalParamContext) => {
+ if (this.verbose) Services.logger.debug(`enterPositionalParam: ${ctx.getText()}`, this.parserStateStack.length);
+ const element = new PositionalParamElement(ctx, this.document.textDocument);
+ this.document.registerElement(element);
+ };
+
+ enterOptionalParam = (ctx: OptionalParamContext) => {
+ if (this.verbose) Services.logger.debug(`enterOptionalParam: ${ctx.getText()}`, this.parserStateStack.length);
+ const identifierCtx = ctx.paramDcl().untypedNameParamDcl()?.ambiguousIdentifier()
+ ?? ctx.paramDcl().typedNameParamDcl()?.typedName().ambiguousIdentifier();
+
+ if (identifierCtx) {
+ this.addNameElementContext(identifierCtx, 'ambigiousNameContext');
+ }
+ };
+
+ exitOptionalParam = (ctx: OptionalParamContext) => {
+ if (this.verbose) Services.logger.debug(`exitOptionalParam: ${ctx.getText()}`, this.parserStateStack.length);
+ this.registerNameElement();
+ };
+
+ enterParamArray = (ctx: ParamArrayContext) => {
+ if (this.verbose) Services.logger.debug(`enterParamArray: ${ctx.getText()}`, this.parserStateStack.length);
+ this.addNameElementContext(ctx.ambiguousIdentifier(), 'ambigiousNameContext');
+ };
+
+ exitParamArray = (ctx: ParamArrayContext) => {
+ if (this.verbose) Services.logger.debug(`exitParamArray: ${ctx.getText()}`, this.parserStateStack.length);
+ this.registerNameElement();
+ };
+
+ enterUnrestrictedName = (ctx: UnrestrictedNameContext) => this.addNameElementContext(ctx, 'enterUnrestrictedName');
+ enterSimpleNameExpression = (ctx: SimpleNameExpressionContext) => this.addNameElementContext(ctx, 'enterSimpleNameExpression');
+
+ private addNameElementContext(ctx: UnrestrictedNameContext | SimpleNameExpressionContext | AmbiguousIdentifierContext, source: string) {
+ if (this.verbose) Services.logger.debug(`${source}: ${ctx.getText()}`, this.parserStateStack.length);
+ const nameElement = this.parserState.nameElements.at(-1);
+ if (!nameElement) {
+ Services.logger.error(`Cannot add name ${ctx.getText()}`, this.parserStateStack.length);
+ return;
+ }
+
+ nameElement.addName(ctx);
+ }
+
+ private pushNameElement(ctx: NameExpressionContext): void {
+ if (this.verbose) Services.logger.debug('Pushing name', this.parserStateStack.length);
+ const element = new NameExpressionElement(ctx, this.document.textDocument);
+
+ // Push the name element to the stack.
+ this.parserState.nameElements.push(element);
+
+ // Link to WithStatement if we have one.
+ const withStatement = this.withStatementStack.at(-1);
+ if (withStatement && !withStatement.nameExpressionElement) {
+ withStatement.nameExpressionElement = element;
+ }
+ }
+
+ private registerNameElement(): void {
+ // Pop the current element and return if we don't have one.
+ const nameElement = this.parserState.nameElements.pop();
+ if (!nameElement) {
+ return;
+ }
+
+ // Add with names if we're in a WithExpression
+ if (this.parserState.isWithExp) {
+ nameElement.withStatementElement = this.withStatementStack.at(-1);
+ this.parserState.isWithExp = false;
+ }
+
+ // Resolve the access members if we have them.
+ nameElement.evaluateNameStack();
+
+ // Set the type based on parser state.
+ switch (this.parserState.assignment) {
+ case ParserAssignmentState.SET:
+ nameElement.setAsSetType();
+ break;
+ case ParserAssignmentState.LET:
+ nameElement.setAsLetType();
+ break;
+ case ParserAssignmentState.CALL:
+ nameElement.setAsCallType();
+ break;
+ }
+ this.parserState.assignment = ParserAssignmentState.NONE;
+
+ // Register this name element.
+ this.document.registerElement(nameElement);
+ if (this.verbose) {
+ const name = nameElement.identifierCapability.name;
+ const fqName = nameElement.accessMembers?.map(x => x.getText).join('.');
+ Services.logger.debug(`Registered ${fqName} as ${name}`, this.parserStateStack.length);
+ }
+
+ // Add the name(s) to the next element down.
+ const nextElement = this.parserState.nameElements.at(-1);
+ if (nextElement) {
+ nextElement.nameContexts = [
+ nameElement.nameContexts,
+ nextElement.nameContexts
+ ].flat();
+ }
+ }
+
+ enterWithStatement = (ctx: WithStatementContext) => {
+ if (this.verbose) Services.logger.debug(`enterWithStatement: ${ctx.getText().split('\n')[0]}...`, this.parserStateStack.length);
+ const element = new WithStatementElement(ctx, this.document.textDocument);
+ this.withStatementStack.push(element);
+ };
+
+ exitWithStatement = (ctx: WithStatementContext) => {
+ if (this.verbose) Services.logger.debug(`exitWithStatement`, this.parserStateStack.length);
+ if (this.withStatementStack.at(-1)?.context.rule === ctx) {
+ this.withStatementStack.pop();
+ } else {
+ Services.logger.error(`Can't exit With`);
+ }
+ };
+
+ enterWithExpression = (_: WithExpressionContext) => {
+ if (this.verbose) Services.logger.debug(`enterWithExpression`, this.parserStateStack.length);
+ this.parserState.isWithExp = true;
+ };
+
+ exitWithExpression = (_: WithExpressionContext) => {
+ if (this.verbose) Services.logger.debug(`exitWithExpression`, this.parserStateStack.length);
+ this.registerNameElement();
+ };
+
enterTypeSuffix = (ctx: TypeSuffixContext) =>
this.document.registerElement(new TypeSuffixElement(ctx, this.document.textDocument));
@@ -207,7 +499,7 @@ export class VbaPreListener extends vbapreListener {
this.common = new CommonParserCapability(document);
}
- static async createAsync(document: VbaClassDocument | VbaModuleDocument): Promise {
+ static async create(document: VbaClassDocument | VbaModuleDocument): Promise {
const result = new VbaPreListener(document);
await result.common.ensureHasSettingsAsync();
return result;
@@ -277,7 +569,7 @@ export class VbaFmtListener extends vbafmtListener {
this.indentationKeys = new Array(document.textDocument.lineCount);
}
- static async createAsync(document: VbaClassDocument | VbaModuleDocument): Promise {
+ static async create(document: VbaClassDocument | VbaModuleDocument): Promise {
const result = new VbaFmtListener(document);
await result.common.ensureHasSettingsAsync();
return result;
diff --git a/server/src/project/parser/vbaParser.ts b/server/src/project/parser/vbaParser.ts
index 9c02671..3f3b0bf 100644
--- a/server/src/project/parser/vbaParser.ts
+++ b/server/src/project/parser/vbaParser.ts
@@ -1,6 +1,6 @@
// Antlr
import { ParseCancellationException, ParseTreeWalker } from 'antlr4ng';
-import { VbaErrorHandler, VbaFmtParser, VbaParser, VbaPreParser } from './vbaAntlr';
+import { VbaFmtParser, VbaParser, VbaPreParser } from './vbaAntlr';
import { VbaFmtListener, VbaListener, VbaPreListener } from './vbaListener';
// Project
@@ -12,69 +12,39 @@ import { Logger } from '../../injection/interface';
export class SyntaxParser {
constructor(private logger: Logger) { }
- async parseAsync(token: CancellationToken, document: VbaClassDocument | VbaModuleDocument): Promise {
+ async parse(token: CancellationToken, document: VbaClassDocument | VbaModuleDocument): Promise {
// Preparse the document if we find a precompiler statement.
const regexp = new RegExp(/^\s*#If/gmi);
let docText = document.textDocument.getText();
if (regexp.test(docText)) {
this.logger.debug(`Beginning pre-parse.`);
- const prelistener = await VbaPreListener.createAsync(document);
+ const prelistener = await VbaPreListener.create(document);
const preparser = VbaPreParser.create(docText);
- await this.parseDocumentAsync(token, prelistener, preparser);
+ await this.parseDocument(token, prelistener, preparser);
docText = prelistener.text;
this.logger.debug(`Completed pre-parse.`);
}
// Perform main document parse without compiler directives.
this.logger.debug(`Beginning main parse.`);
- const listener = await VbaListener.createAsync(document);
+ const listener = await VbaListener.create(document);
const parser = VbaParser.create(docText);
- await this.parseDocumentAsync(token, listener, parser);
+ await this.parseDocument(token, listener, parser);
this.logger.debug(`Completed main parse.`);
}
- async formatParseAsync(token: CancellationToken, document: VbaClassDocument | VbaModuleDocument, range?: Range): Promise {
+ async formatParse(token: CancellationToken, document: VbaClassDocument | VbaModuleDocument, range?: Range): Promise {
// Special parser focused on document format.
this.logger.debug(`Beginning format parse.`);
- const listener = await VbaFmtListener.createAsync(document);
+ const listener = await VbaFmtListener.create(document);
const parser = VbaFmtParser.create(document.textDocument.getText(range));
- await this.parseDocumentAsync(token, listener, parser);
+ await this.parseDocument(token, listener, parser);
this.logger.debug(`Completed format parse.`);
return listener;
}
- // async formatVisit(token: CancellationToken, document: VbaClassDocument | VbaModuleDocument, range?: Range): Promise {
- // // // Handle already cancelled.
- // if (token.isCancellationRequested) {
- // this.logger.debug(`Format visit cancelled before start.`);
- // throw new ParseCancellationException(Error('Parse operation cancelled before it started.'));
- // }
-
- // // Listen for cancellation event.
- // token.onCancellationRequested(() => {
- // this.logger.debug(`Format visit cancelled during run.`);
- // throw new ParseCancellationException(new Error('Parse operation cancelled during parse.'));
- // });
-
-
- // this.logger.debug(`Beginning format visit.`);
- // const parser = VbaFmtParser.create(document.textDocument.getText(range));
- // const tree = parser.startRule();
-
- // // const visitor = container.resolve(VbaFormatVisitor);
- // // const visitor = forceAsync(container.resolve(VbaFormatVisitor));
- // // const visitor = forceAsync(new VbaFormatVisitor(this.logger));
- // const visitor = new VbaFormatVisitor(this.logger);
- // visitor.token = token;
- // await visitor.visit(tree);
- // this.logger.debug(`Operation ${token.isCancellationRequested ? 'cancelled' : 'completed'}.`)
-
- // // Temporary call so I don't have to refactor everything just to call it.
- // return await VbaFmtListener.createAsync(document);
- // }
-
- private async parseDocumentAsync(token: CancellationToken, listener: VbaListener | VbaPreListener | VbaFmtListener, parser: VbaParser | VbaPreParser | VbaFmtParser) {
+ private async parseDocument(token: CancellationToken, listener: VbaListener | VbaPreListener | VbaFmtListener, parser: VbaParser | VbaPreParser | VbaFmtParser) {
// Handle already cancelled.
if (token.isCancellationRequested) {
throw new ParseCancellationException(Error('Parse operation cancelled before it started.'));
diff --git a/server/src/project/workspace.ts b/server/src/project/workspace.ts
index 14ab298..45fe2fe 100644
--- a/server/src/project/workspace.ts
+++ b/server/src/project/workspace.ts
@@ -1,4 +1,5 @@
// Core
+import { inject, injectable } from 'tsyringe';
import { TextDocument } from 'vscode-languageserver-textdocument';
import {
CancellationToken,
@@ -8,6 +9,7 @@ import {
Command,
CompletionItem,
CompletionParams,
+ DefinitionParams,
DidChangeConfigurationNotification,
DidChangeWatchedFilesParams,
DocumentFormattingParams,
@@ -16,25 +18,32 @@ import {
FoldingRangeParams,
Hover,
HoverParams,
+ LocationLink,
+ RenameParams,
SemanticTokensRangeParams,
SymbolInformation,
TextDocuments,
TextEdit,
+ WorkspaceEdit,
+ WorkspaceFolder,
WorkspaceFoldersChangeEvent,
_Connection
} from 'vscode-languageserver';
-import { BaseProjectDocument } from './document';
-import { hasWorkspaceConfigurationCapability } from '../capabilities/workspaceFolder';
-import { sleep } from '../utils/helpers';
+// Antlr
import { ParseCancellationException } from 'antlr4ng';
+
+// Project
+import { sleep, walk } from '../utils/helpers';
+import { Services } from '../injection/services';
import { getFormattingEdits } from './formatter';
+import { BaseProjectDocument } from './document';
+import { SyntaxParser } from './parser/vbaParser';
import { VbaFmtListener } from './parser/vbaListener';
-import { returnDefaultOnCancelClientRequest } from '../utils/wrappers';
-import { inject, injectable } from 'tsyringe';
+import { hasWorkspaceConfigurationCapability } from '../capabilities/workspaceFolder';
import { Logger, ILanguageServer, IWorkspace } from '../injection/interface';
-import { Services } from '../injection/services';
-import { ItemType, ScopeItemCapability } from '../capabilities/capabilities';
+import { returnDefaultOnCancelClientRequest } from '../utils/wrappers';
+import { ScopeType, ScopeItemCapability } from '../capabilities/capabilities';
export interface ExtensionConfiguration {
maxDocumentLines: number;
@@ -56,10 +65,8 @@ export interface ExtensionConfiguration {
@injectable()
export class Workspace implements IWorkspace {
private events?: WorkspaceEvents;
- private documents: BaseProjectDocument[] = [];
private parseCancellationTokenSource?: CancellationTokenSource;
- private _activeDocument?: BaseProjectDocument;
private readonly _hasConfigurationCapability: boolean;
private _extensionConfiguration?: ExtensionConfiguration;
@@ -82,10 +89,6 @@ export class Workspace implements IWorkspace {
})();
}
- get activeDocument() {
- return this._activeDocument;
- }
-
constructor(
@inject("_Connection") public readonly connection: _Connection,
@inject("ILanguageServer") private server: ILanguageServer) {
@@ -95,63 +98,89 @@ export class Workspace implements IWorkspace {
this._hasConfigurationCapability = hasWorkspaceConfigurationCapability(this.server);
// Configure scopes
- const languageScope = new ScopeItemCapability(undefined, ItemType.VBA);
- const applicationScope = new ScopeItemCapability(undefined, ItemType.APPLICATION, undefined, languageScope);
- const projectScope = new ScopeItemCapability(undefined, ItemType.PROJECT, undefined, applicationScope);
+ const languageScope = new ScopeItemCapability(undefined, ScopeType.VBA);
+ const applicationScope = new ScopeItemCapability(undefined, ScopeType.APPLICATION, undefined, languageScope);
+ const projectScope = new ScopeItemCapability(undefined, ScopeType.PROJECT, undefined, applicationScope);
Services.registerProjectScope(projectScope);
}
- activateDocument(document?: BaseProjectDocument) {
- if (document) {
- this._activeDocument = document;
+ // Initially parse everything in the folder.
+ // ToDo: Handle removal of a workspace folder.
+ async addWorkspaceFolder(params: WorkspaceFolder): Promise {
+ this.logger.info(`Adding workspace: ${params.name}`);
+ const workspaceFiles = walk(params.uri, /\.(cls|bas|frm)$/i);
+
+ // No need to continue if we have no files.
+ if (workspaceFiles.size === 0) {
+ return;
}
+
+ // Set up parser and dummy token because we won't cancel this.
+ const parser = new SyntaxParser(this.logger);
+ const token = new CancellationTokenSource().token;
+
+ // Handle each file in the workspace.
+ for (const [uri, file] of workspaceFiles) {
+ const normalisedUri = uri.toFilePath().toFileUri();
+ // Don't parse files that we're already tracking.
+ if (this.projectDocuments.has(normalisedUri)) {
+ this.logger.debug(`Skipping file: ${normalisedUri}`, 1);
+ continue;
+ }
+
+ try {
+ // Read and parse the project document.
+ this.logger.debug(`Reading file: ${normalisedUri}`, 1);
+ const textDocument = TextDocument.create(`${normalisedUri}`, 'vba', 1, file);
+ const projectDocument = BaseProjectDocument.create(textDocument);
+ this.projectDocuments.set(normalisedUri, projectDocument);
+ await parser.parse(token, projectDocument);
+ this.logger.info(`Parsed ${projectDocument.name}`, 1);
+ } catch (e) {
+ // Log errors and anything else without failing.
+ this.logger.error(`Failed to parse ${normalisedUri}`, 0, e);
+ }
+ }
+
+ // Rebuild scopes from Project level.
+ Services.projectScope.build();
+ // Services.projectScope.printToDebug();
}
- async parseDocument(document?: BaseProjectDocument) {
- this.activateDocument(document);
+ async parseDocument(document: BaseProjectDocument) {
+ // this.activateDocument(document);
this.parseCancellationTokenSource?.cancel();
this.parseCancellationTokenSource = new CancellationTokenSource();
- if (!this.activeDocument) {
- this.logger.error('No active document.');
- return;
- }
-
// Exceptions thrown by the parser should be ignored.
try {
- await this.activeDocument.parseAsync(this.parseCancellationTokenSource.token);
- this.logger.info(`Parsed ${this.activeDocument.name}`);
- this.connection.sendDiagnostics(this.activeDocument.languageServerDiagnostics());
+ await document.parse(this.parseCancellationTokenSource.token);
+ this.logger.info(`Parsed ${document.name}`);
+ this.connection.sendDiagnostics(document.languageServerDiagnostics());
} catch (e) {
if (e instanceof ParseCancellationException) {
// Swallow cancellation exceptions. They're good. We like these.
- } else if (e instanceof Error) {
- this.logger.stack(e);
} else {
- this.logger.error('Something went wrong.');
+ this.logger.debug('Parser did not cancel or complete.', 0, e);
}
}
this.parseCancellationTokenSource = undefined;
}
- async formatParseDocument(document: TextDocument): Promise {
- this.parseCancellationTokenSource?.cancel();
- this.parseCancellationTokenSource = new CancellationTokenSource();
-
+ async formatParseDocument(document: TextDocument, token: CancellationToken): Promise {
// Exceptions thrown by the parser should be ignored.
let result: VbaFmtListener | undefined;
try {
- result = await this.activeDocument?.formatParseAsync(this.parseCancellationTokenSource.token);
+ const projectDocument = this.projectDocuments.get(document.uri.toFilePath().toFileUri());
+ result = await projectDocument?.formatParse(token);
this.logger.info(`Formatted ${document.uri}`);
}
catch (e) {
if (e instanceof ParseCancellationException) {
this.logger.debug('Parse cancelled successfully.');
- } else if (e instanceof Error) {
- this.logger.stack(e);
} else {
- this.logger.error(`Parse failed: ${e}`);
+ this.logger.error(`Parse failed.`, 0, e);
}
}
@@ -160,15 +189,20 @@ export class Workspace implements IWorkspace {
}
openDocument(document: TextDocument): void {
- const projectDocument = this.projectDocuments.get(document.uri);
- if (document.version === projectDocument?.version) {
+ const normalisedUri = document.uri.toFilePath().toFileUri();
+ const projectDocument = this.projectDocuments.get(normalisedUri);
+ if (projectDocument) {
projectDocument.open();
+ if (document.version > projectDocument?.version) {
+ this.parseDocument(projectDocument);
+ }
this.connection.sendDiagnostics(projectDocument.languageServerDiagnostics());
}
}
closeDocument(document: TextDocument): void {
- const projectDocument = this.projectDocuments.get(document.uri);
+ const normalisedUri = document.uri.toFilePath().toFileUri();
+ const projectDocument = this.projectDocuments.get(normalisedUri);
if (!projectDocument) {
Services.logger.warn(`Failed to get document to close: ${document.uri}`);
return;
@@ -268,33 +302,33 @@ class WorkspaceEvents {
const cancellableOnDocSymbol = returnDefaultOnCancelClientRequest(
(p: DocumentSymbolParams, t) => this.onDocumentSymbolAsync(p, t), [], 'Document Symbols');
- const cancellableOnFoldingRanges = returnDefaultOnCancelClientRequest(
- (p: FoldingRangeParams, t) => this.onFoldingRangesAsync(p, t), [], 'Folding Range');
-
- connection.onInitialized(() => this.onInitialized());
+ connection.onCodeAction(async (params, token) => this.onCodeActionRequest(params, token));
connection.onCompletion(params => this.onCompletion(params));
connection.onCompletionResolve(item => this.onCompletionResolve(item));
+ connection.onDefinition(async (params, token) => await this.onDefinition(params, token));
connection.onDidChangeConfiguration(() => Services.workspace.clearDocumentsConfiguration());
connection.onDidChangeWatchedFiles(params => this.onDidChangeWatchedFiles(params));
+ connection.onDidCloseTextDocument(params => { Services.logger.debug('[event] onDidCloseTextDocument'); Services.logger.debug(JSON.stringify(params), 1); });
+ connection.onDocumentFormatting(async (params, token) => await this.onDocumentFormatting(params, token));
connection.onDocumentSymbol(async (params, token) => await cancellableOnDocSymbol(params, token));
connection.onHover(params => this.onHover(params));
- connection.onDocumentFormatting(async (params, token) => await this.onDocumentFormatting(params, token));
- connection.onDidCloseTextDocument(params => { Services.logger.debug('[event] onDidCloseTextDocument'); Services.logger.debug(JSON.stringify(params), 1); });
- connection.onCodeAction((params, token) => this.onCodeActionRequest(params, token));
+ connection.onInitialized(() => this.onInitialized());
+ connection.onRenameRequest((params, token) => this.onRenameRequest(params, token));
if (hasWorkspaceConfigurationCapability(Services.server)) {
- connection.onFoldingRanges(async (params, token) => await cancellableOnFoldingRanges(params, token));
+ connection.onFoldingRanges(async (params, token) => await this.onFoldingRangesAsync(params, token));
}
connection.onRequest((method: string, params: object | object[] | any) => {
switch (method) {
case 'textDocument/semanticTokens/full': {
- const uri: string = params.textDocument.uri;
- return this.activeDocument?.languageServerSemanticTokens();
+ const uri: string = params.textDocument.uri.toFilePath();
+ return this.projectDocuments.get(uri)?.languageServerSemanticTokens();
}
case 'textDocument/semanticTokens/range': {
const rangeParams = params as SemanticTokensRangeParams;
- return this.activeDocument?.languageServerSemanticTokens(rangeParams.range);
+ const uri: string = params.textDocument.uri.toFilePath();
+ return this.projectDocuments.get(uri)?.languageServerSemanticTokens(rangeParams.range);
}
default:
Services.logger.error(`Unresolved request path: ${method}`);
@@ -323,6 +357,23 @@ class WorkspaceEvents {
return item;
}
+ private async onDefinition(params: DefinitionParams, token: CancellationToken): Promise {
+ Services.logger.debug('[event] onDefinition');
+ Services.logger.debug(JSON.stringify(params), 1);
+ if (token.isCancellationRequested) {
+ return;
+ }
+
+ const results = Services.projectScope.getDeclarationLocation(params.textDocument.uri, params.position);
+ Services.logger.debug(`Processed onDefinition: returning ${JSON.stringify(results)}`);
+
+ if (results === undefined) {
+ return null;
+ } else {
+ return results;
+ }
+ }
+
private onDidChangeWatchedFiles(params: DidChangeWatchedFilesParams) {
Services.logger.debug('[event] onDidChangeWatchedFiles');
Services.logger.debug(JSON.stringify(params), 1);
@@ -341,18 +392,33 @@ class WorkspaceEvents {
return document?.languageServerSymbolInformation() ?? [];
}
- private async onFoldingRangesAsync(params: FoldingRangeParams, token: CancellationToken): Promise {
+ private async onFoldingRangesAsync(params: FoldingRangeParams, token: CancellationToken): Promise {
const logger = Services.logger;
logger.debug('[Event] onFoldingRanges');
+
+ // Don't do any work if we don't have to.
+ if (token.isCancellationRequested) {
+ logger.debug('Cancellation requested before start for Folding Ranges.');
+ return;
+ }
+
let document: BaseProjectDocument | undefined;
try {
- document = await this.getParsedProjectDocument(params.textDocument.uri, 0, token);
+ const normalisedUri = params.textDocument.uri.toFilePath().toFileUri();
+ document = await this.getParsedProjectDocument(normalisedUri, 0, token);
} catch (error) {
// Swallow parser cancellations and rethrow anything else.
if (error instanceof ParseCancellationException) {
throw error;
}
}
+
+ // Check again if we're cancelled.
+ if (token.isCancellationRequested) {
+ logger.debug('Cancellation requested before start for Folding Ranges.');
+ return;
+ }
+
const result = document?.languageServerFoldingRanges();
for (const foldingRange of result ?? []) {
logger.debug(`${JSON.stringify(foldingRange.range)} '${foldingRange.openWord}..${foldingRange.closeWord}'`, 1);
@@ -379,6 +445,11 @@ class WorkspaceEvents {
);
connection.client.register(DidChangeConfigurationNotification.type, undefined);
}
+
+ // Read workspace folders if we have them.
+ Services.server.configuration?.params
+ .workspaceFolders?.forEach(folder => setImmediate(() =>
+ Services.workspace.addWorkspaceFolder(folder)));
}
private async onDocumentFormatting(params: DocumentFormattingParams, token: CancellationToken): Promise {
@@ -412,8 +483,6 @@ class WorkspaceEvents {
}
try {
- // We don't actually need the document but await to ensure it's parsed.
- await this.getParsedProjectDocument(params.textDocument.uri, 0, token);
const uri = params.textDocument.uri;
const result: (Command | CodeAction)[] = [];
const codeActionRegistry = Services.codeActionsRegistry;
@@ -433,6 +502,44 @@ class WorkspaceEvents {
}
}
+ private async onRenameRequest(params: RenameParams, token: CancellationToken): Promise {
+ Services.logger.debug(`[event] onRenameRequest: ${JSON.stringify(params)}`);
+ if (token.isCancellationRequested) {
+ Services.logger.debug(`onRenameRequest cancelled before start.`);
+ return;
+ }
+
+ const renameItems = Services.projectScope.getRenameItems(params.textDocument.uri, params.position);
+ const workspaceEdit: { changes: { [uri: string]: TextEdit[] }; } = { changes: {} };
+
+ for (const renameItem of renameItems) {
+ const uri = renameItem.locationUri;
+ if (!uri) {
+ Services.logger.warn('Scope item has no element to rename');
+ continue;
+ }
+
+ const range = renameItem.element?.identifierCapability?.range;
+ if (!range) {
+ Services.logger.warn('Scope item has no identifier to rename');
+ continue;
+ }
+
+ workspaceEdit.changes[uri] ??= [];
+ workspaceEdit.changes[uri].push(TextEdit.replace(range, params.newName));
+ }
+
+ Services.logger.debug(`resolved onRenameRequest: returning\n${JSON.stringify(workspaceEdit)}`);
+
+ // Allow a cancellation to be processed if we have one.
+ await new Promise(resolve => setTimeout(resolve, 0));
+ if (token.isCancellationRequested) {
+ Services.logger.debug(`onRenameRequest cancelled during run.`);
+ return;
+ }
+ return workspaceEdit;
+ }
+
/** Documents event handlers */
/**
@@ -440,13 +547,10 @@ class WorkspaceEvents {
* @param document The document being opened.
*/
onDidOpen(document: TextDocument) {
- const logger = Services.logger;
- logger.debug('[event] onDidOpen');
- logger.debug(`uri: ${document.uri}`, 1);
- logger.debug(`languageId: ${document.languageId}`, 1);
- logger.debug(`version: ${document.version}`, 1);
- const projectDocument = this.projectDocuments.get(document.uri);
- if (projectDocument) {
+ Services.logger.debug('[event] onDidOpen');
+ this.printDocumentInformation(document);
+ const normalisedUri = document.uri.toFilePath().toFileUri();
+ if (this.projectDocuments.has(normalisedUri)) {
Services.workspace.openDocument(document);
}
}
@@ -456,23 +560,22 @@ class WorkspaceEvents {
* @param document The document that was changed.
*/
onDidChangeContent(document: TextDocument): void {
- const logger = Services.logger;
- logger.debug('[event] onDidChangeContentAsync');
- logger.debug(`uri: ${document.uri}`, 1);
- logger.debug(`languageId: ${document.languageId}`, 1);
- logger.debug(`version: ${document.version}`, 1);
+ Services.logger.debug('[event] onDidChangeContent');
+ this.printDocumentInformation(document);
// If the event is fired for the same version of the document, don't reparse.
- const existingDocument = this.projectDocuments.get(document.uri);
- if ((existingDocument?.version ?? -1) >= document.version) {
- logger.debug('Document already parsed.');
+ const normalisedUri = document.uri.toFilePath().toFileUri();
+ const existingDocument = this.projectDocuments.get(normalisedUri);
+ const existingVersion = existingDocument?.version ?? -1;
+ Services.logger.debug(`existing: ${existingVersion}`, 1);
+ if (existingVersion >= document.version) {
return;
}
// The document is new or a new version that we should parse.
const projectDocument = BaseProjectDocument.create(document);
- this.projectDocuments.set(document.uri, projectDocument);
- Services.projectScope.invalidate(document.uri);
+ this.projectDocuments.set(normalisedUri, projectDocument);
+ Services.projectScope.invalidateModule(normalisedUri);
Services.workspace.parseDocument(projectDocument);
}
@@ -481,14 +584,21 @@ class WorkspaceEvents {
* @param document The document being closed.
*/
onDidClose(document: TextDocument) {
+ Services.logger.debug('[event] onDidClose');
+ this.printDocumentInformation(document);
+
+ const normalisedUri = document.uri.toFilePath().toFileUri();
+ if (this.projectDocuments.has(normalisedUri)) {
+ Services.workspace.closeDocument(document);
+ }
+ }
+
+ private printDocumentInformation(document: TextDocument) {
const logger = Services.logger;
- logger.debug('[event] onDidClose');
- logger.debug(`uri: ${document.uri}`, 1);
+ const normalisedUri = document.uri.toFilePath().toFileUri();
+ logger.debug(`doc uri: ${document.uri}`, 1);
+ logger.debug(`norm uri: ${normalisedUri}`, 1);
logger.debug(`languageId: ${document.languageId}`, 1);
logger.debug(`version: ${document.version}`, 1);
- const projectDocument = this.projectDocuments.get(document.uri);
- if (projectDocument) {
- Services.workspace.closeDocument(document);
- }
}
}
diff --git a/server/src/server.ts b/server/src/server.ts
index f42fff0..c527289 100644
--- a/server/src/server.ts
+++ b/server/src/server.ts
@@ -16,8 +16,10 @@ import { Services } from './injection/services';
// Ensures globally available type extensions.
import './extensions/stringExtensions';
-import './extensions/parserExtensions';
import './extensions/numberExtensions';
+import './extensions/antlrCoreExtensions';
+import './extensions/antlrVbaParserExtensions';
+import './extensions/antlrVbaPreParserExtensions';
import { Workspace } from './project/workspace';
import { activateSemanticTokenProvider } from './capabilities/semanticTokens';
import { activateWorkspaceFolderCapability } from './capabilities/workspaceFolder';
@@ -45,6 +47,10 @@ export class LanguageServer implements ILanguageServer {
activateSemanticTokenProvider(result);
return result;
});
+ // Register shutdown actions
+ this.connection.onShutdown(() => { });
+ this.connection.onExit(() => process.exit(0));
+
// Register for client configuration notification changes.
this.connection.onInitialized(() => { this.connection.client.register(DidChangeConfigurationNotification.type, undefined); });
this.connection.onDidChangeConfiguration(() => this._clientConfiguration = undefined);
@@ -70,26 +76,21 @@ export class LanguageServer implements ILanguageServer {
export class LanguageServerConfiguration {
- params: InitializeParams;
capabilities: ServerCapabilities = {
// Implemented
- documentSymbolProvider: true,
+ codeActionProvider: true,
+ definitionProvider: true,
foldingRangeProvider: true,
+ documentSymbolProvider: true,
textDocumentSync: TextDocumentSyncKind.Incremental,
- // diagnosticProvider: {
- // interFileDependencies: false,
- // workspaceDiagnostics: false
- // },
// Implement soon.
- codeActionProvider: true,
- completionProvider: undefined,
hoverProvider: false,
+ completionProvider: undefined,
// Not implemented.
signatureHelpProvider: undefined,
declarationProvider: false,
- definitionProvider: false,
typeDefinitionProvider: false,
implementationProvider: false,
referencesProvider: false,
@@ -101,7 +102,7 @@ export class LanguageServerConfiguration {
documentFormattingProvider: true,
documentRangeFormattingProvider: false,
documentOnTypeFormattingProvider: undefined,
- renameProvider: false,
+ renameProvider: true,
selectionRangeProvider: false,
executeCommandProvider: undefined,
callHierarchyProvider: false,
@@ -111,9 +112,7 @@ export class LanguageServerConfiguration {
experimental: undefined,
};
- constructor(params: InitializeParams) {
- this.params = params;
- }
+ constructor(public params: InitializeParams) { }
}
diff --git a/server/src/utils/helpers.ts b/server/src/utils/helpers.ts
index cea83e3..40e69da 100644
--- a/server/src/utils/helpers.ts
+++ b/server/src/utils/helpers.ts
@@ -1,3 +1,10 @@
+// Core
+import * as fs from 'fs';
+import * as path from 'path';
+import { Services } from '../injection/services';
+import { pathToFileURL } from 'url';
+import { Position, Range } from 'vscode-languageserver';
+
export class Dictionary extends Map {
private defaultFactory: (...args: any) => V;
@@ -34,4 +41,50 @@ export function ioEvents(): Promise {
export function sleep(ms: number): Promise {
return new Promise(resolve => setTimeout(resolve, ms));
+}
+
+/**
+ * Recursively walks a directory structure and returns a map of file path to string content.
+ * @param dirOrUri A directory as a path or 'file://' uri.
+ * @param pattern A predicate to filter results.
+ * @param files Used for internal recursive calls.
+ */
+export function walk(dirOrUri: string, pattern?: RegExp, files: Map = new Map()): Map {
+ const logger = Services.logger;
+ logger.debug(`Walking ${dirOrUri}`);
+
+ // Walk the contents of the directory.
+ const dir = dirOrUri.toFilePath();
+ for (const name of fs.readdirSync(dir)) {
+ const p = path.join(dir, name);
+
+ // Check if we have a directory. This can occasionally throw at an OS level.
+ let pIsDirectory: boolean | undefined;
+ try { pIsDirectory = fs.statSync(p).isDirectory(); }
+ catch (e) { logger.warn(`The OS threw an exception checking whether ${p} is a directory.`, 0, e); }
+ if (pIsDirectory) {
+ // Recursive call for directories.
+ walk(p, pattern, files);
+ } else if (pattern?.test(name) ?? true) {
+ // Track files that match the pattern.
+ logger.debug(`Found ${p}`, 1);
+ logger.debug(`href: ${pathToFileURL(p).href}`);
+ let fileContent = '';
+ try { fileContent = fs.readFileSync(p, 'utf-8'); }
+ catch (e) { logger.error(`The OS threw an exception reading ${p}.`, 0, e); }
+ files.set(p, fileContent);
+ }
+ }
+ return files;
+}
+
+export function isPositionInsideRange(position: Position, range: Range): boolean {
+ if (range.start.line !== range.end.line) {
+ return position.line >= range.start.line
+ && position.line <= range.end.line;
+ }
+
+ return position.line === range.start.line
+ && position.character >= range.start.character
+ && position.character <= range.end.character;
}
\ No newline at end of file
diff --git a/server/src/utils/logger.ts b/server/src/utils/logger.ts
index 2a79dd9..f7d4311 100644
--- a/server/src/utils/logger.ts
+++ b/server/src/utils/logger.ts
@@ -1,7 +1,10 @@
+// Core
import { inject, injectable } from 'tsyringe';
-import { Logger, ILanguageServer } from '../injection/interface';
import { _Connection } from 'vscode-languageserver';
+// Project
+import { Logger, ILanguageServer } from '../injection/interface';
+
enum LogLevel {
error = 1,
@@ -23,14 +26,14 @@ export class LspLogger implements Logger {
@inject("_Connection") public connection: _Connection,
@inject("ILanguageServer") private server: ILanguageServer) { }
- error = (msg: string, lvl?: number) => this.emit(LogLevel.error, msg, lvl);
- warn = (msg: string, lvl?: number) => this.emit(LogLevel.warn, msg, lvl);
- info = (msg: string, lvl?: number) => this.emit(LogLevel.info, msg, lvl);
- log = (msg: string, lvl?: number) => this.emit(LogLevel.log, msg, lvl);
- debug = (msg: string, lvl?: number) => this.emit(LogLevel.debug, msg, lvl);
- stack = (e: Error) => this.emit(LogLevel.error, `${e.name}: ${e.message}\n${e.stack}`);
+ error = (msg: string, lvl?: number, e?: unknown) => this.emit(LogLevel.error, msg, lvl, e);
+ warn = (msg: string, lvl?: number, e?: unknown) => this.emit(LogLevel.warn, msg, lvl, e);
+ info = (msg: string, lvl?: number, e?: unknown) => this.emit(LogLevel.info, msg, lvl, e);
+ log = (msg: string, lvl?: number, e?: unknown) => this.emit(LogLevel.log, msg, lvl, e);
+ debug = (msg: string, lvl?: number, e?: unknown) => this.emit(LogLevel.debug, msg, lvl, e);
+ stack = (e: Error, logLevel?: LogLevel) => this.emit(logLevel ?? LogLevel.error, `${e.name}: ${e.message}\n${e.stack}`);
- private emit(logLevel: LogLevel, msgText: string, msgLevel?: number): void {
+ private emit(logLevel: LogLevel, msgText: string, msgLevel?: number, e?: unknown): void {
// Async get the configuration and then emit.
this.server.clientConfiguration.then(config => {
try {
@@ -54,6 +57,11 @@ export class LspLogger implements Logger {
message: msgText,
level: msgLevel ?? 0
});
+
+ // If we have an error, then log stack trace too.
+ if (e instanceof Error) {
+ this.stack(e, logLevel);
+ }
});
}
diff --git a/server/src/utils/wrappers.ts b/server/src/utils/wrappers.ts
index 2c04a32..3476144 100644
--- a/server/src/utils/wrappers.ts
+++ b/server/src/utils/wrappers.ts
@@ -1,36 +1,11 @@
+// Core
import { CancellationToken } from 'vscode-languageserver';
-import { LspLogger } from './logger';
-import { Logger } from '../injection/interface';
+
+// Project
import { Services } from '../injection/services';
-type signature = (token: CancellationToken, ...args: A) => Promise;
type paramsSignature = (params: P, token: CancellationToken) => Promise;
-/**
- * A wrapper to give cancellation token handling to an async function.
- * @param fn An async function that requires cancellation token handling.
- * @param defaultValue The value to return when cancelled.
- */
-function returnDefaultOnCancel(fn: signature, logger?: Logger, name?: string, defaultValue?: T, cancelError?: Error): signature {
- return async (token: CancellationToken, ...args: A): Promise => {
- if (token.isCancellationRequested) {
- if (logger) logger.debug(`Cancellation requested before start for ${name ?? 'unknown'}. Returning default.`);
- if (cancelError) throw cancelError;
- return defaultValue;
- }
-
- return new Promise((resolve) => {
- const onCancel = () => {
- if (logger) logger.debug(`Cancellation requested during processing for ${name ?? 'unknown'}. Returning default.`);
- if (cancelError) throw cancelError;
- resolve(defaultValue);
- };
- token.onCancellationRequested(onCancel);
- fn(token, ...args).then(resolve).catch(() => resolve(defaultValue));
- });
- };
-}
-
/**
* A wrapper to give cancellation token handling to an async client request.
* @param fn An async function that requires cancellation token handling.
diff --git a/vba.language-configuration.json b/vba.language-configuration.json
index 91918b0..9d5867f 100644
--- a/vba.language-configuration.json
+++ b/vba.language-configuration.json
@@ -8,12 +8,20 @@
["(", ")"]
],
"autoClosingPairs": [
- { "open": "\"", "close": "\""}
+ { "open": "\"", "close": "\""},
+ { "open": "(", "close": ")"},
+ { "open": "[", "close": "]"}
],
+ "autoCloseBefore": ": \n\r\t)}]\n",
"surroundingPairs": [
[ "(", ")" ],
[ "[", "]" ],
[ "\"", "\"" ]
],
"wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)",
+ // Placeholder - possibly won't use as it's a little awkward. Prefer to implement with LSP.
+ // "indentationRules": {
+ // "increaseIndentPattern": "^\\s*(?:Sub|Function|Property\\s+(?:Get|Let|Set)|Else|(Else)?If.*?Then|For|While|Do|Select\\s+Case|Type|With|Enum)\\b",
+ // "decreaseIndentPattern": "^\\s*(?:End\\s+(?:Sub|Function|Property|If|Select|Type|With|Enum)|Next|Loop|Else|ElseIf.*?Then)\\b"
+ // }
}
\ No newline at end of file