はじめに
atomのvim-mode-plusはvimと同様、insert modeで色々変更した後にnormal modeに戻ってundoすると変更が全て戻ってしまいます。
以下のリンク2つ目のgifがわかりやすいです。
Undo/ReDo behavior completely broken
overactive undo when vim-mode is enabled
これが本当に不便だったので、なんとかすることにしました。
対応策
insertモードからnormalモードに戻るとundo履歴が区切られるようだったので、スペースとエンター(改行)を入力したときに、いったんノーマルモードに戻り、またインサートモードに入るようにしました。
スペースと改行の時に区切られて欲しかったので、今回はスペースと改行コマンドを改造してノーマルモードとインサートモードの移動処理を差し込みます。
コード
init.coffeeにオリジナルコマンドを定義し、それをインサートモードのスペースとエンターに定義しなおします。
.atom/init.coffee
# undoに区切りをつけるため、キー実行前にvimのmodeを変える
atom.commands.add 'atom-text-editor.vim-mode-plus.insert-mode', 'custom:key-with-mode-change', (e) ->
editor = @getModel()
modeChange(editor)
e.abortKeyBinding()
modeChange = (editor) ->
view = atom.views.getView atom.workspace.getActiveTextEditor()
column = editor.getCursorBufferPosition().column
atom.commands.dispatch view, 'vim-mode-plus:activate-normal-mode'
if column is 0
atom.commands.dispatch view, 'vim-mode-plus:activate-insert-mode'
else
atom.commands.dispatch view, 'vim-mode-plus:insert-after'
.atom/keymap.cson
'atom-text-editor.vim-mode-plus.insert-mode':
'space': 'custom:key-with-mode-change'
'enter': 'custom:key-with-mode-change'
上記の設定を書き込むことでとりあえず使えるようになりました。
もしかしたら何かしらの不都合が起きるかもしれませんが、いったんこれで使ってみます。
※ 2017/9/13現在、vim-mode-plusの設定のgroupChangesWhenLeavingInsertMode のチェックを外す(デフォルトはチェック有り)ことでinsert modeのundo履歴を区切ることができます。
今回の実装はスペースと改行を打つとundo履歴を区切りますが、groupChangesWhenLeavingInsertModeは時間でundo履歴を区切るという違いがあります。
参考
* 1つのキーバインドで、同時に複数のコマンドを実行する
* Keymaps In-Depth
* How to get cursor position as buffer offset (one dimensional, in chars)?
2017/07/21 追記
行頭にスペースや改行を入れる時にうまくいかなかったので、1列目の時の特別処理を追加
2017/08/06 追記
改行コードやスペースをinsertText
する処理だとc++などのコーディング時に変な挙動をしたため、abortKeyBinding
で元の処理に戻すようにした
2017/09/13 修正&追記
t9mdさんの指摘を受け、
「atomのvim-mode-plusには2017/07/19現在、undoが戻りすぎるバグがあります。」
を
「atomのvim-mode-plusはvimと同様、insert modeで色々変更した後にnormal modeに戻ってundoすると変更が全て戻ってしまいます。」
に変更
「groupChangesWhenLeavingInsertMode」について追記