editor-profile-sync 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -5
- package/index.js +72 -50
- package/lib/constants.js +9 -4
- package/lib/extensions-sync.js +2 -19
- package/lib/keybindings-sync.js +57 -0
- package/lib/profile-paths.js +10 -1
- package/lib/prompts.js +36 -81
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ You can sync:
|
|
|
9
9
|
- extensions
|
|
10
10
|
- snippets
|
|
11
11
|
- `settings.json`
|
|
12
|
+
- `keybindings.json`
|
|
12
13
|
|
|
13
14
|
## Requirements
|
|
14
15
|
|
|
@@ -67,8 +68,9 @@ npm install
|
|
|
67
68
|
2. Choose a source editor.
|
|
68
69
|
3. Choose what to share:
|
|
69
70
|
- `Extensions`
|
|
70
|
-
- `settings.json`
|
|
71
71
|
- `Snippets`
|
|
72
|
+
- `settings.json`
|
|
73
|
+
- `keybindings.json`
|
|
72
74
|
4. Choose mode(s) for selected item types:
|
|
73
75
|
- Extensions:
|
|
74
76
|
- Install on top of existing (additive)
|
|
@@ -123,6 +125,48 @@ Result:
|
|
|
123
125
|
}
|
|
124
126
|
```
|
|
125
127
|
|
|
128
|
+
### Keybindings merge behavior
|
|
129
|
+
|
|
130
|
+
For `keybindings.json`, keybindings are merged intelligently:
|
|
131
|
+
|
|
132
|
+
- Source keybindings override target ones with the same `key` + `command` combination
|
|
133
|
+
- Existing target keybindings that don't conflict are preserved
|
|
134
|
+
- New source keybindings are added to the target
|
|
135
|
+
|
|
136
|
+
Example:
|
|
137
|
+
|
|
138
|
+
Target:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
[{ "key": "ctrl+k", "command": "workbench.action.terminal.clear" }]
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Source:
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
[
|
|
148
|
+
{
|
|
149
|
+
"key": "ctrl+k",
|
|
150
|
+
"command": "workbench.action.terminal.clear",
|
|
151
|
+
"when": "terminalFocus"
|
|
152
|
+
},
|
|
153
|
+
{ "key": "ctrl+shift+p", "command": "workbench.action.showCommands" }
|
|
154
|
+
]
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Result:
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
[
|
|
161
|
+
{
|
|
162
|
+
"key": "ctrl+k",
|
|
163
|
+
"command": "workbench.action.terminal.clear",
|
|
164
|
+
"when": "terminalFocus"
|
|
165
|
+
},
|
|
166
|
+
{ "key": "ctrl+shift+p", "command": "workbench.action.showCommands" }
|
|
167
|
+
]
|
|
168
|
+
```
|
|
169
|
+
|
|
126
170
|
## Supported editors
|
|
127
171
|
|
|
128
172
|
These editors are currently supported:
|
|
@@ -140,10 +184,6 @@ These editors are currently supported:
|
|
|
140
184
|
|
|
141
185
|
**Windows/Linux**: Each editor must be installed and its CLI available in your terminal (e.g. `code`, `cursor`).
|
|
142
186
|
|
|
143
|
-
## Generated files
|
|
144
|
-
|
|
145
|
-
- `extensions.txt` is created when syncing extensions and contains the exported source extension IDs.
|
|
146
|
-
|
|
147
187
|
## License
|
|
148
188
|
|
|
149
189
|
MIT
|
package/index.js
CHANGED
|
@@ -9,19 +9,22 @@ import updateNotifier from "update-notifier";
|
|
|
9
9
|
import {
|
|
10
10
|
EDITORS,
|
|
11
11
|
EXTENSION_MODES,
|
|
12
|
-
EXTENSIONS_FILE,
|
|
13
12
|
SNIPPET_MODES,
|
|
14
13
|
SYNC_ITEMS,
|
|
15
14
|
} from "./lib/constants.js";
|
|
16
15
|
import { isEditorInstalled } from "./lib/editor-cli.js";
|
|
16
|
+
import { exportExtensions, syncExtensions } from "./lib/extensions-sync.js";
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
} from "./lib/
|
|
22
|
-
import { getSettingsPath, getSnippetsPath } from "./lib/profile-paths.js";
|
|
18
|
+
getSettingsPath,
|
|
19
|
+
getSnippetsPath,
|
|
20
|
+
getKeybindingsPath,
|
|
21
|
+
} from "./lib/profile-paths.js";
|
|
23
22
|
import { readSourceSettings, syncSettings } from "./lib/settings-sync.js";
|
|
24
23
|
import { syncSnippets } from "./lib/snippets-sync.js";
|
|
24
|
+
import {
|
|
25
|
+
readSourceKeybindings,
|
|
26
|
+
syncKeybindings,
|
|
27
|
+
} from "./lib/keybindings-sync.js";
|
|
25
28
|
import {
|
|
26
29
|
promptExtensionMode,
|
|
27
30
|
promptSnippetMode,
|
|
@@ -96,7 +99,7 @@ async function main() {
|
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
detectSpinner.succeed(
|
|
99
|
-
`Found ${availableEditors.length} editor
|
|
102
|
+
`Found ${availableEditors.length} editor${availableEditors.length === 1 ? "" : "s"}: ${availableEditors
|
|
100
103
|
.map((e) => e.name)
|
|
101
104
|
.join(", ")}`,
|
|
102
105
|
);
|
|
@@ -133,9 +136,6 @@ async function main() {
|
|
|
133
136
|
targetIds.includes(e.id),
|
|
134
137
|
);
|
|
135
138
|
|
|
136
|
-
const cwd = process.cwd();
|
|
137
|
-
const extensionsPath = join(cwd, EXTENSIONS_FILE);
|
|
138
|
-
|
|
139
139
|
let desiredExtensions = [];
|
|
140
140
|
if (syncItems.includes("extensions")) {
|
|
141
141
|
const exportSpinner = ora({
|
|
@@ -143,11 +143,8 @@ async function main() {
|
|
|
143
143
|
color: "cyan",
|
|
144
144
|
}).start();
|
|
145
145
|
try {
|
|
146
|
-
await exportExtensions(sourceEditor
|
|
147
|
-
desiredExtensions
|
|
148
|
-
exportSpinner.succeed(
|
|
149
|
-
`Exported ${desiredExtensions.length} extensions to ${EXTENSIONS_FILE}`,
|
|
150
|
-
);
|
|
146
|
+
desiredExtensions = await exportExtensions(sourceEditor);
|
|
147
|
+
exportSpinner.succeed(`${desiredExtensions.length} extensions detected`);
|
|
151
148
|
} catch (err) {
|
|
152
149
|
exportSpinner.fail("Extension export failed");
|
|
153
150
|
console.error(" Error:", err.message, "\n");
|
|
@@ -176,58 +173,43 @@ async function main() {
|
|
|
176
173
|
}
|
|
177
174
|
}
|
|
178
175
|
|
|
176
|
+
let sourceKeybindings = [];
|
|
177
|
+
if (syncItems.includes("keybindings")) {
|
|
178
|
+
try {
|
|
179
|
+
sourceKeybindings = readSourceKeybindings(
|
|
180
|
+
getKeybindingsPath(sourceEditor),
|
|
181
|
+
);
|
|
182
|
+
} catch (err) {
|
|
183
|
+
console.error(` ${err.message}\n`);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
179
188
|
console.log("");
|
|
180
189
|
|
|
181
190
|
for (const editor of targetEditors) {
|
|
182
191
|
try {
|
|
183
|
-
console.log(chalk.bold(editor.name));
|
|
184
|
-
|
|
185
|
-
if (syncItems.includes("extensions")) {
|
|
186
|
-
const spinner = ora({
|
|
187
|
-
text: `${chalk.bold(editor.name)}: Installing extensions...`,
|
|
188
|
-
color: "cyan",
|
|
189
|
-
}).start();
|
|
190
|
-
const result = await syncExtensions(
|
|
191
|
-
editor,
|
|
192
|
-
desiredExtensions,
|
|
193
|
-
extensionMode,
|
|
194
|
-
(i, extensionId) => {
|
|
195
|
-
spinner.text = `${chalk.bold(editor.name)}: [${i + 1}/${desiredExtensions.length}] Installing ${extensionId}`;
|
|
196
|
-
},
|
|
197
|
-
);
|
|
198
|
-
const parts = [chalk.green(`${result.synced} extensions synced`)];
|
|
199
|
-
if (result.failed.length > 0) {
|
|
200
|
-
parts.push(chalk.red(`${result.failed.length} failed`));
|
|
201
|
-
}
|
|
202
|
-
spinner.succeed(`${chalk.bold(editor.name)}: ${parts.join(", ")}`);
|
|
203
|
-
if (result.failed.length > 0) {
|
|
204
|
-
console.log(
|
|
205
|
-
` ${chalk.red("Failed:")} ${result.failed.join(", ")}`,
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
192
|
+
console.log(chalk.bold(editor.name) + ":");
|
|
209
193
|
|
|
210
194
|
if (syncItems.includes("settings")) {
|
|
211
195
|
const spinner = ora({
|
|
212
|
-
text:
|
|
196
|
+
text: "Syncing settings.json...",
|
|
213
197
|
color: "cyan",
|
|
214
198
|
}).start();
|
|
215
199
|
try {
|
|
216
200
|
const targetPath = getSettingsPath(editor, { createIfMissing: true });
|
|
217
201
|
const merged = syncSettings(sourceSettings, targetPath);
|
|
218
202
|
spinner.succeed(
|
|
219
|
-
|
|
203
|
+
`settings.json synced (${Object.keys(merged).length} keys)`,
|
|
220
204
|
);
|
|
221
205
|
} catch (err) {
|
|
222
|
-
spinner.fail(
|
|
223
|
-
`${chalk.bold(editor.name)}: settings sync failed (${err.message})`,
|
|
224
|
-
);
|
|
206
|
+
spinner.fail(`settings sync failed (${err.message})`);
|
|
225
207
|
}
|
|
226
208
|
}
|
|
227
209
|
|
|
228
210
|
if (syncItems.includes("snippets")) {
|
|
229
211
|
const spinner = ora({
|
|
230
|
-
text:
|
|
212
|
+
text: `Syncing snippets (${snippetMode} mode)...`,
|
|
231
213
|
color: "cyan",
|
|
232
214
|
}).start();
|
|
233
215
|
try {
|
|
@@ -240,12 +222,52 @@ async function main() {
|
|
|
240
222
|
snippetMode,
|
|
241
223
|
);
|
|
242
224
|
spinner.succeed(
|
|
243
|
-
|
|
225
|
+
`snippets synced (${fileCount} file${fileCount === 1 ? "" : "s"}, ${snippetMode} mode)`,
|
|
244
226
|
);
|
|
245
227
|
} catch (err) {
|
|
246
|
-
spinner.fail(
|
|
247
|
-
|
|
228
|
+
spinner.fail(`snippets sync failed (${err.message})`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (syncItems.includes("keybindings")) {
|
|
233
|
+
const spinner = ora({
|
|
234
|
+
text: "Syncing keybindings.json...",
|
|
235
|
+
color: "cyan",
|
|
236
|
+
}).start();
|
|
237
|
+
try {
|
|
238
|
+
const targetPath = getKeybindingsPath(editor, {
|
|
239
|
+
createIfMissing: true,
|
|
240
|
+
});
|
|
241
|
+
const merged = syncKeybindings(sourceKeybindings, targetPath);
|
|
242
|
+
spinner.succeed(
|
|
243
|
+
`keybindings.json synced (${merged.length} binding${merged.length === 1 ? "" : "s"})`,
|
|
248
244
|
);
|
|
245
|
+
} catch (err) {
|
|
246
|
+
spinner.fail(`keybindings sync failed (${err.message})`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (syncItems.includes("extensions")) {
|
|
251
|
+
const spinner = ora({
|
|
252
|
+
text: "Installing extensions...",
|
|
253
|
+
color: "cyan",
|
|
254
|
+
}).start();
|
|
255
|
+
const result = await syncExtensions(
|
|
256
|
+
editor,
|
|
257
|
+
desiredExtensions,
|
|
258
|
+
extensionMode,
|
|
259
|
+
(i, extensionId) => {
|
|
260
|
+
spinner.text = `Installing extensions [${i + 1}/${desiredExtensions.length}] ${chalk.dim(extensionId)}`;
|
|
261
|
+
},
|
|
262
|
+
);
|
|
263
|
+
const successPart = chalk.green(`${result.synced} installed`);
|
|
264
|
+
const failedPart =
|
|
265
|
+
result.failed.length > 0
|
|
266
|
+
? `, ${chalk.red(`${result.failed.length} failed`)}`
|
|
267
|
+
: "";
|
|
268
|
+
spinner.succeed(`extensions synced (${successPart}${failedPart})`);
|
|
269
|
+
if (result.failed.length > 0) {
|
|
270
|
+
console.log(`${chalk.red("Failed:")} ${result.failed.join(", ")}`);
|
|
249
271
|
}
|
|
250
272
|
}
|
|
251
273
|
|
package/lib/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export const EXTENSIONS_FILE = "extensions.txt";
|
|
2
1
|
export const SETTINGS_FILE = "settings.json";
|
|
3
2
|
export const SNIPPETS_DIR = "snippets";
|
|
3
|
+
export const KEYBINDINGS_FILE = "keybindings.json";
|
|
4
4
|
|
|
5
5
|
// Sorted alphabetically by display name.
|
|
6
6
|
export const EDITORS = [
|
|
@@ -44,15 +44,20 @@ export const SYNC_ITEMS = [
|
|
|
44
44
|
name: "Extensions",
|
|
45
45
|
short: "Extensions",
|
|
46
46
|
},
|
|
47
|
+
{
|
|
48
|
+
value: "snippets",
|
|
49
|
+
name: "Snippets",
|
|
50
|
+
short: "Snippets",
|
|
51
|
+
},
|
|
47
52
|
{
|
|
48
53
|
value: "settings",
|
|
49
54
|
name: "settings.json",
|
|
50
55
|
short: "settings.json",
|
|
51
56
|
},
|
|
52
57
|
{
|
|
53
|
-
value: "
|
|
54
|
-
name: "
|
|
55
|
-
short: "
|
|
58
|
+
value: "keybindings",
|
|
59
|
+
name: "keybindings.json",
|
|
60
|
+
short: "keybindings.json",
|
|
56
61
|
},
|
|
57
62
|
];
|
|
58
63
|
|
package/lib/extensions-sync.js
CHANGED
|
@@ -1,32 +1,15 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from "fs";
|
|
2
1
|
import {
|
|
3
2
|
getInstalledExtensions,
|
|
4
3
|
installExtension,
|
|
5
4
|
uninstallExtension,
|
|
6
5
|
} from "./editor-cli.js";
|
|
7
6
|
|
|
8
|
-
export async function exportExtensions(sourceEditor
|
|
7
|
+
export async function exportExtensions(sourceEditor) {
|
|
9
8
|
const list = await getInstalledExtensions(sourceEditor);
|
|
10
9
|
if (list == null) {
|
|
11
10
|
throw new Error(`${sourceEditor.name} CLI not found or failed.`);
|
|
12
11
|
}
|
|
13
|
-
|
|
14
|
-
const sorted = [...list].sort();
|
|
15
|
-
writeFileSync(
|
|
16
|
-
filePath,
|
|
17
|
-
sorted.join("\n") + (sorted.length ? "\n" : ""),
|
|
18
|
-
"utf-8",
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
return sorted;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function readExtensionsFile(filePath) {
|
|
25
|
-
const content = readFileSync(filePath, "utf-8");
|
|
26
|
-
return content
|
|
27
|
-
.split(/\r?\n/)
|
|
28
|
-
.map((s) => s.trim())
|
|
29
|
-
.filter(Boolean);
|
|
12
|
+
return [...list].sort();
|
|
30
13
|
}
|
|
31
14
|
|
|
32
15
|
export async function syncExtensions(editor, desired, mode, onProgress) {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
2
|
+
import { parse, printParseErrorCode } from "jsonc-parser";
|
|
3
|
+
|
|
4
|
+
export function readSourceKeybindings(keybindingsPath) {
|
|
5
|
+
if (!existsSync(keybindingsPath)) {
|
|
6
|
+
throw new Error(`Source keybindings.json not found: ${keybindingsPath}`);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const raw = readFileSync(keybindingsPath, "utf-8");
|
|
10
|
+
const errors = [];
|
|
11
|
+
const parsed = parse(raw, errors, { allowTrailingComma: true });
|
|
12
|
+
|
|
13
|
+
if (errors.length > 0) {
|
|
14
|
+
const firstError = errors[0];
|
|
15
|
+
throw new Error(
|
|
16
|
+
`Invalid JSON in source keybindings.json: ${printParseErrorCode(firstError.error)} at offset ${firstError.offset}`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!Array.isArray(parsed)) {
|
|
21
|
+
throw new Error("Source keybindings.json must be an array");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return parsed;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function syncKeybindings(sourceKeybindings, targetPath) {
|
|
28
|
+
let targetKeybindings = [];
|
|
29
|
+
|
|
30
|
+
if (existsSync(targetPath)) {
|
|
31
|
+
const raw = readFileSync(targetPath, "utf-8");
|
|
32
|
+
const errors = [];
|
|
33
|
+
const parsed = parse(raw, errors, { allowTrailingComma: true });
|
|
34
|
+
|
|
35
|
+
if (errors.length === 0 && Array.isArray(parsed)) {
|
|
36
|
+
targetKeybindings = parsed;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Merge: source keybindings override target ones with same key+command combo
|
|
41
|
+
const merged = [...targetKeybindings];
|
|
42
|
+
|
|
43
|
+
for (const sourceBinding of sourceKeybindings) {
|
|
44
|
+
const existingIndex = merged.findIndex(
|
|
45
|
+
(t) => t.key === sourceBinding.key && t.command === sourceBinding.command,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
if (existingIndex >= 0) {
|
|
49
|
+
merged[existingIndex] = sourceBinding;
|
|
50
|
+
} else {
|
|
51
|
+
merged.push(sourceBinding);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
writeFileSync(targetPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
56
|
+
return merged;
|
|
57
|
+
}
|
package/lib/profile-paths.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { existsSync, mkdirSync } from "fs";
|
|
2
2
|
import { homedir } from "os";
|
|
3
3
|
import { join } from "path";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
EDITOR_DATA_DIRS,
|
|
6
|
+
KEYBINDINGS_FILE,
|
|
7
|
+
SETTINGS_FILE,
|
|
8
|
+
SNIPPETS_DIR,
|
|
9
|
+
} from "./constants.js";
|
|
5
10
|
|
|
6
11
|
function getConfigBaseDir() {
|
|
7
12
|
if (process.platform === "win32") {
|
|
@@ -34,3 +39,7 @@ export function getSettingsPath(editor, options = {}) {
|
|
|
34
39
|
export function getSnippetsPath(editor, options = {}) {
|
|
35
40
|
return join(getEditorUserDir(editor, options), SNIPPETS_DIR);
|
|
36
41
|
}
|
|
42
|
+
|
|
43
|
+
export function getKeybindingsPath(editor, options = {}) {
|
|
44
|
+
return join(getEditorUserDir(editor, options), KEYBINDINGS_FILE);
|
|
45
|
+
}
|
package/lib/prompts.js
CHANGED
|
@@ -1,96 +1,51 @@
|
|
|
1
|
-
import
|
|
2
|
-
import CheckboxPrompt from "inquirer/lib/prompts/checkbox.js";
|
|
3
|
-
|
|
4
|
-
class CleanCheckboxPrompt extends CheckboxPrompt {
|
|
5
|
-
constructor(questions, rl, answers) {
|
|
6
|
-
super(questions, rl, answers);
|
|
7
|
-
this.dontShowHints = true;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
let isRegistered = false;
|
|
12
|
-
|
|
13
|
-
function ensurePromptRegistered() {
|
|
14
|
-
if (isRegistered) return;
|
|
15
|
-
inquirer.registerPrompt("clean-checkbox", CleanCheckboxPrompt);
|
|
16
|
-
isRegistered = true;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const CHECKBOX_HINT =
|
|
20
|
-
"(Press <space> to select, <a> to toggle all, <enter> to continue)";
|
|
1
|
+
import { select, checkbox } from "@inquirer/prompts";
|
|
21
2
|
|
|
22
3
|
export async function promptSourceEditor(availableEditors) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
message: "Share from:",
|
|
29
|
-
choices: availableEditors.map((e) => ({ name: e.name, value: e.id })),
|
|
30
|
-
pageSize: 10,
|
|
31
|
-
},
|
|
32
|
-
]);
|
|
33
|
-
return answer.sourceId;
|
|
4
|
+
return await select({
|
|
5
|
+
message: "Share from:",
|
|
6
|
+
choices: availableEditors.map((e) => ({ name: e.name, value: e.id })),
|
|
7
|
+
pageSize: 10,
|
|
8
|
+
});
|
|
34
9
|
}
|
|
35
10
|
|
|
36
11
|
export async function promptSyncItems(syncItems, chalk) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
choices: syncItems,
|
|
44
|
-
validate: (v) => (v.length ? true : "Select at least one item."),
|
|
45
|
-
},
|
|
46
|
-
]);
|
|
47
|
-
return answer.selectedItems;
|
|
12
|
+
return await checkbox({
|
|
13
|
+
message: "Select items to sync:",
|
|
14
|
+
choices: syncItems,
|
|
15
|
+
required: true,
|
|
16
|
+
validate: (v) => (v.length ? true : "Select at least one item."),
|
|
17
|
+
});
|
|
48
18
|
}
|
|
49
19
|
|
|
50
20
|
export async function promptExtensionMode(extensionModes) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
name:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
})),
|
|
61
|
-
default: "additive",
|
|
62
|
-
},
|
|
63
|
-
]);
|
|
64
|
-
return answer.extensionMode;
|
|
21
|
+
return await select({
|
|
22
|
+
message: "Extension mode:",
|
|
23
|
+
choices: extensionModes.map((m) => ({
|
|
24
|
+
name: m.name,
|
|
25
|
+
value: m.value,
|
|
26
|
+
short: m.short,
|
|
27
|
+
})),
|
|
28
|
+
default: "additive",
|
|
29
|
+
});
|
|
65
30
|
}
|
|
66
31
|
|
|
67
32
|
export async function promptSnippetMode(snippetModes) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
name:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
})),
|
|
78
|
-
default: "merge",
|
|
79
|
-
},
|
|
80
|
-
]);
|
|
81
|
-
return answer.snippetMode;
|
|
33
|
+
return await select({
|
|
34
|
+
message: "Snippet mode:",
|
|
35
|
+
choices: snippetModes.map((m) => ({
|
|
36
|
+
name: m.name,
|
|
37
|
+
value: m.value,
|
|
38
|
+
short: m.short,
|
|
39
|
+
})),
|
|
40
|
+
default: "merge",
|
|
41
|
+
});
|
|
82
42
|
}
|
|
83
43
|
|
|
84
44
|
export async function promptTargetEditors(targetChoices, chalk) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
choices: targetChoices,
|
|
92
|
-
validate: (v) => (v.length ? true : "Select at least one editor."),
|
|
93
|
-
},
|
|
94
|
-
]);
|
|
95
|
-
return answer.targetIds;
|
|
45
|
+
return await checkbox({
|
|
46
|
+
message: "Select target editors:",
|
|
47
|
+
choices: targetChoices,
|
|
48
|
+
required: true,
|
|
49
|
+
validate: (v) => (v.length ? true : "Select at least one editor."),
|
|
50
|
+
});
|
|
96
51
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "editor-profile-sync",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Cross-platform extensions, settings.json, and snippets sync for VS Code-based editors",
|
|
3
|
+
"version": "1.0.6",
|
|
4
|
+
"description": "Cross-platform extensions, settings.json, keybindings, and snippets sync for VS Code-based editors",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"bin": {
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"node": ">=18"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"@inquirer/prompts": "^8.2.1",
|
|
35
36
|
"chalk": "^5.6.2",
|
|
36
|
-
"inquirer": "^9.2.22",
|
|
37
37
|
"jsonc-parser": "^3.3.1",
|
|
38
38
|
"ora": "^9.3.0",
|
|
39
39
|
"update-notifier": "^7.3.1"
|