n行を連結して1行にする J コマンドを実装する。
話は単純で、コマンド文字が 'J' だったら doJoin() という処理メソッドを呼ぶ。 J コマンドは .(redo) 対象だが delFrom も toInsertMode も設定しないので、新たに toUpdateRedoCmd というフラグを導入する。 このフラグが立っている場合は .(redo) のためにコマンド文字列を記録する。
1: bool ViEngine::doViCommand(const QChar &qch)
2: {
3: .....
4: bool toUpdateRedoCmd = false;
5: .....
6: switch( ch ) {
7: .....
8: case 'J':
9: doJoin(repeatCount());
10: toUpdateRedoCmd = true;
11: break;
12: .....
13: }
14: .....
15: if( (delFrom >= 0 && delFrom < delTo || toUpdateRedoCmd || toInsertMode)
16: && !m_redoing )
17: {
18: if( m_cmdPrefix != 0 )
19: m_redoCmd = QChar(m_cmdPrefix);
20: m_redoCmd += qch;
21: m_redoRepeatCount = m_repeatCount;
22: }
23: .....
24: }
行をJoinする処理は以下のようになる。注意すべきは n の意味。n は連結回数ではなく、何行をひとつにするか、という意味である。 (しかしながら、1J は2行を連結する。その訳を責任者に問いただしたい。責任者はどこか?)
QTextCursor オブジェクトを使って、改行部分を選択して半角空白を挿入することで連結処理を行っている。 挿入処理全体を、beginEditBlock()、endEditBlock() で囲むことで、3行以上を連結した場合でも1回のundoで元に戻れるようにしている。
1: void ViEngine::doJoin(int n)
2: {
3: QTextCursor cur = m_editor->textCursor();
4: int pos = cur.position();
5: cur.beginEditBlock();
6: do {
7: QTextBlock block = cur.block();
8: QTextBlock next = block.next();
9: if( !next.isValid() ) break;
10: cur.setPosition(pos = block.position() + block.text().length());
11: cur.setPosition(next.position(), QTextCursor::KeepAnchor);
12: cur.insertText(" ");
13: } while( --n > 1 ); // 2J までは1回だけjoin
14: cur.endEditBlock();
15: cur.setPosition(pos); // 最後の空白位置に移動
16: m_editor->setTextCursor(cur);
17: }