├── .gitignore ├── src ├── .editorconfig └── editorConfigMain.ts ├── typings ├── node.d.ts ├── vscode-typings.d.ts └── editorconfig.d.ts ├── EditorConfig_icon.png ├── .vscodeignore ├── tsconfig.json ├── .vscode ├── settings.json ├── launch.json └── tasks.json ├── .editorconfig ├── test ├── index.ts └── extension.test.ts ├── LICENSE.md ├── README.md ├── package.json └── ThirdPartyNotices.txt /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .DS_Store 4 | Thumbs.db 5 | *.log -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.ts] 2 | indent_style = space 3 | indent_size = 4 4 | -------------------------------------------------------------------------------- /typings/node.d.ts: -------------------------------------------------------------------------------- 1 | /// -------------------------------------------------------------------------------- /typings/vscode-typings.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /EditorConfig_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-editorconfig/HEAD/EditorConfig_icon.png -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | typings/** 3 | out/test/** 4 | test/** 5 | src/** 6 | **/*.map 7 | .gitignore 8 | tsconfig.json 9 | vsc-extension-quickstart.md 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES5", 5 | "outDir": "out", 6 | "noLib": true, 7 | "sourceMap": true 8 | }, 9 | "exclude": [ 10 | "node_modules" 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 | "files.trimTrailingWhitespace": true, 10 | "typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version 11 | } -------------------------------------------------------------------------------- /typings/editorconfig.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'editorconfig' { 2 | 3 | export interface knownProps { 4 | end_of_line?: string, 5 | indent_style?: string, 6 | indent_size?: any, 7 | insert_final_newline?: boolean, 8 | tab_width?: number, 9 | trim_trailing_whitespace?: boolean, 10 | charset?: string 11 | } 12 | 13 | export interface options {config:string, version: string, root:string} 14 | 15 | export function parse(filepath:string, options?:options): any; 16 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | [*.ts] 12 | indent_style = tab 13 | indent_size = 4 14 | 15 | # Matches multiple files with brace expansion notation 16 | # Set default charset 17 | [*.{js,py}] 18 | charset = utf-8 19 | 20 | # 4 space indentation 21 | [*.py] 22 | indent_style = space 23 | indent_size = 4 24 | 25 | # Tab indentation (no size specified) 26 | [Makefile] 27 | indent_style = tab 28 | 29 | # Indentation override for all JS under lib directory 30 | [lib/**.js] 31 | indent_style = space 32 | indent_size = 2 33 | 34 | # Matches the exact files either package.json or .travis.yml 35 | [{package.json,.travis.yml}] 36 | indent_style = space 37 | indent_size = 2 38 | -------------------------------------------------------------------------------- /.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 | "outDir": "out/src", 14 | "preLaunchTask": "npm" 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 | "outDir": "out/test", 25 | "preLaunchTask": "npm" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /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; -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | 9 | // A task runner that calls a custom npm script that compiles the extension. 10 | { 11 | "version": "0.1.0", 12 | 13 | // we want to run npm 14 | "command": "npm", 15 | 16 | // the command is a shell script 17 | "isShellCommand": true, 18 | 19 | // show the output window only if unrecognized errors occur. 20 | "showOutput": "silent", 21 | 22 | // we run the custom script "compile" as defined in package.json 23 | "args": ["run", "compile", "--loglevel", "silent"], 24 | 25 | // The tsc compiler is started in watching mode 26 | "isWatching": true, 27 | 28 | // use the standard tsc in watch mode problem matcher to find compile problems in the output. 29 | "problemMatcher": "$tsc-watch" 30 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation 2 | 3 | All rights reserved. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Editor Config for Visual Studio Code 2 | 3 | > **This version of the Editor Config extension has been deprecated.** 4 | 5 | > Please see [editorconfig/editorconfig-vscode](https://github.com/editorconfig/editorconfig-vscode) for the latest Editor Config extension for VS Code. 6 | 7 | The `microsoft/vscode-editorconfig` extension was initially created to validate the VS Code extension API. This has been a very popular extension that is now actively being enhanced and maintained by the community at [editorconfig/editorconfig-vscode](https://github.com/editorconfig/editorconfig-vscode). 8 | 9 | We are excited to see the community take ownership of this extension. As a result, we are no longer maintaining this version. We recommend that you uninstall the Microsoft version (published by `Chris Dias`) by bringing up the Command Palette, typing in `ext Editor Config`, and clicking on the Uninstall icon: 10 | 11 | ![How to uninstall Editor Config extension](https://cloud.githubusercontent.com/assets/1487073/13100657/4f0a3e94-d4f4-11e5-8851-d80ab5e57c2d.png) 12 | 13 | Afte restarting VS Code, you can install the latest from the `EditorConfig` publisher: 14 | 15 | ![How to install latest Editor Config extension](https://cloud.githubusercontent.com/assets/1487073/13100658/52ab6974-d4f4-11e5-88ec-751312f33ca8.png) 16 | 17 | We apologize for the inconvenience and thank the community for taking this on! 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscodeEditorConfig", 3 | "displayName": "Editor Config for VS Code", 4 | "description": "DEPRECATED - See Read Me for more information", 5 | "publisher": "chrisdias", 6 | "version": "0.1.7", 7 | "icon": "./EditorConfig_icon.png", 8 | "engines": { 9 | "vscode": "^0.10.1" 10 | }, 11 | "author": "Microsoft Corporation", 12 | "license": "MIT", 13 | "categories": [ 14 | "Other" 15 | ], 16 | "homepage": "https://github.com/Microsoft/vscode-editorconfig/blob/master/README.md", 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/Microsoft/vscode-editorconfig.git" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/Microsoft/vscode-editorconfig/issues" 23 | }, 24 | "galleryBanner": { 25 | "color": "#37699A", 26 | "theme": "dark" 27 | }, 28 | "activationEvents": [ 29 | "*" 30 | ], 31 | "main": "./out/src/editorConfigMain", 32 | "contributes": { 33 | "commands": [ 34 | { 35 | "command": "vscode.generateeditorconfig", 36 | "title": "EditorConfig: Generate" 37 | } 38 | ] 39 | }, 40 | "dependencies": { 41 | "editorconfig": "0.12.2", 42 | "open": "0.0.5" 43 | }, 44 | "devDependencies": { 45 | "typescript": "^1.6.2", 46 | "vscode": "0.10.x" 47 | }, 48 | "scripts": { 49 | "vscode:prepublish": "node ./node_modules/vscode/bin/compile", 50 | "compile": "node ./node_modules/vscode/bin/compile -watch -p ./" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ThirdPartyNotices.txt: -------------------------------------------------------------------------------- 1 | THIRD-PARTY SOFTWARE NOTICES AND INFORMATION 2 | Do Not Translate or Localize 3 | 4 | This project incorporates material from the project(s) listed below (collectively, “Third Party Code”). 5 | Microsoft is not the original author of the Third Party Code. The original copyright notice and license 6 | under which Microsoft received such Third Party Code are set out below. This Third Party Code is licensed 7 | to you under their original license terms set forth below. Microsoft reserves all other rights not 8 | expressly granted, whether by implication, estoppel or otherwise. 9 | 10 | ============================================================ 11 | editorconfig https://github.com/editorconfig/editorconfig-core-js 12 | 13 | Copyright © 2012 EditorConfig Team 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the “Software”), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in 23 | all copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 31 | THE SOFTWARE. 32 | 33 | ============================================================ 34 | 35 | node-open https://github.com/pwnall/node-open 36 | 37 | Copyright (c) 2012 Jay Jordan 38 | 39 | Permission is hereby granted, free of charge, to any person 40 | obtaining a copy of this software and associated documentation 41 | files (the "Software"), to deal in the Software without 42 | restriction, including without limitation the rights to use, 43 | copy, modify, merge, publish, distribute, sublicense, and/or sell 44 | copies of the Software, and to permit persons to whom the 45 | Software is furnished to do so, subject to the following 46 | conditions: 47 | 48 | The above copyright notice and this permission notice shall be 49 | included in all copies or substantial portions of the Software. 50 | 51 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 52 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 53 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 54 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 55 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 56 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 57 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 58 | OTHER DEALINGS IN THE SOFTWARE. 59 | 60 | ============================================================ 61 | -------------------------------------------------------------------------------- /test/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as vscode from 'vscode'; 3 | import {Utils} from '../src/editorConfigMain'; 4 | 5 | suite('.editorconfig extension', () => { 6 | 7 | // Defines a Mocha unit test 8 | test('Utils.fromEditorConfig', () => { 9 | [ 10 | { 11 | config: { 12 | indent_style: 'tab', 13 | indent_size: 5 14 | }, 15 | defaults: { 16 | insertSpaces: false, 17 | tabSize: 4 18 | }, 19 | expected: { 20 | insertSpaces: false, 21 | tabSize: 5 22 | } 23 | }, 24 | { 25 | config: { 26 | indent_style: 'tab', 27 | tab_width: 5 28 | }, 29 | defaults: { 30 | insertSpaces: false, 31 | tabSize: 4 32 | }, 33 | expected: { 34 | insertSpaces: false, 35 | tabSize: 5 36 | } 37 | }, 38 | { 39 | config: { 40 | indent_style: 'space', 41 | indent_size: 5 42 | }, 43 | defaults: { 44 | insertSpaces: false, 45 | tabSize: 4 46 | }, 47 | expected: { 48 | insertSpaces: true, 49 | tabSize: 5 50 | } 51 | }, 52 | { 53 | config: { 54 | indent_size: 5 55 | }, 56 | defaults: { 57 | insertSpaces: false, 58 | tabSize: 4 59 | }, 60 | expected: { 61 | insertSpaces: false, 62 | tabSize: 5 63 | } 64 | }, 65 | { 66 | config: { 67 | tab_width: 5 68 | }, 69 | defaults: { 70 | insertSpaces: false, 71 | tabSize: 4 72 | }, 73 | expected: { 74 | insertSpaces: false, 75 | tabSize: 5 76 | } 77 | }, 78 | { 79 | config: { 80 | indent_size: 5 81 | }, 82 | defaults: { 83 | insertSpaces: true, 84 | tabSize: 4 85 | }, 86 | expected: { 87 | insertSpaces: true, 88 | tabSize: 5 89 | } 90 | }, 91 | { 92 | config: { 93 | tab_width: 5 94 | }, 95 | defaults: { 96 | insertSpaces: true, 97 | tabSize: 4 98 | }, 99 | expected: { 100 | insertSpaces: true, 101 | tabSize: 5 102 | } 103 | }, 104 | { 105 | config: { 106 | indent_style: 'space' 107 | }, 108 | defaults: { 109 | insertSpaces: false, 110 | tabSize: 4 111 | }, 112 | expected: { 113 | insertSpaces: true, 114 | tabSize: 4 115 | } 116 | }, 117 | { 118 | config: { 119 | indent_style: 'space' 120 | }, 121 | defaults: { 122 | insertSpaces: false, 123 | tabSize: 5 124 | }, 125 | expected: { 126 | insertSpaces: true, 127 | tabSize: 5 128 | } 129 | }, 130 | { 131 | config: { 132 | indent_size: 'tab', 133 | tab_width: 3 134 | }, 135 | defaults: { 136 | insertSpaces: false, 137 | tabSize: 5 138 | }, 139 | expected: { 140 | insertSpaces: false, 141 | tabSize: 3 142 | } 143 | }, 144 | { 145 | config: {}, 146 | defaults: { 147 | insertSpaces: false, 148 | tabSize: 5 149 | }, 150 | expected: { 151 | insertSpaces: false, 152 | tabSize: 5 153 | } 154 | }, 155 | { 156 | config: {}, 157 | defaults: { 158 | insertSpaces: true, 159 | tabSize: 4 160 | }, 161 | expected: { 162 | insertSpaces: true, 163 | tabSize: 4 164 | } 165 | } 166 | ].forEach(({ config, defaults, expected }) => { 167 | assert.deepEqual(Utils.fromEditorConfig.call(this, config, defaults), expected); 168 | }); 169 | }); 170 | 171 | test('Utils.toEditorConfig', () => { 172 | [ 173 | { 174 | options: { 175 | insertSpaces: true, 176 | tabSize: 5 177 | }, 178 | expected: { 179 | indent_style: 'space', 180 | indent_size: 5 181 | } 182 | }, 183 | { 184 | options: { 185 | insertSpaces: false, 186 | tabSize: 6 187 | }, 188 | expected: { 189 | indent_style: 'tab', 190 | tab_width: 6 191 | } 192 | }, 193 | { 194 | options: { 195 | insertSpaces: false, 196 | tabSize: 'auto' 197 | }, 198 | expected: { 199 | indent_style: 'tab', 200 | tab_width: 4 201 | } 202 | }, 203 | { 204 | options: { 205 | insertSpaces: 'auto', 206 | tabSize: 7 207 | }, 208 | expected: { 209 | indent_style: 'tab', 210 | tab_width: 7 211 | } 212 | }, 213 | { 214 | options: { 215 | insertSpaces: 'auto', 216 | tabSize: 'auto' 217 | }, 218 | expected: { 219 | indent_style: 'tab', 220 | tab_width: 4 221 | } 222 | } 223 | ].forEach(({ options, expected }) => { 224 | assert.deepEqual(Utils.toEditorConfig.call(this, options), expected); 225 | }); 226 | }); 227 | }); -------------------------------------------------------------------------------- /src/editorConfigMain.ts: -------------------------------------------------------------------------------- 1 | import * as editorconfig from 'editorconfig'; 2 | import * as fs from 'fs'; 3 | import {commands, window, workspace, ExtensionContext, TextEditorOptions, 4 | TextEditor, TextEdit, TextDocument, Disposable, Position} from 'vscode'; 5 | 6 | var open = require('open'); 7 | 8 | export function activate(ctx: ExtensionContext): void { 9 | 10 | if (ctx.globalState.get('chrisdias.vscodeEditorConfig.informUser', true)) { 11 | window.showInformationMessage("This version of EditorConfig has been deprecated, more information is available online.", "How to Upgrade").then(selection => { 12 | if (selection) { 13 | open("https://marketplace.visualstudio.com/items?itemName=chrisdias.vscodeEditorConfig"); 14 | } 15 | }); 16 | // only prompt one time 17 | ctx.globalState.update('chrisdias.vscodeEditorConfig.informUser', false); 18 | } 19 | 20 | let documentWatcher = new DocumentWatcher(); 21 | 22 | ctx.subscriptions.push(documentWatcher); 23 | ctx.subscriptions.push(window.onDidChangeActiveTextEditor((textEditor) => { 24 | applyEditorConfigToTextEditor(textEditor, documentWatcher); 25 | })); 26 | applyEditorConfigToTextEditor(window.activeTextEditor, documentWatcher); 27 | 28 | // register a command handler to generate a .editorconfig file 29 | commands.registerCommand('vscode.generateeditorconfig', generateEditorConfig); 30 | } 31 | 32 | interface IEditorConfigProvider { 33 | getSettingsForDocument(document: TextDocument): editorconfig.knownProps; 34 | } 35 | 36 | /** 37 | * Listens to vscode document open and maintains a map (Document => editor config settings) 38 | */ 39 | class DocumentWatcher implements IEditorConfigProvider { 40 | 41 | private _documentToConfigMap: { [uri: string]: editorconfig.knownProps }; 42 | private _disposable: Disposable; 43 | 44 | constructor() { 45 | 46 | let subscriptions: Disposable[] = [] 47 | 48 | // Listen for new documents being openend 49 | subscriptions.push(workspace.onDidOpenTextDocument((doc) => this._onDidOpenDocument(doc))); 50 | 51 | // Listen for saves to ".editorconfig" files and rebuild the map 52 | subscriptions.push(workspace.onDidSaveTextDocument(savedDocument => { 53 | if (/\.editorconfig$/.test(savedDocument.fileName)) { 54 | // Saved an .editorconfig file => rebuild map entirely 55 | this._rebuildConfigMap(); 56 | } 57 | applyOnSaveTransformations(savedDocument, this); 58 | })); 59 | 60 | // dispose event subscriptons upon disposal 61 | this._disposable = Disposable.from(...subscriptions); 62 | 63 | // Build the map (cover the case that documents were opened before my activation) 64 | this._rebuildConfigMap(); 65 | } 66 | 67 | public dispose(): void { 68 | this._disposable.dispose(); 69 | } 70 | 71 | public getSettingsForDocument(document: TextDocument): editorconfig.knownProps { 72 | return this._documentToConfigMap[document.fileName]; 73 | } 74 | 75 | private _rebuildConfigMap(): void { 76 | this._documentToConfigMap = {}; 77 | workspace.textDocuments.forEach(document => this._onDidOpenDocument(document)); 78 | } 79 | 80 | private _onDidOpenDocument(document: TextDocument): void { 81 | if (document.isUntitled) { 82 | // Does not have a fs path 83 | return; 84 | } 85 | 86 | let path = document.fileName; 87 | editorconfig.parse(path).then((config: editorconfig.knownProps) => { 88 | // workaround for the fact that sometimes indent_size is set to "tab": 89 | // see https://github.com/editorconfig/editorconfig-core-js/blob/b2e00d96fcf3be242d4bf748829b8e3a778fd6e2/editorconfig.js#L56 90 | if (config.indent_size === 'tab') { 91 | delete config.indent_size; 92 | } 93 | 94 | // console.log('storing ' + path + ' to ' + JSON.stringify(config, null, '\t')); 95 | this._documentToConfigMap[path] = config; 96 | 97 | applyEditorConfigToTextEditor(window.activeTextEditor, this); 98 | }); 99 | } 100 | } 101 | 102 | function applyEditorConfigToTextEditor(textEditor: TextEditor, provider: IEditorConfigProvider): void { 103 | if (!textEditor) { 104 | // No more open editors 105 | return; 106 | } 107 | 108 | let doc = textEditor.document; 109 | let editorconfig = provider.getSettingsForDocument(doc); 110 | 111 | if (!editorconfig) { 112 | // no configuration found for this file 113 | return; 114 | } 115 | 116 | let { insertSpaces, tabSize } = textEditor.options; 117 | let newOptions = Utils.fromEditorConfig( 118 | editorconfig, 119 | { 120 | insertSpaces, 121 | tabSize 122 | } 123 | ); 124 | 125 | // console.log('setting ' + textEditor.document.fileName + ' to ' + JSON.stringify(newOptions, null, '\t')); 126 | 127 | window.setStatusBarMessage('EditorConfig: ' + (newOptions.insertSpaces ? "Spaces:" : "Tabs:") + ' ' + newOptions.tabSize, 1500); 128 | 129 | textEditor.options = newOptions; 130 | } 131 | 132 | function applyOnSaveTransformations( 133 | textDocument: TextDocument, 134 | provider: IEditorConfigProvider): void { 135 | 136 | let editorconfig = provider.getSettingsForDocument(textDocument); 137 | 138 | if (!editorconfig) { 139 | // no configuration found for this file 140 | return; 141 | } 142 | 143 | insertFinalNewlineTransform(editorconfig, textDocument); 144 | } 145 | 146 | function insertFinalNewlineTransform( 147 | editorconfig: editorconfig.knownProps, 148 | textDocument: TextDocument): void { 149 | 150 | if (editorconfig.insert_final_newline && textDocument.lineCount > 0) { 151 | let lastLine = textDocument.lineAt(textDocument.lineCount - 1); 152 | let lastLineLength = lastLine.text.length; 153 | if (lastLineLength < 1) { 154 | return; 155 | } 156 | let editor = findEditor(textDocument); 157 | if (!editor) { 158 | return; 159 | } 160 | editor.edit(edit => { 161 | let pos = new Position(lastLine.lineNumber, lastLineLength); 162 | return edit.insert(pos, newline(editorconfig)); 163 | }).then(() => textDocument.save()); 164 | } 165 | } 166 | 167 | function newline(editorconfig: editorconfig.knownProps): string { 168 | if (editorconfig.end_of_line === 'cr') { 169 | return '\r'; 170 | } else if (editorconfig.end_of_line == 'crlf') { 171 | return '\r\n'; 172 | } 173 | return '\n'; 174 | } 175 | 176 | function findEditor(textDocument: TextDocument): TextEditor { 177 | for (let editor of window.visibleTextEditors) { 178 | if (editor.document === textDocument) { 179 | return editor; 180 | } 181 | } 182 | 183 | return null; 184 | } 185 | 186 | /** 187 | * Generate an .editorconfig file in the root of the workspace based on the current vscode settings. 188 | */ 189 | function generateEditorConfig() { 190 | if (!workspace.rootPath) { 191 | window.showInformationMessage("Please open a folder before generating an .editorconfig file"); 192 | return; 193 | } 194 | 195 | let editorConfigurationNode = workspace.getConfiguration('editor'); 196 | let settings = Utils.toEditorConfig({ 197 | insertSpaces: editorConfigurationNode.get('insertSpaces'), 198 | tabSize: editorConfigurationNode.get('tabSize') 199 | }); 200 | 201 | let fileContents = 202 | `root = true 203 | 204 | [*] 205 | `; 206 | 207 | [ 208 | 'indent_style', 209 | 'indent_size', 210 | 'tab_width' 211 | ].forEach(setting => { 212 | if (settings.hasOwnProperty(setting)) { 213 | fileContents += `${setting} = ${settings[setting]} 214 | `; 215 | } 216 | }); 217 | 218 | let editorconfigFile = workspace.rootPath + '/.editorconfig'; 219 | fs.exists(editorconfigFile, (exists) => { 220 | if (exists) { 221 | window.showInformationMessage('An .editorconfig file already exists in your workspace.'); 222 | return; 223 | } 224 | 225 | fs.writeFile(editorconfigFile, fileContents, err => { 226 | if (err) { 227 | window.showErrorMessage(err.toString()); 228 | return; 229 | } 230 | }); 231 | }); 232 | } 233 | 234 | export class Utils { 235 | 236 | /** 237 | * Convert .editorconfig values to vscode editor options 238 | */ 239 | public static fromEditorConfig( 240 | config: editorconfig.knownProps, 241 | defaults: { 242 | insertSpaces: boolean; 243 | tabSize: number; 244 | } 245 | ): TextEditorOptions { 246 | return { 247 | insertSpaces: config.indent_style ? (config.indent_style === 'tab' ? false : true) : defaults.insertSpaces, 248 | tabSize: config.tab_width || config.indent_size || defaults.tabSize 249 | }; 250 | } 251 | 252 | /** 253 | * Convert vscode editor options to .editorconfig values 254 | */ 255 | public static toEditorConfig( 256 | options: { 257 | insertSpaces: boolean | string; 258 | tabSize: number | string; 259 | } 260 | ) { 261 | let result: editorconfig.knownProps = {}; 262 | 263 | switch (options.insertSpaces) { 264 | case true: 265 | result.indent_style = 'space'; 266 | result.indent_size = Utils.resolveTabSize(options.tabSize); 267 | break; 268 | case false: 269 | case 'auto': 270 | result.indent_style = 'tab'; 271 | result.tab_width = Utils.resolveTabSize(options.tabSize); 272 | break; 273 | } 274 | 275 | return result; 276 | } 277 | 278 | /** 279 | * Convert vscode tabSize option into numeric value 280 | */ 281 | public static resolveTabSize(tabSize: number | string) { 282 | return (tabSize === 'auto') ? 4 : parseInt(tabSize + '', 10); 283 | } 284 | } 285 | --------------------------------------------------------------------------------