本稿では、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: }