nvim-keymap-migrator 1.0.0
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/LICENSE +674 -0
- package/README.md +193 -0
- package/index.js +423 -0
- package/package.json +41 -0
- package/src/config.js +207 -0
- package/src/detector.js +401 -0
- package/src/extractor.js +265 -0
- package/src/generators/intellij.js +178 -0
- package/src/generators/vimrc.js +118 -0
- package/src/generators/vscode.js +175 -0
- package/src/install.js +379 -0
- package/src/namespace.js +63 -0
- package/src/registry.js +47 -0
- package/src/report.js +81 -0
- package/src/utils.js +36 -0
- package/templates/aliases.json +31 -0
- package/templates/defaults.json +11 -0
- package/templates/editing-mappings.json +34 -0
- package/templates/git-mappings.json +38 -0
- package/templates/lsp-mappings.json +62 -0
- package/templates/navigation-mappings.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# nvim-keymap-migrator
|
|
2
|
+
|
|
3
|
+
A CLI tool that extracts user-defined keymaps from your Neovim configuration and integrates them with vim emulator plugins (IdeaVim, VSCodeVim, etc.).
|
|
4
|
+
|
|
5
|
+
## Warning
|
|
6
|
+
|
|
7
|
+
**Back up your files before running this tool!**. This tool was made for me, so it may have unintended consequences on your setup. Always review the changes it proposes before applying them.
|
|
8
|
+
|
|
9
|
+
This tool modifies the following files:
|
|
10
|
+
|
|
11
|
+
- `~/.ideavimrc` (IntelliJ/IdeaVim config)
|
|
12
|
+
- VS Code `settings.json` (location varies by platform - see below)
|
|
13
|
+
|
|
14
|
+
While `--clean` attempts to cleanly remove all changes, **always back up these files** before running:
|
|
15
|
+
|
|
16
|
+
| Platform | VS Code settings.json |
|
|
17
|
+
| -------- | ------------------------------------------------------- |
|
|
18
|
+
| Linux | `~/.config/Code/User/settings.json` |
|
|
19
|
+
| macOS | `~/Library/Application Support/Code/User/settings.json` |
|
|
20
|
+
| Windows | `%APPDATA%/Code/User/settings.json` |
|
|
21
|
+
|
|
22
|
+
## Why?
|
|
23
|
+
|
|
24
|
+
When moving from Neovim to another editor (VS Code, IntelliJ, etc.), you'll likely use a vim emulator plugin like IdeaVim or VSCodeVim. This tool extracts your custom keymaps from your Neovim config so you don't have to manually recreate them.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install -g nvim-keymap-migrator
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Requirements
|
|
33
|
+
|
|
34
|
+
- Node.js 18+
|
|
35
|
+
- Neovim 0.8+ (for `vim.keymap.set` and `vim.api.nvim_get_keymap`)
|
|
36
|
+
- Editor with a Vim emulator plugin (e.g., IdeaVim for IntelliJ, VSCodeVim for VS Code)
|
|
37
|
+
- Your Neovim config must be loadable via `nvim --headless`
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
nvim-keymap-migrator <editor> [options]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Editors
|
|
46
|
+
|
|
47
|
+
- `vscode` - Generate and integrate keybindings for VS Code
|
|
48
|
+
- `intellij` - Generate and integrate keybindings for IntelliJ
|
|
49
|
+
|
|
50
|
+
### Options
|
|
51
|
+
|
|
52
|
+
- `--dry-run` - Print report without writing files
|
|
53
|
+
- `--clean` - Remove managed keybindings from editor config
|
|
54
|
+
- `--help, -h` - Show help
|
|
55
|
+
- `--version, -v` - Show version
|
|
56
|
+
|
|
57
|
+
### Examples
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Integrate with VS Code
|
|
61
|
+
nvim-keymap-migrator vscode
|
|
62
|
+
|
|
63
|
+
# Integrate with IntelliJ
|
|
64
|
+
nvim-keymap-migrator intellij
|
|
65
|
+
|
|
66
|
+
# Preview without making changes
|
|
67
|
+
nvim-keymap-migrator vscode --dry-run
|
|
68
|
+
|
|
69
|
+
# Remove VS Code keybindings
|
|
70
|
+
nvim-keymap-migrator vscode --clean
|
|
71
|
+
|
|
72
|
+
# Remove IntelliJ mappings
|
|
73
|
+
nvim-keymap-migrator intellij --clean
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## How It Works
|
|
77
|
+
|
|
78
|
+
The tool extracts keymaps from your Neovim config and categorizes them:
|
|
79
|
+
|
|
80
|
+
1. **IDE actions** - Keymaps that can be translated to IDE-specific actions (e.g., LSP, file explorer)
|
|
81
|
+
2. **Pure Vim mappings** - Native Vim keymaps that work in any Vim emulator
|
|
82
|
+
3. **Plugin mappings** - Keymaps from plugins (require manual configuration)
|
|
83
|
+
4. **Unsupported** - Keymaps that couldn't be categorized
|
|
84
|
+
|
|
85
|
+
### IntelliJ
|
|
86
|
+
|
|
87
|
+
Mappings are appended to `~/.ideavimrc` wrapped in markers:
|
|
88
|
+
|
|
89
|
+
```vim
|
|
90
|
+
" <<< nvim-keymap-migrator start >>>
|
|
91
|
+
" Managed by nvim-keymap-migrator. Run with --clean to remove.
|
|
92
|
+
|
|
93
|
+
" Pure Vim mappings (native Vim motions)
|
|
94
|
+
nnoremap K mzK`z
|
|
95
|
+
vnoremap K :m '<-2<CR>gv=gv
|
|
96
|
+
|
|
97
|
+
" IDE action mappings
|
|
98
|
+
nnoremap <leader>ff <Action>(GotoFile)
|
|
99
|
+
" >>> nvim-keymap-migrator end <<<
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Re-running replaces the content between markers. Use `--clean` to remove.
|
|
103
|
+
|
|
104
|
+
### VS Code
|
|
105
|
+
|
|
106
|
+
VS Code uses a two-pronged approach:
|
|
107
|
+
|
|
108
|
+
1. **IDE actions** - Merged directly into `settings.json`:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
"vim.normalModeKeyBindings": [
|
|
112
|
+
{ "before": ["<leader>", "f"], "commands": ["workbench.action.quickOpen"], "_managedBy": "nvim-keymap-migrator" }
|
|
113
|
+
]
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
2. **Pure Vim mappings** - Written to a shared `.vimrc` file, configured via `vim.vimrc.path` and `vim.vimrc.enable`:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
"vim.vimrc.path": "~/.config/nvim-keymap-migrator/.vimrc",
|
|
120
|
+
"vim.vimrc.enable": true
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The tool manages both settings:
|
|
124
|
+
|
|
125
|
+
- `vim.vimrc.path` - Set to point to the shared .vimrc
|
|
126
|
+
- `vim.vimrc.enable` - Set to `true` only if unset (respects existing user values)
|
|
127
|
+
|
|
128
|
+
Re-running replaces managed keybindings. Use `--clean` to remove them.
|
|
129
|
+
|
|
130
|
+
## Namespace
|
|
131
|
+
|
|
132
|
+
A small namespace directory stores shared files:
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
~/.config/nvim-keymap-migrator/
|
|
136
|
+
.vimrc Shared pure-Vim mappings (read by VS Code and IntelliJ)
|
|
137
|
+
metadata.json Extraction metadata
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Supported Intents
|
|
141
|
+
|
|
142
|
+
The tool detects and translates these keymap intents:
|
|
143
|
+
|
|
144
|
+
### Navigation
|
|
145
|
+
|
|
146
|
+
- `navigation.file_explorer` - File explorer (`:Ex`, `<leader>pv`)
|
|
147
|
+
- `navigation.find_files` - Quick open files
|
|
148
|
+
- `navigation.live_grep` - Search in files
|
|
149
|
+
- `navigation.buffers` - Switch buffers
|
|
150
|
+
- `navigation.recent_files` - Recent files
|
|
151
|
+
- `navigation.grep_string` - Search word under cursor
|
|
152
|
+
|
|
153
|
+
### LSP
|
|
154
|
+
|
|
155
|
+
- `lsp.definition` - Go to definition (`gd`)
|
|
156
|
+
- `lsp.declaration` - Go to declaration (`gD`)
|
|
157
|
+
- `lsp.references` - Find references (`gr`)
|
|
158
|
+
- `lsp.implementation` - Go to implementation (`gi`)
|
|
159
|
+
- `lsp.hover` - Show hover info
|
|
160
|
+
- `lsp.signature_help` - Signature help
|
|
161
|
+
- `lsp.rename` - Rename symbol
|
|
162
|
+
- `lsp.code_action` - Code actions
|
|
163
|
+
- `lsp.format` - Format document
|
|
164
|
+
|
|
165
|
+
### Git
|
|
166
|
+
|
|
167
|
+
- `git.fugitive` - Git commands
|
|
168
|
+
- `git.push` / `git.pull` - Push/pull
|
|
169
|
+
- `git.commit` - Git commit
|
|
170
|
+
|
|
171
|
+
### Pure Vim Mappings
|
|
172
|
+
|
|
173
|
+
Native Vim motions and commands are detected and output as pure Vim mappings, so any mapping from one Vim command to another is included here.
|
|
174
|
+
|
|
175
|
+
These work out of the box in any Vim emulator.
|
|
176
|
+
|
|
177
|
+
## What Gets Extracted
|
|
178
|
+
|
|
179
|
+
Only **user-defined** keymaps are extracted (not plugin defaults or built-in mappings). The tool identifies these by checking:
|
|
180
|
+
|
|
181
|
+
- If the keymap's callback source is in your config directory
|
|
182
|
+
- If the keymap has a `desc` field
|
|
183
|
+
- If the keymap's script path starts with your config path
|
|
184
|
+
|
|
185
|
+
## Limitations
|
|
186
|
+
|
|
187
|
+
- `<Lua function>` keymaps without a command string are included as comments (vim emulators can't execute arbitrary Lua)
|
|
188
|
+
- Buffer-local keymaps are marked with `<buffer>` - they'll only work in the current buffer
|
|
189
|
+
- Some plugin-specific keymaps may require manual configuration
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
GPL-3.0-only
|
package/index.js
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import { extractKeymaps } from "./src/extractor.js";
|
|
9
|
+
import { detectConfig } from "./src/config.js";
|
|
10
|
+
import { detectIntents } from "./src/detector.js";
|
|
11
|
+
import { loadMappings, lookupIntent } from "./src/registry.js";
|
|
12
|
+
import { generateVimrc, isPureVimMapping } from "./src/generators/vimrc.js";
|
|
13
|
+
import { generateIdeaVimrc } from "./src/generators/intellij.js";
|
|
14
|
+
import { generateVSCodeBindings } from "./src/generators/vscode.js";
|
|
15
|
+
import { generateReport } from "./src/report.js";
|
|
16
|
+
import { ensureNamespaceDir, getRcPath } from "./src/namespace.js";
|
|
17
|
+
import {
|
|
18
|
+
integrateIdeaVim,
|
|
19
|
+
cleanIdeaVim,
|
|
20
|
+
integrateVSCode,
|
|
21
|
+
cleanVSCode,
|
|
22
|
+
saveMetadata,
|
|
23
|
+
} from "./src/install.js";
|
|
24
|
+
|
|
25
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
26
|
+
const __dirname = dirname(__filename);
|
|
27
|
+
|
|
28
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, "package.json"), "utf8"));
|
|
29
|
+
const args = process.argv.slice(2);
|
|
30
|
+
|
|
31
|
+
await main(args);
|
|
32
|
+
|
|
33
|
+
function checkNeovimAvailable() {
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
const proc = spawn("nvim", ["--version"], { stdio: "ignore" });
|
|
36
|
+
proc.on("error", () => resolve(false));
|
|
37
|
+
proc.on("close", (code) => resolve(code === 0));
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function main(argv) {
|
|
42
|
+
const parsed = parseArgs(argv);
|
|
43
|
+
|
|
44
|
+
if (parsed.error) {
|
|
45
|
+
printHelp(parsed.error);
|
|
46
|
+
process.exitCode = 1;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (parsed.help) {
|
|
51
|
+
printHelp();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (parsed.version) {
|
|
56
|
+
console.log(pkg.version);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!parsed.editor) {
|
|
61
|
+
printHelp('Missing required <editor>. Use "vscode" or "intellij".');
|
|
62
|
+
process.exitCode = 1;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!["vscode", "intellij"].includes(parsed.editor)) {
|
|
67
|
+
printHelp(`Unsupported editor: ${parsed.editor}`);
|
|
68
|
+
process.exitCode = 1;
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (parsed.clean) {
|
|
73
|
+
await handleClean(parsed.editor);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await handleGenerate(parsed);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function handleGenerate(parsed) {
|
|
81
|
+
try {
|
|
82
|
+
const nvimAvailable = await checkNeovimAvailable();
|
|
83
|
+
if (!nvimAvailable) {
|
|
84
|
+
console.error("Error: Neovim not found. Please install Neovim 0.8+");
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const config = await detectConfig();
|
|
90
|
+
const extracted = await extractKeymaps();
|
|
91
|
+
const intents = detectIntents(extracted);
|
|
92
|
+
const registry = loadMappings();
|
|
93
|
+
|
|
94
|
+
if (intents.length === 0) {
|
|
95
|
+
console.log(`No user-defined keymaps found in your Neovim config.
|
|
96
|
+
Nothing to write.`);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const translated = [];
|
|
101
|
+
const manual = [];
|
|
102
|
+
const unsupported = [];
|
|
103
|
+
|
|
104
|
+
for (const item of intents) {
|
|
105
|
+
if (!item.intent) {
|
|
106
|
+
unsupported.push(item);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const command = lookupIntent(item.intent, parsed.editor, registry);
|
|
111
|
+
if (!command) {
|
|
112
|
+
manual.push(item);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
translated.push({ ...item, command });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const vimrcText = generateVimrc(intents);
|
|
120
|
+
const pureVim = intents.filter(isPureVimMapping);
|
|
121
|
+
const counts = {
|
|
122
|
+
total: intents.length,
|
|
123
|
+
translated: translated.length,
|
|
124
|
+
pureVim: pureVim.length,
|
|
125
|
+
manual: manual.length,
|
|
126
|
+
unsupported: unsupported.length,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const leaderLabel = formatKeyDisplay(config.leader);
|
|
130
|
+
|
|
131
|
+
if (parsed.dryRun) {
|
|
132
|
+
const report = generateReport({
|
|
133
|
+
target: parsed.editor,
|
|
134
|
+
configPath: config.config_path,
|
|
135
|
+
leader: leaderLabel,
|
|
136
|
+
total: intents.length,
|
|
137
|
+
translated,
|
|
138
|
+
manual,
|
|
139
|
+
manualPlugin: manual.filter((item) => item.category === "plugin"),
|
|
140
|
+
manualOther: manual.filter((item) => item.category !== "plugin"),
|
|
141
|
+
pureVim,
|
|
142
|
+
unsupported: unsupported.filter((item) => !isPureVimMapping(item)),
|
|
143
|
+
outputs: [],
|
|
144
|
+
});
|
|
145
|
+
console.log(report.trimEnd());
|
|
146
|
+
printDetectionWarnings(config, extracted);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
await ensureNamespaceDir();
|
|
151
|
+
const vimrcPath = getRcPath("neovim");
|
|
152
|
+
await writeFile(vimrcPath, vimrcText, "utf8");
|
|
153
|
+
|
|
154
|
+
console.log(`=== nvim-keymap-migrator ===
|
|
155
|
+
Editor: ${parsed.editor}
|
|
156
|
+
Config: ${config.config_path}
|
|
157
|
+
Leader: ${leaderLabel}
|
|
158
|
+
|
|
159
|
+
`);
|
|
160
|
+
|
|
161
|
+
if (parsed.editor === "intellij") {
|
|
162
|
+
const ideaVimrcResult = generateIdeaVimrc(intents, { registry });
|
|
163
|
+
const ideaVimrcText = ideaVimrcResult.text;
|
|
164
|
+
const ideaDefaults = ideaVimrcResult.defaultsAdded ?? 0;
|
|
165
|
+
const result = await integrateIdeaVim(ideaVimrcText, {
|
|
166
|
+
leader: config.leader,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
await saveMetadata(config, counts);
|
|
170
|
+
|
|
171
|
+
console.log(`Shared .vimrc: ${vimrcPath}
|
|
172
|
+
|
|
173
|
+
IntelliJ:
|
|
174
|
+
Mappings appended to ~/.ideavimrc${result.updated ? "\n (replaced previous mappings)" : ""}
|
|
175
|
+
Defaults added: ${ideaDefaults}`);
|
|
176
|
+
} else if (parsed.editor === "vscode") {
|
|
177
|
+
const vscodeBindings = generateVSCodeBindings(intents, { registry });
|
|
178
|
+
const result = await integrateVSCode(vscodeBindings, {
|
|
179
|
+
leader: config.leader,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
await saveMetadata(config, counts, {
|
|
183
|
+
leaderSet: result.setLeader,
|
|
184
|
+
vimrcPathSet: result.setVimrcPath,
|
|
185
|
+
vimrcEnableSet: result.setVimrcEnable,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
let vscodeOutput = `Shared .vimrc: ${vimrcPath}
|
|
189
|
+
|
|
190
|
+
VS Code:
|
|
191
|
+
Keybindings merged into settings.json`;
|
|
192
|
+
|
|
193
|
+
if (result.setVimrcPath) {
|
|
194
|
+
vscodeOutput +=
|
|
195
|
+
"\n vim.vimrc.path set in settings.json (reads shared .vimrc)";
|
|
196
|
+
}
|
|
197
|
+
if (result.setVimrcEnable) {
|
|
198
|
+
vscodeOutput +=
|
|
199
|
+
"\n vim.vimrc.enable set in settings.json (loads shared .vimrc)";
|
|
200
|
+
}
|
|
201
|
+
if (result.setLeader) {
|
|
202
|
+
vscodeOutput += "\n vim.leader set in settings.json";
|
|
203
|
+
}
|
|
204
|
+
if (result.sections) {
|
|
205
|
+
vscodeOutput += `\n Sections: ${result.sections.join(", ")}`;
|
|
206
|
+
}
|
|
207
|
+
if (result.warnings) {
|
|
208
|
+
for (const w of result.warnings) {
|
|
209
|
+
vscodeOutput += `\n ${w}`;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const vsDefaults = vscodeBindings._meta?.defaultsAdded ?? 0;
|
|
213
|
+
vscodeOutput += `\n Defaults added: ${vsDefaults}`;
|
|
214
|
+
|
|
215
|
+
console.log(vscodeOutput);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
console.log(`
|
|
219
|
+
Total keymaps: ${counts.total}
|
|
220
|
+
Translated: ${counts.translated}
|
|
221
|
+
Pure Vim: ${counts.pureVim}
|
|
222
|
+
Manual review: ${counts.manual}
|
|
223
|
+
Unsupported: ${counts.unsupported}`);
|
|
224
|
+
|
|
225
|
+
printDetectionWarnings(config, extracted);
|
|
226
|
+
} catch (error) {
|
|
227
|
+
console.error(`Error: ${error.message}`);
|
|
228
|
+
process.exitCode = 1;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async function handleClean(editor) {
|
|
233
|
+
try {
|
|
234
|
+
console.log(`=== nvim-keymap-migrator --clean ===
|
|
235
|
+
Editor: ${editor}
|
|
236
|
+
|
|
237
|
+
`);
|
|
238
|
+
|
|
239
|
+
if (editor === "intellij") {
|
|
240
|
+
const result = await cleanIdeaVim();
|
|
241
|
+
if (result.cleaned) {
|
|
242
|
+
console.log("Removed managed mappings from ~/.ideavimrc");
|
|
243
|
+
} else {
|
|
244
|
+
console.log("No managed mappings found in ~/.ideavimrc");
|
|
245
|
+
}
|
|
246
|
+
} else if (editor === "vscode") {
|
|
247
|
+
const result = await cleanVSCode();
|
|
248
|
+
if (result.cleaned) {
|
|
249
|
+
let output = `Removed ${result.removed} keybinding(s) from settings.json`;
|
|
250
|
+
if (result.sections) {
|
|
251
|
+
output += `\nSections cleaned: ${result.sections.join(", ")}`;
|
|
252
|
+
}
|
|
253
|
+
if (result.removedVimrcPath) {
|
|
254
|
+
output += "\nRemoved vim.vimrc.path from settings.json";
|
|
255
|
+
}
|
|
256
|
+
if (result.removedVimrcEnable) {
|
|
257
|
+
output += "\nRemoved vim.vimrc.enable from settings.json";
|
|
258
|
+
}
|
|
259
|
+
if (result.removedLeader) {
|
|
260
|
+
output += "\nRemoved vim.leader from settings.json";
|
|
261
|
+
}
|
|
262
|
+
console.log(output);
|
|
263
|
+
} else {
|
|
264
|
+
console.log("No managed keybindings found in settings.json");
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
} catch (error) {
|
|
268
|
+
console.error(`Error: ${error.message}`);
|
|
269
|
+
process.exitCode = 1;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function parseArgs(argv) {
|
|
274
|
+
const flags = {
|
|
275
|
+
help: false,
|
|
276
|
+
version: false,
|
|
277
|
+
dryRun: false,
|
|
278
|
+
clean: false,
|
|
279
|
+
editor: null,
|
|
280
|
+
error: null,
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const tokens = [...argv];
|
|
284
|
+
|
|
285
|
+
for (let i = 0; i < tokens.length; i += 1) {
|
|
286
|
+
const arg = tokens[i];
|
|
287
|
+
|
|
288
|
+
if (arg === "--help" || arg === "-h" || arg === "help") {
|
|
289
|
+
flags.help = true;
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (arg === "--version" || arg === "-v" || arg === "version") {
|
|
294
|
+
flags.version = true;
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (arg === "--dry-run") {
|
|
299
|
+
flags.dryRun = true;
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (arg === "--clean") {
|
|
304
|
+
flags.clean = true;
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (arg === "run") {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (!flags.editor && ["vscode", "intellij"].includes(arg)) {
|
|
313
|
+
flags.editor = arg;
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (arg.startsWith("-")) {
|
|
318
|
+
flags.error = `Unknown option: ${arg}`;
|
|
319
|
+
return flags;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
flags.error = `Unknown argument: ${arg}`;
|
|
323
|
+
return flags;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return flags;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function printHelp(error) {
|
|
330
|
+
if (error) {
|
|
331
|
+
console.error(error + "\n");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const help = `Usage: ${pkg.bin["nvim-keymap-migrator"]} <editor> [options]
|
|
335
|
+
|
|
336
|
+
Editors:
|
|
337
|
+
vscode Generate and integrate keybindings for VS Code
|
|
338
|
+
intellij Generate and integrate keybindings for IntelliJ
|
|
339
|
+
|
|
340
|
+
Options:
|
|
341
|
+
--dry-run Print report without writing files
|
|
342
|
+
--clean Remove managed keybindings from editor config
|
|
343
|
+
--help, -h Show help
|
|
344
|
+
--version, -v Show version
|
|
345
|
+
|
|
346
|
+
Examples:
|
|
347
|
+
nvim-keymap-migrator vscode # Integrate with VS Code
|
|
348
|
+
nvim-keymap-migrator intellij # Integrate with IntelliJ
|
|
349
|
+
nvim-keymap-migrator vscode --dry-run # Preview without changes
|
|
350
|
+
nvim-keymap-migrator vscode --clean # Remove VS Code keybindings
|
|
351
|
+
|
|
352
|
+
Files modified:
|
|
353
|
+
IntelliJ: ~/.ideavimrc
|
|
354
|
+
VS Code: settings.json (platform-specific path)`;
|
|
355
|
+
|
|
356
|
+
console.log(help);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function formatKeyDisplay(value) {
|
|
360
|
+
if (value == null) {
|
|
361
|
+
return "<none>";
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (value.length === 0) {
|
|
365
|
+
return "<empty>";
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const special = {
|
|
369
|
+
" ": "<space>",
|
|
370
|
+
"\t": "<Tab>",
|
|
371
|
+
"\n": "<NL>",
|
|
372
|
+
"\r": "<CR>",
|
|
373
|
+
"\u001B": "<Esc>",
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
return [...value]
|
|
377
|
+
.map((char) => special[char] ?? printableChar(char))
|
|
378
|
+
.join("");
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function printableChar(char) {
|
|
382
|
+
const code = char.charCodeAt(0);
|
|
383
|
+
if (code < 32) {
|
|
384
|
+
return `<0x${code.toString(16).padStart(2, "0")}>`;
|
|
385
|
+
}
|
|
386
|
+
if (char === "\\") {
|
|
387
|
+
return "\\\\";
|
|
388
|
+
}
|
|
389
|
+
return char;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function printDetectionWarnings(config, extracted) {
|
|
393
|
+
const extractionMeta = extracted?._meta ?? {};
|
|
394
|
+
const extractionWarnings = Array.isArray(extracted?._warnings)
|
|
395
|
+
? extracted._warnings
|
|
396
|
+
: [];
|
|
397
|
+
|
|
398
|
+
if (config.fallback_from) {
|
|
399
|
+
console.warn(
|
|
400
|
+
`Warning: config detection fell back from ${config.fallback_from} to ${config.mode} (${config.fallback_reason})`,
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (Array.isArray(config.warnings) && config.warnings.length > 0) {
|
|
405
|
+
console.warn(`Config warnings (${config.warnings.length}):`);
|
|
406
|
+
for (const warning of config.warnings.slice(0, 5)) {
|
|
407
|
+
console.warn(`- ${warning}`);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (extractionMeta.fallback_from) {
|
|
412
|
+
console.warn(
|
|
413
|
+
`Warning: extraction fell back from ${extractionMeta.fallback_from} to ${extractionMeta.extraction_mode} (${extractionMeta.fallback_reason})`,
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (extractionWarnings.length > 0) {
|
|
418
|
+
console.warn(`Extraction warnings (${extractionWarnings.length}):`);
|
|
419
|
+
for (const warning of extractionWarnings.slice(0, 5)) {
|
|
420
|
+
console.warn(`- ${warning}`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nvim-keymap-migrator",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Creates a keymap file from your Neovim config to migrate your keybinds to other editors.",
|
|
5
|
+
"files": [
|
|
6
|
+
"index.js",
|
|
7
|
+
"src",
|
|
8
|
+
"templates",
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
12
|
+
"bin": {
|
|
13
|
+
"nvim-keymap-migrator": "index.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"tools",
|
|
17
|
+
"neovim",
|
|
18
|
+
"nvim",
|
|
19
|
+
"editor",
|
|
20
|
+
"ide"
|
|
21
|
+
],
|
|
22
|
+
"homepage": "https://github.com/DerekCorniello/nvim-keymap-migrator#readme",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/DerekCorniello/nvim-keymap-migrator/issues"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/DerekCorniello/nvim-keymap-migrator.git"
|
|
29
|
+
},
|
|
30
|
+
"license": "GPL-3.0-only",
|
|
31
|
+
"author": "Derek Corniello",
|
|
32
|
+
"type": "module",
|
|
33
|
+
"main": "index.js",
|
|
34
|
+
"scripts": {
|
|
35
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
36
|
+
"lint": "prettier --check ."
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"prettier": "^3.0.0"
|
|
40
|
+
}
|
|
41
|
+
}
|