HOMING★WONDER
秀丸マクロ インデントhome - カーソル移動サンプル
最終更新:
kouraku_tiritomado
-
view
include_js plugin Error : このプラグインで利用できない命令または文字列が入っています。
include_js plugin Error : このプラグインで利用できない命令または文字列が入っています。
タブインデントに対応したカーソルの行頭移動マクロです。
連続呼び出しで真の行頭とインデント行頭をフラフラします ( VisualStudio 的動作)。
通常範囲選択、BOX範囲選択中でも正常に動作します。
homeキーに対応させて使って下さい。
連続呼び出しで真の行頭とインデント行頭をフラフラします ( VisualStudio 的動作)。
通常範囲選択、BOX範囲選択中でも正常に動作します。
homeキーに対応させて使って下さい。
解説
タブや空白を除く行頭への移動は、正規表現を覚えれば驚くほど簡単です。
通常の行頭に移動した後 "[^ \t]+" を正規表現で検索すればそれでOKで、秀丸の強力なマクロは当然これをサポートしてくれます。
ただし、単に検索をかけただけでは検索バッファに履歴を残したり、
範囲選択中だとカーソル移動のために選択範囲が解除されてしまいます。
これらに対策を行い、カーソル移動系マクロの習作としてきちんと書いてみました。
興味のある方は(マクロヘルプを片手に)ご一読下さい。
通常の行頭に移動した後 "[^ \t]+" を正規表現で検索すればそれでOKで、秀丸の強力なマクロは当然これをサポートしてくれます。
ただし、単に検索をかけただけでは検索バッファに履歴を残したり、
範囲選択中だとカーソル移動のために選択範囲が解除されてしまいます。
これらに対策を行い、カーソル移動系マクロの習作としてきちんと書いてみました。
興味のある方は(マクロヘルプを片手に)ご一読下さい。
初期処理
{ //初期処理 disabledraw; // 描画停止 disableinvert; // 選択反転停止 // 検索状態のバックアップ $strBuf = searchbuffer; #optBuf = searchoption; $strRepBuf = replacebuffer; // 選択状態のバックアップ #isSelect = selecting; #isRectSel = rectselecting; if ( x == seltopx ) #bufSelBeginX = selendx; else #bufSelBeginX = seltopx; if ( y == seltopy ) #bufSelBeginY = selendy; else #bufSelBeginY = seltopy; }
まずはおまじないです。チラツキ防止のお約束として、disabledraw を設定しておきます。
disableinvert の方は、今回は必要ないのですが、使いまわしを考えて出来るだけの予防策を盛り込みました。
disableinvert の方は、今回は必要ないのですが、使いまわしを考えて出来るだけの予防策を盛り込みました。
- disabledraw / enabledraw ... マクロ実行中の画面の更新を禁止 / 許可
- disableinvert / enableinvert ... 範囲選択のときの反転表示を禁止 / 許可
【検索状態のバックアップ】
後述するカーソル移動部分では、下方向検索( searchdown2 )を使用しています。マクロ内で検索を実施すると「下候補」「上候補」に使われる検索データも書き換えます。また、置換を使えば置換単語も書き換えます。マクロ内でこれらの機能を使う場合は、出来るだけマクロ実行前の状態に復帰しておくのがベターです(※)。今回は置換を行っていないので、置換設定については必要ないのですが、使いまわしを考えて出来るだけの予防策を盛り込みました。
後述するカーソル移動部分では、下方向検索( searchdown2 )を使用しています。マクロ内で検索を実施すると「下候補」「上候補」に使われる検索データも書き換えます。また、置換を使えば置換単語も書き換えます。マクロ内でこれらの機能を使う場合は、出来るだけマクロ実行前の状態に復帰しておくのがベターです(※)。今回は置換を行っていないので、置換設定については必要ないのですが、使いまわしを考えて出来るだけの予防策を盛り込みました。
- searchbuffer ...
「下候補」などで使用される最新の検索単語。検索を行うと更新されます。setsearch を使って別の設定に書き換えることが出来ます。
- searchoption
「下候補」などで使用される最新の検索オプション設定。検索を行うと更新されます。setsearch を使って別の設定に書き換えることが出来ます。
- replacebuffer
「置換」などで使用される最新の置換単語。置換を行うと更新されます。setreplace を使って別の設定に書き換えることが出来ます。
これらの値を使った状態取得&復帰は、お定まりのルーチンみたいなものです。
(※)今回は「単にカーソル移動だけ」が目的ですからね。もし、マクロの自動処理でどんな単語を検索したか重要なら、もちろん最新の検索バッファは消さない方が良いと思います。
【選択状態のバックアップ】
homeとして使うマクロが、呼び出すたびに範囲選択を解除するようでは泣いてしまいます。これらもバックアップしておきます。
homeとして使うマクロが、呼び出すたびに範囲選択を解除するようでは泣いてしまいます。これらもバックアップしておきます。
- selecting ...
範囲選択中かどうかを表します。範囲選択中の場合は1、そうでない場合は0です。
- rectselecting ...
BOX範囲選択中かどうかを表します。範囲選択中の場合は1、そうでない場合は0です。
(※)BOX範囲選択中は、selecting フラグも1になっています。
(※)BOX範囲選択中は、selecting フラグも1になっています。
- seltopx / seltopy / selendx / selendy ...
選択範囲を示す変数です。一種の rect 型で、それぞれ seltopx<=selendx, seltopy<=selendy となります。
ここでは選択開始したカーソル座標を判断しています。”マクロ呼び出し時点でカーソルは選択範囲の端に存在している”ので(※) x, y それぞれに、現在のカーソル座標とは異なる方の値を適用すれば、通常選択・BOX選択どちらでも選択開始位置を読み取れます。
(※)範囲選択状態でマクロを呼び出したら、範囲の隅っこに必ずカーソルが位置しているはずです。もしかしたら「マクロ呼び出し時点でカーソルが選択範囲の端っこに存在しない」という例外もあるかもしれません…が、再現方法を思いつけなかったので対策を入れていません。でも、マクロ呼び出し時に選択範囲有効なおかつ、選択範囲からカーソルが離れているなら、検索で選択範囲が消えたとしても、もともとの範囲を復旧するだけで良い気はします。とは言え、検証のしようがないので今回そういう仕様は見送っています。
正規表現検索によるカーソル移動
{ // 正規表現検索によるカーソル移動。 #firstCur = x; moveto 0,y; searchdown2 "[^ \t]+", casesense, regular; if ( result == 0 || ( #firstCur != 0 && #firstCur <= x ) ) moveto 0,y; }
正規表現を使って行頭を検索しています。正規表現の説明は省きます(※)。全角スペースに対応させても良い気がしますが、とりあえず半角スペースとタブ文字のみをインデント文字として認識させました。
有効な文字が見つからない場合(検索失敗)と、カーソルが通常の行頭~インデント行頭の中間にある場合には、通常の行頭に移動するようにします。これで連続実行すると通常の行頭とインデント行頭をフラフラするようになります。どっちでも良いんですが、この場合、moveto でなく golinetop2 を使ってもオッケー。
(※)一応説明すると、 moveto を使って通常の行頭に移動した後「半角スペースあるいはタブではない文字が一つ以上あらわれる位置」を検索しています。ヒット条件に改行文字を含むので、次の行にヒットしないのがミソと言えばミソです。
終了処理
{ // 終了処理 // 選択状態の復帰 if ( #isSelect ) { #bufSelLastX = x; #bufSelLastY = y; moveto #bufSelBeginX, #bufSelBeginY; if ( #isRectSel == 1 ) beginrect; else beginsel; moveto #bufSelLastX, #bufSelLastY; if ( #isRectSel == 0 ) endsel; } // 検索状態の復帰 setsearch $strBuf, #optBuf; setreplace $strRepBuf; enableinvert; // 選択反転再開 enabledraw; // 画面描画再開 }
【選択状態の復帰】
検索によってカーソル移動した後は、範囲選択が解除されています。必要があれば、バックアップを使って復帰させます。
検索によってカーソル移動した後は、範囲選択が解除されています。必要があれば、バックアップを使って復帰させます。
カーソルをもともとの選択開始位置まで戻し、選択モードフラグに応じて beginsel / beginrect を設定します。選択モードに切り替わったら、新たに見つかったインデント位置までカーソルを戻すことで選択範囲が復帰します。選択モードは endsel で解除できます。
- beginsel / beginrect ... 通常の範囲選択 / BOX 範囲選択 を開始する。
- endsel ... 通常の範囲選択(あるいは BOX 範囲選択)を終了する。
ちなみに私の秀丸設定では、範囲選択は shift キー押しっぱなしで行いますが、BOX 選択はトグル的なモード切り替え式にしています。そのため BOX 選択を行っているときには endsel による選択モードの解除を行わないようにしています。そうしないとマクロ実行後、カーソルを移動したら BOX 選択が消えちゃうんですよね…通常の範囲選択のときは shift キーは押しっぱなしなので大丈夫なんですが…。
【検索状態の復帰】
決まりきっているお約束です。【検索状態のバックアップ】に記述したとおり、検索ダイアログにゴミを残さないようにします。
ついでに、enableinvert, enabledraw も設定して、状態をマクロ実行前に復帰させます。
決まりきっているお約束です。【検索状態のバックアップ】に記述したとおり、検索ダイアログにゴミを残さないようにします。
ついでに、enableinvert, enabledraw も設定して、状態をマクロ実行前に復帰させます。
感想
気がつけば肝心のカーソル移動のコードより、初期化と後始末が大半のコードになってしまいましたね!
行頭移動自体はなんの変哲もないマクロですし、カーソル移動を目的にしたマクロの雛形にしてもらえれば幸いです。
行頭移動自体はなんの変哲もないマクロですし、カーソル移動を目的にしたマクロの雛形にしてもらえれば幸いです。
ちなみにコードに無名スコープ(意味のない{}カッコ)を使っていますが、コレ自体には何の意味もありません。意味的にまとめるだけのものです。
見たことのない人は若干気持ち悪いかもしれませんが、秀マクロはもちろん主要なCコンパイラでもサポートされています。しかし、秀マクロではローカルスコープとしては動作しないので「コードを目的別にまとめてネストすれば、個人的には見やすいかな~」という程度のものです。(Perlみたいに「無名スコープ+ローカル宣言」が通れば変数名重複時の安全性が上がると思いますが、エディタマクロとしては過剰機能なんでしょうね)
このへんは、各人読みやすいように再編してもらえるとありがたいです。