installBindingsForVSCodeTerminal function
Install Shift+Enter keybinding for VSCode, Cursor, or Windsurf.
Creates/modifies the keybindings.json file in the editor's user directory. Backs up existing file before modification.
Implementation
Future<String> installBindingsForVSCodeTerminal({
String editor = 'VSCode',
}) async {
// Check if we're running in a VSCode Remote SSH session.
if (isVSCodeRemoteSSH()) {
return 'Cannot install keybindings from a remote $editor session.\n\n'
'$editor keybindings must be installed on your local machine, '
'not the remote server.\n\n'
'To install the Shift+Enter keybinding:\n'
'1. Open $editor on your local machine (not connected to remote)\n'
'2. Open the Command Palette (Cmd/Ctrl+Shift+P) -> '
'"Preferences: Open Keyboard Shortcuts (JSON)"\n'
'3. Add this keybinding (the file must be a JSON array):\n\n'
'[\n'
' {\n'
' "key": "shift+enter",\n'
' "command": "workbench.action.terminal.sendSequence",\n'
' "args": { "text": "\\u001b\\r" },\n'
' "when": "terminalFocus"\n'
' }\n'
']\n';
}
final editorDir = editor == 'VSCode' ? 'Code' : editor;
final home = Platform.environment['HOME'] ?? '';
String userDirPath;
if (Platform.isWindows) {
final appData = Platform.environment['APPDATA'] ?? '';
userDirPath = p.join(appData, editorDir, 'User');
} else if (Platform.isMacOS) {
userDirPath = p.join(
home,
'Library',
'Application Support',
editorDir,
'User',
);
} else {
userDirPath = p.join(home, '.config', editorDir, 'User');
}
final keybindingsPath = p.join(userDirPath, 'keybindings.json');
try {
// Ensure user directory exists.
await Directory(userDirPath).create(recursive: true);
// Read existing keybindings file.
String content = '[]';
List<dynamic> keybindings = [];
bool fileExists = false;
try {
content = await File(keybindingsPath).readAsString();
fileExists = true;
// Strip comments for parsing (JSONC -> JSON).
final stripped = _stripJsonComments(content);
keybindings = jsonDecode(stripped) as List<dynamic>? ?? [];
} catch (e) {
if (e is! FileSystemException) rethrow;
}
// Backup the existing file before modifying.
if (fileExists) {
final randomSha = _randomHex(4);
final backupPath = '$keybindingsPath.$randomSha.bak';
try {
await File(keybindingsPath).copy(backupPath);
} catch (_) {
return 'Error backing up existing $editor terminal keybindings. '
'Bailing out.\n'
'See $keybindingsPath\n'
'Backup path: $backupPath\n';
}
}
// Check if keybinding already exists.
final existingBinding = keybindings.any((binding) {
if (binding is! Map<String, dynamic>) return false;
return binding['key'] == 'shift+enter' &&
binding['command'] == 'workbench.action.terminal.sendSequence' &&
binding['when'] == 'terminalFocus';
});
if (existingBinding) {
return 'Found existing $editor terminal Shift+Enter key binding. '
'Remove it to continue.\n'
'See $keybindingsPath\n';
}
// Create the new keybinding.
const newKeybinding = _VSCodeKeybinding(
key: 'shift+enter',
command: 'workbench.action.terminal.sendSequence',
args: {'text': '\x1b\r'},
when: 'terminalFocus',
);
// Add to the array and write back.
keybindings.add(newKeybinding.toJson());
final updatedContent = const JsonEncoder.withIndent(
' ',
).convert(keybindings);
await File(keybindingsPath).writeAsString(updatedContent);
return 'Installed $editor terminal Shift+Enter key binding\n'
'See $keybindingsPath\n';
} catch (e) {
throw Exception(
'Failed to install $editor terminal Shift+Enter key binding: $e',
);
}
}