├── .prettierignore ├── .gitattributes ├── NestedCommentsVSCode.code-workspace ├── TODO ├── .markdownlint.json ├── .vscodeignore ├── images ├── icon.png ├── nest-css.gif ├── nest-html.gif └── nest-jsx.gif ├── tsconfig.json ├── .vscode ├── settings.json ├── tasks.json └── launch.json ├── .prettierrc ├── src ├── test │ ├── suite │ │ ├── extension.test.ts │ │ └── index.ts │ └── runTest.ts └── extension.ts ├── .eslintrc.cjs ├── .gitignore ├── LICENSE ├── vsc-extension-quickstart.md ├── package.json ├── CHANGELOG.md └── README.md /.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | package.json 3 | package-lock.json 4 | public 5 | graphics -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.gif filter=lfs diff=lfs merge=lfs -text 2 | *.png filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /NestedCommentsVSCode.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": {} 8 | } 9 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Research: 2 | ☐ Embedded Language Support https://code.visualstudio.com/api/language-extensions/embedded-languages 3 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD013": false, 3 | "MD024": false, 4 | "MD033": false, 5 | "MD041": false, 6 | "MD046": false 7 | } 8 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | out/**/*.map 5 | src/** 6 | .gitignore 7 | tsconfig.json 8 | vsc-extension-quickstart.md 9 | -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:9cb68fec5fab227db57a6f4d723ce63ad81859bd372309c55a70a05613061778 3 | size 62988 4 | -------------------------------------------------------------------------------- /images/nest-css.gif: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:d80cab1460f6cb43674baf2dd1f7030f201202083aa45d8f119f07f2e79c92fc 3 | size 106170 4 | -------------------------------------------------------------------------------- /images/nest-html.gif: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:52be414b915fa70d999ea0ef79ffc8416729cbe12b52b3e7d97b6df1f9860de1 3 | size 118229 4 | -------------------------------------------------------------------------------- /images/nest-jsx.gif: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:c868b31e4e0e411be766aef3caa769f55a6e445f44240a2f6ee2c7b81609e5b1 3 | size 128378 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": ["es6", "ES2021.String"], 7 | "sourceMap": true, 8 | "rootDir": "src" 9 | }, 10 | "exclude": ["node_modules", ".vscode-test"] 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | } 9 | } -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSpacing": true, 4 | "printWidth": 100, 5 | "semi": false, 6 | "singleQuote": true, 7 | "trailingComma": "none", 8 | "useTabs": true, 9 | "overrides": [ 10 | { 11 | "files": ["*.svelte"], 12 | "options": { 13 | "svelteBracketNewLine": true 14 | } 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.strictEqual(-1, [1, 2, 3].indexOf(5)); 13 | assert.strictEqual(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | // extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], 6 | plugins: ['@typescript-eslint'], 7 | ignorePatterns: ['*.cjs', '*.svelte'], 8 | parserOptions: { 9 | sourceType: 'module', 10 | ecmaVersion: 2020 11 | }, 12 | env: { 13 | browser: true, 14 | es2017: true, 15 | node: true 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | *.sass-cache 10 | 11 | # Packages # 12 | ############ 13 | # it's better to unpack these files and commit the raw source 14 | # git has its own built in compression methods 15 | *.7z 16 | *.dmg 17 | *.gz 18 | *.iso 19 | *.jar 20 | *.rar 21 | *.tar 22 | *.zip 23 | 24 | # Logs and databases # 25 | ###################### 26 | *.log 27 | *.sql 28 | *.sqlite 29 | 30 | # OS generated files # 31 | ###################### 32 | .DS_Store 33 | .DS_Store? 34 | ._* 35 | .Spotlight-V100 36 | .Trashes 37 | Icon? 38 | ehthumbs.db 39 | Thumbs.db 40 | 41 | # Custom # 42 | .vscode-test/ 43 | .vsix 44 | graphics 45 | node_modules 46 | out -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from '@vscode/test-electron'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Phil Sinatra 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 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.1.0", 4 | "configurations": [ 5 | { 6 | "name": "Launch Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "runtimeExecutable": "${execPath}", 10 | "args": ["--extensionDevelopmentPath=${workspaceRoot}" ], 11 | "stopOnEntry": false, 12 | "sourceMaps": true, 13 | "outFiles": [ "${workspaceRoot}/out/**/*.js" ], 14 | "preLaunchTask": "npm: watch" 15 | }, 16 | { 17 | "name": "Launch Tests", 18 | "type": "extensionHost", 19 | "request": "launch", 20 | "runtimeExecutable": "${execPath}", 21 | "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], 22 | "stopOnEntry": false, 23 | "sourceMaps": true, 24 | "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ], 25 | "preLaunchTask": "npm: watch" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your extension and command. 7 | The sample plugin registers a command and defines its title and command name. With this information 8 | VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 9 | * `src/extension.ts` - this is the main file where you will provide the implementation of your command. 10 | The file exports one function, `activate`, which is called the very first time your extension is 11 | activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 12 | We pass the function containing the implementation of the command as the second parameter to 13 | `registerCommand`. 14 | 15 | ## Get up and running straight away 16 | 17 | * Press `F5` to open a new window with your extension loaded. 18 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 19 | * Set breakpoints in your code inside `src/extension.ts` to debug your extension. 20 | * Find output from your extension in the debug console. 21 | 22 | ## Make changes 23 | 24 | * You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. 25 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 26 | 27 | ## Explore the API 28 | 29 | * You can open the full set of our API when you open the file `node_modules/vscode/vscode.d.ts`. 30 | 31 | ## Run tests 32 | 33 | * Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Launch Tests`. 34 | * Press `F5` to run the tests in a new window with your extension loaded. 35 | * See the output of the test result in the debug console. 36 | * Make changes to `test/extension.test.ts` or create new test files inside the `test` folder. 37 | * By convention, the test runner will only consider files matching the name pattern `**.test.ts`. 38 | * You can create folders inside the `test` folder to structure your tests any way you want. 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nested-comments", 3 | "displayName": "Nested Comments", 4 | "description": "This is a VSCode extension for toggling nested comments.", 5 | "version": "4.1.4", 6 | "author": { 7 | "email": "code@philsinatra.com", 8 | "name": "Phil Sinatra", 9 | "url": "http://philsinatra.com" 10 | }, 11 | "publisher": "philsinatra", 12 | "license": "MIT", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/philsinatra/NestedCommentsVSCode" 16 | }, 17 | "bugs": { 18 | "url": "https://github.com/philsinatra/NestedCommentsVSCode/issues" 19 | }, 20 | "homepage": "http://philsinatra.com/html-nested-comments.html", 21 | "engines": { 22 | "vscode": "^1.64.0" 23 | }, 24 | "categories": [ 25 | "Formatters", 26 | "Other" 27 | ], 28 | "galleryBanner": { 29 | "color": "#6868ac", 30 | "theme": "dark" 31 | }, 32 | "keywords": [ 33 | "comment", 34 | "html", 35 | "css", 36 | "multi-root ready", 37 | "web development", 38 | "scss", 39 | "stylus", 40 | "format" 41 | ], 42 | "icon": "images/icon.png", 43 | "screenshots": [ 44 | { 45 | "path": "images/nest-html.gif" 46 | }, 47 | { 48 | "path": "images/nest-css.gif" 49 | }, 50 | { 51 | "path": "images/nest-jsx.gif" 52 | } 53 | ], 54 | "activationEvents": [ 55 | "onCommand:extension.nestComments" 56 | ], 57 | "main": "./out/extension.js", 58 | "contributes": { 59 | "commands": [ 60 | { 61 | "command": "extension.nestComments", 62 | "title": "Nest Comments" 63 | } 64 | ], 65 | "configuration": { 66 | "type": "object", 67 | "title": "NestedComments", 68 | "properties": { 69 | "nestedComments.notSupportCommand": { 70 | "type": "boolean", 71 | "default": false, 72 | "description": "Does not support executing system comments." 73 | } 74 | } 75 | }, 76 | "keybindings": [ 77 | { 78 | "command": "extension.nestComments", 79 | "key": "ctrl+alt+/", 80 | "mac": "cmd+alt+/", 81 | "when": "editorTextFocus && editorHasSelection" 82 | } 83 | ] 84 | }, 85 | "scripts": { 86 | "vscode:prepublish": "npm run compile", 87 | "compile": "tsc -p ./", 88 | "watch": "tsc -watch -p ./", 89 | "pretest": "npm run compile && npm run lint", 90 | "lint": "eslint src --ext ts", 91 | "test": "node ./out/test/runTest.js" 92 | }, 93 | "devDependencies": { 94 | "@types/glob": "^7.2.0", 95 | "@types/mocha": "^9.0.0", 96 | "@types/node": "14.x", 97 | "@types/vscode": "^1.64.0", 98 | "@typescript-eslint/eslint-plugin": "^5.9.1", 99 | "@typescript-eslint/parser": "^5.9.1", 100 | "@vscode/test-electron": "^2.0.3", 101 | "eslint": "^8.6.0", 102 | "eslint-config-prettier": "^10.1.8", 103 | "eslint-plugin-prettier": "^5.5.4", 104 | "glob": "^7.2.0", 105 | "mocha": "^11.7.5", 106 | "prettier": "^3.6.2", 107 | "typescript": "^4.5.4" 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "nested-comments" 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 | ## 4.1.1 Add Astro support 8 | 9 | ## [4.1.0] 🩹 Update Markdown support 10 | 11 | ## [4.0.0] 🔖 Version 4.0 12 | 13 | ### 🎉 The [Scott Rhamy](https://github.com/cycle4passion) update! 14 | 15 | A big thank you to [Scott Rhamy](https://github.com/cycle4passion) for this major update that finally brings support to Svelte/Vue. 16 | 17 | - Add support for `*.js` and `*.ts` files 18 | - Add support for multiple cursor selections 19 | - Add Svelte/Vue support 20 | - Fix Selection after commenting to include the initial block comment indicator. 21 | - Fix Selection starting with a block comment indicator and having an ending block comment indicator in middle with additional text selected. It would uncomment rather than comment. 22 | - Fix Selection ending on line with additional unselected content. This would cause additional unselected content to be deleted on nesting or unnesting. 23 | 24 | ## [3.0.3] 💄 Update Icon Transparency 25 | 26 | ## [3.0.2] 🔧 Add Publisher 27 | 28 | ## [3.0.1] 🔧 Update Test Scripts 29 | 30 | ## [3.0.0] 🔖 Version 3.0 With Svelte Support 31 | 32 | - Add support for Svelte components 33 | - Upgrade to match version 1.64 34 | - Update screenshots 35 | - Update icon 36 | 37 | ## 2021-10-28 38 | 39 | - 🔧 Add `.tpl` Extension Support 40 | 41 | ## 2019-05-28 42 | 43 | - 🐛 Fix HTML Nesting Bug 44 | 45 | Revert Laverdet update. Separate branch with Laverdet code pushed as a debug source. 46 | 47 | ## 2019-02-17 48 | 49 | - 🚀 Laverdet Update 50 | 51 | Special thanks to [laverdet](https://github.com/laverdet) for a major update, which includes: 52 | 53 | - support for additional languages (full list of supported languages is available in the README file) 54 | - flexible selections: selections don't need to be exact, so if you want to uncomment a block and your selection is off by just whitespace you can still activate the command 55 | - partial uncommenting: if you make a selection within a larger comment block and activate the command you can uncomment just a subset of the larger block 56 | 57 | ## 2018-11-21 58 | 59 | - 💄 Update Icon 60 | 61 | ## 2018-11-19 62 | 63 | - ⬆️ Fix Dependency Vulnerabilities 64 | - ✨ Add Typescript React Language Support 65 | 66 | ## 2018-11-18 67 | 68 | - ✨ Add Twig Support 69 | 70 | ## 2018-11-16 71 | 72 | - ✨ Add JSX Support 73 | 74 | ## 2018-07-27 75 | 76 | - 💡 Update Documentation 77 | 78 | ## [2.1.4] 🐛 Fix CSS Spacing Bug 79 | 80 | ## [2.1.3] 🖼️ Update Icon 81 | 82 | ## [2.1.2] 🎨 Remove Extra Space In CSS Comments 83 | 84 | ## [2.1.1] 📚 Update README 85 | 86 | ## [2.1.0] ✨ Add `XSL` File Support 87 | 88 | ## [2.0.2] 📚 Update `multi-root ready` Status 89 | 90 | ## [2.0.1] 📚 Update `package.json` Keywords/Categories 91 | 92 | ## [2.0.0] 🔧 Add CSS Syntax Support 93 | 94 | ## [1.1.2] 🔧 Fix Keybinding 95 | 96 | - Adjust default keybinding so the package does not hijack the default commenting key binding for Windows users. 97 | 98 | ## [1.1.1] 99 | 100 | - Update Trigger 'When' Case 101 | 102 | Keybinding trigger only happens when a the editor has an active selection. 103 | 104 | ## [1.1.0] 105 | 106 | - Update Icon Image 107 | 108 | ## [1.0.0] 109 | 110 | - Initial release 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nested Comments 2 | 3 | ![Visual Studio Marketplace](https://img.shields.io/vscode-marketplace/v/philsinatra.nested-comments.svg?style=flat-square) 4 | [![Visual Studio Marketplace](https://img.shields.io/vscode-marketplace/d/philsinatra.nested-comments.svg?style=flat-square)] 5 | [![license](https://img.shields.io/github/license/philsinatra/NestedCommentsVSCode.svg?style=flat-square)](https://github.com/philsinatra/NestedCommentsVSCode/blob/master/LICENSE) 6 | 7 | ## About 8 | 9 | If your code contains a comment, and you want to add a new comment to temporarily disable a block or portion of code, the built in commenting functionality does not actually place the comment tags in expected locations. If an existing comment is included in the content being commented out, the first instance of a `-->` or `*/` closing comment tag will end the entire comment. 10 | 11 | This extension will convert pre-existing comments to safe characters, allowing a new block comment that includes the original comment. It also reverses the effect to uncomment the same block of code. Additionally, this extension will work with multiple cursor selections. 12 | 13 | ## Features 14 | 15 | If you need to comment out a portion of your code that includes pre-existing comments, the native commenting functionality will not comment properly or preserve your existing comments. This extension will maintain your original comments and allow you to quickly toggle comments on sections of code. 16 | 17 | ## Examples 18 | 19 | ### HTML Syntax 20 | 21 | ![HTML example](images/nest-html.gif) 22 | 23 | ```html 24 |
25 |
26 |

Hello World

27 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

28 | 29 |
30 |
31 | ``` 32 | 33 | Becomes: 34 | 35 | ```html 36 | 43 | ``` 44 | 45 | ### CSS Syntax 46 | 47 | ![CSS example](images/nest-css.gif) 48 | 49 | ```css 50 | .example { 51 | /* display: flex; */ 52 | transition: all 0.5s; 53 | /* user-select: none; */ 54 | background: linear-gradient(to bottom, white, black); 55 | } 56 | ``` 57 | 58 | Becomes: 59 | 60 | ```css 61 | /*.example { 62 | /~ display: flex; ~/ 63 | transition: all 0.5s; 64 | /~ user-select: none; ~/ 65 | background: linear-gradient(to bottom, white, black); 66 | }*/ 67 | ``` 68 | 69 | ### JSX Syntax 70 | 71 | ![JSX example](images/nest-jsx.gif) 72 | 73 | This commenting style will work for JSX content in `.js` and `.ts` files. Make sure to set the language mode of the file to `javascriptreact`/`typescriptreact` rather than using standard JavaScript for files using JSX. 74 | 75 | ```jsx 76 | 77 | 85 | 86 | ``` 87 | 88 | Becomes: 89 | 90 | ```jsx 91 | 92 | {/**/} 100 | 101 | ``` 102 | 103 | ## Usage 104 | 105 | To trigger the extension, highlight the text that should be commented/uncommented. 106 | 107 | ### Default Keybindings 108 | 109 | - Mac: cmd + alt + / 110 | - Windows: ctrl + alt + / 111 | 112 | ## Extension Settings 113 | 114 | The following languages are supported: 115 | 116 | - asp 117 | - cfm 118 | - css 119 | - htm 120 | - html 121 | - js 122 | - jsx 123 | - md 124 | - njk 125 | - php 126 | - svelte 127 | - svg 128 | - tpl 129 | - ts 130 | - tsx 131 | - twig 132 | - vue 133 | - xml 134 | - xsl 135 | - blade 136 | 137 | ## Known Issues 138 | 139 | None at this time 😃 140 | 141 | ## Release Notes 142 | 143 | Full release notes are available in the CHANGELOG file. 144 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | export function activate(context: vscode.ExtensionContext) { 4 | console.log('Congratulations, your extension "Nested Comments" is now active!') 5 | const nestComments = new NestComments() 6 | 7 | const disposable = vscode.commands.registerCommand('extension.nestComments', () => { 8 | nestComments.updateNestedComments() 9 | }) 10 | 11 | context.subscriptions.push(disposable) 12 | } 13 | 14 | function wrappingRootTag(text: string, selection: string): string { 15 | // Check for Astro frontmatter first (JS/TS between --- delimiters) 16 | const fmRegex = /^---([\s\S]*?)---/ 17 | const fmMatch = text.match(fmRegex) 18 | if (fmMatch?.[1]?.includes(selection)) return 'javascript' 19 | 20 | // Find the position of the selection in the text 21 | const selectionIndex = text.indexOf(selection) 22 | if (selectionIndex === -1) return 'html' 23 | 24 | // Look for script and style tags that contain the selection 25 | const scriptRegex = /]*>([\s\S]*?)<\/script>/gi 26 | const styleRegex = /]*>([\s\S]*?)<\/style>/gi 27 | 28 | // Check style tags first 29 | let match: RegExpExecArray | null = styleRegex.exec(text) 30 | while (match !== null) { 31 | const tagStart = match.index + match[0].indexOf('>') + 1 32 | const tagEnd = match.index + match[0].lastIndexOf('<') 33 | 34 | if (selectionIndex >= tagStart && selectionIndex < tagEnd) { 35 | return 'css' 36 | } 37 | match = styleRegex.exec(text) 38 | } 39 | 40 | // Check script tags 41 | match = scriptRegex.exec(text) 42 | while (match !== null) { 43 | const tagStart = match.index + match[0].indexOf('>') + 1 44 | const tagEnd = match.index + match[0].lastIndexOf('<') 45 | 46 | if (selectionIndex >= tagStart && selectionIndex < tagEnd) { 47 | return 'javascript' 48 | } 49 | match = scriptRegex.exec(text) 50 | } 51 | 52 | return 'html' 53 | } 54 | 55 | function toggleComment( 56 | text: string, 57 | prefix: string, 58 | suffix: string, 59 | nestedPrefix: string, 60 | nestedSuffix: string 61 | ) { 62 | if (text.trimStart().startsWith(prefix) && text.trimEnd().endsWith(suffix)) { 63 | text = text.replaceAll(prefix, '') 64 | text = text.replaceAll(suffix, '') 65 | text = text.replaceAll(nestedPrefix, prefix) 66 | text = text.replaceAll(nestedSuffix, suffix) 67 | } else { 68 | text = text.replaceAll(prefix, nestedPrefix) 69 | text = text.replaceAll(suffix, nestedSuffix) 70 | text = `${prefix}${text}${suffix}` 71 | } 72 | return text 73 | } 74 | 75 | function getNotSupportCommand(): boolean { 76 | return vscode.workspace.getConfiguration('nestedComments').get('notSupportCommand') as boolean 77 | } 78 | 79 | class NestComments { 80 | public updateNestedComments() { 81 | const editor = vscode.window.activeTextEditor 82 | if (!editor) return 83 | const doc = editor.document 84 | const supported = [ 85 | 'asp', 86 | 'astro', 87 | 'cfm', 88 | 'css', 89 | 'htm', 90 | 'html', 91 | 'javascript', 92 | 'javascriptreact', 93 | 'typescript', 94 | 'typescriptreact', 95 | 'markdown', 96 | 'md', 97 | 'njk', 98 | 'php', 99 | 'blade', 100 | 'twig', 101 | 'svelte', 102 | 'svg', 103 | 'tpl', 104 | 'vue', 105 | 'xml', 106 | 'xsl', 107 | 'xslt' 108 | ] 109 | if (supported.indexOf(doc.languageId) === -1) { 110 | if (getNotSupportCommand()) vscode.commands.executeCommand('editor.action.commentLine') 111 | else vscode.window.showInformationMessage(`${doc.languageId} file format not supported!`) 112 | return 113 | } else { 114 | return editor.edit(editBuilder => { 115 | editor.selections.forEach(selection => { 116 | const all_text = editor.document.getText() 117 | const selected_text = editor.document.getText(selection) 118 | let language = doc.languageId 119 | let modified_text = '' 120 | 121 | if (language === 'svelte' || language === 'vue' || language === 'astro') 122 | language = wrappingRootTag(all_text, selected_text) 123 | 124 | switch (language) { 125 | case 'markdown': 126 | if (selected_text.includes('', '') 128 | else if (selected_text.includes('/*')) 129 | modified_text = toggleComment(selected_text, '/*', '*/', '/~', '~/') 130 | else return 131 | break 132 | case 'javascript': 133 | case 'typescript': 134 | case 'css': 135 | modified_text = toggleComment(selected_text, '/*', '*/', '/~', '~/') 136 | break 137 | case 'javascriptreact': 138 | case 'typescriptreact': 139 | modified_text = toggleComment(selected_text, '{/*', '*/}', '/~', '~/') 140 | break 141 | case 'tpl': 142 | case 'twig': 143 | modified_text = toggleComment(selected_text, '{#', '#}', '{~#', '#~}') 144 | break 145 | case 'blade': 146 | modified_text = toggleComment(selected_text, '{{--', '--}}', '{{~~', '~~}}') 147 | break 148 | default: 149 | modified_text = toggleComment(selected_text, '', '') 150 | break 151 | } 152 | 153 | editBuilder.replace(selection, modified_text) 154 | }) 155 | }) 156 | } 157 | } 158 | } 159 | 160 | // this method is called when your extension is deactivated 161 | export function deactivate() { 162 | console.log('NestedComments deactivated') 163 | } 164 | --------------------------------------------------------------------------------