お次は空行へジャンプするコマンド } { を実装してみよう。
} は文書末尾方向に、{ は文書先頭方向に空行を検索する。空行が存在しない場合は最後の行・最初の行にカーソル移動する。
数値を前置した場合は、その数だけ空行を検索する。
ViMoveOperation にシンボルを追加し、doViCommand() で '}'、'{' を見つけたら、moveCursor() をコールするだけだ。 moveCursor() の中では switch 文で処理を分け、実際にカーソル移動する関数 gotoBlankLine() をコールしている。
ViEngine::doViCommand() から直接 gotoBlankLine() をコールした方が、余計な中間管理が入らずいいような気もする。 後で要検討。
1: namespace ViMoveOperation { 2: enum { 3: Left = 100, // h 4: ..... 5: NextBlankLine, // } 6: PrevBlankLine, // { 7: }; 8: }
1: bool ViEngine::doViCommand(const QChar &qch) 2: { 3: ..... 4: switch( ch ) { 5: ..... 6: case '}': 7: cursorMoved = moveCursor(cur, ViMoveOperation::NextBlankLine, repeatCount()); 8: break; 9: case '{': 10: cursorMoved = moveCursor(cur, ViMoveOperation::PrevBlankLine, repeatCount()); 11: break; 12: } 13: ..... 14: }
1: bool moveCursor(QTextCursor &cur, int mv, int n) 2: { 3: ..... 4: switch( mv ) { 5: ..... 6: case ViMoveOperation::NextBlankLine: 7: return gotoBlankLine(cur, /*forward=*/true, n); 8: case ViMoveOperation::PrevBlankLine: 9: return gotoBlankLine(cur, /*forward=*/false, n); 10: } 11: ..... 12: }
実際に空行を探す関数は以下の様になる。 テキストブロックから文字列を取り出し、その長さをチェックすることで空行かどうかを判定している。
1: bool gotoBlankLine(QTextCursor &cur, bool forward, int n) 2: { 3: QTextBlock block = cur.block(); 4: if( !block.isValid() ) return false; 5: int lastPos = block.position(); 6: while( --n >= 0 ) { 7: // 空行を読み飛ばす 8: while( block.text().length() == 0 ) { 9: block = forward ? block.next() : block.previous(); 10: if( !block.isValid() ) { 11: cur.setPosition(lastPos); 12: return true; 13: } 14: lastPos = block.position(); 15: } 16: // 空行まで読み飛ばす 17: while( block.text().length() != 0 ) { 18: block = forward ? block.next() : block.previous(); 19: if( !block.isValid() ) { 20: cur.setPosition(lastPos); 21: return true; 22: } 23: lastPos = block.position(); 24: } 25: } 26: cur.setPosition(lastPos); 27: return true; 28: }