├── .github ├── assignment.yml ├── locker.yml └── needs_more_info.yml ├── .gitignore ├── .readme ├── contributions_list.png └── demo.gif ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── SECURITY.md ├── build ├── node-extension.webpack.config.js ├── pipeline.yml └── web-extension.webpack.config.js ├── package-lock.json ├── package.json ├── package.nls.json ├── settings ├── defaults.json └── mappings.json ├── src ├── extension.ts ├── fsWrapper.ts ├── mapper.ts ├── settings.ts ├── sublimeFolderFinder.ts ├── test │ ├── runTests.ts │ └── suite │ │ ├── extension.test.ts │ │ ├── index.ts │ │ └── testData.ts └── web │ └── extension.ts ├── sublime_keyboard_with_padding.png ├── tsconfig.json └── tslint.json /.github/assignment.yml: -------------------------------------------------------------------------------- 1 | { 2 | perform: true, 3 | assignees: [chrisdias] 4 | } 5 | -------------------------------------------------------------------------------- /.github/locker.yml: -------------------------------------------------------------------------------- 1 | { 2 | daysAfterClose: 45, 3 | daysSinceLastUpdate: 3, 4 | perform: true 5 | } 6 | -------------------------------------------------------------------------------- /.github/needs_more_info.yml: -------------------------------------------------------------------------------- 1 | { 2 | daysUntilClose: 7, 3 | needsMoreInfoLabel: 'needs more info', 4 | perform: true, 5 | closeComment: "This issue has been closed automatically because it needs more information and has not had recent activity. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" 6 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | node_modules 4 | .DS_Store 5 | .vscode-test 6 | *.vsix -------------------------------------------------------------------------------- /.readme/contributions_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-sublime-keybindings/5d7eac6603cf57b8a8f1b5cff6f63c1f59529111/.readme/contributions_list.png -------------------------------------------------------------------------------- /.readme/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-sublime-keybindings/5d7eac6603cf57b8a8f1b5cff6f63c1f59529111/.readme/demo.gif -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 6 | "eamodio.tsl-problem-matcher" 7 | ] 8 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Launch Extension", 6 | "type": "extensionHost", 7 | "request": "launch", 8 | "runtimeExecutable": "${execPath}", 9 | "args": [ 10 | "--extensionDevelopmentPath=${workspaceRoot}" 11 | ], 12 | "stopOnEntry": false, 13 | "sourceMaps": true, 14 | "outFiles": [ 15 | "${workspaceRoot}/out/**/*.js" 16 | ], 17 | "preLaunchTask": "npm: watch" 18 | }, 19 | { 20 | "name": "Extension Tests", 21 | "type": "extensionHost", 22 | "request": "launch", 23 | "runtimeExecutable": "${execPath}", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceRoot}", 26 | "--extensionTestsPath=${workspaceRoot}/out/test" 27 | ], 28 | "stopOnEntry": false, 29 | "sourceMaps": true, 30 | "outFiles": [ 31 | "${workspaceRoot}/out/test/**/*.js" 32 | ], 33 | "preLaunchTask": "npm: watch" 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /.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": "compile", 9 | "group": { 10 | "kind": "build", 11 | "isDefault": true 12 | }, 13 | "problemMatcher": [ 14 | "$ts-webpack", 15 | "$tslint-webpack" 16 | ] 17 | }, 18 | { 19 | "type": "npm", 20 | "script": "watch", 21 | "group": "build", 22 | "isBackground": true, 23 | "problemMatcher": [ 24 | "$ts-webpack-watch", 25 | "$tslint-webpack-watch" 26 | ] 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | typings/** 3 | out/test/** 4 | test/** 5 | build/** 6 | out/** 7 | src/** 8 | **/*.map 9 | .gitignore 10 | tsconfig.json 11 | vsc-extension-quickstart.md 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 4.0.10 2 | - Update extensionKind property in `package.json`. 3 | 4 | ## 4.0.9 5 | - Add `deleteAllLeft` binding (`Ctrl+Shift+Backspace` and `Ctrl+Shift+Delete`) [#136](https://github.com/microsoft/vscode-sublime-keybindings/pull/136) 6 | 7 | ## 4.0.8 8 | - Don't show welcome message if installed by Settings Sync [#132](https://github.com/microsoft/vscode-sublime-keybindings/issues/132) 9 | - Updated dependencies to address dependabot issues 10 | 11 | ## 4.0.7 12 | - Update readme 13 | - Fix tests 14 | 15 | ## 4.0.6 16 | - Update `extensionKind` to be both `ui` and `workspace` (will favor ui), see [vscode#85819](https://github.com/microsoft/vscode/issues/85819) 17 | 18 | ## 4.0.5 19 | - Update `extensionKind` property, fix npm security issues 20 | - Adopt [PR #116](https://github.com/microsoft/vscode-sublime-keybindings/pull/116) that adds `CMD+Y` 21 | 22 | ## 4.0 23 | - New feature: import settings from an existing Sublime installation 24 | 25 | ## 3.0.3 26 | - Add command to delete from cursor until end of line fixes in https://github.com/Microsoft/vscode-sublime-keybindings/commit/ca4f3e787c8533e67451870b193bdf8bd5609108 27 | - Bump required VS Code version to 1.18 in https://github.com/Microsoft/vscode-sublime-keybindings/commit/9c8a5547821af06f9e3caa69900e9b9d76fbc15a 28 | - Make quick open - enter behave like in Sublime in https://github.com/Microsoft/vscode-sublime-keybindings/commit/ff2de479301947f90cf740c3afdfc66832239a4b 29 | 30 | ## 3.0 - Added settings: minimap, format on paste. 31 | 32 | ## 2.0 - Numerous small fixes. 33 | 34 | ## 1.5.0 - New keybindings and nit fixes per [@bhancock8](https://github.com/bhancock8) 35 | 36 | ## 1.4.0 - Added Windows / Linux key bindings and a number of missing commands. Updated the README. 37 | 38 | ## 1.3.0 - Improved README 39 | 40 | ## 1.2.0 - Fixes a number of keybinding changes with [PR #9](https://github.com/Microsoft/vscode-sublime-keybindings/pull/9) and [PR #12](https://github.com/Microsoft/vscode-sublime-keybindings/pull/12) (credit to [securingsincity](https://github.com/Microsoft/vscode-sublime-keybindings/issues?q=is%3Apr+author%3Asecuringsincity) and [benmosher](https://github.com/Microsoft/vscode-sublime-keybindings/issues?q=is%3Apr+author%3Abenmosher)). 41 | 42 | ## 1.0.0 - Initial migration. 43 | ## 1.0.0 - Initial. 44 | -------------------------------------------------------------------------------- /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 of this software and associated documentation 8 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 9 | modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 17 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Sublime Importer for VS Code 3 | 4 | This extension imports keybindings and settings from Sublime Text to Visual Studio Code. 5 | 6 | ## Getting Started 7 | ### Keymappings 8 | This extension ports the most popular Sublime Text keyboard shortcuts to Visual Studio Code. 9 | Just restart VS Code after the installation of this extension and your favorite Sublime Text keyboard shortcuts will be available in VS Code. 10 | ### Importing settings 11 | The first time the extension is launched a prompt is shown that lets you import your Sublime Settings. 12 | If you want to import your settings at a later time use the `Sublime Text Keymap: Import Sublime Text Settings` command from the Command Palette (F1). 13 | 14 | ![](.readme/demo.gif) 15 | ## FAQ 16 | ### What keyboard shortcuts are included? 17 | 18 | The included keyboard shortcuts can be looked up in the [contribution list](https://code.visualstudio.com/docs/editor/extension-gallery#_extension-details). 19 | 20 | ![extension contributions](.readme/contributions_list.png) 21 | 22 | ### Why don't all Sublime Text commands work? 23 | 24 | VS Code has not implemented all features. Head on over to this [GitHub issue](https://github.com/Microsoft/vscode/issues/3776) and let the VS Code team know what you'd like to see. 25 | 26 | You can install an extension for many of these features: 27 | 28 | * [Expand Selection To Scope](https://marketplace.visualstudio.com/items?itemName=vittorioromeo.expand-selection-to-scope) 29 | * [FontSize Shortcuts](https://marketplace.visualstudio.com/items?itemName=peterjuras.fontsize-shortcuts) 30 | * [change case](https://marketplace.visualstudio.com/items?itemName=wmaurer.change-case) 31 | * [expand-region](https://marketplace.visualstudio.com/items?itemName=letrieu.expand-region) 32 | * [transpose](https://marketplace.visualstudio.com/items?itemName=v4run.transpose) 33 | * [Close HTML/XML tag](https://marketplace.visualstudio.com/items?itemName=Compulim.compulim-vscode-closetag) 34 | 35 | ## Contributing 36 | ### How do I contribute a keyboard shortcut? 37 | 38 | We may have missed a keyboard shortcut. If we did please help us out! It is very easy to make a PR. 39 | 40 | 1. Head over to our [GitHub repository](https://github.com/Microsoft/vscode-sublime-keybindings). 41 | 2. Open the [`package.json` file](https://github.com/Microsoft/vscode-sublime-keybindings/blob/main/package.json). 42 | 3. Add a JSON object to [`contributes.keybindings`](https://github.com/Microsoft/vscode-sublime-keybindings/blob/main/package.json#L57) as seen below. 43 | 4. Open a pull request. 44 | 45 | ```json 46 | { 47 | "mac": "", 48 | "linux": "", 49 | "win": "", 50 | "key": "", 51 | "command": "" 52 | } 53 | ``` 54 | 55 | ### How do I contribute a Sublime setting? 56 | 57 | There are two different types of settings files: The ```mappings``` file holds the information on how a sublime setting can be mapped to a VS Code setting. The ```defaults``` file contains default Sublime settings that are not explicitly set in the Sublime settings file (e.g. the Monokai theme). 58 | To make a Pull Request: 59 | 1. Head over to our [GitHub repository](https://github.com/Microsoft/vscode-sublime-keybindings). 60 | 2. Open the [`settings/mappings.json`](https://github.com/Microsoft/vscode-sublime-keybindings/blob/main/settings/mappings.json) or the [`settings/defaults.json`](https://github.com/Microsoft/vscode-sublime-keybindings/blob/main/settings/defaults.json) file. 61 | 3. Add your setting 62 | 4. Open a pull request. 63 | 64 | 65 | ## License 66 | [MIT](LICENSE.md) 67 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /build/node-extension.webpack.config.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | 3 | 'use strict'; 4 | 5 | const path = require('path'); 6 | 7 | /**@type {import('webpack').Configuration}*/ 8 | const config = { 9 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 10 | mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') 11 | node: false, 12 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 13 | output: { 14 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 15 | path: path.resolve(__dirname, '..', 'dist'), 16 | filename: 'extension.js', 17 | libraryTarget: 'commonjs2', 18 | devtoolModuleFilenameTemplate: '../[resource-path]' 19 | }, 20 | devtool: 'source-map', 21 | externals: { 22 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 23 | }, 24 | resolve: { 25 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 26 | extensions: ['.ts', '.js'] 27 | }, 28 | module: { 29 | rules: [ 30 | { 31 | test: /\.ts$/, 32 | exclude: /node_modules/, 33 | use: [ 34 | { 35 | loader: 'ts-loader' 36 | } 37 | ] 38 | } 39 | ] 40 | } 41 | }; 42 | module.exports = config; -------------------------------------------------------------------------------- /build/pipeline.yml: -------------------------------------------------------------------------------- 1 | name: $(Date:yyyyMMdd)$(Rev:.r) 2 | 3 | trigger: 4 | branches: 5 | include: 6 | - main 7 | pr: none 8 | 9 | resources: 10 | repositories: 11 | - repository: templates 12 | type: github 13 | name: microsoft/vscode-engineering 14 | ref: main 15 | endpoint: Monaco 16 | 17 | parameters: 18 | - name: publishExtension 19 | displayName: 🚀 Publish Extension 20 | type: boolean 21 | default: false 22 | 23 | extends: 24 | template: azure-pipelines/extension/stable.yml@templates 25 | parameters: 26 | publishExtension: ${{ parameters.publishExtension }} 27 | 28 | l10nSourcePaths: ./src 29 | 30 | buildSteps: 31 | - script: npm ci 32 | displayName: Install dependencies 33 | 34 | tsa: 35 | config: 36 | areaPath: 'Visual Studio Code Keybinding Extensions' 37 | serviceTreeID: 'b43346cb-06b1-4256-97a5-9aaa18eaff90' 38 | enabled: true 39 | -------------------------------------------------------------------------------- /build/web-extension.webpack.config.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | //@ts-check 7 | 'use strict'; 8 | 9 | //@ts-check 10 | /** @typedef {import('webpack').Configuration} WebpackConfig **/ 11 | 12 | const path = require('path'); 13 | 14 | module.exports = /** @type WebpackConfig */ { 15 | context: path.dirname(__dirname), 16 | mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') 17 | target: 'webworker', // extensions run in a webworker context 18 | entry: { 19 | extension: './src/web/extension.ts', 20 | }, 21 | resolve: { 22 | mainFields: ['module', 'main'], 23 | extensions: ['.ts', '.js'], // support ts-files and js-files 24 | alias: { 25 | } 26 | }, 27 | module: { 28 | rules: [{ 29 | test: /\.ts$/, 30 | exclude: /node_modules/, 31 | use: [{ 32 | // configure TypeScript loader: 33 | // * enable sources maps for end-to-end source maps 34 | loader: 'ts-loader', 35 | options: { 36 | compilerOptions: { 37 | 'sourceMap': true, 38 | 'declaration': false 39 | } 40 | } 41 | }] 42 | }] 43 | }, 44 | externals: { 45 | 'vscode': 'commonjs vscode', // ignored because it doesn't exist 46 | }, 47 | performance: { 48 | hints: false 49 | }, 50 | output: { 51 | filename: 'extension.js', 52 | path: path.join(__dirname, '../dist/web'), 53 | libraryTarget: 'commonjs' 54 | }, 55 | devtool: 'source-map' 56 | }; 57 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sublime-keybindings", 3 | "displayName": "Sublime Text Keymap and Settings Importer", 4 | "description": "Import Sublime Text settings and keybindings into VS Code.", 5 | "version": "4.1.10", 6 | "publisher": "ms-vscode", 7 | "license": "SEE LICENSE IN LICENSE.md", 8 | "engines": { 9 | "vscode": "^1.75.0" 10 | }, 11 | "categories": [ 12 | "Keymaps" 13 | ], 14 | "keywords": [ 15 | "keymap", 16 | "Importer", 17 | "Settings", 18 | "Sublime Text" 19 | ], 20 | "activationEvents": [ 21 | "onStartupFinished" 22 | ], 23 | "main": "./dist/extension.js", 24 | "browser": "./dist/web/extension.js", 25 | "l10n": "./l10n", 26 | "preview": false, 27 | "extensionKind": [ 28 | "ui", 29 | "workspace" 30 | ], 31 | "icon": "sublime_keyboard_with_padding.png", 32 | "repository": { 33 | "type": "git", 34 | "url": "https://github.com/Microsoft/vscode-sublime-keybindings.git" 35 | }, 36 | "bugs": { 37 | "url": "https://github.com/Microsoft/vscode-sublime-keybindings/issues" 38 | }, 39 | "scripts": { 40 | "test": "node ./out/test/runTests.js", 41 | "pretest": "tsc -p ./", 42 | "vscode:prepublish": "npm run package && npm run package-web", 43 | "package": "webpack --mode production --config ./build/node-extension.webpack.config.js", 44 | "compile": "webpack --config ./build/node-extension.webpack.config.js", 45 | "watch": "webpack --watch --config ./build/node-extension.webpack.config.js", 46 | "compile-web": "webpack --config ./build/web-extension.webpack.config.js", 47 | "watch-web": "webpack --watch --config ./build/web-extension.webpack.config.js", 48 | "package-web": "webpack --mode production --config ./build/web-extension.webpack.config.js", 49 | "lint": "tslint -p ./" 50 | }, 51 | "devDependencies": { 52 | "@types/glob": "^7.1.3", 53 | "@types/mocha": "^8.2.2", 54 | "@types/node": "^12.12.0", 55 | "@types/vscode": "^1.75.0", 56 | "@types/relaxed-json": "^1.0.0", 57 | "glob": "^7.1.6", 58 | "mocha": "^10.2.0", 59 | "tslint": "^6.1.3", 60 | "typescript": "^4.2.3", 61 | "vscode-test": "^1.5.2", 62 | "ts-loader": "^8.1.0", 63 | "webpack": "^5.89.0", 64 | "webpack-cli": "^5.1.4" 65 | }, 66 | "dependencies": { 67 | "relaxed-json": "^1.0.3" 68 | }, 69 | "contributes": { 70 | "menus": { 71 | "commandPalette": [ 72 | { 73 | "command": "extension.importFromSublime", 74 | "when": "" 75 | } 76 | ] 77 | }, 78 | "commands": [ 79 | { 80 | "command": "extension.importFromSublime", 81 | "title": "%extension.importFromSublime.title%", 82 | "category": "%extension.category%" 83 | } 84 | ], 85 | "keybindings": [ 86 | { 87 | "mac": "cmd+y", 88 | "win": "ctrl+y", 89 | "linux": "ctrl+y", 90 | "key": "ctrl+y", 91 | "command": "redo", 92 | "when": "editorTextFocus && !editorReadonly" 93 | }, 94 | { 95 | "mac": "ctrl+shift+cmd+f", 96 | "win": "shift+f11", 97 | "linux": "shift+f11", 98 | "key": "shift+f11", 99 | "command": "workbench.action.toggleZenMode" 100 | }, 101 | { 102 | "mac": "cmd+w", 103 | "win": "ctrl+w", 104 | "linux": "ctrl+w", 105 | "key": "ctrl+w", 106 | "command": "workbench.action.closeActiveEditor" 107 | }, 108 | { 109 | "mac": "shift+cmd+[", 110 | "key": "ctrl+pageup", 111 | "command": "workbench.action.previousEditor" 112 | }, 113 | { 114 | "mac": "shift+cmd+]", 115 | "key": "ctrl+pagedown", 116 | "command": "workbench.action.nextEditor" 117 | }, 118 | { 119 | "mac": "alt+cmd+s", 120 | "key": "none", 121 | "command": "workbench.action.files.saveAll" 122 | }, 123 | { 124 | "mac": "cmd+k cmd+b", 125 | "win": "ctrl+k ctrl+b", 126 | "linux": "ctrl+k ctrl+b", 127 | "key": "ctrl+k ctrl+b", 128 | "command": "workbench.action.toggleSidebarVisibility" 129 | }, 130 | { 131 | "mac": "ctrl+alt+up", 132 | "key": "ctrl+up", 133 | "command": "scrollLineUp", 134 | "when": "editorTextFocus" 135 | }, 136 | { 137 | "mac": "ctrl+alt+down", 138 | "key": "ctrl+down", 139 | "command": "scrollLineDown", 140 | "when": "editorTextFocus" 141 | }, 142 | { 143 | "mac": "cmd+t", 144 | "key": "ctrl+p", 145 | "command": "workbench.action.quickOpen" 146 | }, 147 | { 148 | "mac": "cmd+r", 149 | "win": "ctrl+r", 150 | "linux": "ctrl+r", 151 | "key": "ctrl+r", 152 | "command": "workbench.action.gotoSymbol" 153 | }, 154 | { 155 | "mac": "cmd+r", 156 | "win": "ctrl+;", 157 | "linux": "ctrl+;", 158 | "key": "ctrl+;", 159 | "command": "workbench.action.gotoSymbol" 160 | }, 161 | { 162 | "mac": "cmd+alt+down", 163 | "key": "f12", 164 | "command": "editor.action.goToDeclaration" 165 | }, 166 | { 167 | "win": "alt+-", 168 | "linux": "alt+-", 169 | "key": "ctrl+-", 170 | "command": "workbench.action.navigateBack" 171 | }, 172 | { 173 | "win": "alt+shift+-", 174 | "linux": "alt+shift+-", 175 | "key": "ctrl+shift+-", 176 | "command": "workbench.action.navigateForward" 177 | }, 178 | { 179 | "mac": "cmd+g", 180 | "win": "f3", 181 | "linux": "f3", 182 | "key": "f3", 183 | "command": "editor.action.nextMatchFindAction", 184 | "when": "editorTextFocus" 185 | }, 186 | { 187 | "mac": "f4", 188 | "win": "f4", 189 | "linux": "f4", 190 | "key": "f4", 191 | "command": "editor.action.nextMatchFindAction", 192 | "when": "editorTextFocus" 193 | }, 194 | { 195 | "mac": "shift+f4", 196 | "win": "shift+f4", 197 | "linux": "shift+f4", 198 | "key": "shift+f4", 199 | "command": "editor.action.previousMatchFindAction", 200 | "when": "editorTextFocus" 201 | }, 202 | { 203 | "mac": "ctrl+cmd+up", 204 | "win": "ctrl+shift+up", 205 | "linux": "ctrl+shift+up", 206 | "key": "ctrl+shift+up", 207 | "command": "editor.action.moveLinesUpAction", 208 | "when": "editorTextFocus" 209 | }, 210 | { 211 | "mac": "ctrl+cmd+down", 212 | "win": "ctrl+shift+down", 213 | "linux": "ctrl+shift+down", 214 | "key": "ctrl+shift+down", 215 | "command": "editor.action.moveLinesDownAction", 216 | "when": "editorTextFocus" 217 | }, 218 | { 219 | "mac": "cmd+alt+/", 220 | "win": "ctrl+shift+/", 221 | "linux": "ctrl+shift+/", 222 | "key": "ctrl+shift+/", 223 | "command": "editor.action.commentLine", 224 | "when": "editorTextFocus" 225 | }, 226 | { 227 | "mac": "cmd+k cmd+up", 228 | "win": "ctrl+k ctrl+up", 229 | "linux": "ctrl+k ctrl+up", 230 | "key": "ctrl+k ctrl+up", 231 | "command": "workbench.action.splitEditor" 232 | }, 233 | { 234 | "mac": "alt+cmd+1", 235 | "linux": "alt+shift+1", 236 | "win": "alt+shift+1", 237 | "key": "alt+shift+1", 238 | "command": "workbench.action.joinTwoGroups" 239 | }, 240 | { 241 | "mac": "alt+cmd+2", 242 | "win": "alt+shift+2", 243 | "linux": "alt+shift+2", 244 | "key": "alt+shift+2", 245 | "command": "workbench.action.splitEditor" 246 | }, 247 | { 248 | "mac": "alt+cmd+8", 249 | "win": "alt+shift+8", 250 | "linux": "alt+shift+8", 251 | "key": "alt+shift+8", 252 | "command": "workbench.action.toggleEditorGroupLayout" 253 | }, 254 | { 255 | "mac": "cmd+k cmd+down", 256 | "win": "ctrl+k ctrl+down", 257 | "linux": "ctrl+k ctrl+down", 258 | "key": "ctrl+k ctrl+down", 259 | "command": "workbench.action.closeActiveEditor" 260 | }, 261 | { 262 | "mac": "alt+cmd+[", 263 | "key": "ctr+shift+[", 264 | "command": "editor.fold", 265 | "when": "editorFocus" 266 | }, 267 | { 268 | "mac": "cmd+alt+]", 269 | "key": "ctrl+shift+]", 270 | "command": "editor.unfold", 271 | "when": "editorFocus" 272 | }, 273 | { 274 | "mac": "cmd+k cmd+0", 275 | "win": "ctrl+k ctrl+0", 276 | "linux": "ctrl+k ctrl+0", 277 | "key": "ctrl+k ctrl+0", 278 | "command": "editor.unfoldAll", 279 | "when": "editorFocus" 280 | }, 281 | { 282 | "mac": "alt+f12", 283 | "key": "alt+f12", 284 | "command": "editor.action.showContextMenu", 285 | "when": "editorTextFocus" 286 | }, 287 | { 288 | "mac": "cmd+shift+d", 289 | "win": "ctrl+shift+d", 290 | "linux": "ctrl+shift+d", 291 | "key": "ctrl+shift+d", 292 | "command": "editor.action.copyLinesDownAction", 293 | "when": "editorFocus" 294 | }, 295 | { 296 | "mac": "cmd+l", 297 | "win": "ctrl+l", 298 | "linux": "ctrl+l", 299 | "key": "ctrl+l", 300 | "command": "expandLineSelection", 301 | "when": "editorFocus" 302 | }, 303 | { 304 | "mac": "cmd+d", 305 | "win": "ctrl+d", 306 | "linux": "ctrl+d", 307 | "key": "ctrl+d", 308 | "command": "editor.action.addSelectionToNextFindMatch", 309 | "when": "editorFocus" 310 | }, 311 | { 312 | "mac": "ctrl+m", 313 | "win": "ctrl+m", 314 | "linux": "ctrl+m", 315 | "key": "ctrl+m", 316 | "command": "editor.action.jumpToBracket", 317 | "when": "editorFocus" 318 | }, 319 | { 320 | "mac": "cmd+alt+/", 321 | "win": "ctrl+shift+/", 322 | "linux": "ctrl+shift+/", 323 | "key": "ctrl+shift+/", 324 | "command": "editor.action.blockComment", 325 | "when": "editorFocus" 326 | }, 327 | { 328 | "mac": "cmd+alt+f", 329 | "win": "ctrl+h", 330 | "linux": "ctrl+h", 331 | "key": "ctrl+h", 332 | "command": "editor.action.startFindReplaceAction" 333 | }, 334 | { 335 | "mac": "ctrl+shift+k", 336 | "win": "ctrl+shift+k", 337 | "linux": "ctrl+shift+k", 338 | "key": "ctrl+shift+k", 339 | "command": "editor.action.deleteLines", 340 | "when": "editorFocus" 341 | }, 342 | { 343 | "mac": "ctrl+shift+backspace", 344 | "win": "ctrl+shift+backspace", 345 | "linux": "ctrl+shift+backspace", 346 | "key": "ctrl+shift+backspace", 347 | "command": "deleteAllLeft", 348 | "when": "editorFocus" 349 | }, 350 | { 351 | "mac": "ctrl+shift+delete", 352 | "win": "ctrl+shift+delete", 353 | "linux": "ctrl+shift+delete", 354 | "key": "ctrl+shift+delete", 355 | "command": "deleteAllRight", 356 | "when": "editorFocus" 357 | }, 358 | { 359 | "mac": "ctrl+shift+up", 360 | "win": "alt+shift+up", 361 | "linux": "alt+shift+up", 362 | "key": "alt+shift+up", 363 | "command": "editor.action.insertCursorAbove", 364 | "when": "editorTextFocus" 365 | }, 366 | { 367 | "mac": "ctrl+shift+down", 368 | "win": "alt+shift+down", 369 | "linux": "alt+shift+down", 370 | "key": "alt+shift+down", 371 | "command": "editor.action.insertCursorBelow", 372 | "when": "editorTextFocus" 373 | }, 374 | { 375 | "mac": "ctrl+shift+pageup", 376 | "win": "alt+shift+pageup", 377 | "linux": "alt+shift+pageup", 378 | "key": "alt+shift+pageup", 379 | "command": "cursorColumnSelectPageUp", 380 | "when": "editorTextFocus" 381 | }, 382 | { 383 | "mac": "ctrl+shift+pagedown", 384 | "win": "alt+shift+pagedown", 385 | "linux": "alt+shift+pagedown", 386 | "key": "alt+shift+pagedown", 387 | "command": "cursorColumnSelectPageDown", 388 | "when": "editorTextFocus" 389 | }, 390 | { 391 | "mac": "cmd+shift+l", 392 | "win": "ctrl+shift+l", 393 | "linux": "ctrl+shift+l", 394 | "key": "ctrl+shift+l", 395 | "command": "editor.action.insertCursorAtEndOfEachLineSelected", 396 | "when": "editorTextFocus" 397 | }, 398 | { 399 | "mac": "cmd+1", 400 | "win": "alt+1", 401 | "linux": "alt+1", 402 | "key": "alt+1", 403 | "command": "workbench.action.openEditorAtIndex1" 404 | }, 405 | { 406 | "mac": "cmd+2", 407 | "win": "alt+2", 408 | "linux": "alt+2", 409 | "key": "alt+2", 410 | "command": "workbench.action.openEditorAtIndex2" 411 | }, 412 | { 413 | "mac": "cmd+3", 414 | "win": "alt+3", 415 | "linux": "alt+3", 416 | "key": "alt+3", 417 | "command": "workbench.action.openEditorAtIndex3" 418 | }, 419 | { 420 | "mac": "cmd+4", 421 | "win": "alt+4", 422 | "linux": "alt+4", 423 | "key": "alt+4", 424 | "command": "workbench.action.openEditorAtIndex4" 425 | }, 426 | { 427 | "mac": "cmd+5", 428 | "win": "alt+5", 429 | "linux": "alt+5", 430 | "key": "alt+5", 431 | "command": "workbench.action.openEditorAtIndex5" 432 | }, 433 | { 434 | "mac": "cmd+6", 435 | "win": "alt+6", 436 | "linux": "alt+6", 437 | "key": "alt+6", 438 | "command": "workbench.action.openEditorAtIndex6" 439 | }, 440 | { 441 | "mac": "cmd+7", 442 | "win": "alt+7", 443 | "linux": "alt+7", 444 | "key": "alt+7", 445 | "command": "workbench.action.openEditorAtIndex7" 446 | }, 447 | { 448 | "mac": "cmd+8", 449 | "win": "alt+8", 450 | "linux": "alt+8", 451 | "key": "alt+8", 452 | "command": "workbench.action.openEditorAtIndex8" 453 | }, 454 | { 455 | "mac": "cmd+9", 456 | "win": "alt+9", 457 | "linux": "alt+9", 458 | "key": "alt+9", 459 | "command": "workbench.action.openEditorAtIndex9" 460 | }, 461 | { 462 | "mac": "cmd+ctrl+g", 463 | "win": "alt+f3", 464 | "linux": "alt+f3", 465 | "key": "alt+f3", 466 | "command": "editor.action.selectHighlights", 467 | "when": "editorFocus" 468 | }, 469 | { 470 | "mac": "cmd+shift+r", 471 | "win": "ctrl+shift+r", 472 | "linux": "ctrl+shift+r", 473 | "key": "ctrl+shift+r", 474 | "command": "workbench.action.showAllSymbols" 475 | }, 476 | { 477 | "mac": "ctrl+alt+left", 478 | "win": "alt+left", 479 | "linux": "ctrl+alt+left", 480 | "key": "ctrl+alt+left", 481 | "command": "cursorWordStartLeft", 482 | "when": "editorTextFocus" 483 | }, 484 | { 485 | "mac": "ctrl+alt+right", 486 | "win": "alt+right", 487 | "linux": "ctrl+alt+right", 488 | "key": "ctrl+alt+right", 489 | "command": "cursorWordEndRight", 490 | "when": "editorTextFocus" 491 | }, 492 | { 493 | "mac": "ctrl+alt+shift+left", 494 | "win": "alt+shift+left", 495 | "linux": "ctrl+alt+shift+left", 496 | "key": "ctrl+alt+shift+left", 497 | "command": "cursorWordStartLeftSelect", 498 | "when": "editorTextFocus" 499 | }, 500 | { 501 | "mac": "ctrl+alt+shift+right", 502 | "win": "alt+shift+right", 503 | "linux": "ctrl+alt+shift+right", 504 | "key": "ctrl+alt+shift+right", 505 | "command": "cursorWordEndRightSelect", 506 | "when": "editorTextFocus" 507 | }, 508 | { 509 | "mac": "cmd+j", 510 | "key": "ctrl+j", 511 | "command": "editor.action.joinLines", 512 | "when": "editorTextFocus" 513 | }, 514 | { 515 | "mac": "cmd+k cmd+u", 516 | "key": "ctrl+k ctrl+u", 517 | "command": "editor.action.transformToUppercase", 518 | "when": "editorTextFocus" 519 | }, 520 | { 521 | "mac": "cmd+k cmd+l", 522 | "key": "ctrl+k ctrl+l", 523 | "command": "editor.action.transformToLowercase", 524 | "when": "editorTextFocus" 525 | }, 526 | { 527 | "mac": "cmd+k a", 528 | "key": "ctrl+k a", 529 | "command": "workbench.action.showErrorsWarnings" 530 | }, 531 | { 532 | "mac": "cmd+k n", 533 | "key": "ctrl+k n", 534 | "command": "editor.action.marker.next", 535 | "when": "editorFocus" 536 | }, 537 | { 538 | "mac": "cmd+k p", 539 | "key": "ctrl+k p", 540 | "command": "editor.action.marker.prev", 541 | "when": "editorFocus" 542 | }, 543 | { 544 | "mac": "ctrl+1", 545 | "win": "ctrl+1", 546 | "linux": "ctrl+1", 547 | "key": "ctrl+1", 548 | "command": "workbench.action.focusFirstEditorGroup", 549 | "when": "editorFocus" 550 | }, 551 | { 552 | "mac": "ctrl+2", 553 | "win": "ctrl+2", 554 | "linux": "ctrl+2", 555 | "key": "ctrl+2", 556 | "command": "workbench.action.focusSecondEditorGroup", 557 | "when": "editorFocus" 558 | }, 559 | { 560 | "mac": "ctrl+3", 561 | "win": "ctrl+3", 562 | "linux": "ctrl+3", 563 | "key": "ctrl+3", 564 | "command": "workbench.action.focusThirdEditorGroup", 565 | "when": "editorFocus" 566 | }, 567 | { 568 | "mac": "cmd+p", 569 | "win": "ctrl+p", 570 | "linux": "ctrl+p", 571 | "key": "ctrl+p", 572 | "command": "workbench.action.quickOpenPreviousEditor" 573 | }, 574 | { 575 | "mac": "cmd+k cmd+k", 576 | "win": "ctrl+k ctrl+k", 577 | "linux": "ctrl+k ctrl+k", 578 | "command": "deleteAllRight", 579 | "key": "ctrl+k ctrl+k", 580 | "when": "editorTextFocus && !editorReadonly" 581 | }, 582 | { 583 | "mac": "cmd+shift+space", 584 | "win": "ctrl+shift+space", 585 | "linux": "ctrl+shift+space", 586 | "command": "editor.action.smartSelect.grow", 587 | "key": "ctrl+shift+space", 588 | "when": "editorTextFocus" 589 | } 590 | ] 591 | } 592 | } 593 | -------------------------------------------------------------------------------- /package.nls.json: -------------------------------------------------------------------------------- 1 | { 2 | "extension.importFromSublime.title": "Import Sublime Text Settings", 3 | "extension.category": "Sublime Text Keymap" 4 | } 5 | -------------------------------------------------------------------------------- /settings/defaults.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | "editor.multiCursorModifier", 4 | "ctrlCmd" 5 | ], 6 | [ 7 | "editor.snippetSuggestions", 8 | "top" 9 | ], 10 | [ 11 | "editor.formatOnPaste", 12 | true 13 | ], 14 | [ 15 | "workbench.colorTheme", 16 | "Monokai" 17 | ] 18 | ] -------------------------------------------------------------------------------- /settings/mappings.json: -------------------------------------------------------------------------------- 1 | { 2 | "scroll_speed": "editor.mouseWheelScrollSensitivity", // Number 3 | "hot_exit": { 4 | "true": { 5 | "files.hotExit": "onExit" 6 | }, 7 | "false": { 8 | "files.hotExit": "off" 9 | } 10 | }, 11 | "open_files_in_new_window": { 12 | "true": { 13 | "window.openFilesInNewWindow": "on" 14 | }, 15 | "false": { 16 | "window.openFilesInNewWindow": "off" 17 | } 18 | }, 19 | "close_windows_when_empty": "window.closeWhenEmpty", // Boolean 20 | "show_full_path": { 21 | "true": { 22 | "window.title": "${activeEditorFull}${separator}${rootName}" 23 | }, 24 | "false": { 25 | "window.title": "${activeEditorShort}${separator}${rootName}" 26 | } 27 | }, 28 | "preview_on_click": "workbench.editor.enablePreview", // Boolean 29 | "show_tab_close_buttons": { 30 | "true": { 31 | "workbench.editor.tabCloseButton": "right" 32 | }, 33 | "false": { 34 | "workbench.editor.tabCloseButton": "off" 35 | } 36 | }, 37 | "save_on_focus_lost": { 38 | "true": { 39 | "files.autoSave": "onFocusChange" 40 | }, 41 | "false": { 42 | "files.autoSave": "off" 43 | } 44 | }, 45 | "find_selected_text": "editor.find.seedSearchStringFromSelection", // Boolean 46 | "word_separators": "editor.wordSeparators", // String 47 | "ensure_newline_at_eof_on_save": "files.insertFinalNewline", // Boolean 48 | "auto_indent": "editor.autoIndent", // Boolean 49 | "tab_size": "editor.tabSize", // Number 50 | "use_tab_stops": "editor.useTabStops", // Boolean 51 | "trim_automatic_white_space": "editor.trimAutoWhitespace", // Boolean 52 | "detect_indentation": "editor.detectIndentation", // Boolean 53 | "draw_white_space": { 54 | "all": { 55 | "editor.renderWhitespace": "all" 56 | }, 57 | "none": { 58 | "editor.renderWhitespace": "none" 59 | }, 60 | "selection": { 61 | "editor.renderWhitespace": "boundary" 62 | } 63 | }, 64 | "trim_trailing_white_space_on_save": "files.trimTrailingWhitespace", // Boolean 65 | "tab_completion": "editor.tabCompletion", // Boolean 66 | "auto_complete_delay": "editor.quickSuggestionsDelay", // Number 67 | "auto_complete_commit_on_tab": { 68 | "true": { 69 | "editor.acceptSuggestionOnEnter": "off" 70 | }, 71 | "false": { 72 | "editor.acceptSuggestionOnEnter": "on" 73 | } 74 | }, 75 | "copy_with_empty_selection": "editor.emptySelectionClipboard", // Boolean 76 | "auto_find_in_selection": "editor.find.autoFindInSelection", // Boolean 77 | "drag_text": "editor.dragAndDrop", // Boolean 78 | "font_face": "editor.fontFamily", // String 79 | "font_size": "editor.fontSize", // Number 80 | "line_numbers": { 81 | "true": { 82 | "editor.lineNumbers": "on" 83 | }, 84 | "false": { 85 | "editor.lineNumbers": "off" 86 | } 87 | }, 88 | "fade_fold_buttons": { 89 | "true": { 90 | "editor.showFoldingControls": "mouseover" 91 | }, 92 | "false": { 93 | "editor.showFoldingControls": "always" 94 | } 95 | }, 96 | "scroll_past_end": "editor.scrollBeyondLastLine", // Boolean 97 | "word_wrap": { 98 | "true": { 99 | "editor.wordWrap": "on" 100 | }, 101 | "false": { 102 | "editor.wordWrap": "off" 103 | }, 104 | "auto": { 105 | "editor.wordWrap": "on" 106 | } 107 | }, 108 | "indent_subsequent_lines": { 109 | "true": { 110 | "editor.wrappingIndent": "same" 111 | }, 112 | "false": { 113 | "editor.wrappingIndent": "none" 114 | } 115 | }, 116 | "match_brackets": "editor.matchBrackets", // Boolean 117 | "match_selection": "editor.selectionHighlight", // Boolean 118 | "draw_indent_guides": "editor.renderIndentGuides", // Boolean 119 | "remember_full_screen": "window.restoreFullscreen", // Boolean, 120 | "default_encoding": { 121 | "UTF-8": { 122 | "files.encoding": "utf8" 123 | }, 124 | "UTF-16 LE": { 125 | "files.encoding": "utf16le" 126 | }, 127 | "UTF-16 BE": { 128 | "files.encoding": "utf16be" 129 | }, 130 | "Western (Windows 1252)": { 131 | "files.encoding": "windows1252" 132 | }, 133 | "Western (ISO 8859-1)": { 134 | "files.encoding": "iso88591" 135 | }, 136 | "Western (ISO 8859-3)": { 137 | "files.encoding": "iso88593" 138 | }, 139 | "Western (ISO 8859-15)": { 140 | "files.encoding": "iso885915" 141 | }, 142 | "Western (Mac Roman)": { 143 | "files.encoding": "macroman" 144 | }, 145 | "DOS (CP 437)": { 146 | "files.encoding": "cp437" 147 | }, 148 | "Arabic (Windows 1256)": { 149 | "files.encoding": "windows1256" 150 | }, 151 | "Arabic (ISO 8859-6)": { 152 | "files.encoding": "iso88596" 153 | }, 154 | "Baltic (Windows 1257)": { 155 | "files.encoding": "windows1257" 156 | }, 157 | "Baltic (ISO 8859-4)": { 158 | "files.encoding": "iso88594" 159 | }, 160 | "Celtic (ISO 8859-14)": { 161 | "files.encoding": "iso885914" 162 | }, 163 | "Central European (Windows 1250)": { 164 | "files.encoding": "windows1250" 165 | }, 166 | "Central European (ISO 8859-2)": { 167 | "files.encoding": "iso88592" 168 | }, 169 | "Cyrillic (Windows 1251)": { 170 | "files.encoding": "windows1251" 171 | }, 172 | "Cyrillic (Windows 866)": { 173 | "files.encoding": "cp866" 174 | }, 175 | "Cyrillic (ISO 8859-5)": { 176 | "files.encoding": "iso88595" 177 | }, 178 | "Cyrillic (KOI8-R)": { 179 | "files.encoding": "koi8r" 180 | }, 181 | "Cyrillic (KOI8-U)": { 182 | "files.encoding": "koi8u" 183 | }, 184 | "Estonian (ISO 8859-13)": { 185 | "files.encoding": "iso885913" 186 | }, 187 | "Greek (Windows 1253)": { 188 | "files.encoding": "windows1253" 189 | }, 190 | "Greek (ISO 8859-7)": { 191 | "files.encoding": "iso88597" 192 | }, 193 | "Hebrew (Windows 1255)": { 194 | "files.encoding": "windows1255" 195 | }, 196 | "Hebrew (ISO 8859-8)": { 197 | "files.encoding": "iso88598" 198 | }, 199 | "Nordic (ISO 8859-10)": { 200 | "files.encoding": "iso885910" 201 | }, 202 | "Romanian (ISO 8859-16)": { 203 | "files.encoding": "iso885916" 204 | }, 205 | "Turkish (Windows 1254)": { 206 | "files.encoding": "windows1254" 207 | }, 208 | "Turkish (ISO 8859-9)": { 209 | "files.encoding": "iso88599" 210 | }, 211 | "Vietnamese (Windows 1258)": { 212 | "files.encoding": "windows1258" 213 | } 214 | } 215 | // "folder_exclude_patterns": "files.exclude", 216 | // "file_exclude_patterns": "files.exclude", 217 | // "color_scheme": "workbench.colorTheme", 218 | // "wrap_width": "editor.wordWrapColumn", 219 | // "rulers": "editor.rulers", 220 | // "caret_style": "editor.cursorBlinking", 221 | // "auto_complete": "editor.quickSuggestions", 222 | // "find_selected_text": "autoFindInSelection", // Boolean 223 | } -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { readFileAsync } from './fsWrapper'; 3 | import { Mapper } from './mapper'; 4 | import { ISetting, MappedSetting, CategorizedSettings, VscodeSetting } from './settings'; 5 | import * as sublimeFolderFinder from './sublimeFolderFinder'; 6 | import * as path from 'path'; 7 | 8 | const mapper = new Mapper(); 9 | 10 | export async function activate(context: vscode.ExtensionContext): Promise { 11 | context.globalState.setKeysForSync(['alreadyPrompted']); 12 | context.subscriptions.push(vscode.commands.registerCommand('extension.importFromSublime', () => start())); 13 | const hasPrompted = context.globalState.get('alreadyPrompted') || false; 14 | if (!hasPrompted) { 15 | await showPrompt(); 16 | await context.globalState.update('alreadyPrompted', true); 17 | } 18 | } 19 | 20 | async function showPrompt(): Promise { 21 | const yes = vscode.l10n.t('Yes'); 22 | const no = vscode.l10n.t('No'); 23 | const answer: string | undefined = await vscode.window.showInformationMessage( 24 | vscode.l10n.t('Would you like to customize VS Code to behave more like Sublime Text?'), 25 | yes, 26 | no, 27 | ); 28 | if (answer && answer === yes) { 29 | start(); 30 | } 31 | } 32 | 33 | async function start(): Promise { 34 | const categorizedSettings = await getCategorizedSettings(); 35 | if (categorizedSettings) { 36 | if (categorizedSettings.mappedSettings.length || categorizedSettings.defaultSettings.length) { 37 | const selectedSettings: VscodeSetting[] = await showPicker(categorizedSettings); 38 | if (selectedSettings && selectedSettings.length) { 39 | await importSettings(selectedSettings); 40 | await vscode.commands.executeCommand('workbench.action.openGlobalSettings'); 41 | } 42 | } else { 43 | vscode.window.showInformationMessage(vscode.l10n.t('Nothing to import. All settings have already been imported')); 44 | } 45 | } 46 | } 47 | 48 | async function getCategorizedSettings(): Promise { 49 | const settingsPath = await getSublimeFolderPath(); 50 | if (settingsPath) { 51 | return getSettings(settingsPath); 52 | } 53 | return null; 54 | } 55 | 56 | async function getSublimeFolderPath(): Promise { 57 | const sublimeSettingsPath = await sublimeFolderFinder.getExistingDefaultPaths(); 58 | if (sublimeSettingsPath) { 59 | return sublimeSettingsPath.fsPath; 60 | } 61 | return await browsePrompt( 62 | vscode.l10n.t( 63 | 'No Sublime settings file found at the default location: {0}', 64 | path.join(sublimeFolderFinder.getOSDefaultPaths()[0], sublimeFolderFinder.sublimeSettingsFilename) 65 | ) 66 | ); 67 | } 68 | 69 | async function browsePrompt(msg: string): Promise { 70 | const result = await vscode.window.showInformationMessage(msg, vscode.l10n.t('Browse...')); 71 | if (!result) { 72 | return undefined; 73 | } 74 | const sublimeSettingsFiles = await vscode.window.showOpenDialog({ canSelectFiles: true }); 75 | if (!sublimeSettingsFiles || !sublimeSettingsFiles.length) { 76 | return undefined; 77 | 78 | } 79 | const filePath = sublimeSettingsFiles[0].fsPath; 80 | const isValidFilePath = await validate(filePath); 81 | if (isValidFilePath) { 82 | return filePath; 83 | } else { 84 | vscode.window.showErrorMessage( 85 | vscode.l10n.t({ 86 | message: 'Could not find {0} at {1}', 87 | args: [sublimeFolderFinder.sublimeSettingsFilename, sublimeSettingsFiles[0].fsPath], 88 | comment: ['{0} is a filename, {1} is a path'] 89 | }) 90 | ); 91 | return undefined; 92 | } 93 | } 94 | 95 | function validate(settingsFilePath: string): boolean { 96 | return settingsFilePath.endsWith(sublimeFolderFinder.sublimeSettingsFilename); 97 | } 98 | 99 | async function getSettings(sublimeSettingsPath: string): Promise { 100 | const settings: CategorizedSettings | undefined = await mapper.getMappedSettings(await readFileAsync(sublimeSettingsPath, 'utf-8')); 101 | settings.mappedSettings.sort((a, b) => { 102 | if (a.vscode.overwritesValue && b.vscode.overwritesValue) { 103 | return a.sublime.name.localeCompare(b.sublime.name); 104 | } else if (a.vscode.overwritesValue) { 105 | return -1; 106 | } else if (b.vscode.overwritesValue) { 107 | return 1; 108 | } 109 | return a.sublime.name.localeCompare(b.sublime.name); 110 | }); 111 | return settings; 112 | } 113 | 114 | interface ISettingsQuickPickItem extends vscode.QuickPickItem { 115 | /** Used to map back from QuickPickItem to Setting */ 116 | setting: MappedSetting | VscodeSetting; 117 | } 118 | 119 | async function showPicker(settings: CategorizedSettings): Promise { 120 | // showing mapped & default settings 121 | const pickedItems = await vscode.window.showQuickPick( 122 | [...settings.mappedSettings.map((ms) => setting2QuickPickItem(ms.vscode, ms.sublime.name)), 123 | ...settings.defaultSettings.map((s) => setting2QuickPickItem(s))], { canPickMany: true, ignoreFocusOut: true }); 124 | // converting all selected entries to VscodeSettings 125 | return pickedItems ? pickedItems.map(pickItem => pickItem.setting instanceof MappedSetting ? pickItem.setting.vscode : pickItem.setting) : []; 126 | } 127 | 128 | function setting2QuickPickItem(setting: VscodeSetting, sublimeName?: string): ISettingsQuickPickItem { 129 | const icons = { exclamationPoint: '$(issue-opened)', arrowRight: '$(arrow-right)' }; // stored in var because auto-format adds spaces to hypens 130 | return { 131 | detail: setting.overwritesValue 132 | ? icons.exclamationPoint + ' ' + vscode.l10n.t(`Overwrites existing value: '{0}' with '{1}'`, setting.oldValue, setting.value) 133 | : '', 134 | label: sublimeName 135 | ? `${sublimeName} ${icons.arrowRight} ${setting.name}` 136 | : `${setting.name}: ${setting.value}`, 137 | picked: !setting.overwritesValue, 138 | setting, 139 | }; 140 | } 141 | 142 | async function importSettings(settings: ISetting[]): Promise { 143 | return vscode.window.withProgress({ 144 | location: vscode.ProgressLocation.Notification, 145 | title: vscode.l10n.t('Importing Settings'), 146 | }, async (progress) => { 147 | progress.report({ increment: 0 }); 148 | const incrementSize = 100.0 / settings.length; 149 | const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration(); 150 | for (const setting of settings) { 151 | try { 152 | await config.update(setting.name, setting.value, vscode.ConfigurationTarget.Global); 153 | progress.report({ increment: incrementSize, message: setting.name }); 154 | } catch (e: any) { 155 | vscode.window.showErrorMessage(e.message); 156 | return; 157 | } 158 | } 159 | }); 160 | } 161 | -------------------------------------------------------------------------------- /src/fsWrapper.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | 3 | export async function pathExists(stringPath: string): Promise { 4 | try { 5 | await fsAccess(stringPath, fs.constants.F_OK); 6 | return true; 7 | } catch (e) { 8 | return false; 9 | } 10 | } 11 | 12 | function fsAccess(stringPath: string, checks: number): Promise { 13 | return promisifier(fs.access, stringPath, checks); 14 | } 15 | 16 | // adapted from vs/base/common/async 17 | export function promisifier(fn: Function, ...args: any[]): Promise { 18 | return new Promise((c, e) => fn(...args, (err: any, result: any) => err ? e(err) : c(result))); 19 | } 20 | 21 | export async function readFileAsync(filePath: string, encoding?: string): Promise { 22 | return await promisifier(fs.readFile, filePath, encoding); 23 | } 24 | -------------------------------------------------------------------------------- /src/mapper.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import * as rjson from 'relaxed-json'; 3 | import * as vscode from 'vscode'; 4 | import { readFileAsync } from './fsWrapper'; 5 | import { ISetting, MappedSetting, CategorizedSettings, VscodeSetting } from './settings'; 6 | 7 | interface IConfigCheck { 8 | /** Key-Value pair already exists in user settings */ 9 | readonly alreadyExists: boolean; 10 | /** Setting already exists in user settings but with a different value */ 11 | readonly existingValue: string; 12 | } 13 | 14 | interface IMapperSettings { 15 | mappings: { [key: string]: any }; 16 | defaults: VscodeSetting[]; 17 | } 18 | export class Mapper { 19 | 20 | constructor(private settings?: IMapperSettings, private mockConfig?: any) { } 21 | 22 | public async getMappedSettings(sublimeSettings: string): Promise { 23 | const settingsMappings = await this.getSettings(); 24 | let parsedSublimeSettings; 25 | try { 26 | parsedSublimeSettings = rjson.parse(sublimeSettings); 27 | } catch (e) { 28 | vscode.window.showErrorMessage(vscode.l10n.t('The sublime settings file could not be parsed. Please check if it contains syntax errors.')); 29 | throw (e); 30 | } 31 | return this.mapAllSettings(settingsMappings, parsedSublimeSettings); 32 | } 33 | 34 | private async getSettings(): Promise { 35 | if (!this.settings) { 36 | // make sure set node: false in /build/node_extension.webpack.config.json so that __dirname is correct 37 | const [mappingsFile, defaultsFile] = await Promise.all([readFileAsync(resolve(__dirname, '..', 'settings/mappings.json'), 'utf-8'), 38 | readFileAsync(resolve(__dirname, '..', 'settings/defaults.json'), 'utf-8')]); 39 | this.settings = { 40 | mappings: rjson.parse(mappingsFile), 41 | defaults: (rjson.parse(defaultsFile) as [[string, any]]).map((setting) => new VscodeSetting(setting[0], setting[1])), 42 | }; 43 | } 44 | return this.settings; 45 | } 46 | 47 | private mapAllSettings(settings: IMapperSettings, sublimeSettings: { [key: string]: any }): CategorizedSettings { 48 | const analyzedSettings: CategorizedSettings = new CategorizedSettings(); 49 | const config = this.mockConfig || vscode.workspace.getConfiguration(); 50 | 51 | for (const sublimeKey of Object.keys(sublimeSettings)) { 52 | const sublimeSetting = { name: sublimeKey, value: sublimeSettings[sublimeKey] }; 53 | const vscodeSetting = this.mapSetting(sublimeSetting, settings.mappings[sublimeKey]); 54 | if (vscodeSetting) { 55 | const configTest = this.checkWithExistingSettings(vscodeSetting, config); 56 | const mappedSetting = new MappedSetting(sublimeSetting, vscodeSetting); 57 | 58 | if (configTest.alreadyExists) { 59 | analyzedSettings.alreadyExisting.push(mappedSetting); // setting with same key-value pair already exists 60 | } else { 61 | if (configTest.existingValue) { 62 | mappedSetting.vscode.markAsOverride(configTest.existingValue); // setting with same key but different value exists 63 | } 64 | analyzedSettings.mappedSettings.push(mappedSetting); 65 | } 66 | } else { 67 | analyzedSettings.noMappings.push(sublimeSetting); 68 | } 69 | } 70 | return this.appendDefaultSublimeSettings(analyzedSettings, settings.defaults, config); 71 | } 72 | 73 | private checkWithExistingSettings(vscodeSetting: VscodeSetting, config: vscode.WorkspaceConfiguration): IConfigCheck { 74 | const returnVal = { alreadyExists: false, existingValue: '' }; 75 | const info = config.inspect(vscodeSetting.name); 76 | if (info && info.globalValue !== undefined) { 77 | if (info.globalValue === vscodeSetting.value) { 78 | returnVal.alreadyExists = true; 79 | } else { 80 | returnVal.existingValue = returnVal.existingValue === null ? '' : String(info.globalValue); 81 | } 82 | } 83 | return returnVal; 84 | } 85 | 86 | private appendDefaultSublimeSettings(settings: CategorizedSettings, defaultSettings: VscodeSetting[], config: vscode.WorkspaceConfiguration): CategorizedSettings { 87 | const mappedAndExisting: MappedSetting[] = [...settings.mappedSettings, ...settings.alreadyExisting]; 88 | // filter out default settings that will be imported as mapped settings or already exist in the user settings 89 | const uniqueDefaultSettings = mappedAndExisting.length 90 | ? defaultSettings.filter(defaultSetting => !mappedAndExisting.find(mappedSetting => mappedSetting.vscode.name === defaultSetting.name)) 91 | : defaultSettings; 92 | 93 | // don't show settings that already exist in user config 94 | uniqueDefaultSettings.forEach(defaultSetting => { 95 | const configTest = this.checkWithExistingSettings(defaultSetting, config); 96 | 97 | if (configTest.alreadyExists) { 98 | settings.alreadyExisting.push(new MappedSetting({ name: vscode.l10n.t('Default Setting'), value: '' }, defaultSetting)); 99 | } else { 100 | if (configTest.existingValue) { 101 | defaultSetting.markAsOverride(configTest.existingValue); 102 | } 103 | settings.defaultSettings.push(defaultSetting); 104 | } 105 | }); 106 | 107 | settings.defaultSettings.sort((a, b) => { 108 | if (a.overwritesValue && b.overwritesValue) { 109 | return a.name.localeCompare(b.name); 110 | } else if (a.overwritesValue) { 111 | return 1; 112 | } else if (b.overwritesValue) { 113 | return -1; 114 | } 115 | return a.name.localeCompare(b.name); 116 | }); 117 | 118 | return settings; 119 | } 120 | 121 | private mapSetting(sublimeSetting: ISetting, mappedValue: any): VscodeSetting | undefined { 122 | if (mappedValue !== undefined) { 123 | if (typeof mappedValue === 'string') { 124 | return new VscodeSetting(mappedValue, sublimeSetting.value); 125 | } else if (typeof mappedValue === 'object') { 126 | const obj = mappedValue[sublimeSetting.value]; 127 | if (!obj) { 128 | vscode.window.showErrorMessage(vscode.l10n.t( 129 | { 130 | message: "Failed to parse setting: '{0}: {1}'. Please check if it contains syntax errors", 131 | args: [sublimeSetting.name, sublimeSetting.value], 132 | comment: ["{0} is the name of the setting, {1} is the value of the setting"] 133 | } 134 | )); 135 | return undefined; 136 | } 137 | const keys = Object.keys(obj); 138 | const newKey = keys[0]; 139 | const newValue = obj[newKey]; 140 | return new VscodeSetting(newKey, newValue); 141 | } 142 | } 143 | 144 | return undefined; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/settings.ts: -------------------------------------------------------------------------------- 1 | export interface ISetting { 2 | readonly name: string; 3 | readonly value: any; 4 | } 5 | 6 | export class VscodeSetting implements ISetting { 7 | public overwritesValue?: boolean; 8 | public oldValue?: any; 9 | 10 | constructor(public readonly name: string, public readonly value: any) { } 11 | 12 | public markAsOverride(oldValue: any): void { 13 | this.overwritesValue = true; 14 | this.oldValue = oldValue; 15 | } 16 | } 17 | 18 | export class MappedSetting { 19 | constructor(public readonly sublime: ISetting, public readonly vscode: VscodeSetting) {} 20 | } 21 | 22 | export class CategorizedSettings { 23 | public mappedSettings: MappedSetting[] = []; 24 | public alreadyExisting: MappedSetting[] = []; 25 | public noMappings: ISetting[] = []; 26 | public defaultSettings: VscodeSetting[] = []; // default sublime settings that are not in the mappings file but improve the sublime feel & look in VS Code 27 | } 28 | -------------------------------------------------------------------------------- /src/sublimeFolderFinder.ts: -------------------------------------------------------------------------------- 1 | import * as os from 'os'; 2 | import * as path from 'path'; 3 | import * as vscode from 'vscode'; 4 | import * as fileSystem from './fsWrapper'; 5 | 6 | export const sublimeSettingsFilename = 'Preferences.sublime-settings'; 7 | 8 | const defaultSublimeSettingsPaths: Map = new Map([ 9 | ['win32', [path.join(os.homedir(), 'AppData', 'Roaming', 'Sublime Text 3')]], 10 | ['darwin', [path.join(os.homedir(), 'Library', 'Application Support', 'Sublime Text 3')]], 11 | ['linux', [path.join(os.homedir(), '.config', 'sublime-text-3')]], 12 | ]); 13 | 14 | const settingsSubfoldersPath = path.join('Packages', 'User', 'Preferences.sublime-settings'); 15 | 16 | export async function getExistingDefaultPaths(): Promise { 17 | const foundPaths = await getOSDefaultPaths(); 18 | if (!foundPaths.length) { 19 | return undefined; 20 | } 21 | return filterForExistingDirsAsync(foundPaths); 22 | } 23 | 24 | export function getOSDefaultPaths(): string[] { 25 | const platform: NodeJS.Platform = os.platform(); 26 | const foundPaths: string[] | undefined = defaultSublimeSettingsPaths.get(platform); 27 | if (!foundPaths) { 28 | console.error('OS could not be identified. No default paths provided.'); 29 | return []; 30 | } 31 | return foundPaths; 32 | } 33 | 34 | export async function filterForExistingDirsAsync(paths: string[]): Promise { 35 | for (const p of paths) { 36 | const settingsPath: string = path.resolve(p, settingsSubfoldersPath); 37 | if (await fileSystem.pathExists(settingsPath)) { 38 | return vscode.Uri.file(settingsPath); 39 | } 40 | } 41 | 42 | return undefined; 43 | } 44 | -------------------------------------------------------------------------------- /src/test/runTests.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import { runTests } from 'vscode-test'; 3 | 4 | async function main() { 5 | try { 6 | // The folder containing the Extension Manifest package.json 7 | // Passed to `--extensionDevelopmentPath` 8 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 9 | 10 | // The path to the extension test script 11 | // Passed to --extensionTestsPath 12 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 13 | 14 | // Download VS Code, unzip it and run the integration test 15 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 16 | } catch (err) { 17 | console.error('Failed to run tests'); 18 | process.exit(1); 19 | } 20 | } 21 | 22 | main(); -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import { Mapper } from '../../mapper'; 3 | import { ISetting, MappedSetting, CategorizedSettings, VscodeSetting } from '../../settings'; 4 | import * as testData from './testData'; 5 | 6 | suite('Importer Tests', async () => { 7 | 8 | const expected = new Map([ 9 | ['numberSetting', new MappedSetting({ name: 'tab_size$test', value: 12 }, new VscodeSetting('editor.tabSize$test', 12))], 10 | ['stringSetting', new MappedSetting({ name: 'word_separators$test', value: "./\\()\"'-:,.;<>~!@#$%^&*|+=[]{}`~?" }, new VscodeSetting('editor.wordSeparators$test', "./\\()\"'-:,.;<>~!@#$%^&*|+=[]{}`~?"))], 11 | ['boolSetting', new MappedSetting({ name: 'ensure_newline_at_eof_on_save$test', value: false }, new VscodeSetting('files.insertFinalNewline$test', false))], 12 | ['complexSetting', new MappedSetting({ name: 'draw_white_space$test', value: 'boundary' }, new VscodeSetting('editor.renderWhitespace$test', 'boundary'))], 13 | ]); 14 | 15 | test('Import different types', async () => { 16 | const mapper: Mapper = new Mapper({ mappings: testData.testMappings, defaults: [] }); 17 | const settings: CategorizedSettings = await mapper.getMappedSettings(JSON.stringify(testData.sublimeSettings.mapped)); 18 | assert.ok(settings.mappedSettings.length === 4, `mappedSettings.length is ${settings.mappedSettings.length} instead of 4`); 19 | expected.forEach((expSetting) => { 20 | const setting = settings.mappedSettings.find(m => m.sublime.name === expSetting.sublime.name); 21 | if (!setting) { 22 | assert.fail(JSON.stringify(expSetting), 'Could not find mapped setting'); 23 | } else { 24 | assert.ok(setting.vscode.name === expSetting.vscode.name 25 | && setting.vscode.value === expSetting.vscode.value, 26 | `Setting ${setting.vscode.name}: ${setting.vscode.value} failed`); 27 | } 28 | }); 29 | }); 30 | 31 | const alreadyExistingVsSettings: ISetting[] = [ 32 | { name: 'editor.sameKeySameValue', value: testData.sublimeSettings.mappedSpecialCases.sameKeyVal.sameKeySameValue }, 33 | { name: 'editor.sameKeyDiffVal', value: testData.sublimeSettings.mappedSpecialCases.sameKeyDiffVal.sameKeyDiffVal + 'different' }, 34 | ]; 35 | 36 | test('Categorization of settings works', async () => { 37 | const mockConfig = { 38 | inspect: ((s: string) => { 39 | const foundSetting: ISetting | undefined = alreadyExistingVsSettings.find((setting) => setting.name === s); 40 | if (foundSetting) { 41 | return { globalValue: foundSetting.value }; 42 | } 43 | return undefined; 44 | }), 45 | }; 46 | 47 | const defaultSettings = [ 48 | new VscodeSetting(testData.testMappings.tab_size$test, 6), // already exists in sublime settings and should be removed 49 | new VscodeSetting('thisShouldStay', true), 50 | ]; 51 | 52 | const mapper: Mapper = new Mapper({ mappings: testData.testMappings, defaults: defaultSettings }, mockConfig); 53 | const sublimeSettings = JSON.stringify({ ...testData.sublimeSettings.mapped, ...testData.sublimeSettings.mappedSpecialCases.sameKeyDiffVal, ...testData.sublimeSettings.mappedSpecialCases.sameKeyVal, ...testData.sublimeSettings.noMapping }); 54 | const settings: CategorizedSettings = await mapper.getMappedSettings(sublimeSettings); 55 | 56 | assert.ok(settings.alreadyExisting.length === 1, 'settings.alreadyExisting.length === 1'); 57 | assert.ok(settings.noMappings.length === 1, 'settings.noMappings.length === 1'); 58 | assert.ok(settings.mappedSettings.filter(s => s.vscode.overwritesValue).length === 1, 'settings.mappedSettings.filter(s => s.vscode.overwritesValue).length === 1'); 59 | assert.ok(settings.defaultSettings.length === 1, 'settings.defaultSettings.length === 1'); 60 | assert.ok(settings.defaultSettings[0].name === 'thisShouldStay', "settings.defaultSettings[0].name === 'thisShouldStay'"); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /src/test/suite/testData.ts: -------------------------------------------------------------------------------- 1 | export const sublimeSettings = { 2 | mapped: { 3 | "tab_size$test": 12, 4 | "word_separators$test": "./\\()\"'-:,.;<>~!@#$%^&*|+=[]{}`~?", 5 | "ensure_newline_at_eof_on_save$test": false, 6 | "draw_white_space$test": "selection", 7 | }, 8 | mappedSpecialCases: { 9 | sameKeyVal: { "sameKeySameValue": true }, 10 | sameKeyDiffVal: { "sameKeyDiffVal": 'asdfjadfsla' }, 11 | }, 12 | noMapping: { "noMapping": 'someVal' }, 13 | }; 14 | 15 | export const testMappings = { 16 | "tab_size$test": "editor.tabSize$test", // Number 17 | "word_separators$test": "editor.wordSeparators$test", // String 18 | "ensure_newline_at_eof_on_save$test": "files.insertFinalNewline$test", // Boolean 19 | "draw_white_space$test": { 20 | "all": { 21 | "editor.renderWhitespace$test": "all" 22 | }, 23 | "none": { 24 | "editor.renderWhitespace$test": "none" 25 | }, 26 | "selection": { 27 | "editor.renderWhitespace$test": "boundary" 28 | }, 29 | }, 30 | "sameKeySameValue": "editor.sameKeySameValue", 31 | "sameKeyDiffVal": "editor.sameKeyDiffVal", 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /src/web/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | 4 | export async function activate(context: vscode.ExtensionContext): Promise { 5 | context.subscriptions.push(vscode.commands.registerCommand('extension.importFromSublime', () => { 6 | vscode.window.showWarningMessage(vscode.l10n.t('Importing from local Sublime settings is currently only possible when running in the desktop.'), { modal: true }) 7 | })); 8 | } 9 | -------------------------------------------------------------------------------- /sublime_keyboard_with_padding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-sublime-keybindings/5d7eac6603cf57b8a8f1b5cff6f63c1f59529111/sublime_keyboard_with_padding.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 5 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 6 | // "lib": [], /* Specify library files to be included in the compilation. */ 7 | "allowJs": false, /* Allow javascript files to be compiled. */ 8 | // "checkJs": true, /* Report errors in .js files. */ 9 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 10 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 11 | "sourceMap": true, /* Generates corresponding '.map' file. */ 12 | // "outFile": "./", /* Concatenate and emit output to single file. */ 13 | "outDir": "out", /* Redirect output structure to the directory. */ 14 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 15 | // "removeComments": true, /* Do not emit comments to output. */ 16 | // "noEmit": true, /* Do not emit outputs. */ 17 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 18 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 19 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 20 | 21 | /* Strict Type-Checking Options */ 22 | "strict": true, /* Enable all strict type-checking options. */ 23 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 24 | // "strictNullChecks": true, /* Enable strict null checks. */ 25 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 26 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 27 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 28 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 29 | 30 | /* Additional Checks */ 31 | "noUnusedLocals": true, /* Report errors on unused locals. */ 32 | "noUnusedParameters": true, /* Report errors on unused parameters. */ 33 | "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 34 | "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 35 | 36 | 37 | /* Module Resolution Options */ 38 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 39 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 40 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 41 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 42 | // "typeRoots": [], /* List of folders to include type definitions from. */ 43 | // "types": [], /* Type declaration files to be included in compilation. */ 44 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 45 | // "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 46 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 47 | 48 | /* Source Map Options */ 49 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 50 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ 51 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 52 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 53 | 54 | /* Experimental Options */ 55 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 56 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 57 | }, 58 | "include": [ 59 | "src" 60 | ] 61 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "warning", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "linterOptions": { 7 | "exclude": [ 8 | "test/testData.ts" 9 | ] 10 | }, 11 | "jsRules": {}, 12 | "rules": { 13 | "no-string-throw": true, 14 | "no-unused-expression": true, 15 | "no-duplicate-variable": true, 16 | "curly": true, 17 | "class-name": true, 18 | "arrow-parens": false, 19 | "max-classes-per-file": false, 20 | "object-literal-sort-keys": false, 21 | "ordered-imports": false, 22 | "typedef": [ 23 | true, 24 | "call-signature", 25 | "parameter", 26 | "member-variable-declaration" 27 | ], 28 | "max-line-length": [ 29 | false 30 | ], 31 | "no-console": [ 32 | true, 33 | "log" 34 | ], 35 | "semicolon": [ 36 | true, 37 | "always" 38 | ], 39 | "triple-equals": true, 40 | "quotemark": [ 41 | true, 42 | "single", 43 | "avoid-escape", 44 | "avoid-template" 45 | ] 46 | }, 47 | } --------------------------------------------------------------------------------