├── src ├── test │ ├── workspace │ │ └── .gitkeep │ ├── extension.test.ts │ └── index.ts └── extension.ts ├── .gitignore ├── .vscode ├── extensions.json ├── settings.json ├── tasks.json └── launch.json ├── .gitattributes ├── assets ├── demo.gif └── icon.png ├── .vscodeignore ├── tslint.json ├── CHANGELOG.md ├── README.md ├── tsconfig.json ├── LICENSE └── package.json /src/test/workspace/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test/ 4 | *.vsix 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "eg2.tslint" 4 | ] 5 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behavior to automatically normalize line endings. 2 | * text=auto 3 | 4 | -------------------------------------------------------------------------------- /assets/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lacroixdavid1/vscode-format-context-menu/HEAD/assets/demo.gif -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lacroixdavid1/vscode-format-context-menu/HEAD/assets/icon.png -------------------------------------------------------------------------------- /.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 | tslint.json -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-string-throw": true, 4 | "no-unused-expression": true, 5 | "no-duplicate-variable": true, 6 | "curly": true, 7 | "class-name": true, 8 | "semicolon": [ 9 | true, 10 | "always" 11 | ], 12 | "triple-equals": true 13 | }, 14 | "defaultSeverity": "warning" 15 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.4 2 | - Now shows progression. 3 | - Now cancellable. 4 | 5 | ## 1.0.3 6 | - Added a setting to close files after saving. 7 | 8 | ## 1.0.2 9 | - Added demo in `README.md`. 10 | - Fixes formatting files from SCM when some deleted files are selected. 11 | 12 | ## 1.0.1 13 | - Fixed extension `README.md` from vscode extension store. 14 | 15 | ## 1.0.0 16 | - Initial release. -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": true, 5 | ".vscode-test": true, 6 | "node_modules": true 7 | }, 8 | "search.exclude": { 9 | "out": true, 10 | ".vscode-test": true, 11 | "node_modules": true 12 | }, 13 | 14 | "typescript.tsc.autoDetect": "off" 15 | } -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /src/test/extension.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Note: This example test is leveraging the Mocha test framework. 3 | // Please refer to their documentation on https://mochajs.org/ for help. 4 | // 5 | 6 | // The module 'assert' provides assertion methods from node 7 | import * as assert from 'assert'; 8 | 9 | // You can import and use all API from the 'vscode' module 10 | // as well as import your extension to test it 11 | // import * as vscode from 'vscode'; 12 | // import * as myExtension from '../extension'; 13 | 14 | // Defines a Mocha test suite to group tests of similar kind together 15 | suite("Extension Tests", () => { 16 | 17 | // Defines a Mocha unit test 18 | test("Something 1", () => { 19 | assert.equal(-1, [1, 2, 3].indexOf(5)); 20 | assert.equal(-1, [1, 2, 3].indexOf(0)); 21 | }); 22 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VSCode format in context menus 2 | 3 | This VSCode extension allows the user to format one or multiple files with right-click context menu. 4 | 5 | ![Demo](https://github.com/lacroixdavid1/vscode-format-context-menu/blob/master/assets/demo.gif?raw=true) 6 | 7 | ## Features 8 | 9 | - Format one or multiple files from Explorer Context Menu 10 | - Format one or multiple files from SCM Context Menu 11 | - Format one file from Editor File Tile Context Menu 12 | 13 | ## Extension Settings 14 | 15 | This extension contributes the following settings: 16 | 17 | * `formatContextMenu.saveAfterFormat`: enable/disable saving after formatting (default: `true`). 18 | * `formatContextMenu.closeAfterSave`: enable/disable closing closing after saving (default: `false`). This does nothing unless you have enabled saving after formatting. 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | /* Strict Type-Checking Option */ 12 | "strict": true, 13 | /* enable all strict type-checking options */ 14 | /* Additional Checks */ 15 | "noUnusedLocals": true /* Report errors on unused locals. */ 16 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 17 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 18 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 19 | }, 20 | "exclude": [ 21 | "node_modules", 22 | ".vscode-test" 23 | ] 24 | } -------------------------------------------------------------------------------- /src/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 | import * as testRunner from '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; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David Lacroix 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 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js" 18 | ], 19 | "preLaunchTask": "npm: watch" 20 | }, 21 | { 22 | "name": "Extension Tests", 23 | "type": "extensionHost", 24 | "request": "launch", 25 | "runtimeExecutable": "${execPath}", 26 | "args": [ 27 | "${workspaceRoot}/src/test/workspace", 28 | "--extensionDevelopmentPath=${workspaceFolder}", 29 | "--extensionTestsPath=${workspaceFolder}/out/test" 30 | ], 31 | "outFiles": [ 32 | "${workspaceFolder}/out/test/**/*.js" 33 | ], 34 | "preLaunchTask": "npm: watch" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as vscode from 'vscode'; 4 | import * as fs from 'fs'; 5 | 6 | export function activate(context: vscode.ExtensionContext) { 7 | 8 | const formatUris = async (uris: vscode.Uri[]) => { 9 | 10 | // Getting current settings 11 | const saveAfterFormat = vscode.workspace.getConfiguration().get('formatContextMenu.saveAfterFormat') as boolean; 12 | const closeAfterSave = vscode.workspace.getConfiguration().get('formatContextMenu.closeAfterSave') as boolean; 13 | 14 | const increment = (1 / uris.length) * 100; 15 | 16 | const progressOptions: vscode.ProgressOptions = { 17 | location: vscode.ProgressLocation.Notification, 18 | title: 'Formatting files', 19 | cancellable: true, 20 | }; 21 | 22 | vscode.window.withProgress(progressOptions, async (progress: vscode.Progress<{ message?: string; increment?: number }>, cancellationToken: vscode.CancellationToken) => { 23 | for (let i = 0; i < uris.length; i++) { 24 | const uri = uris[i]; 25 | if (cancellationToken.isCancellationRequested) { 26 | break; 27 | } 28 | try { 29 | progress.report({ 30 | message: `${i + 1}/${uris.length}` 31 | }); 32 | await vscode.window.showTextDocument(uris[i], { preserveFocus: false, preview: true }); 33 | await vscode.commands.executeCommand('editor.action.formatDocument', uri); 34 | if (saveAfterFormat) { 35 | await vscode.commands.executeCommand('workbench.action.files.save', uri); 36 | if (closeAfterSave) { 37 | await vscode.commands.executeCommand('workbench.action.closeActiveEditor', uri); 38 | } 39 | } 40 | } catch (exception) { 41 | vscode.window.showWarningMessage(`Could not format file ${uri}`); 42 | } 43 | progress.report({ 44 | increment: increment, 45 | }); 46 | } 47 | }); 48 | 49 | }; 50 | 51 | const getRecursiveUris = async (uris: vscode.Uri[]) => { 52 | let outputUris: vscode.Uri[] = []; 53 | for (let i = 0; i < uris.length; i++) { 54 | if (fs.existsSync(uris[i].fsPath)) { 55 | if (fs.lstatSync(uris[i].fsPath).isDirectory()) { 56 | outputUris = [...outputUris, ...await vscode.workspace.findFiles({ 57 | base: uris[i].path, 58 | pattern: '**/*' 59 | })]; 60 | } else { 61 | outputUris.push(uris[i]); 62 | } 63 | } 64 | } 65 | return outputUris; 66 | }; 67 | 68 | context.subscriptions.push(...[ 69 | 70 | vscode.commands.registerCommand('extension.formatSelectedFilesFromScmContext', async (...selectedFiles: vscode.SourceControlResourceState[]) => { 71 | const uris = await getRecursiveUris(selectedFiles.map(x => x.resourceUri)); 72 | await formatUris(uris); 73 | }), 74 | 75 | vscode.commands.registerCommand('extension.formatSelectedFileFromEditorTileContext', async (clickedFile: vscode.Uri) => { 76 | await formatUris([clickedFile]); 77 | }), 78 | 79 | vscode.commands.registerCommand('extension.formatSelectedFilesFromExplorerContext', async (clickedFile: vscode.Uri, selectedFiles: vscode.Uri[]) => { 80 | const uris = await getRecursiveUris(selectedFiles || [clickedFile]); 81 | await formatUris(uris); 82 | }) 83 | 84 | ]); 85 | 86 | } 87 | 88 | export function deactivate() { 89 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-format-context-menu", 3 | "displayName": "Format in context menus", 4 | "description": "VSCode extension to format multiple files with right click context menu", 5 | "version": "1.0.4", 6 | "publisher": "lacroixdavid1", 7 | "icon": "assets/icon.png", 8 | "author": { 9 | "name": "David Lacroix", 10 | "email": "lacroix.david1@gmail.com" 11 | }, 12 | "license": "MIT", 13 | "keywords": [ 14 | "format multiple files", 15 | "format", 16 | "context menu" 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/lacroixdavid1/vscode-format-context-menu.git" 21 | }, 22 | "homepage": "https://github.com/lacroixdavid1/vscode-format-context-menu/blob/master/README.md", 23 | "bugs": { 24 | "url": "https://github.com/lacroixdavid1/vscode-format-context-menu/issues", 25 | "email": "lacroix.david1@gmail.com" 26 | }, 27 | "engines": { 28 | "vscode": "^1.25.0" 29 | }, 30 | "categories": [ 31 | "Other", 32 | "Formatters" 33 | ], 34 | "activationEvents": [ 35 | "onCommand:extension.formatSelectedFilesFromExplorerContext", 36 | "onCommand:extension.formatSelectedFilesFromScmContext", 37 | "onCommand:extension.formatSelectedFileFromEditorTileContext" 38 | ], 39 | "main": "./out/extension", 40 | "contributes": { 41 | "configuration": [ 42 | { 43 | "title": "Format From Context Menu", 44 | "properties": { 45 | "formatContextMenu.saveAfterFormat": { 46 | "type": "boolean", 47 | "default": true, 48 | "description": "Save file after formatting.", 49 | "scope": "window" 50 | }, 51 | "formatContextMenu.closeAfterSave": { 52 | "type": "boolean", 53 | "default": false, 54 | "description": "Close file after saving. This does nothing unless you have enabled saving after formatting.", 55 | "scope": "window" 56 | } 57 | } 58 | } 59 | ], 60 | "commands": [ 61 | { 62 | "command": "extension.formatSelectedFilesFromExplorerContext", 63 | "title": "Format" 64 | }, 65 | { 66 | "command": "extension.formatSelectedFilesFromScmContext", 67 | "title": "Format" 68 | }, 69 | { 70 | "command": "extension.formatSelectedFileFromEditorTileContext", 71 | "title": "Format" 72 | } 73 | ], 74 | "menus": { 75 | "explorer/context": [ 76 | { 77 | "command": "extension.formatSelectedFilesFromExplorerContext" 78 | } 79 | ], 80 | "scm/resourceState/context": [ 81 | { 82 | "command": "extension.formatSelectedFilesFromScmContext" 83 | } 84 | ], 85 | "editor/title/context": [ 86 | { 87 | "command": "extension.formatSelectedFileFromEditorTileContext" 88 | } 89 | ] 90 | } 91 | }, 92 | "scripts": { 93 | "vscode:prepublish": "npm run compile", 94 | "compile": "tsc -p ./", 95 | "watch": "tsc -watch -p ./", 96 | "postinstall": "node ./node_modules/vscode/bin/install", 97 | "test": "npm run compile && export CODE_TESTS_WORKSPACE=./src/test/workspace && node ./node_modules/vscode/bin/test" 98 | }, 99 | "devDependencies": { 100 | "typescript": "^2.6.1", 101 | "vscode": "^1.1.6", 102 | "tslint": "^5.8.0", 103 | "@types/node": "^7.0.43", 104 | "@types/mocha": "^2.2.42" 105 | } 106 | } --------------------------------------------------------------------------------