Vz Editor
2007-05-07T21:05:28+09:00

コマンド拡張で学ぶVZマクロ入門 #46

番号記号初期キー機能
#46#b^B [F10]ブロックモードの指定

s==0(編集モード)

ブロックモードの指定

戻り値 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氏が言及しているので引用する。

※ブロック始点変更のタイミング

ブロックの種類と方向

システム変数mbの値は0と1だけではない。#bを実行した直後はmbは1で行ブロックモードであるが,カーソルを左右に文字単位で動かすとmbは2の文字ブロックモードになる。カーソルを上下に行単位で動かすと行ブロックモードになる。矩形ブロックモードにはカーソルの移動だけでは入れないため,マクロでmbに4(ビット4の立っている値)を設定する。(値は各マクロに依存する)

 mb  *     ブロックモード
   0  : 非ブロックモード
   1  : 行境界のブロックモード
   2  : 文字境界のブロックモード
   4  : 矩形ブロックモード

ブロックマーク位置から左右上下にカーソルを移動することで,ブロック範囲とブロックの方向が定まる。ブロックの方向とは,ブロックマーク位置よりも後ろ(メモリ上の上位)にカーソルがある状態を「正」,その逆にカーソル位置がブロックマーク位置より前(メモリ上の下位)にある状態を「逆」ととらえられ,その方向を判定するための「ブロック範囲比較変数」xcがある。

xc:ブロック範囲比較変数(v1.6以降)
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セグメント変数テキストスタックのエンドオフセット
&#51(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

ブロックモードに入るには,#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

s==1(文字列入力モード)

無効

s==2(コマンドラインモード)

無効

s==3(ファイラーモード)

無効

s==4(メニュー)

戻り値rの内容

s==4(1文字入力モード)

無効

マクロによる拡張

ブロック範囲の復元

#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) .


コマンド拡張で学ぶVZマクロ入門 #46
The VZ resources, valid XHTML 1.0 Strict. ©2007-2018 by mezala.