Skip to content

Commit e50eaf1

Browse files
authored
feat(editor): add vim mode support (#3044)
1 parent 0c2868d commit e50eaf1

File tree

4 files changed

+54
-1
lines changed

4 files changed

+54
-1
lines changed

pkgs/dartpad_ui/lib/editor/codemirror.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ extension type CodeMirror._(JSObject _) implements JSObject {
5050
String getTheme() => (getOption('theme') as JSString).toDart;
5151
void setTheme(String theme) => setOption('theme', theme.toJS);
5252

53+
String getKeymap() => (getOption('keyMap') as JSString).toDart;
54+
void setKeymap(String keyMap) => setOption('keyMap', keyMap.toJS);
55+
5356
external void scrollTo(num? x, num? y);
5457
external ScrollInfo getScrollInfo();
5558

pkgs/dartpad_ui/lib/editor/editor.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ class _EditorWidgetState extends State<EditorWidget> implements EditorService {
228228
appModel.sourceCodeController.addListener(_updateCodemirrorFromModel);
229229
appModel.analysisIssues
230230
.addListener(() => _updateIssues(appModel.analysisIssues.value));
231+
appModel.vimKeymapsEnabled.addListener(_updateCodemirrorKeymap);
231232

232233
widget.appServices.registerEditorService(this);
233234

@@ -309,6 +310,7 @@ class _EditorWidgetState extends State<EditorWidget> implements EditorService {
309310
widget.appModel.sourceCodeController
310311
.removeListener(_updateCodemirrorFromModel);
311312
widget.appModel.appReady.removeListener(_updateEditableStatus);
313+
widget.appModel.vimKeymapsEnabled.removeListener(_updateCodemirrorKeymap);
312314

313315
super.dispose();
314316
}
@@ -424,6 +426,17 @@ class _EditorWidgetState extends State<EditorWidget> implements EditorService {
424426
);
425427
}
426428
}
429+
430+
void _updateCodemirrorKeymap() {
431+
final enabled = widget.appModel.vimKeymapsEnabled.value;
432+
final cm = codeMirror!;
433+
434+
if (enabled) {
435+
cm.setKeymap('vim');
436+
} else {
437+
cm.setKeymap('default');
438+
}
439+
}
427440
}
428441

429442
// codemirror commands

pkgs/dartpad_ui/lib/main.dart

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,10 @@ class StatusLineWidget extends StatelessWidget {
832832
builder: (context) => MediumDialog(
833833
title: 'Keyboard shortcuts',
834834
smaller: true,
835-
child: KeyBindingsTable(bindings: keys.keyBindings),
835+
child: KeyBindingsTable(
836+
bindings: keys.keyBindings,
837+
appModel: appModel,
838+
),
836839
),
837840
),
838841
child: Icon(
@@ -1157,9 +1160,11 @@ class ContinueInMenu extends StatelessWidget {
11571160

11581161
class KeyBindingsTable extends StatelessWidget {
11591162
final List<(String, List<ShortcutActivator>)> bindings;
1163+
final AppModel appModel;
11601164

11611165
const KeyBindingsTable({
11621166
required this.bindings,
1167+
required this.appModel,
11631168
super.key,
11641169
});
11651170

@@ -1210,6 +1215,10 @@ class KeyBindingsTable extends StatelessWidget {
12101215
],
12111216
),
12121217
),
1218+
const Divider(),
1219+
_VimModeSwitch(
1220+
appModel: appModel,
1221+
),
12131222
],
12141223
);
12151224
}
@@ -1283,6 +1292,32 @@ class _BrightnessButton extends StatelessWidget {
12831292
}
12841293
}
12851294

1295+
class _VimModeSwitch extends StatelessWidget {
1296+
final AppModel appModel;
1297+
1298+
const _VimModeSwitch({
1299+
required this.appModel,
1300+
});
1301+
1302+
@override
1303+
Widget build(BuildContext context) {
1304+
return ValueListenableBuilder(
1305+
valueListenable: appModel.vimKeymapsEnabled,
1306+
builder: (BuildContext context, bool value, Widget? child) {
1307+
return SwitchListTile(
1308+
value: value,
1309+
title: const Text('Use Vim Key Bindings'),
1310+
onChanged: _handleToggle,
1311+
);
1312+
},
1313+
);
1314+
}
1315+
1316+
void _handleToggle(bool value) {
1317+
appModel.vimKeymapsEnabled.value = value;
1318+
}
1319+
}
1320+
12861321
extension MenuControllerToggleMenu on MenuController {
12871322
void toggleMenuState() {
12881323
if (isOpen) {

pkgs/dartpad_ui/lib/model.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ class AppModel {
6767
final SplitDragStateManager splitDragStateManager = SplitDragStateManager();
6868
late final StreamSubscription<SplitDragState> _splitSubscription;
6969

70+
final ValueNotifier<bool> vimKeymapsEnabled = ValueNotifier(false);
71+
7072
AppModel() {
7173
consoleOutput.addListener(_recalcLayout);
7274

0 commit comments

Comments
 (0)