前置き
Atom で自分の Package 以外に最も気にして PR を投げたりしているのは vim-mode なのですが、色々と事を進めるにあたり、リファクタリングの必要も感じています(自分ができるかどうかはおいといて)。
今回、表題の件について自分なりに考え、vim-mode の issue に記録として書いておきました。
[NOTE] What is Motion, TextObject, Operator
以下は、その翻訳です。私はそれほど英語は得意ではないですが、英語でまず最初に書いて、日本語に訳すという流れになっている。
翻訳をする理由は2つあり、ひとつは自分の理解をさらに確かめ、深める為と、もうひとつは、日本人からのフィードバックを期待しているからです。
Motion, TextObject, Operator とは何なのか?
このノートは、Vim の主要な概念である Motion, TextObject, Operator についてまとめたものである。
今後のリファクタリングや、TextObject, Motion, Operator オブジェクトをサービスAPIで公開する際に役に立てば嬉しい。
TextObject と Motion
両方共とても似ている。概念も実装も。
- Motion も TextObject も end(ターゲット位置)ポジションを持つ.
- TextObject は start ポジションを要求する。Motion はしない。言い換えれば、Motion の start ポジションは常に現在のカーソル位置になる。
- 全ての TextObject は Motion のスーパーセットである。
- よって、全ての TextObject は Motion としても使用可能。逆は出来ない。
e.g. TextObject for function は、function body(=TextObject) を yank, delete するのに使える。また、次や、前の function 位置に移動(=Motion)するのにも使える。 - Motion も TextObject も Operator のターゲット(=対象)として使える。
Operator
- Operator はアクションである。アクションはターゲットを要求する。
- ターゲットは、通常 Motion か TextObject である、概念的には、範囲を返す全てのオブジェクトはターゲットになることが出来る。
Visual mode
Visual mode は特別である。暗黙的な Operator と、TextObject を持っているという点において。
- 本質的には、visual-mode は modal エディタである Vim のモードの一つである。
- Visual-mode で Operator コマンドが実行(invoke)されると、暗黙的な "TextObject for selection" が Operator のターゲットとして使われる。
- Visual-mode で
i
(inside) やa
(a or around)を使って、TextObject コマンドが実行(invoke)されると、暗黙的な "select Operator" が Operator として使用される。 - TextObject for selection は現在の visual area(選択範囲)を返す。
- Select Operator は visual area(選択範囲) を TextObject が返した範囲に拡張する。
コンセプト実装
上記の概念を CoffeeScript で実装したもの。
class Motion
constructor: (@editor) ->
getStartPoint: ->
@editor.getCursorBufferPosition()
getEndPoint: ->
throw "Motion must implement `getEndPoint()`"
getRange: ->
new Range(@getStartPoint(), @getEndPoint())
execute: ->
@editor.setCursorBufferPosition(@getEndPoint())
class TextObject extends Motion
getStartPoint: ->
throw "TextObject must implement `getStartPoint()`"
class Operator
constructor: (@editor) ->
operate: (range) ->
throw "Operator must implement `operate(range)`"
# target is Motion or TextObject, but all object can be target as long as
# its respond to getRange().
execute: (target) ->
@operate target.getRange()
# Visual mode's implict TextObject and Operator
class TextObjectSelection extends TextObject
getRange: ->
@editor.getSelectedBufferRange()
class OperatorSelect extends Operator
operate: (range) ->
@editor.setSelectedBufferRange range