お次は空行へジャンプするコマンド } { を実装してみよう。
} は文書末尾方向に、{ は文書先頭方向に空行を検索する。空行が存在しない場合は最後の行・最初の行にカーソル移動する。
数値を前置した場合は、その数だけ空行を検索する。
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: }