From 20d7c20f604045cace337e4db5e7406347f8c7af Mon Sep 17 00:00:00 2001 From: maranix Date: Sun, 18 Aug 2024 18:51:07 +0530 Subject: [PATCH] feat(editor): add vim mode support --- pkgs/dartpad_ui/lib/editor/codemirror.dart | 3 ++ pkgs/dartpad_ui/lib/editor/editor.dart | 13 ++++++++ pkgs/dartpad_ui/lib/main.dart | 37 +++++++++++++++++++++- pkgs/dartpad_ui/lib/model.dart | 2 ++ 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/pkgs/dartpad_ui/lib/editor/codemirror.dart b/pkgs/dartpad_ui/lib/editor/codemirror.dart index bebf6ffb5..b1587f93c 100644 --- a/pkgs/dartpad_ui/lib/editor/codemirror.dart +++ b/pkgs/dartpad_ui/lib/editor/codemirror.dart @@ -50,6 +50,9 @@ extension type CodeMirror._(JSObject _) implements JSObject { String getTheme() => (getOption('theme') as JSString).toDart; void setTheme(String theme) => setOption('theme', theme.toJS); + String getKeymap() => (getOption('keyMap') as JSString).toDart; + void setKeymap(String keyMap) => setOption('keyMap', keyMap.toJS); + external void scrollTo(num? x, num? y); external ScrollInfo getScrollInfo(); diff --git a/pkgs/dartpad_ui/lib/editor/editor.dart b/pkgs/dartpad_ui/lib/editor/editor.dart index 50b918919..6428de9d3 100644 --- a/pkgs/dartpad_ui/lib/editor/editor.dart +++ b/pkgs/dartpad_ui/lib/editor/editor.dart @@ -236,6 +236,7 @@ class _EditorWidgetState extends State implements EditorService { appModel.sourceCodeController.addListener(_updateCodemirrorFromModel); appModel.analysisIssues .addListener(() => _updateIssues(appModel.analysisIssues.value)); + appModel.vimKeymapsEnabled.addListener(_updateCodemirrorKeymap); widget.appServices.registerEditorService(this); @@ -317,6 +318,7 @@ class _EditorWidgetState extends State implements EditorService { widget.appModel.sourceCodeController .removeListener(_updateCodemirrorFromModel); widget.appModel.appReady.removeListener(_updateEditableStatus); + widget.appModel.vimKeymapsEnabled.removeListener(_updateCodemirrorKeymap); super.dispose(); } @@ -432,6 +434,17 @@ class _EditorWidgetState extends State implements EditorService { ); } } + + void _updateCodemirrorKeymap() { + final enabled = widget.appModel.vimKeymapsEnabled.value; + final cm = codeMirror!; + + if (enabled) { + cm.setKeymap('vim'); + } else { + cm.setKeymap('default'); + } + } } // codemirror commands diff --git a/pkgs/dartpad_ui/lib/main.dart b/pkgs/dartpad_ui/lib/main.dart index 9dc4f3328..a7db9053f 100644 --- a/pkgs/dartpad_ui/lib/main.dart +++ b/pkgs/dartpad_ui/lib/main.dart @@ -830,7 +830,10 @@ class StatusLineWidget extends StatelessWidget { builder: (context) => MediumDialog( title: 'Keyboard shortcuts', smaller: true, - child: KeyBindingsTable(bindings: keys.keyBindings), + child: KeyBindingsTable( + bindings: keys.keyBindings, + appModel: appModel, + ), ), ), child: Icon( @@ -1156,9 +1159,11 @@ class ContinueInMenu extends StatelessWidget { class KeyBindingsTable extends StatelessWidget { final List<(String, List)> bindings; + final AppModel appModel; const KeyBindingsTable({ required this.bindings, + required this.appModel, super.key, }); @@ -1209,6 +1214,10 @@ class KeyBindingsTable extends StatelessWidget { ], ), ), + const Divider(), + _VimModeSwitch( + appModel: appModel, + ), ], ); } @@ -1282,6 +1291,32 @@ class _BrightnessButton extends StatelessWidget { } } +class _VimModeSwitch extends StatelessWidget { + final AppModel appModel; + + const _VimModeSwitch({ + required this.appModel, + }); + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: appModel.vimKeymapsEnabled, + builder: (BuildContext context, bool value, Widget? child) { + return SwitchListTile( + value: value, + title: const Text('Use Vim Key Bindings'), + onChanged: _handleToggle, + ); + }, + ); + } + + void _handleToggle(bool value) { + appModel.vimKeymapsEnabled.value = value; + } +} + extension MenuControllerToggleMenu on MenuController { void toggleMenuState() { if (isOpen) { diff --git a/pkgs/dartpad_ui/lib/model.dart b/pkgs/dartpad_ui/lib/model.dart index eaf6a292b..0e0272608 100644 --- a/pkgs/dartpad_ui/lib/model.dart +++ b/pkgs/dartpad_ui/lib/model.dart @@ -75,6 +75,8 @@ class AppModel { final SplitDragStateManager splitDragStateManager = SplitDragStateManager(); late final StreamSubscription _splitSubscription; + final ValueNotifier vimKeymapsEnabled = ValueNotifier(false); + AppModel() { consoleOutput.addListener(_recalcLayout);