|
|
| (4人の利用者による、間の20版が非表示) |
| 1行目: |
1行目: |
| <div>__TOC__</div>
| | このマクロは[https://www.haijin-boys.com/software/mery/mery-3-6-0#17 Mery Ver 3.6.1]で追加されたコマンド「対応する括弧へ移動」と同機能です。 |
|
| |
|
| = Kuro, kurama 版 (2009/08) = | | == Kuro, kurama 版 == |
| * 「shift」変数を「true」に書き換えると、選択しながら移動します。
| | 対応する括弧に移動します。「shift」変数を「true」に設定した場合は選択しながら移動します。 |
|
| |
|
| <source lang="javascript"> | | <syntaxhighlight lang="javascript" copy> |
| // ----------------------------------------------------------------------------- | | // ----------------------------------------------------------------------------- |
| // 対応する括弧に移動 | | // 対応する括弧に移動 |
| // | | // |
| // Copyright (c) Kuro. All Rights Reserved. | | // Copyright (c) Kuro. All Rights Reserved. |
| // www: http://www.haijin-boys.com/ | | // www: https://www.haijin-boys.com/ |
| // Special Thanks for Kurama さん, Take さん | | // Special Thanks for Kurama さん, Take さん |
| // ----------------------------------------------------------------------------- | | // ----------------------------------------------------------------------------- |
| 22行目: |
22行目: |
| // ステータスバーを消去 | | // ステータスバーを消去 |
| Status = ""; | | Status = ""; |
| with (document.selection) {
| | // Selection オブジェクトを取得 |
| // カーソル位置を保存
| | var sel = document.selection; |
| var ax = GetActivePointX(mePosLogical);
| | // カーソル位置を保存 |
| var ay = GetActivePointY(mePosLogical);
| | var ax = sel.GetActivePointX(mePosLogical); |
| // スクロール位置を保存
| | var ay = sel.GetActivePointY(mePosLogical); |
| var sx = ScrollX;
| | // スクロール位置を保存 |
| var sy = ScrollY;
| | var sx = ScrollX; |
| // カーソル位置を復元
| | var sy = ScrollY; |
| SetActivePoint(mePosLogical, ax, ay, false);
| | // カーソル位置を復元 |
| // 単語を選択
| | sel.SetActivePoint(mePosLogical, ax, ay, false); |
| SelectWord();
| | // 単語を選択 |
| // 現在位置の括弧を取得
| | sel.SelectWord(); |
| var c1 = Text;
| | // 現在位置の括弧を取得 |
| // 選択範囲を解除
| | var c1 = sel.Text; |
| Collapse();
| | // 選択範囲を解除 |
| var l = lp.indexOf(c1);
| | sel.Collapse(); |
| var r = rp.indexOf(c1);
| | var l = lp.indexOf(c1); |
| var st = 0;
| | var r = rp.indexOf(c1); |
| if (l > -1) {
| | var st = 0; |
| // 対応する括弧の種類を取得
| | if (l > -1) { |
| var c2 = rp.charAt(l);
| | // 対応する括弧の種類を取得 |
| EndOfDocument(true);
| | var c2 = rp.charAt(l); |
| var s = Text;
| | sel.EndOfDocument(true); |
| // カーソル位置を復元
| | var s = sel.Text; |
| SetActivePoint(mePosLogical, ax, ay, false);
| | // カーソル位置を復元 |
| // スクロール位置を復元
| | sel.SetActivePoint(mePosLogical, ax, ay, false); |
| ScrollX = sx;
| | // スクロール位置を復元 |
| ScrollY = sy;
| | ScrollX = sx; |
| var x = ax;
| | ScrollY = sy; |
| var y = ay;
| | var x = ax; |
| for (var i = 0; i < s.length; i++) {
| | var y = ay; |
| x++;
| | for (var i = 0; i < s.length; i++) { |
| if (s.charAt(i) == c1)
| | x++; |
| st++;
| | if (s.charAt(i) == c1) { |
| if (s.charAt(i) == c2)
| | st++; |
| st--;
| | } |
| if (st == 0) {
| | if (s.charAt(i) == c2) { |
| y = GetActivePointY(mePosLogical);
| | st--; |
| // カーソル位置を復元
| | } |
| SetActivePoint(mePosLogical, ax, ay, false);
| | if (st == 0) { |
| SetActivePoint(mePosLogical, x, y, shift);
| | y = sel.GetActivePointY(mePosLogical); |
| // 左に戻る
| | // カーソル位置を復元 |
| CharLeft(shift, 1);
| | sel.SetActivePoint(mePosLogical, ax, ay, false); |
| break;
| | sel.SetActivePoint(mePosLogical, x, y, shift); |
| }
| | // 左に戻る |
| if (s.charAt(i) == "\n") {
| | sel.CharLeft(shift, 1); |
| x = 1;
| | break; |
| y = GetActivePointY(mePosLogical) + 1;
| | } |
| SetActivePoint(mePosLogical, x, y, false);
| | if (s.charAt(i) == "\n") { |
| StartOfLine(false, mePosLogical);
| | x = 1; |
| x = GetActivePointX(mePosLogical);
| | y = sel.GetActivePointY(mePosLogical) + 1; |
| }
| | sel.SetActivePoint(mePosLogical, x, y, false); |
| }
| | sel.StartOfLine(false, mePosLogical); |
| } else if (r > -1) {
| | x = sel.GetActivePointX(mePosLogical); |
| // 対応する括弧の種類を取得
| | } |
| var c2 = lp.charAt(r);
| | } |
| CharRight(false, 1);
| | } else if (r > -1) { |
| StartOfDocument(true);
| | // 対応する括弧の種類を取得 |
| var s = Text;
| | var c2 = lp.charAt(r); |
| // カーソル位置を復元
| | sel.CharRight(false, 1); |
| SetActivePoint(mePosLogical, ax, ay, false);
| | sel.StartOfDocument(true); |
| // スクロール位置を復元
| | var s = sel.Text; |
| ScrollX = sx;
| | // カーソル位置を復元 |
| ScrollY = sy;
| | sel.SetActivePoint(mePosLogical, ax, ay, false); |
| var x = ax;
| | // スクロール位置を復元 |
| for (var i = s.length - 1; i >= 0; i--) {
| | ScrollX = sx; |
| x--;
| | ScrollY = sy; |
| if (s.charAt(i) == c1)
| | var x = ax; |
| st++;
| | for (var i = s.length - 1; i >= 0; i--) { |
| if (s.charAt(i) == c2)
| | x--; |
| st--;
| | if (s.charAt(i) == c1) { |
| if (st == 0) {
| | st++; |
| y = GetActivePointY(mePosLogical);
| | } |
| // カーソル位置を復元
| | if (s.charAt(i) == c2) { |
| SetActivePoint(mePosLogical, ax, ay, false);
| | st--; |
| SetActivePoint(mePosLogical, x, y, shift);
| | } |
| // 右に進む
| | if (st == 0) { |
| CharRight(shift, 1);
| | y = sel.GetActivePointY(mePosLogical); |
| break;
| | // カーソル位置を復元 |
| }
| | sel.SetActivePoint(mePosLogical, ax, ay, false); |
| if (s.charAt(i) == "\n") {
| | sel.SetActivePoint(mePosLogical, x, y, shift); |
| x = 1;
| | // 右に進む |
| y = GetActivePointY(mePosLogical) - 1;
| | sel.CharRight(shift, 1); |
| SetActivePoint(mePosLogical, x, y, false);
| | break; |
| EndOfLine(false, mePosLogical);
| | } |
| x = GetActivePointX(mePosLogical);
| | if (s.charAt(i) == "\n") { |
| }
| | x = 1; |
| }
| | y = sel.GetActivePointY(mePosLogical) - 1; |
| } else {
| | sel.SetActivePoint(mePosLogical, x, y, false); |
| // 括弧が無い場合は元の位置に戻す
| | sel.EndOfLine(false, mePosLogical); |
| SetActivePoint(mePosLogical, ax, ay, false);
| | x = sel.GetActivePointX(mePosLogical); |
| Status = "カーソル位置に括弧が見つかりませんでした";
| | } |
| }
| | } |
| if (st != 0) {
| | } else { |
| SetActivePoint(mePosLogical, ax, ay, false);
| | // 括弧が無い場合は元の位置に戻す |
| Status = "対応する括弧が見つかりませんでした";
| | sel.SetActivePoint(mePosLogical, ax, ay, false); |
| }
| | Status = "カーソル位置に括弧が見つかりませんでした"; |
| | } |
| | if (st != 0) { |
| | sel.SetActivePoint(mePosLogical, ax, ay, false); |
| | Status = "対応する括弧が見つかりませんでした"; |
| } | | } |
| // 描画開始 | | // 描画開始 |
| Redraw = true; | | Redraw = true; |
| </source> | | </syntaxhighlight> |
| <br>
| |
|
| |
|
| = masme 版 = | | == masme 版 == |
| * ステータスバーに括弧間の文字数を表示するようにしました。 | | * ステータスバーに括弧間の文字数を表示するようにしました。 |
| * Kuro, kurama 版の不安定な挙動を調整しました。 | | * Kuro, kurama 版の不安定な挙動を調整しました。 |
| 131行目: |
134行目: |
| ** 開き括弧の直前ではなく、直後に移動する場合<sup>※</sup>があるのを修正。直前に移動するよう統一した。<br>※カーソル右側が改行か[EOF]の場合。改行をまたぐ移動になる場合。対応する括弧が行頭にある場合。 | | ** 開き括弧の直前ではなく、直後に移動する場合<sup>※</sup>があるのを修正。直前に移動するよう統一した。<br>※カーソル右側が改行か[EOF]の場合。改行をまたぐ移動になる場合。対応する括弧が行頭にある場合。 |
|
| |
|
| == 更新履歴 == | | === 変更履歴 === |
| * 2019/04/12 | | * 1.0.2 (2019-04-12) |
| ** Quit() → break ラベル文に変更。 | | ** Quit() → break ラベル文に変更 |
| * 2017/05/27 | | * 1.0.1 (2017-05-27) |
| ** 処理方法を正規表現検索 → 文字列検索に変更し、高速化。 | | ** 処理方法を正規表現検索 → 文字列検索に変更し、高速化 |
| ** 対応する括弧が見つからなかった場合、選択解除する → しない仕様に変更。 | | ** 対応する括弧が見つからなかった場合、選択解除する → しない仕様に変更 |
| * 2014/02/05 | | * 1.0.0 (2014-02-05) |
| ** 初版公開。 | | ** 初版公開 |
|
| |
|
| == ソースコード == | | === ソースコード === |
| <source lang="javascript"> | | <syntaxhighlight lang="javascript" copy> |
| //■対応する括弧に移動 | | //■対応する括弧に移動 |
| // 2014/02/05-2019/04/12 | | // 2014-02-05 - 2019-04-12 |
|
| |
|
| //■括弧の定義(0+2n:開き/1+2n:閉じ) | | //■括弧の定義(0+2n:開き/1+2n:閉じ) |
| 159行目: |
162行目: |
| var nest = 1, s, e; | | var nest = 1, s, e; |
| if (iBrc % 2) { //◆閉じ括弧の場合、先頭方向へ探す | | if (iBrc % 2) { //◆閉じ括弧の場合、先頭方向へ探す |
| var eBrc = BRACKET.charAt(iBrc-1); //対応する開き括弧を取得
| | var eBrc = BRACKET.charAt(iBrc-1); //対応する開き括弧を取得 |
| while (nest) {
| | while (nest) { |
| s = txt.lastIndexOf(sBrc,ePos-1);
| | s = txt.lastIndexOf(sBrc,ePos-1); |
| e = txt.lastIndexOf(eBrc,ePos-1);
| | e = txt.lastIndexOf(eBrc,ePos-1); |
| if (e===-1 || ePos<=0) break;
| | if (e===-1 || ePos<=0) break; |
| if (e<s) {nest++; ePos=s;} else {nest--; ePos=e;}
| | if (e<s) {nest++; ePos=s;} else {nest--; ePos=e;} |
| }
| | } |
| } else { //◆開き括弧の場合、末尾方向へ探す | | } else { //◆開き括弧の場合、末尾方向へ探す |
| var eBrc = BRACKET.charAt(iBrc+1); //対応する閉じ括弧を取得
| | var eBrc = BRACKET.charAt(iBrc+1); //対応する閉じ括弧を取得 |
| while (nest) {
| | while (nest) { |
| s = txt.indexOf(sBrc,ePos+1);
| | s = txt.indexOf(sBrc,ePos+1); |
| e = txt.indexOf(eBrc,ePos+1);
| | e = txt.indexOf(eBrc,ePos+1); |
| if (e===-1) break;
| | if (e===-1) break; |
| if (s<e && s!==-1) {nest++; ePos=s;} else {nest--; ePos=e;}
| | if (s<e && s!==-1) {nest++; ePos=s;} else {nest--; ePos=e;} |
| }
| | } |
| } | | } |
| if (nest!==0) { Status = "対応する括弧が見つかりませんでした"; break quit; } | | if (nest!==0) { Status = "対応する括弧が見つかりませんでした"; break quit; } |
| 180行目: |
183行目: |
| Status = "対応する括弧の距離: "+(Math.abs(ePos - sPos)-1)+"文字"; | | Status = "対応する括弧の距離: "+(Math.abs(ePos - sPos)-1)+"文字"; |
| } | | } |
| </source> | | </syntaxhighlight> |
| <br>
| |
| | |
| = masme 版用 機能拡張コード =
| |
| == 範囲選択の拡張 ==
| |
| (sukemaru 2019/04/24)<br>
| |
| [[GetKeyState.exe(キー状態取得実行ファイル)]] を利用して、'''カッコを含めた全体を範囲選択'''、または '''カッコの内側部分だけを範囲選択''' するための追加コードです。<br>
| |
| [[#masme 版|masme 版]] (2019/04/12) のソースコードに追加コードを挿入してください('''2ヵ所''')。<br><br>
| |
| <span style="color:#c00;">ツールバーアイコンやメニュー(マクロメニューや右クリックメニュー)からマクロを実行するさいに Ctrl または Shift キーを押しながら実行すると、拡張コードが適用されます。 </span><br>
| |
| | |
| * '''Ctrl''' キーを押しながらマクロを実行した場合には、カッコを含めた全体を範囲選択します。
| |
| ::<span style="background:#bfdfff;">【 Ctrl ありでの選択範囲 】</span> → ※カーソルは 開きカッコの左 (選択範囲の先頭)
| |
| * '''Shift''' キーを押しながらマクロを実行した場合には、カッコの内側部分だけを範囲選択します。
| |
| :: 【<span style="background:#bfdfff;"> Shift ありでの選択範囲 </span>】 → ※カーソルは 閉じカッコの左 (選択範囲の末尾)
| |
| * '''Ctrl'''+'''Shift''' キー両方が押されている(または両方とも押されていない)場合には、masme 版の設定変数「SHIFT」の true / false で指定された動作をします。
| |
| ::<span style="background:#bfdfff;">【 SHIFT=true のばあい </span>】
| |
| ※「対応する括弧に移動」を連続で実行(トグル移動)できるよう、拡張機能で範囲選択したあともカーソルは開きカッコか閉じカッコいずれかの「カッコの左」にセットされます。
| |
| <br><br>
| |
| ※ ショートカットキーでマクロを実行する場合、Ctrl キーを含むパターン、Shift キーを含むパターン、Ctrl と Shift 両方を含む(または両方を含まない)パターンのみっつのショートカットキーを登録する必要があります。 すでに masme 版「対応する括弧に移動」マクロにショートカットキーを割り当てて使用している場合、この追加コードを使用するにあたり、ショートカットの再割り当てをしてください。<br>
| |
| e.g. Ctrl+F9 / Shift+F9 / Ctrl+Shift+F9(または Alt+F9 など)
| |
| <span style="color:#c00;">※ 外部実行ファイル GetKeyState.exe を2回呼び出すため、拡張コードの処理にはタイムラグが生じます。選択範囲が確定するまで Ctrl または Shift キーを押しっぱなしにしてください。</span><br><br>
| |
| ※ GetKeyState.exe のダウンロードや導入方法については、マクロライブラリ内の「[[GetKeyState.exe(キー状態取得実行ファイル)]] 」のページへ
| |
| <br><br>
| |
| | |
| ;追加コード➀<br>
| |
| 15行目<br>
| |
| <syntaxhighlight lang="javascript" inline>if (iBrc===-1 || sBrc==="") { Status = "カーソル右側に括弧がありません"; break quit; }</syntaxhighlight><br>
| |
| の下に追加する
| |
| <source lang="javascript">
| |
| // ▼ GetKeyState を利用した機能拡張 ▼
| |
| // Ctrl / Shift キーの状態を取得
| |
| var $ctrl = 0, $shift = 0;
| |
| var getKeyState = editor.FullName.replace(/mery\.exe$/i,"") + "Macros\\GetKeyState.exe";
| |
| var WshShell = new ActiveXObject("WScript.Shell");
| |
| $ctrl = WshShell.Run('"' + getKeyState + '" ctrl',0,true);
| |
| $shift = WshShell.Run('"' + getKeyState + '" shift',0,true);
| |
| // ▲ GetKeyState を利用した機能拡張 ▲
| |
| </source>
| |
| ※「[[#カーソルの右側にカッコがないなら左側のカッコで|カーソルの右側にカッコがないなら左側のカッコで]]」の改造コードと併用する場合は、改造コードの下に挿入してください。
| |
| <br><br>
| |
| ;追加コード➁<br>
| |
| 37行目<br>
| |
| <syntaxhighlight lang="javascript" inline>Status = "対応する括弧の距離: "+(Math.abs(ePos - sPos)-1)+"文字";</syntaxhighlight><br>
| |
| の下に追加する
| |
| <source lang="javascript">
| |
| // ▼ GetKeyState を利用した機能拡張 ▼
| |
| // ※SHIFT 変数による選択範囲を上書きする(SHIFT = false; でも拡張コードでの範囲選択は有効)
| |
| if ($ctrl || $shift) {
| |
| var tPos = Math.min(sPos,ePos);
| |
| var bPos = Math.max(sPos,ePos);
| |
| // Ctrl キーだけ押し下げ時にはカッコを含めた全体を範囲選択
| |
| if ($ctrl>0 && $shift==0) {
| |
| Sel.SetActivePos(tPos);
| |
| Sel.SetAnchorPos(bPos+1);
| |
| }
| |
| // Shift キーだけ押し下げ時にはカッコの内側だけを範囲選択
| |
| else if ($ctrl==0 && $shift>0) {
| |
| Sel.SetActivePos(bPos);
| |
| Sel.SetAnchorPos(tPos+1);
| |
| }
| |
| }
| |
| // ▲ GetKeyState を利用した機能拡張 ▲
| |
| </source>
| |
| * 2019/05/12 変数名間違いを修正 sel → Sel (sukemaru)
| |
| <br><br>
| |
| | |
| == カーソルの右側にカッコがないなら左側のカッコで ==
| |
| (sukemaru 2019/12/01)<br>
| |
| <span style="color:#c00;">カーソルの右側にカッコがないとき</span> で、左側にカッコがあるなら、そのカッコに対応するカッコに移動します。<br>
| |
| * <b style="color:#c00;">右側のカッコ優先</b> です。<br>
| |
| : 移動後は対応する '''カッコの左側''' にカーソルがセットされます(連続で実行しても元のカッコの左側に)。
| |
| <br>
| |
| [[#masme 版|masme 版]] (2019/04/12) のソースコードを以下のとおり書き換えてください。
| |
| | |
| '''変更箇所''': 15 行目<br>
| |
| <syntaxhighlight lang="javascript" inline>if (iBrc===-1 || sBrc==="") { Status = "カーソル右側に括弧がありません"; break quit; }</syntaxhighlight><br>
| |
| をコメントアウトして
| |
| <source lang="javascript">
| |
| // if (iBrc===-1 || sBrc==="") { Status = "カーソル右側に括弧がありません"; break quit; } // ※ 1行 コメントアウト
| |
| | |
| // ▼ カーソルの左側にカッコがある場合に対応 ▼
| |
| if (iBrc>-1 && sBrc) { /* empty */ ; }
| |
| else if (BRACKET.indexOf(txt.charAt(sPos-1))>-1) {
| |
| sPos = ePos = sPos-1;
| |
| sBrc = txt.charAt(sPos);
| |
| iBrc = BRACKET.indexOf(txt.charAt(sPos));
| |
| }
| |
| else { Status = "カーソルの側に括弧がありません"; break quit; }
| |
| // ▲ カーソルの左側にカッコがある場合に対応 ▲
| |
| </source>
| |
| | |
| ※「[[#範囲選択の拡張|範囲選択の拡張]]」コードを併用する場合は、この変更箇所の下に「追加コード①」を挿入してください。
| |
| <br><br>
| |
| | |
| == カッコの種類を追加 ==
| |
| (sukemaru, 2019/12/01)<br>
| |
| [[#masme 版|masme 版]] (2019/04/12) のソースコードにカッコの種類を追加します。
| |
| :※ Mery 本体のオプション機能の「対応する括弧を強調する」には非対応です。
| |
| <br>
| |
| 4 行目<br>
| |
| <syntaxhighlight lang="javascript" inline>var BRACKET = "()<>[]{}「」『』【】()";</syntaxhighlight><br>
| |
| の下に追加する
| |
| <source lang="javascript">
| |
| BRACKET += "<>[]{}「」〖〗⦅⦆〈〉《》〚〛〔〕〘〙‹›«»≪≫〝〟‘’“”︵︶︿﹀︽︾︷︸﹁﹂﹃﹄︻︼︹︺";
| |
| </source>
| |
| | |
| ※ 左右のカッコのかたち(文字)が異なるペアしか登録できないので、半角二重引用符 <syntaxhighlight lang="javascript" inline> "" </syntaxhighlight> や 半角一重引用符 <syntaxhighlight lang="javascript" inline> '' </syntaxhighlight> などは不可。
| |
| <br><br><br>
| |
| | |
| = sukemaru 版 =
| |
| 【自家用】 '''対応するカッコを選択''' (sukemaru, 2019/12/02)
| |
| <br><br>
| |
| [[#masme 版|masme 版]] (2019/04/12) をベースに、<q>ジャンプ後の範囲選択の拡張</q>、 <q>キャレットの左側にあるカッコ</q> に対応、 <q>カッコの種類を追加</q>、 <q>タグなどの複数文字のペアに対応</q> などの改造をした【自家用版】も貼っておきます(おもっていたほど便利ではないアルファバージョンですが)。
| |
| <div class="warningbox">
| |
| 要:[[GetKeyState.exe(キー状態取得実行ファイル)]]
| |
| </div>
| |
| <source lang="javascript" style="height:60em; overflow:auto;">
| |
| #title = "対応するカッコを選択"
| |
| #tooltip = "対応するカッコに移動・選択"
| |
| // #icon = "Mery用 マテリアルデザインっぽいアイコン.icl" ,127
| |
| | |
| /**
| |
| * ---------------------------------------------------------
| |
| * 「対応するカッコに移動」
| |
| * Original Coded by: Kuro, kurama, ( - 2009/08)
| |
| * ; masme,(2014/02/05 - 2019/04/12)
| |
| * 「対応するカッコを選択」
| |
| * Modified by: sukemaru, (2019/04/24 - 2019/12/05)
| |
| * ---------------------------------------------------------
| |
| * ・masme 版「対応するカッコに移動」マクロ (2019/04/12) をベースに、
| |
| * キャレットの左側にあるカッコの取得や、
| |
| * タグなどの複数文字同士のペアに対応できるようにしました。
| |
| *
| |
| * ・以下の優先順位でカッコを検索します。
| |
| * ➀ カッコを範囲選択しているとき、対応するカッコを検索
| |
| * ➁ 選択範囲が HTML タグ形式 <hoge> のときは </hoge> を、
| |
| * 終了タグ </fuga> の ときは <fuga> を検索(オプション設定)
| |
| * ➂ キャレットの右側にカッコがあるとき、対応するカッコを検索
| |
| * ➃ キャレットの左側にカッコがあるとき、対応するカッコを検索(オプション設定)
| |
| *
| |
| * ・pizz 氏作成の "GetKeyState.exe(キー状態取得実行ファイル)" を利用して
| |
| * 対応するカッコに移動後の範囲選択状態を選択できます。
| |
| * GetKeyState.exe を Mery\Macros フォルダに用意してください。
| |
| *
| |
| * ▼ Ctrl, Shift キーを押しながらマクロを実行したとき ▼
| |
| *
| |
| * ・Ctrl + Shift キー両方を押しているとき
| |
| * → 対応するカッコの右側にキャレットを移動します。
| |
| * ・Ctrl キーのみ押しているとき
| |
| * → 対応するカッコをふくむ全体(外側)を範囲選択します。
| |
| * ・Shift キーのみ押しているとき
| |
| * → 対応するカッコの中身(内側)を範囲選択します。
| |
| *
| |
| * ・Ctrl / Shift キーを押していないときは
| |
| * → 対応するカッコだけを範囲選択します。
| |
| *
| |
| * 【仕様上の制限】
| |
| * ・カッコの定義は、通例として前後関係が定まっているもののみとしてください。
| |
| * 同一の記号を使う '一重引用符' や "二重引用符"、―ダーシ― などでは、
| |
| * 開き ← 閉じ の方向に戻れないので使用できません。
| |
| * ・\ などでエスケープされたものを考慮せずにジャンプします。
| |
| * ・HTML/XML タグなどのように < > をカッコとして使用しているものと
| |
| * 比較・計算で使用している半角不等号 < > とを区別しません。
| |
| * ・<div id="hoge"> や <div style="fuga"> のような属性つきのタグを
| |
| * 個別に登録することはできません。
| |
| * (終了側のタグが同一 </div> なので、</div> から前方に検索したときに
| |
| * <div> や <div class="piyo"> などと区別をつけられない)
| |
| *
| |
| * (2019/12/05)
| |
| * ・設定項目 tagEnable と altTagInvert を追加。
| |
| * <hoge> </hoge> 形式のタグ全般に対応 (配列 brackets2 への登録不要)。
| |
| *
| |
| * ※ タグを範囲選択しているときのみ有効。
| |
| * 範囲選択なしの場合、キャレットの左または右にあるタグを自動取得しません
| |
| * (配列 brackets2 に登録されたペアであれば、自動取得しますが…)。
| |
| * ※ 開始タグ側から実行する場合、キャレットがタグの先頭位置にあるとき、
| |
| * または選択範囲に属性部分を含めていないときのみ有効。
| |
| * ※ 基本的に、開始タグは "<" の直後が空白でないこと(正規表現 ^<\w+ )、
| |
| * 終了タグ内には空白文字を含めないこと(正規表現 \/\w+>$ )を条件とします。
| |
| * e.g. < hoge > </hoge > などは NG.
| |
| * <fuga/> <!PIYO> を範囲選択している場合も通常のカッコ囲いとして扱います。
| |
| * ※ <hoge> の hoge 部分が有効な HTML タグであるかをチェックしないので、
| |
| * <ABC> 形式のカッコにたいしては、通常の「対応するカッコに移動・選択」
| |
| * の動作になりません(設定項目 tagEnable = false で無効化できます)。
| |
| * 「対応するカッコがない」 となって両端の "<" と ">" での移動ができなくなります。
| |
| * ※ tagEnable = true の場合、配列 brackets2 にタグが登録されていると
| |
| * うまく動作しないことがあります。
| |
| * ※ tagEnable = false の場合でも、配列 brackets2 に登録されたペアであれば
| |
| * 通常のカッコと同様に扱います。
| |
| * ※ 同種のタグがネストすることはないはずですが、
| |
| * 便宜上、通常のカッコと同様にネストのチェックをします。
| |
| */
| |
| | |
| | |
| // ---------- ▼ 設定項目 ▼ ---------- //
| |
| | |
| // ■ <hoge> </hoge> 形式のタグを検索対象にする(優先オプション)
| |
| var tagEnable = true;
| |
| | |
| // ■ Alt キー押し下げで tabEnable の true / false を一時的に反転させる
| |
| var altTagInvert = true;
| |
| | |
| // ■ キャレットの左側のカッコも検索対象にする(true でも右側が優先)
| |
| var leftsideEnable = true;
| |
| | |
| // ■ Shift キーのみ押し下げのとき、実行後の選択範囲が複数行になるなら
| |
| // カッコの内側の行だけを範囲選択する
| |
| var insideLines = false;
| |
| | |
| // ■ カッコの定義1 (開きカッコと閉じカッコをペアにして列挙する)
| |
| var brackets1 = "()<>[]{}「」『』【】()" // Mery で強調表示可能なカッコ
| |
| brackets1 += "<>[]{}「」〖〗⦅⦆〈〉《》〚〛〔〕〘〙"
| |
| + "︵︶︿﹀︽︾︷︸﹁﹂﹃﹄︻︼︹︺"
| |
| + "‹›«»≪≫〝〟‘’“”" ; // ―——
| |
| | |
| // ■ カッコの定義2 (タグなどの複数文字のペアを配列に列挙する)
| |
| // ※ おなじ開きカッコを持つペアや、おなじ閉じカッコを持つペア、
| |
| // braclets1 に含まれているカッコ1文字だけの要素は不可。
| |
| var brackets2 = [];
| |
| brackets2 = [
| |
| "\\(" , "\\)" , "\\[" , "\\]" , "\\{" , "\\}" ,"[[" , "]]" ,
| |
| /* HTML/XML 形式のタグは登録不要 (2019/12/05) */
| |
| // "<b>" , "</b>" , "<a>" , "</a>" , "<pre>" , "</pre>" ,
| |
| // "<b" , "/b>" , "<a" , "/a>" , // <abc> や <blah> に反応しなくなるかも?
| |
| // "<div>" , "</div>" , "<div" , "/div>" ,
| |
| "/**" , " */" , "/*" , "*/" , "<!--" , "-->"
| |
| ];
| |
| | |
| // ---------- ▲ 設定項目 ▲ ---------- //
| |
| | |
| | |
| // Ctrl キーと Shift キーの状態を取得
| |
| var $ctrl = 0, $shift = 0, $alt = 0;
| |
| var gks = editor.FullName.replace( /[^\\]+$/, "" )
| |
| + "Macros\\GetKeyState.exe";
| |
| if ( new ActiveXObject( "Scripting.FileSystemObject" ).FileExists( gks ) ) {
| |
| var WshShell = new ActiveXObject( "WScript.Shell" );
| |
| $ctrl = WshShell.Run( '"' + gks + '" control', 0, true );
| |
| $shift = WshShell.Run( '"' + gks + '" shift', 0, true );
| |
| if ( altTagInvert ) {
| |
| $alt = WshShell.Run( '"' + gks + '" alt', 0, true );
| |
| if ( $alt === 1 ) { tagEnable = ! tagEnable; }
| |
| }
| |
| }
| |
| | |
| var start = new Date(); // ここでタイマースタート
| |
| | |
| // カッコの定義をひとつの配列に統合する (brackets2 が前、brackets1 が後ろ)
| |
| var brackets = brackets2.concat( brackets1.split( "" ) );
| |
| var len = brackets.length;
| |
| | |
| var d = editor.ActiveDocument, sel = d.selection;
| |
| var dt = d.Text, st = sel.Text;
| |
| var act = sel.GetActivePos(), anc = sel.GetAnchorPos();
| |
| var tPos = Math.min( act, anc ), bPos = Math.max( act, anc );
| |
| var txt, brc, bLen, sPos, ePos, sBrc, iBrc;
| |
| if ( tagEnable ) {
| |
| var isTag = false, isEndTag = false;
| |
| var pos, gt;
| |
| }
| |
| | |
| // 選択範囲がカッコか
| |
| check: {
| |
| if ( st ) {
| |
| for ( var i = 0; i < len; i ++ ) {
| |
| brc = brackets[i];
| |
| if ( st === brc ) {
| |
| sPos = ePos = tPos; sBrc = brc; iBrc = i;
| |
| break check;
| |
| }
| |
| }
| |
| // 選択範囲が <HTML> タグ(開始タグ)か
| |
| // ※ 開始タグの閉じカッコを含めずに "開きカッコ" とする
| |
| if ( ! sBrc && tagEnable && ! /(?:\/\s*>|\W>)$/.test( st ) &&
| |
| ( /^<\w+[\t >]?$/.test( st ) ||
| |
| ( act < anc && /^<\w+[\t >](?!\s*\/)/.test( st ) ) ) ) {
| |
| brc = /^(<\w+)[ >]?/.exec( st )[1]; // <hoge
| |
| bLen = brc.length; isTag = true;
| |
| eBrc = "</" + brc.slice( 1 ) + ">"; // </hoge>
| |
| sPos = ePos = tPos; sBrc = brc; iBrc = 0;
| |
| break check;
| |
| }
| |
| // 選択範囲が </HTML> タグ(終了タグ)か // </hoge>
| |
| else if ( ! sBrc && tagEnable &&
| |
| ( /^<?\/\w+>$/.test( st ) ||
| |
| ( anc < act && /<\/\w+>$/.test( st ) ) ) ) {
| |
| brc = "<" + /<?(\/\w+>)$/.exec( st )[1];
| |
| bLen = brc.length; isEndTag = true;
| |
| eBrc = "<" + brc.slice( 2, -1 ); // <hoge
| |
| sPos = ePos = bPos - bLen; sBrc = brc; iBrc = 1;
| |
| break check;
| |
| }
| |
| }
| |
| // 右側にカッコがあるか
| |
| if ( ! sBrc && act < dt.length ) {
| |
| txt = dt.slice( act );
| |
| for ( var i = 0; i < len; i ++ ) {
| |
| brc = brackets[i]; bLen = brc.length;
| |
| if ( txt.slice( 0, bLen ) === brc ) {
| |
| sPos = ePos = act; sBrc = brc; iBrc = i;
| |
| break check;
| |
| }
| |
| }
| |
| }
| |
| // 左側にカッコがあるか
| |
| if ( ! sBrc && act > 0 && leftsideEnable ) {
| |
| txt = dt.slice( 0, act );
| |
| for ( var i = 0; i < len; i ++ ) {
| |
| brc = brackets[i]; bLen = brc.length;
| |
| if ( txt.slice( - bLen ) === brc ) {
| |
| sPos = ePos = act - bLen; sBrc = brc; iBrc = i;
| |
| break check;
| |
| }
| |
| }
| |
| }
| |
| }
| |
| | |
| if ( sBrc ) {
| |
| // カッコありならネスト(入れ子)をチェックする
| |
| var nest = 1;
| |
| var s, e, eBrc, eLen;
| |
| var sLen = sBrc.length; // 検索元のカッコの文字数
| |
| | |
| // 閉じカッコの場合、先頭方向へ探す ※剰余あり = 奇数
| |
| if ( iBrc % 2 ) {
| |
| eBrc = eBrc ? eBrc : brackets[ iBrc - 1 ]; // 対応する開きカッコ
| |
| eLen = eBrc.length; // 開きカッコの文字数
| |
| // ネストが無くなるまで探す
| |
| while ( nest > 0 ) {
| |
| s = dt.lastIndexOf( sBrc, ePos - sLen ); // 開きカッコが見つかった位置
| |
| e = dt.lastIndexOf( eBrc, ePos - eLen ); // 閉じカッコが見つかった位置
| |
| if ( e === -1 || ePos <= 0 ) { break; } // 閉じカッコがなければ終了
| |
| if ( e < s ) { nest ++; ePos = s; } // ( ) セットで見つかれば
| |
| else { nest --; ePos = e; } // 開きカッコだけが見つかれば
| |
| }
| |
| }
| |
| // 開きカッコの場合、末尾方向へ探す ※剰余なし = 偶数
| |
| else {
| |
| eBrc = eBrc ? eBrc : brackets[ iBrc + 1 ]; // 対応する閉じカッコ
| |
| eLen = eBrc.length; // 閉じカッコの文字数
| |
| //ネストが無くなるまで探す
| |
| while ( nest > 0 ) {
| |
| s = dt.indexOf( sBrc, ePos + sLen ); // 開きカッコが見つかった位置
| |
| e = dt.indexOf( eBrc, ePos + eLen ); // 閉じカッコが見つかった位置
| |
| if ( e === -1 ) { break }; // 閉じカッコがなければ終了
| |
| if ( s > -1 && s < e ) { nest ++; ePos = s; } // ( ) セットで見つかれば
| |
| else { nest --; ePos = e; } // 閉じカッコだけが見つかれば
| |
| }
| |
| }
| |
| | |
| // 対応するカッコにジャンプ
| |
| if ( nest === 0 ) {
| |
| // 修飾キーなし → 対応するカッコを範囲選択
| |
| if ( $ctrl !== 1 && $shift !== 1 ) {
| |
| pos = ePos + eLen;
| |
| if ( isEndTag ) { // 開始タグの閉じカッコを探す
| |
| gt = dt.slice( pos, sPos ).indexOf( ">" ) + 1;
| |
| sel.SetActivePos( pos + gt );
| |
| } else {
| |
| sel.SetActivePos( pos );
| |
| }
| |
| sel.SetActivePos( ePos, true );
| |
| }
| |
| // Ctrl + Shift キー両方 → 対応するカッコの左側にジャンプ
| |
| else if ( $ctrl === 1 && $shift === 1 ) {
| |
| sel.SetActivePos( ePos );
| |
| }
| |
| // Ctrl キーのみ → 対応するカッコをふくめて範囲選択(外側)
| |
| else if ( $ctrl === 1 && $shift !== 1 ) {
| |
| if ( ePos < sPos ) {
| |
| sel.SetActivePos( sPos + sLen );
| |
| sel.SetActivePos( ePos, true );
| |
| } else { // ( sPos < ePos )
| |
| sel.SetActivePos( sPos );
| |
| sel.SetActivePos( ePos + eLen, true );
| |
| }
| |
| }
| |
| // Shift キーのみ → 対応するカッコとの中身を範囲選択(内側)
| |
| else if ( $shift === 1 && $ctrl !== 1 ) {
| |
| if ( ePos < sPos ) {
| |
| pos = ePos + eLen;
| |
| sel.SetActivePos( sPos );
| |
| if ( isEndTag ) {
| |
| gt = dt.slice( pos, sPos ).indexOf( ">" ) + 1;
| |
| sel.SetActivePos( pos + gt, true );
| |
| } else {
| |
| sel.SetActivePos( pos, true );
| |
| }
| |
| } else { // ( sPos < ePos )
| |
| pos = sPos + sLen;
| |
| if ( isTag ) {
| |
| gt = dt.slice( pos, ePos ).indexOf( ">" ) + 1;
| |
| sel.SetActivePos( pos + gt );
| |
| } else {
| |
| sel.SetActivePos( pos );
| |
| }
| |
| sel.SetActivePos( ePos, true );
| |
| }
| |
| // カッコの内側の行を範囲選択
| |
| if ( insideLines ) {
| |
| var ty = sel.GetTopPointY( mePosLogical );
| |
| var by = sel.GetBottomPointY( mePosLogical );
| |
| var bx = sel.GetBottomPointX( mePosLogical );
| |
| var strTest = /[^\t ]/.test( d.GetLine( by, 0 ).slice( 0, bx -1 ) );
| |
| if ( ( by - ty ) > 1 && ! strTest ) {
| |
| sel.SetActivePoint( mePosLogical, 1, by - 1 );
| |
| sel.EndOfLine( false, mePosLogical );
| |
| sel.SetAnchorPoint( mePosLogical, 1, ty + 1 );
| |
| }
| |
| }
| |
| }
| |
| Status = " 対応するカッコに移動" ;
| |
| } else { Status = " 対応するカッコが見つかりませんでした"; }
| |
| } else { Status = " カーソルの側にカッコがありません"; }
| |
| | |
| // var elapsedSec = ( ( new Date() - start ) / 1000 ).toFixed( 3 );
| |
| // Status += " [ " + elapsedSec.replace( /\./, ". " ) + " 秒 ]" ;
| |
| </source>
| |