This commit is contained in:
Till Salinger 2018-04-15 19:05:51 +02:00
Родитель ddfb1effdd 7e8fdc7f9c
Коммит 37fdbd45e2
23 изменённых файлов: 3433 добавлений и 606 удалений

4
.github/assignment.yml поставляемый
Просмотреть файл

@ -1,4 +1,4 @@
{
perform: true,
assignees: [auchenberg]
}
assignees: [tsalinger]
}

Двоичные данные
.readme/demo.gif Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 11 MiB

8
.vscode/extensions.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,8 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
]
}

22
.vscode/launch.json поставляемый
Просмотреть файл

@ -10,7 +10,27 @@
"--extensionDevelopmentPath=${workspaceRoot}"
],
"stopOnEntry": false,
"sourceMaps": true
"sourceMaps": true,
"outFiles": [
"${workspaceRoot}/out/**/*.js"
],
"preLaunchTask": "npm: watch"
},
{
"name": "Extension Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceRoot}",
"--extensionTestsPath=${workspaceRoot}/out/test"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceRoot}/out/test/**/*.js"
],
"preLaunchTask": "npm: watch"
}
]
}

9
.vscode/settings.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,9 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false // set this to true to hide the "out" folder with the compiled JS files
},
"search.exclude": {
"out": true // set this to false to include "out" folder in search results
}
}

34
.vscode/tasks.json поставляемый
Просмотреть файл

@ -1,26 +1,20 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
"command": "npm",
"isShellCommand": true,
"showOutput": "always",
"suppressTaskName": true,
"version": "2.0.0",
"tasks": [
{
"taskName": "install",
"args": ["install"]
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"taskName": "update",
"args": ["update"]
},
{
"taskName": "test",
"args": ["run", "test"]
},
{
"taskName": "prelaunchTask"
}
]
}

Просмотреть файл

@ -16,3 +16,4 @@
## 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)).
## 1.0.0 - Initial migration.
## 1.0.0 - Initial.

Просмотреть файл

@ -67,6 +67,14 @@ We may have missed a keyboard shortcut. If we did please help us out! It is very
You can read more about how to contribute keybindings in extensions in the [official documentation](http://code.visualstudio.com/docs/extensionAPI/extension-points#_contributeskeybindings).
# Sublime Importer for VS Code
This extension imports settings and snippets from Sublime Text to VS Code.
![](.readme/demo.gif)
## Getting started
1. [Click here to install extension](https://marketplace.visualstudio.com/items?itemName=auchenberg.vscode-sublime-importer#overview)
2. Run `Import Sublime Text settings` command from Command Palette
## License
[MIT](license.txt)

Просмотреть файл

@ -1,95 +0,0 @@
const vscode = require('vscode');
const showInformationMessage = vscode.window.showInformationMessage;
const isGlobalConfigValue = true;
class Setting {
constructor(name, value) {
this.name = name;
this.value = value;
}
}
const versionThreeSettings = [
new Setting('multiCursorModifier', 'ctrlCmd'),
new Setting('snippetSuggestions', 'top'),
new Setting('formatOnPaste', true)
];
function updateSettings(editorConfig, settings) {
settings.forEach((setting) => {
editorConfig.update(setting.name, setting.value, isGlobalConfigValue);
});
}
function isDefaultValueSet(editorConfig, settings) {
for (var i = 0; i < settings.length; i++) {
var setting = editorConfig.inspect(settings[i].name);
const dv = setting ? setting.defaultValue : null;
const gv = setting ? setting.globalValue : null;
if (gv === dv || gv === undefined) {
return true;
}
}
return false;
}
class VersionThreeUpdateSetting {
constructor() {
this.name = 'promptV3Features';
this.config = vscode.workspace.getConfiguration('sublimeTextKeymap');
this.hasPrompted = this.config.get(this.name) || false;
}
persist() {
this.config.update(this.name, true, isGlobalConfigValue);
}
}
class View {
constructor(updateSetting, editorConfig) {
this.updateSetting = updateSetting;
this.editorConfig = editorConfig;
this.messages = {
yes: 'Yes',
no: 'No',
learnMore: 'Learn More',
prompt: 'New features are available for Sublime Text Keymap 3.0. Do you want to enable the new features?',
noChange: 'Sublime Text Keymap: New features have not been enable.',
change: 'Sublime Text Keymap: New features have been added.',
};
}
showMessage() {
const answer = showInformationMessage(this.messages.prompt, this.messages.yes, this.messages.no, this.messages.learnMore);
answer.then((selectedOption) => {
if (selectedOption === this.messages.yes) {
this.updateSetting.persist();
updateSettings(this.editorConfig, versionThreeSettings);
showInformationMessage(this.messages.change);
} else if (selectedOption === this.messages.no) {
this.updateSetting.persist();
showInformationMessage(this.messages.noChange);
} else if (selectedOption === this.messages.learnMore) {
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse('https://marketplace.visualstudio.com/items?itemName=ms-vscode.sublime-keybindings'));
}
});
}
}
const activate = () => {
const editorConfig = vscode.workspace.getConfiguration('editor');
const updateSetting = new VersionThreeUpdateSetting();
if (!updateSetting.hasPrompted && isDefaultValueSet(editorConfig, versionThreeSettings)) {
new View(updateSetting, editorConfig).showMessage();
}
}
module.exports = { activate };

Двоичные данные
icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

115
mappings/settings.json Normal file
Просмотреть файл

@ -0,0 +1,115 @@
{
"scroll_speed": "editor.mouseWheelScrollSensitivity", // Number
"hot_exit": {
"true": {
"files.hotExit": "onExit"
},
"false": {
"files.hotExit": "off"
}
},
"remember_open_files": {
"true": {
"window.restoreWindows": "all"
},
"false": {
"window.restoreWindows": "off"
}
},
"open_files_in_new_window": {
"true": {
"window.openFilesInNewWindow": "on"
},
"false": {
"window.openFilesInNewWindow": "off"
}
},
"close_windows_when_empty": "window.closeWhenEmpty", // Boolean
"show_full_path": {
"true": {
"window.title": "${activeEditorFull}${separator}${rootName}"
},
"false": {
"window.title": "${activeEditorShort}${separator}${rootName}"
}
},
"preview_on_click": "workbench.editor.enablePreview", // Boolean
"show_tab_close_buttons": {
"false": {
"workbench.editor.tabCloseButton": "off"
}
},
"save_on_focus_lost": {
"true": {
"files.autoSave": "onFocusChange"
},
"false": {
"files.autoSave": "off"
}
},
"find_selected_text": "editor.find.seedSearchStringFromSelection", // Boolean
"word_separators": "editor.wordSeparators", // String
"ensure_newline_at_eof_on_save": "files.insertFinalNewline", // Boolean
"auto_indent": "editor.autoIndent", // Boolean
"tab_size": "editor.tabSize", // Number
"use_tab_stops": "editor.useTabStops", // Boolean
"trim_automatic_white_space": "editor.trimAutoWhitespace", // Boolean
"detect_indentation": "editor.detectIndentation", // Boolean
"draw_white_space": {
"all": {
"editor.renderWhitespace": "all"
},
"none": {
"editor.renderWhitespace": "none"
},
"selection": {
"editor.renderWhitespace": "boundary"
}
},
"trim_trailing_white_space_on_save": "files.trimTrailingWhitespace", // Boolean
"tab_completion": "editor.tabCompletion", // Boolean
"auto_complete_delay": "editor.quickSuggestionsDelay", // Number
"auto_complete_commit_on_tab": {
"true" : {
"editor.acceptSuggestionOnEnter": "off"
}
},
"copy_with_empty_selection": "editor.emptySelectionClipboard ", // Boolean
"auto_find_in_selection": "editor.find.autoFindInSelection", // Boolean
"drag_text": "editor.dragAndDrop", // Boolean
"default_encoding": "files.encoding", // String
"font_face": "editor.fontFamily", // String
"font_size": "editor.fontSize", // Number
"line_numbers": {
"true": {
"editor.lineNumbers": "on"
},
"false": {
"editor.lineNumbers": "off"
}
},
"fade_fold_buttons": {
"true": {
"editor.showFoldingControls": "mouseover"
}
},
"scroll_past_end": "editor.scrollBeyondLastLine", // Boolean
"word_wrap": "editor.wordWrap", // String
"indent_subsequent_lines": {
"yes": {
"editor.wrappingIndent": "none"
}
},
"match_brackets": "editor.matchBrackets", // Boolean
"match_selection": "editor.selectionHighlight", // Boolean
"draw_indent_guides": "editor.renderIndentGuides", // Boolean
"remember_full_screen": "window.restoreFullscreen" // Boolean,
// "folder_exclude_patterns": "files.exclude",
// "file_exclude_patterns": "files.exclude",
// "color_scheme": "workbench.colorTheme",
// "wrap_width": "editor.wordWrapColumn",
// "rulers": "editor.rulers",
// "caret_style": "editor.cursorBlinking",
// "auto_complete": "editor.quickSuggestions",
// "find_selected_text": "autoFindInSelection", // Boolean
}

2665
package-lock.json сгенерированный Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,22 +1,26 @@
{
"name": "sublime-keybindings",
"displayName": "Sublime Text Keymap",
"description": "Popular Sublime Text keybindings for VS Code.",
"version": "3.0.3",
"displayName": "Sublime Text Keymap and settings importer",
"description": "Import Sublime Text settings and keybindings into VS Code.",
"version": "3.0.4",
"publisher": "ms-vscode",
"engines": {
"vscode": "^1.18.0"
"vscode": "^1.22.0"
},
"categories": [
"Keymaps"
],
"keywords": [
"keymap"
"keymap",
"Importer",
"Settings",
"Sublime Text"
],
"activationEvents": [
"*"
"*",
"onCommand:extension.importFromSublime"
],
"main": "./extension",
"main": "./out/extension",
"preview": false,
"icon": "sublime_keyboard_with_padding.png",
"repository": {
@ -27,491 +31,58 @@
"url": "https://github.com/Microsoft/vscode-sublime-keybindings/issues"
},
"contributes": {
"keybindings": [
"commands": [
{
"mac": "ctrl+shift+cmd+f",
"win": "shift+f11",
"linux": "shift+f11",
"key": "shift+f11",
"command": "workbench.action.toggleZenMode"
},
{
"mac": "cmd+w",
"win": "ctrl+w",
"linux": "ctrl+w",
"key": "ctrl+w",
"command": "workbench.action.closeActiveEditor"
},
{
"mac": "shift+cmd+[",
"key": "ctrl+pageup",
"command": "workbench.action.previousEditor"
},
{
"mac": "shift+cmd+]",
"key": "ctrl+pagedown",
"command": "workbench.action.nextEditor"
},
{
"mac": "alt+cmd+s",
"key": "none",
"command": "workbench.action.files.saveAll"
},
{
"mac": "cmd+k cmd+b",
"win": "ctrl+k ctrl+b",
"linux": "ctrl+k ctrl+b",
"key": "ctrl+k ctrl+b",
"command": "workbench.action.toggleSidebarVisibility"
},
{
"mac": "ctrl+alt+up",
"key": "ctrl+up",
"command": "scrollLineUp",
"when": "editorTextFocus"
},
{
"mac": "ctrl+alt+down",
"key": "ctrl+down",
"command": "scrollLineDown",
"when": "editorTextFocus"
},
{
"mac": "cmd+t",
"key": "ctrl+p",
"command": "workbench.action.quickOpen"
},
{
"mac": "cmd+r",
"win": "ctrl+r",
"linux": "ctrl+r",
"key": "ctrl+r",
"command": "workbench.action.gotoSymbol"
},
{
"mac": "cmd+r",
"win": "ctrl+;",
"linux": "ctrl+;",
"key": "ctrl+;",
"command": "workbench.action.gotoSymbol"
},
{
"mac": "cmd+alt+down",
"key": "f12",
"command": "editor.action.goToDeclaration"
},
{
"win": "alt+-",
"linux": "alt+-",
"key": "ctrl+-",
"command": "workbench.action.navigateBack"
},
{
"win": "alt+shift+-",
"linux": "alt+shift+-",
"key": "ctrl+shift+-",
"command": "workbench.action.navigateForward"
},
{
"mac": "cmd+g",
"win": "f3",
"linux": "f3",
"key": "f3",
"command": "editor.action.nextMatchFindAction",
"when": "editorTextFocus"
},
{
"mac": "f4",
"win": "f4",
"linux": "f4",
"key": "f4",
"command": "editor.action.nextMatchFindAction",
"when": "editorTextFocus"
},
{
"mac": "shift+f4",
"win": "shift+f4",
"linux": "shift+f4",
"key": "shift+f4",
"command": "editor.action.previousMatchFindAction",
"when": "editorTextFocus"
},
{
"mac": "ctrl+cmd+up",
"win": "ctrl+shift+up",
"linux": "ctrl+shift+up",
"key": "ctrl+shift+up",
"command": "editor.action.moveLinesUpAction",
"when": "editorTextFocus"
},
{
"mac": "ctrl+cmd+down",
"win": "ctrl+shift+down",
"linux": "ctrl+shift+down",
"key": "ctrl+shift+down",
"command": "editor.action.moveLinesDownAction",
"when": "editorTextFocus"
},
{
"mac": "cmd+alt+/",
"win": "ctrl+shift+/",
"linux": "ctrl+shift+/",
"key": "ctrl+shift+/",
"command": "editor.action.commentLine",
"when": "editorTextFocus"
},
{
"mac": "cmd+k cmd+up",
"win": "ctrl+k ctrl+up",
"linux": "ctrl+k ctrl+up",
"key": "ctrl+k ctrl+up",
"command": "workbench.action.splitEditor"
},
{
"mac": "alt+cmd+2",
"win": "alt+shift+2",
"linux": "alt+shift+2",
"key": "alt+shift+2",
"command": "workbench.action.splitEditor"
},
{
"mac": "cmd+k cmd+down",
"win": "ctrl+k ctrl+down",
"linux": "ctrl+k ctrl+down",
"key": "ctrl+k ctrl+down",
"command": "workbench.action.closeActiveEditor"
},
{
"mac": "alt+cmd+[",
"key": "ctr+shift+[",
"command": "editor.fold",
"when": "editorFocus"
},
{
"mac": "cmd+alt+]",
"key": "ctrl+shift+]",
"command": "editor.unfold",
"when": "editorFocus"
},
{
"mac": "cmd+k cmd+0",
"win": "ctrl+k ctrl+0",
"linux": "ctrl+k ctrl+0",
"key": "ctrl+k ctrl+0",
"command": "editor.unfoldAll",
"when": "editorFocus"
},
{
"mac": "alt+f12",
"key": "alt+f12",
"command": "editor.action.showContextMenu",
"when": "editorTextFocus"
},
{
"mac": "cmd+shift+d",
"win": "ctrl+shift+d",
"linux": "ctrl+shift+d",
"key": "ctrl+shift+d",
"command": "editor.action.copyLinesDownAction",
"when": "editorFocus"
},
{
"mac": "cmd+l",
"win": "ctrl+l",
"linux": "ctrl+l",
"key": "ctrl+l",
"command": "expandLineSelection",
"when": "editorFocus"
},
{
"mac": "cmd+d",
"win": "ctrl+d",
"linux": "ctrl+d",
"key": "ctrl+d",
"command": "editor.action.addSelectionToNextFindMatch",
"when": "editorFocus"
},
{
"mac": "ctrl+m",
"win": "ctrl+m",
"linux": "ctrl+m",
"key": "ctrl+m",
"command": "editor.action.jumpToBracket",
"when": "editorFocus"
},
{
"mac": "cmd+alt+/",
"win": "ctrl+shift+/",
"linux": "ctrl+shift+/",
"key": "ctrl+shift+/",
"command": "editor.action.blockComment",
"when": "editorFocus"
},
{
"mac": "cmd+alt+f",
"win": "ctrl+h",
"linux": "ctrl+h",
"key": "ctrl+h",
"command": "editor.action.startFindReplaceAction"
},
{
"mac": "ctrl+shift+k",
"win": "ctrl+shift+k",
"linux": "ctrl+shift+k",
"key": "ctrl+shift+k",
"command": "editor.action.deleteLines",
"when": "editorFocus"
},
{
"mac": "ctrl+shift+up",
"win": "alt+shift+up",
"linux": "alt+shift+up",
"key": "alt+shift+up",
"command": "editor.action.insertCursorAbove",
"when": "editorTextFocus"
},
{
"mac": "ctrl+shift+down",
"win": "alt+shift+down",
"linux": "alt+shift+down",
"key": "alt+shift+down",
"command": "editor.action.insertCursorBelow",
"when": "editorTextFocus"
},
{
"mac": "ctrl+shift+pageup",
"win": "alt+shift+pageup",
"linux": "alt+shift+pageup",
"key": "alt+shift+pageup",
"command": "cursorColumnSelectPageUp",
"when": "editorTextFocus"
},
{
"mac": "ctrl+shift+pagedown",
"win": "alt+shift+pagedown",
"linux": "alt+shift+pagedown",
"key": "alt+shift+pagedown",
"command": "cursorColumnSelectPageDown",
"when": "editorTextFocus"
},
{
"mac": "cmd+shift+l",
"win": "ctrl+shift+l",
"linux": "ctrl+shift+l",
"key": "ctrl+shift+l",
"command": "editor.action.insertCursorAtEndOfEachLineSelected",
"when": "editorTextFocus"
},
{
"mac": "cmd+1",
"win": "alt+1",
"linux": "alt+1",
"key": "alt+1",
"command": "workbench.action.openEditorAtIndex1"
},
{
"mac": "cmd+2",
"win": "alt+2",
"linux": "alt+2",
"key": "alt+2",
"command": "workbench.action.openEditorAtIndex2"
},
{
"mac": "cmd+3",
"win": "alt+3",
"linux": "alt+3",
"key": "alt+3",
"command": "workbench.action.openEditorAtIndex3"
},
{
"mac": "cmd+4",
"win": "alt+4",
"linux": "alt+4",
"key": "alt+4",
"command": "workbench.action.openEditorAtIndex4"
},
{
"mac": "cmd+5",
"win": "alt+5",
"linux": "alt+5",
"key": "alt+5",
"command": "workbench.action.openEditorAtIndex5"
},
{
"mac": "cmd+6",
"win": "alt+6",
"linux": "alt+6",
"key": "alt+6",
"command": "workbench.action.openEditorAtIndex6"
},
{
"mac": "cmd+7",
"win": "alt+7",
"linux": "alt+7",
"key": "alt+7",
"command": "workbench.action.openEditorAtIndex7"
},
{
"mac": "cmd+8",
"win": "alt+8",
"linux": "alt+8",
"key": "alt+8",
"command": "workbench.action.openEditorAtIndex8"
},
{
"mac": "cmd+9",
"win": "alt+9",
"linux": "alt+9",
"key": "alt+9",
"command": "workbench.action.openEditorAtIndex9"
},
{
"mac": "cmd+ctrl+g",
"win": "alt+f3",
"linux": "alt+f3",
"key": "alt+f3",
"command": "editor.action.selectHighlights",
"when": "editorFocus"
},
{
"mac": "cmd+shift+r",
"win": "ctrl+shift+r",
"linux": "ctrl+shift+r",
"key": "ctrl+shift+r",
"command": "workbench.action.showAllSymbols"
},
{
"mac": "ctrl+alt+left",
"win": "alt+left",
"linux": "ctrl+alt+left",
"key": "ctrl+alt+left",
"command": "cursorWordStartLeft",
"when": "editorTextFocus"
},
{
"mac": "ctrl+alt+right",
"win": "alt+right",
"linux": "ctrl+alt+right",
"key": "ctrl+alt+right",
"command": "cursorWordEndRight",
"when": "editorTextFocus"
},
{
"mac": "ctrl+alt+shift+left",
"win": "alt+shift+left",
"linux": "ctrl+alt+shift+left",
"key": "ctrl+alt+shift+left",
"command": "cursorWordStartLeftSelect",
"when": "editorTextFocus"
},
{
"mac": "ctrl+alt+shift+right",
"win": "alt+shift+right",
"linux": "ctrl+alt+shift+right",
"key": "ctrl+alt+shift+right",
"command": "cursorWordEndRightSelect",
"when": "editorTextFocus"
},
{
"mac": "cmd+j",
"key": "ctrl+j",
"command": "editor.action.joinLines",
"when": "editorTextFocus"
},
{
"mac": "cmd+k cmd+u",
"key": "ctrl+k ctrl+u",
"command": "editor.action.transformToUppercase",
"when": "editorTextFocus"
},
{
"mac": "cmd+k cmd+l",
"key": "ctrl+k ctrl+l",
"command": "editor.action.transformToLowercase",
"when": "editorTextFocus"
},
{
"mac": "cmd+k a",
"key": "ctrl+k a",
"command": "workbench.action.showErrorsWarnings"
},
{
"mac": "cmd+k n",
"key": "ctrl+k n",
"command": "editor.action.marker.next",
"when": "editorFocus"
},
{
"mac": "cmd+k p",
"key": "ctrl+k p",
"command": "editor.action.marker.prev",
"when": "editorFocus"
},
{
"mac": "ctrl+1",
"win": "ctrl+1",
"linux": "ctrl+1",
"key": "ctrl+1",
"command": "workbench.action.focusFirstEditorGroup",
"when": "editorFocus"
},
{
"mac": "ctrl+2",
"win": "ctrl+2",
"linux": "ctrl+2",
"key": "ctrl+2",
"command": "workbench.action.focusSecondEditorGroup",
"when": "editorFocus"
},
{
"mac": "ctrl+3",
"win": "ctrl+3",
"linux": "ctrl+3",
"key": "ctrl+3",
"command": "workbench.action.focusThirdEditorGroup",
"when": "editorFocus"
},
{
"mac": "cmd+p",
"win": "ctrl+p",
"linux": "ctrl+p",
"key": "ctrl+p",
"command": "workbench.action.quickOpenPreviousEditor"
},
{
"mac": "cmd+k cmd+k",
"win": "ctrl+k ctrl+k",
"linux": "ctrl+k ctrl+k",
"command": "deleteAllRight",
"key": "ctrl+k ctrl+k",
"when": "editorTextFocus && !editorReadonly"
},
{
"mac": "cmd+shift+space",
"win": "ctrl+shift+space",
"linux": "ctrl+shift+space",
"command": "editor.action.smartSelect.grow",
"key": "ctrl+shift+space",
"when": "editorTextFocus"
"command": "extension.importFromSublime",
"title": "Import Sublime Text settings"
}
],
"configuration": {
"type": "object",
"title": "Sublime Text Keymap configuration",
"properties": {
"sublimeTextKeymap.promptV3Features": {
"type": ["boolean", "null"],
"default": null,
"description": "Status of Sublime Text Keymap version three features added."
"configuration": [
{
"type": "object",
"title": "Sublime Text Keymap configuration",
"properties": {
"sublimeTextKeymap.promptV3Features": {
"type": [
"boolean",
"null"
],
"default": null,
"description": "Status of Sublime Text Keymap version three features added."
}
}
},
{
"type": "object",
"title": "Sublime Text Importer configuration",
"properties": {
"sublimeImporter.hasPromptedOnStartup": {
"type": [
"boolean",
"null"
],
"default": null,
"description": "Status of Sublime Text Importer startup prompt."
}
}
}
],
"scripts": {
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "npm run compile && node ./node_modules/vscode/bin/test",
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./"
},
"devDependencies": {
"@types/mocha": "^2.2.42",
"@types/node": "^7.0.43",
"@types/relaxed-json": "^1.0.0",
"typescript": "^2.0.3",
"vscode": "^1.1.14"
},
"dependencies": {
"relaxed-json": "^1.0.1"
}
},
"scripts": {
"postinstall": "node ./node_modules/vscode/bin/install"
},
"devDependencies": {
"vscode": "^1.0.3",
"typescript": "^2.0.3"
}
}
}

121
src/extension.ts Normal file
Просмотреть файл

@ -0,0 +1,121 @@
import * as vscode from 'vscode';
import { readFileAsync } from './fsWrapper';
import { AnalyzedSettings, Mapper } from './mapper';
import { ISetting, MappedSetting } from './settings';
import * as sublimeFolderFinder from './sublimeFolderFinder';
import * as path from 'path';
const mapper = new Mapper();
export async function activate(context: vscode.ExtensionContext): Promise<void> {
context.subscriptions.push(vscode.commands.registerCommand('extension.importFromSublime', () => importSettingsFromSublime()));
}
async function importSettingsFromSublime(): Promise<void> {
const analyzedSettings = await getAnalyzedSettings();
if (analyzedSettings) {
if (analyzedSettings.mappedSettings.length) {
const mappedSettings = await selectSettingsToImport(analyzedSettings);
if (mappedSettings && mappedSettings.length) {
await importSelectedSettings(mappedSettings);
}
} else {
vscode.window.showInformationMessage('All settings imported.');
}
}
}
async function getAnalyzedSettings(): Promise<AnalyzedSettings | null> {
const settingsPath = await getSublimeFolderPath();
if (settingsPath) {
return getSettings(settingsPath);
}
return null;
}
async function getSublimeFolderPath(): Promise<string | undefined> {
const sublimeSettingsPath = await sublimeFolderFinder.getExistingDefaultPaths();
if (sublimeSettingsPath) {
return sublimeSettingsPath.fsPath;
}
return await browsePrompt(`No Sublime settings file found at the default location: ${path.join(sublimeFolderFinder.getOSDefaultPaths()[0], sublimeFolderFinder.sublimeSettingsFilename)}`);
}
async function browsePrompt(msg: string): Promise<string | undefined> {
const result = await vscode.window.showInformationMessage(msg, 'Browse...');
if (result) {
const sublimeSettingsFiles = await vscode.window.showOpenDialog({ canSelectFiles: true });
if (sublimeSettingsFiles && sublimeSettingsFiles.length) {
const filePath = sublimeSettingsFiles[0].fsPath;
const isValidFilePath = await validate(filePath);
if (isValidFilePath) {
return filePath;
} else {
vscode.window.showErrorMessage(`Could not find ${sublimeFolderFinder.sublimeSettingsFilename} at ${sublimeSettingsFiles[0].fsPath}`);
}
}
}
return undefined;
}
function validate(settingsFilePath: string): boolean {
return settingsFilePath.endsWith(sublimeFolderFinder.sublimeSettingsFilename);
}
async function getSettings(sublimeSettingsPath: string): Promise<AnalyzedSettings> {
const settings: AnalyzedSettings | undefined = await mapper.getMappedSettings(await readFileAsync(sublimeSettingsPath, 'utf-8'));
settings.mappedSettings.sort((a, b) => {
if (a.isDuplicate && b.isDuplicate) {
return a.sublime.name.localeCompare(b.sublime.name);
} else if (a.isDuplicate) {
return -1;
} else if (b.isDuplicate) {
return 1;
}
return a.sublime.name.localeCompare(b.sublime.name);
});
return settings;
}
async function selectSettingsToImport(settings: AnalyzedSettings): Promise<MappedSetting[]> {
const pickedSettingNames: vscode.QuickPickItem[] | undefined = await vscode.window.showQuickPick(settings.mappedSettings
.map(setting2QuickPickItem), { canPickMany: true });
if (pickedSettingNames) {
return pickedSettingNames
.map(name => settings.mappedSettings
.find(setting => setting2QuickPickItem(setting).label === name.label)) as MappedSetting[];
}
return [];
}
function setting2QuickPickItem(setting: MappedSetting): vscode.QuickPickItem {
return {
detail: setting.isDuplicate
? `$(issue-opened) Overwrites existing value: ${setting.duplicateVscodeSetting && setting.duplicateVscodeSetting.value}`
: '',
label: `${setting.sublime.name} $(arrow-right) ${setting.vscode.name}`,
picked: !setting.isDuplicate,
};
}
async function importSelectedSettings(selectedSettings: MappedSetting[]): Promise<void> {
await importSettings(selectedSettings.map(selSettings => selSettings.vscode));
await vscode.commands.executeCommand('workbench.action.openGlobalSettings');
}
async function importSettings(settings: ISetting[]): Promise<void> {
return vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Importing Settings',
}, async (progress) => {
progress.report({ increment: 0 });
const incrementSize = 100.0 / settings.length;
const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration();
await Promise.all(settings.map(async setting => {
// workaround for https://github.com/Microsoft/vscode/issues/47730
return config.update(setting.name, 'bug-workaround-47730', vscode.ConfigurationTarget.Global)
.then(() => config.update(setting.name, setting.value, vscode.ConfigurationTarget.Global))
.then(() => progress.report({ increment: incrementSize, message: setting.name }));
}));
});
}

23
src/fsWrapper.ts Normal file
Просмотреть файл

@ -0,0 +1,23 @@
import * as fs from 'fs';
export async function pathExists(stringPath: string): Promise<boolean> {
try {
await fsAccess(stringPath, fs.constants.F_OK);
return true;
} catch (e) {
return false;
}
}
function fsAccess(stringPath: string, checks: number): Promise<any> {
return promisifier(fs.access, stringPath, checks);
}
// adapted from vs/base/common/async
export function promisifier<T>(fn: Function, ...args: any[]): Promise<T> {
return new Promise((c, e) => fn(...args, (err: any, result: any) => err ? e(err) : c(result)));
}
export async function readFileAsync(filePath: string, encoding?: string): Promise<string> {
return await promisifier<string>(fs.readFile, filePath, encoding);
}

80
src/mapper.ts Normal file
Просмотреть файл

@ -0,0 +1,80 @@
import { resolve } from 'path';
import * as rjson from 'relaxed-json';
import * as vscode from 'vscode';
import { readFileAsync } from './fsWrapper';
import { ISetting, MappedSetting } from './settings';
export class AnalyzedSettings {
public mappedSettings: MappedSetting[] = [];
public alreadyExisting: MappedSetting[] = [];
public noMappings: ISetting[] = [];
}
export class Mapper {
private settingsMappings: Promise<{}> | undefined = undefined;
constructor(settingsMappings?: Promise<{}>, private mockConfig?: any) {
this.settingsMappings = settingsMappings;
}
public async getMappedSettings(sublimeSettings: string): Promise<AnalyzedSettings> {
const settingsMappings = await this.getSettingsMappings();
return this.mapAllSettings(settingsMappings, rjson.parse(sublimeSettings));
}
private async getSettingsMappings(): Promise<{}> {
if (!this.settingsMappings) {
this.settingsMappings = readFileAsync(resolve(__dirname, '..', 'mappings/settings.json'), 'utf-8').then(rjson.parse);
}
return this.settingsMappings;
}
private mapAllSettings(mappedSettings: { [key: string]: any }, sublimeSettings: { [key: string]: any }): AnalyzedSettings {
const analyzedSettings: AnalyzedSettings = new AnalyzedSettings();
const config = this.mockConfig || vscode.workspace.getConfiguration();
for (const key of Object.keys(sublimeSettings)) {
const value = sublimeSettings[key];
const vscodeMapping = this.mapSetting(key, value, mappedSettings[key]);
if (vscodeMapping) {
const mappedSetting: MappedSetting = new MappedSetting({ name: key, value });
mappedSetting.setVscode(vscodeMapping);
const info = config.inspect(vscodeMapping.name);
if (info && info.globalValue !== undefined) {
if (info.globalValue === vscodeMapping.value) {
analyzedSettings.alreadyExisting.push(mappedSetting);
continue;
}
mappedSetting.markAsDuplicate({ name: vscodeMapping.name, value: info.globalValue.toString() });
}
analyzedSettings.mappedSettings.push(mappedSetting);
} else {
analyzedSettings.noMappings.push({ name: key, value });
}
}
return analyzedSettings;
}
private mapSetting(key: string, value: string, mappedValue: any): ISetting | undefined {
if (mappedValue !== undefined) {
if (typeof mappedValue === 'string') {
return { name: mappedValue, value };
} else if (typeof mappedValue === 'object') {
const obj = mappedValue[value];
if (!obj) {
vscode.window.showErrorMessage(`mapSetting() failed on key: ${key}, value: ${value}, mappedSetting: ${JSON.stringify(mappedValue)}`);
return undefined;
}
const keys = Object.keys(obj);
const newKey = keys[0];
const newValue = obj[newKey];
return { name: newKey, value: newValue };
}
}
return undefined;
}
}

33
src/settings.ts Normal file
Просмотреть файл

@ -0,0 +1,33 @@
export interface ISetting {
readonly name: string;
readonly value: any;
}
export class MappedSetting {
public static hasNoMatch(setting: MappedSetting): boolean {
if (setting && setting.vscode) {
return setting.vscode.name === MappedSetting.NO_MATCH;
}
return true;
}
private static readonly NO_MATCH: string = '--No Match--';
public sublime: ISetting;
public vscode: ISetting;
public isDuplicate: boolean = false;
public duplicateVscodeSetting?: ISetting;
constructor(sublimeSetting: ISetting, vscodeSetting?: ISetting) {
this.sublime = sublimeSetting;
this.vscode = vscodeSetting || {name: MappedSetting.NO_MATCH, value: MappedSetting.NO_MATCH};
}
public setVscode(setting: ISetting): void {
this.vscode = setting;
}
public markAsDuplicate(vscodeSetting: ISetting): void {
this.isDuplicate = true;
this.duplicateVscodeSetting = vscodeSetting;
}
}

Просмотреть файл

@ -0,0 +1,43 @@
import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import * as fileSystem from './fsWrapper';
export const sublimeSettingsFilename = 'Preferences.sublime-settings';
const defaultSublimeSettingsPaths: Map<string, string[]> = new Map([
['win32', [path.join(os.homedir(), 'AppData', 'Roaming', 'Sublime Text 3')]],
['darwin', [path.join(os.homedir(), 'Library', 'Application Support', 'Sublime Text 3')]],
['linux', [path.join(os.homedir(), '.config', 'sublime-text-3')]],
]);
const settingsSubfoldersPath = path.join('Packages', 'User', 'Preferences.sublime-settings');
export async function getExistingDefaultPaths(): Promise<vscode.Uri | undefined> {
const foundPaths = await getOSDefaultPaths();
if (!foundPaths.length) {
return undefined;
}
return filterForExistingDirsAsync(foundPaths);
}
export function getOSDefaultPaths(): string[] {
const platform: NodeJS.Platform = os.platform();
const foundPaths: string[] | undefined = defaultSublimeSettingsPaths.get(platform);
if (!foundPaths) {
console.error('OS could not be identified. No default paths provided.');
return [];
}
return foundPaths;
}
export async function filterForExistingDirsAsync(paths: string[]): Promise<vscode.Uri | undefined> {
for (const p of paths) {
const settingsPath: string = path.resolve(p, settingsSubfoldersPath);
if (await fileSystem.pathExists(settingsPath)) {
return vscode.Uri.file(settingsPath);
}
}
return undefined;
}

Просмотреть файл

@ -0,0 +1,76 @@
import * as assert from 'assert';
import { AnalyzedSettings, Mapper } from '../mapper';
import { ISetting, MappedSetting } from '../settings';
import * as testData from './testData';
import * as vscode from 'vscode';
suite('Importer Tests', async () => {
const expected = new Map<string, MappedSetting>([
['numberSetting', new MappedSetting({ name: 'tab_size$test', value: 12 }, { name: 'editor.tabSize$test', value: 12 })],
['stringSetting', new MappedSetting({ name: 'word_separators$test', value: "./\\()\"'-:,.;<>~!@#$%^&*|+=[]{}`~?" }, { name: 'editor.wordSeparators$test', value: "./\\()\"'-:,.;<>~!@#$%^&*|+=[]{}`~?" })],
['boolSetting', new MappedSetting({ name: 'ensure_newline_at_eof_on_save$test', value: false }, { name: 'files.insertFinalNewline$test', value: false })],
['complexSetting', new MappedSetting({ name: 'draw_white_space$test', value: 'boundary' }, { name: 'editor.renderWhitespace$test', value: 'boundary' })],
]);
test('Import different types', async () => {
const testMappings = Promise.resolve(testData.testMappings);
const mapper: Mapper = new Mapper(testMappings);
const settings: AnalyzedSettings = await mapper.getMappedSettings(JSON.stringify(testData.sublimeSettings));
assert.ok(settings.mappedSettings.length === 4, `mappedSettings.length is ${settings.mappedSettings.length} instead of 4`);
expected.forEach((expSetting) => {
const setting = settings.mappedSettings.find(m => m.sublime.name === expSetting.sublime.name);
if (!setting) {
assert.fail(JSON.stringify(expSetting), 'Could not find mapped setting');
} else {
assert.ok(setting.vscode.name === expSetting.vscode.name
&& setting.vscode.value === expSetting.vscode.value,
`Setting ${setting.vscode.name}: ${setting.vscode.value} failed`);
}
});
});
const alreadyExistingVsSettings: ISetting[] = [
{ name: 'editor.sameKeySameValue', value: true },
{ name: 'editor.sameKeyDiffVal', value: 'jajslfn' },
];
test('Categorization of settings works', async () => {
const mockConfig = {
inspect: ((s: string) => {
const foundSetting: ISetting | undefined = alreadyExistingVsSettings.find((setting) => setting.name === s);
if (foundSetting) {
return { globalValue: foundSetting.value };
}
return undefined;
}),
};
const testMappings = Promise.resolve(testData.testMappings);
const mapper: Mapper = new Mapper(testMappings, mockConfig);
const sublimeSettings = JSON.stringify({ ...testData.sublimeSettings, ...testData.sublimeSettingNoMapping, ...testData.sublimeSettingSameKeyDiffVal, ...testData.sublimeSettingSameKeyVal });
const settings: AnalyzedSettings = await mapper.getMappedSettings(sublimeSettings);
assert.ok(settings.alreadyExisting.length === 1);
assert.ok(settings.noMappings.length === 1);
});
test('Workaround for https://github.com/Microsoft/vscode/issues/47730', async () => {
let config = vscode.workspace.getConfiguration();
const settingName = 'editor.matchBrackets';
const backupSettingValue = config.inspect(settingName)!.globalValue;
await config.update(settingName, 'bogusValueForActivatingChangeListener', vscode.ConfigurationTarget.Global);
await config.update(settingName, true, vscode.ConfigurationTarget.Global);
config = vscode.workspace.getConfiguration();
const info = config.inspect(settingName);
if (!info) {
return assert.fail(info, 'inspect object');
}
assert.ok(info.globalValue === true, `globalValue: ${info.globalValue} is not true`);
assert.ok(info.defaultValue === true, `defaultValue: ${info.defaultValue} is not true`);
await config.update(settingName, backupSettingValue, vscode.ConfigurationTarget.Global);
});
});

22
src/test/index.ts Normal file
Просмотреть файл

@ -0,0 +1,22 @@
//
// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
//
// This file is providing the test runner to use when running extension tests.
// By default the test runner in use is Mocha based.
//
// You can provide your own test runner if you want to override it by exporting
// a function run(testRoot: string, clb: (error:Error) => void) that the extension
// host can call to run the tests. The test runner is expected to use console.log
// to report the results back to the caller. When the tests are finished, return
// a possible error to the callback or null if none.
import * as testRunner from 'vscode/lib/testrunner';
// You can directly control Mocha options by uncommenting the following lines
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
testRunner.configure({
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
useColors: true, // colored output from test results
});
module.exports = testRunner;

29
src/test/testData.ts Normal file
Просмотреть файл

@ -0,0 +1,29 @@
export const sublimeSettings = {
"draw_white_space$test": "selection",
"word_separators$test": "./\\()\"'-:,.;<>~!@#$%^&*|+=[]{}`~?",
"tab_size$test": 12,
"ensure_newline_at_eof_on_save$test": false,
};
export const sublimeSettingSameKeyVal = { "sameKeySameValue": true };
export const sublimeSettingSameKeyDiffVal = { "sameKeyDiffVal": 'asdfjadfsla' };
export const sublimeSettingNoMapping = { "noMapping": 'someVal' };
export const testMappings = {
"tab_size$test": "editor.tabSize$test", // Number
"word_separators$test": "editor.wordSeparators$test", // String
"ensure_newline_at_eof_on_save$test": "files.insertFinalNewline$test", // Boolean
"draw_white_space$test": {
"all": {
"editor.renderWhitespace$test": "all"
},
"none": {
"editor.renderWhitespace$test": "none"
},
"selection": {
"editor.renderWhitespace$test": "boundary"
},
},
"sameKeySameValue": "editor.sameKeySameValue",
"sameKeyDiffVal": "editor.sameKeyDiffVal",
};

61
tsconfig.json Normal file
Просмотреть файл

@ -0,0 +1,61 @@
{
"compilerOptions": {
/* Basic Options */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
"allowJs": false, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "out", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
"noUnusedLocals": true, /* Report errors on unused locals. */
"noUnusedParameters": true, /* Report errors on unused parameters. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
// "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
/* Source Map Options */
// "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
},
"include": [
"src"
]
}

43
tslint.json Normal file
Просмотреть файл

@ -0,0 +1,43 @@
{
"defaultSeverity": "warning",
"extends": [
"tslint:recommended"
],
"jsRules": {},
"rules": {
"no-string-throw": true,
"no-unused-expression": true,
"no-duplicate-variable": true,
"curly": true,
"class-name": true,
"arrow-parens": false,
"max-classes-per-file": false,
"object-literal-sort-keys": false,
"ordered-imports": false,
"typedef": [
true,
"call-signature",
"parameter",
"member-variable-declaration"
],
"max-line-length": [
false
],
"no-console": [
true,
"log"
],
"semicolon": [
true,
"always"
],
"triple-equals": true,
"quotemark": [
true,
"single",
"avoid-escape",
"avoid-template"
]
}
}