├── .github └── workflows │ └── main.yml ├── .gitignore ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── images ├── examples │ ├── block-clever.gif │ ├── block-select.gif │ ├── fast-array.gif │ ├── fast-arrow.gif │ ├── fast-curly.gif │ ├── index.js │ ├── macro-fragment.gif │ ├── macro-quickopen.gif │ ├── multipaste.gif │ ├── quote-switch.gif │ ├── template-var.gif │ ├── toggle-endline.gif │ └── toggle-maximize.gif ├── icon-small.png └── icon.png ├── keybindings.json ├── package.json ├── src ├── config.ts ├── controlers │ ├── block.ts │ ├── jump.ts │ ├── macro.ts │ ├── maximize.ts │ ├── multipast.ts │ ├── string.ts │ └── toggleEnd.ts ├── main.ts ├── models │ ├── EditorBuilder.ts │ └── RangeBuilder.ts ├── services │ ├── commands.ts │ ├── otherSelector.ts │ ├── ownSelector.ts │ ├── parser.ts │ ├── selector.ts │ └── string.ts └── utils │ ├── debug.ts │ ├── editor.ts │ ├── quote.ts │ └── utils.ts ├── test ├── index.ts └── main.test.ts ├── tsconfig.json └── yarn.lock /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - "*" 5 | 6 | name: Deploy Extension 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: 12 15 | - run: yarn install --frozen-lockfile 16 | - name: Publish to Visual Studio Marketplace 17 | uses: HaaLeo/publish-vscode-extension@v0 18 | with: 19 | # refresh: https://dev.azure.com/davidbabel/_usersSettings/tokens 20 | pat: ${{ secrets.VS_MARKETPLACE_TOKEN }} 21 | registryUrl: https://marketplace.visualstudio.com 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | vscode-reference.ts 4 | .vscode-test -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | test/** 5 | src/** 6 | **/*.map 7 | .gitignore 8 | tsconfig.json 9 | vsc-extension-quickstart.md 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "clever" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [0.0.13] - 24-02-2021 8 | 9 | - add fast array inserting for windows users 10 | - change default windows bind suggestion to more accurate ones 11 | - bump typescript version 12 | 13 | ## [0.0.11] - a long time ago 14 | 15 | - Initial release 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David B. 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 | # Clever Visual Studio Code 2 | 3 | 4 | 5 | **Clever vscode** was initially a personnal project to provide some missing features to the editor. It inspired from **Sublime Text**, **Google Chrome** and **iTerm** worflows. 6 | 7 | After sharing it with almost all my friends they motivate me to push it for cummunity. 8 | 9 | Suggestions, PR or ideas for embed macros are very welcome. 10 | 11 | Think about [rating and review](https://marketplace.visualstudio.com/items?itemName=davidbabel.Clever). 12 |


13 | 14 | ## Features 15 | 16 | Here are all the awesome current features of **Clever** (you can browse behaviour gifs below): 17 | 18 | - 🚀🚀🚀 [fast block select](#fast-block-select) 19 | - 💡 [maximise (toggle) the current editor](#toggle-maximise-current-editor) 20 | - ⚙️ [advanced macros system](#advanced-macros) 21 | - [Add fragment macro example](#add-fragment-macro-example) 22 | - [Sublime Text file navigation macro example](#sublime-text-file-navigation-macro-example) 23 | - [Rebind any key to another](#rebind-any-key-to-another) 24 | - 🚀🚀 [quick switch between string quotes ' → " → `](#quick-quotes-switch) 25 | - 🚀 [toggle endline with **","** or **";"** or **":"**](#toggle-endline) 26 | - 🚀 [insert incremental number or letter via multi cursor](#insert-incremental-numbers-or-letters) 27 | - 🚀 [fast cursor navigation / selection](#fast-cursor-navigation) 28 | - 🚀 [shortcut commands to](#shortcuts) : 29 | - [insert curly braces](#insert-curly-braces) 30 | - [insert array](#insert-array) 31 | - [insert arrow function](#insert-arrow-function) 32 | - [insert template string var](#insert-template-string-var) 33 | - ⚙️⚙️ [an advanced guide to improve vscode by config](#create-the-best-editor) 34 | - and more to come ... 35 | - and i'm aware of your ideas ([submit yours](#contribs)) 36 | 37 | Every feature comes with keybinding suggestions. On install, this extension does not set any keybinding to prevent issues with different countries keyboard compatibility and allow you to only use the keybindings you need. 38 | 39 | So you have to set it manually in your `keybindings.json`. We are developpers, we made the `json` version ;) 40 | 41 | ## Fast block select 42 | 43 | _Demo_ 44 | 45 | **Note** that this is a single same shortcut allowing this result : 46 | 47 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/block-clever.gif) 48 | 49 | _Binding suggestion:_ 50 | 51 | ```json 52 | { 53 | "key": "ctrl+r", 54 | "mac": "cmd+r", 55 | "command": "clever.blockSelect.cleverSelect", 56 | "when": "editorTextFocus" 57 | } 58 | ``` 59 | 60 | If needed, the following commands are also provided : 61 | 62 | ```js 63 | clever.blockSelect.quotes; // " " , ' ' , ` ` 64 | clever.blockSelect.parenthesis; // ( ) 65 | clever.blockSelect.squareBrackets; // [ ] 66 | clever.blockSelect.curlyBrackets; // { } 67 | clever.blockSelect.angleBrackets; // 68 | clever.blockSelect.inTag; // <> inTag 69 | ``` 70 | 71 | I recommand you to bind them to something like `cmd+k '` or `cmd+k (` etc ... It's very handy and may not create binding conflicts. 72 | 73 | ## Toggle maximise current editor 74 | 75 | _Demo_ 76 | 77 | **Note:** this is especially helpfull on a side comparaison during commit diff 78 | 79 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/toggle-maximize.gif) 80 | 81 | _Binding suggestion:_ 82 | 83 | ```json 84 | { 85 | "key": "shift+ctrl+enter", 86 | "mac": "shift+cmd+enter", 87 | "command": "clever.maximize.toggleWithSidebar", 88 | "when": "editorTextFocus" 89 | } 90 | ``` 91 | 92 | If needed, the following command is also provided : 93 | 94 | ```js 95 | clever.maximize.toggleWithoutSidebar; 96 | ``` 97 | 98 | ## Advanced macros 99 | 100 | The Macro feature allows you to execute a list of vscode commands or any extensions commands, including "clever vscode" ones. 101 | 102 | It also provides two helpers commands (see examples below for API): 103 | 104 | - a `wait` helper to be able to manage async commands (especially extension ones which may miss to await callbacks). 105 | - a `type` helper to insert text, like a "programmatic snippet". 106 | 107 | Each macro is a "config / keybinding" combo. The wanted macro got a name, and an array of commands : 108 | 109 | ### Add fragment macro example 110 | 111 | _Demo_ 112 | 113 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/macro-fragment.gif) 114 | 115 | _Configs_ 116 | 117 | ```js 118 | { 119 | "clever.macros": { 120 | "exampleAddFragment": [ // macro name to remember in bindings 121 | "type:<>\n\n", // type command with text param 122 | "cursorUp" // 2nd command 123 | ], 124 | "betterAddFragment": [ 125 | "type:<>\n$1\n" // type also support snippet syntax 126 | ] 127 | // "otherMacro": [/* commands list */] 128 | // ... 129 | } 130 | } 131 | ``` 132 | 133 | _Binding suggestion:_ 134 | 135 | ```json 136 | { 137 | "key": "whatever you want", 138 | "command": "clever.macros.betterAddFragment", 139 | "when": "editorTextFocus" 140 | } 141 | ``` 142 | 143 | **Note:** to find every commands available, browse it in the shortcut palette `cmd+k cmd+s` 144 | 145 | ### Sublime Text file navigation macro example 146 | 147 | Another example, this macro allow to fastOpen a file without loosing focus from the file explorer (sublime text style). 148 | 149 | _Demo_ 150 | 151 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/macro-quickopen.gif) 152 | 153 | This workflow is amazing, it allows you to not use your mouse to open quickly multiple files. Check the [advanced config guide](#create-the-best-editor) to create a enhanced navigation system into vscode. 154 | 155 | _Configs_ 156 | 157 | ```js 158 | { 159 | "clever.macros": { 160 | "fastOpenFile": [ 161 | "list.select", // open current hover file 162 | "wait:20", // wait for 20ms before next (default 50ms) 163 | "workbench.action.focusSideBar" // send focus back to the file explorer 164 | ], 165 | "openAndKeepFile": [ 166 | "list.select", // open current hover file 167 | "workbench.action.files.save", // this will keep the file open 168 | "wait:20", // wait for 20ms before next (default 50ms) 169 | "workbench.action.focusSideBar" // send focus back to the file explorer 170 | ], 171 | "openFile": [ 172 | "list.select", // open current hover file 173 | "workbench.action.files.save", // this will keep the file open 174 | ] 175 | } 176 | } 177 | ``` 178 | 179 | _Binding suggestion:_ 180 | 181 | **Note:** to be able to map "enter" here you have to unbind it first. (see the [advanced config guide](#create-the-best-editor) to do so) 182 | 183 | ```js 184 | { 185 | "key": "right", 186 | "command": "clever.macros.fastOpenFile", 187 | "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !inputFocus" 188 | }, 189 | { 190 | // note : "enter" must be unbind first 191 | "key": "enter", 192 | "command": "clever.macros.openAndKeepFile", 193 | "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !inputFocus" 194 | }, 195 | { 196 | "key": "left", 197 | "command": "clever.macros.openFile", 198 | "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !inputFocus" 199 | } 200 | ``` 201 | 202 | ### Rebind any key to another 203 | 204 | The following will insert a `b` when you type a `j`. It works with any key, especially special characters. 205 | 206 | _Configs_ 207 | 208 | ```js 209 | { 210 | "clever.macros": { 211 | "b": ["type:b"] 212 | } 213 | } 214 | ``` 215 | 216 | _Binding example:_ 217 | 218 | ```json 219 | { 220 | "key": "j", 221 | "command": "clever.macros.b", 222 | "when": "editorTextFocus" 223 | } 224 | ``` 225 | 226 | ## Quick quotes switch 227 | 228 | _Demo_ 229 | 230 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/quote-switch.gif) 231 | 232 | _Binding suggestion:_ 233 | 234 | ```json 235 | { 236 | "key": "alt+3", 237 | "mac": "cmd+`", 238 | "command": "clever.string.nextQuotes", 239 | "when": "editorTextFocus" 240 | } 241 | ``` 242 | 243 | ## Toggle endline 244 | 245 | _Demo_ 246 | 247 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/toggle-endline.gif) 248 | 249 | _Binding suggestion:_ 250 | 251 | ```json 252 | ({ 253 | "key": "ctrl+oem_period", 254 | "mac": "cmd+;", 255 | "command": "clever.toggleEnd.semicolon", 256 | "when": "editorTextFocus" 257 | }, 258 | { 259 | "key": "ctrl+oem_2", 260 | "mac": "cmd+:", 261 | "command": "clever.toggleEnd.colon", 262 | "when": "editorTextFocus" 263 | }, 264 | { 265 | "key": "ctrl+oem_comma", 266 | "mac": "cmd+[Comma]", 267 | "command": "clever.toggleEnd.comma", 268 | "when": "editorTextFocus" 269 | }) 270 | ``` 271 | 272 | ## Insert incremental numbers or letters 273 | 274 | _Demo_ 275 | 276 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/multipaste.gif) 277 | 278 | _Binding suggestion:_ 279 | 280 | ```json 281 | ({ 282 | "key": "shift+ctrl+0", 283 | "mac": "shift+cmd+0", 284 | "command": "clever.multipast.0toN", 285 | "when": "editorTextFocus" 286 | }, 287 | { 288 | "key": "shift+ctrl+1", 289 | "mac": "shift+cmd+1", 290 | "command": "clever.multipast.1toN", 291 | "when": "editorTextFocus" 292 | }, 293 | { 294 | "key": "shift+ctrl+a", 295 | "mac": "shift+cmd+a", 296 | "command": "clever.multipast.atoN", 297 | "when": "editorTextFocus" 298 | }, 299 | { 300 | "key": "shift+alt+ctrl+a", 301 | "mac": "shift+alt+cmd+a", 302 | "command": "clever.multipast.AtoN", 303 | "when": "editorTextFocus" 304 | }) 305 | ``` 306 | 307 | ## Fast cursor navigation 308 | 309 | _Demo_ 310 | 311 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/block-select.gif) 312 | 313 | _Configs_ 314 | 315 | ```js 316 | // Clever: number of lines of small jumps 317 | "clever.fastJump.small.linesToJump": 5, 318 | // Clever: number of lines of large jumps 319 | "clever.fastJump.large.linesToJump": 10 320 | ``` 321 | 322 | _Binding suggestion:_ 323 | 324 | ```json 325 | ({ 326 | "key": "ctrl+up", 327 | "mac": "cmd+up", 328 | "command": "clever.fastJump.small.up", 329 | "when": "editorTextFocus" 330 | }, 331 | { 332 | "key": "ctrl+down", 333 | "mac": "cmd+down", 334 | "command": "clever.fastJump.small.down", 335 | "when": "editorTextFocus" 336 | }, 337 | { 338 | "key": "shift+ctrl+up", 339 | "mac": "shift+cmd+up", 340 | "command": "clever.fastJump.small.selectUp", 341 | "when": "editorTextFocus" 342 | }, 343 | { 344 | "key": "shift+ctrl+down", 345 | "mac": "shift+cmd+down", 346 | "command": "clever.fastJump.small.selectDown", 347 | "when": "editorTextFocus" 348 | }, 349 | { 350 | "key": "alt+ctrl+pageup", 351 | "mac": "alt+cmd+pageup", 352 | "command": "clever.fastJump.big.up", 353 | "when": "editorTextFocus" 354 | }, 355 | { 356 | "key": "alt+ctrl+pagedown", 357 | "mac": "alt+cmd+pagedown", 358 | "command": "clever.fastJump.big.down", 359 | "when": "editorTextFocus" 360 | }, 361 | { 362 | "key": "shift+alt+ctrl+pageup", 363 | "mac": "shift+alt+cmd+pageup", 364 | "command": "clever.fastJump.big.selectUp", 365 | "when": "editorTextFocus" 366 | }, 367 | { 368 | "key": "shift+alt+ctrl+pagedown", 369 | "mac": "shift+alt+cmd+pagedown", 370 | "command": "clever.fastJump.big.selectDown", 371 | "when": "editorTextFocus" 372 | }) 373 | ``` 374 | 375 | ## Shortcuts 376 | 377 | Clever also provide some usefull shortcuts out of the box. 378 | 379 | ### Insert curly braces 380 | 381 | _Demo_ 382 | 383 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/fast-curly.gif) 384 | 385 | _Binding suggestion:_ 386 | 387 | ```json 388 | { 389 | "key": "alt-4", 390 | "mac": "cmd+{", 391 | "command": "clever.fastInsert.curly", 392 | "when": "editorTextFocus" 393 | } 394 | ``` 395 | 396 | ### Insert array 397 | 398 | _Demo_ 399 | 400 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/fast-array.gif) 401 | 402 | _Binding suggestion:_ 403 | 404 | ```json 405 | { 406 | "key": "alt+5", 407 | "mac": "cmd+{", 408 | "command": "clever.fastInsert.array", 409 | "when": "editorTextFocus" 410 | }, 411 | ``` 412 | 413 | ### Insert arrow function 414 | 415 | _Demo_ (not related to intellisense, this is a keyboard shortcut) 416 | 417 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/fast-arrow.gif) 418 | 419 | _Binding suggestion:_ 420 | 421 | ```json 422 | { 423 | "key": "ctrl+3", 424 | "mac": "cmd+=", 425 | "command": "clever.fastInsert.arrowFunction", 426 | "when": "editorTextFocus" 427 | } 428 | ``` 429 | 430 | ### Insert template string var 431 | 432 | _Demo_ 433 | 434 | ![](https://raw.githubusercontent.com/DavidBabel/clever-vscode/master/images/examples/template-var.gif) 435 | 436 | _Binding suggestion:_ 437 | 438 | ```json 439 | { 440 | "key": "ctrl+oem_1", 441 | "mac": "cmd+$", 442 | "command": "clever.string.insertTemplateVar", 443 | "when": "editorTextFocus" 444 | } 445 | ``` 446 | 447 | ## Create the best editor 448 | 449 | Here is a complete guide to custom your editor the right way. 450 | 451 | This does not need any extension, only modify the editor `settings.json` and `keybindings.json` the right way. 452 | 453 | // WIP 454 | 455 | Take a look at https://vscodecandothat.com/. You will learn a lot a things, for sure. 456 | 457 | ## Contribs 458 | 459 | If you want to help, find a bug or just correct an english mistake please [create an issue](https://github.com/DavidBabel/clever-vscode/issues). 460 | 461 | ## Inspirations & credits 462 | 463 | - document parser by Vilic : https://github.com/vilic/vscode-es-quotes 464 | - selecting library by dbankier https://github.com/dbankier/vscode-quick-select 465 | 466 | ## Why embed other libraries 467 | 468 | For me, the features provided by the embed library are from far, the big miss in vscode base commands. I had to modify some of it to add new awesome features. 469 | 470 | Also, as i said in introduction, i made this library for myself initially, and include them to be sure they will never disapear or stop to be maintained with a possible incompatible vscode version. 471 | 472 | ## License 473 | 474 | MIT. Copyright (c) David Babel. 475 | 476 | **Donations:** If you like this package, want it to be maintained and use it to makes millions, you can buy me [a coffee](https://www.paypal.me/devilhunter/2) ☕ or [a beer](https://www.paypal.me/devilhunter/4) 🍺. 477 | -------------------------------------------------------------------------------- /images/examples/block-clever.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/block-clever.gif -------------------------------------------------------------------------------- /images/examples/block-select.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/block-select.gif -------------------------------------------------------------------------------- /images/examples/fast-array.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/fast-array.gif -------------------------------------------------------------------------------- /images/examples/fast-arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/fast-arrow.gif -------------------------------------------------------------------------------- /images/examples/fast-curly.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/fast-curly.gif -------------------------------------------------------------------------------- /images/examples/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/index.js -------------------------------------------------------------------------------- /images/examples/macro-fragment.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/macro-fragment.gif -------------------------------------------------------------------------------- /images/examples/macro-quickopen.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/macro-quickopen.gif -------------------------------------------------------------------------------- /images/examples/multipaste.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/multipaste.gif -------------------------------------------------------------------------------- /images/examples/quote-switch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/quote-switch.gif -------------------------------------------------------------------------------- /images/examples/template-var.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/template-var.gif -------------------------------------------------------------------------------- /images/examples/toggle-endline.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/toggle-endline.gif -------------------------------------------------------------------------------- /images/examples/toggle-maximize.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/examples/toggle-maximize.gif -------------------------------------------------------------------------------- /images/icon-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/icon-small.png -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidBabel/clever-vscode/578a296a5c65d884ced1dc7e3d25e54db41f819c/images/icon.png -------------------------------------------------------------------------------- /keybindings.json: -------------------------------------------------------------------------------- 1 | { 2 | "keybindings": [ 3 | { 4 | "command": "clever.blockSelect.cleverSelect", 5 | "key": "shift+ctrl+dd", 6 | "mac": "cmd+1", 7 | "when": "editorTextFocus" 8 | }, 9 | { 10 | "command": "clever.blockSelect.quotes", 11 | "key": "shift+ctrl+dd", 12 | "mac": "cmd+2", 13 | "when": "editorTextFocus" 14 | }, 15 | { 16 | "command": "clever.blockSelect.quotesBeta", 17 | "key": "shift+ctrl+dd", 18 | "mac": "cmd+8", 19 | "when": "editorTextFocus" 20 | }, 21 | { 22 | "command": "clever.blockSelect.parenthesis", 23 | "key": "shift+ctrl+dd", 24 | "mac": "cmd+3", 25 | "when": "editorTextFocus" 26 | }, 27 | { 28 | "command": "clever.blockSelect.squareBrackets", 29 | "key": "shift+ctrl+dd", 30 | "mac": "cmd+4", 31 | "when": "editorTextFocus" 32 | }, 33 | { 34 | "command": "clever.blockSelect.curlyBrackets", 35 | "key": "shift+ctrl+dd", 36 | "mac": "cmd+5", 37 | "when": "editorTextFocus" 38 | }, 39 | { 40 | "command": "clever.blockSelect.angleBrackets", 41 | "key": "shift+ctrl+dd", 42 | "mac": "cmd+6", 43 | "when": "editorTextFocus" 44 | }, 45 | { 46 | "command": "clever.blockSelect.inTag", 47 | "key": "shift+ctrl+dd", 48 | "mac": "cmd+7", 49 | "when": "editorTextFocus" 50 | }, 51 | { 52 | "command": "clever.rebind.•", 53 | "key": "alt+[IntlBackslash]", 54 | "when": "editorTextFocus" 55 | }, 56 | { 57 | "command": "clever.rebind.", 58 | "key": "alt+1", 59 | "when": "editorTextFocus" 60 | }, 61 | { 62 | "command": "clever.rebind.¶", 63 | "key": "alt+6", 64 | "when": "editorTextFocus" 65 | }, 66 | { 67 | "command": "clever.rebind.®", 68 | "key": "alt+r", 69 | "when": "editorTextFocus" 70 | }, 71 | { 72 | "command": "clever.rebind.†", 73 | "key": "alt+t", 74 | "when": "editorTextFocus" 75 | }, 76 | { 77 | "command": "clever.rebind.º", 78 | "key": "alt+u", 79 | "when": "editorTextFocus" 80 | }, 81 | { 82 | "command": "clever.rebind.π", 83 | "key": "alt+p", 84 | "when": "editorTextFocus" 85 | }, 86 | { 87 | "command": "clever.rebind.‡", 88 | "key": "alt+q", 89 | "when": "editorTextFocus" 90 | }, 91 | { 92 | "command": "clever.rebind.ƒ", 93 | "key": "alt+f", 94 | "when": "editorTextFocus" 95 | }, 96 | { 97 | "command": "clever.rebind.fi", 98 | "key": "alt+g", 99 | "when": "editorTextFocus" 100 | }, 101 | { 102 | "command": "clever.rebind.¬", 103 | "key": "alt+l", 104 | "when": "editorTextFocus" 105 | }, 106 | { 107 | "command": "clever.rebind.µ", 108 | "key": "alt+m", 109 | "when": "editorTextFocus" 110 | }, 111 | { 112 | "command": "clever.rebind.≈", 113 | "key": "alt+x", 114 | "when": "editorTextFocus" 115 | }, 116 | { 117 | "command": "clever.rebind.©", 118 | "key": "alt+c", 119 | "when": "editorTextFocus" 120 | }, 121 | { 122 | "command": "clever.rebind.◊", 123 | "key": "alt+v", 124 | "when": "editorTextFocus" 125 | }, 126 | { 127 | "command": "clever.rebind.ß", 128 | "key": "alt+b", 129 | "when": "editorTextFocus" 130 | }, 131 | { 132 | "command": "clever.rebind.∞", 133 | "key": "alt+[KeyM]", 134 | "when": "editorTextFocus" 135 | }, 136 | { 137 | "command": "clever.rebind.…", 138 | "key": "alt+[Comma]", 139 | "when": "editorTextFocus" 140 | }, 141 | { 142 | "command": "clever.rebind.÷", 143 | "key": "alt+[Period]", 144 | "when": "editorTextFocus" 145 | }, 146 | { 147 | "command": "clever.rebind.≠", 148 | "key": "alt+=", 149 | "when": "editorTextFocus" 150 | } 151 | ] 152 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "clever", 3 | "displayName": "Clever VSCode", 4 | "description": "Add many productivity usefull commands to vscode", 5 | "version": "0.1.1", 6 | "publisher": "davidbabel", 7 | "author": { 8 | "email": "babel.david@gmail.com", 9 | "name": "David Babel", 10 | "url": "https://github.com/DavidBabel/clever-vscode" 11 | }, 12 | "license": "MIT", 13 | "engines": { 14 | "vscode": "^1.15.0" 15 | }, 16 | "categories": [ 17 | "Snippets", 18 | "Keymaps", 19 | "Other" 20 | ], 21 | "keywords": [ 22 | "productivity", 23 | "macro", 24 | "macros", 25 | "smart", 26 | "clever", 27 | "better", 28 | "jump", 29 | "rebind", 30 | "indent", 31 | "format", 32 | "selection", 33 | "navigation", 34 | "maximize", 35 | "toggle" 36 | ], 37 | "activationEvents": [ 38 | "*" 39 | ], 40 | "main": "./out/src/main", 41 | "icon": "images/icon.png", 42 | "homepage": "https://github.com/DavidBabel/clever-vscode/blob/master/README.md", 43 | "repository": { 44 | "type": "git", 45 | "url": "https://github.com/DavidBabel/clever-vscode.git" 46 | }, 47 | "bugs": { 48 | "url": "https://github.com/DavidBabel/clever-vscode/issues" 49 | }, 50 | "contributes": { 51 | "commands": [ 52 | { 53 | "command": "clever.toggleEnd.semicolon", 54 | "title": "Clever: Toggle semicolon" 55 | }, 56 | { 57 | "command": "clever.toggleEnd.colon", 58 | "title": "Clever: Toggle colon" 59 | }, 60 | { 61 | "command": "clever.toggleEnd.comma", 62 | "title": "Clever: Toggle comma" 63 | }, 64 | { 65 | "command": "clever.string.insertTemplateVar", 66 | "title": "Insert Template string" 67 | }, 68 | { 69 | "command": "clever.string.nextQuotes", 70 | "title": "Switch to next quotes style" 71 | }, 72 | { 73 | "command": "clever.multipast.0toN", 74 | "title": "Multi Paste from 0 to N" 75 | }, 76 | { 77 | "command": "clever.multipast.1toN", 78 | "title": "Multi Paste from 1 to N" 79 | }, 80 | { 81 | "command": "clever.multipast.atoN", 82 | "title": "Multi Paste from a to N" 83 | }, 84 | { 85 | "command": "clever.multipast.AtoN", 86 | "title": "Multi Paste from A to N" 87 | }, 88 | { 89 | "command": "clever.fastJump.small.up", 90 | "title": "Clever: fastJump up (small)" 91 | }, 92 | { 93 | "command": "clever.fastJump.small.down", 94 | "title": "Clever: fastJump down (small)" 95 | }, 96 | { 97 | "command": "clever.fastJump.small.selectUp", 98 | "title": "Clever: fastJump up with select (small)" 99 | }, 100 | { 101 | "command": "clever.fastJump.small.selectDown", 102 | "title": "Clever: fastJump down with select (small)" 103 | }, 104 | { 105 | "command": "clever.fastJump.big.up", 106 | "title": "Clever: fastJump up (big)" 107 | }, 108 | { 109 | "command": "clever.fastJump.big.down", 110 | "title": "Clever: fastJump down (big)" 111 | }, 112 | { 113 | "command": "clever.fastJump.big.selectUp", 114 | "title": "Clever: fastJump up with select (big)" 115 | }, 116 | { 117 | "command": "clever.fastJump.big.selectDown", 118 | "title": "Clever: fastJump down with select (big)" 119 | }, 120 | { 121 | "command": "clever.fastInsert.curly", 122 | "title": "Clever: fast add {curly} block at end of line" 123 | }, 124 | { 125 | "command": "clever.fastInsert.array", 126 | "title": "Clever: fast add [] array block (usefull on windows)" 127 | }, 128 | { 129 | "command": "clever.fastInsert.arrowFunction", 130 | "title": "Clever: fast add arrow function" 131 | }, 132 | { 133 | "command": "clever.maximize.toggleWithSidebar", 134 | "title": "Clever: toggle maximize current editor (with sidebar)" 135 | }, 136 | { 137 | "command": "clever.maximize.toggleWithoutSidebar", 138 | "title": "Clever: toggle maximize current editor (without sidebar)" 139 | }, 140 | { 141 | "command": "clever.blockSelect.cleverSelect", 142 | "title": "Clever: cleverSelect" 143 | }, 144 | { 145 | "command": "clever.blockSelect.quotes", 146 | "title": "Clever: Select current block quotes" 147 | }, 148 | { 149 | "command": "clever.blockSelect.quotesBeta", 150 | "title": "Clever: Select current block quotesBeta" 151 | }, 152 | { 153 | "command": "clever.blockSelect.parenthesis", 154 | "title": "Clever: Select current block parenthesis ()" 155 | }, 156 | { 157 | "command": "clever.blockSelect.squareBrackets", 158 | "title": "Clever: Select current block squareBrackets []" 159 | }, 160 | { 161 | "command": "clever.blockSelect.curlyBrackets", 162 | "title": "Clever: Select current block curlyBrackets {}" 163 | }, 164 | { 165 | "command": "clever.blockSelect.angleBrackets", 166 | "title": "Clever: Select current block angleBrackets <>" 167 | }, 168 | { 169 | "command": "clever.blockSelect.inTag", 170 | "title": "Clever: Select current block inTag <>" 171 | } 172 | ], 173 | "configuration": { 174 | "type": "object", 175 | "title": "Clever Configuration", 176 | "properties": { 177 | "clever.macros": { 178 | "type": "object", 179 | "default": {}, 180 | "description": "Clever: you can define macros here. see clever/README.md for more informations." 181 | }, 182 | "clever.fastJump.small.linesToJump": { 183 | "type": "number", 184 | "default": 5, 185 | "description": "Clever: number of lines of small jumps" 186 | }, 187 | "clever.fastJump.large.linesToJump": { 188 | "type": "number", 189 | "default": 10, 190 | "description": "Clever: number of lines of large jumps" 191 | } 192 | } 193 | } 194 | }, 195 | "scripts": { 196 | "vscode:prepublish": "tsc -p ./", 197 | "compile": "tsc -watch -p ./", 198 | "postinstall": "node ./node_modules/vscode/bin/install", 199 | "test": "node ./node_modules/vscode/bin/test" 200 | }, 201 | "devDependencies": { 202 | "@types/mocha": "^2.2.42", 203 | "@types/node": "^6.0.88", 204 | "mocha": "^3.5.0", 205 | "typescript": "^4.2.2", 206 | "vscode": "^1.1.5" 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | workspace as Workspace 3 | } from 'vscode'; 4 | 5 | export const staticConfig = { 6 | macroDefaultWaitDelay: 50 7 | }; 8 | 9 | export default function config(): any { 10 | return { 11 | ...staticConfig, 12 | ...Workspace.getConfiguration('clever') 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/controlers/block.ts: -------------------------------------------------------------------------------- 1 | import { 2 | window as Window, 3 | commands as Commands, 4 | Range, 5 | Position, 6 | Selection 7 | } from 'vscode'; 8 | // import { blockSelect } from '../services/selector'; 9 | import { prepareEdit } from '../utils/editor'; 10 | 11 | export function deployBlock() { 12 | const editor = Window.activeTextEditor; 13 | const document = editor.document; 14 | 15 | // blockSelect(); 16 | // prepareEdit((editBuilder, selection) => { 17 | // const initialText = document.getText(selection); 18 | // // const initialTextAsObject = JSON.parse(initialText); 19 | // let newText = initialText; 20 | // if ( selection.isSingleLine ) { 21 | // // let indentationChar = editor.options.insertSpaces ? ' ' : '\t'; 22 | // // let levelOfIndent = newText.search(/\S/); 23 | // // let padding = indentationChar.repeat(levelOfIndent + editor.options.tabSize); 24 | // newText = initialText.replace(/,/g, ',\n'); 25 | // newText = newText.replace(/{/g, '{\n'); 26 | // newText = newText.replace(/}/g, '\n}'); 27 | // // newText = newText.replace(/\n/g, '\n'); 28 | // } else { 29 | // // remove multiples spaces 30 | // newText = initialText.replace(/\s+/g,' '); 31 | // } 32 | // editBuilder.replace(selection, newText); 33 | 34 | // // selection.intersection(new Range(selection.(1, 1), selection.translate(1, 1))) 35 | // editor.selection = new Selection( 36 | // new Position(selection.start.line, selection.start.character + 1), 37 | // new Position(selection.end.line, selection.end.character - 1), 38 | // ); 39 | // }); 40 | // Commands.executeCommand('editor.action.formatSelection'); 41 | } 42 | 43 | export function imployBlock() { 44 | 45 | } -------------------------------------------------------------------------------- /src/controlers/jump.ts: -------------------------------------------------------------------------------- 1 | import { 2 | commands as Commands 3 | } from 'vscode'; 4 | import config from '../config'; 5 | // import { prepareEdit } from "../utils/editor"; 6 | 7 | type Jump = { 8 | size: number, 9 | direction: string 10 | }; 11 | 12 | export const jumpSizes = { 13 | small: { 14 | up: { 15 | size: config().fastJump.small.linesToJump, 16 | direction: 'Up' 17 | }, 18 | down: { 19 | size: config().fastJump.small.linesToJump, 20 | direction: 'Down' 21 | }, 22 | }, 23 | big: { 24 | up: { 25 | size: config().fastJump.large.linesToJump, 26 | direction: 'Up' 27 | }, 28 | down: { 29 | size: config().fastJump.large.linesToJump, 30 | direction: 'Down' 31 | } 32 | } 33 | }; 34 | 35 | export function jumpLines(jumpSizes: Jump) { 36 | const command = 'cursor' + jumpSizes.direction; 37 | for (let i = 0; i < jumpSizes.size; i++) { 38 | Commands.executeCommand(command); 39 | } 40 | } 41 | 42 | export function jumpSelectLines( jumpSizes: Jump) { 43 | const command = `cursor${jumpSizes.direction}Select`; 44 | for (let i = 0; i < jumpSizes.size; i++) { 45 | Commands.executeCommand(command); 46 | } 47 | } -------------------------------------------------------------------------------- /src/controlers/macro.ts: -------------------------------------------------------------------------------- 1 | import config from "../config"; 2 | import { executeCommands } from "../services/commands"; 3 | import { insertSnippet } from "../services/string"; 4 | 5 | export function executeMacro(macroName: string) { 6 | const commands = config().macros[macroName]; 7 | if (commands) { 8 | executeCommands(commands); 9 | } 10 | } 11 | 12 | export function fastCurly() { 13 | executeCommands([ 14 | "cursorEnd", 15 | "wait:60", 16 | insertSnippet.bind(null, " {\n\t$1\n}"), 17 | ]); 18 | } 19 | export function fastArray() { 20 | executeCommands([insertSnippet.bind(null, "[$1]")]); 21 | } 22 | 23 | export function fastArrowFunction() { 24 | insertSnippet("($1) => {\n\t$2\n}"); 25 | } 26 | 27 | // TODO add more embed functions 28 | export function previewCurrentFile() { 29 | executeCommands(["list.select", "wait", "workbench.action.focusSideBar"]); 30 | } 31 | 32 | // export function closeCurrentOpened() { 33 | // executeCommands([ 34 | // "list.select", 35 | // "wait", 36 | // "workbench.action.focusSideBar" 37 | // ]); 38 | // } 39 | -------------------------------------------------------------------------------- /src/controlers/maximize.ts: -------------------------------------------------------------------------------- 1 | import { 2 | commands as Commands 3 | } from 'vscode'; 4 | 5 | let currentlyExpended = false; 6 | 7 | export async function toggleMaximize(withSideBar: boolean = true) { 8 | if (currentlyExpended) { 9 | if (withSideBar) { 10 | await Commands.executeCommand('workbench.action.toggleSidebarVisibility'); 11 | } 12 | await Commands.executeCommand('workbench.action.evenEditorWidths'); 13 | await Commands.executeCommand('workbench.action.focusActiveEditorGroup'); 14 | } else { 15 | await Commands.executeCommand('workbench.action.maximizeEditor'); 16 | await Commands.executeCommand('workbench.action.maximizeEditor'); 17 | } 18 | currentlyExpended = !currentlyExpended; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/controlers/multipast.ts: -------------------------------------------------------------------------------- 1 | import { prepareEdit } from "../utils/editor"; 2 | import { nextToken } from '../utils/utils'; 3 | 4 | export function multiPast(initChar: string|number) { 5 | let currentChar = initChar; 6 | prepareEdit((editBuilder, selection) => { 7 | editBuilder.insert(selection.start, currentChar.toString()); 8 | currentChar = nextToken(currentChar); 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /src/controlers/string.ts: -------------------------------------------------------------------------------- 1 | 2 | import { 3 | window as Window, 4 | workspace as Workspace, 5 | SnippetString 6 | } from 'vscode'; 7 | import { prepareEdit } from '../utils/editor'; 8 | import { parse, findActiveStringTarget } from '../services/parser'; 9 | import { getNextQuotes } from '../utils/quote'; 10 | import config from '../config'; 11 | 12 | export { insertBind, insertSnippet } from '../services/string'; 13 | // export { insertBind, insertSnippet }; 14 | 15 | export function toggleRebindActivation() { 16 | Workspace.getConfiguration('clever').update('disableRebindForEdit', !config().disableRebindForEdit); 17 | } 18 | 19 | export function nextQuotes() { 20 | try { 21 | prepareEdit((editBuilder, selection) => { 22 | const source = Window.activeTextEditor.document.getText(); 23 | if (!source) return; 24 | const result = parse(source); 25 | if (!result || !result.stringTargets) return; 26 | const activeTarget = findActiveStringTarget(result.stringTargets, selection); 27 | if (!activeTarget) return; 28 | editBuilder.replace(activeTarget.range, getNextQuotes(activeTarget)); 29 | }); 30 | } catch (error) { 31 | // :) 32 | } 33 | } -------------------------------------------------------------------------------- /src/controlers/toggleEnd.ts: -------------------------------------------------------------------------------- 1 | import { prepareEdit } from "../utils/editor"; 2 | 3 | export function toggleEnd (char: string) { 4 | prepareEdit((editBuilder, selection, lines) => { 5 | lines.forEach(line => { 6 | if (line.text.endsWith(char)) { 7 | editBuilder.deleteEol(line, char.length); 8 | } else { 9 | editBuilder.insertEol(line, char); 10 | } 11 | }); 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | commands as Commands, 3 | ExtensionContext, 4 | window as Window, 5 | } from "vscode"; 6 | import config from "./config"; 7 | import { jumpLines, jumpSelectLines, jumpSizes } from "./controlers/jump"; 8 | import { 9 | executeMacro, 10 | fastArray, 11 | fastArrowFunction, 12 | fastCurly, 13 | previewCurrentFile, 14 | } from "./controlers/macro"; 15 | import { toggleMaximize } from "./controlers/maximize"; 16 | import { multiPast } from "./controlers/multipast"; 17 | import { insertSnippet, nextQuotes } from "./controlers/string"; 18 | import { toggleEnd } from "./controlers/toggleEnd"; 19 | import { 20 | cleverSelect, 21 | matchingSelect, 22 | selectEitherQuote, 23 | } from "./services/selector"; 24 | 25 | // import { matchingSelect } from './services/selector'; 26 | // import { deployBlock, imployBlock } from './controlers/block'; 27 | 28 | export function activate(context: ExtensionContext) { 29 | console.log('Congratulations, you are now "clever" than ever!'); 30 | 31 | const _ = null; 32 | const r = (s: string, cb: (...args: any[]) => any) => 33 | Commands.registerCommand(s, cb); 34 | 35 | context.subscriptions.push( 36 | r("clever.toggleEnd.comma", toggleEnd.bind(_, ",")), 37 | r("clever.toggleEnd.semicolon", toggleEnd.bind(_, ";")), 38 | r("clever.toggleEnd.colon", toggleEnd.bind(_, ":")), 39 | r("clever.string.insertTemplateVar", insertSnippet.bind(_, "${$1}")), 40 | r("clever.string.nextQuotes", nextQuotes), 41 | r("clever.multipast.0toN", multiPast.bind(_, 0)), 42 | r("clever.multipast.1toN", multiPast.bind(_, 1)), 43 | r("clever.multipast.atoN", multiPast.bind(_, "a")), 44 | r("clever.multipast.AtoN", multiPast.bind(_, "A")), 45 | r("clever.fastJump.small.up", jumpLines.bind(_, jumpSizes.small.up)), 46 | r("clever.fastJump.small.down", jumpLines.bind(_, jumpSizes.small.down)), 47 | r( 48 | "clever.fastJump.small.selectUp", 49 | jumpSelectLines.bind(_, jumpSizes.small.up) 50 | ), 51 | r( 52 | "clever.fastJump.small.selectDown", 53 | jumpSelectLines.bind(_, jumpSizes.small.down) 54 | ), 55 | r("clever.fastJump.big.up", jumpLines.bind(_, jumpSizes.big.up)), 56 | r("clever.fastJump.big.down", jumpLines.bind(_, jumpSizes.big.down)), 57 | r( 58 | "clever.fastJump.big.selectUp", 59 | jumpSelectLines.bind(_, jumpSizes.big.up) 60 | ), 61 | r( 62 | "clever.fastJump.big.selectDown", 63 | jumpSelectLines.bind(_, jumpSizes.big.down) 64 | ), 65 | r("clever.fastInsert.curly", fastCurly), 66 | r("clever.fastInsert.array", fastArray), 67 | r("clever.fastInsert.arrowFunction", fastArrowFunction), 68 | r("clever.embedMacro.previewCurrentFile", previewCurrentFile), 69 | // clever.closeHoverOpenedFile 70 | r("clever.maximize.toggleWithSidebar", toggleMaximize), 71 | r("clever.maximize.toggleWithoutSidebar", toggleMaximize.bind(_, false)), 72 | r("clever.blockSelect.cleverSelect", cleverSelect), 73 | r("clever.blockSelect.quotes", selectEitherQuote), 74 | r( 75 | "clever.blockSelect.parenthesis", 76 | matchingSelect.bind(_, { start_char: "(", end_char: ")" }) 77 | ), 78 | r( 79 | "clever.blockSelect.squareBrackets", 80 | matchingSelect.bind(_, { start_char: "[", end_char: "]" }) 81 | ), 82 | r( 83 | "clever.blockSelect.curlyBrackets", 84 | matchingSelect.bind(_, { start_char: "{", end_char: "}" }) 85 | ), 86 | r( 87 | "clever.blockSelect.angleBrackets", 88 | matchingSelect.bind(_, { start_char: "<", end_char: ">" }) 89 | ), 90 | r( 91 | "clever.blockSelect.inTag", 92 | matchingSelect.bind(_, { start_char: ">", end_char: "<" }) 93 | ) 94 | // clever.calculate 95 | // clever.block.deploy 96 | // clever.block.imploy 97 | // clever.block.toggleDeploy 98 | // clever.string.objectToJson 99 | // clever.string.jsonToObject 100 | ); 101 | // macros 102 | Object.keys(config().macros).forEach((key) => { 103 | r("clever.macros." + key, executeMacro.bind(_, key)); 104 | }); 105 | } 106 | 107 | export function deactivate() { 108 | Window.showInformationMessage( 109 | "Hope to see you soon, please repport any issue." 110 | ); 111 | } 112 | -------------------------------------------------------------------------------- /src/models/EditorBuilder.ts: -------------------------------------------------------------------------------- 1 | import { 2 | TextLine, 3 | TextEditorEdit, 4 | Position, 5 | Range, 6 | Selection, 7 | EndOfLine 8 | } from 'vscode'; 9 | 10 | export class EditorBuilder { 11 | 12 | vscEditor: TextEditorEdit; 13 | 14 | constructor(editor: TextEditorEdit) { 15 | this.vscEditor = editor; 16 | } 17 | 18 | // replaceNextChar(location: Position, value: string) { 19 | // this.replaceCharAt(location, value, +1); 20 | // } 21 | 22 | // replacePreviousChar(location: Position, value: string) { 23 | // this.replaceCharAt(location, value, -1); 24 | // } 25 | 26 | replaceCharAt(startLocation: Position, value: string, refPosition: number) { 27 | const endLocation = new Position(startLocation.line, startLocation.character + refPosition); 28 | this.replace(new Range(startLocation, endLocation), value); 29 | } 30 | 31 | deleteEol(currentLine: TextLine, length: number): void{ 32 | const startDelete = new Position(currentLine.range.end.line, currentLine.range.end.character - length); 33 | this.vscEditor.delete(currentLine.range.with(startDelete)); 34 | } 35 | 36 | insertEol(location: TextLine, text: string): void{ 37 | this.vscEditor.insert(location.range.end, text); 38 | } 39 | 40 | // defaults 41 | replace(location: Position | Range | Selection, value: string): void { 42 | this.vscEditor.replace(location, value); 43 | } 44 | 45 | insert(location: Position, value: string): void { 46 | this.vscEditor.insert(location, value); 47 | } 48 | 49 | // _delete(location: Range | Selection): void{ 50 | // this.vscEditor.delete(location); 51 | // } 52 | 53 | // _setEndOfLine(endOfLine: EndOfLine): void { 54 | // this.vscEditor.setEndOfLine(endOfLine); 55 | // } 56 | 57 | } -------------------------------------------------------------------------------- /src/models/RangeBuilder.ts: -------------------------------------------------------------------------------- 1 | import { Position, Range } from 'vscode'; 2 | 3 | interface IndexRange { 4 | start: number; 5 | end: number; 6 | } 7 | 8 | export class RangeBuilder { 9 | private indexRanges: IndexRange[]; 10 | 11 | constructor(source: string) { 12 | let regex = /(.*)(\r?\n|$)/g; 13 | 14 | let indexRanges: IndexRange[] = []; 15 | 16 | while (true) { 17 | let groups = regex.exec(source); 18 | let lineText = groups[1]; 19 | let lineEnding = groups[2]; 20 | 21 | let lastIndex = regex.lastIndex - lineEnding.length; 22 | 23 | indexRanges.push({ 24 | start: lastIndex - lineText.length, 25 | end: lastIndex 26 | }); 27 | 28 | if (!lineEnding.length) { 29 | break; 30 | } 31 | } 32 | 33 | this.indexRanges = indexRanges; 34 | } 35 | 36 | getPosition(index: number): Position { 37 | let indexRanges = this.indexRanges; 38 | 39 | for (let i = 0; i < indexRanges.length; i++) { 40 | let indexRange = indexRanges[i]; 41 | if (indexRange.end >= index) { 42 | if (indexRange.start <= index) { 43 | // Within range. 44 | return new Position(i, index - indexRange.start); 45 | } else { 46 | // End of line? 47 | let previousIndexRange = indexRanges[i - 1]; 48 | return new Position(i, previousIndexRange.end - previousIndexRange.start + 1); 49 | } 50 | } 51 | } 52 | } 53 | 54 | getRange(startIndex: number, endIndex: number): Range { 55 | let start = this.getPosition(startIndex); 56 | let end = this.getPosition(endIndex); 57 | return new Range(start, end); 58 | } 59 | } -------------------------------------------------------------------------------- /src/services/commands.ts: -------------------------------------------------------------------------------- 1 | import { 2 | commands as Commands 3 | } from 'vscode'; 4 | import { insertBind } from '../controlers/string'; 5 | import config from '../config'; 6 | 7 | let executeSingleton = false; 8 | 9 | type CmdParam = { 10 | command: string, 11 | args: any[], 12 | } 13 | 14 | export function executeCommands(commands: Array) { 15 | if (executeSingleton) { 16 | return; 17 | } 18 | executeSingleton = true; 19 | 20 | const waitPattern = new RegExp('^wait(:([0-9]+)){0,1}$'); 21 | const typePattern = new RegExp('^type:([\\s\\S]+)', 'gm'); 22 | const loopFunction = async (i) => { 23 | if (i >= commands.length) { 24 | executeSingleton = false; 25 | return; 26 | } 27 | const command = commands[i]; 28 | if (typeof command === 'function') { 29 | command(); 30 | loopFunction(++i); 31 | } else if (typeof command === 'object') { 32 | await Commands.executeCommand(command.command, command.args); 33 | loopFunction(++i); 34 | } else { 35 | const foundWait = waitPattern.exec(command); 36 | const foundType = typePattern.exec(command); 37 | if (foundWait) { 38 | setTimeout(() => { 39 | loopFunction(++i); 40 | }, foundWait[2] && parseInt(foundWait[2]) || config().macroDefaultWaitDelay); 41 | } else if (foundType) { 42 | await insertBind(foundType[1]) 43 | loopFunction(++i); 44 | } else { 45 | await Commands.executeCommand(command); 46 | loopFunction(++i); 47 | } 48 | } 49 | } 50 | loopFunction(0); 51 | } -------------------------------------------------------------------------------- /src/services/otherSelector.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import * as vscode from 'vscode'; 3 | export function activate(context: vscode.ExtensionContext) { 4 | let editor = vscode.window.activeTextEditor; 5 | let disposable = vscode.commands.registerCommand('extension.doDuplicate', () => { 6 | let activeSelections = editor.selections; 7 | // inline copy 8 | editor.edit(editBuilder => { 9 | // for multiple selections 10 | for (var i = 0; i < activeSelections.length; ++i) { 11 | editBuilder.insert(activeSelections[i].end, editor.document.getText(activeSelections[i])); 12 | } 13 | }); 14 | // to keep the cursor where the user first put it 15 | editor.selections = activeSelections; 16 | }); 17 | let disposable2 = vscode.commands.registerCommand('extension.doFastDeploy', () => { 18 | if (editor.selection.isSingleLine) { 19 | let lineNumber = new vscode.Position(editor.selection.start.line, 0); 20 | let endNumber = lineNumber.translate(1, 0); 21 | let stringToParse = editor.document.getText(new vscode.Range(lineNumber, endNumber)); 22 | let indexOfSelection = editor.selection.active.character; 23 | let rangeOfBrackets = bracketSearch(stringToParse, indexOfSelection); 24 | let firstOpen = rangeOfBrackets[0] 25 | let firstClose = rangeOfBrackets[1]; 26 | // if we fail to find brackets, we ignore the command 27 | if (firstClose == -1) return; 28 | editor.edit(editBuilder => { 29 | let indentationChar = editor.options.insertSpaces ? ' ' : '\t'; 30 | let levelOfIndent = stringToParse.search(/\S/); 31 | let rangeToDelete = new vscode.Range(new vscode.Position(editor.selection.start.line, firstOpen), 32 | new vscode.Position(editor.selection.start.line, firstClose)); 33 | let padding = indentationChar.repeat(levelOfIndent + editor.options.tabSize); 34 | let params = ('\n' + stringToParse.substring(+firstOpen, firstClose) + '\n').split(',').map(Function.prototype.call, String.prototype.trim); 35 | editBuilder.replace(rangeToDelete, ('\n' + padding + params.join(',' + '\n' + padding)) + '\n' + indentationChar.repeat(levelOfIndent)); 36 | 37 | }); 38 | } 39 | }); 40 | 41 | context.subscriptions.push(disposable); 42 | } 43 | 44 | // tries to find the bracket pair at the active cursor level (ie will ignore parameters that 45 | // have brackets in them) 46 | function bracketSearch(str: string, index: number) { 47 | let unmatchedBrace = 0; 48 | let unmatchedParen = 0; 49 | let indexBrace, indexParen; 50 | for (let i = index; i <= str.length; ++i) { 51 | if (str[i] == '{') { 52 | unmatchedBrace++; 53 | } 54 | else if (str[i] == '(') { 55 | unmatchedParen++; 56 | } 57 | else if (str[i] == '}') { 58 | if (unmatchedBrace > 0) { 59 | unmatchedBrace--; 60 | } else { 61 | indexBrace = i; 62 | break; 63 | } 64 | } 65 | else if (str[i] == ')') { 66 | if (unmatchedParen > 0) { 67 | unmatchedParen--; 68 | } else { 69 | indexParen = i; 70 | break; 71 | } 72 | } 73 | } 74 | if (indexBrace) { 75 | unmatchedBrace = 0; 76 | for (let i = index; i >= 0; --i) { 77 | if (str[i] == '}') { 78 | unmatchedBrace++; 79 | } 80 | else if (str[i] == '{') { 81 | if (unmatchedBrace > 0) { 82 | unmatchedBrace--; 83 | } else { 84 | return [i + 1, indexBrace]; 85 | } 86 | } 87 | } 88 | } else if (indexParen) { 89 | unmatchedParen = 0; 90 | for (let i = index; i >= 0; --i) { 91 | if (str[i] == ')') { 92 | unmatchedParen++; 93 | } 94 | else if (str[i] == '(') { 95 | if (unmatchedParen > 0) { 96 | unmatchedParen--; 97 | } else { 98 | return [i + 1, indexParen]; 99 | } 100 | } 101 | } 102 | } else { 103 | return [-1, -1]; 104 | } 105 | } 106 | 107 | // this method is called when your extension is deactivated 108 | export function deactivate() { 109 | } 110 | -------------------------------------------------------------------------------- /src/services/ownSelector.ts: -------------------------------------------------------------------------------- 1 | import { Position } from 'vscode'; 2 | 3 | const starters = ['"', "'", "`", "(", "[", '{']; 4 | const enders = ['"', "'", "`", ")", "]", '}']; 5 | 6 | // export function getPrevious(charList: string[], from: Position): Position { 7 | 8 | // } 9 | 10 | // export function getNext(charList: string[], from: Position): Position { 11 | 12 | // } -------------------------------------------------------------------------------- /src/services/parser.ts: -------------------------------------------------------------------------------- 1 | import { Range, Position } from 'vscode'; 2 | import { RangeBuilder } from '../models/RangeBuilder'; 3 | 4 | /// excellent document parser by Vilic : 5 | // https://github.com/vilic/vscode-es-quotes 6 | 7 | export const enum StringType { 8 | singleQuoted, 9 | doubleQuoted, 10 | template 11 | } 12 | 13 | interface InterStringGroupTarget extends StringGroupTarget { 14 | bracketStack: string[]; 15 | partials: InterStringTarget[]; 16 | } 17 | 18 | export interface StringBodyTarget { 19 | /** ", ', ` or } */ 20 | opening: string; 21 | /** ", ', ` or ${ */ 22 | closing: string; 23 | type: StringType; 24 | body: string; 25 | range: Range; 26 | } 27 | 28 | export interface StringGroupTarget { 29 | partials: StringTarget[]; 30 | hasLowPriorityOperator: boolean; 31 | whitespacesRangeAtBeginning: Range; 32 | whitespacesRangeAtEnd: Range; 33 | } 34 | 35 | export type StringTarget = StringBodyTarget | StringGroupTarget; 36 | 37 | type InterStringTarget = StringBodyTarget | InterStringGroupTarget; 38 | 39 | const parsingRegex = /* /$parsing/ */ /(\/\*[\s\S]*?(?:\*\/|$)|\/\/.*\r?\n)|(["'])((?:\\(?:\r\n|[^])|(?!\2|\\).)*)(\2)?|\/(?:\\.|\[(?:\\.|[^\]\\\r\n])*\]?|[^\\\/\r\n])+\/|(`)|([()\[\]{}])|([?&|+-]|&&|\|\||<<>>?)|(\s+)|[^]/g; 40 | const templateStringRegex = /* /$templateString/ */ /([`}])((?:\\[^]|(?!\$\{)[^`])*)(`|\$\{)?/g; // This comment is to fix highlighting: ` 41 | 42 | /* /$parsing/ */ 43 | const enum ParsingRegexIndex { 44 | comment = 1, 45 | quote, 46 | stringBody, 47 | closingQuote, 48 | templateStringQuote, 49 | bracket, 50 | operator, 51 | whitespace 52 | } 53 | 54 | /* /$templateString/ */ 55 | const enum TemplateStringRegexIndex { 56 | quote = 1, 57 | stringBody, 58 | closingQuote 59 | } 60 | 61 | const bracketConsumptionPair: { 62 | [key: string]: string; 63 | } = { 64 | '}': '{', 65 | ']': '[', 66 | ')': '(' 67 | }; 68 | 69 | export interface ParseResult { 70 | defaultQuote: string; 71 | stringTargets: StringTarget[]; 72 | } 73 | 74 | export function findActiveStringTarget(targets: StringTarget[], selection: Range): StringBodyTarget { 75 | for (let target of targets) { 76 | let partials = (target as StringGroupTarget).partials; 77 | if (partials) { 78 | let foundTarget = findActiveStringTarget(partials, selection); 79 | if (foundTarget) { 80 | return foundTarget; 81 | } 82 | } else { 83 | if ((target as StringBodyTarget).range.contains(selection)) { 84 | return target as StringBodyTarget; 85 | } 86 | } 87 | } 88 | 89 | return undefined; 90 | } 91 | 92 | export function parse(source: string): ParseResult { 93 | let rangeBuilder = new RangeBuilder(source); 94 | 95 | let rootStringTargets: InterStringTarget[] = []; 96 | let nestedStringTargetStack: InterStringTarget[] = []; 97 | 98 | let currentGroupTarget: InterStringGroupTarget; 99 | let currentStringTargets = rootStringTargets; 100 | let currentBracketStack: string[]; 101 | 102 | let isNewGroupTarget: boolean; 103 | 104 | let groups: RegExpExecArray; 105 | 106 | let doubleQuotedCount = 0; 107 | let singleQuotedCount = 0; 108 | 109 | while (groups = parsingRegex.exec(source)) { 110 | let text = groups[0]; 111 | 112 | isNewGroupTarget = false; 113 | 114 | if (groups[ParsingRegexIndex.comment]) { 115 | // Do nothing. 116 | } else if (groups[ParsingRegexIndex.quote]) { 117 | let quote = groups[ParsingRegexIndex.quote]; 118 | let body = groups[ParsingRegexIndex.stringBody]; 119 | let range = rangeBuilder.getRange(parsingRegex.lastIndex - text.length, parsingRegex.lastIndex); 120 | 121 | // TODO: 122 | // if (currentBracketStack && currentBracketStack.length) { 123 | // pushNestedTargetStack(); 124 | // } 125 | 126 | let type: StringType; 127 | 128 | if (quote === '"') { 129 | type = StringType.doubleQuoted; 130 | doubleQuotedCount++; 131 | } else { 132 | type = StringType.singleQuoted; 133 | singleQuotedCount++; 134 | } 135 | 136 | let target: StringBodyTarget = { 137 | body, 138 | range, 139 | opening: quote, 140 | closing: quote, 141 | type 142 | }; 143 | 144 | currentStringTargets.push(target); 145 | } else if ( 146 | groups[ParsingRegexIndex.templateStringQuote] || ( 147 | nestedStringTargetStack.length && 148 | currentBracketStack.indexOf('{') < 0 && 149 | groups[ParsingRegexIndex.bracket] === '}' 150 | ) 151 | ) { 152 | if (groups[ParsingRegexIndex.templateStringQuote]) { 153 | // `abc${123}def` 154 | // ^ 155 | pushNestedTargetStack(); 156 | } else { 157 | // `abc${123}def` 158 | // ^ 159 | popNestedTargetStack(); 160 | } 161 | 162 | templateStringRegex.lastIndex = parsingRegex.lastIndex - groups[0].length; 163 | 164 | // The match below should always success. 165 | let templateStringGroups = templateStringRegex.exec(source); 166 | let templateStringText = templateStringGroups[0]; 167 | 168 | parsingRegex.lastIndex = templateStringRegex.lastIndex; 169 | 170 | let body = templateStringGroups[TemplateStringRegexIndex.stringBody]; 171 | 172 | let range = rangeBuilder.getRange( 173 | templateStringRegex.lastIndex - templateStringText.length, 174 | templateStringRegex.lastIndex 175 | ); 176 | 177 | let openingQuote = templateStringGroups[TemplateStringRegexIndex.quote]; 178 | let closingQuote = templateStringGroups[TemplateStringRegexIndex.closingQuote] || '`'; 179 | 180 | let target: StringBodyTarget = { 181 | body, 182 | range, 183 | opening: openingQuote, 184 | closing: closingQuote, 185 | type: StringType.template 186 | }; 187 | 188 | currentStringTargets.push(target); 189 | 190 | if (closingQuote === '${') { 191 | // `abc${123}def` 192 | // ^ 193 | pushNestedTargetStack(); 194 | } else { 195 | // `abc${123}def` 196 | // ^ 197 | popNestedTargetStack(); 198 | } 199 | } else if (currentBracketStack) { 200 | if (groups[ParsingRegexIndex.bracket]) { 201 | let bracket = groups[ParsingRegexIndex.bracket]; 202 | 203 | if (bracket in bracketConsumptionPair) { 204 | let bra = bracketConsumptionPair[bracket]; 205 | if (currentBracketStack.length && bra === currentBracketStack[currentBracketStack.length - 1]) { 206 | currentBracketStack.pop(); 207 | } else { 208 | // Otherwise there might be some syntax error, but we don't really care. 209 | console.warn(`Mismatched right bracket "${bracket}".`); 210 | } 211 | } else { 212 | currentBracketStack.push(bracket); 213 | } 214 | } else if (!currentBracketStack.length && groups[ParsingRegexIndex.operator]) { 215 | currentGroupTarget.hasLowPriorityOperator = true; 216 | } 217 | } 218 | 219 | if (currentGroupTarget) { 220 | if (groups[ParsingRegexIndex.whitespace]) { 221 | let range = rangeBuilder.getRange(parsingRegex.lastIndex - text.length, parsingRegex.lastIndex); 222 | 223 | if (currentGroupTarget.whitespacesRangeAtBeginning instanceof Range) { 224 | currentGroupTarget.whitespacesRangeAtEnd = range; 225 | } else { 226 | currentGroupTarget.whitespacesRangeAtBeginning = range; 227 | } 228 | } else if (!isNewGroupTarget) { 229 | if (currentGroupTarget.whitespacesRangeAtBeginning instanceof Range) { 230 | let start = rangeBuilder.getPosition(parsingRegex.lastIndex); 231 | let range = new Range(start, start); 232 | 233 | currentGroupTarget.whitespacesRangeAtEnd = range; 234 | } else { 235 | let end = rangeBuilder.getPosition(parsingRegex.lastIndex - text.length); 236 | let range = new Range(end, end); 237 | 238 | currentGroupTarget.whitespacesRangeAtBeginning = range; 239 | } 240 | } 241 | } 242 | } 243 | 244 | finalizeTargets(rootStringTargets); 245 | 246 | return { 247 | defaultQuote: singleQuotedCount < doubleQuotedCount ? '"' : "'", 248 | stringTargets: rootStringTargets 249 | }; 250 | 251 | function pushNestedTargetStack(): void { 252 | let target: InterStringGroupTarget = { 253 | partials: [], 254 | bracketStack: [], 255 | hasLowPriorityOperator: false, 256 | whitespacesRangeAtBeginning: undefined, 257 | whitespacesRangeAtEnd: undefined 258 | }; 259 | 260 | currentStringTargets.push(target); 261 | 262 | currentGroupTarget = target; 263 | currentStringTargets = target.partials; 264 | currentBracketStack = target.bracketStack; 265 | nestedStringTargetStack.push(target); 266 | 267 | isNewGroupTarget = true; 268 | } 269 | 270 | function popNestedTargetStack(): void { 271 | nestedStringTargetStack.pop(); 272 | 273 | let lastIndex = nestedStringTargetStack.length - 1; 274 | 275 | if (lastIndex < 0) { 276 | currentGroupTarget = undefined; 277 | currentStringTargets = rootStringTargets; 278 | currentBracketStack = undefined; 279 | } else { 280 | let target = nestedStringTargetStack[lastIndex] as InterStringGroupTarget; 281 | currentGroupTarget = target; 282 | currentStringTargets = target.partials; 283 | currentBracketStack = target.bracketStack; 284 | } 285 | } 286 | 287 | function finalizeTargets(targets: InterStringTarget[]) { 288 | for (let i = 0; i < targets.length; i++) { 289 | let target = targets[i] as InterStringGroupTarget; 290 | 291 | if (target.partials) { 292 | delete target.bracketStack; 293 | 294 | finalizeTargets(target.partials); 295 | } 296 | } 297 | } 298 | } 299 | 300 | export function isStringGroupTarget(target: StringGroupTarget | StringBodyTarget): target is StringGroupTarget { 301 | return !!(target as StringGroupTarget).partials; 302 | } 303 | 304 | export function isStringBodyTarget(target: StringGroupTarget | StringBodyTarget): target is StringBodyTarget { 305 | return !(target as StringGroupTarget).partials; 306 | } -------------------------------------------------------------------------------- /src/services/selector.ts: -------------------------------------------------------------------------------- 1 | // good selecting library by dbankier 2 | // https://github.com/dbankier/vscode-quick-select/blob/master/src/extension.ts 3 | 4 | import * as vscode from 'vscode'; 5 | 6 | function findOccurances(doc: vscode.TextDocument, line: number, char: string): Array { 7 | var content = doc.lineAt(line); 8 | var matches = (content.text + "hack").split(char).reduce((acc, p) => { 9 | var len = p.length + 1; 10 | if (acc.length > 0) { 11 | len += acc[acc.length - 1]; 12 | } 13 | acc.push(len); 14 | return acc; 15 | }, []); 16 | matches.pop(); 17 | return matches; 18 | } 19 | 20 | function findNext(doc: vscode.TextDocument, line: number, char: string, start_index: number = 0, nest_char: string = undefined, nested: number = 0): vscode.Position { 21 | if (line === doc.lineCount) { return undefined }; 22 | var occurances = findOccurances(doc, line, char).filter(n => n >= start_index); 23 | var nests = nest_char ? findOccurances(doc, line, nest_char).filter(n => n >= start_index) : []; 24 | var occurance_index = 0; 25 | var nests_index = 0; 26 | while ((occurance_index < occurances.length || nests_index < nests.length) && nested >= 0) { 27 | if (occurances[occurance_index] < nests[nests_index] || !nests[nests_index]) { 28 | if (nested === 0) { 29 | return new vscode.Position(line, occurances[occurance_index]); 30 | } 31 | nested-- 32 | occurance_index++; 33 | } else if (nests[nests_index] < occurances[occurance_index] || !occurances[occurance_index]) { 34 | nested++; 35 | nests_index++; 36 | } 37 | } 38 | return findNext(doc, ++line, char, 0, nest_char, nested); 39 | } 40 | 41 | function findPrevious(doc: vscode.TextDocument, line: number, char: string, start_index?: number, nest_char: string = undefined, nested: number = 0): vscode.Position { 42 | if (line === -1) { return undefined }; 43 | if (start_index === undefined) { start_index = doc.lineAt(line).text.length; } 44 | var occurances = findOccurances(doc, line, char).filter(n => n <= start_index); 45 | var nests = nest_char ? findOccurances(doc, line, nest_char).filter(n => n <= start_index) : []; 46 | var occurance_index = occurances.length - 1; 47 | var nests_index = nests.length - 1; 48 | while ((occurance_index > -1 || nests_index > -1) && nested >= 0) { 49 | if (occurances[occurance_index] > nests[nests_index] || !nests[nests_index]) { 50 | if (nested === 0) { 51 | return new vscode.Position(line, occurances[occurance_index]); 52 | } 53 | nested-- 54 | occurance_index--; 55 | } else if (nests[nests_index] > occurances[occurance_index] || !occurances[occurance_index]) { 56 | nested++; 57 | nests_index--; 58 | } 59 | } 60 | return findPrevious(doc, --line, char, undefined, nest_char, nested); 61 | } 62 | 63 | function findSingleSelect(s: vscode.Selection, doc: vscode.TextDocument, char: string, outer?: boolean, multiline?: boolean) { 64 | let { line, character } = s.active; 65 | let matches = findOccurances(doc, line, char); 66 | let next = matches.find(a => a > character); 67 | let next_index = matches.indexOf(next); 68 | let offset = outer ? char.length : 0; 69 | if (matches.length > 1 && matches.length % 2 === 0) { 70 | // Jump inside the next matching pair 71 | if (next === -1) { return s } 72 | if (next_index % 2 !== 0) { 73 | next_index--; 74 | } 75 | //Automatically grow to outer selection 76 | if (!outer && 77 | new vscode.Position(line, matches[next_index]).isEqual(s.anchor) && 78 | new vscode.Position(line, matches[next_index + 1] - 1).isEqual(s.end)) { 79 | offset = char.length 80 | } 81 | return new vscode.Selection( 82 | new vscode.Position(line, matches[next_index] - offset), 83 | new vscode.Position(line, matches[next_index + 1] - 1 + offset) 84 | ); 85 | } else if (multiline) { 86 | let start_pos = findPrevious(doc, line, char, character) || new vscode.Position(line, matches[next_index]) 87 | if (!start_pos) { return s }; 88 | let end_pos: vscode.Position = findNext(doc, start_pos.line, char, start_pos.character + 1); 89 | //Automatically grow to outer selection 90 | if (!outer && 91 | start_pos.isEqual(s.anchor) && 92 | new vscode.Position(end_pos.line, end_pos.character - 1).isEqual(s.end)) { 93 | offset = char.length 94 | } 95 | if (start_pos && end_pos) { 96 | start_pos = new vscode.Position(start_pos.line, start_pos.character - offset); 97 | end_pos = new vscode.Position(end_pos.line, end_pos.character - 1 + offset); 98 | return new vscode.Selection(start_pos, end_pos) 99 | } 100 | } 101 | return s; 102 | 103 | } 104 | 105 | export function selectEitherQuote(updateSelect: boolean = true) { 106 | let editor = vscode.window.activeTextEditor; 107 | if (!editor) { return; }; 108 | let doc = editor.document 109 | let sel = editor.selections 110 | const selectionsResult = sel.map((s: vscode.Selection) => { 111 | let selections = ['"', "'", "`"].map(char => findSingleSelect(s, doc, char, false, char === '`')) 112 | .filter(sel => sel !== s) 113 | .filter(sel => sel.start.isBeforeOrEqual(s.start) && sel.end.isAfterOrEqual(s.end)) 114 | .sort((a, b) => a.start.isBefore(b.start) ? 1 : -1) 115 | if (selections.length > 0) { 116 | return selections[0] 117 | } 118 | return s; 119 | }) 120 | 121 | if (updateSelect) { 122 | editor.selections = selectionsResult 123 | } 124 | 125 | return selectionsResult 126 | } 127 | 128 | interface MatchingSelectOptions { start_char: string, end_char: string, outer?: boolean } 129 | export function matchingSelect( 130 | { start_char, end_char, outer = false }: MatchingSelectOptions, 131 | updateSelect: boolean = true 132 | ) { 133 | let editor = vscode.window.activeTextEditor; 134 | if (!editor) { return; }; 135 | let doc = editor.document 136 | let sel = editor.selections 137 | let success = false; 138 | let start_offset = outer ? start_char.length : 0; 139 | let end_offset = outer ? end_char.length : 0; 140 | const selections = sel.map(s => { 141 | let { line, character } = s.active; 142 | let starts = findOccurances(doc, line, start_char); 143 | // let ends = findOccurances(doc, line, end_char); 144 | let start = starts.find(a => a > character); 145 | // let end = ends.find(a => a > character); 146 | let start_index = starts.indexOf(start); 147 | // let end_index = ends.indexOf(end); 148 | let start_pos: vscode.Position = findPrevious(doc, line, start_char, character, end_char) || new vscode.Position(line, starts[start_index]); 149 | if (!start_pos) { return s }; 150 | let end_pos: vscode.Position = findNext(doc, start_pos.line, end_char, start_pos.character + 1, start_char); 151 | if (start_pos && end_pos) { 152 | success = true; 153 | //Automatically grow to outer selection 154 | if (!outer && 155 | start_pos.isEqual(s.anchor) && 156 | new vscode.Position(end_pos.line, end_pos.character - 1).isEqual(s.end)) { 157 | start_offset = start_char.length; 158 | end_offset = end_char.length; 159 | } 160 | start_pos = new vscode.Position(start_pos.line, start_pos.character - start_offset); 161 | end_pos = new vscode.Position(end_pos.line, end_pos.character - 1 + end_offset); 162 | 163 | return new vscode.Selection(start_pos, end_pos) 164 | } 165 | return s; 166 | }) 167 | if (updateSelect) { 168 | editor.selections = selections 169 | if (success && start_char === "<") { 170 | vscode.commands.executeCommand("editor.action.addSelectionToNextFindMatch") 171 | } 172 | } 173 | return selections 174 | } 175 | 176 | export function cleverSelect() { 177 | let editor = vscode.window.activeTextEditor; 178 | if (!editor) { return; }; 179 | // let doc = editor.document 180 | let sel = editor.selections 181 | editor.selections = sel.map((s: vscode.Selection) => { 182 | let selectionsBlocks = [ 183 | { start_char: "(", end_char: ")" }, 184 | { start_char: "[", end_char: "]" }, 185 | { start_char: "{", end_char: "}" }, 186 | { start_char: "<", end_char: ">" }, 187 | { start_char: ">", end_char: "<" } 188 | ].map(opt => { 189 | const selections = matchingSelect(opt, false) 190 | if (selections && selections.length > 0) { 191 | return selections[0] 192 | } 193 | return s 194 | }) 195 | 196 | const selections = [ 197 | ...selectionsBlocks, 198 | ...selectEitherQuote(false) 199 | ].filter(sel => sel.start !== s.start) 200 | .filter( 201 | sel => 202 | sel.start.isBeforeOrEqual(s.start) && 203 | sel.end.isAfterOrEqual(s.end) 204 | ) 205 | .sort((a, b) => a.start.isBefore(b.start) ? 1 : -1) 206 | 207 | if (selections && selections.length > 0) { 208 | return selections[0] 209 | } 210 | return s 211 | }) 212 | } -------------------------------------------------------------------------------- /src/services/string.ts: -------------------------------------------------------------------------------- 1 | 2 | import { 3 | window as Window, 4 | SnippetString 5 | } from 'vscode'; 6 | import config from '../config'; 7 | 8 | export function insertSnippet(text: string) { 9 | Window.activeTextEditor.insertSnippet(new SnippetString(text)); 10 | } 11 | 12 | export function insertBind(configChar: string) { 13 | // if(!config().disableRebindForEdit && config().rebind[configChar]) { 14 | // insertSnippet(config().rebind[configChar]); 15 | // } else { 16 | insertSnippet(configChar); 17 | // } 18 | } 19 | -------------------------------------------------------------------------------- /src/utils/debug.ts: -------------------------------------------------------------------------------- 1 | import { 2 | window as Window 3 | } from 'vscode'; 4 | 5 | export function alert(message: string) { 6 | Window.showInformationMessage(message); 7 | } -------------------------------------------------------------------------------- /src/utils/editor.ts: -------------------------------------------------------------------------------- 1 | 2 | import { 3 | Selection, 4 | TextLine, 5 | window as Window 6 | } from 'vscode'; 7 | import {EditorBuilder} from '../models/EditorBuilder'; 8 | import {sortSelections} from '../utils/utils'; 9 | 10 | function getLines(selection: Selection): Array { 11 | const lines: Array = []; 12 | for (var i = selection.start.line; i < selection.end.line + 1; i++) { 13 | lines.push(Window.activeTextEditor.document.lineAt(i)); 14 | } 15 | return lines; 16 | } 17 | 18 | export function prepareEdit( 19 | cb: ( 20 | editBuilder: EditorBuilder, 21 | selection: Selection, 22 | lines: Array 23 | ) => void, 24 | withSortSelections: boolean = true ) { 25 | const activeTextEditor = Window.activeTextEditor; 26 | activeTextEditor.edit((editBuilder) => { 27 | let selections = activeTextEditor.selections; 28 | if(withSortSelections){ 29 | selections = sortSelections(selections); 30 | } 31 | selections.forEach((selection) => { 32 | cb(new EditorBuilder(editBuilder), selection, getLines(selection)); 33 | }); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /src/utils/quote.ts: -------------------------------------------------------------------------------- 1 | import { StringBodyTarget } from '../services/parser'; 2 | 3 | const quotes = { 4 | '"': { 5 | next: "'", 6 | current: '"', 7 | previous: "`", 8 | }, 9 | "'": { 10 | next: "`", 11 | current: "'", 12 | previous: '"', 13 | }, 14 | '`': { 15 | next: '"', 16 | current: '`', 17 | previous: "'", 18 | } 19 | } 20 | 21 | export function getNextQuotes(activeTarget: StringBodyTarget) : string { 22 | const quote = quotes[activeTarget.opening]; 23 | const currentEscaped = new RegExp('\\\\' + quote.current, 'g'); 24 | const nextToEscape = new RegExp(quote.next, 'g'); 25 | const final = activeTarget.body 26 | .replace(currentEscaped, quote.current) 27 | .replace(nextToEscape, '\\' + quote.next); 28 | 29 | return quote.next + final + quote.next; 30 | } -------------------------------------------------------------------------------- /src/utils/utils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Selection 3 | } from 'vscode'; 4 | 5 | export function wait(ms: number): Promise { 6 | return new Promise(function(resolve) { 7 | setTimeout(resolve, ms); 8 | }); 9 | } 10 | 11 | export function nextToken(c: string|number) : string|number { 12 | if(typeof c === 'string') { 13 | if( c === 'Z') { 14 | return 'A'; 15 | } else if (c === 'z') { 16 | return 'a'; 17 | } else { 18 | return String.fromCharCode(c.charCodeAt(0) + 1); 19 | } 20 | } else { 21 | return ++c; 22 | } 23 | } 24 | 25 | export function sortSelections(selections: Array) { 26 | return selections.sort((previous: Selection, next: Selection) : number => { 27 | const lineIsSmaller = previous.start.line < next.start.line; 28 | const lineIsEqual = previous.start.line === next.start.line; 29 | const characterIsSmaller = previous.start.character < next.start.character; 30 | const characterIsEqual = previous.start.character === next.start.character; 31 | if(lineIsEqual) { 32 | if(characterIsEqual) { 33 | return 0; 34 | } else if (characterIsSmaller) { 35 | return -1; 36 | } else { 37 | return 1; 38 | } 39 | } else if ( lineIsSmaller ) { 40 | return -1; 41 | } else { 42 | return 1; 43 | } 44 | }); 45 | } -------------------------------------------------------------------------------- /test/index.ts: -------------------------------------------------------------------------------- 1 | // 2 | // PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING 3 | // 4 | // This file is providing the test runner to use when running extension tests. 5 | // By default the test runner in use is Mocha based. 6 | // 7 | // You can provide your own test runner if you want to override it by exporting 8 | // a function run(testRoot: string, clb: (error:Error) => void) that the extension 9 | // host can call to run the tests. The test runner is expected to use console.log 10 | // to report the results back to the caller. When the tests are finished, return 11 | // a possible error to the callback or null if none. 12 | 13 | var testRunner = require('vscode/lib/testrunner'); 14 | 15 | // You can directly control Mocha options by uncommenting the following lines 16 | // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info 17 | testRunner.configure({ 18 | ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) 19 | useColors: true // colored output from test results 20 | }); 21 | 22 | module.exports = testRunner; -------------------------------------------------------------------------------- /test/main.test.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as assert from 'assert'; 3 | import * as vscode from 'vscode'; 4 | import * as myExtension from '../src/main'; 5 | 6 | // Defines a Mocha test suite to group tests of similar kind together 7 | suite("Extension Tests", () => { 8 | 9 | // Defines a Mocha unit test 10 | test("Something 1", () => { 11 | assert.equal(-1, [1, 2, 3].indexOf(5)); 12 | assert.equal(-1, [1, 2, 3].indexOf(0)); 13 | }); 14 | }); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "." 11 | }, 12 | "exclude": [ 13 | "node_modules", 14 | ".vscode-test" 15 | ] 16 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@tootallnate/once@1": 6 | version "1.1.2" 7 | resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" 8 | integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== 9 | 10 | "@types/mocha@^2.2.42": 11 | version "2.2.48" 12 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.48.tgz#3523b126a0b049482e1c3c11877460f76622ffab" 13 | integrity sha512-nlK/iyETgafGli8Zh9zJVCTicvU3iajSkRwOh3Hhiva598CMqNJ4NcVCGMTGKpGpTYj/9R8RLzS9NAykSSCqGw== 14 | 15 | "@types/node@^6.0.88": 16 | version "6.14.13" 17 | resolved "https://registry.yarnpkg.com/@types/node/-/node-6.14.13.tgz#b6649578fc0b5dac88c4ef48a46cab33c50a6c72" 18 | integrity sha512-J1F0XJ/9zxlZel5ZlbeSuHW2OpabrUAqpFuC2sm2I3by8sERQ8+KCjNKUcq8QHuzpGMWiJpo9ZxeHrqrP2KzQw== 19 | 20 | agent-base@4, agent-base@^4.3.0: 21 | version "4.3.0" 22 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" 23 | integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== 24 | dependencies: 25 | es6-promisify "^5.0.0" 26 | 27 | agent-base@6: 28 | version "6.0.2" 29 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" 30 | integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== 31 | dependencies: 32 | debug "4" 33 | 34 | balanced-match@^1.0.0: 35 | version "1.0.0" 36 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 37 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 38 | 39 | brace-expansion@^1.1.7: 40 | version "1.1.11" 41 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 42 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 43 | dependencies: 44 | balanced-match "^1.0.0" 45 | concat-map "0.0.1" 46 | 47 | browser-stdout@1.3.0: 48 | version "1.3.0" 49 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" 50 | integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8= 51 | 52 | browser-stdout@1.3.1: 53 | version "1.3.1" 54 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 55 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 56 | 57 | buffer-from@^1.0.0: 58 | version "1.1.1" 59 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" 60 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== 61 | 62 | commander@2.15.1: 63 | version "2.15.1" 64 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" 65 | integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== 66 | 67 | commander@2.9.0: 68 | version "2.9.0" 69 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" 70 | integrity sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q= 71 | dependencies: 72 | graceful-readlink ">= 1.0.0" 73 | 74 | concat-map@0.0.1: 75 | version "0.0.1" 76 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 77 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 78 | 79 | debug@2.6.8: 80 | version "2.6.8" 81 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" 82 | integrity sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw= 83 | dependencies: 84 | ms "2.0.0" 85 | 86 | debug@3.1.0: 87 | version "3.1.0" 88 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 89 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== 90 | dependencies: 91 | ms "2.0.0" 92 | 93 | debug@4: 94 | version "4.3.1" 95 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" 96 | integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== 97 | dependencies: 98 | ms "2.1.2" 99 | 100 | debug@^3.1.0: 101 | version "3.2.7" 102 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" 103 | integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== 104 | dependencies: 105 | ms "^2.1.1" 106 | 107 | diff@3.2.0: 108 | version "3.2.0" 109 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" 110 | integrity sha1-yc45Okt8vQsFinJck98pkCeGj/k= 111 | 112 | diff@3.5.0: 113 | version "3.5.0" 114 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 115 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== 116 | 117 | es6-promise@^4.0.3: 118 | version "4.2.8" 119 | resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" 120 | integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== 121 | 122 | es6-promisify@^5.0.0: 123 | version "5.0.0" 124 | resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" 125 | integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= 126 | dependencies: 127 | es6-promise "^4.0.3" 128 | 129 | escape-string-regexp@1.0.5: 130 | version "1.0.5" 131 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 132 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 133 | 134 | fs.realpath@^1.0.0: 135 | version "1.0.0" 136 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 137 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 138 | 139 | glob@7.1.1: 140 | version "7.1.1" 141 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" 142 | integrity sha1-gFIR3wT6rxxjo2ADBs31reULLsg= 143 | dependencies: 144 | fs.realpath "^1.0.0" 145 | inflight "^1.0.4" 146 | inherits "2" 147 | minimatch "^3.0.2" 148 | once "^1.3.0" 149 | path-is-absolute "^1.0.0" 150 | 151 | glob@7.1.2: 152 | version "7.1.2" 153 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 154 | integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== 155 | dependencies: 156 | fs.realpath "^1.0.0" 157 | inflight "^1.0.4" 158 | inherits "2" 159 | minimatch "^3.0.4" 160 | once "^1.3.0" 161 | path-is-absolute "^1.0.0" 162 | 163 | glob@^7.1.2: 164 | version "7.1.6" 165 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 166 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 167 | dependencies: 168 | fs.realpath "^1.0.0" 169 | inflight "^1.0.4" 170 | inherits "2" 171 | minimatch "^3.0.4" 172 | once "^1.3.0" 173 | path-is-absolute "^1.0.0" 174 | 175 | "graceful-readlink@>= 1.0.0": 176 | version "1.0.1" 177 | resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" 178 | integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= 179 | 180 | growl@1.10.5: 181 | version "1.10.5" 182 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 183 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 184 | 185 | growl@1.9.2: 186 | version "1.9.2" 187 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" 188 | integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8= 189 | 190 | has-flag@^1.0.0: 191 | version "1.0.0" 192 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" 193 | integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= 194 | 195 | has-flag@^3.0.0: 196 | version "3.0.0" 197 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 198 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 199 | 200 | he@1.1.1: 201 | version "1.1.1" 202 | resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" 203 | integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= 204 | 205 | http-proxy-agent@^2.1.0: 206 | version "2.1.0" 207 | resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" 208 | integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== 209 | dependencies: 210 | agent-base "4" 211 | debug "3.1.0" 212 | 213 | http-proxy-agent@^4.0.1: 214 | version "4.0.1" 215 | resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" 216 | integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== 217 | dependencies: 218 | "@tootallnate/once" "1" 219 | agent-base "6" 220 | debug "4" 221 | 222 | https-proxy-agent@^2.2.1: 223 | version "2.2.4" 224 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" 225 | integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== 226 | dependencies: 227 | agent-base "^4.3.0" 228 | debug "^3.1.0" 229 | 230 | https-proxy-agent@^5.0.0: 231 | version "5.0.0" 232 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" 233 | integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== 234 | dependencies: 235 | agent-base "6" 236 | debug "4" 237 | 238 | inflight@^1.0.4: 239 | version "1.0.6" 240 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 241 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 242 | dependencies: 243 | once "^1.3.0" 244 | wrappy "1" 245 | 246 | inherits@2: 247 | version "2.0.4" 248 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 249 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 250 | 251 | json3@3.3.2: 252 | version "3.3.2" 253 | resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" 254 | integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= 255 | 256 | lodash._baseassign@^3.0.0: 257 | version "3.2.0" 258 | resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" 259 | integrity sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4= 260 | dependencies: 261 | lodash._basecopy "^3.0.0" 262 | lodash.keys "^3.0.0" 263 | 264 | lodash._basecopy@^3.0.0: 265 | version "3.0.1" 266 | resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" 267 | integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= 268 | 269 | lodash._basecreate@^3.0.0: 270 | version "3.0.3" 271 | resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" 272 | integrity sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE= 273 | 274 | lodash._getnative@^3.0.0: 275 | version "3.9.1" 276 | resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" 277 | integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= 278 | 279 | lodash._isiterateecall@^3.0.0: 280 | version "3.0.9" 281 | resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" 282 | integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= 283 | 284 | lodash.create@3.1.1: 285 | version "3.1.1" 286 | resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" 287 | integrity sha1-1/KEnw29p+BGgruM1yqwIkYd6+c= 288 | dependencies: 289 | lodash._baseassign "^3.0.0" 290 | lodash._basecreate "^3.0.0" 291 | lodash._isiterateecall "^3.0.0" 292 | 293 | lodash.isarguments@^3.0.0: 294 | version "3.1.0" 295 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" 296 | integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= 297 | 298 | lodash.isarray@^3.0.0: 299 | version "3.0.4" 300 | resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" 301 | integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= 302 | 303 | lodash.keys@^3.0.0: 304 | version "3.1.2" 305 | resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" 306 | integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= 307 | dependencies: 308 | lodash._getnative "^3.0.0" 309 | lodash.isarguments "^3.0.0" 310 | lodash.isarray "^3.0.0" 311 | 312 | minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4: 313 | version "3.0.4" 314 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 315 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 316 | dependencies: 317 | brace-expansion "^1.1.7" 318 | 319 | minimist@0.0.8: 320 | version "0.0.8" 321 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 322 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 323 | 324 | mkdirp@0.5.1: 325 | version "0.5.1" 326 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 327 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 328 | dependencies: 329 | minimist "0.0.8" 330 | 331 | mocha@^3.5.0: 332 | version "3.5.3" 333 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d" 334 | integrity sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg== 335 | dependencies: 336 | browser-stdout "1.3.0" 337 | commander "2.9.0" 338 | debug "2.6.8" 339 | diff "3.2.0" 340 | escape-string-regexp "1.0.5" 341 | glob "7.1.1" 342 | growl "1.9.2" 343 | he "1.1.1" 344 | json3 "3.3.2" 345 | lodash.create "3.1.1" 346 | mkdirp "0.5.1" 347 | supports-color "3.1.2" 348 | 349 | mocha@^5.2.0: 350 | version "5.2.0" 351 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" 352 | integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== 353 | dependencies: 354 | browser-stdout "1.3.1" 355 | commander "2.15.1" 356 | debug "3.1.0" 357 | diff "3.5.0" 358 | escape-string-regexp "1.0.5" 359 | glob "7.1.2" 360 | growl "1.10.5" 361 | he "1.1.1" 362 | minimatch "3.0.4" 363 | mkdirp "0.5.1" 364 | supports-color "5.4.0" 365 | 366 | ms@2.0.0: 367 | version "2.0.0" 368 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 369 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 370 | 371 | ms@2.1.2: 372 | version "2.1.2" 373 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 374 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 375 | 376 | ms@^2.1.1: 377 | version "2.1.3" 378 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 379 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 380 | 381 | once@^1.3.0: 382 | version "1.4.0" 383 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 384 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 385 | dependencies: 386 | wrappy "1" 387 | 388 | path-is-absolute@^1.0.0: 389 | version "1.0.1" 390 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 391 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 392 | 393 | semver@^5.4.1: 394 | version "5.7.1" 395 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 396 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 397 | 398 | source-map-support@^0.5.0: 399 | version "0.5.19" 400 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" 401 | integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== 402 | dependencies: 403 | buffer-from "^1.0.0" 404 | source-map "^0.6.0" 405 | 406 | source-map@^0.6.0: 407 | version "0.6.1" 408 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 409 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 410 | 411 | supports-color@3.1.2: 412 | version "3.1.2" 413 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" 414 | integrity sha1-cqJiiU2dQIuVbKBf83su2KbiotU= 415 | dependencies: 416 | has-flag "^1.0.0" 417 | 418 | supports-color@5.4.0: 419 | version "5.4.0" 420 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" 421 | integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== 422 | dependencies: 423 | has-flag "^3.0.0" 424 | 425 | typescript@^4.2.2: 426 | version "4.2.2" 427 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.2.tgz#1450f020618f872db0ea17317d16d8da8ddb8c4c" 428 | integrity sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ== 429 | 430 | vscode-test@^0.4.1: 431 | version "0.4.3" 432 | resolved "https://registry.yarnpkg.com/vscode-test/-/vscode-test-0.4.3.tgz#461ebf25fc4bc93d77d982aed556658a2e2b90b8" 433 | integrity sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w== 434 | dependencies: 435 | http-proxy-agent "^2.1.0" 436 | https-proxy-agent "^2.2.1" 437 | 438 | vscode@^1.1.5: 439 | version "1.1.37" 440 | resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.37.tgz#c2a770bee4bb3fff765e2b72c7bcc813b8a6bb0a" 441 | integrity sha512-vJNj6IlN7IJPdMavlQa1KoFB3Ihn06q1AiN3ZFI/HfzPNzbKZWPPuiU+XkpNOfGU5k15m4r80nxNPlM7wcc0wg== 442 | dependencies: 443 | glob "^7.1.2" 444 | http-proxy-agent "^4.0.1" 445 | https-proxy-agent "^5.0.0" 446 | mocha "^5.2.0" 447 | semver "^5.4.1" 448 | source-map-support "^0.5.0" 449 | vscode-test "^0.4.1" 450 | 451 | wrappy@1: 452 | version "1.0.2" 453 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 454 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 455 | --------------------------------------------------------------------------------