本稿では、I a A コマンドを実装する。
最初に i コマンドで挿入モードに遷移するようにしたが、挿入モードに遷移するコマンドは i だけではない。
様々に移動しつつ挿入モードに遷移することができる。
a はカーソルをひとつ進めて挿入モードに遷移する。I は現在行の最初の非空白文字位置に移動して挿入モードに遷移する。
A は改行位置に移動して挿入モードに遷移する。わざわざカーソル移動してから挿入モードに遷移する必要がないので、打鍵回数が減る。
1: printf("hello, world.\n");
例えば上記の行にカーソルがあれば、どの文字にカーソルがあっても、I を押すと print の前に、A を押せば ; の直後に文字を挿入することができる。
vi 独自の移動コマンドにはすべてシンボルを割り当てることにする。
1: namespace ViMoveOperation {
2: enum {
3: Left = 100, // h
4: Down, // j
5: Up, // k
6: Right, // l
7: RightForA, // a
8: FirstNonBlankChar, // ^
9: LastChar, // $
10: NextLine, // + Enter
11: PrevLine, // -
12: };
13: }
1: bool ViEngine::cmdModeKeyPressEvent(QKeyEvent *event)
2: {
3: .....
4: case 'a':
5: m_editor->moveCursor(ViMoveOperation::RightForA);
6: // 下にスルー
7: case 'i':
8: setMode(INSERT); // i が押されたら挿入モードへ
9: break;
10: case 'A':
11: m_editor->moveCursor(QTextCursor::EndOfBlock);
12: setMode(INSERT);
13: break;
14: case 'I':
15: m_editor->moveCursor(ViMoveOperation::FirstNonBlankChar);
16: setMode(INSERT);
17: break;
18: .....
19: }
1: bool ViEngine::cmdModeKeyPressEvent(QKeyEvent *event)
2: {
3: .....
4: switch( mv ) {
5: case ViMoveOperation::Up:
6: mv = QTextCursor::Up;
7: break;
8: case ViMoveOperation::Down:
9: mv = QTextCursor::Down;
10: break;
11: case ViMoveOperation::Left:
12: n = qMin(n, pos - blockPos);
13: mv = QTextCursor::Left;
14: break;
15: case ViMoveOperation::Right: {
16: if( blockText.isEmpty() ) return; // 改行 or EOF オンリー行の場合
17: const int endpos = blockPos + blockText.length() - 1;
18: if( pos >= endpos ) return;
19: n = qMin(n, endpos - pos);
20: mv = QTextCursor::Right;
21: break;
22: }
23: case ViMoveOperation::RightForA: // 右移動 for a コマンド
24: if( blockText.isEmpty() ) return; // 改行 or EOF オンリー行の場合
25: if( pos >= blockPos + blockText.length() ) return;
26: cur.setPosition(pos + 1);
27: moved = true;
28: break;
29: .....
30: }
31: .....
32: }