├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── VBScript-vscode.code-workspace ├── client ├── .gitignore ├── .vscode │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── .vscodeignore ├── buildVSIX.bat ├── package-lock.json ├── package.json ├── resources │ ├── vbs.png │ └── vbs.svg ├── src │ └── extension.ts └── tsconfig.json └── server ├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── package-lock.json ├── package.json ├── src ├── VBSSymbols │ ├── VBSClassSymbol.ts │ ├── VBSConstantSymbol.ts │ ├── VBSMemberSymbol.ts │ ├── VBSMethodSymbol.ts │ ├── VBSPropertySymbol.ts │ ├── VBSSymbol.ts │ └── VBSVariableSymbol.ts └── server.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | /client/*.vsix 2 | /client/README.md 3 | /client/CHANGELOG.md 4 | Thumbs.db 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | # Version 1.0.2 4 | 5 | - corrected error message for (end property expected) 6 | - added filename to 'refreshed symbols' log message 7 | - added start character to error messages 8 | - added support for array arguments 9 | 10 | # Version 1.0.1 11 | 12 | - fixed issue: Default property #10 13 | 14 | # Version 1.0.0 15 | 16 | - performance tweaks 17 | - method end were not recognized if they were written in a different case (Sub vs. sub) 18 | 19 | # Version 0.0.7 20 | 21 | - fixed issue: Parameters as symbols 22 | - added language contribution 23 | - fixed issue: Underline seperation 24 | 25 | # Version 0.0.6 26 | 27 | - fixed issue: Multi-Dim support 28 | 29 | # Version 0.0.5 30 | 31 | - support for code completion of symbols based on scope 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Andreas Lenzen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VBScript symbols extension 2 | 3 | This extension provides symbols for VBScript. 4 | 5 | Pressing Ctrl + Shift + O lists all symbols of the current file. 6 | 7 | You can display symbols by using extensions like "Code Outline" by Patryk Zawadzki as well. 8 | 9 | ## Supported Symbols 10 | 11 | - __Class__ 12 | - __Function__ 13 | - __Sub__ 14 | - __Property__ 15 | - __Field__ 16 | - global and class wide __Const__ 17 | - __Dim__ 18 | - Parameters 19 | 20 | ## Version 1.0.0 21 | 22 | This version is the first version which contains a valuable feature set to make VBScript development more productive. 23 | This version supports the recognition of all important symbols of a file and provides IntelliSense support according the scope. 24 | 25 | ## (Maybe) Upcoming Features 26 | 27 | ### VBScript debugging 28 | 29 | I would like to see a VBScript debugger built in into this extension. This will most likely be only available for windows but it would make the VSCode - VBScript experience somwhat complete. 30 | 31 | ### Lexer (ANTLR?) 32 | 33 | I would appreciate if the regular expressions of mine will be superseded someday by a formal grammar. A popular possibility would be ANTLR. I hope that this would make it a bit faster, more reliable and much easier to read. 34 | 35 | 36 | [GitHub](https://github.com/Luncher91/VBScript-vscode) 37 | -------------------------------------------------------------------------------- /VBScript-vscode.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "server" 5 | }, 6 | { 7 | "path": "client" 8 | } 9 | ], 10 | "settings": { 11 | "typescript.tsdk": "./node_modules/typescript/lib" 12 | } 13 | } -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | server 3 | node_modules -------------------------------------------------------------------------------- /client/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "Launch Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "runtimeExecutable": "${execPath}", 10 | "args": ["--extensionDevelopmentPath=${workspaceRoot}" ], 11 | "stopOnEntry": false, 12 | "sourceMaps": true, 13 | "outFiles": [ "${workspaceRoot}/out/src/**/*.js" ] 14 | }, 15 | { 16 | "name": "Launch Tests", 17 | "type": "extensionHost", 18 | "request": "launch", 19 | "runtimeExecutable": "${execPath}", 20 | "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], 21 | "stopOnEntry": false, 22 | "sourceMaps": true, 23 | "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ], 24 | "preLaunchTask": { 25 | "type": "npm", 26 | "script": "watch" 27 | } 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /client/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | "typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version 10 | } -------------------------------------------------------------------------------- /client/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | 9 | // A task runner that calls a custom npm script that compiles the extension. 10 | { 11 | "version": "2.0.0", 12 | "tasks": [ 13 | { 14 | "label": "compile watch", 15 | "type": "shell", 16 | "command": "npm", 17 | "args": ["run", "compile", "--loglevel", "silent"], 18 | "problemMatcher": ["$tsc-watch"], 19 | } 20 | ], 21 | } -------------------------------------------------------------------------------- /client/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | typings/** 3 | out/test/** 4 | test/** 5 | src/** 6 | **/*.map 7 | .gitignore 8 | tsconfig.json 9 | vsc-extension-quickstart.md 10 | buildVSIX.bat 11 | -------------------------------------------------------------------------------- /client/buildVSIX.bat: -------------------------------------------------------------------------------- 1 | xcopy /y ..\README.md . 2 | xcopy /y ..\CHANGELOG.md . 3 | vsce package -------------------------------------------------------------------------------- /client/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vbscript-language-server-client", 3 | "version": "1.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@tootallnate/once": { 8 | "version": "1.1.2", 9 | "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", 10 | "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", 11 | "dev": true 12 | }, 13 | "@types/node": { 14 | "version": "8.10.60", 15 | "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.60.tgz", 16 | "integrity": "sha512-YjPbypHFuiOV0bTgeF07HpEEqhmHaZqYNSdCKeBJa+yFoQ/7BC+FpJcwmi34xUIIRVFktnUyP1dPU8U0612GOg==", 17 | "dev": true 18 | }, 19 | "agent-base": { 20 | "version": "6.0.0", 21 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", 22 | "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", 23 | "dev": true, 24 | "requires": { 25 | "debug": "4" 26 | } 27 | }, 28 | "balanced-match": { 29 | "version": "1.0.0", 30 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 31 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 32 | "dev": true 33 | }, 34 | "brace-expansion": { 35 | "version": "1.1.11", 36 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 37 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 38 | "dev": true, 39 | "requires": { 40 | "balanced-match": "^1.0.0", 41 | "concat-map": "0.0.1" 42 | } 43 | }, 44 | "browser-stdout": { 45 | "version": "1.3.1", 46 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 47 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 48 | "dev": true 49 | }, 50 | "buffer-from": { 51 | "version": "1.1.1", 52 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 53 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 54 | "dev": true 55 | }, 56 | "commander": { 57 | "version": "2.15.1", 58 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", 59 | "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", 60 | "dev": true 61 | }, 62 | "concat-map": { 63 | "version": "0.0.1", 64 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 65 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 66 | "dev": true 67 | }, 68 | "debug": { 69 | "version": "4.1.1", 70 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 71 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 72 | "dev": true, 73 | "requires": { 74 | "ms": "^2.1.1" 75 | } 76 | }, 77 | "diff": { 78 | "version": "3.5.0", 79 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 80 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 81 | "dev": true 82 | }, 83 | "es6-promise": { 84 | "version": "4.2.8", 85 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", 86 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", 87 | "dev": true 88 | }, 89 | "es6-promisify": { 90 | "version": "5.0.0", 91 | "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", 92 | "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", 93 | "dev": true, 94 | "requires": { 95 | "es6-promise": "^4.0.3" 96 | } 97 | }, 98 | "escape-string-regexp": { 99 | "version": "1.0.5", 100 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 101 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 102 | "dev": true 103 | }, 104 | "fs.realpath": { 105 | "version": "1.0.0", 106 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 107 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 108 | "dev": true 109 | }, 110 | "glob": { 111 | "version": "7.1.6", 112 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 113 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 114 | "dev": true, 115 | "requires": { 116 | "fs.realpath": "^1.0.0", 117 | "inflight": "^1.0.4", 118 | "inherits": "2", 119 | "minimatch": "^3.0.4", 120 | "once": "^1.3.0", 121 | "path-is-absolute": "^1.0.0" 122 | } 123 | }, 124 | "growl": { 125 | "version": "1.10.5", 126 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 127 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 128 | "dev": true 129 | }, 130 | "has-flag": { 131 | "version": "3.0.0", 132 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 133 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 134 | "dev": true 135 | }, 136 | "he": { 137 | "version": "1.1.1", 138 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 139 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 140 | "dev": true 141 | }, 142 | "http-proxy-agent": { 143 | "version": "4.0.1", 144 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", 145 | "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", 146 | "dev": true, 147 | "requires": { 148 | "@tootallnate/once": "1", 149 | "agent-base": "6", 150 | "debug": "4" 151 | } 152 | }, 153 | "https-proxy-agent": { 154 | "version": "5.0.0", 155 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", 156 | "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", 157 | "dev": true, 158 | "requires": { 159 | "agent-base": "6", 160 | "debug": "4" 161 | } 162 | }, 163 | "inflight": { 164 | "version": "1.0.6", 165 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 166 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 167 | "dev": true, 168 | "requires": { 169 | "once": "^1.3.0", 170 | "wrappy": "1" 171 | } 172 | }, 173 | "inherits": { 174 | "version": "2.0.4", 175 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 176 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 177 | "dev": true 178 | }, 179 | "minimatch": { 180 | "version": "3.0.4", 181 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 182 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 183 | "dev": true, 184 | "requires": { 185 | "brace-expansion": "^1.1.7" 186 | } 187 | }, 188 | "minimist": { 189 | "version": "0.0.8", 190 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 191 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 192 | "dev": true 193 | }, 194 | "mkdirp": { 195 | "version": "0.5.1", 196 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 197 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 198 | "dev": true, 199 | "requires": { 200 | "minimist": "0.0.8" 201 | } 202 | }, 203 | "mocha": { 204 | "version": "5.2.0", 205 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", 206 | "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", 207 | "dev": true, 208 | "requires": { 209 | "browser-stdout": "1.3.1", 210 | "commander": "2.15.1", 211 | "debug": "3.1.0", 212 | "diff": "3.5.0", 213 | "escape-string-regexp": "1.0.5", 214 | "glob": "7.1.2", 215 | "growl": "1.10.5", 216 | "he": "1.1.1", 217 | "minimatch": "3.0.4", 218 | "mkdirp": "0.5.1", 219 | "supports-color": "5.4.0" 220 | }, 221 | "dependencies": { 222 | "debug": { 223 | "version": "3.1.0", 224 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 225 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 226 | "dev": true, 227 | "requires": { 228 | "ms": "2.0.0" 229 | } 230 | }, 231 | "glob": { 232 | "version": "7.1.2", 233 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 234 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 235 | "dev": true, 236 | "requires": { 237 | "fs.realpath": "^1.0.0", 238 | "inflight": "^1.0.4", 239 | "inherits": "2", 240 | "minimatch": "^3.0.4", 241 | "once": "^1.3.0", 242 | "path-is-absolute": "^1.0.0" 243 | } 244 | }, 245 | "ms": { 246 | "version": "2.0.0", 247 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 248 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 249 | "dev": true 250 | } 251 | } 252 | }, 253 | "ms": { 254 | "version": "2.1.2", 255 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 256 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 257 | "dev": true 258 | }, 259 | "once": { 260 | "version": "1.4.0", 261 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 262 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 263 | "dev": true, 264 | "requires": { 265 | "wrappy": "1" 266 | } 267 | }, 268 | "path-is-absolute": { 269 | "version": "1.0.1", 270 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 271 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 272 | "dev": true 273 | }, 274 | "semver": { 275 | "version": "5.7.1", 276 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 277 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 278 | "dev": true 279 | }, 280 | "source-map": { 281 | "version": "0.6.1", 282 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 283 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 284 | "dev": true 285 | }, 286 | "source-map-support": { 287 | "version": "0.5.18", 288 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.18.tgz", 289 | "integrity": "sha512-9luZr/BZ2QeU6tO2uG8N2aZpVSli4TSAOAqFOyTO51AJcD9P99c0K1h6dD6r6qo5dyT44BR5exweOaLLeldTkQ==", 290 | "dev": true, 291 | "requires": { 292 | "buffer-from": "^1.0.0", 293 | "source-map": "^0.6.0" 294 | } 295 | }, 296 | "supports-color": { 297 | "version": "5.4.0", 298 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", 299 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", 300 | "dev": true, 301 | "requires": { 302 | "has-flag": "^3.0.0" 303 | } 304 | }, 305 | "typescript": { 306 | "version": "2.9.2", 307 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", 308 | "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", 309 | "dev": true 310 | }, 311 | "vscode": { 312 | "version": "1.1.37", 313 | "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.37.tgz", 314 | "integrity": "sha512-vJNj6IlN7IJPdMavlQa1KoFB3Ihn06q1AiN3ZFI/HfzPNzbKZWPPuiU+XkpNOfGU5k15m4r80nxNPlM7wcc0wg==", 315 | "dev": true, 316 | "requires": { 317 | "glob": "^7.1.2", 318 | "http-proxy-agent": "^4.0.1", 319 | "https-proxy-agent": "^5.0.0", 320 | "mocha": "^5.2.0", 321 | "semver": "^5.4.1", 322 | "source-map-support": "^0.5.0", 323 | "vscode-test": "^0.4.1" 324 | } 325 | }, 326 | "vscode-jsonrpc": { 327 | "version": "3.5.0", 328 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz", 329 | "integrity": "sha1-hyOdnhZrLXNSJFuKgTWXgEwdY6o=" 330 | }, 331 | "vscode-languageclient": { 332 | "version": "3.5.1", 333 | "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.1.tgz", 334 | "integrity": "sha512-GTQ+hSq/o4c/y6GYmyP9XNrVoIu0NFZ67KltSkqN+tO0eUNDIlrVNX+3DJzzyLhSsrctuGzuYWm3t87mNAcBmQ==", 335 | "requires": { 336 | "vscode-languageserver-protocol": "3.5.1" 337 | } 338 | }, 339 | "vscode-languageserver-protocol": { 340 | "version": "3.5.1", 341 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.1.tgz", 342 | "integrity": "sha512-1fPDIwsAv1difCV+8daOrJEGunClNJWqnUHq/ncWrjhitKWXgGmRCjlwZ3gDUTt54yRcvXz1PXJDaRNvNH6pYA==", 343 | "requires": { 344 | "vscode-jsonrpc": "3.5.0", 345 | "vscode-languageserver-types": "3.5.0" 346 | } 347 | }, 348 | "vscode-languageserver-types": { 349 | "version": "3.5.0", 350 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz", 351 | "integrity": "sha1-5I15li8LjgLelV4/UkkI4rGcA3Q=" 352 | }, 353 | "vscode-test": { 354 | "version": "0.4.3", 355 | "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-0.4.3.tgz", 356 | "integrity": "sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==", 357 | "dev": true, 358 | "requires": { 359 | "http-proxy-agent": "^2.1.0", 360 | "https-proxy-agent": "^2.2.1" 361 | }, 362 | "dependencies": { 363 | "agent-base": { 364 | "version": "4.3.0", 365 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", 366 | "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", 367 | "dev": true, 368 | "requires": { 369 | "es6-promisify": "^5.0.0" 370 | } 371 | }, 372 | "debug": { 373 | "version": "3.1.0", 374 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 375 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 376 | "dev": true, 377 | "requires": { 378 | "ms": "2.0.0" 379 | } 380 | }, 381 | "http-proxy-agent": { 382 | "version": "2.1.0", 383 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", 384 | "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", 385 | "dev": true, 386 | "requires": { 387 | "agent-base": "4", 388 | "debug": "3.1.0" 389 | } 390 | }, 391 | "https-proxy-agent": { 392 | "version": "2.2.4", 393 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", 394 | "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", 395 | "dev": true, 396 | "requires": { 397 | "agent-base": "^4.3.0", 398 | "debug": "^3.1.0" 399 | } 400 | }, 401 | "ms": { 402 | "version": "2.0.0", 403 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 404 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 405 | "dev": true 406 | } 407 | } 408 | }, 409 | "wrappy": { 410 | "version": "1.0.2", 411 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 412 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 413 | "dev": true 414 | } 415 | } 416 | } 417 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vbscript-language-server-client", 3 | "displayName": "VBScript symbols", 4 | "description": "VBScript symbol support", 5 | "author": "Andreas Lenzen", 6 | "license": "MIT", 7 | "version": "1.1.0", 8 | "publisher": "andreaslenzen", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/Luncher91/VBScript-vscode" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/Luncher91/VBScript-vscode/issues" 15 | }, 16 | "homepage": "https://github.com/Luncher91/VBScript-vscode/blob/master/README.md", 17 | "galleryBanner": { 18 | "color": "#888888", 19 | "theme": "dark" 20 | }, 21 | "icon": "resources/vbs.png", 22 | "engines": { 23 | "vscode": "^1.18.0" 24 | }, 25 | "categories": [ 26 | "Language Packs" 27 | ], 28 | "keywords": [ 29 | "VBS", 30 | "VBScript", 31 | "Language", 32 | "Symbol", 33 | "Functionlist", 34 | "ASP" 35 | ], 36 | "activationEvents": [ 37 | "onLanguage:vb", 38 | "onLanguage:vba", 39 | "onLanguage:vbs", 40 | "onLanguage:vbscript", 41 | "onLanguage:asp" 42 | ], 43 | "main": "./out/extension", 44 | "contributes": { 45 | "languages": [ 46 | { 47 | "id": "vbs", 48 | "aliases": [ 49 | "VBScript", 50 | "vbscript", 51 | "VBS" 52 | ] 53 | } 54 | ], 55 | "configuration": { 56 | "type": "object", 57 | "title": "VBScript language configuration", 58 | "properties": { 59 | "vbsLanguageServer.trace.server": { 60 | "type": "string", 61 | "enum": [ 62 | "off", 63 | "messages", 64 | "verbose" 65 | ], 66 | "default": "off", 67 | "description": "Traces the communication between VSCode and the VBScriptLanguageServer service." 68 | } 69 | } 70 | } 71 | }, 72 | "scripts": { 73 | "vscode:prepublish": "tsc -p ./", 74 | "compile": "tsc -watch -p ./", 75 | "update-vscode": "node ./node_modules/vscode/bin/install", 76 | "postinstall": "node ./node_modules/vscode/bin/install" 77 | }, 78 | "devDependencies": { 79 | "@types/node": "^8.0.26", 80 | "typescript": "^2.1.5", 81 | "vscode": "^1.0.3" 82 | }, 83 | "dependencies": { 84 | "vscode-languageclient": "^3.1.0" 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /client/resources/vbs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Luncher91/VBScript-vscode/074c8b9c3c59fbae26f1e0a0ce9187a9db58ead6/client/resources/vbs.png -------------------------------------------------------------------------------- /client/resources/vbs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /client/src/extension.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as path from 'path'; 4 | 5 | import { workspace, Disposable, ExtensionContext } from 'vscode'; 6 | import { LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, TransportKind } from 'vscode-languageclient'; 7 | 8 | export function activate(context: ExtensionContext) { 9 | let serverModule = context.asAbsolutePath(path.join('server', 'server.js')); 10 | let debugOptions = { execArgv: ["--nolazy", "--inspect=6009"] }; 11 | let serverOptions: ServerOptions = { 12 | run : { module: serverModule, transport: TransportKind.ipc }, 13 | debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions } 14 | } 15 | 16 | let clientOptions: LanguageClientOptions = { 17 | documentSelector: ['asp','vbs', 'vb', 'vbscript', 'vba'], 18 | synchronize: { 19 | configurationSection: 'vbsLanguageServer', 20 | fileEvents: workspace.createFileSystemWatcher('**/.clientrc') 21 | } 22 | } 23 | 24 | let disposable = new LanguageClient('vbsLanguageServer', 'VBScript Language Server', serverOptions, clientOptions).start(); 25 | context.subscriptions.push(disposable); 26 | } 27 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "outDir": "out", 7 | "lib": [ "es2016" ], 8 | "sourceMap": true 9 | }, 10 | "exclude": [ 11 | "node_modules", 12 | "server" 13 | ] 14 | } -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules -------------------------------------------------------------------------------- /server/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | // List of configurations. Add new configurations or edit existing ones. 4 | "configurations": [ 5 | { 6 | "name": "Attach", 7 | "type": "node", 8 | "request": "attach", 9 | "port": 6009, 10 | "sourceMaps": true, 11 | "outFiles": [ "${workspaceRoot}/../client/server/**/*.js" ] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /server/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "./node_modules/typescript/lib" 3 | } -------------------------------------------------------------------------------- /server/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Run watch", 6 | "type": "shell", 7 | "command": "npm", 8 | "args": [ 9 | "run", "watch" 10 | ], 11 | "problemMatcher": ["$tsc-watch"] 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vbscript-language-server", 3 | "version": "1.0.3", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/node": { 8 | "version": "8.10.60", 9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.60.tgz", 10 | "integrity": "sha512-YjPbypHFuiOV0bTgeF07HpEEqhmHaZqYNSdCKeBJa+yFoQ/7BC+FpJcwmi34xUIIRVFktnUyP1dPU8U0612GOg==" 11 | }, 12 | "typescript": { 13 | "version": "2.9.2", 14 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", 15 | "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", 16 | "dev": true 17 | }, 18 | "vscode-jsonrpc": { 19 | "version": "3.5.0", 20 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz", 21 | "integrity": "sha1-hyOdnhZrLXNSJFuKgTWXgEwdY6o=" 22 | }, 23 | "vscode-languageserver": { 24 | "version": "3.5.1", 25 | "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.1.tgz", 26 | "integrity": "sha512-RYUKn0DgHTFcS8kS4VaNCjNMaQXYqiXdN9bKrFjXzu5RPKfjIYcoh47oVWwZj4L3R/DPB0Se7HPaDatvYY2XgQ==", 27 | "requires": { 28 | "vscode-languageserver-protocol": "3.5.1", 29 | "vscode-uri": "^1.0.1" 30 | } 31 | }, 32 | "vscode-languageserver-protocol": { 33 | "version": "3.5.1", 34 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.1.tgz", 35 | "integrity": "sha512-1fPDIwsAv1difCV+8daOrJEGunClNJWqnUHq/ncWrjhitKWXgGmRCjlwZ3gDUTt54yRcvXz1PXJDaRNvNH6pYA==", 36 | "requires": { 37 | "vscode-jsonrpc": "3.5.0", 38 | "vscode-languageserver-types": "3.5.0" 39 | } 40 | }, 41 | "vscode-languageserver-types": { 42 | "version": "3.5.0", 43 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz", 44 | "integrity": "sha1-5I15li8LjgLelV4/UkkI4rGcA3Q=" 45 | }, 46 | "vscode-uri": { 47 | "version": "1.0.8", 48 | "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.8.tgz", 49 | "integrity": "sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ==" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vbscript-language-server", 3 | "description": "Implementation of a VBScript language server in node.", 4 | "version": "1.0.3", 5 | "author": "Andreas Lenzen", 6 | "license": "MIT", 7 | "engines": { 8 | "vscode": "^1.43.0" 9 | }, 10 | "dependencies": { 11 | "vscode-languageserver": "^3.1.0", 12 | "@types/node": "^8.0.26" 13 | }, 14 | "devDependencies": { 15 | "typescript": "^2.1.5" 16 | }, 17 | "scripts": { 18 | "compile": "installServerIntoExtension ../client ./package.json ./tsconfig.json && tsc -p .", 19 | "watch": "installServerIntoExtension ../client ./package.json ./tsconfig.json && tsc --watch -p ." 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /server/src/VBSSymbols/VBSClassSymbol.ts: -------------------------------------------------------------------------------- 1 | import * as ls from 'vscode-languageserver'; 2 | import { VBSSymbol } from "./VBSSymbol"; 3 | 4 | export class VBSClassSymbol extends VBSSymbol { 5 | public GetLsSymbolKind(): ls.SymbolKind { 6 | return ls.SymbolKind.Class; 7 | } 8 | 9 | public GetLsCompletionItem(): ls.CompletionItem { 10 | let item = ls.CompletionItem.create(this.name); 11 | item.filterText = this.name; 12 | item.insertText = this.name; 13 | item.kind = ls.CompletionItemKind.Class; 14 | return item; 15 | } 16 | } -------------------------------------------------------------------------------- /server/src/VBSSymbols/VBSConstantSymbol.ts: -------------------------------------------------------------------------------- 1 | import * as ls from 'vscode-languageserver'; 2 | import { VBSSymbol } from "./VBSSymbol"; 3 | 4 | export class VBSConstantSymbol extends VBSSymbol { 5 | public GetLsSymbolKind(): ls.SymbolKind { 6 | return ls.SymbolKind.Constant; 7 | } 8 | 9 | public GetLsCompletionItem(): ls.CompletionItem { 10 | let item = ls.CompletionItem.create(this.name); 11 | item.filterText = this.name; 12 | item.insertText = this.name; 13 | item.kind = ls.CompletionItemKind.Variable; 14 | return item; 15 | } 16 | } -------------------------------------------------------------------------------- /server/src/VBSSymbols/VBSMemberSymbol.ts: -------------------------------------------------------------------------------- 1 | import * as ls from 'vscode-languageserver'; 2 | import { VBSSymbol } from "./VBSSymbol"; 3 | 4 | export class VBSMemberSymbol extends VBSSymbol { 5 | public GetLsSymbolKind(): ls.SymbolKind { 6 | return ls.SymbolKind.Field; 7 | } 8 | 9 | public GetLsCompletionItem(): ls.CompletionItem { 10 | let item = ls.CompletionItem.create(this.name); 11 | item.filterText = this.name; 12 | item.insertText = this.name; 13 | item.kind = ls.CompletionItemKind.Field; 14 | return item; 15 | } 16 | } -------------------------------------------------------------------------------- /server/src/VBSSymbols/VBSMethodSymbol.ts: -------------------------------------------------------------------------------- 1 | import * as ls from 'vscode-languageserver'; 2 | import { VBSSymbol } from "./VBSSymbol"; 3 | 4 | export class VBSMethodSymbol extends VBSSymbol { 5 | public GetLsName(): string { 6 | return this.name + " (" + this.args + ")"; 7 | } 8 | 9 | public GetLsSymbolKind(): ls.SymbolKind { 10 | return ls.SymbolKind.Method; 11 | } 12 | 13 | public GetLsCompletionItem(): ls.CompletionItem { 14 | let item = ls.CompletionItem.create(this.name); 15 | item.documentation = this.visibility + " " + this.type + " " + this.name + "(" + this.args + ")" 16 | item.filterText = this.name; 17 | item.insertText = this.name + "(" + this.args + ")"; 18 | item.kind = ls.CompletionItemKind.Method; 19 | return item; 20 | } 21 | } -------------------------------------------------------------------------------- /server/src/VBSSymbols/VBSPropertySymbol.ts: -------------------------------------------------------------------------------- 1 | import * as ls from 'vscode-languageserver'; 2 | import { VBSSymbol } from "./VBSSymbol"; 3 | 4 | export class VBSPropertySymbol extends VBSSymbol { 5 | public GetLsName(): string { 6 | if(this.args != "") 7 | return this.type + " " + this.name + " (" + this.args + ")"; 8 | else 9 | return this.type + " " + this.name; 10 | } 11 | 12 | public GetLsSymbolKind(): ls.SymbolKind { 13 | return ls.SymbolKind.Property; 14 | } 15 | 16 | public GetLsCompletionItem(): ls.CompletionItem { 17 | let item = ls.CompletionItem.create(this.name); 18 | 19 | item.documentation = this.GetDocu(); 20 | item.filterText = this.name; 21 | item.insertText = this.name; 22 | item.kind = ls.CompletionItemKind.Property; 23 | return item; 24 | } 25 | 26 | private GetDocu(): string { 27 | let docu = ""; 28 | 29 | if(this.visibility != null) 30 | docu += this.visibility.trim(); 31 | 32 | if(this.type != null) 33 | docu += this.type.trim(); 34 | 35 | if(this.name != null) 36 | docu += this.name.trim(); 37 | 38 | if(this.args != null) 39 | docu += "(" + this.args + ")"; 40 | 41 | return docu.trim(); 42 | } 43 | } -------------------------------------------------------------------------------- /server/src/VBSSymbols/VBSSymbol.ts: -------------------------------------------------------------------------------- 1 | import * as ls from 'vscode-languageserver'; 2 | 3 | export class VBSSymbol { 4 | public visibility: string = ""; 5 | public name: string = ""; 6 | public type: string = ""; 7 | public args: string = ""; 8 | public symbolRange: ls.Range = null; 9 | public nameLocation: ls.Location = null; 10 | 11 | public parentName: string = ""; 12 | 13 | public GetLsName(): string { 14 | return this.name; 15 | } 16 | 17 | public GetLsSymbolKind(): ls.SymbolKind { 18 | // I do not know any better value to return here - I liked to have something like ls.SymbolKind.UNKNOWN 19 | return ls.SymbolKind.File; 20 | } 21 | 22 | public GetLsCompletionItem(): ls.CompletionItem { 23 | let item = ls.CompletionItem.create(this.name); 24 | item.filterText = this.name; 25 | item.insertText = this.name; 26 | item.kind = ls.CompletionItemKind.Text; 27 | return item; 28 | } 29 | 30 | public static GetLanguageServerSymbols(symbols: VBSSymbol[]): ls.SymbolInformation[] { 31 | let lsSymbols: ls.SymbolInformation[] = []; 32 | 33 | symbols.forEach(symbol => { 34 | let lsSymbol: ls.SymbolInformation = ls.SymbolInformation.create( 35 | symbol.GetLsName(), 36 | symbol.GetLsSymbolKind(), 37 | symbol.symbolRange, 38 | symbol.nameLocation.uri, 39 | symbol.parentName 40 | ); 41 | lsSymbols.push(lsSymbol); 42 | }); 43 | 44 | return lsSymbols; 45 | } 46 | 47 | public static GetLanguageServerCompletionItems(symbols: VBSSymbol[]): ls.CompletionItem[] { 48 | let completionItems: ls.CompletionItem[] = []; 49 | 50 | symbols.forEach(symbol => { 51 | let lsItem = symbol.GetLsCompletionItem(); 52 | completionItems.push(lsItem); 53 | }); 54 | 55 | return completionItems; 56 | } 57 | } -------------------------------------------------------------------------------- /server/src/VBSSymbols/VBSVariableSymbol.ts: -------------------------------------------------------------------------------- 1 | import * as ls from 'vscode-languageserver'; 2 | import { VBSSymbol } from "./VBSSymbol"; 3 | 4 | export class VBSVariableSymbol extends VBSSymbol { 5 | public GetLsSymbolKind(): ls.SymbolKind { 6 | return ls.SymbolKind.Variable; 7 | } 8 | 9 | public GetLsCompletionItem(): ls.CompletionItem { 10 | let item = ls.CompletionItem.create(this.name); 11 | item.filterText = this.name; 12 | item.insertText = this.name; 13 | item.kind = ls.CompletionItemKind.Variable; 14 | return item; 15 | } 16 | } -------------------------------------------------------------------------------- /server/src/server.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Andreas Lenzen. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | 'use strict'; 6 | 7 | import * as ls from 'vscode-languageserver'; 8 | import { VBSSymbol } from "./VBSSymbols/VBSSymbol"; 9 | import { VBSMethodSymbol } from './VBSSymbols/VBSMethodSymbol'; 10 | import { VBSPropertySymbol } from './VBSSymbols/VBSPropertySymbol'; 11 | import { VBSClassSymbol } from './VBSSymbols/VBSClassSymbol'; 12 | import { VBSMemberSymbol } from './VBSSymbols/VBSMemberSymbol'; 13 | import { VBSVariableSymbol } from './VBSSymbols/VBSVariableSymbol'; 14 | import { VBSConstantSymbol } from './VBSSymbols/VBSConstantSymbol'; 15 | 16 | // Create a connection for the server. The connection uses Node's IPC as a transport 17 | let connection: ls.IConnection = ls.createConnection(new ls.IPCMessageReader(process), new ls.IPCMessageWriter(process)); 18 | 19 | // Create a simple text document manager. The text document manager 20 | // supports full document sync only 21 | let documents: ls.TextDocuments = new ls.TextDocuments(); 22 | // Make the text document manager listen on the connection 23 | // for open, change and close text document events 24 | documents.listen(connection); 25 | 26 | // After the server has started the client sends an initialize request. The server receives 27 | // in the passed params the rootPath of the workspace plus the client capabilities. 28 | let workspaceRoot: string; 29 | connection.onInitialize((params): ls.InitializeResult => { 30 | workspaceRoot = params.rootPath; 31 | return { 32 | capabilities: { 33 | // Tell the client that the server works in FULL text document sync mode 34 | textDocumentSync: documents.syncKind, 35 | documentSymbolProvider: true, 36 | // Tell the client that the server support code complete 37 | completionProvider: { 38 | resolveProvider: true 39 | } 40 | } 41 | } 42 | }); 43 | 44 | // The content of a text document has changed. This event is emitted 45 | // when the text document first opened or when its content has changed. 46 | documents.onDidChangeContent((change: ls.TextDocumentChangeEvent) => { 47 | }); 48 | 49 | connection.onDidChangeWatchedFiles((changeParams: ls.DidChangeWatchedFilesParams) => { 50 | for (let i = 0; i < changeParams.changes.length; i++) { 51 | let event = changeParams.changes[i]; 52 | 53 | switch(event.type) { 54 | case ls.FileChangeType.Changed: 55 | case ls.FileChangeType.Created: 56 | RefreshDocumentsSymbols(event.uri); 57 | break; 58 | case ls.FileChangeType.Deleted: 59 | symbolCache[event.uri] = null; 60 | break; 61 | } 62 | } 63 | }); 64 | 65 | // This handler provides the initial list of the completion items. 66 | connection.onCompletion((_textDocumentPosition: ls.TextDocumentPositionParams): ls.CompletionItem[] => { 67 | return SelectCompletionItems(_textDocumentPosition); 68 | }); 69 | 70 | connection.onCompletionResolve((complItem: ls.CompletionItem): ls.CompletionItem => { 71 | return complItem; 72 | }); 73 | 74 | function GetSymbolsOfDocument(uri: string) : ls.SymbolInformation[] { 75 | RefreshDocumentsSymbols(uri); 76 | return VBSSymbol.GetLanguageServerSymbols(symbolCache[uri]); 77 | } 78 | 79 | function SelectCompletionItems(textDocumentPosition: ls.TextDocumentPositionParams): ls.CompletionItem[] { 80 | let symbols = symbolCache[textDocumentPosition.textDocument.uri]; 81 | 82 | if(symbols == null) { 83 | RefreshDocumentsSymbols(textDocumentPosition.textDocument.uri); 84 | symbols = symbolCache[textDocumentPosition.textDocument.uri]; 85 | } 86 | 87 | let scopeSymbols = GetSymbolsOfScope(symbols, textDocumentPosition.position); 88 | return VBSSymbol.GetLanguageServerCompletionItems(scopeSymbols); 89 | } 90 | 91 | function GetVBSSymbolTree(symbols: VBSSymbol[]) { 92 | // sort by start positition 93 | let sortedSymbols: VBSSymbol[] = symbols.sort(function(a: VBSSymbol, b: VBSSymbol){ 94 | let diff = a.symbolRange.start.line - b.symbolRange.start.line; 95 | 96 | if(diff != 0) 97 | return diff; 98 | 99 | return a.symbolRange.start.character - b.symbolRange.start.character; 100 | }); 101 | 102 | let root = new VBSSymbolTree(); 103 | 104 | for (var i = 0; i < sortedSymbols.length; i++) { 105 | var symbol = sortedSymbols[i]; 106 | root.InsertIntoTree(symbol); 107 | } 108 | 109 | return root; 110 | } 111 | 112 | function GetSymbolsOfScope(symbols: VBSSymbol[], position: ls.Position): VBSSymbol[] { 113 | let symbolTree = GetVBSSymbolTree(symbols); 114 | // bacause of hoisting we will have just a few possible scopes: 115 | // - file wide 116 | // - method of file wide 117 | // - class scope 118 | // - method or property of class scope 119 | // get all symbols which are accessable from here (ignore visibility in the first step) 120 | 121 | return symbolTree.FindDirectParent(position).GetAllParentsAndTheirDirectChildren(); 122 | } 123 | 124 | class VBSSymbolTree { 125 | parent: VBSSymbolTree = null; 126 | children: VBSSymbolTree[] = []; 127 | data: VBSSymbol = null; 128 | 129 | public InsertIntoTree(symbol: VBSSymbol): boolean { 130 | if(this.data != null && !PositionInRange(this.data.symbolRange, symbol.symbolRange.start)) 131 | return false; 132 | 133 | for (var i = 0; i < this.children.length; i++) { 134 | var symbolTree = this.children[i]; 135 | if(symbolTree.InsertIntoTree(symbol)) 136 | return true; 137 | } 138 | 139 | let newTreeNode = new VBSSymbolTree(); 140 | newTreeNode.data = symbol; 141 | newTreeNode.parent = this; 142 | 143 | this.children.push(newTreeNode); 144 | 145 | return true; 146 | } 147 | 148 | public FindDirectParent(position: ls.Position): VBSSymbolTree { 149 | if(this.data != null && !PositionInRange(this.data.symbolRange, position)) 150 | return null; 151 | 152 | for (var i = 0; i < this.children.length; i++) { 153 | let symbolTree = this.children[i]; 154 | let found = symbolTree.FindDirectParent(position); 155 | if(found != null) 156 | return found; 157 | } 158 | 159 | return this; 160 | } 161 | 162 | public GetAllParentsAndTheirDirectChildren(): VBSSymbol[] { 163 | let symbols: VBSSymbol[]; 164 | 165 | if(this.parent != null) 166 | symbols = this.parent.GetAllParentsAndTheirDirectChildren(); 167 | else 168 | symbols = []; 169 | 170 | let childSymbols = this.children.map(function(symbolTree) { 171 | return symbolTree.data; 172 | }); 173 | 174 | return symbols.concat(childSymbols); 175 | } 176 | } 177 | 178 | function PositionInRange(range: ls.Range, position: ls.Position): boolean { 179 | if(range.start.line > position.line) 180 | return false; 181 | 182 | if(range.end.line < position.line) 183 | return false; 184 | 185 | if(range.start.line == position.line && range.start.character >= position.character) 186 | return false; 187 | 188 | if(range.end.line == position.line && range.end.character <= position.character) 189 | return false; 190 | 191 | return true; 192 | } 193 | 194 | let symbolCache: { [id: string] : VBSSymbol[]; } = {}; 195 | function RefreshDocumentsSymbols(uri: string) { 196 | let startTime: number = Date.now(); 197 | let symbolsList: VBSSymbol[] = CollectSymbols(documents.get(uri)); 198 | symbolCache[uri] = symbolsList; 199 | console.info("Found " + symbolsList.length + " symbols in '" + uri + "': " + (Date.now() - startTime) + " ms"); 200 | } 201 | 202 | connection.onDocumentSymbol((docParams: ls.DocumentSymbolParams): ls.SymbolInformation[] => { 203 | return GetSymbolsOfDocument(docParams.textDocument.uri); 204 | }); 205 | 206 | function CollectSymbols(document: ls.TextDocument): VBSSymbol[] { 207 | let symbols: Set = new Set(); 208 | let lines = document.getText().split(/\r?\n/g); 209 | 210 | let startMultiLine: number = -1; 211 | let multiLines: string[] = []; 212 | 213 | for (var i = 0; i < lines.length; i++) { 214 | let line = lines[i]; 215 | 216 | let containsComment = line.indexOf("'"); 217 | if(containsComment > -1) 218 | line = line.substring(0, containsComment); 219 | 220 | if(startMultiLine == -1) 221 | startMultiLine = i; 222 | 223 | if(line.trim().endsWith("_")) { 224 | multiLines.push(line.slice(0, -1)); 225 | continue; 226 | } else { 227 | multiLines.push(line); 228 | } 229 | 230 | multiLines = ReplaceStringLiterals(multiLines); 231 | let statements = SplitStatements(multiLines, startMultiLine); 232 | 233 | statements.forEach(statement => { 234 | FindSymbol(statement, document.uri, symbols); 235 | }); 236 | 237 | startMultiLine =-1; 238 | multiLines = []; 239 | } 240 | 241 | return Array.from(symbols); 242 | } 243 | 244 | class MultiLineStatement { 245 | startCharacter: number = 0; 246 | startLine: number = -1; 247 | lines: string[] = []; 248 | 249 | public GetFullStatement(): string { 250 | return " ".repeat(this.startCharacter) + this.lines.join(""); 251 | } 252 | 253 | public GetPostitionByCharacter(charIndex: number) : ls.Position { 254 | let internalIndex = charIndex - this.startCharacter; 255 | 256 | for (let i = 0; i < this.lines.length; i++) { 257 | let line = this.lines[i]; 258 | 259 | if(internalIndex <= line.length) { 260 | if(i == 0) 261 | return ls.Position.create(this.startLine + i, internalIndex + this.startCharacter); 262 | else 263 | return ls.Position.create(this.startLine + i, internalIndex); 264 | 265 | } 266 | 267 | internalIndex = internalIndex - line.length; 268 | 269 | if(internalIndex < 0) 270 | break; 271 | } 272 | 273 | console.warn("WARNING: cannot resolve " + charIndex + " in me: " + JSON.stringify(this)); 274 | return null; 275 | } 276 | } 277 | 278 | function SplitStatements(lines: string[], startLineIndex: number): MultiLineStatement[] { 279 | let statement: MultiLineStatement = new MultiLineStatement(); 280 | let statements: MultiLineStatement[] = []; 281 | let charOffset: number = 0; 282 | 283 | for (var i = 0; i < lines.length; i++) { 284 | var line = lines[i]; 285 | charOffset = 0; 286 | let sts: string[] = line.split(":"); 287 | 288 | if(sts.length == 1) { 289 | statement.lines.push(sts[0]); 290 | if(statement.startLine == -1) { 291 | statement.startLine = startLineIndex + i; 292 | } 293 | } else { 294 | for (var j = 0; j < sts.length; j++) { 295 | var st = sts[j]; 296 | 297 | if(statement.startLine == -1) 298 | statement.startLine = startLineIndex + i; 299 | 300 | statement.lines.push(st); 301 | 302 | if(j == sts.length-1) { 303 | break; 304 | } 305 | 306 | statement.startCharacter = charOffset; 307 | statements.push(statement); 308 | statement = new MultiLineStatement(); 309 | 310 | charOffset += st.length 311 | + 1; // ":" 312 | } 313 | } 314 | } 315 | 316 | if(statement.startLine != -1) { 317 | statement.startCharacter = charOffset; 318 | statements.push(statement); 319 | } 320 | 321 | return statements; 322 | } 323 | 324 | function ReplaceStringLiterals(lines:string[]) : string[] { 325 | let newLines: string[] = []; 326 | 327 | for (var i = 0; i < lines.length; i++) { 328 | var line = lines[i]; 329 | let stringLiterals = /\"(([^\"]|\"\")*)\"/gi; 330 | newLines.push(line.replace(stringLiterals, ReplaceBySpaces)); 331 | } 332 | 333 | return newLines; 334 | } 335 | 336 | function ReplaceBySpaces(match: string) : string { 337 | return " ".repeat(match.length); 338 | } 339 | 340 | function AddArrayToSet(s: Set, a: any[]) { 341 | a.forEach(element => { 342 | s.add(element); 343 | }); 344 | } 345 | 346 | function FindSymbol(statement: MultiLineStatement, uri: string, symbols: Set) : void { 347 | let newSym: VBSSymbol; 348 | let newSyms: VBSVariableSymbol[] = null; 349 | 350 | if(GetMethodStart(statement, uri)) { 351 | return; 352 | } 353 | 354 | newSyms = GetMethodSymbol(statement, uri); 355 | if(newSyms != null && newSyms.length != 0) { 356 | AddArrayToSet(symbols, newSyms); 357 | return; 358 | } 359 | 360 | if(GetPropertyStart(statement, uri)) 361 | return; 362 | 363 | newSyms = GetPropertySymbol(statement, uri);; 364 | if(newSyms != null && newSyms.length != 0) { 365 | AddArrayToSet(symbols, newSyms); 366 | return; 367 | } 368 | 369 | if(GetClassStart(statement, uri)) 370 | return; 371 | 372 | newSym = GetClassSymbol(statement, uri); 373 | if(newSym != null) { 374 | symbols.add(newSym); 375 | return; 376 | } 377 | 378 | newSym = GetMemberSymbol(statement, uri); 379 | if(newSym != null) { 380 | symbols.add(newSym); 381 | return; 382 | } 383 | 384 | newSyms = GetVariableSymbol(statement, uri); 385 | if(newSyms != null && newSyms.length != 0) { 386 | AddArrayToSet(symbols, newSyms); 387 | return; 388 | } 389 | 390 | newSym = GetConstantSymbol(statement, uri); 391 | if(newSym != null) { 392 | symbols.add(newSym); 393 | return; 394 | } 395 | } 396 | 397 | let openClassName : string = null; 398 | let openClassStart : ls.Position = ls.Position.create(-1, -1); 399 | 400 | class OpenMethod { 401 | visibility: string; 402 | type: string; 403 | name: string; 404 | argsIndex: number; 405 | args: string; 406 | startPosition: ls.Position; 407 | nameLocation: ls.Location; 408 | statement: MultiLineStatement; 409 | } 410 | 411 | let openMethod: OpenMethod = null; 412 | 413 | function GetMethodStart(statement: MultiLineStatement, uri: string): boolean { 414 | let line = statement.GetFullStatement(); 415 | 416 | let rex:RegExp = /^\s*(?public\s+|private\s+)?(?function|sub)(\s+)(?[a-zA-Z0-9\-\_]+)(\s*)(?\(.*\))?\s*$/gi; 417 | let regexResult = rex.exec(line); 418 | 419 | if(regexResult == null || regexResult.length < 6) 420 | return; 421 | 422 | if(openMethod == null) { 423 | let leadingSpaces = GetNumberOfFrontSpaces(line); 424 | let preLength = leadingSpaces + regexResult.index; 425 | 426 | for (var i = 1; i < 6; i++) { 427 | var resElement = regexResult[i]; 428 | if(resElement != null) 429 | preLength += resElement.length; 430 | } 431 | 432 | openMethod = { 433 | visibility: regexResult.groups.visibility, 434 | type: regexResult.groups.type, 435 | name: regexResult.groups.name, 436 | argsIndex: preLength + 1, // opening bracket 437 | args: regexResult.groups.args, 438 | startPosition: statement.GetPostitionByCharacter(leadingSpaces), 439 | nameLocation: ls.Location.create(uri, ls.Range.create( 440 | statement.GetPostitionByCharacter(line.indexOf(regexResult.groups.name)), 441 | statement.GetPostitionByCharacter(line.indexOf(regexResult.groups.name) + regexResult.groups.name.length)) 442 | ), 443 | statement: statement 444 | }; 445 | 446 | if(openMethod.args == null) 447 | openMethod.args = ""; 448 | 449 | return true; 450 | } else { 451 | // ERROR!!! I expected "end function|sub"! 452 | console.error("ERROR - line " + statement.startLine + " at " + statement.startCharacter + ": 'end " + openMethod.type + "' expected!"); 453 | } 454 | 455 | return false; 456 | } 457 | 458 | function GetMethodSymbol(statement: MultiLineStatement, uri: string) : VBSSymbol[] { 459 | let line: string = statement.GetFullStatement(); 460 | 461 | let classEndRegex:RegExp = /^[ \t]*end[ \t]+(function|sub)[ \t]*$/gi; 462 | 463 | let regexResult = classEndRegex.exec(line); 464 | 465 | if(regexResult == null || regexResult.length < 2) 466 | return null; 467 | 468 | let type = regexResult[1]; 469 | 470 | if(openMethod == null) { 471 | // ERROR!!! I cannot close any method! 472 | console.error("ERROR - line " + statement.startLine + " at " + statement.startCharacter + ": There is no " + type + " to end!"); 473 | return null; 474 | } 475 | 476 | if(type.toLowerCase() != openMethod.type.toLowerCase()) { 477 | // ERROR!!! I expected end function|sub and not sub|function! 478 | // show the user the error and then go on like it was the right type! 479 | console.error("ERROR - line " + statement.startLine + " at " + statement.startCharacter + ": 'end " + openMethod.type + "' expected!"); 480 | } 481 | 482 | let range: ls.Range = ls.Range.create(openMethod.startPosition, statement.GetPostitionByCharacter(GetNumberOfFrontSpaces(line) + regexResult[0].trim().length)) 483 | 484 | let symbol: VBSMethodSymbol = new VBSMethodSymbol(); 485 | symbol.visibility = openMethod.visibility; 486 | symbol.type = openMethod.type; 487 | symbol.name = openMethod.name; 488 | symbol.args = openMethod.args; 489 | symbol.nameLocation = openMethod.nameLocation; 490 | symbol.parentName = openClassName; 491 | symbol.symbolRange = range; 492 | 493 | let parametersSymbol = GetParameterSymbols(openMethod.args, openMethod.argsIndex, openMethod.statement, uri); 494 | 495 | openMethod = null; 496 | 497 | //return [symbol]; 498 | return parametersSymbol.concat(symbol); 499 | } 500 | 501 | function ReplaceAll(target: string, search: string, replacement: string): string { 502 | return target.replace(new RegExp(search, 'g'), replacement); 503 | }; 504 | 505 | function GetParameterSymbols(args: string, argsIndex: number, statement: MultiLineStatement, uri: string): VBSVariableSymbol[] { 506 | let symbols: VBSVariableSymbol[] = []; 507 | 508 | if(args == null || args == "") 509 | return symbols; 510 | 511 | let argsSplitted: string[] = args.split(','); 512 | 513 | for (let i = 0; i < argsSplitted.length; i++) { 514 | let arg = argsSplitted[i]; 515 | 516 | let splittedByValByRefName = ReplaceAll(ReplaceAll(arg, "\t", " "), " ", " ").trim().split(" "); 517 | 518 | let varSymbol:VBSVariableSymbol = new VBSVariableSymbol(); 519 | varSymbol.args = ""; 520 | varSymbol.type = ""; 521 | varSymbol.visibility = ""; 522 | 523 | if(splittedByValByRefName.length == 1) 524 | varSymbol.name = splittedByValByRefName[0].trim(); 525 | else if(splittedByValByRefName.length > 1) 526 | { 527 | // ByVal or ByRef 528 | varSymbol.type = splittedByValByRefName[0].trim(); 529 | varSymbol.name = splittedByValByRefName[1].trim(); 530 | } 531 | 532 | let range = ls.Range.create( 533 | statement.GetPostitionByCharacter(argsIndex + arg.indexOf(varSymbol.name)), 534 | statement.GetPostitionByCharacter(argsIndex + arg.indexOf(varSymbol.name) + varSymbol.name.length) 535 | ); 536 | varSymbol.nameLocation = ls.Location.create(uri, range); 537 | varSymbol.symbolRange = range; 538 | 539 | symbols.push(varSymbol); 540 | argsIndex += arg.length + 1; // comma 541 | } 542 | 543 | return symbols; 544 | } 545 | 546 | function GetNumberOfFrontSpaces(line: string): number { 547 | let counter: number = 0; 548 | 549 | for (var i = 0; i < line.length; i++) { 550 | var char = line[i]; 551 | if(char == " " || char == "\t") 552 | counter++; 553 | else 554 | break; 555 | } 556 | 557 | return counter; 558 | } 559 | 560 | class OpenProperty { 561 | visibility: string; 562 | type: string; 563 | name: string; 564 | argsIndex: number; 565 | args: string; 566 | startPosition: ls.Position; 567 | nameLocation: ls.Location; 568 | statement: MultiLineStatement; 569 | } 570 | 571 | let openProperty: OpenProperty = null; 572 | 573 | function GetPropertyStart(statement: MultiLineStatement, uri: string) : boolean { 574 | let line: string = statement.GetFullStatement(); 575 | 576 | let propertyStartRegex:RegExp = /^[ \t]*(public[ \t]+|private[ \t]+)?(default[ \t]+)?(property[ \t]+)(let[ \t]+|set[ \t]+|get[ \t]+)([a-zA-Z0-9\-\_]+)([ \t]*)(\(([a-zA-Z0-9\_\-, \t(\(\))]*)\))?[ \t]*$/gi; 577 | let regexResult = propertyStartRegex.exec(line); 578 | 579 | if(regexResult == null || regexResult.length < 6) 580 | return null; 581 | 582 | let leadingSpaces = GetNumberOfFrontSpaces(line); 583 | let preLength = leadingSpaces + regexResult.index; 584 | 585 | for (var i = 1; i < 7; i++) { 586 | var resElement = regexResult[i]; 587 | if(resElement != null) 588 | preLength += resElement.length; 589 | } 590 | 591 | if(openProperty == null) { 592 | openProperty = { 593 | visibility: regexResult[1], 594 | type: regexResult[4], 595 | name: regexResult[5], 596 | argsIndex: preLength + 1, 597 | args: regexResult[8], 598 | startPosition: statement.GetPostitionByCharacter(leadingSpaces), 599 | nameLocation: ls.Location.create(uri, ls.Range.create( 600 | statement.GetPostitionByCharacter(line.indexOf(regexResult[5])), 601 | statement.GetPostitionByCharacter(line.indexOf(regexResult[5]) + regexResult[5].length)) 602 | ), 603 | statement: statement 604 | }; 605 | 606 | if(openProperty.args == null) 607 | openProperty.args = ""; 608 | 609 | return true; 610 | } else { 611 | // ERROR!!! I expected "end function|sub"! 612 | console.error("ERROR - line " + statement.startLine + " at " + statement.startCharacter + ": 'end property' expected!"); 613 | } 614 | 615 | return false; 616 | } 617 | 618 | function GetPropertySymbol(statement: MultiLineStatement, uri: string) : VBSSymbol[] { 619 | let line: string = statement.GetFullStatement(); 620 | 621 | let classEndRegex:RegExp = /^[ \t]*end[ \t]+property[ \t]*$/gi; 622 | 623 | let regexResult = classEndRegex.exec(line); 624 | 625 | if(regexResult == null || regexResult.length < 1) 626 | return null; 627 | 628 | if(openProperty == null) { 629 | // ERROR!!! I cannot close any property! 630 | console.error("ERROR - line " + statement.startLine + " at " + statement.startCharacter + ": There is no property to end!"); 631 | return null; 632 | } 633 | 634 | // range of the whole definition 635 | let range: ls.Range = ls.Range.create( 636 | openProperty.startPosition, 637 | statement.GetPostitionByCharacter(GetNumberOfFrontSpaces(line) + regexResult[0].trim().length) 638 | ); 639 | 640 | let symbol = new VBSPropertySymbol(); 641 | symbol.visibility = ""; 642 | symbol.type = openProperty.type; 643 | symbol.name = openProperty.name; 644 | symbol.args = openProperty.args; 645 | symbol.symbolRange = range; 646 | symbol.nameLocation = openProperty.nameLocation; 647 | symbol.parentName = openClassName; 648 | symbol.symbolRange = range; 649 | 650 | let parametersSymbol = GetParameterSymbols(openProperty.args, openProperty.argsIndex, openProperty.statement, uri); 651 | 652 | openProperty = null; 653 | 654 | return parametersSymbol.concat(symbol); 655 | } 656 | 657 | function GetMemberSymbol(statement: MultiLineStatement, uri: string) : VBSMemberSymbol { 658 | let line: string = statement.GetFullStatement(); 659 | 660 | let memberStartRegex:RegExp = /^[ \t]*(public[ \t]+|private[ \t]+)([a-zA-Z0-9\-\_]+)[ \t]*$/gi; 661 | let regexResult = memberStartRegex.exec(line); 662 | 663 | if(regexResult == null || regexResult.length < 3) 664 | return null; 665 | 666 | let visibility = regexResult[1]; 667 | let name = regexResult[2]; 668 | let intendention = GetNumberOfFrontSpaces(line); 669 | let nameStartIndex = line.indexOf(line); 670 | 671 | let range: ls.Range = ls.Range.create( 672 | statement.GetPostitionByCharacter(intendention), 673 | statement.GetPostitionByCharacter(intendention + regexResult[0].trim().length) 674 | ); 675 | 676 | let symbol: VBSMemberSymbol = new VBSMemberSymbol(); 677 | symbol.visibility = visibility; 678 | symbol.type = ""; 679 | symbol.name = name; 680 | symbol.args = ""; 681 | symbol.symbolRange = range; 682 | symbol.nameLocation = ls.Location.create(uri, 683 | ls.Range.create( 684 | statement.GetPostitionByCharacter(nameStartIndex), 685 | statement.GetPostitionByCharacter(nameStartIndex + name.length) 686 | ) 687 | ); 688 | symbol.parentName = openClassName; 689 | 690 | return symbol; 691 | } 692 | 693 | function GetVariableNamesFromList(vars: string): string[] { 694 | return vars.split(',').map(function(s) { return s.trim(); }); 695 | } 696 | 697 | function GetVariableSymbol(statement: MultiLineStatement, uri: string) : VBSVariableSymbol[] { 698 | let line: string = statement.GetFullStatement(); 699 | 700 | let variableSymbols: VBSVariableSymbol[] = []; 701 | let memberStartRegex:RegExp = /^[ \t]*(dim[ \t]+)(([a-zA-Z0-9\-\_]+[ \t]*\,[ \t]*)*)([a-zA-Z0-9\-\_]+)[ \t]*$/gi; 702 | let regexResult = memberStartRegex.exec(line); 703 | 704 | if(regexResult == null || regexResult.length < 3) 705 | return null; 706 | 707 | // (dim[ \t]+) 708 | let visibility = regexResult[1]; 709 | let variables = GetVariableNamesFromList(regexResult[2] + regexResult[4]); 710 | let intendention = GetNumberOfFrontSpaces(line); 711 | let nameStartIndex = line.indexOf(line); 712 | let firstElementOffset = visibility.length; 713 | let parentName: string = ""; 714 | 715 | if(openClassName != null) 716 | parentName = openClassName; 717 | 718 | if(openMethod != null) 719 | parentName = openMethod.name; 720 | 721 | if(openProperty != null) 722 | parentName = openProperty.name; 723 | 724 | for (let i = 0; i < variables.length; i++) { 725 | let varName = variables[i]; 726 | let symbol: VBSVariableSymbol = new VBSVariableSymbol(); 727 | symbol.visibility = ""; 728 | symbol.type = ""; 729 | symbol.name = varName; 730 | symbol.args = ""; 731 | symbol.nameLocation = ls.Location.create(uri, 732 | GetNameRange(statement, varName ) 733 | ); 734 | 735 | symbol.symbolRange = ls.Range.create( 736 | ls.Position.create(symbol.nameLocation.range.start.line, symbol.nameLocation.range.start.character - firstElementOffset), 737 | ls.Position.create(symbol.nameLocation.range.end.line, symbol.nameLocation.range.end.character) 738 | ); 739 | 740 | firstElementOffset = 0; 741 | symbol.parentName = parentName; 742 | 743 | variableSymbols.push(symbol); 744 | } 745 | 746 | return variableSymbols; 747 | } 748 | 749 | function GetNameRange(statement: MultiLineStatement, name: string): ls.Range { 750 | let line: string = statement.GetFullStatement(); 751 | 752 | let findVariableName = new RegExp("(" + name.trim() + "[ \t]*)(\,|$)","gi"); 753 | let matches = findVariableName.exec(line); 754 | 755 | let rng = ls.Range.create( 756 | statement.GetPostitionByCharacter(matches.index), 757 | statement.GetPostitionByCharacter(matches.index + name.trim().length) 758 | ); 759 | 760 | return rng; 761 | } 762 | 763 | function GetConstantSymbol(statement: MultiLineStatement, uri: string) : VBSConstantSymbol { 764 | if(openMethod != null || openProperty != null) 765 | return null; 766 | 767 | let line: string = statement.GetFullStatement(); 768 | 769 | let memberStartRegex:RegExp = /^[ \t]*(public[ \t]+|private[ \t]+)?const[ \t]+([a-zA-Z0-9\-\_]+)[ \t]*\=.*$/gi; 770 | let regexResult = memberStartRegex.exec(line); 771 | 772 | if(regexResult == null || regexResult.length < 3) 773 | return null; 774 | 775 | let visibility = regexResult[1]; 776 | if(visibility != null) 777 | visibility = visibility.trim(); 778 | 779 | let name = regexResult[2].trim(); 780 | let intendention = GetNumberOfFrontSpaces(line); 781 | let nameStartIndex = line.indexOf(line); 782 | 783 | let range: ls.Range = ls.Range.create( 784 | statement.GetPostitionByCharacter(intendention), 785 | statement.GetPostitionByCharacter(intendention + regexResult[0].trim().length) 786 | ); 787 | 788 | let parentName: string = ""; 789 | 790 | if(openClassName != null) 791 | parentName = openClassName; 792 | 793 | if(openMethod != null) 794 | parentName = openMethod.name; 795 | 796 | if(openProperty != null) 797 | parentName = openProperty.name; 798 | 799 | let symbol: VBSConstantSymbol = new VBSConstantSymbol(); 800 | symbol.visibility = visibility; 801 | symbol.type = ""; 802 | symbol.name = name; 803 | symbol.args = ""; 804 | symbol.symbolRange = range; 805 | symbol.nameLocation = ls.Location.create(uri, 806 | ls.Range.create( 807 | statement.GetPostitionByCharacter(nameStartIndex), 808 | statement.GetPostitionByCharacter(nameStartIndex + name.length) 809 | ) 810 | ); 811 | symbol.parentName = parentName; 812 | 813 | return symbol; 814 | } 815 | 816 | function GetClassStart(statement: MultiLineStatement, uri: string) : boolean { 817 | let line: string = statement.GetFullStatement(); 818 | 819 | let classStartRegex:RegExp = /^[ \t]*class[ \t]+([a-zA-Z0-9\-\_]+)[ \t]*$/gi; 820 | let regexResult = classStartRegex.exec(line); 821 | 822 | if(regexResult == null || regexResult.length < 2) 823 | return false; 824 | 825 | let name = regexResult[1]; 826 | openClassName = name; 827 | openClassStart = statement.GetPostitionByCharacter(GetNumberOfFrontSpaces(line)); 828 | 829 | return true; 830 | } 831 | 832 | function GetClassSymbol(statement: MultiLineStatement, uri: string) : VBSClassSymbol { 833 | let line: string = statement.GetFullStatement(); 834 | 835 | let classEndRegex:RegExp = /^[ \t]*end[ \t]+class[ \t]*$/gi; 836 | 837 | if(openClassName == null) 838 | return null; 839 | 840 | let regexResult = classEndRegex.exec(line); 841 | 842 | if(regexResult == null || regexResult.length < 1) 843 | return null; 844 | 845 | if(openMethod != null) { 846 | // ERROR! expected to close method before! 847 | console.error("ERROR - line " + statement.startLine + " at " + statement.startCharacter + ": 'end " + openMethod.type + "' expected!"); 848 | } 849 | 850 | if(openProperty != null) { 851 | // ERROR! expected to close property before! 852 | console.error("ERROR - line " + statement.startLine + " at " + statement.startCharacter + ": 'end property' expected!"); 853 | } 854 | 855 | let range: ls.Range = ls.Range.create(openClassStart, statement.GetPostitionByCharacter(regexResult[0].length)) 856 | let symbol: VBSClassSymbol = new VBSClassSymbol(); 857 | symbol.name = openClassName; 858 | symbol.nameLocation = ls.Location.create(uri, 859 | ls.Range.create(openClassStart, 860 | ls.Position.create(openClassStart.line, openClassStart.character + openClassName.length) 861 | ) 862 | ); 863 | symbol.symbolRange = range; 864 | //let symbol: ls.SymbolInformation = ls.SymbolInformation.create(openClassName, ls.SymbolKind.Class, range, uri); 865 | 866 | openClassName = null; 867 | openClassStart = ls.Position.create(-1, -1); 868 | 869 | return symbol; 870 | } 871 | 872 | // Listen on the connection 873 | connection.listen(); -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "lib" : [ "es2018" ], 8 | "outDir": "../client/server", 9 | "noImplicitAny": true, 10 | "removeComments": true 11 | }, 12 | "exclude": [ 13 | "node_modules" 14 | ], 15 | "types": [ 16 | "node" 17 | ] 18 | } --------------------------------------------------------------------------------