「利用者:Sukemaru」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
Sukemaru (トーク | 投稿記録)
編集の要約なし
MSY-07 (トーク | 投稿記録)
項目の追加と移動、ウィキリンクの追加と修正
 
(2人の利用者による、間の35版が非表示)
1行目: 1行目:
<div id="TOP"> [[#END|>> ページ末尾へ]] </div>
__toc__
<br><br>
== マクロライブラリに投稿したマクロ ==
== マクロライブラリに投稿したマクロ ==
 
=== テキスト操作補助 ===
=== 「テキスト操作補助」 カテゴリ ===
* [[行頭か行末 または 選択範囲の始点か終点]] (last_modified: 2020/06/26)
* [[行頭か行末 または 選択範囲の始点か終点|行頭か行末 または 選択範囲の始点か終点 に移動]] (last modified: 2019/03/29)
* [[文書の先頭か末尾]] (last_modified: 2019/03/29)
* [[文書の先頭か末尾|文書の 先頭か末尾 に移動]] (last modified: 2019/03/29)
* [[対応する括弧に移動#範囲選択の拡張|「対応する括弧に移動」の追加コード]] (last_modified: 2019/12/02)
* [[対応する括弧に移動#範囲選択の拡張|「対応する括弧に移動」の追加コード]] (last modified: 2019/05/12)
* [[日付と時刻を挿入#sukemaru 版|日付と時刻を挿入]] (last_modified: 2018/12/09)
* [[バイト数#バイト数と文字数・行数|バイト数と文字数・行数]] ※イベントマクロ (last modified: 2018/11/18)
* [[日付と時刻を挿入#sukemaru 版|日付と時刻を挿入]] (last modified: 2018/12/09)
* [[行を上下に移動(Mery 2.7 用)]] (uploaded: 2019/05/07) ※ ブックマーク対応
* [[行を上下に移動(Mery 2.7 用)]] (uploaded: 2019/05/07) ※ ブックマーク対応
* [[行を複製 (複数行可)]] (last modified: 2019/05/07) ※ ブックマーク対応
* [[行を複製 (複数行可)]] (last_modified: 2020/06/26) ※ ブックマーク対応
* [[字下げ・字上げ#sukemaru 版|字下げ・字上げ(スペース×2 追加・削除)]] (last modified: 2019/11/18) ※ ブックマークを保持
* [[字下げ・字上げ#sukemaru 版|字下げ・字上げ(スペース×2 追加・削除)]] (last_modified: 2020/06/29) ※ ブックマークを保持
: [[字下げ・字上げ#インデント|インデント/逆インデント]] (last modified: 2019/11/17) ※ ブックマークを保持
** [[字下げ・字上げ#インデント|インデント/逆インデント]] (last_modified: 2020/06/29) ※ ブックマークを保持
* [[貼付け実行後のカーソル位置を貼付け文字列の先頭にする#sukemaru 版|貼付け実行後のカーソル位置を貼付け文字列の先頭にする]] (added: 2018/11/14)
* [[貼付け実行後のカーソル位置を貼付け文字列の先頭にする#sukemaru 版|貼付け実行後のカーソル位置を貼付け文字列の先頭にする]] (added: 2018/11/14)
* [[行の先頭に貼り付け]] (uploaded: 2018/08/24)
* [[行の先頭に貼り付け]] (uploaded: 2018/08/24)
<div id="引用符/コメント"></div>
<span id="引用符/コメント"></span>
* [[引用符/コメント]] ※ポップアップメニュー (last modified: 2019/04/07)  ※行頭の文字列操作マクロ「引用の追加」の増補改訂版
* [[引用符/コメント]] ※ポップアップメニュー (last_modified: 2020/06/23)  ※行頭の文字列操作マクロ「引用の追加」の増補改訂版
* [[カッコで囲う]] ※ポップアップメニュー (last modified: 2019/04/07)
* [[カッコで囲う]] ※ポップアップメニュー (last_modified: 2020/06/23)
: [[カッコで囲う#カッコで囲う (ポップアップメニューなし)|カッコで囲う (簡易版 ポップアップメニューなし)]]
** [[カッコで囲う#カッコで囲う (ポップアップメニューなし)|カッコで囲う (簡易版 ポップアップメニューなし)]]
: [[カッコで囲う#引用符を追加/削除|引用符を追加/削除]]  ※"二重引用符" の追加/削除トグル
** [[カッコで囲う#引用符を追加/削除|引用符を追加/削除]]  ※"二重引用符" の追加/削除トグル
* [[定型文を挿入|定型文を挿入 マクロ集]] (uploaded: 2018/12/03)
** [[カッコで囲う#カッコで囲う2(各行ごとにカッコで囲う/Mery ver 3 用)|カッコで囲う2]] ※ポップアップメニュー
<br>
* [[カッコをはずす]] & [[カッコをはずす#カッコを追加/削除|カッコを追加/削除]] (include版) (last_modified: 2020/06/28)
<gallery heights=192px>
** 2020/06/28 → [[カッコをはずす#カッコを削除/追加|カッコを削除/追加 トグル]] を<b style="color:#c00;">削除</b>
ファイル:引用符/コメント_ポップアップメニュー.png|heights=240px|引用符/コメント
* [[定型文を挿入]] (uploaded: 2018/12/03)
ファイル:カッコで囲う_ポップアップメニュー.png|heights=240px|カッコで囲う
* [[位置情報を保存してから「すべて選択/選択解除」(非スクロール)]] (include版) (last_modified: 2019/11/13)
</gallery>
** 「[[位置情報を保存してから「すべて選択/選択解除」(非スクロール)#【include 版】位置を復帰/保存|位置を復帰/保存]]」 (include版)
<br clear=all>
* [[拡張自動選択]] (uploaded: 2020/07/01) ※「日付」を範囲選択、今日の日付に変換
* [[追加コピー・追加切り取り]] (uploaded: 2020/06/05) ※ Mery ver 2.8.1 以降用
* [[新規行番号入力]] (w/Takuma) (added: 2020/06/26)
* [[バイト数#バイト数と文字数・行数|バイト数と文字数・行数]] ※イベントマクロ (last_modified: 2018/11/18 → '''2019/12/03 削除''')
* [[論理行を選択 (改行を含まない)]] (uploaded: 2021/01/20)
* [[選択範囲を行に分ける・改]] (uploaded: 2021/01/20)


=== 「ファイル操作補助」 カテゴリ ===
=== ファイル操作補助 ===
* [[ファイルのプロパティ]] (uploaded: 2018/12/18)
* [[ファイルのプロパティ]] (uploaded: 2018/12/18)
* [[選択範囲のURL・パスを開く|ひらけゴマ!]] (last modified: 2019/04/07) ※選択範囲のURL・パスを開く
* [[選択範囲のURL・パスを開く]] (last_modified: 2019/04/07) ※選択範囲のURL・パスを開く
* [[ブックマーク一覧ジャンプ#sukemaru 版|ブックマーク一覧ジャンプ]] (通常版/include版) ※ポップアップメニュー (last modified: 2019/04/16)
* [[ブックマーク一覧ジャンプ#sukemaru 版|ブックマーク一覧ジャンプ]] (通常版/[[ブックマーク一覧ジャンプ#include版|include版]]) ※ポップアップメニュー (last_modified: 2020/06/24)
* [[編集モードの自動選択]] (通常版/include版) ※イベントマクロ (last modified: 2019/04/24) ※書き換え禁止で開く
* [[編集モードの自動選択]] (通常版/include版) ※イベントマクロ (last_modified: 2019/04/24) ※書き換え禁止で開く
* [[特定のフォルダで「ファイルを開く」ダイアログ]] (last modified: 2018/12/19)
* [[特定のフォルダで「ファイルを開く」ダイアログ]] (last_modified: 2020/05/10)
* [[すべて閉じる|すべて閉じる マクロ集]] (通常版/include版) (last modified: 2019/05/03)
* [[すべて閉じる]] (通常版/include版) (last_modified: 2019/05/03)
: 「他(右側/左側)のタブを閉じる」 などを追加 ※ポップアップメニュー版あり
**  「他(右側/左側)のタブを閉じる」 などを追加 ※ポップアップメニュー版あり
* [[ファイルを読み直す・開きなおす]] (通常版/include版) ※ポップアップメニュー (last modified: 2019/05/30)
* [[ファイルを読み直す・開きなおす]] (通常版/include版) ※ポップアップメニュー (last_modified: 2019/11/30)
: エンコード指定で読み直し・読み取り専用属性の変更・編集モードの変更・プロパティを開く・さいごに閉じたファイルを開く・etc.
** エンコード指定で読み直し・読み取り専用属性の変更・編集モードの変更・プロパティを開く・さいごに閉じたファイルを開く・etc.
* [[さいごに閉じたファイルを開く]] ※ポップアップメニュー (uploaded: 2019/04/30)
* [[さいごに閉じたファイルを開く]] ※ポップアップメニュー (last_modified: 2019/11/30)
<br>
* [[タブを複製する]] (last_modified: 2020/06/22)
<gallery widths=200px>
* [[強制的に上書き保存]] (uploaded: 2020/06/01)
ファイル:Mery_ブックマークジャンプ_SS(1).png|ブックマークジャンプ 【include版】
* [[すべて戻す]] (uploaded: 2020/06/01)
ファイル:Mery_すべて閉じる(入力).png|すべて閉じる: 入力ダイアログ
* [[作業フォルダの変更]] (uploaded: 2020/06/03)
ファイル:Mery_すべて閉じる(メニュー).png|すべて閉じる: ポップアップメニュー
</gallery>
<gallery widths=200px>
ファイル:ファイルを読み直す・開きなおす.png|ファイルを読み直す 【通常版】
ファイル:ファイルを読み直す・開きなおす【自家用版】.png|ファイルを読み直す 【include版】
</gallery><br clear=all>


=== 「変換・ソート・整形」 カテゴリ ===
=== 変換・ソート・整形 ===
* [[昇順で並び替え/降順で並び替え]] トグル変換 (uploaded: 2019/06/03)
* [[昇順で並び替え/降順で並び替え]] トグル変換 (last_modified: 2020/05/04)
* [[TrueとFalse_を切り替える|YES/NO マクロ]] (last modified: 2018/11/27) ※「<span style="color:#0000c0;">True</span>」 ⇔ 「<span style="color:#c00;">False</span>」 トグル変換
** 「[[昇順で並び替え/降順で並び替え#昇順/降順トグル + 文字列反転|昇順/降順トグル + 文字列反転]](added: 2020/05/04)
: + 改造版「'''ToDoリストモード'''[https://www.haijin-boys.com/software/mery/mery-2-7-0#comment=2240]」 (added: 2019/05/06)
* [[TrueとFalse を切り替える]] (last_modified: 2020/07/01) ※「<span style="color:#0000c0;">True</span>」 ⇔ 「<span style="color:#c00;">False</span>」 トグル変換
* [[全角/半角 トグル変換]] (last modified: 2019/05/20) ※「ABCアイウエオ」 ⇔ 「ABCアイウエオ」
** 改造版「'''ToDoリストモード'''[https://www.haijin-boys.com/software/mery/mery-2-7-0#comment=2240]」 (last_modified: 2020/05/12)
* [[大文字/小文字/頭文字 トグル変換]] (last modified: 2019/08/29) ※「Abc」 → 「ABC」 → 「abc」 ...
* [[全角/半角変換]] (last_modified: 2019/05/11) ※「ABC」→「ABC」 / 「ABC」→「ABC」
* [[ひらがな/カタカナ変換]] (uploaded: 2019/07/06) ※「あいうえお」 「アイウエオ」 / 「カキクケコ」 → 「かきくけこ」
* [[全角/半角 トグル変換]] (last_modified: 2020/07/03) ※「ABCアイウエオ」⇔「ABCアイウエオ」
* [[文字列の順番を逆に書き出す]] (uploaded: 2019/07/06) ※「あいうえお」 → 「おえういあ」
* [[大文字/小文字/頭文字 トグル変換]] (last_modified: 2020/07/03) ※「Abc」 → 「ABC」 → 「abc」 ...
<br><br>
* [[ひらがな/カタカナ変換]] (last_modified: 2020/06/24) ※「あいうえお」 「アイウエオ」
[[#TOP|>> 目次へ]]
* [[TAB/半角空白 トグル変換]] (last_modified: 2020/07/02)
<br><br>
* [[文字列の順番を逆に書き出す]] (last_modified: 2020/01/03) ※「あいうえお」 ⇔ 」おえういあ「
* [[マルチカーソル選択範囲の並べ替え]] (last_modified: 2020/07/04)
* [[マルチカーソル用:「昇順/降順」または「逆順」で並べ替え]] (uploaded: 2020/07/04)


=== 「検索・置換」 カテゴリ ===
=== 検索・置換 ===
* [[ポップアップメニューで検索先にジャンプ#sukemaru 版|ポップアップメニューで検索先にジャンプ]] (通常版/include版) (last modified: 2019/04/16)
* [[ポップアップメニューで検索先にジャンプ#sukemaru 版|ポップアップメニューで検索先にジャンプ]] (last_modified: 2018/12/13, 2020/06/25)
: + おまけマクロ「[[マテリアルデザインっぽいアイコンと『小マクロ集』#次の文字列を検索|次の文字列を検索]]/[[マテリアルデザインっぽいアイコンと『小マクロ集』#前の文字列を検索|前の文字列を検索]] (検索オプションをリセット&強調なし)」他
** [[検索ジャンプの include版]] (last_modified: 2019/04/16)
* [[検索ヒット数表示(選択文字列)]] ※イベントマクロ (last modified: 2019/07/20)
** [[検索ジャンプの人柱版]] (last_modified: 2019/03/16)
: + 機能強化版「[[検索ヒット数表示(選択文字列)#機能強化バージョン|文字数・行数・ヒット件数(選択文字列)]]」 ※イベントマクロ (last modified: 2019/08/28)
* [[検索ヒット数表示(選択文字列)]] ※イベントマクロ (last_modified: 2019/12/03)
* [[次/前の文字列を検索・改]] (last modified: 2019/09/09) ※複数行選択から『次/前の文字列を検索』
** 機能強化版「[[検索ヒット数表示(選択文字列)#機能強化バージョン|文字数・行数・バイト数・ヒット件数(選択文字列)]]」 ※イベントマクロ (last_modified: 2019/12/03)
<br>
* [[次/前の文字列を検索・改]] (last_modified: 2020/05/12) ※複数行選択から『次/前の文字列を検索』
[[ファイル:Mery_ジャンプ_SS_2.png|240px|thumb|left|検索ジャンプ 【include版】]]
<br clear=all><br>


=== 「プログラミング補助」 カテゴリ ===
=== プログラミング補助 ===
* [[コメントマーク付け外し#sukemaru 版|行コメント]] (last modified: 2019/11/10) ※コメントマーク付け外し ブックマークを保持
* [[コメントマーク付け外し#sukemaru 版|行コメント]] (last_modified: 2020/06/28) ※コメントマーク付け外し ブックマークを保持
<br>
* [[JS フォーマット]] (uploaded: 2020/05/03) ※JavaScript のソースコードの整形
** EmEditor 用「Format HTMl, Javascript, Css format for Emeditor」マクロ [https://www.emeditor.com/files/fhtml-jsee/] を Mery に移植するための改造用コード
** 「[[テキスト整形]]」マクロ(masme 氏作成)への機能追加用コード


=== 「実験的マクロ・練習マクロなど」 カテゴリ ===
=== おもしろ ===
* 【自家用】 [[カッコをはずす]] & [[カッコをはずす#カッコを削除/追加|カッコを削除/追加 トグル]] & [[カッコをはずす#カッコを追加/削除|カッコを追加/削除]] (通常版/include版) (last modified: 2019/05/03)
* [[Yahoo!天気情報#sukemaru 版|Yahoo!天気情報]] ※ポップアップメニュー/ダイアログ (last_modified: 2020/05/12)  
* 【自家用】 [[ファイルのフルパスをコピーして閉じる]] ※イベントマクロ (last modified: 2019/04/14)
 
* 【自家用】 [[全角/半角変換]] (last modified: 2019/05/11)
=== 実験的マクロ・練習マクロなど ===
* 【自家用】 [[ファイルのフルパスをコピーして閉じる]] ※イベントマクロ (last_modified: 2019/04/14)
* 【実験】 [[位置情報を保存してから「次の文字列を検索」]]+ 復帰 (include版) (uploaded: 2019/05/28)
* 【実験】 [[位置情報を保存してから「次の文字列を検索」]]+ 復帰 (include版) (uploaded: 2019/05/28)
* 【実験】 [[タブが「縦書き」モードかチェックする]] ※組み込み用関数 (uploaded: 2019/04/29)
* 【自家用】[[行の表示方法を切り替える]] (last_modified: 2019/08/24) ※論理行/表示行 トグル切り替え
: サンプルコード: 「特定の条件で縦書きモードに切りかえる」(※ ver 2.6.5 - 2.7.5 用)
* 【自家用】[[パスを貼り付け(ポップアップメニュー)]] (uploaded: 2020/12/30) ※ Mery Ver 3.2.2 以降 [https://www.haijin-boys.com/discussions/5835#discussion-5868]
* 【実験】 [[「クリップボード履歴」メニューのマクロ化]] (include版) ※ポップアップメニュー (last modified: 2019/11/09) <br> ※「スニペット」の機能を統合 / ※ ver 2.8.1 以降用
* 【実験】 [[タブが「縦書き」モードかチェックする]] ※組み込み用関数 (uploaded: 2019/04/29 → '''2019/ 削除''')
* 【自家用】[[行の表示方法を切り替える]] (last modified: 2019/08/24) ※論理行/表示行 トグル切り替え
** サンプルコード: 「特定の条件で縦書きモードに切りかえる」(※ ver 2.6.5 - 2.7.5 用)
* 【自家用】[[位置情報を保存してから「すべて選択/選択解除」(非スクロール)]] (include版) (last modified: 2019/11/13)
* 【実験】 [[ファイルへ移動(物理座標ジャンプ)]] (uploaded: 2019/05/15 → '''2019/10/27 削除''')
: +「[[位置情報を保存してから「すべて選択/選択解除」(非スクロール)#【include 版】位置を復帰/保存|位置を復帰/保存]]」 (include版)
* 【実験】 [[ブックマークを復元(Mery 2.7用)]] (last_modified: 2019/04/07 → '''2019/04/12 削除''')
* 【実験】 [[コンパクトメニュー]] ※ポップアップメニュー (last modified: 2019/11/21)
* 【自家用】[[対応する括弧に移動#sukemaru 版|対応するカッコに移動・選択]] (last_modified: 2019/12/05 → '''2019/ 削除''')
<br>
* 【実験】 [[カッコで囲う2]](マルチカーソル貼り付け) (uploaded: 2020/06/06 → 2020/06/23 <b style="color:#c00;">削除</b>) ※ Mery ver 3 以降
* 【実験】 [[ファイルへ移動(物理座標ジャンプ)]] (uploaded: 2019/05/15 → '''2019/10/27 隠蔽''')
* 【実験】 [[ブックマークを復元(Mery 2.7用)]] (last modified: 2019/04/07 → '''2019/04/12 削除''')
<br>
[[ファイル:ブックマークを復元D.png|link=|240px|thumb|left|ブックマークを復元]]
<br clear=all><br>


=== 「その他」 カテゴリ ===
=== その他 ===
* [[折り返しトグル切り替え#3つの折り返しモードを順々にトグルする|折り返しトグル切り替え]] (include版) (added: 2019/02/19 ※w/ Bleat氏)
* [[折り返しトグル切り替え#3つの折り返しモードを順々にトグルする|折り返しトグル切り替え]] (include版) (last_modified: 2020/03/15)
* [[Mery.iniのオプション値を取得]] ※組み込み用関数 (last modified: 2019/11/15)
* [[Mery.iniのオプション値を取得]] ※組み込み用関数 (last_modified: 2020/05/14)
* [[Mery本体のバージョンチェック]] ※組み込み用関数 (uploaded: 2019/04/17)
* [[Mery本体のバージョンチェック]] ※組み込み用関数 (uploaded: 2019/04/17)
: サンプルコード: 「Begin/EndUndoGroup() メソッドを使えるのは ver 2.7.0 以降」
** サンプルコード: 「Begin/EndUndoGroup() メソッドを使えるのは ver 2.7.0 以降」
* [[IO.Serialize() の JSON を参照する]] ※組み込み用関数 (uploaded: 2019/04/17)
* [[IO.Serialize() の JSON を参照する]] ※組み込み用関数 (uploaded: 2019/04/17)
* [[ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する]] ※組み込み用関数 (uploaded: 2019/04/20)
* [[ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する]] ※組み込み用関数 (last_modified: 2020/05/28)
: サンプルコード: 「すべての論理行をポップアップメニューに表示する」
** サンプルコード: 「すべての論理行をポップアップメニューに表示する」
* [[アクティブなタブのマクロを実行する]] (uploaded: 2019/08/12)
* [[アクティブなタブのマクロを実行する]] (last_modified: 2020/04/30)
* [[マクロメニュー]] ※ポップアップメニュー (uploaded: 2019/11/02)
* [[「クリップボード履歴」メニューのマクロ化]] (include版) ※ポップアップメニュー (last_modified: 2020/06/27)
<br>
** ※「スニペット」の機能を統合 / ※ ver 2.8.1 以降用
* [[GetKeyState.exe(キー状態取得実行ファイル)]] の [[GetKeyState.exe(キー状態取得実行ファイル)#実装例|サンプルコード2, 3]] (2019/03/23 - 2019/11/13)
* [[コンパクトメニュー]] ※ポップアップメニュー (last_modified: 2020/03/29)
<br>
* [[マクロメニュー]] ※ポップアップメニュー (last_modified: 2020/06/03)
<gallery widths=192px>
* [[Mery.his の履歴を整理]] (uploaded: 2021/01/20)
ファイル:Mery_関数_JsonContents.png|JSON ファイルを開く
ファイル:Mery_分割サブメニュー_SS(1).png|分割サブメニュー 1
ファイル:Mery_分割サブメニュー_SS(2).png|分割サブメニュー 2
</gallery><br clear=all>
 
* [[キーアサイン集]] (last modified: 2018/10/19 ※w/ ks氏, masme氏, 有志)  
* [[マテリアルデザインっぽいアイコンと『小マクロ集』]] (last modified: 2019/05/01) ※アイコン収録数'''300'''コ


<gallery heights=320px>
=== 開発者向け ===
ファイル:Mery用_マテリアルデザインっぽいアイコン.icl.png|&ensp;アイコン 一覧画像
* [[キーアサイン集]] (last_modified: 2018/10/19 ※w/ ks氏, masme氏, 有志)
ファイル:Mery_小マクロ集_アウトライン.png|小マクロ集 アウトラインイメージ
* [[マテリアルデザインっぽいアイコンと『小マクロ集』]] (last_modified: 2020/01/04) ※アイコン収録数 '''337''' コ
</gallery><br clear=all>
* [[GetKeyState.exe(キー状態取得実行ファイル)]] の [[GetKeyState.exe(キー状態取得実行ファイル)#実装例|サンプルコード2, 3]] (2019/03/23 - 2019/12/03)
* [[マクロ用 定数一覧]] (last_modified: 2021/01/27)


== 外部サイトに投稿したマクロ ==
== 外部サイトに投稿したマクロ ==
* [https://pastebin.com/5rUw36qM StrConvテキスト変換メニュー] (uploaded: 2018/08/25) <br> 山本隆 氏作成の [http://gesource.jp/soft/strconv/strconvdll.html 文字変換ライブラリ StrConvDLL] の機能をポップアップメニューにまとめたマクロ
* [https://pastebin.com/5rUw36qM StrConvテキスト変換メニュー] (uploaded: 2018/08/25)
* [https://pastebin.com/Bci0eEx2 gPad用 文字数・行数・ヒット数] (uploaded: 2019/08/26) <br> Mery 用マクロ「[[検索ヒット数表示(選択文字列)#機能強化バージョン|文字数・行数・ヒット件数(選択文字列)]]」を [https://mfactory.me/ gPad] 用に改編したもの
** 山本隆 氏作成の [http://gesource.jp/soft/strconv/strconvdll.html 文字変換ライブラリ StrConvDLL] の機能をポップアップメニューにまとめたマクロ
<br><br>
* [https://pastebin.com/Bci0eEx2 gPad用 文字数・行数・ヒット数] (uploaded: 2019/08/26)
[[#TOP|>> 目次へ]]
** Mery 用マクロ「[[検索ヒット数表示(選択文字列)#機能強化バージョン|文字数・行数・ヒット件数(選択文字列)]]」を [https://mfactory.me/ gPad] 用に改編したもの
<br><br>


== 組み込み用コード・小関数 ==
== 組み込み用コード・小関数 ==
メインコードの途中に短い [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/function 関数] を置く場合は、最初の呼び出しコードより前に変数([https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/function 関数式])として定義しておいてもよい。
メインコードの途中に短い [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/function 関数] を置く場合は、最初の呼び出しコードより前に変数([https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/function 関数式])として定義しておいてもよい。
<source lang="javascript">
<syntaxhighlight lang="javascript">
{
{
   var hoge = "hogehoge";
   var hoge = "hogehoge";
144行目: 128行目:
   }
   }
}
}
</source>
</syntaxhighlight>
ならば、以下のような記述でも同じ意味 (ただし、関数式の場合は、最初に呼び出す文よりも前に定義しておくこと)。
ならば、以下のような記述でも同じ意味 (ただし、関数式の場合は、最初に呼び出す文よりも前に定義しておくこと)。
<source lang="javascript">
<syntaxhighlight lang="javascript">
// 関数式は最初に呼び出されるよりも前に定義すること
// 関数式は最初に呼び出されるよりも前に定義すること
var HogeFuga = function( str ) {
var HogeFuga = function( str ) {
154行目: 138行目:


document.selection.Text = HogeFuga( hoge );
document.selection.Text = HogeFuga( hoge );
</source>
</syntaxhighlight>
<br>


=== メタ記号をエスケープする ===
=== メタ記号をエスケープする ===
任意の文字列を正規表現変数 <syntaxhighlight lang="javascript" inline>RegExp()</syntaxhighlight> におさめる前などにエスケープ(退避修飾)する。


任意の文字列を正規表現変数 <source lang="javascript" inline>RegExp()</source> におさめる前などにエスケープ(退避修飾)する。
* '''正規表現のメタ記号のみ''' をエスケープする方法。
<br><br>
* '''正規表現のメタ記号のみ''' をエスケープする方法。<br>
: ※ ref. 『[https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping 正規表現 - JavaScript | MDN]』
: ※ ref. 『[https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping 正規表現 - JavaScript | MDN]』


<source lang="javascript">
<syntaxhighlight lang="javascript">
/**
/**
  * 関数 RegQuote( str )
  * 関数 RegQuote( str )
174行目: 156行目:
   return str.replace( /[.*+?^=!:${}()|[\]\/\\]/g, "\\$&" );  
   return str.replace( /[.*+?^=!:${}()|[\]\/\\]/g, "\\$&" );  
}
}
</source>
</syntaxhighlight>
<br>
 
* または、記述の簡単な方法。<br>
* または、記述の簡単な方法(ただし、<q>処理対象の文字列が長大</q> な場合や <q>日本語テキスト</q> の場合には適さない)。
: ※ ref. 『[https://ja.wikibooks.org/wiki/JavaScript/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE#RegExp JavaScript/正規表現 - Wikibooks]』
: ※ ref. 『[https://ja.wikibooks.org/wiki/JavaScript/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE#RegExp JavaScript/正規表現 - Wikibooks]』


<source lang="javascript">
<syntaxhighlight lang="javascript">
/**
/**
  * 関数 Quote( str )
  * 関数 Quote( str )
191行目: 173行目:
}
}


// Wikibooks 版は関数を無駄にネストしている…
// function Quote( str ) {
// function Quote( str ) {
//  return str.replace( /\W/g, function( $0 ) {
//  return str.replace( /\W/g, function( $0 ) {
196行目: 179行目:
//  } );
//  } );
// }
// }
</source>
</syntaxhighlight>
: ※ JavaScript において <b style="color:#c00;"> $& </b> は "マッチした部分文字列全体" を意味する JavaScript ネイティブの [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter 特殊変数]。<br> 置換関数 function() の引数がひとつの場合、その引数は <b style="color:#c00;"> $& </b> と同じ意味になるので、上の関数で '''$0''' と記述していることに特別な意味はない('''tmp''' や '''str'''、'''chr''' など任意の文字列でもよい)。
: ※ JavaScript において <b style="color:#c00;"> $& </b> は "マッチした部分文字列全体" を意味する JavaScript ネイティブの [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter 特殊変数]。
: ※ 後述、[[#関数の「呼び出しコスト」|関数の「呼び出しコスト」]] の項に書いているように、上出のふたつの <source lang="javascript" inline>Quote( str )</source> 関数の処理速度にはちがいが生じる。
:: 置換関数 function() の引数がひとつの場合、その引数は <b style="color:#c00;"> $& </b> と同じ意味になるので、上の関数で '''$0''' と記述していることに特別な意味はない('''tmp''' や '''str'''、'''chr''' など任意の文字列でもよい)。
<br><br>
: ※ 後述、[[#関数の「呼び出しコスト」|関数の「呼び出しコスト」]] の項に書いているように、上出のふたつの <syntaxhighlight lang="javascript" inline>Quote( str )</syntaxhighlight> 関数の処理速度にはちがいが生じる。


=== 数値を3ケタ区切り(カンマ区切り)にする ===
=== 数値を3ケタ区切り(カンマ区切り)にする ===
<source lang="javascript">
<syntaxhighlight lang="javascript">
/**
/**
  * 関数 SeparateNum( num )
  * 関数 SeparateNum( num )
214行目: 197行目:
   return num.toString().replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
   return num.toString().replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
}
}
</source>
</syntaxhighlight>
<br>
 
小数、または半角数字を含む文字列の場合は
小数、または半角数字を含む文字列の場合は
<source lang="javascript">
<syntaxhighlight lang="javascript">
/**
/**
  * 関数 SeparateNum2( num )
  * 関数 SeparateNum2( num )
235行目: 218行目:
   return a.join( "" );
   return a.join( "" );
}
}
</source>
</syntaxhighlight>
<br>


=== 数値を小数点以下3ケタの固定長にする ===
=== 数値を小数点以下3ケタの固定長にする ===
<source lang="javascript">
<syntaxhighlight lang="javascript">
/**
/**
  * 関数 NumFix( num )
  * 関数 NumFix( num )
261行目: 243行目:
// 対象が数値( Number 型)であれば toFixed() だけでよい
// 対象が数値( Number 型)であれば toFixed() だけでよい
// num = num.toFixed( 3 );
// num = num.toFixed( 3 );
</source>
</syntaxhighlight>
<br>
[[#TOP|>> 目次へ]]
<br><br>


=== 数値をケタ埋め(ゼロ埋め)する ===
=== 数値をケタ埋め(ゼロ埋め)する ===
※ 引数の型に応じた関数を使用する。
※ 引数の型に応じた関数を使用する。


<source lang="javascript">
<syntaxhighlight lang="javascript">
/**
/**
  * 関数 Pad( num )
  * 関数 Pad( num )
280行目: 259行目:
   return num < 10 ? "0" + num : num;
   return num < 10 ? "0" + num : num;
}
}
</source>
</syntaxhighlight>
<source lang="javascript">
<syntaxhighlight lang="javascript">
/**
/**
  * 関数 Pad2( str )
  * 関数 Pad2( str )
294行目: 273行目:
   } );
   } );
}
}
</source>
</syntaxhighlight>
<source lang="javascript">
<syntaxhighlight lang="javascript">
/**
/**
  * 関数 NumPad2( val )
  * 関数 NumPad2( val )
307行目: 286行目:
   } );
   } );
}
}
</source>
</syntaxhighlight>
<br>


=== 任意の文字列のくりかえしで埋める ===
=== 任意の文字列のくりかえしで埋める ===
※ Windows XP 用
※ Windows XP 用
<source lang="javascript">
<syntaxhighlight lang="javascript">
/**
/**
  * 関数 Repeat( str, count )
  * 関数 Repeat( str, count )
326行目: 304行目:
   return ret;
   return ret;
}
}
</source>
</syntaxhighlight>
<br>
 
=== ascii 文字に対応する全角英数記号を半角変換 / 数値専用の入力ダイアログ ===
※ IME: ON の状態で入力された「全角数字」も許容、「全角/半角の数字」以外の文字列は無視する入力ダイアログのサンプルコード
<syntaxhighlight lang="javascript">
/**
* 関数 ToHalfWidth( str )
*
*  ascii 文字に対応する全角英数記号の文字列を半角変換した ascii 文字列で返す
* ※ カタカナや ascii 文字に対応しない文字列部分はそのまま残す
* ※ 引数は「文字列値」のみ
*/
function ToHalfWidth( str ) {
  return str.replace( /[!-~]/g, function( tmp ) {
      return String.fromCharCode( tmp.charCodeAt(0) - 0xFEE0 )
} ) };
 
/**
* Number( ToHalfWidth( Prompt( message,"" ) ).replace( /\D/g, "" ) )
*
* 正の整数値専用の入力ダイアログ
* ※ ダイアログに入力された "全角/半角の数字" 部分のみを "正の整数値" として取得する
*    i.e. 入力値が「1あ2」「-12」「1.2」「012A」ならば 12 とみなす
*/
var p = Number(
  ToHalfWidth( Prompt( "数値を入力", "" ) )
  .replace( /\D/g, "" ) // 置換処理で半角数字以外を削除
);
 
// e.g. 入力された値がゼロや無効な文字列のみなら「キャンセル」
if ( ! p ) { Status = "キャンセル"; }
else      { Alert( p ); }
</syntaxhighlight>


=== ストップウォッチ・タイマー ===
=== ストップウォッチ・タイマー ===
 
<syntaxhighlight lang="javascript">
<source lang="javascript">
// 計測開始 ※ ソースコードの先頭付近におくこと
// 計測開始 ※ ソースコードの先頭付近におくこと
var start = new Date();
var start = new Date();
340行目: 348行目:
// ステータスバーに処理時間を表示
// ステータスバーに処理時間を表示
Status = ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒";
Status = ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒";
</source>
</syntaxhighlight>
<br>


=== Mery のバージョン情報 ===
=== Mery のバージョン情報 ===
 
<syntaxhighlight lang="javascript">
<source lang="javascript">
/**
/**
  * Mery のバージョン情報
  * Mery のバージョン情報
352行目: 358行目:
                 + editor.Version;
                 + editor.Version;
Status = meryVersion;
Status = meryVersion;
</source>
</syntaxhighlight>
<br>


=== JavaScript (JScript) エンジンのバージョン情報 ===
=== JavaScript (JScript) エンジンのバージョン情報 ===
※ ref. 『[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc392005%28v=msdn.10%29 ScriptEngine 関数 (JScript) | Microsoft Docs]』
※ ref. 『[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc392005%28v=msdn.10%29 ScriptEngine 関数 (JScript) | Microsoft Docs]』


<source lang="javascript">
<syntaxhighlight lang="javascript">
/**
/**
  * JavaScript (JScript) エンジンのバージョン情報
  * JavaScript (JScript) エンジンのバージョン情報
367行目: 372行目:
           + ScriptEngineBuildVersion();
           + ScriptEngineBuildVersion();
Status = engine;
Status = engine;
</source>
</syntaxhighlight>
<br>
[[#TOP|>> 目次へ]]
<br><br>


== マクロ覚え書き ==
== リンク集 ==
 
=== リンク集 ===
<br>
'''[[メインページ|MeryWiki]] / [https://www.haijin-boys.com/ Haijin Boys Online]''' 内
'''[[メインページ|MeryWiki]] / [https://www.haijin-boys.com/ Haijin Boys Online]''' 内
* [[マクロライブラリ#その他|マクロライブラリ]] にある ks 氏らの「[[マクロ覚え書き(開発者向け)|マクロ覚え書き]]」
* [[マクロライブラリ#開発者向け|マクロライブラリ]] の 「[[マクロ覚え書き(開発者向け)]]」
* 黄身氏の「[[利用者:黄身#覚え書き|覚え書き]]」<br>
* 黄身氏の「[[利用者:黄身#覚え書き|覚え書き]]」
* MeryWiki の [[マクロリファレンス]]
* MeryWiki の [[マクロリファレンス]](Mery ver 2.6.7 用)
* MeryWiki の [[よくある質問|FAQ (よくある質問)]]
* MeryWiki の [[マクロリファレンス:3]](Mery ver 3.0.0 以降用)
* [https://www.haijin-boys.com/discussions Mery 公式フォーラム]  
* MeryWiki の [[よくある質問]]
<br>
* [https://www.haijin-boys.com/discussions Mery 公式フォーラム]
; 外部サイト
; 外部サイト
* MDN web docus(mozzila)の「[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference JavaScript リファレンス]」<br>
* MDN web docus(mozzila)の[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference 「JavaScript リファレンス」]
* MSDN(Microsoft Docs)の「[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc392483%28v=msdn.10%29 Microsoft Windows スクリプト テクノロジ]
* MSDN(Microsoft Docs)の[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc392483%28v=msdn.10%29 「Microsoft Windows スクリプト テクノロジ」]
* MSDN(Microsoft Docs)の「[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc409859%28v%3dmsdn.10%29 JScript ランゲージ リファレンス]
* MSDN(Microsoft Docs)の[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc409859%28v%3dmsdn.10%29 「JScript ランゲージ リファレンス」]
* MSDN(Microsoft Docs)の「[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc364460%28v=msdn.10%29 WSH リファレンス]
* MSDN(Microsoft Docs)の[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc364460%28v=msdn.10%29 「WSH リファレンス」]
* MSDN(Microsoft Docs)の「[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc427968%28v%3dmsdn.10%29 FileSystemObject リファレンス]」<br>
* MSDN(Microsoft Docs)の[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc427968%28v%3dmsdn.10%29 「FileSystemObject リファレンス」]
* MDN web docus(mozzila)の「[https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions JavaScript ガイド >> 正規表現]
* MDN web docus(mozzila)の[https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions 「JavaScript ガイド >> 正規表現」]
* MSDN(Microsoft Docs)の「[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc427946%28v=msdn.10%29 JScript 正規表現の概説]
* MSDN(Microsoft Docs)の[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc427946%28v=msdn.10%29 「JScript 正規表現の概説」]
* onigmo(鬼雲 / 鬼車・改)の「[https://github.com/k-takata/Onigmo/blob/master/doc/RE.ja 正規表現 ReadMe]
* onigmo(鬼雲 / 鬼車・改)の[https://github.com/k-takata/Onigmo/blob/master/doc/RE.ja 「正規表現 ReadMe」]
<br><br>
 
----
== Tips ==
拙作マクロはポップアップメニューを利用するものが多いので、Tips はその方面の内容に偏ってしまいますが、以下、個人的に注意していることや気付いたことなど。
拙作マクロはポップアップメニューを利用するものが多いので、Tips はその方面の内容に偏ってしまいますが、以下、個人的に注意していることや気付いたことなど。


=== Document と Editor.ActiveDocument ===
; マクロをツールバーアイコン化する意味(?)
大前提として [[マクロライブラリ]] の [[マクロ覚え書き(開発者向け)#window.Document と Editor.ActiveDocument の違い|マクロ覚え書き(開発者向け)]] で説明されているような違いがあるが、 [[マクロリファレンス:Editor インターフェイス#ActiveDocument プロパティ|Editor.ActiveDocument]] は、マクロ開始時点でタブにフォーカスがあろうとなかろうと [[マクロリファレンス:Document インターフェイス|window.Document]] オブジェクトを取得することができる、という違いもある。
* 通常、アウトプットバーやアウトラインペイン、検索/置換ダイアログにフォーカスがあると、ショートカットキーからはマクロを起動することはできないし、起動してもマクロ開始時点での <code>Document</code> オブジェクトが <code>undefined</code> になるので <code>Document.Selection</code> のメソッドなどが使用できなくなる。
* それにたいして、<code>Document</code> のかわりに <code>Editor.ActiveDocument</code> で記述したマクロであれば、<u>エディタ領域にフォーカスがない場合でもツールバーアイコンやマクロメニューからマクロを起動することができる</u>ので、マウス派・ツールバーアイコン派にはありがたい抜け道である。
: ※ ただし、アクティブなタブ以外を操作・編集するマクロにおいては <code>Editor.Documents.Item(n)</code> などのような形式での記述が必要。


=== アイコン化したマクロ ===
マウス派・ツールバーアイコン派の sukemaru においては、マクロをツールバー/マクロバーから使用するために [[マテリアルデザインっぽいアイコンと『小マクロ集』|アイコン]] を作ったり、マクロバーに1つでも多くのアイコンを詰め込むために 試行錯誤 したり…。
通常、フォーカスがアウトプットバーやアウトラインペイン、検索/置換ダイアログにあると、ポップアップメニューやショートカットキーからマクロを起動することはできない。<br>
 
しかし、[[マクロリファレンス:Document インターフェイス|Document]] オブジェクトのかわりに [[マクロリファレンス:Editor インターフェイス#ActiveDocument プロパティ|Editor.ActiveDocument]] で記述したマクロであれば、エディタ領域にフォーカスがない場合でもツールバーアイコンやマクロメニューからマクロを起動できる。
マクロ/プラグイン/外部ツールの登録数が多かったり <code>#icon="hoge.ico"</code> でアイコン化しているマクロが多いせいか、Mery の起動がもたつくのが悩ましい… ([[#投稿した構文ファイル|自作の編集モード]] が重いのも影響しているかも)
<br><br>
ただし、アクティブなタブ以外を操作・編集するマクロにおいては <source lang="javascript" inline>Editor.Documents.Item( dd )</source> などのような記述が必要。
<br><br>
マクロをツールバー/マクロバーから使用するために [[マテリアルデザインっぽいアイコンと『小マクロ集』|アイコン]] を作ったり、マクロバーにアイコンを詰め込むために [[#スクショ|試行錯誤]] したりも…。
<br><br>


=== イベントマクロ ===
=== イベントマクロ ===
411行目: 415行目:
{|class="wikitable"
{|class="wikitable"
!フォーカスを受け取った時
!フォーカスを受け取った時
| エディタのウインドウがアクティブになったとき。<br> ・「オプション」 などモーダルなダイアログからの復帰時には発動しない<br> ・<source lang="javascript" inline>Editor.ActiveDocument == Document</source>
| エディタのウインドウがアクティブになったとき。<br> ・「オプション」 などモーダルなダイアログからの復帰時には発動しない<br> ・<code>Editor.ActiveDocument == Document</code>
|-
|-
!フォーカスを失った時
!フォーカスを失った時
| エディタのウインドウがアクティブでなくなったとき。<br> ・「検索」 「置換」 ダイアログを開いたときにも発動する…<br> ・<source lang="javascript" inline>Editor.ActiveDocument != Document</source>
| エディタのウインドウがアクティブでなくなったとき。<br> ・「検索」 「置換」 ダイアログを開いたときにも発動する…<br> ・<code>Editor.ActiveDocument != Document</code>
|-
|-
!ファイルを開いた時
!ファイルを開いた時
438行目: 442行目:
|-
|-
!<span style="color:#c00;">文字が挿入された時</span>
!<span style="color:#c00;">文字が挿入された時</span>
| 文字数が増えたとき?<br> ・選択範囲文字列の [ Ctrl+ドラッグ ] による複製や、 <br> クリップボードからのペースト、<br> マクロの <span style="color:#0000c0;">Document.Write( "hoge" )</span> や <br> <span style="color:#0000c0;">Document.Selection.Text = "hoge"</span> では発動しないようだった <br> ・<span style="color:#c00;">'''遅延''' を大きく設定しないと、すごくジャマ</span>
| 文字数が増えたとき?<br> ・選択範囲文字列の [ Ctrl+ドラッグ ] による複製や、 <br> クリップボードからのペースト、<br> マクロの <code>Document.Write( "hoge" )</code> や <br> <code>Document.Selection.Text = "hoge"</code> では発動しないようだった <br> ・<span style="color:#c00;">'''遅延''' を大きく設定しないと、すごくジャマ</span>
|-
|-
!編集モードが変更された時
!編集モードが変更された時
458行目: 462行目:
|ファイルを保存する前。
|ファイルを保存する前。
|}
|}
<br>
 
: ※ イベントマクロ であっても、ショートカットキーなどで任意のタイミングに強制的に実行できる。
: ※ 複数のイベントマクロで <b style="color:#c00;">各赤字イベント</b> の遅延時間の設定は共有されるので、同じイベントに複数のマクロを割りあてている場合にマクロの発動の順序を恣意的に指定することはできない。
:: → マクロのコードを統合するか、イベントを設定するマクロをひとつだけにして [[マクロ覚え書き(開発者向け)#他のマクロの実行方法|include]] で別のマクロを発動させることができる。
: ※ イベントマクロ であっても、ショートカットキーなどから任意のタイミングで強制的に実行することもできる。
: ※ イベントマクロでない「マクロA」のコードでファイルを 開く または 閉じる をおこない、それ以降にも「マクロA」のコードが続いている場合は、ファイルを開いた時/閉じた時の「イベントマクロB」は発動しないことがある。
: ※ イベントマクロでない「マクロA」のコードでファイルを 開く または 閉じる をおこない、それ以降にも「マクロA」のコードが続いている場合は、ファイルを開いた時/閉じた時の「イベントマクロB」は発動しないことがある。
<br>
 
* sukemaru の Mery では、「[[バイト数#バイト数と文字数・行数|バイト数]]」マクロと「[[検索ヒット数表示(選択文字列)#機能強化バージョン|文字数・行数・ヒット件数(選択文字列)]]」マクロの機能を統合したマクロに「ファイルを開いた時」「'''選択範囲が変更された時'''」「'''テキストが変更された時'''」「'''文字が挿入された時'''」「アクティブな文書が変更された時」イベントを設定している('''太字''' のイベントには遅延時間を 1 秒に設定。 ロースペックな PC ゆえ、一定以上の長さのファイル/タブにおいては機能を制限してある)。<br> 遅延時間が短すぎると、"文字列や選択範囲を変更するような他のマクロの実行後に、そのマクロからのステータスメッセージが読めなくなるから"、という意味もある。
* sukemaru の Mery では、「[[バイト数#バイト数と文字数・行数|バイト数]]」マクロと「[[検索ヒット数表示(選択文字列)]]」マクロの機能を統合した「[[検索ヒット数表示(選択文字列)#機能強化バージョン|文字数・行数・バイト数・ヒット件数]]」マクロに「ファイルを開いた時」「<span style="color:#c00;">選択範囲が変更された時</span>」「<span style="color:#c00;">テキストが変更された時</span>」「<span style="color:#c00;">文字が挿入された時</span>」「アクティブな文書が変更された時」イベントを設定している(<span style="color:#c00;">赤字</span> の各イベントには遅延時間を 1 秒に設定。 ロースペックな PC ゆえ、一定以上の長さのファイル/タブにおいては機能を制限してある)。
* また、「[[編集モードの自動選択#sukemaru 版2(include版)|編集モードの自動選択 (include版)]]」マクロを「ファイルを開いた時」「文書を閉じた時」イベントに、[[編集モードの自動選択#サブマクロ|補助マクロ]] を「ファイルを保存した時」イベントに設定して、それなりに按配よく運用できている。<br> ([[includeライブラリ|include ライブラリ]] を利用して、複数のファイルを開いたときにも、それぞれのタブにたいして編集モードの変更や書き換え禁止を適用できるようにしてある)
** 遅延時間が短すぎると、"文字列や選択範囲を変更するような他のマクロの実行後に、そのマクロからのステータスメッセージが読めなくなるから"、という意味もある。
<br><br>
* また、「[[編集モードの自動選択#sukemaru 版2(include版)|編集モードの自動選択 (include版)]]」マクロを「ファイルを開いた時」「文書を閉じた時」イベントに、[[編集モードの自動選択#サブマクロ|補助マクロ]] を「ファイルを保存した時」イベントに設定して、それなりに按配よく運用できている。
[[#TOP|>> 目次へ]]
** ([[includeライブラリ]] を利用して、複数のファイルを開いたときにもそれぞれのタブにたいして編集モードの変更や書き換え禁止を適用できるようにしてある)
<br><br>


=== ポップアップメニュー ===
=== ポップアップメニュー ===
sukemaru の環境では、メニューに表示するアイテムが 5000 件とか 10000 件とかを超えるとポップアップメニューが表示されず(エラーメッセージも表示されず)にマクロが終了してしまうことがある…。<br>
sukemaru の環境では、メニューに表示するアイテムが 5000 件とか 10000 件とかを超えるとポップアップメニューが表示されず(エラーメッセージも表示されず)にマクロが終了してしまうことがある…。
「[[ポップアップメニューで検索先にジャンプ#sukemaru 版|検索ジャンプ]]」マクロの include 版で発生するのだが、ポップアップメニューを表示する直前にステータスバーに表示すべき情報を <source lang="javascript" inline>ClipboardData.SetData( Status );</source> でコピーしておくと、<br>
 
ヒット数: 21,525 件 ( 4 件目 ) ・ 21,525 行 ( 4 行目 ) / 全体の行数: 61,001 行  [ 12. 906 秒 ]
「[[ポップアップメニューで検索先にジャンプ#sukemaru 版|検索ジャンプ]]」マクロの include 版で発生するのだが、ポップアップメニューを表示する直前にステータスバーに表示すべき情報を <code>ClipboardData.SetData( Status );</code> でコピーしておくと、
のようにデータが残ったので、前処理段階でコケたのではなくポップアップメニューの描画のさいにコケていたようだ。<br>
 
<code>ヒット数: 21,525 件 ( 4 件目 ) ・ 21,525 行 ( 4 行目 ) / 全体の行数: 61,001 行  [ 12. 906 秒 ]</code>
 
のようにデータが残ったので、前処理段階でコケたのではなくポップアップメニューの描画のさいにコケていたようだ。
 
また、11 万行の文書から空行を検索したとき、ステータスバーに以下のメッセージを表示して
また、11 万行の文書から空行を検索したとき、ステータスバーに以下のメッセージを表示して
一致: 27,814 行 / 空白行数: 27,849 行 / 全体の行数: 111,186 行  [ 6. 485 秒 ]
 
ポップアップメニューも表示されたが、実際に表示されていたアイテム数は 6000 件台で、20000 件以上のアイテムは表示されずにスポイルされてしまっていたということもあった。<br><br>
<code>一致: 27,814 行 / 空白行数: 27,849 行 / 全体の行数: 111,186 行  [ 6. 485 秒 ]</code>
 
ポップアップメニューも表示されたが、実際に表示されていたアイテム数は 6000 件台で、20000 件以上のアイテムは表示されずにスポイルされてしまっていたということもあった。
 
以下の単純なコードでアイテム 10000 件のポップアップメニューを表示させようとしても、4000 件ぐらい(4000 前後で不定)までしか表示されない…。
以下の単純なコードでアイテム 10000 件のポップアップメニューを表示させようとしても、4000 件ぐらい(4000 前後で不定)までしか表示されない…。
<source lang="javascript">
<syntaxhighlight lang="javascript">
var m = CreatePopupMenu();
var m = CreatePopupMenu();
for ( var i = 1; i <= 10000; i ++ ) {
for ( var i = 1; i <= 10000; i ++ ) {
483行目: 495行目:
}
}
var r = m.Track( mePosMouse );
var r = m.Track( mePosMouse );
</source>
</syntaxhighlight>
<br>
 
環境依存の不具合かもしれないが、はて…?
環境依存の不具合かもしれないが、はて…?
<br><br>


==== オプションフラグ ====
==== オプションフラグ ====
[[マクロリファレンス:PopupMenu インターフェイス#Add メソッド|PopupMenu.Add() メソッド]] の第三引数 '''Flags''' : int を数値化すると
[[マクロリファレンス:PopupMenu インターフェイス#Add メソッド|PopupMenu.Add() メソッド]] の第三引数 '''Flags''' : int を数値化すると
<source lang="javascript">
<syntaxhighlight lang="javascript">
meMenuChecked = 1
meMenuChecked = 1
meMenuGrayed = 2
meMenuGrayed = 2
meMenuChecked + meMenuGrayed = 3
meMenuChecked + meMenuGrayed = 3
meMenuSeparator = 4
meMenuSeparator = 4
</source>
</syntaxhighlight>
となるので、真偽値が <source lang="javascript" inline>true=1</source> / <source lang="javascript" inline>false=0</source> で評価されることを利用して、真偽値を返す変数や条件式を代入することができる(ただし Number 型に変換する必要がある → 算術演算子「+」をつけるなど)。
となるので、真偽値が <syntaxhighlight lang="javascript" inline>true=1</syntaxhighlight> / <syntaxhighlight lang="javascript" inline>false=0</syntaxhighlight> で評価されることを利用して、真偽値を返す変数や条件式を代入することができる(ただし Number 型に変換する必要がある ← 算術演算子 <syntaxhighlight lang="javascript" inline>+</syntaxhighlight> をつけるなど)。
<source lang="javascript">
<syntaxhighlight lang="javascript">
var menu = CreatePopupMenu();
var menu = CreatePopupMenu();
var hoge = true;
var hoge = true;
var fuga = false;
var fuga = false;
var piyo = true;


menu.Add( "Hoge", 1, + hoge ); // "+" を付けて数値化すると meMenuChecked
menu.Add( "Hoge", 1, + hoge ); // "+" を付けて数値化すると meMenuChecked
menu.Add( "Fuga", 2, !fuga * 2 ); // (!fuga = 1) *2 なので meMenuGrayed
menu.Add( "Fuga", 2, !fuga * 2 ); // (!fuga = 1) *2 なので meMenuGrayed
if ( piyo ) {
  menu.Add( "Piyo", 3 ); // piyo が true のときだけ表示
}
var num = menu.Track( mePosMouse );
var num = menu.Track( mePosMouse );
</source>
</syntaxhighlight>


: ※ オプションフラグ ''meMenuGrayed'' を使用して条件付きで特定の項目をグレーアウトするだけでなく、<source lang="javascript" inline>menu.Add( ... );</source> の行を [https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#if...else_statement if() 文] で囲むなどすれば、状況に応じたメニュー項目だけを表示させることもできる。
: ※ オプションフラグ ''meMenuGrayed'' を使用して条件付きで特定の項目をグレーアウトするだけでなく、<code>menu.Add( ... );</code> の行を [https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#if...else_statement if() 文] で囲むなどすれば、状況に応じたメニュー項目だけを表示させることもできる。
<br><br>


==== アクセラレータ ====
==== アクセラレータ ====
ポップアップメニューのラベルの文字列に「半角アンパサンド記号 '''<q>&</q>''' + 半角英数字 (またはアスキー記号)」を付記することで、アクセラレータ(アクセスキー)を設定することができる。<br>
ポップアップメニューのラベルの文字列に「半角アンパサンド記号 '''<q>&</q>''' + '''半角英数字''' (またはアスキー記号)」を付記することで、アクセラレータ(アクセスキー)を設定することができる。
ラベルの先頭に連番数字などがある場合は、アンパサンド記号を付加することで、数字をアクセラレータにするとよい。<br>
 
ラベルの先頭に連番数字などがある場合は、数字のまえにアンパサンド記号を付加して数字をアクセラレータにすることもできる。
 
そのさい、Shift キー付きでの入力が必要な記号は Shift キーなしで入力可能なキーのラベルと同一視される (e.g. 「'''&#'''」で '''<q>#</q>''' 記号をアクセラレータに指定した場合、JIS 配列のキーボードでは <kbd>3</kbd> キーがアクセラレータになる)。
そのさい、Shift キー付きでの入力が必要な記号は Shift キーなしで入力可能なキーのラベルと同一視される (e.g. 「'''&#'''」で '''<q>#</q>''' 記号をアクセラレータに指定した場合、JIS 配列のキーボードでは <kbd>3</kbd> キーがアクセラレータになる)。


* <span style="color:#0000c0;">'''<q>&</q>''' 記号でアクセラレータ化する文字の位置は限定されないが、<u>最初の '''<q>&</q>''' 記号のうしろの文字がアクセラレータになる</u></span>( … とおもわれる ← ポップアップメニュー内で「下線つきで表示される文字」と一致しないことがある)。
* <span style="color:#0000c0;">'''<q>&</q>''' 記号でアクセラレータ化する文字の位置は限定されないが、<u>最初の '''<q>&</q>''' 記号のうしろの文字がアクセラレータになる</u></span>( … とおもわれる ← ポップアップメニュー内で「下線つきで表示される文字」と一致しないことがある)。
* <span style="color:#c00;">全角文字はアクセラレータにできない。</span>
* <span style="color:#c00;">全角文字はアクセラレータにできない。</span>
* <span style="color:#c00;">ラベル文字列に含まれる '''<q>&</q>''' 記号はすべてエスケープされてしまい、ポップアップメニューには表示されなくなるので、ラベルに '''<q>&</q>''' 記号を表示させたいときは、'''<q>&&</q>''' のように二重に記述する必要がある。</span><br> → 不特定の文字列をラベルにする場合は、あらかじめ <source lang="javascript" inline>String.replace( /&/g, "&&" )</source> と記述するとよい。
* <span style="color:#c00;">ラベル文字列に含まれる '''<q>&</q>''' 記号はすべてエスケープされてしまい、ポップアップメニューには表示されなくなるので、ラベルに '''<q>&</q>''' 記号を表示させたいときは、'''<q>&&</q>''' のように二重に記述する必要がある。</span>
: ※ '''<q>&&</q>''' で表示される '''<q>&</q>''' 記号は、アクセラレータにならない。
** → 不特定の文字列 <syntaxhighlight lang="javascript" inline>String</syntaxhighlight> (文書内から抽出したテキストなど)をラベルにする場合は、あらかじめ <syntaxhighlight lang="javascript" inline>String.replace( /&/g, "&&" )</syntaxhighlight> と記述するとよい。
* <span style="color:#0000c0;">同じキーが重複してアクセラレータに指定されていると、そのキーを押した場合、アイテム間をトグル移動する(その場合は <kbd>Enter</kbd> キーで決定する)。</span><br> → アイテム数が多くなるメニューの場合、<source lang="javascript" inline>menu.Add( "キャンセル & ", 0 );</source> という行を 10 件とか 20 件ごとに挿入すると、スペースキーでポップアップメニュー内をスクロールさせることができる。
: ※ '''<q>&&</q>''' の記述で表示される '''<q>&</q>''' 記号は、アクセラレータにならない。
* <span style="color:#0000c0;">同じキーが重複してアクセラレータに指定されていると、そのキーを押した場合、アイテム間をトグル移動する(その場合は <kbd>Enter</kbd> キーで決定する)。</span>
** → アイテム数が多くなるメニューの場合、<syntaxhighlight lang="javascript" inline>menu.Add( "キャンセル & ", 0 );</syntaxhighlight> という行を 10 件とか 20 件ごとに挿入すると、スペースキーでポップアップメニュー内をスクロールさせることができる。
: ※「'''&<span style="background:#bfdfff;"> </span>'''」(半角アンパサンド+半角空白) で半角スペースをアクセラレータに指定したアイテムは、<kbd>Space</kbd> キーがアクセスキーになる。
: ※「'''&<span style="background:#bfdfff;"> </span>'''」(半角アンパサンド+半角空白) で半角スペースをアクセラレータに指定したアイテムは、<kbd>Space</kbd> キーがアクセスキーになる。
<source lang="javascript">
<syntaxhighlight lang="javascript">
/* アクセラレータを付加する */
/* アクセラレータを付加する */


542行目: 560行目:


var ret = menu.Track( 0 );
var ret = menu.Track( 0 );
</source>
</syntaxhighlight>
<source lang="javascript">
<syntaxhighlight lang="javascript">
/* 10 行ごとに「キャンセル」項目を挿入し、スペースキーでスクロール可能にする */
/* 10 行ごとに「キャンセル」項目を挿入し、スペースキーでスクロール可能にする */


555行目: 573行目:
     menu.Add( "", 0, meMenuSeparator );
     menu.Add( "", 0, meMenuSeparator );
   }
   }
   menu.Add( arr[i].slice( 0, 30 ), i + 1 );
   menu.Add( arr[i].slice( 0, 30 ).replace( /&/g, "&&" ), i + 1 );
}
}


562行目: 580行目:
   document.selection.SetActivePoint( mePosLogical, 1, y );
   document.selection.SetActivePoint( mePosLogical, 1, y );
}
}
</source>
</syntaxhighlight>
<br>


==== ラベルの整形 ====
==== ラベルの整形 ====
* 基本的にポップアップメニュー(警告・確認ダイアログなどもだが)は UI フォントで表示されるので、文字列が英数字の羅列の場合には読みづらい ( …と個人的に感じている)。<br>
* 基本的にポップアップメニュー(警告・確認ダイアログなどもだが)は UI フォントで表示されるので、文字列が英数字の羅列の場合には読みづらい ( …と個人的に感じている @WinXP)。
: 文書内の文字列など不特定の文字列をラベル化する「[[ポップアップメニューで検索先にジャンプ#sukemaru 版|検索ジャンプ]]」や「[[ブックマーク一覧ジャンプ#sukemaru 版|ブックマークジャンプ]]」、「[[「クリップボード履歴」メニューのマクロ化|クリップボード履歴メニュー]]」マクロでは、読みづらい半角アルファベットや記号を全角化させるなどしている。
: 文書内の文字列など不特定の文字列をラベル化する「[[ポップアップメニューで検索先にジャンプ#sukemaru 版|検索ジャンプ]]」や「[[ブックマーク一覧ジャンプ#sukemaru 版|ブックマークジャンプ]]」、「[[「クリップボード履歴」メニューのマクロ化]]」マクロでは、読みづらい半角アルファベットや記号を全角化させるなどしている。
<source lang="javascript">
<syntaxhighlight lang="javascript">
/**
/**
  * ポップアップメニューに表示するラベルを整形する
  * ポップアップメニューに表示するラベルを整形する
604行目: 621行目:
// 文字数を切り詰めた場合は「 ...」を付加
// 文字数を切り詰めた場合は「 ...」を付加
menuKey += ( str.length > menuWidth ) ? " ..." : "";
menuKey += ( str.length > menuWidth ) ? " ..." : "";


// 文字列の先頭に行番号(連番)を付加する
// 文字列の先頭に行番号(連番)を付加する
621行目: 637行目:
var num = ( "      " + y ).slice( - numWidth ).replace( /\d$/, "&$&" );
var num = ( "      " + y ).slice( - numWidth ).replace( /\d$/, "&$&" );
menuKey = num + ": " + menuKey;
menuKey = num + ": " + menuKey;
</source>
</syntaxhighlight>
: ※ このコードでは色々と unicode 文字を使用しているので、マクロの JS ファイルは UTF-8 などの形式で保存しなければならない。
: ※ このコードでは色々と unicode 文字を使用しているので、マクロの JS ファイルは UTF-8 などの形式で保存しなければならない。
<!--
 
: ※ Mery のダイアログのフォントは Mery.ini の「[[よくある質問#ダイアログのフォントを変更したい|隠しオプション]]」により任意のフォントに変更できるらしいので、個人的にしか使わない非公開マクロであれば、ラベルの整形についてはあまり気にする必要はないかも。
→ ポップアップメニューにはカスタムフォントは適用されない
-->
<br>
* また、「[[#マクロライブラリに投稿したマクロ|マクロライブラリに投稿したマクロ]]」の節の画像リンク(サムネイル)のように、タブインデントや連番のケタ埋め、サブメニューの活用などの工夫で、ポップアップメニューの体裁はある程度自分好みにカスタマイズできる。
* また、「[[#マクロライブラリに投稿したマクロ|マクロライブラリに投稿したマクロ]]」の節の画像リンク(サムネイル)のように、タブインデントや連番のケタ埋め、サブメニューの活用などの工夫で、ポップアップメニューの体裁はある程度自分好みにカスタマイズできる。
<br><br>


==== ステータスバーの表示 ====
==== ステータスバーの表示 ====
ポップアップメニュー表示のさいにステータスバーに任意の文字列を表示する場合は、 [[マクロリファレンス:PopupMenu インターフェイス#Track メソッド|PopupMenu.Track()]] の行の直前に ''[[マクロリファレンス:Window インターフェイス#Status プロパティ|Status]] = "hoge";'' を記述する。<br>
ポップアップメニューの表示と同時ににステータスバーに任意の文字列を表示する場合は、 [[マクロリファレンス:PopupMenu インターフェイス#Track メソッド|PopupMenu.Track()]] の行の直前に ''[[マクロリファレンス:Window インターフェイス#Status プロパティ|Status]] = "hoge";'' を記述する。
※ <syntaxhighlight lang="javascript" inline>PopupMenu.Track()</syntaxhighlight> が発動した時点でエディタウインドウ本体は停止するので、直後に <syntaxhighlight lang="javascript" inline>Status = "hoge";</syntaxhighlight> を記述しても、ポップアップメニューの項目を選択するかメニューをキャンセルするまで表示されない。


<source lang="javascript">
<code>PopupMenu.Track()</code> が発動した時点でエディタウインドウ本体は停止するので、直後に <syntaxhighlight lang="javascript" inline>Status = "hoge";</syntaxhighlight> を記述しても、ポップアップメニューの項目を選択するかメニューをキャンセルするまで表示されない。
 
<syntaxhighlight lang="javascript">
// e.g. ポップアップメニュー表示までのマクロの処理時間をステータス表示させる
// e.g. ポップアップメニュー表示までのマクロの処理時間をステータス表示させる


645行目: 657行目:
var lineArray = document.Text.split( "\n" );
var lineArray = document.Text.split( "\n" );
var menu = CreatePopupMenu();
var menu = CreatePopupMenu();
for ( var i = 0, y, flag; i < lineArray.length; i ++ ) {
for ( var i = 0, len = lineArray.length, y, flag; i < len; i ++ ) {
   y = i + 1;
   y = i + 1;
   flag = ( y == ay ) ? meMenuChecked : 0;
   flag = ( y == ay ) ? meMenuChecked : 0;
661行目: 673行目:
   document.selection.SetActivePoint( mePosLogical, 1, yy, false );
   document.selection.SetActivePoint( mePosLogical, 1, yy, false );
}
}
</source>
</syntaxhighlight>
<br>
 
: ※ 順番が逆になると、ステータスはポップアップメニュー項目を選択(またはキャンセル)するまで表示されない。
: ※ ポップアップメニューにかぎらず、[[マクロリファレンス:Window インターフェイス#Alert メソッド|警告 (Alert)]] や [[マクロリファレンス:Window インターフェイス#Confirm メソッド|確認 (Confirm)]]、 [[マクロリファレンス:Window インターフェイス#Prompt メソッド|入力 (Prompt)]] ダイアログなどモーダルなポップアップウインドウを表示させる場合も、同様に <syntaxhighlight lang="javascript" inline>Status = "hoge";</syntaxhighlight> を先に記述する必要がある。
: ※ ポップアップメニューにかぎらず、[[マクロリファレンス:Window インターフェイス#Alert メソッド|警告 (Alert)]] や [[マクロリファレンス:Window インターフェイス#Confirm メソッド|確認 (Confirm)]]、 [[マクロリファレンス:Window インターフェイス#Prompt メソッド|入力 (Prompt)]] ダイアログなどモーダルなポップアップウインドウを表示させる場合も、同様に <syntaxhighlight lang="javascript" inline>Status = "hoge";</syntaxhighlight> を先に記述する必要がある。
: ※ Mery メインウインドウのメニューバー項目のような、マウスホバーで動的にステータス表示を変更させる制御はできない。
: ※ Mery メインウインドウのメニューバー項目のような、マウスホバーで動的にステータス表示を変更させる制御はできない。
<br><br>
[[#TOP|>> 目次へ]]
<br><br>


==== 配列からポップアップメニューを生成 ====
==== 配列からポップアップメニューを生成 ====
[https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Loop_Statements/for_Statement for 文] などの [https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Loop_Statements/ ループ処理] によって配列からポップアップメニューのアイテムを生成する場合に、[[マクロリファレンス:PopupMenu インターフェイス#Add メソッド|PopupMenu.Add() メソッド]] の第二引数 '''Id''' (※通常は 1 ~ )と配列のアイテムのインデックス '''[ i ]''' の値(※通常は 0 ~ )を一致させたいときは、配列の先頭にダミーまたは空の要素を置いておき、ループ処理の開始インデックスを 1 にする。
[https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Loop_Statements/for_Statement for 文] などの [https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Loop_Statements/ ループ処理] によって配列からポップアップメニューのアイテムを生成する場合に、[[マクロリファレンス:PopupMenu インターフェイス#Add メソッド|PopupMenu.Add() メソッド]] の第二引数 '''id''' (※通常は 1 ~ )と配列のアイテムのインデックス '''[ i ]''' の値(※通常は 0 ~ )を一致させたいときは、配列の先頭にダミーまたは空の要素を置いておき、ループ処理の開始インデックスを 1 にする。
<source lang="javascript">
<syntaxhighlight lang="javascript">
var a = new Array( "" ); // 先頭に空のダミー要素を入れておく
var a = new Array( "" ); // 先頭に空のダミー要素を入れておく
a.push( "あああ" );
a.push( "あああ" );
a.push( "いいい" );
a.push( "いいい" );
680行目: 689行目:


var menuA = CreatePopupMenu();
var menuA = CreatePopupMenu();
for ( var i = 1; i < a.length; i ++ ) { // 開始値を 1 にすると
for ( var i = 1; i < a.length; i ++ ) { // 開始値を var i = 1 にすると
   menuA.Add( a[i], i ); // Id を ( i + 1 ) にする必要がない
   menuA.Add( a[i], i ); // Id を ( i + 1 ) にする必要がない
}
}
var num = menuA.Track( mePosMouse );
var numA = menuA.Track( mePosMouse );


// c.f. 空要素なしの配列 [ "あああ", "いいい", "ううう" ] をループ処理する場合
// c.f. 空要素なしの配列 [ "あああ", "いいい", "ううう" ] をループ処理する場合
691行目: 700行目:
   menuB.Add( b[i], i + 1 ); // Id を 1 ~ にするには ( i + 1 )
   menuB.Add( b[i], i + 1 ); // Id を 1 ~ にするには ( i + 1 )
}
}
</source>
var numB = menuB.Track( mePosMouse );
</syntaxhighlight>


==== サブメニュー ====
サブメニューを組みこむ場合、通常はそれぞれの PopupMenu オブジェクトをあらかじめ宣言しておくものだが、[[マクロリファレンス:PopupMenu インターフェイス#AddPopup メソッド|PopupMenu.AddPopup() メソッド]] 内の第二引数で定義することもできる。
[[マクロリファレンス:PopupMenu インターフェイス#Add メソッド|PopupMenu.Add() メソッド]] が大量に並んでいる項目群の一部をサブメニュー化して整理したくなったときなどに、サブメニューオブジェクトの宣言行を用意しなくて済むので便利である。


==== サブメニュー ====
サブメニューを組みこむ場合、通常はそれぞれの PopupMenu オブジェクトをあらかじめ宣言しておくものだが、[[マクロリファレンス:PopupMenu インターフェイス#AddPopup メソッド|PopupMenu.AddPopup() メソッド]] 内の第二引数で定義することもできる。<br>
[[マクロリファレンス:PopupMenu インターフェイス#Add メソッド|PopupMenu.Add() メソッド]] が大量に並んでいる項目群の一部をサブメニュー化して整理したくなったときなどに、サブメニューオブジェクトの宣言行を用意しなくて済むので便利である。<br>
サブメニューを多重に含むコードの場合、字下げ(インデント)を活用することで、メニューの階層構造を把握しやすくできる。
サブメニューを多重に含むコードの場合、字下げ(インデント)を活用することで、メニューの階層構造を把握しやすくできる。


<source lang="javascript">
<syntaxhighlight lang="javascript">
var mainMenu = CreatePopupMenu();
var mainMenu = CreatePopupMenu();
mainMenu.Add( "アイテム1", 1 );
mainMenu.Add( "アイテム1", 1 );
708行目: 719行目:


var r = mainMenu.Track( 0 );
var r = mainMenu.Track( 0 );
Alert( ret > 0 ? mainMenu.GetText( r ) : "キャンセル" );
Alert( r > 0 ? mainMenu.GetText( r ) : "キャンセル" );
</source>
</syntaxhighlight>
<br>
 
* 配列やオブジェクトからポップアップメニューの生成をするときにサブメニューを利用する場合、あらかじめサブメニューのラベルや各要素の振り分け方が決まっていれば難しいことはないが、<span style="color:#c00;">要素が不定数の配列やオブジェクトを複数のサブメニューに振り分けるのは簡単ではない…。</span>
* 配列やオブジェクトからポップアップメニューの生成をするときにサブメニューを利用する場合、あらかじめサブメニューのラベルや各要素の振り分け方が決まっていれば難しいことはないが、<span style="color:#c00;">要素が不定数の配列やオブジェクトを複数のサブメニューに振り分けるのは簡単ではない…。</span>


: → 組み込み関数「[[ポップアップメニューを手軽に扱う]]」や「[[階層化マクロメニュー]]」マクロなどのソースコードを参考にして自力でコードを組むか、組み込み関数「[[ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する]]」で一定数ごとにサブメニュー項目を自動生成して要素を放り込むしかない。
: → 組み込み関数「[[ポップアップメニューを手軽に扱う]]」や「[[階層化マクロメニュー]]」マクロなどのソースコードを参考にして自力でコードを組むか、組み込み関数「[[ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する]]」で一定数ごとにサブメニュー項目を自動生成して要素を放り込むしかない。
<br>
: ※ 自動分割サブメニューのページに「[[ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する#サンプルコード2|サンプルコード2]] (簡易版)」を追加した。
以下は、自動分割サブメニューのサンプルコード。
: 「[[ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する#サンプルコード1|サンプルコード1]]」の組み込み関数ではサブメニューオブジェクト専用の配列 smArray を用意して <code>smArray.push( CreatePopupMenu() );</code> → <code>menu.AddPopup( label, smArray[ smId ] );</code> としているが、サンプルコード2のようにループ処理内で <code>subMenu = CreatePopupMenu();</code> を使いまわしするだけでも新規のサブメニューアイテムを生成できるようだ。
<source lang="javascript">
// ポップアップメニューの項目にする任意の配列を用意する
var itemArray = [];
// ※ アイテムとして 1 ~ 100 の数値を放り込んでおく
for ( var i = 0; i < 100; i ++ ) {
  itemArray.push( i + 1 );
}
var len = itemArray.length;
 
var mainMenu = CreatePopupMenu();
var subMenu,  id;
 
// 配列からポップアップメニューを生成する
for ( var i = 0, j = 1; i < len; i ++ ) {
  // アイテムを 20 件ずつ分割収容するサブメニューを自動生成する
  if ( i % 20 == 0 ) {
    // ※ ループ処理 20 回ごとに subMenu を新しいサブメニュー項目として更新する
    subMenu = CreatePopupMenu();
    // 「サブメニュー 1」からの連番つき定型文字列
    mainMenu.AddPopup( "サブメニュー " + ( j ++ ), subMenu );
  }
 
  // アイテムをサブメニューに収容する
  id = i + 1;
  // 「アイテム 1」からの連番つき定型文字列
  subMenu.Add( "アイテム " + id, id );
}


// ポップアップメニューを表示
var r = mainMenu.Track( 0 );
Alert( r > 0 ? mainMenu.GetText( r ) : "キャンセル" );
</source>
※ 組み込み関数「[[ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する]]」のソースコードでは、サブメニューオブジェクト専用の配列 smArray を用意して <source lang="javascript" inline>smArray.push( CreatePopupMenu() );</source> → <source lang="javascript" inline>menu.AddPopup( label, smArray[ smId ] );</source> としているが、上のサンプルコードのようにループ処理内で <source lang="javascript" inline>subMenu = CreatePopupMenu();</source> を使いまわしするだけでも新規のサブメニューアイテムを生成できるようだ。
<br><br>
* [[マクロリファレンス:PopupMenu インターフェイス#AddPopup メソッド|PopupMenu.AddPopup() メソッド]] では [[マクロリファレンス:PopupMenu インターフェイス#Add メソッド|Add() メソッド]] の第三引数(''meMenuChecked, meMenuGrayed, meMenuSeparator'')は使用できない。
* [[マクロリファレンス:PopupMenu インターフェイス#AddPopup メソッド|PopupMenu.AddPopup() メソッド]] では [[マクロリファレンス:PopupMenu インターフェイス#Add メソッド|Add() メソッド]] の第三引数(''meMenuChecked, meMenuGrayed, meMenuSeparator'')は使用できない。
: サブメニュー内のすべてのアイテムが無効(グレーアウト)になる条件でも、サブメニュー見出しを無効化することはできないので、サブメニュー見出しが表示されなくなるように(またはグレーアウトされるように) <source lang="javascript" inline>PopupMenu.AddPopup()</source> 周りを [https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#if...else_statement if() 文] で囲うしかない(※ メニューの階層構造が複雑な場合に、ソースコードが見づらくなってしまうが…)。
: サブメニュー内のすべてのアイテムが無効(グレーアウト)になる条件でも、サブメニュー見出しを無効化することはできないので、サブメニュー見出しが表示されなくなるように(またはグレーアウトされるように) <code>PopupMenu.AddPopup()</code> 周りを [https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#if...else_statement if() 文] で囲うしかない(※ メニューの階層構造が複雑な場合に、ソースコードが見づらくなってしまうが…)。


<source lang="javascript">
<syntaxhighlight lang="javascript">
// e.g. 編集モードが Text ならサブメニューを表示する
// e.g. 編集モードが Text ならサブメニューを表示する
// ※ Text 以外ならグレーアウトさせた "サブメニュー" アイテムを表示
// ※ Text 以外ならグレーアウトさせた "サブメニュー" アイテムを表示
769行目: 747行目:


var r = menu1.Track( mePosMouse );
var r = menu1.Track( mePosMouse );
</source>
</syntaxhighlight>
<br>
 
: また、上出の「自動分割サブメニュー」の組み込み関数を制作するさい、チェックつきアイテムを含むサブメニュー見出しにもチェックを付けられるようにしたかったが、これも無理だった。<br> → サブメニューオブジェクトを <syntaxhighlight lang="javascript" inline>AddPopup()</syntaxhighlight> する前に孫アイテムを <syntaxhighlight lang="javascript" inline>Add()</syntaxhighlight> しておき、チェックつきアイテムを含むかどうかの条件文でサブメニューオブジェクトのラベルを生成(サブメニューラベルの先頭に "'''*'''\t" や "'''✔'''" などを付加)してから <syntaxhighlight lang="javascript" inline>AddPopup()</syntaxhighlight> することはできるが、 ''meMenuChecked'' とおなじチェックマークをつけられるわけではないので、コードが煩雑になるわりにあまり報われない努力となる…。
: また、上出の「自動分割サブメニュー」の組み込み関数を制作するさい、チェックつきアイテムを含むサブメニュー見出しにもチェックを付けられるようにしたかったが、これも無理だった。
<br><br>
:: → サブメニューオブジェクトを <code>AddPopup()</code> する前に孫アイテムを <code>Add()</code> しておき、チェックつきアイテムを含むかどうかの条件文でサブメニューオブジェクトのラベルを生成(サブメニューラベルの先頭に "'''*'''\t" や "'''✔'''" などを付加)してから <code>AddPopup()</code> することはできるが、 ''meMenuChecked'' とおなじチェックマークをつけられるわけではないので、コードが煩雑になるわりにあまり報われない努力となる…。


==== マクロの動作設定を変更可能にする ====
==== マクロの動作設定を変更可能にする ====
拙作マクロは、ポップアップメニューを使うものにかぎらず動作設定用の項目が多い。<br>
拙作マクロは、ポップアップメニューを使うものにかぎらず動作設定用の項目が多い。
ポップアップメニューマクロでないものは、通常、頻繁に動作設定を弄る必要はないが、sukemaru 好みの動作方式は一般的嗜好と合致しないであろうことから公開用のマクロにするにあたってカスタマイズ可能な「設定項目 (変数)」ににして調整しなおすことが多い…。
 
<br><br>
ポップアップメニューマクロでないものは、通常、頻繁に動作設定を弄る必要はないが、sukemaru 好みの動作方式は一般的嗜好と合致しないであろうことから公開用のマクロにするにあたってカスタマイズ可能な「設定項目 (変数)」にして調整しなおすことが多い…。
 
<span style="color:#0000c0;"> ポップアップメニューマクロであれば、メニュー項目から動作設定をカスタマイズできるようにコーディングすることができる。</span>
<span style="color:#0000c0;"> ポップアップメニューマクロであれば、メニュー項目から動作設定をカスタマイズできるようにコーディングすることができる。</span>
<br>
 
* まず、[[利用者:Masme|masme]] 氏の「[[行並べ替え]]」や「[[連番を挿入]]」マクロのように、[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/do...while do ... while() 文] によるループを利用して、動作設定の既定値を何度も書き換えながらポップアップメニューを再描画する方法がある。
* まず、[[利用者:Masme|masme]] 氏の「[[行並べ替え]]」や「[[連番を挿入]]」マクロのように、[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/do...while do ... while() 文] によるループを利用して、動作設定の既定値を何度も書き換えながらポップアップメニューを再描画する方法がある。
: 動作設定の変更内容はマクロの完了時に破棄されてしまうので、同じマクロを連続して利用することが多いならば、マクロメニューの [[ヘルプ:マクロ#編集|編集]] コマンドからソースコードを開いて、初期設定項目(変数)の既定値を書き換えておくとよい。
: <s>動作設定の変更内容はマクロの完了時に破棄されてしまうので、</s> 同じマクロを連続して利用することが多いならば、マクロメニューの [[ヘルプ:マクロ#編集|編集]] コマンドからソースコードを開いて、初期設定項目(変数)の既定値を書き換えておくとよい。
* sukemaru の場合は、「[[ポップアップメニューで検索先にジャンプ#include版|検索ジャンプ]]」「[[ブックマーク一覧ジャンプ#include版|ブックマークジャンプ]]」や「[[ファイルを読み直す・開きなおす#include版|読みなおし]]」マクロなどで、【include 版】と称するものを作っている。
* sukemaru の場合は、「[[ポップアップメニューで検索先にジャンプ#include版|検索ジャンプ]]」「[[ブックマーク一覧ジャンプ#include版|ブックマークジャンプ]]」や「[[ファイルを読み直す・開きなおす#include版|読みなおし]]」マクロなどで、【include 版】と称するものを作っている。
: これらにおいては、[[includeライブラリ|include ライブラリ]] の IO クラス(IO.js)の関数メソッド <syntaxhighlight lang="javascript" inline>Serialize() / Deserialize()</syntaxhighlight> を利用して、ポップアップメニュー内の「設定変更」サブメニューから変更した [[#外部ファイルにマクロの設定などを書き出す|設定値を外部ファイル(JSON ファイル)に保持]] できるようにしている。
: これらにおいては、[[includeライブラリ]] の IO クラス(IO.js)の関数メソッド <code>IO.Serialize() / IO.Deserialize()</code> を利用して、ポップアップメニュー内の「設定変更」サブメニューから変更した [[#外部ファイルにマクロの設定などを書き出す|設定値を外部ファイル(JSON ファイル)に保持]] できるようにしている。
: カスタマイズしながら実行するのも、カスタマイズした動作設定を維持したままでままで再実行するのも容易にはなったが、コードが煩雑になって他のマクロに流用しづらくなってしまっている…。
: カスタマイズしながら実行するのも、カスタマイズした動作設定を維持したままでままで再実行するのも容易にはなったが、コードが煩雑になって他のマクロに流用しづらくなってしまっている…。
: ※ 非 include 版では、「設定変更」サブメニューや masme 氏のマクロのような処理コードは入れず、動作設定の変更方法はソースコードの変数の値の書き換えのみとしている。
: ※ 非 include 版では、「設定変更」サブメニューや masme 氏のマクロのような処理コードは入れず、動作設定の変更方法はソースコードの変数の値の書き換えのみとしている。
<br><br>


==== GetKeyState.exe の活用 ====
==== GetKeyState.exe の活用 ====
pizz 氏作成の「[[GetKeyState.exe(キー状態取得実行ファイル)]]」を使うと、マクロ実行(開始)時の修飾キーの押し下げ状態でポップアップメニューに表示する項目を変化させたり、メニュー内のアイテムを選択(クリック)するときの修飾キーの押し下げ状態で実行するコマンドを変化させることができる。<br>
pizz 氏作成の「[[GetKeyState.exe(キー状態取得実行ファイル)]]」を使うと、マクロ実行(開始)時の修飾キーの押し下げ状態でポップアップメニューに表示する項目を変化させたり、メニュー内のアイテムを選択(クリック)するときの修飾キーの押し下げ状態で実行するコマンドを変化させることができる。
マクロ開始時に仕込むとショートカットキーの割りあて方が制限されたり、メニュー表示までにタイムラグが生じてしまうこともあるが、アイテム選択後のコマンド実行時に仕込めばあまり問題にならない。<br>
 
※ ただし、Mery のポップアップメニューは <kbd>Alt</kbd> キーでキャンセルされてしまうので、コマンド実行時に仕込めるのは <kbd>Ctrl</kbd><kbd>Shift</kbd> キーにかぎられる。
マクロ開始時に仕込むとショートカットキーの割りあて方が制限されたり、メニュー表示までにタイムラグが生じてしまうこともあるが、アイテム選択後のコマンド実行時に仕込めばあまり問題にならない。
<br><br>
 
※ ただし、Mery のポップアップメニューは <kbd>Alt</kbd> キーでキャンセルされてしまうので、ポップアップメニュー内のコマンド実行用に仕込めるのは <kbd>Ctrl</kbd> <kbd>Shift</kbd> キーにかぎられる。
 
: ref. [[GetKeyState.exe(キー状態取得実行ファイル)#実装例|GetKeyState.exe の実装例: サンプルコード3]]
: ref. [[GetKeyState.exe(キー状態取得実行ファイル)#実装例|GetKeyState.exe の実装例: サンプルコード3]]
<br><br>
[[#TOP|>> 目次へ]]
<br><br>


=== 配列 ===
=== 配列 ===
<source lang="javascript">
<syntaxhighlight lang="javascript">
var arr1 = [];
var arr1 = [];
arr1[arr1.length] = "hoge";
arr1[arr1.length] = "hoge";
805行目: 782行目:
arr1[arr1.length] = "piyo";
arr1[arr1.length] = "piyo";
... ;
... ;
</source>
</syntaxhighlight>
個人的な所感であるが、配列の要素を羅列して定義するさいに、上のような書き方は好きではない。以下のような書き方のほうが、スッキリしていてよい。
個人的な所感であるが、配列の要素を羅列して定義するさいに、上のような書き方は好きではない。以下のような書き方のほうが、スッキリしていてよい。
<source lang="javascript">
<syntaxhighlight lang="javascript">
var arr2 = [];
var arr2 = [];
arr2.push( "Hoge" );
arr2.push( "Hoge" );
813行目: 790行目:
arr2.push( "Piyo" );
arr2.push( "Piyo" );
... ;
... ;
</source>
</syntaxhighlight>
<source lang="javascript">
<syntaxhighlight lang="javascript">
var arr3 = [
var arr3 = [
   "HogeHoge",
   "HogeHoge",
822行目: 799行目:
];
];
// ※ カンマの位置は、前でも後ろでも
// ※ カンマの位置は、前でも後ろでも
</source>
</syntaxhighlight>
<br>


=== 複数行の論理行を範囲選択(末尾改行を含まない) ===
=== 複数行の論理行を範囲選択(末尾改行を含まない) ===
文字列操作のマクロでしばしば必要になる処理。<br>
文字列操作のマクロでしばしば必要になる処理。
 
※ 行番号のクリックやドラッグによる行単位の範囲選択をしたときや [[マクロリファレンス:Selection インターフェイス#SelectLine メソッド|Selection.SelectLine()]] のあとなど、選択範囲末尾の改行(次行の先頭)を除外するときに必要。
※ 行番号のクリックやドラッグによる行単位の範囲選択をしたときや [[マクロリファレンス:Selection インターフェイス#SelectLine メソッド|Selection.SelectLine()]] のあとなど、選択範囲末尾の改行(次行の先頭)を除外するときに必要。
<br><br>
 
※ 以下のふたつのコードは、左下(行頭位置)から右上に矩形選択した状態から実行したときの結果が異なる。
※ 以下のふたつのコードは、左下(行頭位置)から右上に矩形選択した状態から実行したときの結果が異なる。
<source lang="javascript">
<syntaxhighlight lang="javascript">
var s = document.selection;
var s = document.selection;
// もとの選択範囲の座標を取得
// もとの選択範囲の座標を取得
842行目: 819行目:
s.EndOfLine( false, mePosLogical );
s.EndOfLine( false, mePosLogical );
s.SetAnchorPoint( mePosLogical, 1, ty );
s.SetAnchorPoint( mePosLogical, 1, ty );
</source>
</syntaxhighlight>
<source lang="javascript">
<syntaxhighlight lang="javascript">
// または masme 氏作成の「コメントマーク付け外し」マクロより
// または masme 氏作成の「コメントマーク付け外し」マクロより
// ※ 左下(行頭位置)から右上に矩形選択した場合も考慮したコード
// ※ 左下(行頭位置)から右上に矩形選択した場合も考慮したコード
855行目: 832行目:
s.EndOfLine( false, mePosLogical );
s.EndOfLine( false, mePosLogical );
s.SetAnchorPoint( mePosLogical, 1, ty );
s.SetAnchorPoint( mePosLogical, 1, ty );
</source>
</syntaxhighlight>
: ref. Mery 公式フォーラム 『[https://www.haijin-boys.com/discussions/4431 マクロについてアドバイスお願いします]』
: ref. Mery 公式フォーラム 『[https://www.haijin-boys.com/discussions/4431 マクロについてアドバイスお願いします]』
<br><br>


=== 選択範囲の 先頭位置/末尾位置 ===
=== 選択範囲の 先頭位置/末尾位置 ===
選択範囲の 開始(キャレットなし)/終了(キャレットあり) の位置は [[マクロリファレンス:Selection インターフェイス#GetAnchorPos メソッド|Selection.GetAnchorPos()]] と [[マクロリファレンス:Selection インターフェイス#GetActivePos メソッド|Selection.GetActivePos()]] とで取得できるが、先頭/末尾 の位置はそれらをもとにして前後関係を割りだす必要がある。
選択範囲の 開始(キャレットなし)/終了(キャレットあり) の位置は [[マクロリファレンス:Selection インターフェイス#GetAnchorPos メソッド|Selection.GetAnchorPos()]] と [[マクロリファレンス:Selection インターフェイス#GetActivePos メソッド|Selection.GetActivePos()]] とで取得できるが、先頭/末尾 の位置はそれらをもとにして前後関係を割りだす必要がある。
<br>
 
<span style="color:#c00;">※ '''GetTopPos()''' や '''GetBottomPos()''' というメソッドはない。 </span><br>
<span style="color:#c00;">※ '''GetTopPos()''' や '''GetBottomPos()''' というメソッドはない。 </span>
<source lang="javascript">
<syntaxhighlight lang="javascript">
var ancPos, actPos, topPos, endPos;
var ancPos, actPos, topPos, endPos;


875行目: 851行目:
topPos = ( ancPos < actPos ) ? ancPos : actPos;
topPos = ( ancPos < actPos ) ? ancPos : actPos;
endPos = ( ancPos < actPos ) ? actPos : ancPos;
endPos = ( ancPos < actPos ) ? actPos : ancPos;
</source>
</syntaxhighlight>
<br>


=== 変換・挿入した文字列を範囲選択するとき ===
=== 変換・挿入した文字列を範囲選択するとき ===
<source lang="javascript">
<syntaxhighlight lang="javascript">
var str = "hoge";
var str = "hoge";
document.Write( str ); // または document.selection.text = str;
document.Write( str ); // または document.selection.text = str;
</source>
</syntaxhighlight>
のあとで文字列 '''hoge''' を範囲選択したい場合は、<source lang="javascript" inline>document.selection.CharLeft( str.length, true );</source> ではなく
のあとで文字列 '''hoge''' を範囲選択したい場合は、<syntaxhighlight lang="javascript" inline>document.selection.CharLeft( str.length, true );</syntaxhighlight> ではなく
<source lang="javascript">
<syntaxhighlight lang="javascript">
// キャレットは選択範囲の末尾位置
// キャレットは選択範囲の末尾位置
document.selection.SetAnchorPos( document.selection.GetActivePos() - str.length );
document.selection.SetAnchorPos( document.selection.GetActivePos() - str.length );
890行目: 865行目:
// または(キャレットは選択範囲の先頭位置)
// または(キャレットは選択範囲の先頭位置)
document.selectionSetActivePos( document.selection.GetActivePos() - str.length, true );
document.selectionSetActivePos( document.selection.GetActivePos() - str.length, true );
</source>
</syntaxhighlight>
と記述すること。
と記述すること。
<br><br>
 
※ ''[[マクロリファレンス:Selection インターフェイス#CharLeft メソッド|Selection.CharLeft]]( str.length, true )'' の場合、文字列 ''str'' が「折り返し」にかかってしまったときに想定どおりの選択範囲にならない。
※ ''[[マクロリファレンス:Selection インターフェイス#CharLeft メソッド|Selection.CharLeft]]( str.length, true )'' の場合、文字列 ''str'' が「折り返し」にかかってしまったときに想定どおりの選択範囲にならない。
: ref. Mery 公式フォーラム 『[https://www.haijin-boys.com/discussions/3740 "折り返し表示" での CharRight( document.selection.Text.length - 1 ) について]』
: ref. Mery 公式フォーラム 『[https://www.haijin-boys.com/discussions/3740 "折り返し表示" での CharRight( document.selection.Text.length - 1 ) について]』
<br><br>
[[#TOP|>> 目次へ]]
<br><br>


=== Collapse() メソッド とキャレット位置 ===
=== Mery のマクロの定数 ===
[https://github.com/haijinboys/mery-plugin-sdk/blob/master/SDK/C/Basic/plugin.h リテラル形式の定数を数値化した値] は
Alert( <b style="color:#408040;">meFindNext</b> );
のような1行マクロで調べることができる。
 
=== Document.Selection オブジェクトの各種メソッドについて ===
==== ChangeCase() メソッド ====
[[マクロリファレンス:Selection インターフェイス#ChangeCase メソッド|Selection.ChangeCase() メソッド]] は
* 全角/半角の英字(いわゆるラテンアルファベット <code>A-Z</code>, <code>a-z</code>, <code>A-Z</code>, <code>a-z</code>)以外の欧文アルファベット(ギリシア文字、キリル文字など)やローマ数字の「大文字/小文字/頭文字」変換にも対応。
* 選択範囲内のテキストが「漢字と平仮名のみ」のばあいなど、「大文字/小文字/頭文字」変換されなかったさいにも '''Undo''' 履歴や [https://www.haijin-boys.com/software/mery/mery-2-6-9#4 変更行の強調表示] が残る。
: ''ref.'' [[#文字列操作が空振りしたときは undo 履歴に残さない|文字列操作が空振りしたときは undo 履歴に残さない]]
: ''ref.'' 拙作「[[大文字/小文字/頭文字 トグル変換]]」マクロ
 
==== ChangeWidth() メソッド ====
[[マクロリファレンス:Selection インターフェイス#ChangeWidth メソッド|Selection.ChangeWidth() メソッド]] は
* 選択範囲内のテキストが「漢字と平仮名のみ」のばあいなど、「全角/半角」変換されなかったさいにも '''Undo''' 履歴や [https://www.haijin-boys.com/software/mery/mery-2-6-9#4 変更行の強調表示] が残る。
: ''ref.'' [[#文字列操作が空振りしたときは undo 履歴に残さない|文字列操作が空振りしたときは undo 履歴に残さない]]
: ''ref.'' 拙作「[[全角/半角 トグル変換]]」マクロ
 
==== Collapse() メソッド ====
[[マクロリファレンス:Selection インターフェイス#Collapse メソッド|Selection.Collapse() メソッド]] で引数 '''''meCollapseEnd''''' を指定した場合は
[[マクロリファレンス:Selection インターフェイス#Collapse メソッド|Selection.Collapse() メソッド]] で引数 '''''meCollapseEnd''''' を指定した場合は
Selection.SetActivePos( Selection.GetActivePos() )  
 
<code>document.selection.SetActivePos( Selection.GetActivePos() ) </code>
 
'''''meCollapseStart''''' を指定した場合は
'''''meCollapseStart''''' を指定した場合は
Selection.SetActivePos( Selection.SetAnchorPos() )
と意味的には同じである。
<br><br>
※ 引数を省略した場合は ''meCollapseStart'' として動作する。<br>
※ ''meCollapseStart / meCollapseEnd'' はそれぞれ「選択開始位置」と「選択終了位置 (キャレット位置)」を指し、「選択範囲の 先頭/末尾」ではない。<br>
※ [[マクロリファレンス:Selection インターフェイス#SelectLine メソッド|Selection.SelectLine()]] や [[マクロリファレンス:Selection インターフェイス#SelectWord メソッド|Selection.SelectWord()]] メソッドなどでの範囲選択では「キャレット位置=選択範囲の末尾」となり、[[マクロリファレンス:Selection インターフェイス#Find メソッド|Selection.Find()]] や [[マクロリファレンス:Selection インターフェイス#FindRepeat メソッド|Selection.FindRepeat()]] メソッドでの範囲選択では「キャレット位置=選択範囲の先頭」なので、つづけて Collapse() メソッドを使用するときは注意が必要 (…というほどのことでもないか?)。
<br><br>


=== Find() メソッド FindRepeat() メソッド の 定数 ===
<code>document.selection.SetActivePos( Selection.SetAnchorPos() )</code>
<span style="color:#0000c0;">※ [https://github.com/haijinboys/mery-plugin-sdk/blob/master/SDK/C/Basic/plugin.h 定数] の数値は</span>
 
Alert( <span style="color:#408040;">meFindNext</span> );
* 引数を省略した場合は ''meCollapseStart'' として動作する。
<span style="color:#0000c0;">のような1行マクロで調べることができる。</span>
* ''meCollapseStart / meCollapseEnd'' はそれぞれ「選択開始位置」と「選択終了位置 (キャレット位置)」を指し、「選択範囲の 先頭/末尾」ではない。
<br><br>
* [[マクロリファレンス:Selection インターフェイス#SelectLine メソッド|Selection.SelectLine()]] や [[マクロリファレンス:Selection インターフェイス#SelectWord メソッド|Selection.SelectWord()]] メソッドなどでの範囲選択では「キャレット位置=選択範囲の末尾」となり、[[マクロリファレンス:Selection インターフェイス#Find メソッド|Selection.Find()]] や [[マクロリファレンス:Selection インターフェイス#FindRepeat メソッド|Selection.FindRepeat()]] メソッドでの範囲選択では「キャレット位置=選択範囲の先頭」なので、つづけて Collapse() メソッドを使用するときは注意が必要 (…というほどのことでもないか?)。
; [[マクロリファレンス:Selection インターフェイス#Find メソッド|Find() メソッド]]
 
  document.selection.'''Find()''' メソッド
==== DuplicateLine() メソッド ====
[[マクロリファレンス:Selection インターフェイス#DuplicateLine メソッド|Selection.DuplicateLine() メソッド]] は
* 行末の改行が選択範囲に含まれているときや複数行選択の状態から実行したとき、キャレットのある論理行 ActivePointY が複製対象になる(複数行不可)。
* 行を複製したあとのキャレットの位置(桁)が、メソッド実行前の ActivePointX ではなく AnchorPointX になる。
⇒ 複数行選択状態や、行番号クリックでの行選択状態から実行した後のキャレット位置が不自然なかんじになる。
 
じっさいのマクロのコーディングでは行全体の文字列を
<syntaxhighlight lang="javascript">
// 1行選択
document.selection.StartOfLine( mePosLogical );
document.selection.EndOfLine( mePosLogical, true );
</syntaxhighlight>
または [[#複数行の論理行を範囲選択(末尾改行を含まない)|複数行の論理行を範囲選択(末尾改行を含まない)]] のようなコードで範囲選択状態にしてから「行を複製」することが多いので、<syntaxhighlight lang="javascript" inline>document.selection.Text = document.selection.Text + "\n" + document.selection.Text;</syntaxhighlight> とすれば「複製」後のキャレット位置が曖昧になることはない。
: ''ref.'' 拙作「[[行を複製 (複数行可)]]」マクロ
 
==== Indent/Unindent() メソッド ====
[[マクロリファレンス:Selection インターフェイス#Indent メソッド|Selection.Indent() メソッド]] / [[マクロリファレンス:Selection インターフェイス#Unindent メソッド|Selection.Unindent() メソッド]] は
* 「選択範囲のテキスト」ではなく、「選択範囲をふくむ論理行全体」が操作対象。
* 選択範囲が表示行での1行全体に達していないと空振りするので、事前に行全体を範囲選択する(''e.g.'' <syntaxhighlight lang="javascript" inline>document.selection.SelectLine(); // または SelectLine( true );</syntaxhighlight> )や [[#複数行の論理行を範囲選択(末尾改行を含まない)|複数行の論理行を範囲選択(末尾改行を含まない)]] のようなコードが必要。
* 実行可能条件を満たしてから実行すると、「もとの選択範囲をふくむ論理行全体 (<span style="color:#0000c0;">末尾改行を'''ふくむ'''</span>)」が範囲選択された状態で残る。
* 引数に 1 以上の数値を渡して実行すると、「元に戻す」さいには <code>document.selection.Indent(n)</code> や <code>document.selection.Unindent(n)</code> での引数の値とおなじ回数の [[マクロリファレンス:Document インターフェイス#Undo メソッド|<code>document.Undo()</code>]] や Ctrl+Z の操作が必要。
 
: ''ref.'' 「[[非選択状態でも逆インデント]]」「[[字下げ・字上げ]]」など、標準のインデント/逆インデント機能の代替マクロがマクロライブラリにある。
 
==== NewLine() メソッド ====
[[マクロリファレンス:Selection インターフェイス#NewLine メソッド|Selection.NewLine() メソッド]] は
* 引数に 1 以上の数値を渡して実行したばあい、「元に戻す」さいには <code>document.selection.NewLine(n)</code> での引数の数値とおなじ回数の [[マクロリファレンス:Document インターフェイス#Undo メソッド|<code>document.Undo()</code>]] や Ctrl+Z の操作が必要。
 
==== Tabify/Untabify() メソッド ====
[[マクロリファレンス:Selection インターフェイス#Tabify メソッド|Selection.Tabify() メソッド]] / [[マクロリファレンス:Selection インターフェイス#Untabify メソッド|Selection.Untabify() メソッド]] は
* 「選択範囲のテキスト」ではなく「選択範囲をふくむ論理行全体」が操作対象で、1文字以上の選択範囲が必要。
* 実行可能条件を満たしてから実行すると、「もとの選択範囲をふくむ論理行全体 (末尾改行をふくまない)」が範囲選択された状態で残る。
* 選択範囲内のテキストが「タブや2コ以上連続する半角空白をふくまない」ばあいなど、「タブ/空白」変換されなかったさいにも Undo 履歴や変更行のマーキングなどが残る。
: ''ref.'' [[#文字列操作が空振りしたときは undo 履歴に残さない|文字列操作が空振りしたときは undo 履歴に残さない]]
: ''ref.'' 拙作「[[TAB/半角空白 トグル変換]]」マクロ
 
==== SelectLine() メソッド ====
[[マクロリファレンス:Selection インターフェイス#SelectLine メソッド|Selection.SelectLine() メソッド]]
* 「論理行」全体の選択のみで、「表示行」の選択には非対応。
: ※ エディタ内でのトリプルクリック操作に相当し、行末改行も選択範囲にふくまれる。
* 引数に <syntaxhighlight lang="javascript" inline>true</syntaxhighlight> を渡すと複数行選択が可能。
* トリプルクリックや行番号のクリック(またはドラッグ)で論理行全体が範囲選択された状態から実行すると、もとの選択範囲末尾改行のつぎの行まで範囲選択されてしまう。
: ''c.f.'' [[#複数行の論理行を範囲選択(末尾改行を含まない)|複数行の論理行を範囲選択(末尾改行を含まない)]]
 
=== 検索/置換 ===
===== Find() メソッド =====
* 定数
  document.selection.'''[[マクロリファレンス:Selection インターフェイス#Find メソッド|Find()]]''' メソッド
  指定のパターンを検索します。
  指定のパターンを検索します。
   
   
  &#32;0: meFindPrevious カーソル位置から前を検索します。
  &#32;0: meFindPrevious カーソル位置から前を検索します
  &#32;1: meFindNext カーソル位置から次を検索します。
  &#32;1: meFindNext カーソル位置から次を検索します
  &#32;2: meFindReplaceCase 検索する単語の大文字と小文字を区別します。
  &#32;2: meFindReplaceCase 検索する単語の大文字と小文字を区別します
  &#32;4: meFindReplaceOnlyWord 完全に一致する単語を検索します。
  &#32;4: meFindReplaceOnlyWord 完全に一致する単語を検索します
  &#32;8: meFindAround 文書の末尾まで検索したら先頭から検索を開始します。
  &#32;8: meFindAround 文書の末尾まで検索したら先頭から検索を開始します
  16: meFindReplaceRegExp 正規表現で検索します。
  16: meFindReplaceRegExp 正規表現で検索します
<br>
: <span style="color:#c00;">「検索/置換」ダイアログのオプションフラグをすべて OFF にする方法</span> として
※ document.selection.'''[[マクロリファレンス:Selection インターフェイス#Replace メソッド|Replace()]]''' メソッド専用の定数
<source lang="javascript">
<span style="color:#808080;">32: meReplaceSelOnly 選択した範囲のみ置換します</span>
document.selection.Find( "", 0 ); // 空文字列の検索でオプションフラグを解除する
<span style="color:#808080;">64: meReplaceAll すべて置換します</span>
</source>
: というコードを挟み込むという手がある(第二引数には 0 または 1 を指定する)。
※ editor.'''[[マクロリファレンス:Editor_インターフェイス#ReplaceInFiles_メソッド|FindInFiles()]]'''/'''[[マクロリファレンス:Editor_インターフェイス#ReplaceInFiles_メソッド|ReplaceInFiles()]]''' メソッド専用の定数
<span style="color:#808080;">&#32;128: meFindRecursive サブディレクトリも検索します</span>
<span style="color:#808080;">&#32;256: meFindFileNamesOnly ファイル名のみ表示します</span>
<span style="color:#808080;">&#32;512: meReplaceBackup バックアップを保存します</span>
※ '''[https://www.haijin-boys.com/software/mery/mery-2-8-3 Mery ver 2.8.3]''' で追加された定数 [https://www.haijin-boys.com/wiki/マクロリファレンス:3:Selection_オブジェクト#Findメソッド]
&#32;1024: meFindMigemo Migemo を使用します(※ 検索/すべて検索 でのみ)
※ '''[https://www.haijin-boys.com/software/mery/mery-3-0-0#13 Mery ver 3.0.1]''' で追加された定数 [https://www.haijin-boys.com/wiki/マクロリファレンス:3:Selection_オブジェクト#Findメソッド][https://www.haijin-boys.com/wiki/マクロリファレンス:3:Selection_オブジェクト#Replace_メソッド]
&#32;2048: meFindAll すべて検索して選択範囲に追加します
<span style="color:#808080;">&#32;4096: meFindNotBOL 選択範囲の先頭を行頭とみなさず置換します</span>
<span style="color:#808080;">&#32;8192: meFindNotEOL 選択範囲の終端を行頭とみなさず置換します</span>
16384: meFindKeepOptions 検索ダイアログの文字列、オプション項目を維持します
 
* <span style="color:#c00;">「検索/置換」ダイアログのオプションフラグをすべて OFF にする方法</span> として
: <syntaxhighlight lang="javascript" inline>document.selection.Find( "", 0 ); // 空文字列の検索でオプションフラグを解除する</syntaxhighlight>
: というコードを挟み込む手法がある(第二引数には 0 または 1 を指定する)。
:: ref. Mery 公式フォーラム 『[https://www.haijin-boys.com/discussions/3398 空検索の動作、など]』
:: ref. Mery 公式フォーラム 『[https://www.haijin-boys.com/discussions/3398 空検索の動作、など]』


937行目: 986行目:


: ※ ただし、「終了したら閉じる」と、[https://www.haijin-boys.com/software/mery/mery-2-6-10#1 ベータ版 2.6.10] で追加された「インクリメンタルサーチ」のオプションフラグはマクロから解除することができない。
: ※ ただし、「終了したら閉じる」と、[https://www.haijin-boys.com/software/mery/mery-2-6-10#1 ベータ版 2.6.10] で追加された「インクリメンタルサーチ」のオプションフラグはマクロから解除することができない。
: ※ ''meFindReplaceOnlyWord'' と ''meFindReplaceRegExp'' は排他関係なので、<span style="color:#c00;">同時に使用した場合 ''meFindReplaceRegExp'' は適用されるが ''meFindReplaceOnlyWord'' は無視される</span>
 
* ''meFindReplaceOnlyWord'' と ''meFindReplaceRegExp'' は排他関係なので、<span style="color:#c00;">同時に使用した場合 ''meFindReplaceRegExp'' は適用されるが ''meFindReplaceOnlyWord'' は無視される</span>
: (検索ダイアログで「正規表現」オプションを有効化したときに「単語のみ」オプションが無効になるのと同様)。
: (検索ダイアログで「正規表現」オプションを有効化したときに「単語のみ」オプションが無効になるのと同様)。
<br>
* [https://www.haijin-boys.com/software/mery/mery-2-8-3#13 ベータ版 2.8.3] で追加された ''meFindMigemo'' と従来からの ''meFindReplaceRegExp'' も排他関係で、''meFindMigemo'' が優先される。
; [[マクロリファレンス:Selection インターフェイス#FindRepeat メソッド|FindRepeat() メソッド]]
* [https://www.haijin-boys.com/software/mery/mery-3-0-0#13 Mery ver 3.0.1] での定数 ''meFindKeepOptions'' の追加にともない、マクロで <code>Find()</code> メソッドを使用したあとに「検索/置換」ダイアログ内の「Migemo を使用する」オプションの状態もリセットされるようになった (''meFindMigemo'' の有無で Migemo の ON/OFF が切り替わる)ようなので、<syntaxhighlight lang="javascript" inline>document.selection.Find( "", 0 );</syntaxhighlight> を使用すると「Migemo を使用する」オプションは OFF (無効) になる。
  document.selection.'''FindRepeat()''' メソッド
 
: ※「検索/置換」ダイアログの検索文字列欄に <q>HOGE</q> が入力されたまま閉じて、マクロで <syntaxhighlight lang="javascript" inline>document.selection..Find( "FUGA", meFindKeepOptions );</syntaxhighlight> を実行すると、検索ハイライトされた文字列と「検索/置換」ダイアログ内の検索文字列に齟齬が生じることになる
:: ( ⇒ 「次/前を検索(F3/Shift+F3)」コマンドでは <q>HOGE</q> が再検索される)。
: たとえば「[[検索(SJIS以外)]]」マクロのような長大な正規表現を使用するマクロで ''meFindKeepOptions'' を適用すると、マクロ実行後に [Shift+F3] キーによる上方向への再検索はできなくなるので、長大な検索文字列を検索履歴に残したくない特殊な検索(置換)マクロの場合での扱いはむずかしい (検索マクロに「[[GetKeyState.exe(キー状態取得実行ファイル)]]」を導入して、''meFindNext''/''meFindPrevious'' を切り替える、または ''meFindKeepOptions'' の有無を切り替えるなどの対応をするか、検索方向(次/前)の差分で検索マクロを2件登録するか…)。
 
===== FindRepeat() メソッド =====
* 定数
  document.selection.'''[[マクロリファレンス:Selection インターフェイス#FindRepeat メソッド|FindRepeat() ]]''' メソッド
  前回検索した文字列を検索します。  
  前回検索した文字列を検索します。  
   
   
  &#32;0: meFindPrevious カーソル位置から前を検索します。
  &#32;0: meFindRepeatPrevious カーソル位置から前を検索します。
  &#32;1: meFindNext カーソル位置から次を検索します。
  &#32;1: meFindRepeatNext カーソル位置から次を検索します。
  &#32;2: meFindRepeatWord 選択範囲が空の場合はカーソル位置の単語を検索します。
  &#32;2: meFindRepeatWord 選択範囲が空の場合はカーソル位置の単語を検索します。


: <source lang="javascript" inline>FindRepeat()</source> メソッドでは定数 ''meFindReplaceCase'' や ''meFindReplaceOnlyWord , meFindAround , meFindReplaceRegExp'' が使用できないが、 <span style="color:#0000c0;">'''直前''' の「検索/置換」コマンドや <source lang="javascript" inline>Find() / Replace()</source> メソッドで使用したこれらのオプションのうち ''meFindReplaceRegExp'' 以外の三つの ON/OFF 状態が '''継承''' される。</span>
: <code>FindRepeat()</code> メソッドでは定数 ''meFindReplaceCase'' や ''meFindReplaceOnlyWord , meFindAround , meFindReplaceRegExp'' が使用できず、 <span style="color:#0000c0;">'''直前''' の「検索/置換」コマンドや <code>Find()</code> / <code>Replace()</code> メソッドで使用したこれらのオプションのうち ''meFindReplaceRegExp'' 以外の三つの ON/OFF 状態が '''継承''' される。</span>


: よって、<source lang="javascript" inline>FindRepeat()</source> メソッドで ''meFindReplaceCase'' や ''meFindReplaceOnlyWord , meFindAround'' を適用した検索をしたいばあいは、以下のように記述すればよい。
* <code>FindRepeat()</code> メソッドで ''meFindReplaceCase'' や ''meFindReplaceOnlyWord , meFindAround'' を適用した検索をしたいばあいは、以下のように記述する。
: ※ ''meFindReplaceRegExp'' があっても <source lang="javascript" inline>FindRepeat()</source> の実行時には無視される。
: ※ ''meFindReplaceRegExp'' があっても <code>FindRepeat()</code> の実行時には無視される。
<source lang="javascript">
<syntaxhighlight lang="javascript">
// 1.空文字列の検索をして、任意のオプションフラグを設定(付加)する
// FindRepeat() で使用したいフラグ
document.selection.Find( "", meFindNext + meFindReplaceCase + meFindAround );
var flags = meFindReplaceCase + meFindAround;


// 2.「前回検索した文字列を検索」または キャレット位置の単語で「次の文字列を検索」
// ➀ 空文字列の検索をして、フラグを設定する
document.selection.FindRepeat( meFindNext + meFindRepeatWord );
document.selection.Find( "", flags );
 
// ➁「前回検索した文字列を検索」または キャレット位置の単語で「次の文字列を検索」
document.selection.FindRepeat( meFindRepeatNext + meFindRepeatWord );


// -------------------------------------------------- //
// -------------------------------------------------- //


// 3.最後にオプションフラグを解除しておきたいなら
// ➂ 最後にオプションフラグを解除しておきたいなら
document.selection.Find( "", 0 );
document.selection.Find( "", 0 );
</source>
</syntaxhighlight>
: ※ ➂ のコードを最後に使用した場合、「検索/置換」ダイアログのオプションフラグも解除される。
: ※ ➂ の行のコードを最後に使用した場合、「検索/置換」ダイアログのオプションフラグも解除される。
<br>
: [https://www.haijin-boys.com/software/mery/mery-3-0-0#13 Mery ver 3.0.1] で <code>Find()</code> メソッドなどで利用できる定数が追加されたが、<code>FindRepeat()</code> メソッドの仕様は変わっていないので検索フラグを適用する方法はうえのサンプルコードのようにしなければならないことに変わりはない。
* ちなみに、sukemaru は検索ダイアログの履歴に残るマクロや、検索ハイライトが残るマクロが好きではないので、なるべく <source lang="javascript" inlineSelection.Find/Replace()</source> を使わずに JavaScript ネイティブの [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf String.indexOf( searchValue, fromIndex ) メソッド] や [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace String.replace( regexp ) メソッド] で検索/置換を行なったり、 [[マクロリファレンス:Document インターフェイス#HighlightFind プロパティ|Document.HighlightFind = false]] で検索マーカーを消すなどする自作マクロが多い ([https://www.haijin-boys.com/software/mery/mery-2-6-0#3 自動マーカー] で背景色をハイライトする設定にしているから「検索ハイライト」はいらなくて…)。
: ※ <span style="color:#c00;">サンプルコードの「➀」で ''meFindKeepOptions'' 定数を追加すると「➁」の <code>FindRepeat()</code> メソッドに「➀」で設定したフラグが適用されなくなり、「検索/置換」ダイアログ内のオプションフラグのチェック状態が適用されてしまうので '''要注意'''。</span>
: マクロ独自のフラグ設定状態で <code>FindRepeat()</code> メソッド(次/前の文字列を検索)使用したいばあいには、「検索/置換」ダイアログ内のオプションフラグをクリア/リセットしなければならないままである。
 
==== Mery ver 3.0.1 以降でオプションフラグを維持したまま「置換」を行うサンプルコード ====
実行前になんらかの文字列を検索していて "検索マーカーが表示されている場合" を考慮すると、なかなか面倒な部分が多い…。
 
<syntaxhighlight lang="javascript">
/**
* 「スペース×2削除」マクロの Mery v3 対応テスト
* 行頭の字下げを1段階解除する(半角×2, 全角×1, タブ×1)
* ※ マルチカーソル非対応
*/
var d = editor.ActiveDocument,  s = d.selection;
var sx = ScrollX,  sy = ScrollY;
var ty = s.GetTopPointY(mePosLogical);
var by = s.GetBottomPointY(mePosLogical);
var bx = s.GetBottomPointX(mePosLogical);
// ver 3.0.1 以降かバージョンチェック用
var meFindKeepOptions; // (meFindKeepOptions = 16384) > 0
 
// 選択範囲の先頭/末尾を論理行全体に拡張
if (s.Text && by != ty && bx == 1)  by--;
s.SetActivePoint(mePosLogical, 1, by);
s.EndOfLine(false, mePosLogical);
s.SetAnchorPoint(mePosLogical, 1, ty);
s.CharRight(true);
 
var st = s.Text;
 
if (st && meFindKeepOptions) {
  // Undo 用の選択範囲を保存
  var sv = d.Saved;
  BeginUndoGroup();  AddUndo();
 
  // 置換で字上げ(逆インデント)
  var hl = d.HighlightFind; // 検索ハイライトの状態を取得
  var regRep = "^(?:\t| {1,2}| )(.*+)$"; // ※ masme氏による
  var result = "$1";
  var flag = meReplaceSelOnly + meReplaceAll
          + meFindReplaceRegExp + meFindKeepOptions;
 
  s.Replace(regRep, result, flag); // ⇒ イヤな感じにハイライトが残る
  var act = s.GetActivePos();      // 置換終了時のキャレット位置
 
  // もとの検索ハイライトの状態に復帰(※カーソル移動をともなう)
  s.FindRepeat(0); // 検索履歴の文字列で「前の文字列を検索」
  d.HighlightFind = hl;  Status = "";
 
  // 選択範囲とスクロール位置を復旧
  s.SetAnchorPoint(mePosLogical, 1, ty);
  s.SetActivePos(act, true);
  ScrollX = sx;  ScrollY = sy;
 
  EndUndoGroup();
  // 字上げ(置換)ナシなら AddUndo を破棄
  if (s.Text == st) {
    d.Undo();  d.Saved = sv;
  }
}
</syntaxhighlight>
 
* ちなみに、sukemaru は検索ダイアログの履歴に残るマクロや、検索ハイライトが残るマクロが好きではないので、なるべく <code>Selection.Find()</code> や <code>Selection.Replace()</code> を使わずに JavaScript ネイティブの [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf String.indexOf( searchValue, fromIndex )] / [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/search String.search( regexp ) メソッド] や [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace String.replace( regexp ) メソッド] で検索/置換を行なったり、あるいは [[マクロリファレンス:Document インターフェイス#HighlightFind プロパティ|Document.HighlightFind = false]] で最終的に検索マーカーを消すなどする自作マクロが多い ([https://www.haijin-boys.com/software/mery/mery-2-6-0#3 自動マーカー] でハイライトさせる設定にしているから「検索ハイライト」はいらなくて…)。
: [ [https://www.haijin-boys.com/software/mery/mery-tips#2 Ctrl+Shift+↑ / ↓] ] の機能も「[[次/前の文字列を検索・改]]」マクロに置きかえてしまったので、検索ダイアログを開くのは正規表現で検索するときぐらいかも。
: [ [https://www.haijin-boys.com/software/mery/mery-tips#2 Ctrl+Shift+↑ / ↓] ] の機能も「[[次/前の文字列を検索・改]]」マクロに置きかえてしまったので、検索ダイアログを開くのは正規表現で検索するときぐらいかも。
<br><br>


=== 文字列操作が空振りしたときは undo 履歴に残さない ===
=== 文字列操作が空振りしたときは undo 履歴に残さない ===
* 条件付きで文字列操作(挿入・置換など)するマクロが空振りしたときに、
* 条件付きで文字列操作(挿入・置換など)するマクロが空振りしたとき
<source lang="javascript">
<syntaxhighlight lang="javascript">
// e.g. 選択範囲に「hoge」が含まれなければ置換しない
// e.g. 選択範囲に「hoge」が含まれていれば「fuga」に置換する
var fuga = document.selection.Text.replace( /hoge/g, "fuga" );
var fuga = document.selection.Text.replace( /hoge/g, "fuga" );
document.selection.Text = fuga;
document.selection.Text = fuga;
</source>
</syntaxhighlight>
: 上のようなコードの場合は '''undo''' 履歴に無駄に残ったり、文書に「'''未保存 *'''」のフラグが付加されたりする。
: 上のようなコードの場合は '''undo''' 履歴に無駄に残ったり、文書に「'''未保存 *'''」のフラグが付加されたりする。


: 以下のように「文字列操作の前後で "変化なし" なら undo 履歴には残さない」記述にすると、[https://www.haijin-boys.com/software/mery/mery-2-6-9#4 変更行の強調表示] なども無用に付かなくなる。
: 以下のように「文字列操作の前後で "変化なし" なら undo 履歴には残さない」記述にすると、[https://www.haijin-boys.com/software/mery/mery-2-6-9#4 変更行の強調表示] なども無用に付かなくなる。
<source lang="javascript">
<syntaxhighlight lang="javascript">
// e.g. 選択範囲に「hoge」が含まれなければ置換しない
// e.g. 選択範囲に「hoge」が含まれなければ置換しない
var st = document.selection.Text;
var st = document.selection.Text;
988行目: 1,108行目:
   document.selection.Text = piyo;
   document.selection.Text = piyo;
}
}
</source>
</syntaxhighlight>


<br>
* 大文字/小文字変換の [[マクロリファレンス:Selection インターフェイス#ChangeCase メソッド|Selection.ChangeCase() メソッド]] や、全角/半角変換の [[マクロリファレンス:Selection インターフェイス#ChangeWidth メソッド|Selection.ChangeWidth() メソッド]] なども、日本語文などで空振りしたときに undo 履歴に残るが、上のサンプルコードのようなかたち <syntaxhighlight lang="javascript" inline>var temp = document.selection.ChangeCase( meCaseLowerCase );</syntaxhighlight> で変数に格納することはできない。
* 大文字/小文字変換の [[マクロリファレンス:Selection インターフェイス#ChangeCase メソッド|Selection.ChangeCase() メソッド]] や、全角/半角変換の [[マクロリファレンス:Selection インターフェイス#ChangeWidth メソッド|Selection.ChangeWidth() メソッド]] なども、日本語文などで空振りしたときに undo 履歴に残るが、<syntaxhighlight lang="javascript" inline>var temp = document.selection.ChangeCase( meCaseLowerCase );</syntaxhighlight> のようなかたちで変数に格納することはできない。<br>
: [[マクロリファレンス:Selection インターフェイス|Document.Selection クラス]] の文字列操作メソッドの場合は、以下のように記述することで「<span style="color:#0000c0;">変換なしなら undo 履歴を巻き戻し</span>」できる。
: [[マクロリファレンス:Selection インターフェイス|Document.Selection クラス]] の文字列操作メソッドの場合は、以下のように記述することで「<span style="color:#0000c0;">変換なしなら undo 履歴を巻き戻し</span>」できる。


<source lang="javascript">
<syntaxhighlight lang="javascript">
// 変換前の文字列 と 保存済み/未保存 の状態を取得
// 変換前の文字列 と 保存済み/未保存 の状態を取得
var st = document.selection.Text;
var st = document.selection.Text;
1,010行目: 1,129行目:
   }
   }
}
}
</source>
</syntaxhighlight>
: ※ ただし、厳密にいえば undo 履歴には残っているので、'''redo''' (やり直し: Ctrl+Y) することができる。
: ※ ただし、厳密にいえば undo 履歴には残っているので、'''redo''' (やり直し: Ctrl+Y) することができる。
<br><br>
[[#TOP|>> 目次へ]]
<br><br>


=== スクロール位置の調整 ===
=== スクロール位置の調整 ===
キャレットをジャンプさせた後のスクロール位置とキャレット位置は、移動先の行(表示座標での行番号)がエディタの表示領域の高さに収まるかどうかとジャンプ方向によるので安定的ではない(スクロールマージンの考慮も必要)。
* [[マクロリファレンス:Window インターフェイス#ScrollX プロパティ|ScrollX/ScrollY プロパティ]] は <code>Window</code> オブジェクト直下のプロパティに属するため、<code>Editor.ActiveDocument</code> 以外の <code>Document</code> オブジェクト(''e.g.'' <code>Documents.Item(n)</code>)を指定してスクロールさせることができない。
<br><br>
* 同様に、<code>ActiveDocument</code> 以外の <code>Document</code> にたいして <code>Selection.StartOFDocument()</code> 等のキャレット移動をともなうメソッドを実行しても、スクロール位置は移動しない。
以下のコードは、ジャンプ後にエディタの表示領域がスクロールした場合に、キャレットが表示領域の 先頭位置([[マクロリファレンス:Window インターフェイス#ScrollY プロパティ|window.ScrollY]]) になるように調整するもの。
: ※ いずれも、操作対象のウインドウ/タブを明示的にアクティブ化(<code>Editors.Item(m).Documents.Item(n).Activate();</code>)してからなら意図的なスクロール操作ができるが、もとのタブをアクティブ状態に戻すならコードの最後に <code>Document.Activate();</code> による復帰操作が必要(ほかのエディタウインドウのドキュメントの操作のばあいは、自他のエディタウインドウの <code>Editors.Item(m)</code> のインデックスの取得が必要)。
<source lang="javascript">
 
* キャレットをジャンプさせた後のスクロール位置とキャレット位置は、移動先の行(表示座標での行番号)がエディタの表示領域の高さに収まるかどうかとジャンプ方向によるので安定的ではない(スクロールマージンの考慮も必要)。
 
: 以下は、ジャンプしてスクロールが発生した場合に、キャレットが表示領域の先頭位置になるようにスクロール状態(<code>window.ScrollY</code>)を調整するコード。
<syntaxhighlight lang="javascript">
var s = Document.Selection;
var s = Document.Selection;
var ax = s.GetActivePointX( mePosLogical ); // キャレット位置の X
var ax = s.GetActivePointX( mePosLogical ); // キャレット位置の X
1,038行目: 1,158行目:


// ※ ScrollY プロパティに値を代入するときは物理座標(表示行)の行番号で
// ※ ScrollY プロパティに値を代入するときは物理座標(表示行)の行番号で
</source>
</syntaxhighlight>


※ スクロールマージンは [https://www.haijin-boys.com/software/mery/mery-2-7-0#2 ベータ版 2.7.0] より「オプション」ダイアログの「スクロール」のページ内で変更できるようになっている。[https://www.haijin-boys.com/weblog/assets/uploads/2019/04/mery-2-7-0-4.png?20190417]
※ スクロールマージンは [https://www.haijin-boys.com/software/mery/mery-2-7-0#2 ベータ版 2.7.0] より「オプション」ダイアログの「スクロール」のページ内で変更できるようになっている。[https://www.haijin-boys.com/weblog/assets/uploads/2019/04/mery-2-7-0-4.png?20190417]
<br><br>
 
=== OutputBar オブジェクト ===
[[マクロリファレンス:OutputBar インターフェイス|OutputBar オブジェクト]] も [[マクロリファレンス:Window インターフェイス#プロパティ|<code>Window</code> オブジェクト直下のプロパティ]] に属するため、アウトプットバー操作の各メソッドやプロパティは、複数ウインドウ状態のときに非アクティブウインドウのアウトプットバーを操作することができない。
 
※ <code>Editors.Item(m).Documents.Item(0).Activate();</code> してからなら、OutputBar 操作可。


=== Window オブジェクト ===
=== Window オブジェクト ===
通常はソースコード内で [[マクロリファレンス:Window インターフェイス|Window オブジェクト]] を明示的に記述する必要はないが、[[#動作要件としてのバージョンチェック|バージョンチェック]] の節の「例4」のように <span style="color:#c00;"> 実際に記述する場合には <source lang="javascript" inline>Window</source> ではなく <source lang="javascript" inline>window</source> でないと宣言されていない変数・オブジェクトあつかいのエラーになる。</span>
通常はソースコード内で [[マクロリファレンス:Window インターフェイス|Window オブジェクト]] を明示的に記述する必要はないが、[[#動作要件としてのバージョンチェック|バージョンチェック]] の節の「例4」のように <span style="color:#c00;"> 実際に記述する場合には <code>Window</code> ではなく <syntaxhighlight lang="javascript" inline>window</syntaxhighlight> でないと宣言されていない変数・オブジェクトあつかいのエラーになる。</span>


※ <source lang="javascript" inline>Document</source> や <source lang="javascript" inline>Selection</source>、<source lang="javascript" inline>Alert</source> など他の主要なプロパティは「大文字/小文字/頭文字のみ大文字」の区別なしに同一のプロパティとしてあつかわれる。
※ <code>Document</code> や <code>Selection</code>、<code>Alert</code> など他の主要なプロパティは「大文字/小文字/頭文字のみ大文字」の区別なしに同一のプロパティとしてあつかわれる。
<br><br>


=== カレントディレクトリ ===
=== カレントディレクトリ ===
カレントディレクトリ(作業フォルダ)は、Mery を起動したときに決定され、一定ではない。<br>
カレントディレクトリ(作業フォルダ)は、Mery を起動したときに決定され、一定ではない。
 
記述の都合上で相対パスを利用するために特定のカレントディレクトリを指定するマクロもあるが、「あえて流動的なカレントディレクトリを利用する」ようなコードが続く場合は、カレントディレクトリを書きもどす必要がある。
記述の都合上で相対パスを利用するために特定のカレントディレクトリを指定するマクロもあるが、「あえて流動的なカレントディレクトリを利用する」ようなコードが続く場合は、カレントディレクトリを書きもどす必要がある。
<source lang="javascript">
 
var fso = new ActiveXObject( "Scripting.FileSystemObject" );
:※ マクロでカレントディレクトリを変更すると、実行中の Mery のプロセスの作業フォルダも変更されるため、あとから他のマクロを実行するさいのカレントディレクトリにも影響する。
 
<syntaxhighlight lang="javascript">
// マクロ実行前の作業フォルダを保存する
var wshShell = new ActiveXObject( "WScript.Shell" );
var wshShell = new ActiveXObject( "WScript.Shell" );
var currentDir = wshShell.CurrentDirectory;


var meryIni = Editor.FullName.replace( /exe$/, "ini" );
// 任意のカレントディレクトリを設定する    e.g. %AppData%\Mery
wshShell.CurrentDirectory = wshShell.SpecialFolders( "APPDATA" ) + "\\Mery";


if ( fso.FileExists( meryIni ) ) {
/* いろいろな処理を実行... */
  // メモ帳で Mery.ini を開く
 
  wshShell.Run( "notepad \"" + meryIni + "\"" );
// 最終的にマクロ実行前の作業フォルダを復帰する
}
wshShell.CurrentDirectory = currentDir;
else {
</syntaxhighlight>
  // マクロ実行前の作業フォルダを保存
  var currentDir = wshShell.CurrentDirectory;


  // 相対パス解決のためにカレントディレクトリを設定 e.g. %AppData%\Mery
* システムの関連付けを利用してテキストファイルなどのダブルクリックから Mery を起動した場合、そのファイルの親フォルダが Mery のプロセスの作業フォルダとなり、Windows OS の仕様により Mery のプロセスを終了するまでそのフォルダはロックされた状態になる(フォルダの移動や削除ができなくなる)が、マクロでカレントディレクトリを変更するとフォルダのロックを解除できる。
  wshShell.CurrentDirectory = wshShell.SpecialFolders( "APPDATA" ) + "\\Mery";
  wshShell.Run( "notepad " + "Mery.ini" );
 
  // マクロ実行前の作業フォルダを復帰
  wshShell.CurrentDirectory = currentDir;
}
</source>
<br>
※ マクロでカレントディレクトリを変更すると、実行中の Mery のプロセスの作業フォルダも変更されるため、あとから他のマクロを実行するさいのカレントディレクトリにも影響する。<br>
システムの関連付けを利用してテキストファイルなどのダブルクリックから Mery を起動した場合、そのファイルの親フォルダが Mery のプロセスの作業フォルダとなり、Windows OS の仕様により Mery のプロセスを終了するまでそのフォルダはロックされた状態になる(フォルダの移動や削除ができなくなる)が、マクロでカレントディレクトリを変更するとフォルダのロックを解除できる。
<br><br>


=== 動作要件としてのバージョンチェック ===
=== 動作要件としてのバージョンチェック ===
公開するマクロに Mery ベータ版で追加されたマクロ用プロパティ・定数を利用する場合は、マクロの動作要件として Mery 本体のバージョンをチェックするコードを入れておくのが無難である。
公開するマクロに Mery ベータ版で追加されたマクロ用プロパティ・定数を利用する場合は、マクロの動作要件として Mery 本体のバージョンをチェックするコードを入れておくのが無難である。
<br>
 
* 拙作の '''組み込み関数''' [[Mery本体のバージョンチェック|VersionCheck()]] を利用すれば、Mery のバージョン番号を指定して動作要件のチェックができるが、あらかじめプロパティや定数が導入された Mery のバージョン番号を調べておく必要がある( ← Mery.txt か CHNGELOG.txt に記載されているはず)。
 
* JavaScript には特定のプロパティがオブジェクト配下に定義されているかを調べる方法も色々とあるが、親オブジェクトのタイプやプロパティ・定数のタイプ、JavaScript(JScript)のバージョンによる互換性などへの考慮が必要になる。 [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/typeof][https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/in][https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty]
* JavaScript には特定のプロパティがオブジェクト配下に定義されているかを調べる方法も色々とあるが、親オブジェクトのタイプやプロパティ・定数のタイプ、JavaScript(JScript)のバージョンによる互換性などへの考慮が必要になる。 [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/typeof][https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/in][https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty]
<br>
: ベータバージョンで追加された定数やプロパティが有効かどうかを調べる程度であれば、シンプルな記述で済む。
* 拙作の '''組み込み関数''' [[Mery本体のバージョンチェック|VersionCheck()]] を利用すれば、Mery のバージョン番号を指定して動作要件のチェックができる。
<syntaxhighlight lang="javascript">
: ※ あらかじめ、プロパティや定数が導入された Mery のバージョン番号を調べておく必要がある( ← Mery.txt に記載されているはず)。
<source lang="javascript">
// ▼ ChangeCase() メソッドで定数 meCaseCapitalize を使えるのは ver 2.6.10 以降
// ▼ ChangeCase() メソッドで定数 meCaseCapitalize を使えるのは ver 2.6.10 以降
if ( document.Selection.IsEmpty ) {
  document.selection.SelectLine(); // とりあえず行を範囲選択
}


// 例1. VersionCheck() 関数を利用する場合
// 例1. VersionCheck() 関数を利用する場合
1,101行目: 1,213行目:
   // 「小文字に変換」
   // 「小文字に変換」
   document.selection.ChangeCase( meCaseLowerCase );
   document.selection.ChangeCase( meCaseLowerCase );
   Status = "小文字で許せ。";
   Status = "小文字…。";
}
}


1,110行目: 1,222行目:
// -------------------------------------------------- //
// -------------------------------------------------- //


// 例2. 定数が定義されているかを調べる場合
// 例2. 定数 meCaseCapitalize が定義されているかを調べる場合
if ( typeof meCaseCapitalize == "number" ) { // または meCaseCapitalize==3
var meCaseCapitalize;
if ( typeof meCaseCapitalize == "number" ) { // または if (meCaseCapitalize == 3)
   // 「単語の最初の文字を大文字に変換」
   // 「単語の最初の文字を大文字に変換」
   document.selection.ChangeCase( meCaseCapitalize );
   document.selection.ChangeCase( meCaseCapitalize );
}
}
else {
else {
   // ExecuteCommandByID() で「単語の最初の文字を大文字に変換」
   // 「小文字に変換」
   editor.ExecuteCommandByID( MEID_EDIT_CAPITALIZE = 2116 );
  document.selection.ChangeCase( meCaseLowerCase );
   Status = "小文字…。";
}
}
</source>
</syntaxhighlight>
<source lang="javascript">
<syntaxhighlight lang="javascript">
// ▼ BeginUndoGroup() メソッドを使えるのは ver 2.7.0 以降
// ▼ BeginUndoGroup() メソッドを使えるのは ver 2.7.0 以降


1,138行目: 1,252行目:
   BeginUndoGroup();
   BeginUndoGroup();
}
}
</source>
</syntaxhighlight>
<br>


=== 外部リソースのチェック ===
=== 外部リソースのチェック ===
「include ライブラリ」や「GetKeyState.exe」のような外部リソースを必要とする前提のマクロでも、それらのリソースがない場合にもある程度マクロが動くようにコーディングすることができる。
「includeライブラリ」や「GetKeyState.exe」のような外部リソースを必要とする前提のマクロでも、それらのリソースがない場合にもある程度マクロが動くようにコーディングすることができる。
<br><br>
 
* [[includeライブラリ|include ライブラリ]] が必要なマクロの場合、ユーザー側が include ライブラリを正しく導入していることが要求される。
* [[includeライブラリ]] が必要なマクロの場合、ユーザー側が includeライブラリを正しく導入していることが要求される。
: ユーザー側で include ライブラリが導入されていて、マクロ側で <source lang="javascript" inline>#include "include/IO.js"</source> のようなプリプロセッサがソースコードの先頭で宣言されていれば問題ないのだが、include ライブラリが導入されていなくても、プリプロセッサを削除(コメントアウト)すればマクロがある程度動くようにコーディングすることもできる。
: ユーザー側で includeライブラリを導入していて、マクロ側で <syntaxhighlight lang="javascript" inline>#include "include/IO.js"</syntaxhighlight> のようなプリプロセッサがソースコードの先頭で宣言されていれば問題ないのだが、includeライブラリが導入されていなくても、プリプロセッサを削除(コメントアウト)すればマクロがある程度動くようにコーディングすることもできる。
<source lang="javascript">
<syntaxhighlight lang="javascript">
// #include "include/IO.js"
// #include "include/IO.js"


1,153行目: 1,266行目:
}
}
else {
else {
   /* IO.js がインクルードされていないときの動作 */ ;
   /* IO.js がインクルードされていないときの代替動作 */ ;
}
}
</source>
</syntaxhighlight>
<br>
 
* また、[[GetKeyState.exe(キー状態取得実行ファイル)]] のあるなしで動作内容を分けるなら、以下のようにコードを記述すればよい。
* また、[[GetKeyState.exe(キー状態取得実行ファイル)]] のあるなしで動作内容を分けるなら、以下のようにコードを記述すればよい。
<source lang="javascript">
<syntaxhighlight lang="javascript">
// あらかじめ変数 ctrl に 0 を代入しておく
// あらかじめ変数 ctrl に 0 を代入しておく
var ctrl = 0;
var ctrl = 0;
1,179行目: 1,292行目:
   /* GetKeyState.exe がない、または Ctrl キーが押されていないとき */ ;
   /* GetKeyState.exe がない、または Ctrl キーが押されていないとき */ ;
}
}
</source>
</syntaxhighlight>
<br>
[[#TOP|>> 目次へ]]
<br><br>


=== Mery.ini から設定値を取得する ===
=== Mery.ini から設定値を取得する ===
[[includeライブラリ|include ライブラリ]] の MeryInfo クラス (MeryInfo.js) を利用して Mery.ini からいくつかの設定項目の値や状態を取得することはできるが、制約が非常に多い。
[[includeライブラリ]] の MeryInfo クラス (<code>#include "include/MeryInfo.js"</code>) を利用して Mery.ini からいくつかの設定項目の値や状態を取得することはできるが、制約が非常に多い。
* 取得できる項目がきわめて限定的である
* 取得できる項目がきわめて限定的である
* 取得する項目が複数あると、その都度 Mery.ini 全体の読み込みが発生する(キャッシュ可)
* 取得したい項目が複数あると、その都度 Mery.ini 全体の読み込みが発生する(キャッシュ可)
* Mery.exe のファイル名を変更 (e.g. Mery_hoge.exe) している場合、MeryInfo.js のコードを改変しないと Mery.ini (Mery_hoge.ini) のパスを得られず、設定値を取得できない。
* Mery.exe のファイル名を変更 (e.g. Mery_hoge.exe) している場合、MeryInfo.js のコードを改変しないと Mery.ini (Mery_hoge.ini) のパスを得られず、設定値を取得できない。
<br>
 
拙作の '''組み込み関数''' [[Mery.iniのオプション値を取得#関数|GetIniOption()]] と [[Mery.iniのオプション値を取得#GetIniOption2() 関数|GetIniOption2()]] はこれらの制約を受けず、とくに後者は <span style="color:#0000c0;"> Mery.ini のすべての項目にアクセスして値を取得することができる。</span><br>
==== GetIniOption() 関数 ====
拙作の '''組み込み関数''' [[Mery.iniのオプション値を取得#関数|GetIniOption()]] と [[Mery.iniのオプション値を取得#GetIniOption2() 関数|GetIniOption2()]] はこれらの制約を受けず、とくに後者は <span style="color:#0000c0;"> Mery.ini のすべての項目にアクセスして値を取得することができる。</span>
 
ただし、制約がない代わりに組み込み関数自体のコードが長いことや、引数や戻り値が配列であることでコードが煩雑にならざるをえない( ⇔ 配列を使用することで、複数の項目を取得する場合でも Mery.ini ファイルの読み込みを1回におさえられる)。
ただし、制約がない代わりに組み込み関数自体のコードが長いことや、引数や戻り値が配列であることでコードが煩雑にならざるをえない( ⇔ 配列を使用することで、複数の項目を取得する場合でも Mery.ini ファイルの読み込みを1回におさえられる)。
<br>
 
※ [[#Mery.ini を読みこむ|IO.LoadFromFile() 関数で Mery.ini を読みこむ]] という方法もある。
※ [[#Mery.ini を読みこむ|IO.LoadFromFile() 関数で Mery.ini を読みこむ]] という方法もある。
<br><br>
 
また、Mery.ini 側の仕様として、
また、Mery.ini 側の仕様として、
  「オプション」など各種の設定ダイアログを [ '''OK''' ] ボタンで閉じたときか、
  「オプション」など各種の設定ダイアログを [ '''OK''' ] ボタンで閉じたときか、
1,201行目: 1,313行目:
  Mery.ini に直ちに反映されない
  Mery.ini に直ちに反映されない
という制約がある(Mery.ini の実体ファイルへの書き込み回数を減らすための仕様)。
という制約がある(Mery.ini の実体ファイルへの書き込み回数を減らすための仕様)。
<br><br>
 
<span style="color:#c00;">エディタの表示状態をトグル切り替えするコマンド(縦書き、色の反転、全画面表示、etc. ...)については、マクロ用の標準メソッド/プロパティから「現在の表示状態」を取得する手段がなく、'''組み込み関数 GetIniOption2() で Mery.ini を読み込んでも、必ずしも「最新の設定状態」を取得できるわけではない'''…。</span>
<span style="color:#c00;">エディタの表示状態をトグル切り替えするコマンド(縦書き、色の反転、全画面表示、etc. ...)については、マクロ用の標準メソッド/プロパティから「現在の表示状態」を取得する手段がなく、'''組み込み関数 GetIniOption2() で Mery.ini を読み込んでも、必ずしも「最新の設定状態」を取得できるわけではない'''…。</span>
<br><br>
 
※ 「現在の表示状態」を取得してから ON/OFF を指定しての切り替えを行なうためには、include ライブラリの IO クラスを利用するなどして外部に Mery.ini とは別の設定ファイル (e.g. JSON ファイル) を用意し、切り替え実行のたびに設定ファイルを読み書きする必要がある。<br>
※ 「現在の表示状態」を取得してから ON/OFF を指定しての切り替えを行なうためには、includeライブラリの IO クラスを利用するなどして外部に Mery.ini とは別の設定ファイル (e.g. JSON ファイル) を用意し、切り替え実行のたびに設定ファイルを読み書きする必要がある。
 
ただし、この方法をとる場合は、外部ファイルに設定内容をあずける項目(コマンド)の切り替えについては必ずマクロ経由で行なわなければならず、デフォルトの メニュー項目/ツールバーアイコン/ショートカットキー による通常操作でその項目の状態の変更をすると、最新の設定状態(現在の表示状態)と外部ファイルが保持している設定内容とのあいだに齟齬が生じてしまう。
ただし、この方法をとる場合は、外部ファイルに設定内容をあずける項目(コマンド)の切り替えについては必ずマクロ経由で行なわなければならず、デフォルトの メニュー項目/ツールバーアイコン/ショートカットキー による通常操作でその項目の状態の変更をすると、最新の設定状態(現在の表示状態)と外部ファイルが保持している設定内容とのあいだに齟齬が生じてしまう。
: → e.g. 「[[折り返しトグル切り替え#3つの折り返しモードを順々にトグルする|折り返しトグル切り替え]]」マクロ
: → e.g. 「[[折り返しトグル切り替え#3つの折り返しモードを順々にトグルする|折り返しトグル切り替え]]」マクロ
<br><br>
 
==== Mery.ini からさまざまな情報を読み込んで利用するマクロ ====
組み込み関数 GetIniOption / GetIniOption2 を利用(必用に応じてカスタマイズ)した拙作マクロ
* 「[[ブックマーク一覧ジャンプ#include版|ブックマーク一覧ジャンプ(include版)]]」「[[ポップアップメニューで検索先にジャンプ#include版|ポップアップメニューで検索先にジャンプ(include版)]]」: 行の表示方法(論理座標/表示座標)の設定状態を取得して、ポップアップメニューに表示するアイテムの行番号の表示方法を切り替え。
* 「[[ファイルを読み直す・開きなおす]]」: 自動保存・バックアップの設定状態、タブの閉じるボタンの表示設定などを取得して動作コードの条件分岐に利用。 編集モード名の一覧取得してポップアップメニューから切り替える。
* 「[[マクロメニュー]]」: [[ヘルプ:マクロ#カスタマイズ|マクロのカスタマイズ]] に登録済みのマクロの一覧をポップアップメニューに表示して、選択したマクロを実行または Mery で開く(編集)。
* 「[[コンパクトメニュー]]」: 登録されている編集モード名の一覧、マクロ(Mery.exe からの相対パス)の一覧、プラグイン(Mery.exe からの相対パス)の一覧、外部ツール名の一覧、およびそれぞれの登録された並び順を取得して、ポップアップメニュー化。 通常では表示されないような機能もほぼ全てメニュー化する。
** ※ [[コンパクトメニュー#制限事項|制限事項]] にマクロから できること/できないこと についての説明あり。
 
==== Mery.ini からは「最新の状態」を取得できない設定項目 ====
* [[ヘルプ:ファイル#最近のファイル|最近開いたファイルの一覧]]、検索履歴、[ [[ヘルプ:表示#フォント|フォントの履歴]] ] とフォントのサイズ、標準ツールバーの [ [[ヘルプ:表示|表示]] ] メニューや [ [[ヘルプ:ウィンドウ|ウインドウ]] ] メニュー内から ON/OFF の切り替えが可能な項目、[[ヘルプ:ツール#プラグイン|プラグイン]] の ON/OFF の状態、現在のウインドウサイズや位置、etc. ...。
※ メニューバーから設定状態を変更できる項目は、即時 Mery.ini の内容が更新されるわけではないので、マクロから「最新の状態」を取得することはできない。 検索履歴も同様。
 
※ フォントの使用履歴の取得は可能だが、[ 表示 ] メニューから切り替えたさいの「最新の状態」は取得できない。 また、マクロからフォントを変更する手段がない (履歴内の並び順を取得できないので <code>wshShell.SendKeys()</code> などのキーストロークエミュレーションでも不可)。 フォントサイズを 大きく/小さく するだけならマクロからでも変更可能。


=== 外部ファイルにマクロの設定などを書き出す ===
=== 外部ファイルにマクロの設定などを書き出す ===
マクロの設定情報を保存して次回の実行時にそれを参照して使いたい場合、[[includeライブラリ|include ライブラリ]] の IO クラス (IO.js) の <source lang="javascript" inline>IO.Serialize()</source> と <source lang="javascript" inline>IO.Deserialize()</source> を利用するのがもっとも簡単な方法だとおもわれる。
マクロの設定情報を保存して次回の実行時にそれを参照して使いたい場合、[[includeライブラリ]] の IO クラス (IO.js) の <code>IO.Serialize()</code> と <code>IO.Deserialize()</code> を利用するのがもっとも簡単な方法だとおもわれる。


* [[マクロライブラリ]] では「[[折り返しトグル切り替え]]」マクロ(Bleat 版 / sukemaru 版)や ks 氏の「[[スマートインデント(C 構文)]]」マクロの SwitchSmartIndent.js のコードが、 <source lang="javascript" inline>IO.Serialize() / Deserialize()</source> を利用したマクロの雛形として利用しやすい。
* [[マクロライブラリ]] では「[[折り返しトグル切り替え]]」マクロ(Bleat 版 / sukemaru 版)や ks 氏の「[[スマートインデント(C 構文)]]」マクロの SwitchSmartIndent.js のコードが、 <code>IO.Serialize()</code> <code>IO.Deserialize()</code> を利用したマクロの雛形として利用しやすい。
* 複数の設定値を保存/参照する複雑なものとしては、ks 氏の「[[階層化マクロメニュー]]」マクロや、拙作「[[ポップアップメニューで検索先にジャンプ#include版|検索ジャンプ]]」「[[ブックマーク一覧ジャンプ#include版|ブックマークジャンプ]]」や「[[ファイルを読み直す・開きなおす#include版|読みなおし]]」マクロなどもあるが、メイン部分の動作コード自体が長く煩雑なので参考にしづらいとおもわれる…。
* 複数の設定値を保存/参照する複雑なものとしては、ks 氏の「[[階層化マクロメニュー]]」マクロや、拙作「[[ポップアップメニューで検索先にジャンプ#include版|検索ジャンプ]]」「[[ブックマーク一覧ジャンプ#include版|ブックマークジャンプ]]」や「[[ファイルを読み直す・開きなおす#include版|読みなおし]]」マクロなどもあるが、メイン部分の動作コード自体が長く煩雑なので参考にしづらいとおもわれる…。
* 「マクロA」で書き込んだ外部ファイル(JSON)を別の「マクロB」で読み込んで利用する例として、ks 氏の「[[スマートインデント(C 構文)]]」、拙作「[[位置情報を保存してから「すべて選択/選択解除」(非スクロール)]]」。<br>
* 「マクロA」で書き込んだ外部ファイル(JSON)を別の「マクロB」で読み込んで利用する例として、ks 氏の「[[スマートインデント(C 構文)]]」、拙作「[[位置情報を保存してから「すべて選択/選択解除」(非スクロール)]]」。


※ ただし、マクロの実行ごとに外部ファイル(設定ファイル.JSON と include ライブラリの IO.js および json2.js)を読みこむことになるので、環境によってはマクロの動作のもたつきや [[#エラー処理|エラー]] が生じてしまう可能性がある。
※ ただし、マクロの実行ごとに外部ファイル(設定ファイル.JSON と includeライブラリの IO.js および json2.js)を読みこむことになるので、環境によってはマクロの動作のもたつきや [[#エラー処理|エラー]] が生じてしまう可能性がある。
<br><br>
 
以下、「[[折り返しトグル切り替え#3つの折り返しモードを順々にトグルする|折り返しトグル切り替え]]」マクロを例に <source lang="javascript" inline>IO.Serialize() / Deserialize()</source> の利用方法の簡単な説明。
以下、「[[折り返しトグル切り替え#3つの折り返しモードを順々にトグルする|折り返しトグル切り替え]]」マクロを例に <code>IO.Serialize()</code> <code>Deserialize()</code> の利用方法の簡単な説明。
<source lang="javascript">
<syntaxhighlight lang="javascript">
#include "include/IO.js"
#include "include/IO.js"
   // \Macros\include\IO.js をインクルードする
   // \Macros\include\IO.js をインクルードする
1,238行目: 1,364行目:


// または、以下のようにまとめてもよい ( ➀+➁ と意味は同じ)
// または、以下のようにまとめてもよい ( ➀+➁ と意味は同じ)
var setting = { wrapMode: 0, count: 0 }
var setting = { wrapMode: 0, count: 0 };
   // ※ {ブラケット} で囲う場合はコロンで結んで  propertyName : value  とする。
   // ※ {ブラケット} で囲う場合はコロンで結んで  propertyName : value  とする。
   //    複数のプロパティを列挙する場合はカンマ「,」で区切る。
   //    複数のプロパティを列挙する場合はカンマ「,」で区切る。
   //    最後にセミコロン「;」をつけないこと。
   //    ブラケット内の最後にセミコロン「;」をつけないこと。


/* 【JSON 読み込み】 */
/* 【JSON 読み込み】 */
1,265行目: 1,391行目:
setting.dateTime = new Date(); // 最終実行日時の記録
setting.dateTime = new Date(); // 最終実行日時の記録


// マクロの実行回数を記録
setting.count += 1; // マクロの実行回数を記録
setting.count += 1;
if ( setting.count % 100 == 0 ) { // 100 回ごとにダイアログを表示
if ( setting.count % 100 == 0 ) { // 100 回ごとにダイアログを表示
   var d = setting.dateTime;
   var d = setting.dateTime;
1,279行目: 1,404行目:
// setting オブジェクトの変更内容を保存する
// setting オブジェクトの変更内容を保存する
IO.Serialize( setting, jsonName );
IO.Serialize( setting, jsonName );
</source>
</syntaxhighlight>
<br>
 
==== Tag プロパティ ====
[https://www.haijin-boys.com/software/mery/mery-3-0-0 ベータ版 ver 3.0.0] で追加された <code>Tag</code> プロパティを活用することで、外部ファイルにマクロの設定を書き出す必用がなくなる場面もでてくるとおもわれる。
: ref. [[マクロリファレンス:3:Document_オブジェクト#Tag_プロパティ|Document.Tag プロパティ]]、[[マクロリファレンス:3:Editor_オブジェクト#Tag_プロパティ|Editor.Tag プロパティ]]、[[マクロリファレンス:3:Window=オブジェクト#Tag_プロパティ|Window.Tag プロパティ]](@[[マクロリファレンス:3]])
 
外部ファイルへのアクセスの必用がなくなり、マクロの実行コードのスリム化(「includeライブラリ」も利用せずに済む)や安定性の向上、動作の高速化などが期待できるが、<code>Tag</code> プロパティへの書き込みは <span style="color:#c00;">最長でも Mery.exe のプロセスが終了するまでの "一時保存/一時利用"</span> にとどまるので、マクロのデフォルト動作の設定を保存したい場合には外部ファイルを利用するほうがよさそうである。
 
* 拙作マクロで外部ファイルの利用から <code>Tag</code> プロパティの利用に切り替えたのは、現時点では上出の「[[折り返しトグル切り替え#3つの折り返しモードを順々にトグルする|折り返しトグル切り替え]]」マクロだけである。
: ※「[[位置情報を保存してから「すべて選択/選択解除」(非スクロール)]]」マクロ (include版) や「[[位置情報を保存してから「すべて選択/選択解除」(非スクロール)#【include 版】位置を復帰/保存|位置を復帰/保存]]」マクロ (include版)、「[[カッコをはずす#カッコを追加/削除|カッコを追加/削除]]」マクロ (include版) も <code>Tag</code> プロパティへの移行を検討中 (いまのところ、ベータ版 ver 3.0.0 で追加された '''マルチカーソル''' 機能 [https://www.haijin-boys.com/software/mery/mery-3-0-0#4] に対応する目処が立っていないので、公開版の更新は保留)。
* ポップアップメニュー内の「設定変更サブメニュー」で動作設定を変更するタイプの拙作【include版】マクロは、外部ファイルを利用する仕様のままにする予定。


=== 関数の「呼び出しコスト」 ===
=== 関数の「呼び出しコスト」 ===
ユーザー関数は、呼び出し元から参照可能な位置に記述すれば、ソースコードの任意の位置に配置することができる。 <br>繰り返し何度も呼び出して使用する関数の場合に「呼び出しコスト」を気にする人もいるらしいが、Mery で使用するマクロ程度のソースコードであればあまり気にする必要はないようにおもわれる。
ユーザー関数は、呼び出し元から参照可能な位置に記述すれば、ソースコードの任意の位置に配置することができる。
<br><br>
 
'''e.g. [[#メタ記号をエスケープする|半角英数字以外を「¥」でエスケープ処理する]]''' <br>
繰り返し何度も呼び出して使用する関数の場合に「呼び出しコスト」を気にする人もいるらしいが、Mery で使用するマクロ程度のソースコードであればあまり気にする必要はないようにおもわれる。
※ あえて '''ループ処理''' で1行ずつエスケープしてみる ([[#その他、拙作マクロについて|@ロースペの XP ノート]])
 
<source lang="javascript">
'''e.g. [[#メタ記号をエスケープする|半角英数字以外を「¥」でエスケープ処理する]]'''
 
※ あえて '''ループ処理で1行ずつエスケープ''' してみる ([[#その他、拙作マクロについて|@ロースペの XP ノート]])
<syntaxhighlight lang="javascript">
/* 関数バージョン */
/* 関数バージョン */


1,306行目: 1,443行目:
}
}
document.Text = a.join( "\n" );
document.Text = a.join( "\n" );
</source>
</syntaxhighlight>
<br>
 
<source lang="javascript" inline>function Quote( str )</source> でも <source lang="javascript" inline>var Quote = function( str )</source> でも、約 9500 行の日本語テキスト(約 33 万文字)にたいして 1.1 秒台の処理時間がかかり有意な差はみられなかった。
<syntaxhighlight lang="javascript" inline>function Quote( str )</syntaxhighlight> でも <syntaxhighlight lang="javascript" inline>var Quote = function( str )</syntaxhighlight> でも、約 9500 行の日本語テキスト(約 33 万文字)にたいして 1.1 秒台の処理時間がかかり有意な差はみられなかった。
<br>
 
関数を使用しない以下のようなベタ書きのコードの場合でも、ほぼ同じ程度の処理時間がかかった (@ロースペの XP ノート)。
関数を使用しない以下のようなベタ書きのコードの場合でも、ほぼ同じ程度の処理時間がかかった (@ロースペの XP ノート)。
<source lang="javascript">
<syntaxhighlight lang="javascript">
/* 非関数バージョン */
/* 非関数バージョン */


1,321行目: 1,458行目:
}
}
document.Text = a.join( "\n" );
document.Text = a.join( "\n" );
</source>
</syntaxhighlight>
<br>
 
※ ループ文の中で関数を定義した場合は、やや遅くなって 1.3 秒台。
※ ループ文の中で関数を定義した場合は、やや遅くなって 1.3 秒台。
<source lang="javascript">
<syntaxhighlight lang="javascript">
BeginUndoGroup();
BeginUndoGroup();
var lines = document.GetLines( 0 );
var lines = document.GetLines( 0 );
1,335行目: 1,472行目:
}
}
document.Text = a.join( "\n" );
document.Text = a.join( "\n" );
</source>
</syntaxhighlight>


<br>
※ 行ごとのループ処理ではなく、文書全体の '''一括処理''' にすると速くなる。
※ 行ごとのループ処理ではなく、文書全体の '''一括処理''' にすると速くなる。<br>
 
上とおなじ <source lang="javascript" inline>Quote()</source> 関数を使用しての文書全体の一括処理でも…
上とおなじ <code>Quote()</code> 関数を使用しての文書全体の一括処理でも…
<source lang="javascript">
<syntaxhighlight lang="javascript">
function Quote( str ) {
function Quote( str ) {
   return str.replace( /\W/g, "\\$&" );
   return str.replace( /\W/g, "\\$&" );
1,346行目: 1,483行目:


document.Text = Quote( document.Text );
document.Text = Quote( document.Text );
</source>
</syntaxhighlight>
関数を使用しないベタ書きの一括処理でも…
関数を使用しないベタ書きの一括処理でも…
<source lang="javascript">
<syntaxhighlight lang="javascript">
document.Text = document.Text.replace( /\W/g, "\\$&" );
document.Text = document.Text.replace( /\W/g, "\\$&" );
</source>
</syntaxhighlight>
…処理時間はほぼ同じで、約 0.7 ~ 0.8 秒だった。
…処理時間はほぼ同じで、約 0.7 ~ 0.8 秒だった。
<br>
 
現行 OS の [https://ja.wikipedia.org/wiki/Chakra#%E6%AD%B4%E5%8F%B2 Chakra エンジン (jscript9.dll) であれば約 20 倍] の速度が出るらしいので、数メガバイトとか数万行とかのよほど長大な文書の処理をする場合でもなければ、「関数の呼び出しコスト」を気にする必要はあまりなさそう。
現行 OS の [https://ja.wikipedia.org/wiki/Chakra#%E6%AD%B4%E5%8F%B2 Chakra エンジン (jscript9.dll) であれば約 20 倍] の速度が出るらしいので、数メガバイトとか数万行とかのよほど長大な文書の処理をする場合でもなければ、「関数の呼び出しコスト」を気にする必要はあまりなさそう。
<br><br>
 
それよりも、
それよりも、
* 文字列操作や検索/置換にさいして、なるべくキャレットの移動をともなうメソッドを使用しない
* 文字列操作や検索/置換にさいして、なるべくキャレットの移動をともなうメソッドを使用しない
1,361行目: 1,498行目:
: e.g. [[マクロリファレンス:Document インターフェイス#Text プロパティ|Document.Text]] や [[マクロリファレンス:Selection インターフェイス#Text プロパティ|Document.Selection.Text]]、 [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/length#Iterating_over_an_array for 文 での Array.length] など。
: e.g. [[マクロリファレンス:Document インターフェイス#Text プロパティ|Document.Text]] や [[マクロリファレンス:Selection インターフェイス#Text プロパティ|Document.Selection.Text]]、 [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/length#Iterating_over_an_array for 文 での Array.length] など。
* 関数定義文で必要となる引数をすべて与えておき、関数スコープからグローバルスコープに変数の値を参照しに行かないで済むようにしておく
* 関数定義文で必要となる引数をすべて与えておき、関数スコープからグローバルスコープに変数の値を参照しに行かないで済むようにしておく
などで、ソースコードの最適化をはかるほうが良いはず。<br>
* ループ処理などから繰りかえして呼び出す必要のある関数の場合は、なるべくなら関数定義文を呼び出し元のコードよりも先に記述しておく
<br><br>
などで、ソースコードの最適化をはかるほうが良いはず。(… sukemaru 自身はこのルールをあまり守っていない)
※ ちなみに、Quote() 関数を以下のように記述した場合、上出のループ処理コードでの所要時間は 3 倍(3 秒台)。
 
<source lang="javascript">
※ ちなみに、<code>Quote()</code> 関数を以下のように記述した場合、上のようなループ処理コードでの所要時間は 3 倍(3 秒台)。
<syntaxhighlight lang="javascript">
function Quote( str ) {
function Quote( str ) {
   return str.replace( /\W/g, function( $0 ) {
   return str.replace( /\W/g, function( $0 ) {
1,370行目: 1,508行目:
   } );
   } );
}
}
</source>
</syntaxhighlight>
以下のような記述だと、ループ処理した場合の所要時間は 4 倍以上(4 ~ 5 秒台)になる。
以下のような記述だと、ループ処理した場合の所要時間は 4 倍以上(4 ~ 5 秒台)になる。
<source lang="javascript">
<syntaxhighlight lang="javascript">
function Quote( str ) {
function Quote( str ) {
   return str.replace( /\W/g, Escape );
   return str.replace( /\W/g, Escape );
1,379行目: 1,517行目:
   return "\\" + matched;
   return "\\" + matched;
}
}
</source>
</syntaxhighlight>
…ループ処理から参照する関数のネストや二重参照は、ループ文内で関数を定義する場合以上に鬼門のようだ。
…ループ処理から参照する関数のネストや二重参照は、ループ文内で関数を定義する場合以上に鬼門のようだ。
<br>
[[#TOP|>> 目次へ]]
<br><br>


=== FileSystemObject と WScript.Shell でファイルパスを引数にするとき ===
=== FileSystemObject と WScript.Shell でファイルパスを引数にするとき ===
1,389行目: 1,524行目:
* [https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc409800(v=msdn.10) FileSystemObject] ではパスをダブルクオートなどの <b style="color:#0000c0;">引用符で囲う必要がない</b>
* [https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc409800(v=msdn.10) FileSystemObject] ではパスをダブルクオートなどの <b style="color:#0000c0;">引用符で囲う必要がない</b>
* [https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc364436%28v%3dmsdn.10%29 WScript.Shell] などの WSH コードではパスをダブルクオートなどの <b style="color:#c00;">引用符で囲う必要がある</b>
* [https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc364436%28v%3dmsdn.10%29 WScript.Shell] などの WSH コードではパスをダブルクオートなどの <b style="color:#c00;">引用符で囲う必要がある</b>
<br>
よって、[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc364421%28v%3dmsdn.10%29 WshShell.Run() コマンド] などで不特定のパス(または任意のパス)を指定するときは <source lang="javascript" inline>WshShell.Run( "\"" + path + "\"" )</source> または <source lang="javascript" inline>'WshShell.Run( '"' + path + '"' )</source> のように記述しておき、パスに半角空白がふくまれていてもエラーにならないように備えておくとよい。


<source lang="javascript">
よって、[https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc364421%28v%3dmsdn.10%29 WshShell.Run() コマンド] などで不特定のパス(または任意のパス)を指定するときは <syntaxhighlight lang="javascript" inline>WshShell.Run( "\"" + path + "\"" )</syntaxhighlight> または <syntaxhighlight lang="javascript" inline>WshShell.Run( '"' + path + '"' )</syntaxhighlight> のように記述しておき、パスに半角空白がふくまれていてもエラーにならないように備えておくとよい。
 
<syntaxhighlight lang="javascript">
// 半角空白を含むパス
// 半角空白を含むパス
var path = "C:\\Hoge hoge\\Fuga fuga\\Piyo piyo.txt";
var path = "C:\\Hoge hoge\\Fuga fuga\\Piyo piyo.txt";
1,402行目: 1,537行目:
   wshShell.Run( "\"" + path + "\"" ); // 引用符で囲う必要がある
   wshShell.Run( "\"" + path + "\"" ); // 引用符で囲う必要がある
}
}
</source>
</syntaxhighlight>
 


=== 警告・確認ダイアログとステータスバーの使い分け ===
=== 警告・確認ダイアログとステータスバーの使い分け ===
マクロからユーザーにメッセージを与える手段として '''警告'''([[マクロリファレンス:Window インターフェイス#Alert メソッド|window.Alert]])・'''確認'''([[マクロリファレンス:Window インターフェイス#Confirm メソッド|window.Confirm]])ダイアログと '''ステータスバー'''([[マクロリファレンス:Window インターフェイス#Status プロパティ|window.Status]])への表示などがある(ほかに '''アウトプットバー'''([[マクロリファレンス:OutputBar インターフェイス#Write メソッド|OutputBar.Write]])や '''ポップアップメニュー''' を使う方法もある)。
マクロからユーザーにメッセージを与える手段として '''警告'''([[マクロリファレンス:Window インターフェイス#Alert メソッド|window.Alert]])・'''確認'''([[マクロリファレンス:Window インターフェイス#Confirm メソッド|window.Confirm]])ダイアログと '''ステータスバー'''([[マクロリファレンス:Window インターフェイス#Status プロパティ|window.Status]])への表示などがある(ほかに '''アウトプットバー'''([[マクロリファレンス:OutputBar インターフェイス#Write メソッド|OutputBar.Write]])や '''ポップアップメニュー''' を使う方法もある)。
<source lang="javascript">
<syntaxhighlight lang="javascript">
// e.g. ポップアップメニューを「ポップアップヒント」として使用する
// e.g. ポップアップメニューを「ポップアップヒント」として使用する


1,415行目: 1,549行目:
   var r = m.Track( 1 );
   var r = m.Track( 1 );
}
}
</source>
</syntaxhighlight>
<br>
 
基本的に、Mery のマクロで利用できるポップアップダイアログ(警告、確認)はどちらもサウンドをともない、ボタン操作で閉じるまで作業を中断させてしまうので、あえて作業を一時停止させる必要がある場面以外ではステータス表示を使用するのがよい。
基本的に、Mery のマクロで利用できるポップアップダイアログ(警告、確認)はどちらもシステムサウンドをともない、ボタン操作で閉じるまで作業を中断させてしまうので、あえて作業を一時停止させる必要がある場面以外ではステータス表示を使用するのがよい。
<br>
 
※ ユーザー側がステータス表示を使用するイベントマクロなどを別途で導入していることを考慮すると、マクロの終了時になんらかのイベントが発生するマクロの場合、重要なメッセージはダイアログで出力させるか、マクロ内の動作設定用の変数で出力方法を選択できるようにしておくとなおよい。
※ ユーザー側がステータス表示を使用するイベントマクロなどを別途で導入していることを考慮すると、マクロの終了時になんらかのイベントが発生するマクロの場合、重要なメッセージはダイアログで出力させるか、マクロ内の動作設定用の変数で出力方法を選択できるようにしておくとなおよい。
<br><br>
また、Mery の Window クラスのメソッド・プロパティを使うほかにも、WSH の [https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc364428(v=msdn.10) WshShell.Popup メソッド] によるメッセージボックス利用することもできる。<br>
ダイアログ内の左側のアイコンの種類や <kbd>OK</kbd> <kbd>キャンセル</kbd> <kbd>はい</kbd> <kbd>いいえ</kbd> などのボタンの種類をカスタマイズでき、指定時間の経過後に自動で閉じさせることもできるが、引数の指定や戻り値の処理が煩雑なので、 <kbd>はい</kbd> <kbd>いいえ</kbd> <kbd>キャンセル</kbd> の3ボタンが必要な場合でもなければお勧めはしない…。<br>
※ アイコンなしにすれば、システムのサウンドなしでダイアログを表示できる。
<br><br>


<!--  
また、Mery の Window クラスのメソッド・プロパティを使うほかにも、WSH の [https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc364428(v=msdn.10) WshShell.Popup() メソッド] によるメッセージボックスを利用することもできる。
=== エラー処理 ===
 
Mery のマクロで例外(エラー)が発生した場合、ダイアログのポップアップにより中断される。<br>
ダイアログ内の左側のアイコンの種類や <kbd>OK</kbd> <kbd>キャンセル</kbd> <kbd>はい</kbd> <kbd>いいえ</kbd> などのボタンの種類をカスタマイズでき、指定時間の経過後に自動で閉じさせることもできるが、引数の指定や戻り値の処理が煩雑なので、 <kbd>はい</kbd> <kbd>いいえ</kbd> <kbd>キャンセル</kbd> の3ボタンが必要な場合でもなければお勧めはしない…。
マクロの開発者側にとってはソースファイル内の例外が発生した行に速やかにアクセスできるので便利ではあるが、コードを読むのに不慣れなユーザーにおいてはソースコードを開いたところで何が解決するわけでもない。<br>
エラーダイアログは自家用の自作マクロのメンテナンスのさいには有用であるが、公開用のマクロの場合はユーザーがソースコードに誤った改変を加えてしまう惧れもあるので、基本的に必要性がないといえる。
<br><br>
<source lang="javascript" inline>wshShell.Run( "実在しない実行ファイル.exe /間違ったパラメータ" );</source> のようなコードの場合でも、Mery.exe のエラーとして扱われる。
<br><br>
例外が発生することを予期できたり、例外が発生してもそれを無視してマクロの実行を継続したり回避用の処理に移行させられる場合は、JavaScript の [https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Exception_Handling_Statements/try...catch_Statement try...catch 文] を組み込むとよい。
<source lang="javascript">
// e.g. コピーや上書き保存のようなファイルシステムを操作するマクロは
//      アクセス権限や読取専用ファイルへの書き込み、パスの指定ミスなど
//      ユーザーの実行環境により例外が発生する可能性がある


try {
アイコンなしにすれば、システムのサウンドなしでダイアログを表示できる。
  /*
  * 例外が発生する可能性のあるコード
  * (例外が発生しなかったときはそのまま処理される)
  *
  * このブロック内で例外が発生したとき
  *    原因箇所より後ろのコードは処理されず
  *    catch や finally ブロックにジャンプする
  */ ;
}
catch( e ) {
  /*
  * 例外が発生したときにだけ実行されるコードブロック
  * (例外が発生しなかったときは処理されない)
  *
  * ・Alert(), Confirm() や Status= でメッセージを表示させたり
  *  回避処理用のコードを記述したりしてもよい。
  *
  * ※ エラーの内容を特定して予期できるなら
  *  catch( e if e == hoge ) { ... ; }
  *  catch( e if e == fuga ) { ... ; }
  *  catch( e ) {
  *    if ( e.number == -xxxxxxxxxx ) { ... ; }
  *    else { ... ; }
  *  }
  *    のように列記して処理を分岐させてもよい。
  *
  * ・Alert(e); だけ記述しておいて、エラーダイアログだけは出して
  *  マクロを終了させてもよい(ソースファイルを開かせない)。
  * ・Quit(); だけ記述しておいて、エラーダイアログなしで
  *  マクロを終了させてもよい。
  * ・セミコロンだけおいて {;} とすれば、エラーを無視して
  *  catch(e) {;} ブロックよりうしろのコードを処理させることもできる。
  */ ;
}
finally {
  /*
  * 例外が発生してもしなくても処理されるコード
  * (例外が発生したときは catch ブロックの後に実行される)
  * ※ finally { ... } ブロックはまるごと省略可
  *
  * Scripting.FileSystemObject や ADODB.Stream でファイルを開いている場合は
  * ここでリソースを解放してやるとよい。
  *
  * try ... catch 文を関数ブロック function(){ ... } 内においている場合は
  *  return piyo;
  * などで、なんらかの戻り値を返してやってもよい。
  *
  * ※ catch ブロックで Quit(); や return ***; を記述している場合は
  *    エラーが発生したときに finally ブロックは処理されない
  *
  */ ;
}


/*
<code>WshShell.Popup()</code> メソッドならばメッセージボックスが表示されたままの状態でもエディタの編集操作が可能な場合もあるが、メッセージボックスが表示されているあいだは別のマクロを起動することはできない (ショートカットキーなどから別のマクロを起動しようとすると、Mery 本体のプロセスが不安定になることがある)。
* 上で Quit(); や return ***; を記述していない場合は
* try ... catch 文のあとのコードも処理される
*/ ;
</source>
<source lang="javascript">
// テスト
try{
  hoge;
} catch(e) {
  Status = e.message; // 「'hoge' は宣言されていません。」
  Alert(e); // 「TypeError: 'hoge' は宣言されていません。」
}
Status = "Error Test";
</source>
<br>
-->
[[#TOP|>> 目次へ]]
<br><br>


=== その他、拙作マクロについて ===
=== その他、拙作マクロについて ===
Kuro 氏の [[#引用符/コメント|「引用を追加」マクロのカスタマイズ]] をきっかけとしてマクロの改造に手を染め、 [[#アイコン|マクロのアイコン化のためにアイコンを量産]] していくうちにマクロの自作も始めて、マクロ制作のための補助的マクロの自作とか「タマゴ? ニワトリ?」状態になったりしています。<br>
Kuro 氏の [[#引用符/コメント|「引用を追加」マクロのカスタマイズ]] をきっかけとしてマクロの改造に手を染め、 [[#アイコン|マクロのアイコン化のためにアイコンを量産]] していくうちにマクロの自作も始めて、マクロ制作のための補助的マクロの自作とか「タマゴ? ニワトリ?」状態になったりしています。
'''マウス派''' として Mery を便利に扱えるようにするつもりでマクロを作っていますが、マニアックな個人的要求(欲求)を自己解決していくうちに [[#スクショ|Mery の外観]] が本来の姿からかけ離れてしまっているという…。
 
'''マウス派''' として Mery を便利に扱えるようにするつもりでマクロを作っていますが、マニアックな個人的要求(欲求)を自己解決していくうちに Mery の外観 が本来の姿からかけ離れてしまっているという…。


* sukemaru の Mery 運用環境はロースペックの '''Windows XP sp3 (32bit), JScript 5.8.20587''' のノート PC (CPU: Atom 1.7GHz, 1 コア, 2 スレッド) です。
* sukemaru の Mery 運用環境はロースペックの '''Windows XP sp3 (32bit), JScript 5.8.20587''' のノート PC (CPU: Atom 1.7GHz, 1 コア, 2 スレッド) です。
: ※ 制作したマクロの動作テストは、この XP 機でしかおこなっていません。
: ※ 制作したマクロの動作テストは、この XP 機でしかおこなっていません。
: ※ マクロの動作テストに使用している Mery のバージョンは、"最新のベータ版" (および "最新の正式版" ver. 2.6.7 ) のみです。 基本的に ver 2.6.7 以降のバージョンで動作するように作成していますが、ver 2.6.6 以前のバージョンでの利用を想定していません( ver 2.6.6 以下での動作確認はしていません)。
: ※ マクロの動作テストに使用している Mery のバージョンは、"最新のベータ版" (および "最新の正式版" ver. 2.6.7 ) のみです。 基本的に ver 2.6.7 以降のバージョンで動作するように作成していますが、ver 2.6.6 以前のバージョンでの利用を想定していません( ver 2.6.6 以下での動作確認はしていません)。
: ※ とくに「[[マクロライブラリ#実験的マクロ・練習マクロなど|実験的マクロ・練習マクロ]]」カテゴリに投稿した【自家用】/【実験】マクロにおいては、よその環境を考慮した動作テストをしていません。
: ※ とくに「[[#実験的マクロ・練習マクロなど|実験的マクロ・練習マクロなど]]」カテゴリに投稿した【自家用】/【実験】マクロにおいては、よその環境を考慮した動作テストをしていません。
: ※ マクロの動作速度のテストは [https://www.aozora.gr.jp/ 青空文庫] からダウンロードした『[https://www.aozora.gr.jp/cards/000148/card789.html 吾輩は猫である]』のルビを削除して1文ごとに改行させたテキストファイル(約 33 万文字/約 9500 行)でおこなっています。 1 メガバイト超のファイルでのテストはしていません ( ロースペ PC なので 2000 行を超えるあたりから動作速度が気になりだすのですが… [https://www.haijin-boys.com/discussions/4395])。
: ※ マクロの動作速度のテストは [https://www.aozora.gr.jp/ 青空文庫] からダウンロードした『[https://www.aozora.gr.jp/cards/000148/card789.html 吾輩は猫である]』のルビを削除して1文ごとに改行させたテキストファイル(約 33 万文字/約 9500 行)でおこなっています。 1 メガバイト超のファイルでのテストはしていません ( ロースペ PC なので 2000 行を超えるあたりから動作速度が気になりだすのですが… [https://www.haijin-boys.com/discussions/4395])。
: ※ ZIP 版の Mery でマクロを作成・運用しているので、インストーラ版では正しく動作しないマクロがあるかもしれません。
: ※ ZIP 版の Mery でマクロを作成・運用しているので、インストーラ版では正しく動作しないマクロがあるかもしれません。
* 開発環境が Windows XP なので、拙作マクロは基本的に JavaScript(JScript)マクロです。
* 開発環境が Windows XP なので、拙作マクロは基本的に JavaScript(JScript)マクロです。
: ※ 変数はすべて <source lang="javascript" inline>var</source> で宣言し、JScript 5.8 の環境で実行できるようにコーディングしています。
: ※ 変数はすべて <syntaxhighlight lang="javascript" inline>var</syntaxhighlight> で宣言し、JScript 5.8 の環境で実行できるようにコーディングしています。
* Mery のオプション設定で「行の表示方法=論理座標 (論理行)」の状態で運用する前提でマクロを作っています。 公開しているマクロでは、「表示座標 (表示行)」ベースで Mery を運用している場合でも利用できるように設定項目(変数)を設けるか「行の表示方法」を自動判定するコードを追加していますが、動作が不完全になったり処理がおそくなったりすることがあります。
* Mery のオプション設定で「行の表示方法=論理座標 (論理行)」の状態で運用する前提でマクロを作っています。 公開しているマクロでは、「表示座標 (表示行)」ベースで Mery を運用している場合でも利用できるように設定項目(変数)を設けるか「行の表示方法」を自動判定するコードを追加していますが、動作が不完全になったり処理がおそくなったりすることがあります。
: <span style="color:#c00;"> ※「表示座標 (表示行)」ベースでの動作テストはほとんどしていません。</span>
: <span style="color:#c00;"> ※「表示座標 (表示行)」ベースでの動作テストはほとんどしていません。</span>
* ソースコード内ではしばしば unicode 文字を使用していますので、マクロの JS ファイルは UTF-8 形式で保存する前提となっています。
* ソースコード内ではしばしば unicode 文字を使用していますので、マクロの JS ファイルは UTF-8 形式で保存する前提となっています。
* ソースコード内の変数名の検索などで「[[ポップアップメニューで検索先にジャンプ|検索ジャンプ]]」マクロを利用しやすいように(個人的にタグジャンプ系のマクロに馴染めないので)、マクロのコードには半角空白を多用しています。
* ソースコード内の変数名の検索などで「[[ポップアップメニューで検索先にジャンプ]]」マクロを利用しやすいように(個人的にタグジャンプ系のマクロに馴染めないので)、マクロのコードには半角空白を多用しています。
* 基本的に、変数名は頭文字が小文字の '''camelCase''' に、関数名は頭文字が大文字の '''TitleCase''' にしてあります。
* 基本的に、変数名は頭文字が小文字の '''camelCase''' に、関数名は頭文字が大文字の '''TitleCase''' にしてあります。
<br>
* 「[[includeライブラリ]]」(作成: ks 氏) を利用する【'''include 版'''】と利用しない【'''通常版'''】とがあるマクロでは、include 版を優先的にメンテ・更新しています(←自家用)。
* 「[[includeライブラリ|include ライブラリ]]」(作成: ks 氏) を利用する【'''include 版'''】と利用しない【'''通常版'''】とがあるマクロでは、include 版を優先的にメンテ・更新しています(←自家用)。
* 外部実行ファイル「[[GetKeyState.exe(キー状態取得実行ファイル)]]」(作成: pizz 氏) の導入が必要なものもあります。
* 外部実行ファイル「[[GetKeyState.exe(キー状態取得実行ファイル)|GetKeyState.exe]]」(作成: pizz 氏) の導入が必要なものもあります。[https://www.haijin-boys.com/wiki/GetKeyState.exe%28%E3%82%AD%E3%83%BC%E7%8A%B6%E6%85%8B%E5%8F%96%E5%BE%97%E5%AE%9F%E8%A1%8C%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%29#.E3.81.9D.E3.81.AE.E4.BB.96]


* ポップアップメニューマクロの「設定変更サブメニュー」など、複数のマクロで共通の自作関数を使用しているものがありますが、当面は「include ライブラリ」のような外部ファイルにまとめる予定なしです。
* ポップアップメニューマクロの「設定変更サブメニュー」など、複数のマクロで共通の自作関数を使用しているものがありますが、当面は「includeライブラリ」のような外部ファイルにまとめる予定なしです。
: ∴ すでに公開しているマクロが多いこと、公開用と自家用とでコードの内容がちがうマクロが複数あること、それぞれのマクロごとに自作関数のコードに改変をくわえていることなどの理由で、もはや関数・クラスを統一しなおして更新メンテするのが困難。
: ∴ すでに公開しているマクロが多いこと、公開用と自家用とでコードの内容がちがうマクロが複数あること、それぞれのマクロごとに自作関数のコードに改変をくわえていることなどの理由で、もはや関数・クラスを統一しなおして更新メンテするのが困難。
: <div id="Mery.ini を読みこむ"></div>∴ 「include ライブラリ」のように独自クラスでまとめたものをインクルードして利用するよりも、必要な関数だけをソースコード内にコピペして使用するほうが、マクロの処理速度的には僅かながらも有利?(な気がする… @ロースペ XP)。
: <span id="Mery.ini を読みこむ"></span>∴ 「includeライブラリ」のように独自クラスでまとめたものをインクルードして利用するよりも、必要な関数だけをソースコード内にコピペして使用するほうが、マクロの処理速度的には僅かながらも有利?(な気がする… @ロースペ XP)。
<br>
:: →念のため確認してみたら、やはり差は僅かだった。
→ 念のため確認してみたら、やはり差は僅かだった。
: ※「includeライブラリ」の MeryInfo.js と [[マクロ覚え書き(開発者向け)#includeライブラリの IO クラスを利用する|IO.js をインクルード]] したマクロで Mery.ini ( 31 万文字超/約 5600 行、約 320 kB ) から「行の表示方法 (LineColumnView キー)」を取得すると、平均 0.125 秒。
: ※「include ライブラリ」の MeryInfo.js と [[マクロ覚え書き(開発者向け)#include ライブラリの IO クラスを利用する|IO.js をインクルード]] したマクロで Mery.ini ( 31 万文字超/約 5600 行、約 320 kB ) から「行の表示方法 (LineColumnView キー)」を取得すると、平均 0.125 秒。
<syntaxhighlight lang="javascript">
<source lang="javascript">
#include "include/IO.js"
#include "include/IO.js"
#include "include/MeryInfo.js"
#include "include/MeryInfo.js"
1,553行目: 1,601行目:
Alert( "行の表示方法: " + ( lineColumnView ? "表示行" : "論理行" )
Alert( "行の表示方法: " + ( lineColumnView ? "表示行" : "論理行" )
     + "\n\n" + ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒" );
     + "\n\n" + ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒" );
</source>
</syntaxhighlight>
<br>
 
: ※ [[Mery.iniのオプション値を取得#GetIniOption2() 関数|組み込み関数 GetIniOption2()]] を利用したマクロで「行の表示方法」を取得すると、平均 0.095 秒。
: ※ [[Mery.iniのオプション値を取得#GetIniOption2() 関数|組み込み関数 GetIniOption2()]] を利用したマクロで「行の表示方法」を取得すると、平均 0.095 秒。
<source lang="javascript">
<syntaxhighlight lang="javascript">
var start = new Date();
var start = new Date();
// 関数の戻り値 iniOption[0][2] が LineColumnView キーの値
// 関数の戻り値 iniOption[0][2] が LineColumnView キーの値
1,570行目: 1,618行目:
}
}
// ---------- ▲ 組み込み関数 ココまで ▲ ----------
// ---------- ▲ 組み込み関数 ココまで ▲ ----------
</source>
</syntaxhighlight>
: GetIniOption2() 関数は、<source lang="javascript" inline>IO.LoadFromFile()</source> と <source lang="javascript" inline>MeryInfo.GetIniPath()</source> のコードを翻案して作ったものなので、Mery.ini のパスを解決して [[マクロ覚え書き(開発者向け)#ADODB.Stream を利用する|ADODB.Stream で読みこむ]] 処理の部分はほぼ同じ。 Mery.ini のテキストデータから LineColumnView キーの値を検索する方法は異なるが、その部分は「include ライブラリ」を使用したコードの [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec RegExp.exec( str ) メソッド] のほうが速いはず。<br> ※ GetIniOption2() 関数は [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/search String.search( regexp ) メソッド] と、[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf String.indexOf( searchValue, fromIndex ) メソッド] ×3回でキーの値を取得する。<br>
: GetIniOption2() 関数は、<code>IO.LoadFromFile()</code> と <code>MeryInfo.GetIniPath()</code> のコードを翻案して作ったものなので、Mery.ini のパスを解決して [[マクロ覚え書き(開発者向け)#ADODB.Stream を利用する|ADODB.Stream で読みこむ]] 処理の部分はほぼ同じ。 Mery.ini のテキストデータから LineColumnView キーの値を検索する方法は異なるが、その部分は「includeライブラリ」を使用したコードの [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec RegExp.exec( str ) メソッド] のほうが速いはず。
: … とはいえど、「include ライブラリ」は多種多様な各クラス同士でのプロパティ(関数)の相互参照により高度に効率化されていて、おいそれとアレンジできない部分がたくさんあるため、素直にインクルードして利用するほうがよいのかも。
:: ※ GetIniOption2() 関数は [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/search String.search( regexp ) メソッド] と、[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf String.indexOf( searchValue, fromIndex ) メソッド] ×3回でキーの値を取得する。
<br><br>
: … とはいえど、「includeライブラリ」は多種多様な各クラス同士でのプロパティ(関数)の相互参照により高度に効率化されていて、おいそれとアレンジできない部分がたくさんあるため、素直にインクルードして利用するほうがよいのかも。
[[#TOP|>> 目次へ]]
<br><br>


== 投稿した構文ファイル ==
== 投稿した構文ファイル ==
<br>
* [[JaneStyle (正規表現用)]] (uploaded: 2018/08/31)
* [[JaneStyle (正規表現用)]] (uploaded: 2018/08/31)
: ReplaceStr.txt / ImageViewURLReplace.dat / URLExec.dat / command.dat に対応
: ReplaceStr.txt / ImageViewURLReplace.dat / URLExec.dat / command.dat に対応
1,590行目: 1,635行目:
: Mery の MSY 構文ファイル用
: Mery の MSY 構文ファイル用


* [[Mery Macro JS]] (last modified: 2018/11/10)
* [[Mery Macro JS]] (last_modified: 2020/06/02)
: マクロの JS ファイル(JScript)用
: マクロの JS ファイル(JScript)用
: JavaScript 用構文ファイル/入力補完用辞書/スペルチェック用辞書/おまけマクロ を同梱
: JavaScript 用構文ファイル/入力補完用辞書/スペルチェック用辞書/おまけマクロ を同梱
: <span style="color:#c00;"> ※ Web 開発向けのキーワードは未収録 </span>
: <span style="color:#c00;"> ※ Web 開発向けのキーワードは未収録 </span>
<br>
: ref. Mery 公式フォーラム 『 [https://www.haijin-boys.com/discussions/3655#discussion-3951 デフォルトの構文定義の拡充について]』
: ref. Mery 公式フォーラム 『 [https://www.haijin-boys.com/discussions/3655#discussion-3951 デフォルトの構文定義の拡充について]』
<br><br>
[[#TOP|>> 目次へ]]
<br><br>


== スクショ ==
== メモ ==
<br>
=== マーカー設定 ===
; マクロバーのアイコン化
正規表現でマーカーに登録するさいは、
マクロバー (1段目) にアイコンを詰めこむための sukemaru の試行錯誤の遍歴... [https://www.haijin-boys.com/software/mery/mery-2-7-5#comment-2379][https://www.haijin-boys.com/discussions/4643]
* '''共通'''
: システム環境: Windows XP 32bit SP3 (Classic テーマ)
: ウインドウサイズ (幅): 約 970 px
: アイコンサイズ: 中 (24px)
: アイコン:[[マテリアルデザインっぽいアイコンと『小マクロ集』|マテリアルデザインっぽいアイコン]]
: 標準ツールバー (2段目) のアイコン数: 28 コ
<br>
* [https://www.haijin-boys.com/software/mery/mery-2-8-0#4 Ver. 2.8.0](2019/06/22)
: マクロバーのアイコン数 28 コ、ラベルなし、セパレータあり( #begingroup=3 )
: [[ファイル:Mery_2.8.0_SS.png|link=https://www.haijin-boys.com/wiki/images/1/1b/Mery_2.8.0_SS.png|480px|thumb|left|Ver. 2.8.0]]<br clear=all>


* [https://www.haijin-boys.com/software/mery/mery-2-7-5#12 Ver. 2.7.8](2019/06/13)
<code>ラベル |正規表現</code>
: マクロバーのアイコン数 22 コ半、ラベルなし、余白あり( #title="" )<br> ※ 3段目は外部ツールバー (アイコン 30 コ)
: [[ファイル:Mery_2.7.8_SS.png|link=https://www.haijin-boys.com/wiki/images/5/54/Mery_2.7.8_SS.png|480px|thumb|left|Ver. 2.7.8]]<br clear=all>


* Ver. 2.7.4 まで(2019/05/05)
のように並列演算子 <q>|</q> の左側に「題名+全角空白」、右側に正規表現としておくと、マーカーバーが見やすくなる(パフォーマンス的にはよくないかも)。
: マクロバーのアイテム数 16 件、ラベルあり(#title="hoge" の文字数を切りつめてやり繰り)
: [[ファイル:Mery_2.7.4_SS.png|link=https://www.haijin-boys.com/wiki/images/3/3f/Mery_2.7.4_SS.png|480px|thumb|left|Ver. 2.7.4]]<br clear=all>
<br>


<div id="アイコン"></div>
* いわゆる「プログラミング用フォント」を導入していないので、ゼロ <q>0</q> と '''オー <q>O</q>''' や、イチ <q>1</q> と '''アイ <q>I</q>''' と エル <q>l</q> と バー <q>|</q> を区別できるよう、アイ と オー にマーカーを設定。
* 「マテリアルデザインっぽいアイコン」は、sukemaru の自作マクロと、sukemaru がマクロライブラリからダウンロードして利用しているマクロを対象として制作しています。
** '''円マーク <q>¥</q>''' (U+00A5) や '''波ダーシ <q>〜</q>''' (U+301C) 他、見分けづらい文字も追加。
: ※ [[ヘルプ:目次#コマンドリファレンス|メニューバーの標準コマンド]] や、ショートカット設定/右クリックメニュー用コマンド、[[キーアサイン集]] の小マクロをアイコン化できるように、『小マクロ集』としてまとめました。
<u> ☑ 大文字小文字を区別  ☑ 正規表現 </u>
<br><br>


== おまけ ==
<code>[OOII]|[¥∖╲〜☓×〇➀-➉]</code>
: ※「半角数字」には、 [ オプション ] の [ 表示 ] 設定でカスタム文字色を設定。
: ※ 半角バーチカルバー (パイプ) <q>|</q> は、必要に応じて [ 編集モード ] の強調文字列に設定。
: ※ 小文字エル <q>l</q> は、出現頻度が高く、編集モードの登録単語にふくまれていることも多いので強調なし。


=== マーカー設定 ===
* 特殊な空白文字用
<br>
** 「MeiryoKe_Gothic」 フォントで通常の全角/半角空白と区別できない <q>特殊な空白文字</q> と、<q>ゼロ幅空白文字</q>
正規表現でマーカーに登録するさいは、
ラベル |正規表現
のように並列演算子 <q>|</q> の左側に「題名+全角空白」、右側に正規表現としておくと、マーカーバーが見やすくなる(パフォーマンス的にはよくないかも)。
<br><br>
* いわゆる「プログラミング用フォント」を導入していないので、'''ゼロ <q>0</q>''' と オー <q>O</q> や、イチ <q>1</q> と '''アイ <q>I</q>''' と エル <q>l</q> と バー <q>|</q> を区別できるよう、アイ と オー にマーカーを設定。<br> '''円マーク <q>¥</q>''' や '''波ダーシ <q></q>''' 他、見分けづらい文字も追加。
<u> ☑ 大文字小文字を区別  ☑ 正規表現 </u>
<u> ☑ 大文字小文字を区別  ☑ 正規表現 </u>
[OOII]|[¥∖╲〜☓×〇➀-➉]
: ※「半角数字」は、 [ オプション ] の [ 表示 ] 設定でカスタム文字色を設定。
: ※ 半角バーチカルバー <q>|</q> は、必要におうじて [ 編集モード ] の強調文字列に設定。
: ※ 小文字エル <q>l</q> は、強調なし。
<br>
* 特殊な空白文字用 <br>「MeiryoKe_Gothic」 フォントで通常の全角/半角空白と区別できない <q>特殊な空白文字</q> と、<q>ゼロ幅空白文字</q>。
<u> ☑ 大文字小文字を区別  ☑ 正規表現 </u>
特殊な空白文字 |[\x{00A0}\x{2000}-\x{200A}\x{2028}\x{1680}\x{180E}]


ゼロ幅空白文字 |\g<blank>\g<chara>|(?<chara>[\n\s\S])(?<blank>[\x{200B}-\x{200E}\x{2029}\x{202C}\x{202F}\x{205F}\x{2062}\x{2063}\x{FEFF}])
<code>特殊な空白文字 |[\x{00A0}\x{2000}-\x{200A}\x{2028}\x{1680}\x{180E}]</code>
 
<code>ゼロ幅空白文字 |\g<blank>\g<chara>|(?<chara>[\n\s\S])(?<blank>[\x{200B}-\x{200E}\x{2029}\x{202C}\x{202F}\x{205F}\x{2062}\x{2063}\x{FEFF}])</code>
: ※ 「MeiryoKe_Gothic」 フォントで文字化けして中黒 <q>・</q> で表示されるものや、ゼロ幅結合子は含めていない。
: ※ 「MeiryoKe_Gothic」 フォントで文字化けして中黒 <q>・</q> で表示されるものや、ゼロ幅結合子は含めていない。
<br>
 
* /JavaScript の正規表現リテラル用/
* /JavaScript の正規表現リテラル用/
<u> ☑ 大文字小文字を区別  ☑ 正規表現 </u>
<u> ☑ 大文字小文字を区別  ☑ 正規表現 </u>
正規表現リテラル |(?<=^|[{(\[= \t])\/(?![*+?|/)\]])[^\r\n\t]*\/[gmi]{0,3}(?=\s*(?:[.,:;})\]]|//|/\*|$))
 
<code>正規表現リテラル |(?<=^|[{(\[= \t])\/(?![*+?|/)\]])[^\r\n\t]*\/[gmi]{0,3}(?=\s*(?:[.,:;})\]]|//|/\*|$))</code>
: ※ ある程度の誤爆はやむなし。
: ※ ある程度の誤爆はやむなし。
<br><br>
<div id="END"> [[#TOP|>> 目次へ]] </div>
<!-- 【スクショ】
[https://i.imgur.com/tJsZBAF.png https://i.imgur.com/tJsZBAF.png 2.8.0]
[https://i.imgur.com/fuu5nFy.png https://i.imgur.com/fuu5nFy.png 2.7.8]
[https://i.imgur.com/VizaHVo.png https://i.imgur.com/VizaHVo.png 2.7.4]
-->
<!-- 【マーカー設定】
[OOII]|[¥∖╲〜☓×〇➀-➉]
// [OOII]|[\x{00A5}\x{2216}\x{2572}\x{301C}\x{2613}\x{00D7}\x{3007}\x{2780}-\x{2789}]
正規表現リテラル |(?<=^|[{(\[= \t])\/(?![*+?|/)\]])[^\r\n\t]*\/[gmi]{0,3}(?=\s*(?:[.,:;})\]]|//|/\*|$))
特殊な空白文字 |[\x{00A0}\x{2000}-\x{200A}\x{2028}\x{1680}\x{180E}]
ゼロ幅空白文字 |\g<blank>\g<chara>|(?<chara>[\n\s\S])(?<blank>[\x{200B}-\x{200E}\x{2029}\x{202C}\x{202F}\x{205F}\x{2062}\x{2063}\x{FEFF}])
\[行頭の角カッコ ]|^\[[^\]\r\n]+\]
var regBlankLine = /^[\s \u00A0\u1680\u180e\u2000-\u200A\u2028\u2029\u202F\u205F\uFEFF]+$/;
var regBlank = /[\u00A0\u1680\u180E\u2000-\u200E\u2028\u2029\u202F\u205F\u2062\u2063\uFEFF]/g
-->

2024年9月7日 (土) 12:56時点における最新版

マクロライブラリに投稿したマクロ[編集]

テキスト操作補助[編集]

ファイル操作補助[編集]

変換・ソート・整形[編集]

検索・置換[編集]

プログラミング補助[編集]

  • 行コメント (last_modified: 2020/06/28) ※コメントマーク付け外し ブックマークを保持
  • JS フォーマット (uploaded: 2020/05/03) ※JavaScript のソースコードの整形
    • EmEditor 用「Format HTMl, Javascript, Css format for Emeditor」マクロ [2] を Mery に移植するための改造用コード
    • テキスト整形」マクロ(masme 氏作成)への機能追加用コード

おもしろ[編集]

  • Yahoo!天気情報 ※ポップアップメニュー/ダイアログ (last_modified: 2020/05/12)

実験的マクロ・練習マクロなど[編集]

その他[編集]

開発者向け[編集]

外部サイトに投稿したマクロ[編集]

組み込み用コード・小関数[編集]

メインコードの途中に短い 関数 を置く場合は、最初の呼び出しコードより前に変数(関数式)として定義しておいてもよい。

{
  var hoge = "hogehoge";
  // function 宣言で定義された関数は、宣言された位置より前からでも呼び出せる
  document.selection.Text = HogeFuga( hoge );

  // 関数宣言は参照可能なスコープ内のどの位置に置いてもよい
  function HogeFuga( str ) {
    return str.replace( /hoge/ig, "fuga" );
  }
}

ならば、以下のような記述でも同じ意味 (ただし、関数式の場合は、最初に呼び出す文よりも前に定義しておくこと)。

// 関数式は最初に呼び出されるよりも前に定義すること
var HogeFuga = function( str ) {
  return str.replace( /hoge/ig, "fuga" );
};
var hoge = "hogehoge";

document.selection.Text = HogeFuga( hoge );

メタ記号をエスケープする[編集]

任意の文字列を正規表現変数 RegExp() におさめる前などにエスケープ(退避修飾)する。

  • 正規表現のメタ記号のみ をエスケープする方法。
※ ref. 『正規表現 - JavaScript | MDN
/**
 * 関数 RegQuote( str )
 * 
 * 正規表現のメタ記号をすべてエスケープ(退避修飾)する
 */

function RegQuote( str ) {
  return str.replace( /[.*+?^=!:${}()|[\]\/\\]/g, "\\$&" ); 
}
  • または、記述の簡単な方法(ただし、処理対象の文字列が長大 な場合や 日本語テキスト の場合には適さない)。
※ ref. 『JavaScript/正規表現 - Wikibooks
/**
 * 関数 Quote( str )
 * 
 * 半角アルファベットと半角数字以外の文字を
 * すべてエスケープして返す
 */

function Quote( str ) {
  return str.replace( /\W/g, "\\$&" );
}

// Wikibooks 版は関数を無駄にネストしている…
// function Quote( str ) {
//   return str.replace( /\W/g, function( $0 ) {
//     return "\\" + $0;
//   } );
// }
※ JavaScript において $& は "マッチした部分文字列全体" を意味する JavaScript ネイティブの 特殊変数
置換関数 function() の引数がひとつの場合、その引数は $& と同じ意味になるので、上の関数で $0 と記述していることに特別な意味はない(tmpstrchr など任意の文字列でもよい)。
※ 後述、関数の「呼び出しコスト」 の項に書いているように、上出のふたつの Quote( str ) 関数の処理速度にはちがいが生じる。

数値を3ケタ区切り(カンマ区切り)にする[編集]

/**
 * 関数 SeparateNum( num )
 * 
 * 数値を3ケタごとにカンマ区切りした文字列にして返す
 * 引数(推奨):整数値
 * ※ 小数点以下が4ケタ以上の場合、小数点以下もケタ区切りされてしまう
 */

function SeparateNum( num ) {
  return num.toString().replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
}

小数、または半角数字を含む文字列の場合は

/**
 * 関数 SeparateNum2( num )
 * 
 * 数値を3ケタごとにカンマ区切りした文字列にして返す
 * 引数:任意の数値(を含む文字列)
 * ※ 小数点以下はケタ区切りしない
 */

function SeparateNum2( num ) {
  var num = ( num === 0 || ! num ) ? "0" : num;
  var a = num.toString().split( /\b/ );
  for ( var i = 0, len = a.length; i < len; i ++ ) {
    if ( a[i] == "." ) { i ++; continue; }
    a[i] = a[i].replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
  }
  return a.join( "" );
}

数値を小数点以下3ケタの固定長にする[編集]

/**
 * 関数 NumFix( num )
 * 
 * 数値を小数点以下3ケタの固定長小数(文字列)にして返す
 * 引数(推奨):任意の数値(または数字のみの文字列)
 */

function NumFix( num ) {
  if ( typeof num == "number" ) {
    return num.toFixed( 3 );
  }
  else if ( /^-?\d+(?:\.\d+)?$/.test( num.toString() ) ) {
    return Number( num ).toFixed( 3 );
  }
  else {
    return num;
  }
}

// 対象が数値( Number 型)であれば toFixed() だけでよい
// num = num.toFixed( 3 );

数値をケタ埋め(ゼロ埋め)する[編集]

※ 引数の型に応じた関数を使用する。

/**
 * 関数 Pad( num )
 * 
 * 半角1ケタの数値を0埋めして2ケタの文字列で返す
 * ※ 引数は「正の整数値」のみ
 */

function Pad( num ) {
  return num < 10 ? "0" + num : num;
}
/**
 * 関数 Pad2( str )
 * 
 * 文字列中に含まれる半角1ケタの数値を0埋めして2ケタにした文字列で返す
 * ※ 引数は「文字列値」のみ
 */

function Pad2( str ) {
  return str.replace( /[0-9]+/g , function( num ) {
    return num.length < 2 ? "0" + num : num
  } );
}
/**
 * 関数 NumPad2( val )
 * 
 * 半角1ケタの数字を0埋めして2ケタにした文字列で返す
 */

function NumPad2( val ) {
  return val.toString().replace( /[0-9]+/g, function( num ) {
    return num.length < 2 ? "0" + num : num;
  } );
}

任意の文字列のくりかえしで埋める[編集]

※ Windows XP 用

/**
 * 関数 Repeat( str, count )
 * 
 * String.prototype.repeat( count ) の代用
 */

function Repeat( str, count ) {
  var ret = "";
  for ( var i = 0; i < count; i ++ ) {
    ret += str;
  }
  return ret;
}

ascii 文字に対応する全角英数記号を半角変換 / 数値専用の入力ダイアログ[編集]

※ IME: ON の状態で入力された「全角数字」も許容、「全角/半角の数字」以外の文字列は無視する入力ダイアログのサンプルコード

/**
 * 関数 ToHalfWidth( str )
 * 
 *  ascii 文字に対応する全角英数記号の文字列を半角変換した ascii 文字列で返す
 * ※ カタカナや ascii 文字に対応しない文字列部分はそのまま残す
 * ※ 引数は「文字列値」のみ
 */
function ToHalfWidth( str ) {
  return str.replace( /[!-~]/g, function( tmp ) {
      return String.fromCharCode( tmp.charCodeAt(0) - 0xFEE0 )
} ) };

/**
 * Number( ToHalfWidth( Prompt( message,"" ) ).replace( /\D/g, "" ) )
 * 
 * 正の整数値専用の入力ダイアログ
 * ※ ダイアログに入力された "全角/半角の数字" 部分のみを "正の整数値" として取得する
 *    i.e. 入力値が「1あ2」「-12」「1.2」「012A」ならば 12 とみなす
 */
var p = Number(
  ToHalfWidth( Prompt( "数値を入力", "" ) )
  .replace( /\D/g, "" )		// 置換処理で半角数字以外を削除
);

// e.g. 入力された値がゼロや無効な文字列のみなら「キャンセル」
if ( ! p ) { Status = "キャンセル"; }
else       { Alert( p ); }

ストップウォッチ・タイマー[編集]

// 計測開始		※ ソースコードの先頭付近におくこと
var start = new Date();

// 任意のコードを実行
{ ; }

// ステータスバーに処理時間を表示
Status = ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒";

Mery のバージョン情報[編集]

/**
 * Mery のバージョン情報
 */
var meryVersion = /([^\\]+$)/.exec( editor.FullName )[1] + " "
                + editor.Version;
Status = meryVersion;

JavaScript (JScript) エンジンのバージョン情報[編集]

※ ref. 『ScriptEngine 関数 (JScript) | Microsoft Docs

/**
 * JavaScript (JScript) エンジンのバージョン情報
 */
var engine = ScriptEngine() + " ";
           + ScriptEngineMajorVersion() + ".";
           + ScriptEngineMinorVersion() + ".";
           + ScriptEngineBuildVersion();
Status = engine;

リンク集[編集]

MeryWikiHaijin Boys Online

外部サイト

Tips[編集]

拙作マクロはポップアップメニューを利用するものが多いので、Tips はその方面の内容に偏ってしまいますが、以下、個人的に注意していることや気付いたことなど。

Document と Editor.ActiveDocument[編集]

マクロをツールバーアイコン化する意味(?)

大前提として マクロライブラリマクロ覚え書き(開発者向け) で説明されているような違いがあるが、 Editor.ActiveDocument は、マクロ開始時点でタブにフォーカスがあろうとなかろうと window.Document オブジェクトを取得することができる、という違いもある。

  • 通常、アウトプットバーやアウトラインペイン、検索/置換ダイアログにフォーカスがあると、ショートカットキーからはマクロを起動することはできないし、起動してもマクロ開始時点での Document オブジェクトが undefined になるので Document.Selection のメソッドなどが使用できなくなる。
  • それにたいして、Document のかわりに Editor.ActiveDocument で記述したマクロであれば、エディタ領域にフォーカスがない場合でもツールバーアイコンやマクロメニューからマクロを起動することができるので、マウス派・ツールバーアイコン派にはありがたい抜け道である。
※ ただし、アクティブなタブ以外を操作・編集するマクロにおいては Editor.Documents.Item(n) などのような形式での記述が必要。

マウス派・ツールバーアイコン派の sukemaru においては、マクロをツールバー/マクロバーから使用するために アイコン を作ったり、マクロバーに1つでも多くのアイコンを詰め込むために 試行錯誤 したり…。

※ マクロ/プラグイン/外部ツールの登録数が多かったり #icon="hoge.ico" でアイコン化しているマクロが多いせいか、Mery の起動がもたつくのが悩ましい… (自作の編集モード が重いのも影響しているかも)

イベントマクロ[編集]

イベントマクロ を実行できる "イベント" の種類
赤字 は遅延時間を設定できるイベント
フォーカスを受け取った時 エディタのウインドウがアクティブになったとき。
・「オプション」 などモーダルなダイアログからの復帰時には発動しない
Editor.ActiveDocument == Document
フォーカスを失った時 エディタのウインドウがアクティブでなくなったとき。
・「検索」 「置換」 ダイアログを開いたときにも発動する…
Editor.ActiveDocument != Document
ファイルを開いた時 複数ファイルをまとめて開いたときは、すべて開いたあとに1回だけ。
・複数ファイルをまとめて開いたときには、さいごのタブにしか作用しない
ファイルを保存した時 複数ファイルをまとめて保存したときは、すべて保存したあとに1回だけ。
更新状態が変更された時 「保存済み」 状態から 「未保存*」 状態になったときに発動した。
カーソルが移動した時 キャレット位置が動いたとき。
遅延 を大きく設定しないと、すごくジャマ
スクロールした時 エディタウインドウをスクロールしたとき。
・マウスホイール操作やスクロールバーの操作、
 PgUp / PgDn / Home / End キーなどでスクロールさせたとき
・文字入力中や、矢印キーなどでのキャレット移動にともなうスクロールでは発動しない
選択範囲が変更された時 範囲選択したときと、選択範囲を解除したとき。
遅延 を大きく設定しないと、ドラッグ操作や Shift+矢印キーで範囲選択するときにジャマ
テキストが変更された時 入力・削除・置換などの編集操作をしたとき。
遅延 を大きく設定しないと、すごくジャマ
文字が挿入された時 文字数が増えたとき?
・選択範囲文字列の [ Ctrl+ドラッグ ] による複製や、
 クリップボードからのペースト、
 マクロの Document.Write( "hoge" )
 Document.Selection.Text = "hoge" では発動しないようだった
遅延 を大きく設定しないと、すごくジャマ
編集モードが変更された時 編集モードを変更したとき。
・マクロで編集モードを変更したときも
アクティブな文書が変更された時 別のタブをアクティブにした後に発動。
・タブを閉じた後や、新規タブを開いたときにも
文書を閉じた時 複数のタブをまとめて閉じたときは、すべて閉じたあとに1回だけ。
・最後のタブが閉じてエディタウインドウが終了する場合は発動しない
タブを移動した時 タブをドラッグ&ドロップ操作で動かしたとき。
・左側のタブを閉じて右側のタブが動いた場合には発動しない
アイドル状態になった時 (不明)
ファイルを保存する前 ファイルを保存する前。
※ 複数のイベントマクロで 各赤字イベント の遅延時間の設定は共有されるので、同じイベントに複数のマクロを割りあてている場合にマクロの発動の順序を恣意的に指定することはできない。
→ マクロのコードを統合するか、イベントを設定するマクロをひとつだけにして include で別のマクロを発動させることができる。
※ イベントマクロ であっても、ショートカットキーなどから任意のタイミングで強制的に実行することもできる。
※ イベントマクロでない「マクロA」のコードでファイルを 開く または 閉じる をおこない、それ以降にも「マクロA」のコードが続いている場合は、ファイルを開いた時/閉じた時の「イベントマクロB」は発動しないことがある。
  • sukemaru の Mery では、「バイト数」マクロと「検索ヒット数表示(選択文字列)」マクロの機能を統合した「文字数・行数・バイト数・ヒット件数」マクロに「ファイルを開いた時」「選択範囲が変更された時」「テキストが変更された時」「文字が挿入された時」「アクティブな文書が変更された時」イベントを設定している(赤字 の各イベントには遅延時間を 1 秒に設定。 ロースペックな PC ゆえ、一定以上の長さのファイル/タブにおいては機能を制限してある)。
    • 遅延時間が短すぎると、"文字列や選択範囲を変更するような他のマクロの実行後に、そのマクロからのステータスメッセージが読めなくなるから"、という意味もある。
  • また、「編集モードの自動選択 (include版)」マクロを「ファイルを開いた時」「文書を閉じた時」イベントに、補助マクロ を「ファイルを保存した時」イベントに設定して、それなりに按配よく運用できている。
    • includeライブラリ を利用して、複数のファイルを開いたときにもそれぞれのタブにたいして編集モードの変更や書き換え禁止を適用できるようにしてある)

ポップアップメニュー[編集]

sukemaru の環境では、メニューに表示するアイテムが 5000 件とか 10000 件とかを超えるとポップアップメニューが表示されず(エラーメッセージも表示されず)にマクロが終了してしまうことがある…。

検索ジャンプ」マクロの include 版で発生するのだが、ポップアップメニューを表示する直前にステータスバーに表示すべき情報を ClipboardData.SetData( Status ); でコピーしておくと、

ヒット数: 21,525 件 ( 4 件目 ) ・ 21,525 行 ( 4 行目 ) / 全体の行数: 61,001 行 [ 12. 906 秒 ]

のようにデータが残ったので、前処理段階でコケたのではなくポップアップメニューの描画のさいにコケていたようだ。

また、11 万行の文書から空行を検索したとき、ステータスバーに以下のメッセージを表示して

一致: 27,814 行 / 空白行数: 27,849 行 / 全体の行数: 111,186 行 [ 6. 485 秒 ]

ポップアップメニューも表示されたが、実際に表示されていたアイテム数は 6000 件台で、20000 件以上のアイテムは表示されずにスポイルされてしまっていたということもあった。

以下の単純なコードでアイテム 10000 件のポップアップメニューを表示させようとしても、4000 件ぐらい(4000 前後で不定)までしか表示されない…。

var m = CreatePopupMenu();
for ( var i = 1; i <= 10000; i ++ ) {
  m.Add( "" + i, i );
}
var r = m.Track( mePosMouse );

環境依存の不具合かもしれないが、はて…?

オプションフラグ[編集]

PopupMenu.Add() メソッド の第三引数 Flags : int を数値化すると

meMenuChecked	= 1
meMenuGrayed	= 2
meMenuChecked + meMenuGrayed = 3
meMenuSeparator	= 4

となるので、真偽値が true=1false=0 で評価されることを利用して、真偽値を返す変数や条件式を代入することができる(ただし Number 型に変換する必要がある ← 算術演算子 + をつけるなど)。

var menu = CreatePopupMenu();
var hoge = true;
var fuga = false;
var piyo = true;

menu.Add( "Hoge", 1, + hoge );		// "+" を付けて数値化すると meMenuChecked
menu.Add( "Fuga", 2, !fuga * 2 );	// (!fuga = 1) *2 なので meMenuGrayed
if ( piyo ) {
  menu.Add( "Piyo", 3 );			// piyo が true のときだけ表示
}
var num = menu.Track( mePosMouse );
※ オプションフラグ meMenuGrayed を使用して条件付きで特定の項目をグレーアウトするだけでなく、menu.Add( ... ); の行を if() 文 で囲むなどすれば、状況に応じたメニュー項目だけを表示させることもできる。

アクセラレータ[編集]

ポップアップメニューのラベルの文字列に「半角アンパサンド記号 &半角英数字 (またはアスキー記号)」を付記することで、アクセラレータ(アクセスキー)を設定することができる。

ラベルの先頭に連番数字などがある場合は、数字のまえにアンパサンド記号を付加して数字をアクセラレータにすることもできる。

そのさい、Shift キー付きでの入力が必要な記号は Shift キーなしで入力可能なキーのラベルと同一視される (e.g. 「&#」で # 記号をアクセラレータに指定した場合、JIS 配列のキーボードでは 3 キーがアクセラレータになる)。

  • & 記号でアクセラレータ化する文字の位置は限定されないが、最初の & 記号のうしろの文字がアクセラレータになる( … とおもわれる ← ポップアップメニュー内で「下線つきで表示される文字」と一致しないことがある)。
  • 全角文字はアクセラレータにできない。
  • ラベル文字列に含まれる & 記号はすべてエスケープされてしまい、ポップアップメニューには表示されなくなるので、ラベルに & 記号を表示させたいときは、&& のように二重に記述する必要がある。
    • → 不特定の文字列 String (文書内から抽出したテキストなど)をラベルにする場合は、あらかじめ String.replace( /&/g, "&&" ) と記述するとよい。
&& の記述で表示される & 記号は、アクセラレータにならない。
  • 同じキーが重複してアクセラレータに指定されていると、そのキーを押した場合、アイテム間をトグル移動する(その場合は Enter キーで決定する)。
    • → アイテム数が多くなるメニューの場合、menu.Add( "キャンセル & ", 0 ); という行を 10 件とか 20 件ごとに挿入すると、スペースキーでポップアップメニュー内をスクロールさせることができる。
※「& 」(半角アンパサンド+半角空白) で半角スペースをアクセラレータに指定したアイテムは、Space キーがアクセスキーになる。
/* アクセラレータを付加する */

var menu = CreatePopupMenu();
var piyo = "LOVE & PEACE & ...";

menu.Add( "アイテム1(&1)", 1 );		// [1] キーがアクセラレータ
menu.Add( "アイテム&2", 2 );			// [2] キーがアクセラレータ
menu.Add( "0&3 アイテム3", 3 );		// [3] キーがアクセラレータ
menu.Add( "&Hello &World &4", 4 );	// [H] キーがアクセラレータ
menu.Add( piyo.replace( /&/g, "&&" ) + "(&5)", 5 );	// [5] キーがアクセラレータ
menu.Add( piyo + "(&6)", 6 );		// スペースキーがアクセラレータ
menu.Add( "※※※※", 0, meMenuSeparator );	// meMenuSeparator があると第一引数の文字列は無視される
menu.Add( "キャンセル & ", 0 );		// スペースキーがアクセラレータ

// 5つめのアイテムは "LOVE & PEACE & ..." と表示されるが
// 6つめのアイテムは "LOVE  PEACE   ..." と表示される 

// ※ 6つめのアイテムと最後のアイテムでアクセラレータが重複している

var ret = menu.Track( 0 );
/* 10 行ごとに「キャンセル」項目を挿入し、スペースキーでスクロール可能にする */

var arr = document.Text.split( "\n" );
var menu = CreatePopupMenu();

for ( var i = 0; i < arr.length; i ++ ) {
  if ( i > 0 && i % 10 == 0 ) {
    menu.Add( "", 0, meMenuSeparator );
    menu.Add( "キャンセル & ", 0 );
    menu.Add( "", 0, meMenuSeparator );
  }
  menu.Add( arr[i].slice( 0, 30 ).replace( /&/g, "&&" ), i + 1 );
}

var y = menu.Track( 0 );
if ( y ) {
  document.selection.SetActivePoint( mePosLogical, 1, y );
}

ラベルの整形[編集]

  • 基本的にポップアップメニュー(警告・確認ダイアログなどもだが)は UI フォントで表示されるので、文字列が英数字の羅列の場合には読みづらい ( …と個人的に感じている @WinXP)。
文書内の文字列など不特定の文字列をラベル化する「検索ジャンプ」や「ブックマークジャンプ」、「「クリップボード履歴」メニューのマクロ化」マクロでは、読みづらい半角アルファベットや記号を全角化させるなどしている。
/**
 * ポップアップメニューに表示するラベルを整形する
 * 
 * ※ 不要な置換については .replace( ... ) の行を 削除/コメントアウト してよい
 * 
 * ・行頭空白を除去
 * ・空白文字を圧縮:				→「›」(U+203A) に置換
 * ・文字数を切り詰め( String.slice メソッド )
 * ・改行記号を可視化:			→「↲」(U+21B2) または「⏎」(U+23CE) に置換
 * ・削られてしまう「&」を補完
 * ・「¥」(U+005C) を「∖」(U+2216) に置換
 * ・特殊な空白文字を豆腐に置換:	→「⊠」(U+22A0) または「▯」(U+25AF) 
 * ・判読しづらい ascii 記号  !"%'(),.:;@[]`{|}  を全角に置換
 * ・「a-z」を全角に置換
 */

var y = document.selection.GetActivePointY( mePosLogical )	// 行番号
var str = document.GetLine( y, 0 );		// 行の文字列
var menuWidth = 55;						// 切り捨ての閾値
var reg = /[\u00A0\u1680\u180e\u2000-\u200A\u2028\u2029\u202F\u205F\uFEFF]/g;

var menuKey = str.replace( /^[\t  ]+/, "" )
                 .replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " )
                 .slice( 0, menuWidth + 1 )
                 .replace( /\r?\n/g, " ↲ " )
                 .replace( /[&]/g, "&&" )
                 .replace( /[\\]/g, "∖" )
                 .replace( reg, "▯" )
                 .replace( /[!"%'(),.:;@\[\]`a-z{|}]/g,
                   function( tmp ) {
                     return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
                   } );

// 文字数を切り詰めた場合は「 ...」を付加
menuKey += ( str.length > menuWidth ) ? " ..." : "";

// 文字列の先頭に行番号(連番)を付加する

// パターン➀: アクセラレータつきの番号(左端揃え)を付加
var num = "&" + y;
menuKey = num + ": " + menuKey;

// パターン➁: 番号(左端揃え)の 末尾1桁 をアクセラレータにするなら
var num = String( y ).replace( /\d$/, "&$&" );
menuKey = num + ": " + menuKey;

// パターン➂: 連番が多いときは「空白文字でケタ埋め (右端揃え)」するとよい
// 例: EN SPACE「 」(U+2002) でケタ埋めして、末尾1桁 をアクセラレータにする
var numWidth = String( d.GetLines( 0 ) ).length;
var num = ( "      " + y ).slice( - numWidth ).replace( /\d$/, "&$&" );
menuKey = num + ": " + menuKey;
※ このコードでは色々と unicode 文字を使用しているので、マクロの JS ファイルは UTF-8 などの形式で保存しなければならない。
  • また、「マクロライブラリに投稿したマクロ」の節の画像リンク(サムネイル)のように、タブインデントや連番のケタ埋め、サブメニューの活用などの工夫で、ポップアップメニューの体裁はある程度自分好みにカスタマイズできる。

ステータスバーの表示[編集]

ポップアップメニューの表示と同時ににステータスバーに任意の文字列を表示する場合は、 PopupMenu.Track() の行の直前に Status = "hoge"; を記述する。

PopupMenu.Track() が発動した時点でエディタウインドウ本体は停止するので、直後に Status = "hoge"; を記述しても、ポップアップメニューの項目を選択するかメニューをキャンセルするまで表示されない。

// e.g. ポップアップメニュー表示までのマクロの処理時間をステータス表示させる

// 計測開始		※ ソースコードの先頭付近におくこと
var start = new Date();

// 文書の各論理行を配列におさめ、ポップアップメニュー項目に
var ay = document.selection.GetActivePointY( mePosLogical );
var lineArray = document.Text.split( "\n" );
var menu = CreatePopupMenu();
for ( var i = 0, len = lineArray.length, y, flag; i < len; i ++ ) {
  y = i + 1;
  flag = ( y == ay ) ? meMenuChecked : 0;
  menu.Add( y + ":  " + lineArray[i].slice( 0, 50 ), y, flag );
}

// ステータスバーに処理時間を表示
Status = ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒";

// ポップアップメニューを表示
var yy = menu.Track( mePosMouse );

// 選択した行に移動する
if ( yy ) {
  document.selection.SetActivePoint( mePosLogical, 1, yy, false );
}
※ ポップアップメニューにかぎらず、警告 (Alert)確認 (Confirm)入力 (Prompt) ダイアログなどモーダルなポップアップウインドウを表示させる場合も、同様に Status = "hoge"; を先に記述する必要がある。
※ Mery メインウインドウのメニューバー項目のような、マウスホバーで動的にステータス表示を変更させる制御はできない。

配列からポップアップメニューを生成[編集]

for 文 などの ループ処理 によって配列からポップアップメニューのアイテムを生成する場合に、PopupMenu.Add() メソッド の第二引数 id (※通常は 1 ~ )と配列のアイテムのインデックス [ i ] の値(※通常は 0 ~ )を一致させたいときは、配列の先頭にダミーまたは空の要素を置いておき、ループ処理の開始インデックスを 1 にする。

var a = new Array( "" );				// 先頭に空のダミー要素を入れておく

a.push( "あああ" );
a.push( "いいい" );
a.push( "ううう" );
// a = [ "", "あああ", "いいい", "ううう" ] となる

var menuA = CreatePopupMenu();
for ( var i = 1; i < a.length; i ++ ) {	// 開始値を var i = 1 にすると
  menuA.Add( a[i], i );					// Id を ( i + 1 ) にする必要がない
}
var numA = menuA.Track( mePosMouse );

// c.f. 空要素なしの配列 [ "あああ", "いいい", "ううう" ] をループ処理する場合
var b = [ "あああ", "いいい", "ううう" ];
var menuB = CreatePopupMenu();
for ( var i = 0; i < b.length; i ++ ) {
  menuB.Add( b[i], i + 1 );				// Id を 1 ~ にするには ( i + 1 )
}
var numB = menuB.Track( mePosMouse );

サブメニュー[編集]

サブメニューを組みこむ場合、通常はそれぞれの PopupMenu オブジェクトをあらかじめ宣言しておくものだが、PopupMenu.AddPopup() メソッド 内の第二引数で定義することもできる。

PopupMenu.Add() メソッド が大量に並んでいる項目群の一部をサブメニュー化して整理したくなったときなどに、サブメニューオブジェクトの宣言行を用意しなくて済むので便利である。

サブメニューを多重に含むコードの場合、字下げ(インデント)を活用することで、メニューの階層構造を把握しやすくできる。

var mainMenu = CreatePopupMenu();
mainMenu.Add( "アイテム1", 1 );
mainMenu.AddPopup( "サブメニュー1", subMenu1 = CreatePopupMenu() );
  subMenu1.Add( "アイテム2", 2 );
  subMenu1.AddPopup( "サブメニュー2", subMenu2 = CreatePopupMenu() );
    subMenu2.Add( "アイテム3", 3 );

var r = mainMenu.Track( 0 );
Alert( r > 0 ? mainMenu.GetText( r ) : "キャンセル" );
  • 配列やオブジェクトからポップアップメニューの生成をするときにサブメニューを利用する場合、あらかじめサブメニューのラベルや各要素の振り分け方が決まっていれば難しいことはないが、要素が不定数の配列やオブジェクトを複数のサブメニューに振り分けるのは簡単ではない…。
→ 組み込み関数「ポップアップメニューを手軽に扱う」や「階層化マクロメニュー」マクロなどのソースコードを参考にして自力でコードを組むか、組み込み関数「ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する」で一定数ごとにサブメニュー項目を自動生成して要素を放り込むしかない。
※ 自動分割サブメニューのページに「サンプルコード2 (簡易版)」を追加した。
サンプルコード1」の組み込み関数ではサブメニューオブジェクト専用の配列 smArray を用意して smArray.push( CreatePopupMenu() ); → menu.AddPopup( label, smArray[ smId ] ); としているが、サンプルコード2のようにループ処理内で subMenu = CreatePopupMenu(); を使いまわしするだけでも新規のサブメニューアイテムを生成できるようだ。
サブメニュー内のすべてのアイテムが無効(グレーアウト)になる条件でも、サブメニュー見出しを無効化することはできないので、サブメニュー見出しが表示されなくなるように(またはグレーアウトされるように) PopupMenu.AddPopup() 周りを if() 文 で囲うしかない(※ メニューの階層構造が複雑な場合に、ソースコードが見づらくなってしまうが…)。
// e.g. 編集モードが Text ならサブメニューを表示する
// ※ Text 以外ならグレーアウトさせた "サブメニュー" アイテムを表示

var menu1 = CreatePopupMenu();
var menu2 = CreatePopupMenu();

if ( document.Mode == "Text" ) {
  menu1.AddPopup( "サブメニュー", menu2 );
    menu2.Add( "アイテム2", 2 );
} else {
  menu1.Add( "サブメニュー", 0, meMenuGrayed );
}
menu1.Add( "アイテム1", 1 );

var r = menu1.Track( mePosMouse );
また、上出の「自動分割サブメニュー」の組み込み関数を制作するさい、チェックつきアイテムを含むサブメニュー見出しにもチェックを付けられるようにしたかったが、これも無理だった。
→ サブメニューオブジェクトを AddPopup() する前に孫アイテムを Add() しておき、チェックつきアイテムを含むかどうかの条件文でサブメニューオブジェクトのラベルを生成(サブメニューラベルの先頭に "*\t" や "" などを付加)してから AddPopup() することはできるが、 meMenuChecked とおなじチェックマークをつけられるわけではないので、コードが煩雑になるわりにあまり報われない努力となる…。

マクロの動作設定を変更可能にする[編集]

拙作マクロは、ポップアップメニューを使うものにかぎらず動作設定用の項目が多い。

ポップアップメニューマクロでないものは、通常、頻繁に動作設定を弄る必要はないが、sukemaru 好みの動作方式は一般的嗜好と合致しないであろうことから公開用のマクロにするにあたってカスタマイズ可能な「設定項目 (変数)」にして調整しなおすことが多い…。

ポップアップメニューマクロであれば、メニュー項目から動作設定をカスタマイズできるようにコーディングすることができる。

  • まず、masme 氏の「行並べ替え」や「連番を挿入」マクロのように、do ... while() 文 によるループを利用して、動作設定の既定値を何度も書き換えながらポップアップメニューを再描画する方法がある。
動作設定の変更内容はマクロの完了時に破棄されてしまうので、 同じマクロを連続して利用することが多いならば、マクロメニューの 編集 コマンドからソースコードを開いて、初期設定項目(変数)の既定値を書き換えておくとよい。
これらにおいては、includeライブラリ の IO クラス(IO.js)の関数メソッド IO.Serialize() / IO.Deserialize() を利用して、ポップアップメニュー内の「設定変更」サブメニューから変更した 設定値を外部ファイル(JSON ファイル)に保持 できるようにしている。
カスタマイズしながら実行するのも、カスタマイズした動作設定を維持したままでままで再実行するのも容易にはなったが、コードが煩雑になって他のマクロに流用しづらくなってしまっている…。
※ 非 include 版では、「設定変更」サブメニューや masme 氏のマクロのような処理コードは入れず、動作設定の変更方法はソースコードの変数の値の書き換えのみとしている。

GetKeyState.exe の活用[編集]

pizz 氏作成の「GetKeyState.exe(キー状態取得実行ファイル)」を使うと、マクロ実行(開始)時の修飾キーの押し下げ状態でポップアップメニューに表示する項目を変化させたり、メニュー内のアイテムを選択(クリック)するときの修飾キーの押し下げ状態で実行するコマンドを変化させることができる。

マクロ開始時に仕込むとショートカットキーの割りあて方が制限されたり、メニュー表示までにタイムラグが生じてしまうこともあるが、アイテム選択後のコマンド実行時に仕込めばあまり問題にならない。

※ ただし、Mery のポップアップメニューは Alt キーでキャンセルされてしまうので、ポップアップメニュー内のコマンド実行用に仕込めるのは CtrlShift キーにかぎられる。

ref. GetKeyState.exe の実装例: サンプルコード3

配列[編集]

var arr1 = [];
arr1[arr1.length] = "hoge";
arr1[arr1.length] = "fuga";
arr1[arr1.length] = "piyo";
... ;

個人的な所感であるが、配列の要素を羅列して定義するさいに、上のような書き方は好きではない。以下のような書き方のほうが、スッキリしていてよい。

var arr2 = [];
arr2.push( "Hoge" );
arr2.push( "Fuga" );
arr2.push( "Piyo" );
... ;
var arr3 = [
  "HogeHoge",
  "FugaFuga",
  "PiyoPiyo",
  ...
];
// ※ カンマの位置は、前でも後ろでも

複数行の論理行を範囲選択(末尾改行を含まない)[編集]

文字列操作のマクロでしばしば必要になる処理。

※ 行番号のクリックやドラッグによる行単位の範囲選択をしたときや Selection.SelectLine() のあとなど、選択範囲末尾の改行(次行の先頭)を除外するときに必要。

※ 以下のふたつのコードは、左下(行頭位置)から右上に矩形選択した状態から実行したときの結果が異なる。

var s = document.selection;
// もとの選択範囲の座標を取得
var ty = s.GetTopPointY( mePosLogical );
var by = s.GetBottomPointY( mePosLogical );
var bx = s.GetBottomPointX( mePosLogical );
// 選択範囲の末尾が行頭 x = 1 にあるときの調整
if ( bx == 1 && ty != by ) { by -= 1; }
// 論理行全体を範囲選択(さいごの末尾改行 \n をふくめない)
s.SetActivePoint( mePosLogical, 1, by );
s.EndOfLine( false, mePosLogical );
s.SetAnchorPoint( mePosLogical, 1, ty );
// または masme 氏作成の「コメントマーク付け外し」マクロより
// ※ 左下(行頭位置)から右上に矩形選択した場合も考慮したコード
var s = document.selection;
var ty = s.GetTopPointY( mePosLogical );
var by = s.GetBottomPointY( mePosLogical );
var bx = s.GetBottomPointX( mePosLogical );
var br = ( s.Text.match( /\n/g ) || [] ).length;
if ( bx === 1 && by - ty === br && br ) { by --; }
s.SetActivePoint( mePosLogical, 1, by );
s.EndOfLine( false, mePosLogical );
s.SetAnchorPoint( mePosLogical, 1, ty );
ref. Mery 公式フォーラム 『マクロについてアドバイスお願いします

選択範囲の 先頭位置/末尾位置[編集]

選択範囲の 開始(キャレットなし)/終了(キャレットあり) の位置は Selection.GetAnchorPos()Selection.GetActivePos() とで取得できるが、先頭/末尾 の位置はそれらをもとにして前後関係を割りだす必要がある。

GetTopPos()GetBottomPos() というメソッドはない。

var ancPos, actPos, topPos, endPos;

ancPos = document.selection.GetAnchorPos();	// 選択開始位置
actPos = document.selection.GetActivePos();	// 選択終了位置(キャレット位置)

topPos = Math.min( ancPos, actPos );		// 選択範囲の先頭位置(左・上)
endPos = Math.max( ancPos, actPos );		// 選択範囲の末尾位置(右・下)

// topPos と endPos の取得は以下のような記述方法でも可
topPos = ( ancPos < actPos ) ? ancPos : actPos;
endPos = ( ancPos < actPos ) ? actPos : ancPos;

変換・挿入した文字列を範囲選択するとき[編集]

var str = "hoge";
document.Write( str );	// または document.selection.text = str;

のあとで文字列 hoge を範囲選択したい場合は、document.selection.CharLeft( str.length, true ); ではなく

// キャレットは選択範囲の末尾位置
document.selection.SetAnchorPos( document.selection.GetActivePos() - str.length );

// または(キャレットは選択範囲の先頭位置)
document.selectionSetActivePos( document.selection.GetActivePos() - str.length, true );

と記述すること。

Selection.CharLeft( str.length, true ) の場合、文字列 str が「折り返し」にかかってしまったときに想定どおりの選択範囲にならない。

ref. Mery 公式フォーラム 『"折り返し表示" での CharRight( document.selection.Text.length - 1 ) について

Mery のマクロの定数[編集]

リテラル形式の定数を数値化した値

Alert( meFindNext );

のような1行マクロで調べることができる。

Document.Selection オブジェクトの各種メソッドについて[編集]

ChangeCase() メソッド[編集]

Selection.ChangeCase() メソッド

  • 全角/半角の英字(いわゆるラテンアルファベット A-Z, a-z, A-Z, a-z)以外の欧文アルファベット(ギリシア文字、キリル文字など)やローマ数字の「大文字/小文字/頭文字」変換にも対応。
  • 選択範囲内のテキストが「漢字と平仮名のみ」のばあいなど、「大文字/小文字/頭文字」変換されなかったさいにも Undo 履歴や 変更行の強調表示 が残る。
ref. 文字列操作が空振りしたときは undo 履歴に残さない
ref. 拙作「大文字/小文字/頭文字 トグル変換」マクロ

ChangeWidth() メソッド[編集]

Selection.ChangeWidth() メソッド

  • 選択範囲内のテキストが「漢字と平仮名のみ」のばあいなど、「全角/半角」変換されなかったさいにも Undo 履歴や 変更行の強調表示 が残る。
ref. 文字列操作が空振りしたときは undo 履歴に残さない
ref. 拙作「全角/半角 トグル変換」マクロ

Collapse() メソッド[編集]

Selection.Collapse() メソッド で引数 meCollapseEnd を指定した場合は

document.selection.SetActivePos( Selection.GetActivePos() )

meCollapseStart を指定した場合は

document.selection.SetActivePos( Selection.SetAnchorPos() )

  • 引数を省略した場合は meCollapseStart として動作する。
  • meCollapseStart / meCollapseEnd はそれぞれ「選択開始位置」と「選択終了位置 (キャレット位置)」を指し、「選択範囲の 先頭/末尾」ではない。
  • Selection.SelectLine()Selection.SelectWord() メソッドなどでの範囲選択では「キャレット位置=選択範囲の末尾」となり、Selection.Find()Selection.FindRepeat() メソッドでの範囲選択では「キャレット位置=選択範囲の先頭」なので、つづけて Collapse() メソッドを使用するときは注意が必要 (…というほどのことでもないか?)。

DuplicateLine() メソッド[編集]

Selection.DuplicateLine() メソッド

  • 行末の改行が選択範囲に含まれているときや複数行選択の状態から実行したとき、キャレットのある論理行 ActivePointY が複製対象になる(複数行不可)。
  • 行を複製したあとのキャレットの位置(桁)が、メソッド実行前の ActivePointX ではなく AnchorPointX になる。

⇒ 複数行選択状態や、行番号クリックでの行選択状態から実行した後のキャレット位置が不自然なかんじになる。

じっさいのマクロのコーディングでは行全体の文字列を

// 1行選択
document.selection.StartOfLine( mePosLogical );
document.selection.EndOfLine( mePosLogical, true );

または 複数行の論理行を範囲選択(末尾改行を含まない) のようなコードで範囲選択状態にしてから「行を複製」することが多いので、document.selection.Text = document.selection.Text + "\n" + document.selection.Text; とすれば「複製」後のキャレット位置が曖昧になることはない。

ref. 拙作「行を複製 (複数行可)」マクロ

Indent/Unindent() メソッド[編集]

Selection.Indent() メソッドSelection.Unindent() メソッド

  • 「選択範囲のテキスト」ではなく、「選択範囲をふくむ論理行全体」が操作対象。
  • 選択範囲が表示行での1行全体に達していないと空振りするので、事前に行全体を範囲選択する(e.g. document.selection.SelectLine(); // または SelectLine( true ); )や 複数行の論理行を範囲選択(末尾改行を含まない) のようなコードが必要。
  • 実行可能条件を満たしてから実行すると、「もとの選択範囲をふくむ論理行全体 (末尾改行をふくむ)」が範囲選択された状態で残る。
  • 引数に 1 以上の数値を渡して実行すると、「元に戻す」さいには document.selection.Indent(n)document.selection.Unindent(n) での引数の値とおなじ回数の document.Undo() や Ctrl+Z の操作が必要。
ref. 「非選択状態でも逆インデント」「字下げ・字上げ」など、標準のインデント/逆インデント機能の代替マクロがマクロライブラリにある。

NewLine() メソッド[編集]

Selection.NewLine() メソッド

  • 引数に 1 以上の数値を渡して実行したばあい、「元に戻す」さいには document.selection.NewLine(n) での引数の数値とおなじ回数の document.Undo() や Ctrl+Z の操作が必要。

Tabify/Untabify() メソッド[編集]

Selection.Tabify() メソッドSelection.Untabify() メソッド

  • 「選択範囲のテキスト」ではなく「選択範囲をふくむ論理行全体」が操作対象で、1文字以上の選択範囲が必要。
  • 実行可能条件を満たしてから実行すると、「もとの選択範囲をふくむ論理行全体 (末尾改行をふくまない)」が範囲選択された状態で残る。
  • 選択範囲内のテキストが「タブや2コ以上連続する半角空白をふくまない」ばあいなど、「タブ/空白」変換されなかったさいにも Undo 履歴や変更行のマーキングなどが残る。
ref. 文字列操作が空振りしたときは undo 履歴に残さない
ref. 拙作「TAB/半角空白 トグル変換」マクロ

SelectLine() メソッド[編集]

Selection.SelectLine() メソッド

  • 「論理行」全体の選択のみで、「表示行」の選択には非対応。
※ エディタ内でのトリプルクリック操作に相当し、行末改行も選択範囲にふくまれる。
  • 引数に true を渡すと複数行選択が可能。
  • トリプルクリックや行番号のクリック(またはドラッグ)で論理行全体が範囲選択された状態から実行すると、もとの選択範囲末尾改行のつぎの行まで範囲選択されてしまう。
c.f. 複数行の論理行を範囲選択(末尾改行を含まない)

検索/置換[編集]

Find() メソッド[編集]
  • 定数
document.selection.Find() メソッド
指定のパターンを検索します。

 0: meFindPrevious		カーソル位置から前を検索します
 1: meFindNext			カーソル位置から次を検索します
 2: meFindReplaceCase		検索する単語の大文字と小文字を区別します
 4: meFindReplaceOnlyWord	完全に一致する単語を検索します
 8: meFindAround		文書の末尾まで検索したら先頭から検索を開始します
16: meFindReplaceRegExp		正規表現で検索します
				
※ document.selection.Replace() メソッド専用の定数
32: meReplaceSelOnly		選択した範囲のみ置換します
64: meReplaceAll		すべて置換します

※ editor.FindInFiles()ReplaceInFiles() メソッド専用の定数
 128: meFindRecursive		サブディレクトリも検索します
 256: meFindFileNamesOnly	ファイル名のみ表示します
 512: meReplaceBackup		バックアップを保存しますMery ver 2.8.3 で追加された定数 [4]
 1024: meFindMigemo		Migemo を使用します(※ 検索/すべて検索 でのみ)

※ Mery ver 3.0.1 で追加された定数 [5][6]
 2048: meFindAll		すべて検索して選択範囲に追加します
 4096: meFindNotBOL		選択範囲の先頭を行頭とみなさず置換します
 8192: meFindNotEOL		選択範囲の終端を行頭とみなさず置換します
16384: meFindKeepOptions	検索ダイアログの文字列、オプション項目を維持します
  • 「検索/置換」ダイアログのオプションフラグをすべて OFF にする方法 として
document.selection.Find( "", 0 ); // 空文字列の検索でオプションフラグを解除する
というコードを挟み込む手法がある(第二引数には 0 または 1 を指定する)。
ref. Mery 公式フォーラム 『空検索の動作、など
これは、マクロ実行時に「検索/置換」ダイアログが開かれていないときにかぎり、マクロ終了後の「検索/置換」ダイアログのオプション項目のチェック ON/OFF の状態にも引き継がれる(次回の「検索/置換」や「次/前を検索」「次/前の文字列を検索」コマンドなどにも引き継がれる)。
※ ただし、「終了したら閉じる」と、ベータ版 2.6.10 で追加された「インクリメンタルサーチ」のオプションフラグはマクロから解除することができない。
  • meFindReplaceOnlyWordmeFindReplaceRegExp は排他関係なので、同時に使用した場合 meFindReplaceRegExp は適用されるが meFindReplaceOnlyWord は無視される
(検索ダイアログで「正規表現」オプションを有効化したときに「単語のみ」オプションが無効になるのと同様)。
  • ベータ版 2.8.3 で追加された meFindMigemo と従来からの meFindReplaceRegExp も排他関係で、meFindMigemo が優先される。
  • Mery ver 3.0.1 での定数 meFindKeepOptions の追加にともない、マクロで Find() メソッドを使用したあとに「検索/置換」ダイアログ内の「Migemo を使用する」オプションの状態もリセットされるようになった (meFindMigemo の有無で Migemo の ON/OFF が切り替わる)ようなので、document.selection.Find( "", 0 ); を使用すると「Migemo を使用する」オプションは OFF (無効) になる。
※「検索/置換」ダイアログの検索文字列欄に HOGE が入力されたまま閉じて、マクロで document.selection..Find( "FUGA", meFindKeepOptions ); を実行すると、検索ハイライトされた文字列と「検索/置換」ダイアログ内の検索文字列に齟齬が生じることになる
( ⇒ 「次/前を検索(F3/Shift+F3)」コマンドでは HOGE が再検索される)。
たとえば「検索(SJIS以外)」マクロのような長大な正規表現を使用するマクロで meFindKeepOptions を適用すると、マクロ実行後に [Shift+F3] キーによる上方向への再検索はできなくなるので、長大な検索文字列を検索履歴に残したくない特殊な検索(置換)マクロの場合での扱いはむずかしい (検索マクロに「GetKeyState.exe(キー状態取得実行ファイル)」を導入して、meFindNextmeFindPrevious を切り替える、または meFindKeepOptions の有無を切り替えるなどの対応をするか、検索方向(次/前)の差分で検索マクロを2件登録するか…)。
FindRepeat() メソッド[編集]
  • 定数
document.selection.FindRepeat()  メソッド
前回検索した文字列を検索します。 

 0: meFindRepeatPrevious	カーソル位置から前を検索します。
 1: meFindRepeatNext		カーソル位置から次を検索します。
 2: meFindRepeatWord		選択範囲が空の場合はカーソル位置の単語を検索します。
FindRepeat() メソッドでは定数 meFindReplaceCasemeFindReplaceOnlyWord , meFindAround , meFindReplaceRegExp が使用できず、 直前 の「検索/置換」コマンドや Find() / Replace() メソッドで使用したこれらのオプションのうち meFindReplaceRegExp 以外の三つの ON/OFF 状態が 継承 される。
  • FindRepeat() メソッドで meFindReplaceCasemeFindReplaceOnlyWord , meFindAround を適用した検索をしたいばあいは、以下のように記述する。
meFindReplaceRegExp があっても FindRepeat() の実行時には無視される。
// FindRepeat() で使用したいフラグ
var flags = meFindReplaceCase + meFindAround;

// ➀ 空文字列の検索をして、フラグを設定する
document.selection.Find( "", flags );

// ➁「前回検索した文字列を検索」または キャレット位置の単語で「次の文字列を検索」
document.selection.FindRepeat( meFindRepeatNext + meFindRepeatWord );

// -------------------------------------------------- //

// ➂ 最後にオプションフラグを解除しておきたいなら
document.selection.Find( "", 0 );
※ ➂ の行のコードを最後に使用した場合、「検索/置換」ダイアログのオプションフラグも解除される。
Mery ver 3.0.1Find() メソッドなどで利用できる定数が追加されたが、FindRepeat() メソッドの仕様は変わっていないので検索フラグを適用する方法はうえのサンプルコードのようにしなければならないことに変わりはない。
サンプルコードの「➀」で meFindKeepOptions 定数を追加すると「➁」の FindRepeat() メソッドに「➀」で設定したフラグが適用されなくなり、「検索/置換」ダイアログ内のオプションフラグのチェック状態が適用されてしまうので 要注意
マクロ独自のフラグ設定状態で FindRepeat() メソッド(次/前の文字列を検索)使用したいばあいには、「検索/置換」ダイアログ内のオプションフラグをクリア/リセットしなければならないままである。

Mery ver 3.0.1 以降でオプションフラグを維持したまま「置換」を行うサンプルコード[編集]

実行前になんらかの文字列を検索していて "検索マーカーが表示されている場合" を考慮すると、なかなか面倒な部分が多い…。

/**
 * 「スペース×2削除」マクロの Mery v3 対応テスト
 * 行頭の字下げを1段階解除する(半角×2, 全角×1, タブ×1)
 * ※ マルチカーソル非対応
 */
var d = editor.ActiveDocument,  s = d.selection;
var sx = ScrollX,  sy = ScrollY;
var ty = s.GetTopPointY(mePosLogical);
var by = s.GetBottomPointY(mePosLogical);
var bx = s.GetBottomPointX(mePosLogical);
// ver 3.0.1 以降かバージョンチェック用
var meFindKeepOptions; // (meFindKeepOptions = 16384) > 0

// 選択範囲の先頭/末尾を論理行全体に拡張
if (s.Text && by != ty && bx == 1)  by--;
s.SetActivePoint(mePosLogical, 1, by);
s.EndOfLine(false, mePosLogical);
s.SetAnchorPoint(mePosLogical, 1, ty);
s.CharRight(true);

var st = s.Text;

if (st && meFindKeepOptions) {
  // Undo 用の選択範囲を保存
  var sv = d.Saved;
  BeginUndoGroup();  AddUndo();

  // 置換で字上げ(逆インデント)
  var hl = d.HighlightFind; // 検索ハイライトの状態を取得
  var regRep = "^(?:\t| {1,2}| )(.*+)$"; // ※ masme氏による
  var result = "$1";
  var flag = meReplaceSelOnly + meReplaceAll
           + meFindReplaceRegExp + meFindKeepOptions;

  s.Replace(regRep, result, flag); // ⇒ イヤな感じにハイライトが残る
  var act = s.GetActivePos();      // 置換終了時のキャレット位置

  // もとの検索ハイライトの状態に復帰(※カーソル移動をともなう)
  s.FindRepeat(0); // 検索履歴の文字列で「前の文字列を検索」
  d.HighlightFind = hl;  Status = "";

  // 選択範囲とスクロール位置を復旧
  s.SetAnchorPoint(mePosLogical, 1, ty);
  s.SetActivePos(act, true);
  ScrollX = sx;  ScrollY = sy;

  EndUndoGroup();
  // 字上げ(置換)ナシなら AddUndo を破棄
  if (s.Text == st) {
    d.Undo();  d.Saved = sv;
  }
}
[ Ctrl+Shift+↑ / ↓ ] の機能も「次/前の文字列を検索・改」マクロに置きかえてしまったので、検索ダイアログを開くのは正規表現で検索するときぐらいかも。

文字列操作が空振りしたときは undo 履歴に残さない[編集]

  • 条件付きで文字列操作(挿入・置換など)するマクロが空振りしたとき
// e.g. 選択範囲に「hoge」が含まれていれば「fuga」に置換する
var fuga = document.selection.Text.replace( /hoge/g, "fuga" );
document.selection.Text = fuga;
上のようなコードの場合は undo 履歴に無駄に残ったり、文書に「未保存 *」のフラグが付加されたりする。
以下のように「文字列操作の前後で "変化なし" なら undo 履歴には残さない」記述にすると、変更行の強調表示 なども無用に付かなくなる。
// e.g. 選択範囲に「hoge」が含まれなければ置換しない
var st = document.selection.Text;
var piyo = st.replace( /hoge/g, "piyo" );

if ( st != piyo ) {
  document.selection.Text = piyo;
}
  • 大文字/小文字変換の Selection.ChangeCase() メソッド や、全角/半角変換の Selection.ChangeWidth() メソッド なども、日本語文などで空振りしたときに undo 履歴に残るが、上のサンプルコードのようなかたち var temp = document.selection.ChangeCase( meCaseLowerCase ); で変数に格納することはできない。
Document.Selection クラス の文字列操作メソッドの場合は、以下のように記述することで「変換なしなら undo 履歴を巻き戻し」できる。
// 変換前の文字列 と 保存済み/未保存 の状態を取得
var st = document.selection.Text;
var sv = document.Saved;

if ( st && ! document.ReadOnly ) {

  // 小文字に変換
  document.selection.ChangeCase( meCaseLowerCase );

  // 変換なしなら undo 履歴を巻き戻す
  if ( document.selection.Text == st ) {
    document.Undo();
    document.Saved = sv;
  }
}
※ ただし、厳密にいえば undo 履歴には残っているので、redo (やり直し: Ctrl+Y) することができる。

スクロール位置の調整[編集]

  • ScrollX/ScrollY プロパティWindow オブジェクト直下のプロパティに属するため、Editor.ActiveDocument 以外の Document オブジェクト(e.g. Documents.Item(n))を指定してスクロールさせることができない。
  • 同様に、ActiveDocument 以外の Document にたいして Selection.StartOFDocument() 等のキャレット移動をともなうメソッドを実行しても、スクロール位置は移動しない。
※ いずれも、操作対象のウインドウ/タブを明示的にアクティブ化(Editors.Item(m).Documents.Item(n).Activate();)してからなら意図的なスクロール操作ができるが、もとのタブをアクティブ状態に戻すならコードの最後に Document.Activate(); による復帰操作が必要(ほかのエディタウインドウのドキュメントの操作のばあいは、自他のエディタウインドウの Editors.Item(m) のインデックスの取得が必要)。
  • キャレットをジャンプさせた後のスクロール位置とキャレット位置は、移動先の行(表示座標での行番号)がエディタの表示領域の高さに収まるかどうかとジャンプ方向によるので安定的ではない(スクロールマージンの考慮も必要)。
以下は、ジャンプしてスクロールが発生した場合に、キャレットが表示領域の先頭位置になるようにスクロール状態(window.ScrollY)を調整するコード。
var s = Document.Selection;
var ax = s.GetActivePointX( mePosLogical );		// キャレット位置の X
var ay = s.GetActivePointY( mePosLogical );		// キャレット位置の Y
var sy = ScrollY;	// エディタ表示領域の先頭行(物理行番号+スクロールマージン)

// 下方向に10行(論理行)ジャンプ
s.SetActivePoint( mePosLogical, ax, ay + 10 );

// スクロールしないならそのまま / スクロールするならキャレットは表示領域の先頭に
ScrollY = ( ScrollY == sy )
            ? sy
            : s.GetActivePointY( mePosView );

// つねにジャンプ先の行が先頭になるようスクロールさせるなら
// ScrollY = s.GetActivePointY( mePosView );

// ※ ScrollY プロパティに値を代入するときは物理座標(表示行)の行番号で

※ スクロールマージンは ベータ版 2.7.0 より「オプション」ダイアログの「スクロール」のページ内で変更できるようになっている。[7]

OutputBar オブジェクト[編集]

OutputBar オブジェクトWindow オブジェクト直下のプロパティ に属するため、アウトプットバー操作の各メソッドやプロパティは、複数ウインドウ状態のときに非アクティブウインドウのアウトプットバーを操作することができない。

Editors.Item(m).Documents.Item(0).Activate(); してからなら、OutputBar 操作可。

Window オブジェクト[編集]

通常はソースコード内で Window オブジェクト を明示的に記述する必要はないが、バージョンチェック の節の「例4」のように 実際に記述する場合には Window ではなく window でないと宣言されていない変数・オブジェクトあつかいのエラーになる。

DocumentSelectionAlert など他の主要なプロパティは「大文字/小文字/頭文字のみ大文字」の区別なしに同一のプロパティとしてあつかわれる。

カレントディレクトリ[編集]

カレントディレクトリ(作業フォルダ)は、Mery を起動したときに決定され、一定ではない。

記述の都合上で相対パスを利用するために特定のカレントディレクトリを指定するマクロもあるが、「あえて流動的なカレントディレクトリを利用する」ようなコードが続く場合は、カレントディレクトリを書きもどす必要がある。

※ マクロでカレントディレクトリを変更すると、実行中の Mery のプロセスの作業フォルダも変更されるため、あとから他のマクロを実行するさいのカレントディレクトリにも影響する。
// マクロ実行前の作業フォルダを保存する
var wshShell = new ActiveXObject( "WScript.Shell" );
var currentDir = wshShell.CurrentDirectory;

// 任意のカレントディレクトリを設定する    e.g. %AppData%\Mery
wshShell.CurrentDirectory = wshShell.SpecialFolders( "APPDATA" ) + "\\Mery";

/* いろいろな処理を実行... */

// 最終的にマクロ実行前の作業フォルダを復帰する
wshShell.CurrentDirectory = currentDir;
  • システムの関連付けを利用してテキストファイルなどのダブルクリックから Mery を起動した場合、そのファイルの親フォルダが Mery のプロセスの作業フォルダとなり、Windows OS の仕様により Mery のプロセスを終了するまでそのフォルダはロックされた状態になる(フォルダの移動や削除ができなくなる)が、マクロでカレントディレクトリを変更するとフォルダのロックを解除できる。

動作要件としてのバージョンチェック[編集]

公開するマクロに Mery ベータ版で追加されたマクロ用プロパティ・定数を利用する場合は、マクロの動作要件として Mery 本体のバージョンをチェックするコードを入れておくのが無難である。

  • 拙作の 組み込み関数 VersionCheck() を利用すれば、Mery のバージョン番号を指定して動作要件のチェックができるが、あらかじめプロパティや定数が導入された Mery のバージョン番号を調べておく必要がある( ← Mery.txt か CHNGELOG.txt に記載されているはず)。
  • JavaScript には特定のプロパティがオブジェクト配下に定義されているかを調べる方法も色々とあるが、親オブジェクトのタイプやプロパティ・定数のタイプ、JavaScript(JScript)のバージョンによる互換性などへの考慮が必要になる。 [8][9][10]
ベータバージョンで追加された定数やプロパティが有効かどうかを調べる程度であれば、シンプルな記述で済む。
// ▼ ChangeCase() メソッドで定数 meCaseCapitalize を使えるのは ver 2.6.10 以降

// 例1. VersionCheck() 関数を利用する場合
if ( VersionCheck( "2.6.10" ) ) {
  // 「単語の最初の文字を大文字に変換」
  document.selection.ChangeCase( meCaseCapitalize );
}
else {
  // 「小文字に変換」
  document.selection.ChangeCase( meCaseLowerCase );
  Status = "小文字…。";
}

function VersionCheck( versionStr ) {
  /* 関数のコードをコピペ */ ;
}

// -------------------------------------------------- //

// 例2. 定数 meCaseCapitalize が定義されているかを調べる場合
var meCaseCapitalize;
if ( typeof meCaseCapitalize == "number" ) {	// または if (meCaseCapitalize == 3)
  // 「単語の最初の文字を大文字に変換」
  document.selection.ChangeCase( meCaseCapitalize );
}
else {
  // 「小文字に変換」
  document.selection.ChangeCase( meCaseLowerCase );
  Status = "小文字…。";
}
// ▼ BeginUndoGroup() メソッドを使えるのは ver 2.7.0 以降

// 例3. VersionCheck() 関数を利用する場合
if ( VersionCheck( "2.7.0" ) ) {
  BeginUndoGroup();
}

function VersionCheck( versionStr ) {
  /* 関数のコードをコピペ */ ;
}

// -------------------------------------------------- //

// 例4. メソッドが定義されているかを調べる場合
if ( "BeginUndoGroup" in window ) {
  BeginUndoGroup();
}

外部リソースのチェック[編集]

「includeライブラリ」や「GetKeyState.exe」のような外部リソースを必要とする前提のマクロでも、それらのリソースがない場合にもある程度マクロが動くようにコーディングすることができる。

  • includeライブラリ が必要なマクロの場合、ユーザー側が includeライブラリを正しく導入していることが要求される。
ユーザー側で includeライブラリを導入していて、マクロ側で #include "include/IO.js" のようなプリプロセッサがソースコードの先頭で宣言されていれば問題ないのだが、includeライブラリが導入されていなくても、プリプロセッサを削除(コメントアウト)すればマクロがある程度動くようにコーディングすることもできる。
// #include "include/IO.js"

if ( typeof IO == "object" ) {
  /* IO.js がインクルードされているときの動作 */ ;
}
else {
  /* IO.js がインクルードされていないときの代替動作 */ ;
}
// あらかじめ変数 ctrl に 0 を代入しておく
var ctrl = 0;

// GetKeyState.exe のパスで実行ファイルの実在確認をする
var getKeyState = editor.FullName.replace( /[^\\]+$/i , "" )
                + "Macros\\GetKeyState.exe";
var fso = new ActiveXObject( "Scripting.FileSystemObject" );

if ( fso.FileExists( getKeyState ) ) {
  // GetKeyState.exe で Ctrl キーの押し下げ状態を取得する
  var wshShell = new ActiveXObject( "WScript.Shell" );
  ctrl = wshShell.Run( "\"" + getKeyState + "\" control", 0, true );
}

if ( ctrl == 1 ) {
  /* GetKeyState.exe があり、Ctrl キーが押されているとき */ ;
}
else {
  /* GetKeyState.exe がない、または Ctrl キーが押されていないとき */ ;
}

Mery.ini から設定値を取得する[編集]

includeライブラリ の MeryInfo クラス (#include "include/MeryInfo.js") を利用して Mery.ini からいくつかの設定項目の値や状態を取得することはできるが、制約が非常に多い。

  • 取得できる項目がきわめて限定的である
  • 取得したい項目が複数あると、その都度 Mery.ini 全体の読み込みが発生する(キャッシュ可)
  • Mery.exe のファイル名を変更 (e.g. Mery_hoge.exe) している場合、MeryInfo.js のコードを改変しないと Mery.ini (Mery_hoge.ini) のパスを得られず、設定値を取得できない。

GetIniOption() 関数[編集]

拙作の 組み込み関数 GetIniOption()GetIniOption2() はこれらの制約を受けず、とくに後者は Mery.ini のすべての項目にアクセスして値を取得することができる。

ただし、制約がない代わりに組み込み関数自体のコードが長いことや、引数や戻り値が配列であることでコードが煩雑にならざるをえない( ⇔ 配列を使用することで、複数の項目を取得する場合でも Mery.ini ファイルの読み込みを1回におさえられる)。

IO.LoadFromFile() 関数で Mery.ini を読みこむ という方法もある。

また、Mery.ini 側の仕様として、

「オプション」など各種の設定ダイアログを [ OK ] ボタンで閉じたときか、
エディタウインドウを閉じたときにしか Mery.ini への書き込みがされないため、
メニュー項目/ツールバーアイコン/ショートカットキー で変更した設定内容は
Mery.ini に直ちに反映されない

という制約がある(Mery.ini の実体ファイルへの書き込み回数を減らすための仕様)。

エディタの表示状態をトグル切り替えするコマンド(縦書き、色の反転、全画面表示、etc. ...)については、マクロ用の標準メソッド/プロパティから「現在の表示状態」を取得する手段がなく、組み込み関数 GetIniOption2() で Mery.ini を読み込んでも、必ずしも「最新の設定状態」を取得できるわけではない…。

※ 「現在の表示状態」を取得してから ON/OFF を指定しての切り替えを行なうためには、includeライブラリの IO クラスを利用するなどして外部に Mery.ini とは別の設定ファイル (e.g. JSON ファイル) を用意し、切り替え実行のたびに設定ファイルを読み書きする必要がある。

ただし、この方法をとる場合は、外部ファイルに設定内容をあずける項目(コマンド)の切り替えについては必ずマクロ経由で行なわなければならず、デフォルトの メニュー項目/ツールバーアイコン/ショートカットキー による通常操作でその項目の状態の変更をすると、最新の設定状態(現在の表示状態)と外部ファイルが保持している設定内容とのあいだに齟齬が生じてしまう。

→ e.g. 「折り返しトグル切り替え」マクロ

Mery.ini からさまざまな情報を読み込んで利用するマクロ[編集]

組み込み関数 GetIniOption / GetIniOption2 を利用(必用に応じてカスタマイズ)した拙作マクロ

  • ブックマーク一覧ジャンプ(include版)」「ポップアップメニューで検索先にジャンプ(include版)」: 行の表示方法(論理座標/表示座標)の設定状態を取得して、ポップアップメニューに表示するアイテムの行番号の表示方法を切り替え。
  • ファイルを読み直す・開きなおす」: 自動保存・バックアップの設定状態、タブの閉じるボタンの表示設定などを取得して動作コードの条件分岐に利用。 編集モード名の一覧取得してポップアップメニューから切り替える。
  • マクロメニュー」: マクロのカスタマイズ に登録済みのマクロの一覧をポップアップメニューに表示して、選択したマクロを実行または Mery で開く(編集)。
  • コンパクトメニュー」: 登録されている編集モード名の一覧、マクロ(Mery.exe からの相対パス)の一覧、プラグイン(Mery.exe からの相対パス)の一覧、外部ツール名の一覧、およびそれぞれの登録された並び順を取得して、ポップアップメニュー化。 通常では表示されないような機能もほぼ全てメニュー化する。
    • 制限事項 にマクロから できること/できないこと についての説明あり。

Mery.ini からは「最新の状態」を取得できない設定項目[編集]

※ メニューバーから設定状態を変更できる項目は、即時 Mery.ini の内容が更新されるわけではないので、マクロから「最新の状態」を取得することはできない。 検索履歴も同様。

※ フォントの使用履歴の取得は可能だが、[ 表示 ] メニューから切り替えたさいの「最新の状態」は取得できない。 また、マクロからフォントを変更する手段がない (履歴内の並び順を取得できないので wshShell.SendKeys() などのキーストロークエミュレーションでも不可)。 フォントサイズを 大きく/小さく するだけならマクロからでも変更可能。

外部ファイルにマクロの設定などを書き出す[編集]

マクロの設定情報を保存して次回の実行時にそれを参照して使いたい場合、includeライブラリ の IO クラス (IO.js) の IO.Serialize()IO.Deserialize() を利用するのがもっとも簡単な方法だとおもわれる。

※ ただし、マクロの実行ごとに外部ファイル(設定ファイル.JSON と includeライブラリの IO.js および json2.js)を読みこむことになるので、環境によってはマクロの動作のもたつきや エラー が生じてしまう可能性がある。

以下、「折り返しトグル切り替え」マクロを例に IO.Serialize()Deserialize() の利用方法の簡単な説明。

#include "include/IO.js"
  // \Macros\include\IO.js をインクルードする
  // ※ ソースコードの1行目に記述すること。

/* 【準備】 */
// ■ JSON のファイル名(この場合 折り返し.json)	※定義しなくてもよい
var jsonName = "折り返し";

// ➀ 書き出し内容として使う「オブジェクト」を用意する
var setting = {};

// ➁ 設定項目として使う「プロパティ」と「初期値」を定義する
setting.wrapMode = 0;
setting.count = 0;
  // ※ objectName.propertyName = value;
  //    value には数値以外(文字列、真偽値、配列など)も設定できる。

// または、以下のようにまとめてもよい ( ➀+➁ と意味は同じ)
var setting = { wrapMode: 0, count: 0 };
  // ※ {ブラケット} で囲う場合はコロンで結んで  propertyName : value  とする。
  //    複数のプロパティを列挙する場合はカンマ「,」で区切る。
  //    ブラケット内の最後にセミコロン「;」をつけないこと。

/* 【JSON 読み込み】 */
// JSON ファイルに保存された設定値で上書きする
setting = IO.Deserialize( setting, jsonName );
  // ※ 第2引数 jsonName を省略した場合は、自動的に「マクロ.js」のベース名。
  //    初回起動で JSON ファイルがないときは初期値のまま。

/* 【動作コード】 */
// 折り返しモード切替
if ( setting.wrapMode == 2 ) {
  editor.ExecuteCommandByID( 2146 );	// 折り返さない
  setting.wrapMode = 0;
} else if ( setting.wrapMode == 0 ) {
  editor.ExecuteCommandByID( 2147 );	// 指定文字数で折り返し
  setting.wrapMode = 1;
} else {	// else if ( setting.wrapMode == 1 )
  editor.ExecuteCommandByID( 2148 );	// ウインドウの右端で折り返し
  setting.wrapMode = 2;
}

// 任意のプロパティを追加することもできる
setting.dateTime = new Date();			// 最終実行日時の記録

setting.count += 1;						// マクロの実行回数を記録
if ( setting.count % 100 == 0 ) {		// 100 回ごとにダイアログを表示
  var d = setting.dateTime;
  var dateTime = d.getFullYear() + "/" + ( d.getMonth() + 1 ) + "/" + d.getDate()
               + " " + d.toLocaleTimeString();
  var str = dateTime + "\n\n"
          + ScriptName + " マクロ実行 " + setting.count + " 回目!!";
  Alert( str );
}

/* 【JSON 書き込み】 */
// setting オブジェクトの変更内容を保存する
IO.Serialize( setting, jsonName );

Tag プロパティ[編集]

ベータ版 ver 3.0.0 で追加された Tag プロパティを活用することで、外部ファイルにマクロの設定を書き出す必用がなくなる場面もでてくるとおもわれる。

ref. Document.Tag プロパティEditor.Tag プロパティWindow.Tag プロパティ(@マクロリファレンス:3

外部ファイルへのアクセスの必用がなくなり、マクロの実行コードのスリム化(「includeライブラリ」も利用せずに済む)や安定性の向上、動作の高速化などが期待できるが、Tag プロパティへの書き込みは 最長でも Mery.exe のプロセスが終了するまでの "一時保存/一時利用" にとどまるので、マクロのデフォルト動作の設定を保存したい場合には外部ファイルを利用するほうがよさそうである。

  • 拙作マクロで外部ファイルの利用から Tag プロパティの利用に切り替えたのは、現時点では上出の「折り返しトグル切り替え」マクロだけである。
※「位置情報を保存してから「すべて選択/選択解除」(非スクロール)」マクロ (include版) や「位置を復帰/保存」マクロ (include版)、「カッコを追加/削除」マクロ (include版) も Tag プロパティへの移行を検討中 (いまのところ、ベータ版 ver 3.0.0 で追加された マルチカーソル 機能 [11] に対応する目処が立っていないので、公開版の更新は保留)。
  • ポップアップメニュー内の「設定変更サブメニュー」で動作設定を変更するタイプの拙作【include版】マクロは、外部ファイルを利用する仕様のままにする予定。

関数の「呼び出しコスト」[編集]

ユーザー関数は、呼び出し元から参照可能な位置に記述すれば、ソースコードの任意の位置に配置することができる。

繰り返し何度も呼び出して使用する関数の場合に「呼び出しコスト」を気にする人もいるらしいが、Mery で使用するマクロ程度のソースコードであればあまり気にする必要はないようにおもわれる。

e.g. 半角英数字以外を「¥」でエスケープ処理する

※ あえて ループ処理で1行ずつエスケープ してみる (@ロースペの XP ノート

/* 関数バージョン */

function Quote( str ) {
  return str.replace( /\W/g, "\\$&" );
}

// または
// var Quote = function( str ) {
//   return str.replace( /\W/g, "\\$&" );
// }

BeginUndoGroup();
var lines = document.GetLines( 0 );
for ( var i = 1, st, a = []; i <= lines; i ++ ) {
  st = Quote( document.GetLine( i, 0 ) );
  a.push( st );
}
document.Text = a.join( "\n" );

function Quote( str ) でも var Quote = function( str ) でも、約 9500 行の日本語テキスト(約 33 万文字)にたいして 1.1 秒台の処理時間がかかり有意な差はみられなかった。

関数を使用しない以下のようなベタ書きのコードの場合でも、ほぼ同じ程度の処理時間がかかった (@ロースペの XP ノート)。

/* 非関数バージョン */

BeginUndoGroup();
var lines = document.GetLines( 0 );
for ( var i = 1, st, a = []; i <= lines; i ++ ) {
  st = document.GetLine( i, 0 ).replace( /\W/g, "\\$&" );
  a.push( st );
}
document.Text = a.join( "\n" );

※ ループ文の中で関数を定義した場合は、やや遅くなって 1.3 秒台。

BeginUndoGroup();
var lines = document.GetLines( 0 );
for ( var i = 1, st, a = []; i <= lines; i ++ ) {
  function Quote( str ) {
    return str.replace( /\W/g, "\\$&" );
  }
  st = Quote( document.GetLine( i, 0 ) );
  a.push( st );
}
document.Text = a.join( "\n" );

※ 行ごとのループ処理ではなく、文書全体の 一括処理 にすると速くなる。

上とおなじ Quote() 関数を使用しての文書全体の一括処理でも…

function Quote( str ) {
  return str.replace( /\W/g, "\\$&" );
}

document.Text = Quote( document.Text );

関数を使用しないベタ書きの一括処理でも…

document.Text = document.Text.replace( /\W/g, "\\$&" );

…処理時間はほぼ同じで、約 0.7 ~ 0.8 秒だった。

現行 OS の Chakra エンジン (jscript9.dll) であれば約 20 倍 の速度が出るらしいので、数メガバイトとか数万行とかのよほど長大な文書の処理をする場合でもなければ、「関数の呼び出しコスト」を気にする必要はあまりなさそう。

それよりも、

  • 文字列操作や検索/置換にさいして、なるべくキャレットの移動をともなうメソッドを使用しない
※ できるだけ Mery 独自のメソッドよりも、代替可能な JavaScript の String オブジェクトのメソッド を変数内で使用する (Mery のマクロメソッドは「キー操作の記録と再生が一番の目的」なので、動作速度的に最適化されていないのかも)。
  • くりかえし何度も参照されるオブジェクトやプロパティは変数に格納する
e.g. Document.TextDocument.Selection.Textfor 文 での Array.length など。
  • 関数定義文で必要となる引数をすべて与えておき、関数スコープからグローバルスコープに変数の値を参照しに行かないで済むようにしておく
  • ループ処理などから繰りかえして呼び出す必要のある関数の場合は、なるべくなら関数定義文を呼び出し元のコードよりも先に記述しておく

などで、ソースコードの最適化をはかるほうが良いはず。(… sukemaru 自身はこのルールをあまり守っていない)

※ ちなみに、Quote() 関数を以下のように記述した場合、上のようなループ処理コードでの所要時間は 3 倍(3 秒台)。

function Quote( str ) {
  return str.replace( /\W/g, function( $0 ) {
    return "\\" + $0;
  } );
}

以下のような記述だと、ループ処理した場合の所要時間は 4 倍以上(4 ~ 5 秒台)になる。

function Quote( str ) {
  return str.replace( /\W/g, Escape );
}
function Escape( matched ) {
  return "\\" + matched;
}

…ループ処理から参照する関数のネストや二重参照は、ループ文内で関数を定義する場合以上に鬼門のようだ。

FileSystemObject と WScript.Shell でファイルパスを引数にするとき[編集]

引数として使用するファイルパス文字列に 半角空白 がふくまれている場合、

  • FileSystemObject ではパスをダブルクオートなどの 引用符で囲う必要がない
  • WScript.Shell などの WSH コードではパスをダブルクオートなどの 引用符で囲う必要がある

よって、WshShell.Run() コマンド などで不特定のパス(または任意のパス)を指定するときは WshShell.Run( "\"" + path + "\"" ) または WshShell.Run( '"' + path + '"' ) のように記述しておき、パスに半角空白がふくまれていてもエラーにならないように備えておくとよい。

// 半角空白を含むパス
var path = "C:\\Hoge hoge\\Fuga fuga\\Piyo piyo.txt";

var fso = new ActiveXObject( "Scripting.FileSystemObject" );
var wshShell = new ActiveXObject( "WScript.Shell" );

if ( fso.FileExists( path ) ) {			// 引用符で囲わないでよい
  wshShell.Run( "\"" + path + "\"" );	// 引用符で囲う必要がある
}

警告・確認ダイアログとステータスバーの使い分け[編集]

マクロからユーザーにメッセージを与える手段として 警告window.Alert)・確認window.Confirm)ダイアログと ステータスバーwindow.Status)への表示などがある(ほかに アウトプットバーOutputBar.Write)や ポップアップメニュー を使う方法もある)。

// e.g. ポップアップメニューを「ポップアップヒント」として使用する

if ( document.ReadOnly ) {
  var m = CreatePopupMenu();
  m.Add( "  このドキュメントは 書き換え禁止 です	& ", 0 );
  var r = m.Track( 1 );
}

基本的に、Mery のマクロで利用できるポップアップダイアログ(警告、確認)はどちらもシステムサウンドをともない、ボタン操作で閉じるまで作業を中断させてしまうので、あえて作業を一時停止させる必要がある場面以外ではステータス表示を使用するのがよい。

※ ユーザー側がステータス表示を使用するイベントマクロなどを別途で導入していることを考慮すると、マクロの終了時になんらかのイベントが発生するマクロの場合、重要なメッセージはダイアログで出力させるか、マクロ内の動作設定用の変数で出力方法を選択できるようにしておくとなおよい。

また、Mery の Window クラスのメソッド・プロパティを使うほかにも、WSH の WshShell.Popup() メソッド によるメッセージボックスを利用することもできる。

ダイアログ内の左側のアイコンの種類や OK キャンセル はい いいえ などのボタンの種類をカスタマイズでき、指定時間の経過後に自動で閉じさせることもできるが、引数の指定や戻り値の処理が煩雑なので、 はい いいえ キャンセル の3ボタンが必要な場合でもなければお勧めはしない…。

※ アイコンなしにすれば、システムのサウンドなしでダイアログを表示できる。

WshShell.Popup() メソッドならばメッセージボックスが表示されたままの状態でもエディタの編集操作が可能な場合もあるが、メッセージボックスが表示されているあいだは別のマクロを起動することはできない (ショートカットキーなどから別のマクロを起動しようとすると、Mery 本体のプロセスが不安定になることがある)。

その他、拙作マクロについて[編集]

Kuro 氏の 「引用を追加」マクロのカスタマイズ をきっかけとしてマクロの改造に手を染め、 マクロのアイコン化のためにアイコンを量産 していくうちにマクロの自作も始めて、マクロ制作のための補助的マクロの自作とか「タマゴ? ニワトリ?」状態になったりしています。

マウス派 として Mery を便利に扱えるようにするつもりでマクロを作っていますが、マニアックな個人的要求(欲求)を自己解決していくうちに Mery の外観 が本来の姿からかけ離れてしまっているという…。

  • sukemaru の Mery 運用環境はロースペックの Windows XP sp3 (32bit), JScript 5.8.20587 のノート PC (CPU: Atom 1.7GHz, 1 コア, 2 スレッド) です。
※ 制作したマクロの動作テストは、この XP 機でしかおこなっていません。
※ マクロの動作テストに使用している Mery のバージョンは、"最新のベータ版" (および "最新の正式版" ver. 2.6.7 ) のみです。 基本的に ver 2.6.7 以降のバージョンで動作するように作成していますが、ver 2.6.6 以前のバージョンでの利用を想定していません( ver 2.6.6 以下での動作確認はしていません)。
※ とくに「実験的マクロ・練習マクロなど」カテゴリに投稿した【自家用】/【実験】マクロにおいては、よその環境を考慮した動作テストをしていません。
※ マクロの動作速度のテストは 青空文庫 からダウンロードした『吾輩は猫である』のルビを削除して1文ごとに改行させたテキストファイル(約 33 万文字/約 9500 行)でおこなっています。 1 メガバイト超のファイルでのテストはしていません ( ロースペ PC なので 2000 行を超えるあたりから動作速度が気になりだすのですが… [12])。
※ ZIP 版の Mery でマクロを作成・運用しているので、インストーラ版では正しく動作しないマクロがあるかもしれません。
  • 開発環境が Windows XP なので、拙作マクロは基本的に JavaScript(JScript)マクロです。
※ 変数はすべて var で宣言し、JScript 5.8 の環境で実行できるようにコーディングしています。
  • Mery のオプション設定で「行の表示方法=論理座標 (論理行)」の状態で運用する前提でマクロを作っています。 公開しているマクロでは、「表示座標 (表示行)」ベースで Mery を運用している場合でも利用できるように設定項目(変数)を設けるか「行の表示方法」を自動判定するコードを追加していますが、動作が不完全になったり処理がおそくなったりすることがあります。
※「表示座標 (表示行)」ベースでの動作テストはほとんどしていません。
  • ソースコード内ではしばしば unicode 文字を使用していますので、マクロの JS ファイルは UTF-8 形式で保存する前提となっています。
  • ソースコード内の変数名の検索などで「ポップアップメニューで検索先にジャンプ」マクロを利用しやすいように(個人的にタグジャンプ系のマクロに馴染めないので)、マクロのコードには半角空白を多用しています。
  • 基本的に、変数名は頭文字が小文字の camelCase に、関数名は頭文字が大文字の TitleCase にしてあります。
  • includeライブラリ」(作成: ks 氏) を利用する【include 版】と利用しない【通常版】とがあるマクロでは、include 版を優先的にメンテ・更新しています(←自家用)。
  • 外部実行ファイル「GetKeyState.exe(キー状態取得実行ファイル)」(作成: pizz 氏) の導入が必要なものもあります。
  • ポップアップメニューマクロの「設定変更サブメニュー」など、複数のマクロで共通の自作関数を使用しているものがありますが、当面は「includeライブラリ」のような外部ファイルにまとめる予定なしです。
∴ すでに公開しているマクロが多いこと、公開用と自家用とでコードの内容がちがうマクロが複数あること、それぞれのマクロごとに自作関数のコードに改変をくわえていることなどの理由で、もはや関数・クラスを統一しなおして更新メンテするのが困難。
∴ 「includeライブラリ」のように独自クラスでまとめたものをインクルードして利用するよりも、必要な関数だけをソースコード内にコピペして使用するほうが、マクロの処理速度的には僅かながらも有利?(な気がする… @ロースペ XP)。
→念のため確認してみたら、やはり差は僅かだった。
※「includeライブラリ」の MeryInfo.js と IO.js をインクルード したマクロで Mery.ini ( 31 万文字超/約 5600 行、約 320 kB ) から「行の表示方法 (LineColumnView キー)」を取得すると、平均 0.125 秒。
#include "include/IO.js"
#include "include/MeryInfo.js"

var start = new Date();
// Mery.ini のテキストデータを読みこむ
var iniText = IO.LoadFromFile( MeryInfo.GetIniPath(), "utf-8" );
// LineColumnView キーの値を検索する
var lineColumnView = + /^LineColumnView=(\d)$/m.exec( iniText )[1];

Alert( "行の表示方法: " + ( lineColumnView ? "表示行" : "論理行" )
     + "\n\n" + ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒" );
組み込み関数 GetIniOption2() を利用したマクロで「行の表示方法」を取得すると、平均 0.095 秒。
var start = new Date();
// 関数の戻り値 iniOption[0][2] が LineColumnView キーの値
var iniOption = GetIniOption2( [[ "General", "LineColumnView" ]] );

Alert( "行の表示方法: " + ( iniOption[0][2] ? "表示行" : "論理行" )
     + "\n\n" + ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒" );

// ---------- ▼ 組み込み関数 ココから ▼ ----------
function GetIniOption2( keyArray ) {
  /* ~ 省略 ~ */
  // https://www.haijin-boys.com/wiki/Mery.iniのオプション値を取得#ソースコード_2
}
// ---------- ▲ 組み込み関数 ココまで ▲ ----------
GetIniOption2() 関数は、IO.LoadFromFile()MeryInfo.GetIniPath() のコードを翻案して作ったものなので、Mery.ini のパスを解決して ADODB.Stream で読みこむ 処理の部分はほぼ同じ。 Mery.ini のテキストデータから LineColumnView キーの値を検索する方法は異なるが、その部分は「includeライブラリ」を使用したコードの RegExp.exec( str ) メソッド のほうが速いはず。
※ GetIniOption2() 関数は String.search( regexp ) メソッド と、String.indexOf( searchValue, fromIndex ) メソッド ×3回でキーの値を取得する。
… とはいえど、「includeライブラリ」は多種多様な各クラス同士でのプロパティ(関数)の相互参照により高度に効率化されていて、おいそれとアレンジできない部分がたくさんあるため、素直にインクルードして利用するほうがよいのかも。

投稿した構文ファイル[編集]

ReplaceStr.txt / ImageViewURLReplace.dat / URLExec.dat / command.dat に対応
bregonig の正規表現のハイライト可 (基本的に onigmo の正規表現にも利用可)
※ 収録しなかった正規表現タグ (文字・文字種の変数など) があるので、リンク先ページ末尾の注記を参照のこと
MediaWiki 用構文ファイル
Mery の MSY 構文ファイル用
マクロの JS ファイル(JScript)用
JavaScript 用構文ファイル/入力補完用辞書/スペルチェック用辞書/おまけマクロ を同梱
※ Web 開発向けのキーワードは未収録
ref. Mery 公式フォーラム 『 デフォルトの構文定義の拡充について

メモ[編集]

マーカー設定[編集]

正規表現でマーカーに登録するさいは、

ラベル |正規表現

のように並列演算子 | の左側に「題名+全角空白」、右側に正規表現としておくと、マーカーバーが見やすくなる(パフォーマンス的にはよくないかも)。

  • いわゆる「プログラミング用フォント」を導入していないので、ゼロ 0オー O や、イチ 1アイ I と エル l と バー | を区別できるよう、アイ と オー にマーカーを設定。
    • 円マーク ¥ (U+00A5) や 波ダーシ (U+301C) 他、見分けづらい文字も追加。

☑ 大文字小文字を区別  ☑ 正規表現

[OOII]|[¥∖╲〜☓×〇➀-➉]

※「半角数字」には、 [ オプション ] の [ 表示 ] 設定でカスタム文字色を設定。
※ 半角バーチカルバー (パイプ) | は、必要に応じて [ 編集モード ] の強調文字列に設定。
※ 小文字エル l は、出現頻度が高く、編集モードの登録単語にふくまれていることも多いので強調なし。
  • 特殊な空白文字用
    • 「MeiryoKe_Gothic」 フォントで通常の全角/半角空白と区別できない 特殊な空白文字 と、ゼロ幅空白文字

☑ 大文字小文字を区別  ☑ 正規表現

特殊な空白文字 |[\x{00A0}\x{2000}-\x{200A}\x{2028}\x{1680}\x{180E}]

ゼロ幅空白文字 |\g<blank>\g<chara>|(?<chara>[\n\s\S])(?<blank>[\x{200B}-\x{200E}\x{2029}\x{202C}\x{202F}\x{205F}\x{2062}\x{2063}\x{FEFF}])

※ 「MeiryoKe_Gothic」 フォントで文字化けして中黒 で表示されるものや、ゼロ幅結合子は含めていない。
  • /JavaScript の正規表現リテラル用/

☑ 大文字小文字を区別  ☑ 正規表現

正規表現リテラル |(?<=^|[{(\[= \t])\/(?![*+?|/)\]])[^\r\n\t]*\/[gmi]{0,3}(?=\s*(?:[.,:;})\]]|//|/\*|$))

※ ある程度の誤爆はやむなし。
スポンサーリンク