replaced HTML UI with multipicker
This commit is contained in:
Родитель
362c8ba304
Коммит
d53eb13eb5
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -5,7 +5,7 @@
|
|||
"version": "1.0.1",
|
||||
"publisher": "auchenberg",
|
||||
"engines": {
|
||||
"vscode": "^1.18.0"
|
||||
"vscode": "^1.22.0"
|
||||
},
|
||||
"categories": [
|
||||
"Other"
|
||||
|
@ -62,7 +62,7 @@
|
|||
"@types/node": "^7.0.43",
|
||||
"@types/relaxed-json": "^1.0.0",
|
||||
"typescript": "^2.0.3",
|
||||
"vscode": "^1.1.5"
|
||||
"vscode": "^1.1.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"relaxed-json": "^1.0.1"
|
||||
|
|
|
@ -1,236 +0,0 @@
|
|||
function addClasses(el: HTMLElement, classesWhiteSpaceSeparated: string): void {
|
||||
classesWhiteSpaceSeparated.split(' ').forEach(cls => el.classList.add(cls));
|
||||
}
|
||||
class Setting {
|
||||
constructor(readonly name: string, readonly value: any) { }
|
||||
}
|
||||
|
||||
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: Setting;
|
||||
public vscode: Setting;
|
||||
public isDuplicate: boolean = false;
|
||||
public duplicateVscodeSetting: Setting;
|
||||
|
||||
constructor(sublimeSetting: Setting, vscodeSetting?: Setting) {
|
||||
this.sublime = sublimeSetting;
|
||||
this.vscode = vscodeSetting || new Setting(MappedSetting.NO_MATCH, MappedSetting.NO_MATCH);
|
||||
}
|
||||
|
||||
public setVscode(setting: Setting): void {
|
||||
this.vscode = setting;
|
||||
}
|
||||
|
||||
public markAsDuplicate(vscodeSetting: Setting) {
|
||||
this.isDuplicate = true;
|
||||
this.duplicateVscodeSetting = vscodeSetting;
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsTable {
|
||||
|
||||
public renderMappedSettings(mappedSettings: MappedSetting[]): HTMLElement[] {
|
||||
return mappedSettings.filter(m => !MappedSetting.hasNoMatch(m)).map((m, index) => this.renderMappedSetting(m, index));
|
||||
}
|
||||
|
||||
private renderMappedSetting(setting: MappedSetting, index: number): HTMLElement {
|
||||
let settingRow = document.createElement('div');
|
||||
addClasses(settingRow, 'settingRow clickable_parent');
|
||||
if (index % 2 === 0) {
|
||||
addClasses(settingRow, 'odd');
|
||||
}
|
||||
settingRow.dataset.sublimename = setting.sublime.name;
|
||||
settingRow.dataset.sublimevalue = JSON.stringify(setting.sublime.value);
|
||||
settingRow.dataset.vscodename = setting.vscode.name;
|
||||
settingRow.dataset.vscodevalue = JSON.stringify(setting.vscode.value);
|
||||
|
||||
settingRow.appendChild(this.renderCheckbox(setting));
|
||||
settingRow.appendChild(this.renderSetting(setting));
|
||||
return settingRow;
|
||||
}
|
||||
|
||||
private renderCheckbox(setting: MappedSetting) {
|
||||
const checkbox: HTMLInputElement = document.createElement('input') as HTMLInputElement;
|
||||
checkbox.type = 'checkbox';
|
||||
if (!setting.isDuplicate) {
|
||||
checkbox.setAttribute('checked', '');
|
||||
}
|
||||
addClasses(checkbox, 'ui checkbox matching_setting_checkbox');
|
||||
const td = document.createElement('div');
|
||||
td.appendChild(checkbox);
|
||||
return td;
|
||||
}
|
||||
|
||||
private renderSetting(setting: MappedSetting): HTMLElement {
|
||||
const mappedSetting = document.createElement('div');
|
||||
addClasses(mappedSetting, 'mappedSetting');
|
||||
mappedSetting.appendChild(this.renderSublimeSetting(setting.sublime));
|
||||
mappedSetting.appendChild(this.renderVscodeSetting(setting.vscode, setting.duplicateVscodeSetting));
|
||||
return mappedSetting;
|
||||
}
|
||||
|
||||
private renderSublimeSetting(sublime: Setting): HTMLElement {
|
||||
const setting = document.createElement('div');
|
||||
addClasses(setting, 'sublimeSetting');
|
||||
setting.appendChild(this.renderSettingNameAndValue(sublime.name, sublime.value));
|
||||
return setting;
|
||||
}
|
||||
|
||||
private renderVscodeSetting(vscode: Setting, existingSetting?: Setting): HTMLElement {
|
||||
const setting = document.createElement('div');
|
||||
addClasses(setting, 'vscodeSetting');
|
||||
setting.appendChild(this.renderSettingNameAndValue(vscode.name, vscode.value, existingSetting ? existingSetting.value : undefined));
|
||||
return setting;
|
||||
}
|
||||
|
||||
private renderSettingNameAndValue(name: string, value: string | boolean | number, currVal?: string | boolean | number): HTMLElement {
|
||||
const setting = document.createElement('div');
|
||||
addClasses(setting, 'setting-name-value');
|
||||
const nameContainer = document.createElement('div');
|
||||
addClasses(nameContainer, 'setting-name');
|
||||
nameContainer.textContent = name;
|
||||
nameContainer.title = name;
|
||||
setting.appendChild(nameContainer);
|
||||
const valueContainer = document.createElement('div');
|
||||
addClasses(valueContainer, 'setting-value');
|
||||
valueContainer.textContent = value.toString();
|
||||
valueContainer.title = value.toString();
|
||||
setting.appendChild(valueContainer);
|
||||
if (currVal !== undefined) {
|
||||
const warningIcon = document.createElement('div');
|
||||
addClasses(warningIcon, 'warning');
|
||||
warningIcon.title = `Overwrites current value: ${currVal}`;
|
||||
valueContainer.appendChild(warningIcon);
|
||||
}
|
||||
|
||||
return setting;
|
||||
}
|
||||
}
|
||||
|
||||
class Frontend {
|
||||
private selectAllCheckbox: HTMLInputElement = document.querySelector('#selectAllCheckbox input') as HTMLInputElement;
|
||||
private checkboxes: HTMLInputElement[] = Array.from(document.querySelectorAll('input.matching_setting_checkbox') as NodeListOf<HTMLInputElement>);
|
||||
private submitButton: HTMLButtonElement = document.querySelector('#add-settings-button') as HTMLButtonElement;
|
||||
private browseButton: HTMLButtonElement = document.querySelector('.browseButton') as HTMLButtonElement;
|
||||
private reloadIcon: HTMLDivElement = document.querySelector('.reloadIcon') as HTMLDivElement;
|
||||
private settingsPathContainer: HTMLInputElement = document.getElementById('settingsPathContainer') as HTMLInputElement;
|
||||
|
||||
constructor() {
|
||||
this.registerEventListeners();
|
||||
this.initUI();
|
||||
}
|
||||
|
||||
private registerEventListeners(): void {
|
||||
this.selectAllCheckbox.addEventListener('click', () => this.onDidClickSelectAllCheckbox());
|
||||
|
||||
this.checkboxes.forEach(box => box.addEventListener('change', () => this.refreshStates()));
|
||||
|
||||
this.submitButton.addEventListener('click', () => this.sendSettings(this.checkboxes.filter(chkbox => chkbox.checked)));
|
||||
|
||||
this.browseButton.addEventListener('click', () => this.executeCommand('command:extension.onBrowseButtonClicked'));
|
||||
|
||||
this.reloadIcon.addEventListener('click', () => this.executeCommand('command:extension.reload?' + JSON.stringify(this.settingsPathContainer.value)));
|
||||
}
|
||||
|
||||
private onDidClickSelectAllCheckbox() {
|
||||
for (const chkbox of this.checkboxes) {
|
||||
chkbox.checked = this.selectAllCheckbox.checked;
|
||||
}
|
||||
this.refreshStates();
|
||||
}
|
||||
|
||||
private initUI() {
|
||||
this.refreshStates();
|
||||
const { total, numChecked } = this.numCheckboxesChecked();
|
||||
this.selectAllCheckbox.checked = total === numChecked;
|
||||
}
|
||||
|
||||
private numCheckboxesChecked() {
|
||||
const numChecked = this.checkboxes.filter((box) => box.checked).length;
|
||||
return { total: this.checkboxes.length, numChecked };
|
||||
}
|
||||
|
||||
private refreshStates() {
|
||||
const chkboxStates = this.numCheckboxesChecked();
|
||||
this.setImportButtonState(chkboxStates.numChecked > 0);
|
||||
this.selectAllCheckbox.checked = chkboxStates.numChecked === chkboxStates.total;
|
||||
}
|
||||
|
||||
private setImportButtonState(on: boolean) {
|
||||
if (on) {
|
||||
this.submitButton.removeAttribute('disabled');
|
||||
this.submitButton.classList.remove('disabled');
|
||||
} else {
|
||||
this.submitButton.setAttribute('disabled', '');
|
||||
this.submitButton.classList.add('disabled');
|
||||
}
|
||||
}
|
||||
|
||||
private getVscodeSettingsFromParentTR(td: HTMLElement): Setting {
|
||||
return { name: td.parentElement.parentElement.dataset.vscodename, value: td.parentElement.parentElement.dataset.vscodevalue };
|
||||
}
|
||||
|
||||
private sendSettings(selectedCheckboxes: HTMLInputElement[]): void {
|
||||
const settings = selectedCheckboxes.map(chbox => this.getVscodeSettingsFromParentTR(chbox as HTMLElement));
|
||||
this.sendSelectedSettingsToExtension(settings);
|
||||
}
|
||||
|
||||
private sendSelectedSettingsToExtension(settings: Setting[]) {
|
||||
const obj = {
|
||||
data: settings
|
||||
};
|
||||
this.executeCommand('command:extension.onImportSelectedSettings?' + JSON.stringify(obj));
|
||||
}
|
||||
|
||||
private executeCommand(cmd: string): void {
|
||||
const command = encodeURI(cmd);
|
||||
var anchor = document.createElement('a');
|
||||
anchor.href = command;
|
||||
document.body.appendChild(anchor);
|
||||
anchor.click();
|
||||
document.body.removeChild(anchor);
|
||||
}
|
||||
}
|
||||
|
||||
function onNewSettings(settingsTable: SettingsTable) {
|
||||
const { mappedSettings, sublimeSettingsPath, isValid } = JSON.parse(decodeURI(document.getElementById('frontendData').dataset.frontend));
|
||||
if (sublimeSettingsPath) {
|
||||
const sublimeSettingsPathContainer = document.getElementById('settingsPathContainer');
|
||||
sublimeSettingsPathContainer.title = sublimeSettingsPath;
|
||||
sublimeSettingsPathContainer.setAttribute('value', sublimeSettingsPath);
|
||||
|
||||
if (isValid && mappedSettings.length) {
|
||||
const mappedSettingsContainer = document.querySelector('#mappedSettings');
|
||||
const mappedSettingsEls = settingsTable.renderMappedSettings(mappedSettings);
|
||||
for (const mappedSetting of mappedSettingsEls) {
|
||||
mappedSettingsContainer.appendChild(mappedSetting);
|
||||
}
|
||||
} else {
|
||||
const settingsImporter = document.querySelector('#sublimeSettingsImporter');
|
||||
const noSettingsFoundContainer = document.createElement('h4');
|
||||
addClasses(noSettingsFoundContainer, 'noSettingsFound');
|
||||
if (mappedSettings.length === 0) {
|
||||
noSettingsFoundContainer.textContent = `No settings to import`;
|
||||
} else {
|
||||
noSettingsFoundContainer.textContent = `No Sublime settings folder found`;
|
||||
}
|
||||
|
||||
settingsImporter.appendChild(noSettingsFoundContainer);
|
||||
const settingsTable = document.querySelector('#settingsTableMapper');
|
||||
settingsTable.classList.add('hidden');
|
||||
}
|
||||
} else {
|
||||
const settingsTable = document.querySelector('#settingsTableMapper');
|
||||
settingsTable.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
onNewSettings(new SettingsTable());
|
||||
new Frontend();
|
|
@ -1,6 +1,10 @@
|
|||
import {resolve} from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import { readFileAsync } from './fsWrapper';
|
||||
import { HTMLPreviewEditor } from './htmlPreview';
|
||||
import { Importer } from './importer';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
new HTMLPreviewEditor(context);
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<void> {
|
||||
const mappingsFile: string = await readFileAsync(resolve(__dirname, '..', 'mappings/settings.json'), 'utf-8');
|
||||
new HTMLPreviewEditor(context, new Importer(mappingsFile));
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ function fsAccess(stringPath: string, checks: number): Promise<any> {
|
|||
|
||||
// adapted from vs/base/common/async
|
||||
export function promisifier<T>(fn: Function, ...args: any[]): Promise<T> {
|
||||
return new Promise((c, e) => fn(...args, (err, result) => err ? e(err) : c(result)));
|
||||
return new Promise((c, e) => fn(...args, (err: any, result: any) => err ? e(err) : c(result)));
|
||||
}
|
||||
|
||||
export async function getFilenamesInFolderAsync(folderPath: string): Promise<string[]> {
|
||||
|
|
|
@ -1,81 +1,78 @@
|
|||
import * as vscode from 'vscode';
|
||||
import { readFileAsync } from './fsWrapper';
|
||||
import { Importer } from './importer';
|
||||
import { MappedSetting, Setting } from './settings';
|
||||
import { MappedSetting } from './settings';
|
||||
import * as sublimeFolderFinder from './sublimeFolderFinder';
|
||||
import { ISublimeSettingsPickerResult } from './sublimeFolderFinder';
|
||||
import { resolve } from 'path';
|
||||
import { readFileAsync} from './fsWrapper';
|
||||
export const scheme = 'vs-code-html-preview';
|
||||
const previewUri = vscode.Uri.parse(`${scheme}://authority/vs-code-html-preview`);
|
||||
|
||||
interface ISettingsPacket {
|
||||
data: [{ name: string, value: string }];
|
||||
}
|
||||
|
||||
interface IFrontendData {
|
||||
mappedSettings: MappedSetting[];
|
||||
sublimeSettingsPath: string;
|
||||
isValid: boolean;
|
||||
}
|
||||
|
||||
export class HTMLPreviewEditor {
|
||||
|
||||
private _onDidChange: vscode.EventEmitter<vscode.Uri> = new vscode.EventEmitter<vscode.Uri>();
|
||||
public readonly onDidChange: vscode.Event<vscode.Uri> = this._onDidChange.event;
|
||||
private userSelectedPath: vscode.Uri;
|
||||
private isValid: boolean = true;
|
||||
|
||||
private _importer: Importer;
|
||||
|
||||
constructor(private context: vscode.ExtensionContext) {
|
||||
context.subscriptions.push(this._onDidChange);
|
||||
constructor(context: vscode.ExtensionContext, private importer: Importer) {
|
||||
context.subscriptions.push(vscode.commands.registerCommand('extension.importFromSublime', () => this.open()));
|
||||
context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider(scheme, this));
|
||||
context.subscriptions.push(vscode.commands.registerCommand('extension.onBrowseButtonClicked', () => this.pickFolder()));
|
||||
context.subscriptions.push(vscode.commands.registerCommand('extension.onImportSelectedSettings', (packet: ISettingsPacket) => this.onImportSelectedSettings(packet)));
|
||||
context.subscriptions.push(vscode.commands.registerCommand('extension.reload', () => this._onDidChange.fire(previewUri)));
|
||||
}
|
||||
|
||||
public async provideTextDocumentContent(): Promise<string> {
|
||||
const path = await this.getSettingsPath();
|
||||
const settings: MappedSetting[] | undefined = this.isValid && path ? await this.getSettings(path.fsPath) : [];
|
||||
return this.getHTML({
|
||||
mappedSettings: settings,
|
||||
sublimeSettingsPath: path.fsPath,
|
||||
isValid: this.isValid,
|
||||
});
|
||||
}
|
||||
private async open(sublimeSettingsPath?: vscode.Uri): Promise<void> {
|
||||
sublimeSettingsPath = sublimeSettingsPath || await sublimeFolderFinder.getExistingDefaultPaths();
|
||||
if (!sublimeSettingsPath) {
|
||||
return this.showBrowseButtonAsync({
|
||||
label: '$(issue-opened) No Sublime settings folder found. It\'s usually located here:',
|
||||
detail: sublimeFolderFinder.getOSDefaultPaths().join(' '),
|
||||
});
|
||||
}
|
||||
|
||||
private open() {
|
||||
vscode.commands.executeCommand<any>('vscode.previewHtml', previewUri, vscode.ViewColumn.Active, 'Sublime Settings Importer');
|
||||
}
|
||||
const mappedSettings: MappedSetting[] = await this.getSettings(sublimeSettingsPath.fsPath);
|
||||
if (!mappedSettings.length) {
|
||||
return await this.showBrowseButtonAsync({
|
||||
label: '$(issue-opened) No new settings to import from',
|
||||
detail: sublimeSettingsPath.fsPath,
|
||||
});
|
||||
}
|
||||
|
||||
private async pickFolder() {
|
||||
const folderPickerResult: ISublimeSettingsPickerResult = await sublimeFolderFinder.pickSublimeSettings();
|
||||
if (folderPickerResult) {
|
||||
if (folderPickerResult.sublimeSettingsPath) {
|
||||
this.userSelectedPath = folderPickerResult.sublimeSettingsPath;
|
||||
} else {
|
||||
vscode.window.showWarningMessage('No settings folder found');
|
||||
}
|
||||
this.isValid = !!folderPickerResult.sublimeSettingsPath;
|
||||
this._onDidChange.fire(previewUri);
|
||||
const pickedSettingNames: vscode.QuickPickItem[] | undefined = await vscode.window.showQuickPick(mappedSettings
|
||||
.map(this.setting2QuickPickItem), { canPickMany: true });
|
||||
if (pickedSettingNames) {
|
||||
const selSettings = pickedSettingNames.map(name => mappedSettings.find(set => this.setting2QuickPickItem(set).label === name.label)) as MappedSetting[];
|
||||
this.importSelectedSettings(selSettings);
|
||||
}
|
||||
}
|
||||
|
||||
private async onImportSelectedSettings(packet: ISettingsPacket): Promise<void> {
|
||||
if (packet.data) {
|
||||
const settings: Setting[] = packet.data.map((setting) => new Setting(setting.name, JSON.parse(setting.value)));
|
||||
const importer = await this.getImporter();
|
||||
await importer.updateSettingsAsync(settings);
|
||||
private async showBrowseButtonAsync(msgItem: vscode.QuickPickItem): Promise<void> {
|
||||
const browseString = 'Browse...';
|
||||
const browseItem: vscode.QuickPickItem = { label: browseString };
|
||||
const selectedItem: vscode.QuickPickItem | undefined = await vscode.window.showQuickPick([msgItem, browseItem]);
|
||||
if (!selectedItem) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (selectedItem.label === browseString) {
|
||||
this.pickFolder();
|
||||
}
|
||||
}
|
||||
|
||||
private 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,
|
||||
};
|
||||
}
|
||||
private async pickFolder(): Promise<void> {
|
||||
const sublimeSettingsPath: vscode.Uri | undefined = await sublimeFolderFinder.pickSublimeSettings();
|
||||
if (sublimeSettingsPath) {
|
||||
this.open(sublimeSettingsPath);
|
||||
}
|
||||
}
|
||||
|
||||
private async importSelectedSettings(selectedSettings: MappedSetting[]): Promise<void> {
|
||||
if (selectedSettings.length) {
|
||||
await this.importer.updateSettingsAsync(selectedSettings.map(selSettings => selSettings.vscode));
|
||||
await vscode.commands.executeCommand('workbench.action.openGlobalSettings');
|
||||
} else {
|
||||
console.error(`Unhandled message: ${JSON.stringify(packet.data)}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async getSettings(sublimeSettingsPath: string): Promise<MappedSetting[]> {
|
||||
const importer = await this.getImporter();
|
||||
const importer = await this.importer;
|
||||
let settings: MappedSetting[] | undefined = await importer.getMappedSettingsAsync(await readFileAsync(sublimeSettingsPath, 'utf-8'));
|
||||
settings = settings.filter((s) => !MappedSetting.hasNoMatch(s));
|
||||
settings.sort((a, b) => {
|
||||
|
@ -90,67 +87,4 @@ export class HTMLPreviewEditor {
|
|||
});
|
||||
return settings;
|
||||
}
|
||||
|
||||
private async getSettingsPath(): Promise<vscode.Uri> {
|
||||
if (this.userSelectedPath) {
|
||||
return this.userSelectedPath;
|
||||
}
|
||||
const defaultSublimePaths = await sublimeFolderFinder.getExistingDefaultPaths();
|
||||
return defaultSublimePaths && defaultSublimePaths.length ? defaultSublimePaths[0].settings : null;
|
||||
}
|
||||
|
||||
private async getImporter(): Promise<Importer> {
|
||||
if (!this._importer) {
|
||||
const mappingsFilePath = resolve(__dirname, '..', 'mappings/settings.json');
|
||||
this._importer = new Importer(await readFileAsync(mappingsFilePath, 'utf-8'));
|
||||
}
|
||||
return this._importer;
|
||||
}
|
||||
|
||||
private getHTML(frontendData: IFrontendData): string {
|
||||
const projectRoot: string = vscode.Uri.file(this.context.asAbsolutePath('')).fsPath;
|
||||
|
||||
return `
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="file://${projectRoot}/resources/style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="frontendData" data-frontend=${encodeURI(JSON.stringify(frontendData))}></div>
|
||||
<div id="sublimeSettingsImporter">
|
||||
|
||||
<h3>Import Settings from Sublime Text</h3>
|
||||
<div class="selectFolder">
|
||||
<div class="reloadIcon"></div>
|
||||
<input id="settingsPathContainer" name="settingsPathContainer" placeholder="Sublime Settings Folder required." readonly>
|
||||
<button class="browseButton">Browse...</button>
|
||||
</div>
|
||||
|
||||
<!-- Import Settings Tab Start -->
|
||||
<div id='settingsTableMapper'>
|
||||
<div class="settingsTable">
|
||||
<div class="headerRow">
|
||||
<div id='selectAllCheckbox' class="checkbox">
|
||||
<input class="select_all_checkbox ui checkbox" type="checkbox">
|
||||
</div>
|
||||
<div class="title">Sublime</div>
|
||||
<div>
|
||||
<i class="mapping-arrow long arrow alternate right icon"></i>
|
||||
</div>
|
||||
<div class="title">VS Code</div>
|
||||
</div>
|
||||
<div id="mappedSettings" class="mappedSettings">
|
||||
</div>
|
||||
</div>
|
||||
<button id='add-settings-button' class="import-button">Import</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="file://${projectRoot}/out/browser/settingsPageFrontend.js"></script>
|
||||
|
||||
</html>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ export class Importer {
|
|||
this.settingsMappings = this.json2Map(mappings);
|
||||
}
|
||||
|
||||
public async getMappedSettingsAsync(sublimeSettings: string): Promise<MappedSetting[] | undefined> {
|
||||
public async getMappedSettingsAsync(sublimeSettings: string): Promise<MappedSetting[]> {
|
||||
return this.mapAllSettings(this.json2Map(sublimeSettings));
|
||||
}
|
||||
|
||||
|
@ -25,36 +25,37 @@ export class Importer {
|
|||
|
||||
private json2Map(toParse: string): Map<string, any> {
|
||||
const map = new Map<string, any>();
|
||||
const parsed = rjson.parse(toParse);
|
||||
const parsed: any = rjson.parse(toParse);
|
||||
Object.keys(parsed).forEach(key => map.set(key, parsed[key]));
|
||||
return map;
|
||||
}
|
||||
private getExistingValue(setting: Setting): any | undefined {
|
||||
const config = vscode.workspace.getConfiguration();
|
||||
const info = config.inspect(setting.name);
|
||||
return info.globalValue === undefined ? undefined : info.globalValue;
|
||||
}
|
||||
|
||||
private mapAllSettings(sublimeSettings: Map<string, any>): MappedSetting[] {
|
||||
const mappedSettings: MappedSetting[] = [];
|
||||
sublimeSettings.forEach((value, key) => {
|
||||
const ms: MappedSetting = new MappedSetting(new Setting(key, value));
|
||||
const config = vscode.workspace.getConfiguration();
|
||||
|
||||
for (const [key, value] of sublimeSettings.entries()) {
|
||||
const mappedSetting: MappedSetting = new MappedSetting(new Setting(key, value));
|
||||
|
||||
const vscodeMapping = this.mapSetting(key, value);
|
||||
if (vscodeMapping) {
|
||||
ms.setVscode(vscodeMapping);
|
||||
const existingValue = this.getExistingValue(vscodeMapping);
|
||||
if (existingValue) {
|
||||
ms.markAsDuplicate(new Setting(vscodeMapping.name, existingValue.toString()));
|
||||
mappedSetting.setVscode(vscodeMapping);
|
||||
|
||||
const info = config.inspect(vscodeMapping.name);
|
||||
if (info && info.globalValue) {
|
||||
if (info.globalValue === vscodeMapping.value) {
|
||||
continue; // skip settings that already exist with the exact same value
|
||||
}
|
||||
mappedSetting.markAsDuplicate(new Setting(vscodeMapping.name, info.globalValue.toString()));
|
||||
}
|
||||
}
|
||||
mappedSettings.push(ms);
|
||||
});
|
||||
mappedSettings.push(mappedSetting);
|
||||
}
|
||||
return mappedSettings;
|
||||
}
|
||||
|
||||
private mapSetting(key: string, value: string): Setting | undefined {
|
||||
const mappedSetting: string | object = this.settingsMappings.get(key);
|
||||
const mappedSetting: any = this.settingsMappings.get(key);
|
||||
if (mappedSetting) {
|
||||
if (typeof mappedSetting === 'string') {
|
||||
return new Setting(mappedSetting, value);
|
||||
|
@ -71,6 +72,6 @@ export class Importer {
|
|||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ export class MappedSetting {
|
|||
public sublime: Setting;
|
||||
public vscode: Setting;
|
||||
public isDuplicate: boolean = false;
|
||||
public duplicateVscodeSetting: Setting;
|
||||
public duplicateVscodeSetting?: Setting;
|
||||
|
||||
constructor(sublimeSetting: Setting, vscodeSetting?: Setting) {
|
||||
this.sublime = sublimeSetting;
|
||||
|
@ -29,4 +29,4 @@ export class MappedSetting {
|
|||
this.isDuplicate = true;
|
||||
this.duplicateVscodeSetting = vscodeSetting;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,6 @@ import * as path from 'path';
|
|||
import * as vscode from 'vscode';
|
||||
import * as fileSystem from './fsWrapper';
|
||||
|
||||
interface ISublimeFolders {
|
||||
main: vscode.Uri;
|
||||
settings: vscode.Uri;
|
||||
}
|
||||
|
||||
export const sublimeSettingsFilename = 'Preferences.sublime-settings';
|
||||
|
||||
const defaultSublimeSettingsPaths: Map<string, string[]> = new Map([
|
||||
|
@ -18,13 +13,12 @@ const defaultSublimeSettingsPaths: Map<string, string[]> = new Map([
|
|||
|
||||
const settingsSubfoldersPath = path.join('Packages', 'User', 'Preferences.sublime-settings');
|
||||
|
||||
export async function getExistingDefaultPaths(): Promise<ISublimeFolders[]> {
|
||||
export async function getExistingDefaultPaths(): Promise<vscode.Uri | undefined> {
|
||||
const foundPaths = await getOSDefaultPaths();
|
||||
if (!foundPaths.length) {
|
||||
return [];
|
||||
return undefined;
|
||||
}
|
||||
const existingDefaultPaths: ISublimeFolders[] = await filterForExistingDirsAsync(foundPaths);
|
||||
return existingDefaultPaths;
|
||||
return filterForExistingDirsAsync(foundPaths);
|
||||
}
|
||||
|
||||
export function getOSDefaultPaths(): string[] {
|
||||
|
@ -37,16 +31,15 @@ export function getOSDefaultPaths(): string[] {
|
|||
return foundPaths;
|
||||
}
|
||||
|
||||
async function filterForExistingDirsAsync(paths: string[]): Promise<ISublimeFolders[]> {
|
||||
const existingDirs: ISublimeFolders[] = [];
|
||||
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)) {
|
||||
existingDirs.push({ main: vscode.Uri.file(p), settings: vscode.Uri.file(settingsPath) });
|
||||
return vscode.Uri.file(settingsPath);
|
||||
}
|
||||
}
|
||||
|
||||
return existingDirs;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export interface ISublimeSettingsPickerResult {
|
||||
|
@ -54,21 +47,11 @@ export interface ISublimeSettingsPickerResult {
|
|||
sublimeSettingsPath?: vscode.Uri;
|
||||
}
|
||||
|
||||
export async function pickSublimeSettings(): Promise<ISublimeSettingsPickerResult | undefined> {
|
||||
export async function pickSublimeSettings(): Promise<vscode.Uri | undefined> {
|
||||
const folderPaths = await vscode.window.showOpenDialog({ canSelectFolders: true });
|
||||
if (!folderPaths) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const sublimeSettingsFolders: ISublimeFolders[] = await filterForExistingDirsAsync([folderPaths[0].fsPath]);
|
||||
if (!sublimeSettingsFolders.length) {
|
||||
return {
|
||||
path: folderPaths[0],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
path: folderPaths[0],
|
||||
sublimeSettingsPath: sublimeSettingsFolders[0].settings,
|
||||
};
|
||||
return await filterForExistingDirsAsync([folderPaths[0].fsPath]);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as assert from 'assert';
|
|||
import { resolve } from 'path';
|
||||
import { readFileAsync } from '../fsWrapper';
|
||||
import { Importer } from '../importer';
|
||||
import {MappedSetting, Setting} from '../settings';
|
||||
import { MappedSetting, Setting } from '../settings';
|
||||
import * as testData from './testData';
|
||||
|
||||
suite('Importer Tests', async () => {
|
||||
|
@ -20,8 +20,12 @@ suite('Importer Tests', async () => {
|
|||
assert.ok(mappedSettings.length === 4);
|
||||
expected.forEach((expSetting) => {
|
||||
const setting = mappedSettings.find(m => m.sublime.name === expSetting.sublime.name);
|
||||
assert.ok(setting.vscode.name === expSetting.vscode.name
|
||||
&& setting.vscode.value === expSetting.vscode.value);
|
||||
if (!setting) {
|
||||
assert.fail(setting, 'A setting');
|
||||
} else {
|
||||
assert.ok(setting.vscode.name === expSetting.vscode.name
|
||||
&& setting.vscode.value === expSetting.vscode.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": false, /* Enable all 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. */
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"class-name": true,
|
||||
"arrow-parens": false,
|
||||
"max-classes-per-file": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"typedef": [
|
||||
true,
|
||||
"call-signature",
|
||||
|
@ -22,7 +23,7 @@
|
|||
],
|
||||
"max-line-length": [
|
||||
true,
|
||||
150
|
||||
170
|
||||
],
|
||||
"no-console": [
|
||||
true,
|
||||
|
|
Загрузка…
Ссылка в новой задаче