番号 | 記号 | 初期キー | 機能 |
---|---|---|---|
#46 | #b | ^B [F10] | ブロックモードの指定 |
ブロックモードの指定
戻り値 r:常に0
ブロックモードの有効/無効を指定する。非ブロックモードで実行した場合,ブロックモードに移行するとともに,実行位置をブロックの始点に設定する。ブロックモードで実行した場合は,ブロックモードを解除する。つまり,#46
(#b
)はブロックモードをトグルで切り替えると同時にブロック始点のリセットを実行するコマンドである。ブロックモードは,システム変数mbのオン/オフで切り替えることができるので,mb-
により明示的にオフにすることができる。但し,mb+
でブロックモードに入ることは可能だが,ブロック始点のリセットはしないので,状況に応じて使い分ける必要がある。
#b
とmbの関係はnifty:FGALPKの時代にEmmett氏が言及しているので,以下に引用する。
・mb==0 のとき、 #b → ブロック開始ポインタをカーソル位置に変更する。 mb+ → 前回指定された位置から変化しない。 ・mb!=0 のとき、 #b → 前回指定された位置から変化しない。 mb- → 前回指定された位置から変化しない。また、
mb-
でブロックを解除すれば、サイレントフラグが OFF のときは画面の書き換えを行わない。
コマンド#46
(#b
)を実行すると,カーソル位置に「ブロックマーク」が設定される。編集テキストに特段の変化があるわけではないが,ウィンドウ上端のステータスラインの「□」印が反転し,ブロックモードに入ったことが通知される。そこからカーソルを何れかの方向に移動すると,表示属性Ahで指定された背景色でブロック領域が可視化される。ブロック領域におけるカーソル位置の反対側がブロックの開始ポイントとして,wa+110
の4バイトにロング整数で保存されている。
ブロックの開始位置は自動的に記憶されるが,変更されるタイミングについて Emmett氏が言及しているので引用する。
※ブロック始点変更のタイミング
- #b でブロックモードに移行した時。
- #i #p によって、テキストスタックから編集テキストへブロックや行がペーストされた時。この場合、ペーストされたのがブロックである場合にはその先頭が、また、ペーストされたのが行である場合にはペーストされた次の行の先頭が、おのおの新たなブロックの始点の位置になる。
システム変数mbの値は0と1だけではない。#b
を実行した直後はmbは1で行ブロックモードであるが,カーソルを左右に文字単位で動かすとmbは2の文字ブロックモードになる。カーソルを上下に行単位で動かすと行ブロックモードになる。矩形ブロックモードにはカーソルの移動だけでは入れないため,マクロでmbに4(ビット4の立っている値)を設定する(値は各マクロに依存する)。
mb * ブロックモード 0 : 非ブロックモード 1 : 行境界のブロックモード 2 : 文字境界のブロックモード 4 : 矩形ブロックモード
ブロックマーク位置から左右上下にカーソルを移動することで,ブロック範囲とブロックの方向が定まる。ブロックの方向とは,ブロックマーク位置よりも後ろ(メモリ上の上位)にカーソルがある状態を「正」,その逆にカーソル位置がブロックマーク位置より前(メモリ上の下位)にある状態を「逆」ととらえられ,その方向を判定するための「ブロック範囲比較変数」xcがある。
xcの値 | 値の意味 | cp:カーソル位置,tblkp:ブロックマーク位置 |
---|---|---|
-1 | カーソルはブロック開始位置より前 | cp < tblkp |
0 | カーソルはブロック開始位置のまま | cp = tblkp |
1 | カーソルはブロック開始位置より後 | cp > tblkp |
xcについては,Emmett氏の以下の考察がある。(一部を編集)
ブロックモードが解除されていても、ブロックの始点は生きているから、非ブロックモードでもこの変数は使える。但しこの場合には、以下のとおり,変数の意味が少々変わる。
※ブロックモードでのxc (PK/14/10167/Emmett) xcの値 非ブロックモードでの値の意味 -1 カーソルはブロック開始位置より前の論理行にある 0 カーソルはブロック開始位置と同じ論理行にある 1 カーソルはブロック開始位置より後の論理行にある
ブロック範囲は,編集コマンド#47
(#y
) 及び #49
(#k
)を実行すると,「テキストスタック」と呼ばれる最大64KBのメモリに格納される。非ブロックモード時と同様に#47
は切除(カット),#49
は複写(コピー)であり,ブロック範囲と論理行の違いだ。このテキストスタックは,その名の通りスタック(棚)であり,最後に積んだものを最後に出すという規則の制約があるバッファである。ユーザが直接参照可能なオフセットアドレスではアクセスできないセグメント(kz)にある。ユーザが参照できるのは,標準の変数/関数が用意されている以下の項目である。
変数名/関数名 | 種別 | 機能 |
---|---|---|
kz | セグメント変数 | テキストスタックのセグメント |
kp | セグメント変数 | テキストスタックのエンドオフセット |
3(p) | コマンド関数 | テキストスタッククリア |
&Bm | 特殊関数 | テキストスタック先頭のブロックタイプ |
テキストスタックの構造についての詳細は,「テキストスタックの構造」を参照されたい。
なお,テキストスタックに格納された時点で保存される情報は,ブロックタイプ(行/行ブロック/文字ブロック/矩形ブロック)とブロックサイズである。ブロック時のカーソル位置を再現するための情報は持っていないため,ブロック挿入後のカーソル位置を制御するには,編集スイッチEkに依存することになる。Ekはブロックの挿入後にカーソルをブロックの最後に位置させるオプションで,初期値は-(無効)である。
そのほか,一時的に文字,行,ブロック削除時にバッファへの格納を禁止するオプションux(v1.6)がある。これはVZの基本的機能を抑止するという,ある意味「危険」なものであるが,マクロの中断時・終了時にはリセットされるように配慮されている。
前項のブロックタイプの判定において実際に参照しているところはテキストスタックであるわけだが,具体的にどこを見ているのか明らかにするため,テキストスタックの構造を見てゆこう。引用元はnifty:FGALPK/14/09884,Emmett氏のテキストスタックエンドオフセット(kp)に関する解説である。
─┬──┬──┬──┐-----+-----+-----+ ----+-------------- │ │ │ │ (1) | (2) | ★ | ─┴──┴──┴──┘-----+-----+-----+ ----+-------------- ここまでが文字列 ←│kp.-3 kp..-1 ↑このアドレスがkp (1) kp.-3 : ブロックタイプ(0:行,1:行境界,2:字境界,他:矩形) =&Bmの返り値 (2) kp..-1 : ブロックサイズ(文字列の長さ)単位byte
ちなみに,kp.-3
にあるブロックタイプは,最後に積み込んだブロックであれば,確認する関数が標準で用意されている。
&Bm ★テキストスタック先頭のブロックタイプ r = 0 : 行 r = 1 : 行ブロック r = 2 : 文字ブロック r = else : 矩形ブロック
ブロックモードに入るには,#46(#b)の他にmb(ブロックモード)がある。mbを有効にすると,現カーソル位置と保存されたブロックマーク位置の情報を元にブロックモードとなる。但し,ブロックモードには行ブロックと文字ブロックの違いがあるだけでなく,矩形ブロックモードもあることに注意しなければならない。また,それ以上に,直前のブロックマーク位置が何処であるのか把握できていなければならない。したがって,直前のブロック範囲を認識しているタイミングでしか mb は使えないだろう。
製品版サンプルVZ[IBM[J]].DEFの標準組込マクロに「ペーストのアンドゥ」(初期キー^KU)がある。このマクロは,ブロックペースト(#i及び#p)の実行後の戻り値rにブロックモードが格納される仕様を利用したもので,ペースト直後にrからmbに書き戻せばブロックを再現できるので,擬似的なアンドゥを実現できるというものだ。
20 ^KU "ペーストのアンドゥ" ;Undo Paste [r]: -0 =1 |2 ?. mb=r, #y
無効
無効
無効
無効
#46(#b)は非常に基本的かつ代えがたい機能を持つコマンドであるし,トグル動作であるということもあって,裏機能を持たせるというのは難しいが,そんな固定観念を打ち砕いたのが上村郁夫の「Reblock−リブロック」…ブロック範囲の復元である。
実際のブロック再現は少々複雑な手続きが必要で,完璧に再現することは不可能であるのだが,良い加減のところで動作を見切っているのが上村郁夫氏のReblock.defである。ブロックマークとカーソル位置を往復して論理行番号を比較し,同じ行内にあれば文字ブロック,異なる行なら行ブロックとして処理するため,改行を挟んだ文字ブロックには対応していないことになるが,そのような場合はカーソルを前後してやればよいことである。これはバグではなくて仕様だ。
46 ^B "" ;Reblock[\] Ikuo ?. (ks&1)??{ #b. } &s #B n=ln, #B (ln==n) mb+, ? mb=2, &d
#46(#b)の拡張ではなく,矩形ブロック関連のマクロである。矩形ブロックを扱うマクロ(製品版添付ではblock.def)を使って再利用する予定のない矩形ブロックを切除したのち,時としてカット&ペーストのはずみに出力されてしまって,編集テキストがひどく損なわれてしまうことがある。これは矩形ブロックの落し穴でもあるのだが,切除後に再利用予定がなければブロックのタイプを変えておく。これによって,出力されるのは最初の行だけなので最悪の状態にはならない。矩形ブロックには対応していないペーストのアンドゥで出力前に戻せる。また,用途も限定されるが,矩形で切除したブロックを連結させることができる。いずれにしても,ブロックタイプの変更とテキストスタック操作のサンプルとして参考にしてほしい。
84 "スタック先頭のブロックタイプ変更" ;= kb_chang = by H_ear ?. &Bm (r<3)?. dz[=kz, k=kp, :L (k.-3>2)?{ k.-3=2, l=k..-1, k-=3+l, >L } dz], &m("先頭のブロックタイプを変更しました") &w(60) .