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

提供: MeryWiki
ナビゲーションに移動 検索に移動
(同じ利用者による、間の1版が非表示)
1行目: 1行目:
 +
<div id="TOP">__toc__</div>
 +
<br><br>
 
= [[マクロライブラリ]]に投稿したマクロ =
 
= [[マクロライブラリ]]に投稿したマクロ =
  
110行目: 112行目:
 
* [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) <br> 山本隆 氏作成の [http://gesource.jp/soft/strconv/strconvdll.html 文字変換ライブラリ StrConvDLL] の機能をポップアップメニューにまとめたマクロ
 
* [https://pastebin.com/Bci0eEx2 gPad用 文字数・行数・ヒット数] (uploaded: 2019/08/26) <br> Mery 用マクロ「[[検索ヒット数表示(選択文字列)#機能強化バージョン|文字数・行数・ヒット件数(選択文字列)]]」を [https://mfactory.me/ gPad] 用に改編したもの
 
* [https://pastebin.com/Bci0eEx2 gPad用 文字数・行数・ヒット数] (uploaded: 2019/08/26) <br> Mery 用マクロ「[[検索ヒット数表示(選択文字列)#機能強化バージョン|文字数・行数・ヒット件数(選択文字列)]]」を [https://mfactory.me/ gPad] 用に改編したもの
 +
 +
 +
[[#TOP|>> 目次へ]]
  
  
116行目: 121行目:
 
== リンク ==
 
== リンク ==
 
* [[マクロライブラリ#その他|マクロライブラリ]] にある ks 氏らの「[[マクロ覚え書き(開発者向け)|マクロ覚え書き]]」
 
* [[マクロライブラリ#その他|マクロライブラリ]] にある ks 氏らの「[[マクロ覚え書き(開発者向け)|マクロ覚え書き]]」
* 黄身氏の「[[利用者:黄身#覚え書き|覚え書き]]」 <br>
+
* 黄身氏の「[[利用者:黄身#覚え書き|覚え書き]]」<br>
 
* MeryWiki の [[マクロリファレンス]]
 
* MeryWiki の [[マクロリファレンス]]
 +
* MeryWiki の [[よくある質問|FAQ]]
 
* [https://www.haijin-boys.com/discussions Mery 公式フォーラム] <br>
 
* [https://www.haijin-boys.com/discussions Mery 公式フォーラム] <br>
 
* 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 リファレンス] <br>
162行目: 168行目:
 
ポップアップメニューのラベルの文字列に「半角アンパサンド記号('''&''') + 半角英数字 (またはアスキー記号)」を付記することで、アクセラレータ(アクセスキー)を設定することができる。<br>
 
ポップアップメニューのラベルの文字列に「半角アンパサンド記号('''&''') + 半角英数字 (またはアスキー記号)」を付記することで、アクセラレータ(アクセスキー)を設定することができる。<br>
 
ラベルの先頭に連番数字などがある場合は、アンパサンド記号を付加することで、数字をアクセラレータにするとよい。<br>
 
ラベルの先頭に連番数字などがある場合は、アンパサンド記号を付加することで、数字をアクセラレータにするとよい。<br>
そのさい、Shift キー付きでの入力が必要な記号は Shift キーなしで入力可能なキーのラベルと同一視される (e.g. 「&#」で "'''#'''" 記号をアクセラレータに指定した場合、JIS 配列のキーボードでは ['''2'''] キーがアクセラレータになる)。<br>
+
そのさい、Shift キー付きでの入力が必要な記号は Shift キーなしで入力可能なキーのラベルと同一視される (e.g. 「'''&#'''」で "'''#'''" 記号をアクセラレータに指定した場合、JIS 配列のキーボードでは ['''2'''] キーがアクセラレータになる)。<br>
また、「& 」(半角アンパサンド+半角空白) で半角スペースをアクセラレータに指定したアイテムは、スペースキーがアクセスキーになる。
+
また、「'''& '''」(半角アンパサンド+半角空白) で半角スペースをアクセラレータに指定したアイテムは、スペースキーがアクセスキーになる。
  
 
* <span style="color:#c00;">"'''&'''" 記号でアクセラレータ化する文字の位置は限定されないが、<u>最初の "'''&'''" 記号のうしろの文字がアクセラレータになる</u></span>( … とおもわれる ← ポップアップメニュー内で「下線つきで表示される文字」と一致しないことがある)。
 
* <span style="color:#c00;">"'''&'''" 記号でアクセラレータ化する文字の位置は限定されないが、<u>最初の "'''&'''" 記号のうしろの文字がアクセラレータになる</u></span>( … とおもわれる ← ポップアップメニュー内で「下線つきで表示される文字」と一致しないことがある)。
 
* <span style="color:#c00;">全角文字はアクセラレータにできない。</span>
 
* <span style="color:#c00;">全角文字はアクセラレータにできない。</span>
* <span style="color:#c00;">ラベル文字列に含まれる "'''&'''" 記号はすべてエスケープされてしまい、ポップアップメニューには表示されなくなるので、ラベルに "'''&'''" 記号を表示させたいときは、"'''&&'''" のように二重に記述する必要がある。</span><br> → 不特定の文字列をラベルにする場合は、あらかじめ String.replace( /&/g, "&&" ) と記述するとよい。
+
* <span style="color:#c00;">ラベル文字列に含まれる "'''&'''" 記号はすべてエスケープされてしまい、ポップアップメニューには表示されなくなるので、ラベルに "'''&'''" 記号を表示させたいときは、"'''&&'''" のように二重に記述する必要がある。</span><br> → 不特定の文字列をラベルにする場合は、あらかじめ ''String.replace( /&/g, "&&" )'' と記述するとよい。
* <span style="color:#c00;">同じキーが重複してアクセラレータに指定されていると、そのキーを押した場合、アイテム間をトグル移動する(→ [Enter] キーで決定する)。</span>
+
* <span style="color:#c00;">同じキーが重複してアクセラレータに指定されていると、そのキーを押した場合、アイテム間をトグル移動する(→ その場合は [Enter] キーで決定する)。</span><br> → アイテム数が多くなるメニューの場合、''menu.Add( "キャンセル & ", 0 );'' という行を 10 件とか 20 件ごとに挿入すると、スペースキーでポップアップメニュー内をスクロールさせることができる。
 
<source lang="javascript">
 
<source lang="javascript">
 +
/* アクセラレータを付加する */
 +
 
var menu = CreatePopupMenu();
 
var menu = CreatePopupMenu();
 
var piyo = "LOVE & PEACE & ...";
 
var piyo = "LOVE & PEACE & ...";
180行目: 188行目:
 
menu.Add( piyo + "(&6)", 6 ); // スペースキーがアクセラレータ
 
menu.Add( piyo + "(&6)", 6 ); // スペースキーがアクセラレータ
 
menu.Add( "※※※※", 0, meMenuSeparator ); // meMenuSeparator があると第一引数の文字列は無視される
 
menu.Add( "※※※※", 0, meMenuSeparator ); // meMenuSeparator があると第一引数の文字列は無視される
menu.Add( "キャンセル & ", 0 ); // スペースキーがアクセラレータ
+
menu.Add( "キャンセル & ", 0 ); // スペースキーがアクセラレータ
  
 
// 5つめのアイテムは "LOVE & PEACE & ..." と表示されるが
 
// 5つめのアイテムは "LOVE & PEACE & ..." と表示されるが
 
// 6つめのアイテムは "LOVE  PEACE  ..." と表示される  
 
// 6つめのアイテムは "LOVE  PEACE  ..." と表示される  
// ※ 5つめのアイテムと最後のアイテムでアクセラレータが重複している
 
  
var ret = menu.Track();
+
// ※ 6つめのアイテムと最後のアイテムでアクセラレータが重複している
 +
 
 +
var ret = menu.Track( 0 );
 +
</source>
 +
<source lang="javascript">
 +
/* 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 ), i + 1 );
 +
}
 +
 
 +
var y = menu.Track( 0 );
 +
if ( y ) {
 +
  Document.Selection.SetActivePoint( mePosLogical, 1, y );
 +
}
 
</source>
 
</source>
  
  
 
=== ラベルの整形 ===
 
=== ラベルの整形 ===
ポップアップメニュー(警告・確認ダイアログなどもだが)は UI フォントで表示されるので、文字列が英数字の羅列の場合には読みづらい ( …と個人的に感じている)。<br>
+
基本的にポップアップメニュー(警告・確認ダイアログなどもだが)は UI フォントで表示されるので、文字列が英数字の羅列の場合には読みづらい ( …と個人的に感じている)。<br>
 
文書内の文字列など不特定の文字列をラベル化する「[[ポップアップメニューで検索先にジャンプ#sukemaru 版|検索ジャンプ]]」や「[[ブックマーク一覧ジャンプ#sukemaru 版|ブックマークジャンプ]]」、「[[「クリップボード履歴」メニューのマクロ化|クリップボード履歴メニュー]]」マクロでは、読みづらい半角アルファベットや記号を全角化させるなどしている。
 
文書内の文字列など不特定の文字列をラベル化する「[[ポップアップメニューで検索先にジャンプ#sukemaru 版|検索ジャンプ]]」や「[[ブックマーク一覧ジャンプ#sukemaru 版|ブックマークジャンプ]]」、「[[「クリップボード履歴」メニューのマクロ化|クリップボード履歴メニュー]]」マクロでは、読みづらい半角アルファベットや記号を全角化させるなどしている。
 
<source lang="javascript">
 
<source lang="javascript">
200行目: 229行目:
 
  *  
 
  *  
 
  * ・行頭空白を除去
 
  * ・行頭空白を除去
  * ・空白文字を圧縮: →「›」(U+203A) に置換
+
  * ・空白文字を圧縮: →「›」(U+203A) に置換
 
  * ・文字数を切り詰め(String.slice メソッド)
 
  * ・文字数を切り詰め(String.slice メソッド)
  * ・改行記号を可視化: →「⏎」(U+23CE)に置換
+
  * ・改行記号を可視化: →「⏎」(U+23CE) に置換
 
  * ・削られてしまう「&」を補完
 
  * ・削られてしまう「&」を補完
 
  * ・「¥」(U+005C) を「∖」(U+2216) に置換
 
  * ・「¥」(U+005C) を「∖」(U+2216) に置換
237行目: 266行目:
 
// ※ 連番が多い場合は「番号を空白文字でケタ埋め (右端揃え)」などの処理も追加するとよい
 
// ※ 連番が多い場合は「番号を空白文字でケタ埋め (右端揃え)」などの処理も追加するとよい
 
</source>
 
</source>
 +
 +
 +
ただし、Mery のダイアログのフォントは Mery.ini の「[[よくある質問#ダイアログのフォントを変更したい|隠しオプション]]」により任意のフォントに変更可なので、個人的にしか使わない非公開マクロであれば気にする必要はないかも。
  
  
 
=== 配列からポップアップメニューを生成 ===
 
=== 配列からポップアップメニューを生成 ===
[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/for_Statement ループ処理] によって配列からポップアップメニューのアイテムを生成する場合に、[[マクロリファレンス: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/for_Statement ループ処理] によって配列からポップアップメニューのアイテムを生成する場合に、[[マクロリファレンス:PopupMenu インターフェイス#Add メソッド|PopupMenu.Add() メソッド]] の第二引数 '''Id''' (※通常は 1 ~ )と配列のアイテムのインデックス '''[ i ]''' の値(※通常は 0 ~ )を一致させたいときは、配列の先頭にダミーまたは空の要素を置いておき、ループ処理の開始インデックスを 1 にする。
 
<source lang="javascript">
 
<source lang="javascript">
 
var a = new Array( "" ); // 先頭に空のダミー要素を入れておく
 
var a = new Array( "" ); // 先頭に空のダミー要素を入れておく
265行目: 297行目:
 
=== サブメニュー ===
 
=== サブメニュー ===
 
* 配列やオブジェクトからポップアップメニューを生成するさいにサブメニューを利用する場合、あらかじめサブメニューのラベルや各要素の振り分け方が決まっていれば難しいことはないが、要素が不定数の配列やオブジェクトをサブメニューに振り分けるのは簡単ではない。
 
* 配列やオブジェクトからポップアップメニューを生成するさいにサブメニューを利用する場合、あらかじめサブメニューのラベルや各要素の振り分け方が決まっていれば難しいことはないが、要素が不定数の配列やオブジェクトをサブメニューに振り分けるのは簡単ではない。
 +
<br>
 
: 「[[階層化マクロメニュー]]」マクロなどのソースコードを参考にしてコードを組むか、組み込み関数「[[ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する]]」で一定数ごとにサブメニュー項目を自動生成して要素を放り込むしかない…。
 
: 「[[階層化マクロメニュー]]」マクロなどのソースコードを参考にしてコードを組むか、組み込み関数「[[ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する]]」で一定数ごとにサブメニュー項目を自動生成して要素を放り込むしかない…。
 
<br>
 
<br>
274行目: 307行目:
 
=== マクロの動作設定を変更可能にする ===
 
=== マクロの動作設定を変更可能にする ===
 
拙作マクロは、ポップアップメニューを使うものにかぎらず動作設定用の項目が多い。<br>
 
拙作マクロは、ポップアップメニューを使うものにかぎらず動作設定用の項目が多い。<br>
ポップアップメニューマクロでないものは、通常、頻繁に動作設定を弄る必要はないが、sukemaru 好みの動作方式は一般的嗜好と合致しないであろうことから公開用のマクロにするにあたってカスタマイズ可能な「設定項目」に調整しなおすことが多い。
+
ポップアップメニューマクロでないものは、通常、頻繁に動作設定を弄る必要はないが、sukemaru 好みの動作方式は一般的嗜好と合致しないであろうことから公開用のマクロにするにあたってカスタマイズ可能な「設定項目」に調整しなおすことが多い…。
 
<br><br>
 
<br><br>
 
ポップアップメニューマクロであれば、メニュー項目から動作設定をカスタマイズできるようにコーディングすることができる。
 
ポップアップメニューマクロであれば、メニュー項目から動作設定をカスタマイズできるようにコーディングすることができる。
281行目: 314行目:
 
: 動作設定の変更内容はマクロの完了時に破棄されてしまうので、連続して同じマクロを利用する場合には、ソースコードの既定値を書き換えてカスタマイズしておくとよい。
 
: 動作設定の変更内容はマクロの完了時に破棄されてしまうので、連続して同じマクロを利用する場合には、ソースコードの既定値を書き換えてカスタマイズしておくとよい。
 
* sukemaru の場合は、「[[ポップアップメニューで検索先にジャンプ#include版|検索ジャンプ]]」「[[ブックマーク一覧ジャンプ#include版|ブックマークジャンプ]]」や「[[ファイルを読み直す・開きなおす#include版|読みなおし]]」マクロなどで、【include 版】と称するものを作っている。
 
* sukemaru の場合は、「[[ポップアップメニューで検索先にジャンプ#include版|検索ジャンプ]]」「[[ブックマーク一覧ジャンプ#include版|ブックマークジャンプ]]」や「[[ファイルを読み直す・開きなおす#include版|読みなおし]]」マクロなどで、【include 版】と称するものを作っている。
: これらにおいては、[[includeライブラリ|include ライブラリ]] の IO クラス(IO.js)の Serialize() / Deserialize() を利用して、ポップアップメニュー内の「設定変更」サブメニューから変更した設定値を外部ファイル(JSON ファイル)に保持できるようにしている。
+
: これらにおいては、[[includeライブラリ|include ライブラリ]] の IO クラス(IO.js)の関数メソッド Serialize() / Deserialize() を利用して、ポップアップメニュー内の「設定変更」サブメニューから変更した設定値を外部ファイル(JSON ファイル)に保持できるようにしている。
 
: 動作設定を同じままで再実行するのも、カスタマイズしながら再実行するのも容易にはなったが、コードが煩雑になって他のマクロに流用しづらくなってしまっている…。
 
: 動作設定を同じままで再実行するのも、カスタマイズしながら再実行するのも容易にはなったが、コードが煩雑になって他のマクロに流用しづらくなってしまっている…。
 
: ※ 非 include 版では、「設定変更」サブメニューや masme 氏のマクロのような処理コードは入れず、動作設定の変更方法はソースコードの変数の値の書き換えのみとしている。
 
: ※ 非 include 版では、「設定変更」サブメニューや masme 氏のマクロのような処理コードは入れず、動作設定の変更方法はソースコードの変数の値の書き換えのみとしている。
 +
 +
 +
[[#TOP|>> 目次へ]]
  
  
306行目: 342行目:
  
 
== Collapse() メソッド とキャレット位置 ==
 
== Collapse() メソッド とキャレット位置 ==
[[マクロリファレンス:Selection インターフェイス#Collapse メソッド|Selection.Collapse() メソッド]] で引数 ''meCollapseEnd'' を指定した場合は
+
[[マクロリファレンス:Selection インターフェイス#Collapse メソッド|Selection.Collapse() メソッド]] で引数 '''''meCollapseEnd''''' を指定した場合は
 
  Selection.SetActivePos( Selection.GetActivePos() )  
 
  Selection.SetActivePos( Selection.GetActivePos() )  
''meCollapseStart'' を指定した場合は
+
'''''meCollapseStart''''' を指定した場合は
 
  Selection.SetActivePos( Selection.SetAnchorPos() )
 
  Selection.SetActivePos( Selection.SetAnchorPos() )
 
と意味的には同じである。
 
と意味的には同じである。
314行目: 350行目:
 
※ 引数を省略した場合は ''meCollapseStart'' として動作する。<br>
 
※ 引数を省略した場合は ''meCollapseStart'' として動作する。<br>
 
※ ''meCollapseStart / meCollapseEnd'' はそれぞれ「選択開始位置」と「選択終了位置 (キャレット位置)」を指し、「選択範囲の 先頭/末尾」ではない。<br>
 
※ ''meCollapseStart / meCollapseEnd'' はそれぞれ「選択開始位置」と「選択終了位置 (キャレット位置)」を指し、「選択範囲の 先頭/末尾」ではない。<br>
※ [[マクロリファレンス:Selection インターフェイス#SelectLine メソッド|Selection.SelectLine()]] や [[マクロリファレンス:Selection インターフェイス#SelectWord メソッド|Selection.SelectWord()]] などでの範囲選択では「キャレット位置=選択範囲の末尾」となり、[[マクロリファレンス:Selection インターフェイス#Find メソッド|Selection.Find()]] や [[マクロリファレンス:Selection インターフェイス#FindRepeat メソッド|Selection.FindRepeat()]] での範囲選択では「キャレット位置=選択範囲の先頭」なので、つづけて Collapse() メソッドを使用するする場合には注意が必要。
+
※ [[マクロリファレンス:Selection インターフェイス#SelectLine メソッド|Selection.SelectLine()]] や [[マクロリファレンス:Selection インターフェイス#SelectWord メソッド|Selection.SelectWord()]] などでの範囲選択では「キャレット位置=選択範囲の末尾」となり、[[マクロリファレンス:Selection インターフェイス#Find メソッド|Selection.Find()]] や [[マクロリファレンス:Selection インターフェイス#FindRepeat メソッド|Selection.FindRepeat()]] での範囲選択では「キャレット位置=選択範囲の先頭」なので、つづけて Collapse() メソッドを使用するする場合には注意が必要 (…でもないか)。
 
<br><br>
 
<br><br>
  
332行目: 368行目:
 
  &#32;8: meFindAround 文書の末尾まで検索したら先頭から検索を開始します。
 
  &#32;8: meFindAround 文書の末尾まで検索したら先頭から検索を開始します。
 
  16: meFindReplaceRegExp 正規表現で検索します。
 
  16: meFindReplaceRegExp 正規表現で検索します。
 
+
<br><br>
 
: 「検索/置換」ダイアログのオプションフラグをすべて OFF にする方法として
 
: 「検索/置換」ダイアログのオプションフラグをすべて OFF にする方法として
 
<source lang="javascript">
 
<source lang="javascript">
338行目: 374行目:
 
</source>
 
</source>
 
: というコードを挟み込むという手がある(第二引数には 0 または 1 を指定する)。
 
: というコードを挟み込むという手がある(第二引数には 0 または 1 を指定する)。
: これは、マクロ実行時に「[[ヘルプ:検索|検索/置換]]」ダイアログが開かれていないときにかぎり、マクロ終了後の「検索/置換」ダイアログのオプション項目のチェック ON/OFF の状態にも引き継がれる(次回の「検索/置換」や「[[ヘルプ:検索#次を検索|次/前を検索]]」「[[ヘルプ:検索#次の文字列を検索|次/前の文字列を検索]]」コマンドなどに引き継がれる)。
+
: これは、マクロ実行時に「[[ヘルプ:検索|検索/置換]]」ダイアログが開かれていないときにかぎり、マクロ終了後の「検索/置換」ダイアログのオプション項目のチェック ON/OFF の状態にも引き継がれる(次回の「検索/置換」や「[[ヘルプ:検索#次を検索|次/前を検索]]」「[[ヘルプ:検索#次の文字列を検索|次/前の文字列を検索]]」コマンドなどにも引き継がれる)。
  
 
: ※ ただし、「終了したら閉じる」と、[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] で追加された「インクリメンタルサーチ」のオプションフラグはマクロから解除することができない。
352行目: 388行目:
 
  &#32;2: meFindRepeatWord 選択範囲が空の場合はカーソル位置の単語を検索します。
 
  &#32;2: meFindRepeatWord 選択範囲が空の場合はカーソル位置の単語を検索します。
  
: FindRepeat() メソッドでは定数 ''meFindReplaceCase'' や ''meFindReplaceOnlyWord , meFindAround , meFindReplaceRegExp'' が使用できないが、<span style="color:#0000c0;">'''直前'''の「検索/置換」コマンドや Find() / Replace() メソッドで使用したこれらのオプションのうち ''meFindReplaceRegExp'' 以外の三つの ON/OFF 状態が'''継承'''される。</span>
+
: FindRepeat() メソッドでは定数 ''meFindReplaceCase'' や ''meFindReplaceOnlyWord , meFindAround , meFindReplaceRegExp'' が使用できないが、 <span style="color:#0000c0;">'''直前''' の「検索/置換」コマンドや Find() / Replace() メソッドで使用したこれらのオプションのうち ''meFindReplaceRegExp'' 以外の三つの ON/OFF 状態が '''継承''' される。</span>
  
 
: よって、FindRepeat() メソッドで ''meFindReplaceCase'' や ''meFindReplaceOnlyWord , meFindAround'' を適用した検索をしたいばあいは、以下のように記述する。
 
: よって、FindRepeat() メソッドで ''meFindReplaceCase'' や ''meFindReplaceOnlyWord , meFindAround'' を適用した検索をしたいばあいは、以下のように記述する。
362行目: 398行目:
 
// 2.「前回検索した文字列を検索」または キャレット位置の単語で「次の文字列を検索」
 
// 2.「前回検索した文字列を検索」または キャレット位置の単語で「次の文字列を検索」
 
document.selection.FindRepeat( meFindNext + meFindRepeatWord );
 
document.selection.FindRepeat( meFindNext + meFindRepeatWord );
 +
 +
// -------------------------------------------------- //
  
 
// 3.最後にオプションフラグを解除しておきたいなら
 
// 3.最後にオプションフラグを解除しておきたいなら
 
document.selection.Find( "", 0 );
 
document.selection.Find( "", 0 );
 +
</source>
 +
: ref. 『[https://www.haijin-boys.com/discussions/3398 空検索の動作、など]』
 +
 +
 +
== 変換・挿入した文字列を範囲選択するとき ==
 +
<source lang="javascript">
 +
var str = "hoge";
 +
document.Write( str ); // または document.selection.text = str;
 +
</source>
 +
のあとで文字列 ''str'' ('''hoge''')を範囲選択したい場合は、''[[マクロリファレンス:Selection インターフェイス#CharLeft メソッド|document.selection.CharLeft]]( str.length, true );'' ではなく
 +
<source lang="javascript">
 +
document.selection.SetActivePos( document.selection.GetActivePos() - str.length, true );
 +
// または
 +
// document.selection.SetAnchorPos( document.selection.GetActivePos() - str.length );
 +
</source>
 +
と記述すること。
 +
<br><br>
 +
※ CharLeft( str.length, true ) の場合、文字列 ''str'' が「折り返し」にかかってしまったときに想定どおりの選択範囲にならない。
 +
: ref. 『[https://www.haijin-boys.com/discussions/3740 "折り返し表示" での CharRight( document.selection.Text.length - 1 ) について]』
 +
 +
 +
== 複数行の論理行を範囲選択(末尾改行を含まない) ==
 +
: ref. 『[https://www.haijin-boys.com/discussions/4431 マクロについてアドバイスお願いします]』
 +
 +
 +
== 文字列操作が空振りしたときは undo 履歴に残さない ==
 +
条件付きで文字列操作(挿入・置換など)するマクロ
 +
<source lang="javascript">
 +
// e.g. 選択範囲に「hoge」が含まれなければ置換しない
 +
var fuga = document.selection.Text.replace( /hoge/g, "fuga" );
 +
document.selection.Text = fuga;
 +
</source>
 +
が空振りしたときに、上のようなコードの場合は '''undo''' 履歴が無駄に残ったり、文書に「'''未保存 *'''」のフラグが付加されたりする(大文字/小文字変換の [[マクロリファレンス:Selection インターフェイス#ChangeCase メソッド|ChangeCase() メソッド]] や全角/半角変換の [[マクロリファレンス:Selection インターフェイス#ChangeWidth メソッド|ChangeWidth() メソッド]] なども、日本語文などでは空振りするが undo 履歴に残る)。
 +
<br><br>
 +
「文字列操作の前後で "変化なし" なら undo 履歴には残さない」ようにコーディングすると、[https://www.haijin-boys.com/software/mery/mery-2-6-9#4 変更行の強調表示] なども無用に付かなくなる。
 +
<source lang="javascript">
 +
// e.g. 選択範囲に「hoge」が含まれなければ置換しない
 +
var st = document.selection.Text;
 +
var piyo = st.replace( /hoge/g, "piyo" );
 +
 +
if ( st != piyo ) {
 +
  document.selection.Text = piyo;
 +
}
 
</source>
 
</source>
  
393行目: 474行目:
  
 
※ スクロールマージンは [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>
+
 
 +
 
 +
[[#TOP|>> 目次へ]]
 +
 
  
 
== カレントディレクトリ ==
 
== カレントディレクトリ ==
664行目: 748行目:
 
Status = "Error Test";
 
Status = "Error Test";
 
</source>
 
</source>
 +
 +
 +
[[#TOP|>> 目次へ]]
  
  
697行目: 784行目:
 
: ReplaceStr.txt / ImageViewURLReplace.dat / URLExec.dat / command.dat に対応
 
: ReplaceStr.txt / ImageViewURLReplace.dat / URLExec.dat / command.dat に対応
 
: ※ [http://k-takata.o.oo7.jp/mysoft/bregonig.html bregonig] の正規表現のハイライト可 (基本的に [https://github.com/k-takata/Onigmo/blob/master/doc/RE.ja onigmo] の正規表現にも利用可)
 
: ※ [http://k-takata.o.oo7.jp/mysoft/bregonig.html bregonig] の正規表現のハイライト可 (基本的に [https://github.com/k-takata/Onigmo/blob/master/doc/RE.ja onigmo] の正規表現にも利用可)
 +
 +
 +
[[#TOP|>> 目次へ]]
  
  
721行目: 811行目:
 
: マクロバーのアイテム数 16 件、ラベルあり(#title="hoge" の文字数を切りつめてやり繰り)
 
: マクロバーのアイテム数 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>
 
: [[ファイル: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>
 +
 +
 +
[[#TOP|>> 目次へ]]

2019年10月12日 (土) 19:44時点における版

目次



マクロライブラリに投稿したマクロ

「テキスト操作補助」 カテゴリ

インデント/逆インデント
カッコで囲う (簡易版 ポップアップメニューなし)
引用符を追加/削除  ※"二重引用符" の追加/削除トグル



「ファイル操作補助」 カテゴリ

「他(右側/左側)のタブを閉じる」 などを追加
エンコード指定で読み直し・読み取り専用属性の変更・編集モードの変更・プロパティを開く・さいごに閉じたファイルを開く・etc.



「変換・ソート・整形」 カテゴリ

+ 改造版「ToDoリストモード[1]」 (added: 2019/05/06)


「検索・置換」 カテゴリ

+ 機能強化版「文字数・行数・ヒット件数(選択文字列)」 ※イベントマクロ (last modified: 2019/08/28)


検索ジャンプ 【include版】


「プログラミング補助」 カテゴリ

  • 行コメント (last modified: 2019/04/07) ※コメントマーク付け外し


「実験的マクロ・練習マクロなど」 カテゴリ

サンプルコード: 「特定の条件で縦書きモードに切りかえる」(※ ver 2.6.5 - 2.7.5 用)



ブックマークを復元


「その他」 カテゴリ

サンプルコード: 「Begin/EndUndoGroup() メソッドを使えるのは ver 2.7.0 以降」
サンプルコード: 「すべての論理行をポップアップメニューに表示する」




外部サイトに投稿したマクロ


>> 目次へ


マクロ覚え書き

リンク




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


アイコン化したマクロ

通常、フォーカスがアウトプットバーやアウトラインペイン、検索/置換ダイアログにあると、ポップアップメニューやショートカットキーからマクロを起動することはできない。
しかし、Document オブジェクトのかわりに Editor.ActiveDocument で記述したマクロであれば、エディタ領域にフォーカスがない場合でもツールバーアイコンやマクロメニューからマクロを起動できる。

※ ただし、アクティブなタブ以外を操作・編集するマクロにおいては Editor.Documents.Item( dd ) などのような記述が必要。

マクロをツールバー/マクロバーから使用するために アイコン を作ったり、マクロバーにアイコンを詰め込むために 試行錯誤 したりも…。


ポップアップメニュー

オプションフラグ

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

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

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

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

menu.Add( "Hoge", 1, + hoge );		// "+" を付けて数値化すると meMenuChecked
menu.Add( "Fuga", 2, !fuga * 2 );	// (!fuga = 1) *2 なので meMenuGrayed
var num = menu.Track( mePosMouse );


アクセラレータ

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

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

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 ), i + 1 );
}

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


ラベルの整形

基本的にポップアップメニュー(警告・確認ダイアログなどもだが)は UI フォントで表示されるので、文字列が英数字の羅列の場合には読みづらい ( …と個人的に感じている)。
文書内の文字列など不特定の文字列をラベル化する「検索ジャンプ」や「ブックマークジャンプ」、「クリップボード履歴メニュー」マクロでは、読みづらい半角アルファベットや記号を全角化させるなどしている。

/**
 * ポップアップメニューに表示するラベルを整形する
 * 
 * ※ 不要な置換については .replace( ... ) の行を 削除/コメントアウト してよい
 * 
 * ・行頭空白を除去
 * ・空白文字を圧縮:		→「›」(U+203A) に置換
 * ・文字数を切り詰め(String.slice メソッド)
 * ・改行記号を可視化:	→「⏎」(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 menuKey = str.replace( /^[\t  ]+/, "" )
                 .replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " )
                 .slice( 0, menuWidth )
                 .replace( /\r?\n/g, "⏎ " )
                 .replace( /[&]/g, "&&" )
                 .replace( /[\\]/g, "∖" )
                 .replace( /[\u00A0\u1680\u180e\u2000-\u200A\u2028\u2029\u202F\u205F\uFEFF]/g, "▯" )
                 .replace( /[!"%'(),.:;@\[\]`a-z{|}]/g,
                   function( tmp ) {
                     return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
                   } );

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

// ※ アクセラレータつきの番号を付加
menuKey = "&" + y + ": " + menuKey;

// ※ 番号の 一の位 をアクセラレータにするなら
// menuKey = String( y ).replace( /\d$/, "&" + "$&" ) + ": " + menuKey;

// ※ 連番が多い場合は「番号を空白文字でケタ埋め (右端揃え)」などの処理も追加するとよい


ただし、Mery のダイアログのフォントは Mery.ini の「隠しオプション」により任意のフォントに変更可なので、個人的にしか使わない非公開マクロであれば気にする必要はないかも。


配列からポップアップメニューを生成

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 ++ ) {	// 開始値を 1 にすると
  menuA.Add( a[i], i );					// Id を ( i + 1 ) にする必要がない
}
var num = 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 )
}


サブメニュー

  • 配列やオブジェクトからポップアップメニューを生成するさいにサブメニューを利用する場合、あらかじめサブメニューのラベルや各要素の振り分け方が決まっていれば難しいことはないが、要素が不定数の配列やオブジェクトをサブメニューに振り分けるのは簡単ではない。


階層化マクロメニュー」マクロなどのソースコードを参考にしてコードを組むか、組み込み関数「ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する」で一定数ごとにサブメニュー項目を自動生成して要素を放り込むしかない…。


サブメニュー内のすべてのアイテムが無効(グレーアウト)になる条件でも、サブメニュー見出しを無効化することはできないので、サブメニュー見出しが表示されなくなるように PopupMenu.AddPopup() 周りを if() 文で囲うしかない。
上の「自動分割サブメニュー」の組み込み関数を制作するさい、チェックつきアイテムを含むサブメニュー見出しにもチェックを付けられるようにしたかったが、これも無理だった。


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

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

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

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


>> 目次へ


選択範囲の 先頭位置/末尾位置

選択範囲の 開始(キャレットなし)/終了(キャレットあり) の位置は 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;


Collapse() メソッド とキャレット位置

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

Selection.SetActivePos( Selection.GetActivePos() ) 

meCollapseStart を指定した場合は

Selection.SetActivePos( Selection.SetAnchorPos() )

と意味的には同じである。

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

Find() メソッド と FindRepeat() メソッド の 定数

定数 の数値は

Alert( meFindNext );

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

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

 0: meFindPrevious		カーソル位置から前を検索します。
 1: meFindNext			カーソル位置から次を検索します。
 2: meFindReplaceCase		検索する単語の大文字と小文字を区別します。
 4: meFindReplaceOnlyWord	完全に一致する単語を検索します。
 8: meFindAround		文書の末尾まで検索したら先頭から検索を開始します。
16: meFindReplaceRegExp		正規表現で検索します。



「検索/置換」ダイアログのオプションフラグをすべて OFF にする方法として
document.selection.Find( "", 0 );	// 空文字列の検索でオプションフラグを解除する
というコードを挟み込むという手がある(第二引数には 0 または 1 を指定する)。
これは、マクロ実行時に「検索/置換」ダイアログが開かれていないときにかぎり、マクロ終了後の「検索/置換」ダイアログのオプション項目のチェック ON/OFF の状態にも引き継がれる(次回の「検索/置換」や「次/前を検索」「次/前の文字列を検索」コマンドなどにも引き継がれる)。
※ ただし、「終了したら閉じる」と、ベータ版 2.6.10 で追加された「インクリメンタルサーチ」のオプションフラグはマクロから解除することができない。
meFindReplaceOnlyWordmeFindReplaceRegExp は排他関係なので、同時に使用した場合 meFindReplaceRegExp は適用されるが meFindReplaceOnlyWord は無視される
(検索ダイアログで「正規表現」オプションを有効化したときに「単語のみ」オプションが無効になるのと同様)。


FindRepeat() メソッド
document.selection.FindRepeat() メソッド
前回検索した文字列を検索します。 

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

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

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

// 3.最後にオプションフラグを解除しておきたいなら
document.selection.Find( "", 0 );
ref. 『空検索の動作、など


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

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

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

document.selection.SetActivePos( document.selection.GetActivePos() - str.length, true );
// または
// document.selection.SetAnchorPos( document.selection.GetActivePos() - str.length );

と記述すること。

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

ref. 『"折り返し表示" での CharRight( document.selection.Text.length - 1 ) について


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

ref. 『マクロについてアドバイスお願いします


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

条件付きで文字列操作(挿入・置換など)するマクロ

// e.g. 選択範囲に「hoge」が含まれなければ置換しない
var fuga = document.selection.Text.replace( /hoge/g, "fuga" );
document.selection.Text = fuga;

が空振りしたときに、上のようなコードの場合は undo 履歴が無駄に残ったり、文書に「未保存 *」のフラグが付加されたりする(大文字/小文字変換の ChangeCase() メソッド や全角/半角変換の ChangeWidth() メソッド なども、日本語文などでは空振りするが undo 履歴に残る)。

「文字列操作の前後で "変化なし" なら undo 履歴には残さない」ようにコーディングすると、変更行の強調表示 なども無用に付かなくなる。

// e.g. 選択範囲に「hoge」が含まれなければ置換しない
var st = document.selection.Text;
var piyo = st.replace( /hoge/g, "piyo" );

if ( st != piyo ) {
  document.selection.Text = piyo;
}


スクロール位置の調整

キャレットをジャンプさせた後のスクロール位置とキャレット位置は、移動先の行(表示座標での行番号)がエディタの表示領域の高さに収まるかどうかとジャンプ方向によるので安定的ではない(スクロールマージンの考慮も必要)。
以下のコードは、ジャンプ後にエディタの表示領域がスクロールした場合に、キャレットが表示領域の 先頭位置(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 より「オプション」ダイアログの「スクロール」のページ内で変更できるようになっている。[2]


>> 目次へ


カレントディレクトリ

カレントディレクトリ(作業フォルダ)は、Mery を起動したときに決定され、一定ではない。
記述の都合上で相対パスを利用するために特定のカレントディレクトリを指定するマクロもあるが、「あえて流動的なカレントディレクトリを利用する」ようなコードが続く場合は、カレントディレクトリを書きもどす必要がある。

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

var meryIni = Editor.FullName.replace( /exe$/, "ini" );

if ( fso.FileExists( meryIni ) ) {
  // メモ帳で Mery.ini を開く
  wshShell.Run( "notepad \"" + meryIni + "\"" );
}
else {
  // マクロ実行前の作業フォルダを保存
  var currentDir = wshShell.CurrentDirectory;

  // 相対パス解決のためにカレントディレクトリを設定	e.g. %AppData%\Mery
  wshShell.CurrentDirectory = wshShell.SpecialFolders( "APPDATA" ) + "\\Mery";
  wshShell.Run( "notepad " + "Mery.ini" );
  
  // マクロ実行前の作業フォルダを復帰
  wshShell.CurrentDirectory = currentDir;
}


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

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

  • JavaScript には特定のプロパティがオブジェクト配下に定義されているかを調べる方法も色々とあるが、親オブジェクトのタイプやプロパティ・定数のタイプ、JavaScript(JScript)のバージョンによる互換性などへの考慮が必要になる。 [3][4][5]


  • 専用の 組み込み関数 VersionCheck() を利用すれば、Mery のバージョン番号を指定して動作要件のチェックができる。
※ あらかじめ、プロパティや定数が導入された Mery のバージョン番号を調べておく必要がある( ← Mery.txt に記載されているはず)。
// ▼ ChangeCase() メソッドで定数 meCaseCapitalize を使えるのは ver 2.6.10 以降

if ( document.Selection.IsEmpty ) {
  document.selection.SelectLine();	// とりあえず行を範囲選択
}

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

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


// 例2. 定数が定義されているかを調べる場合
if ( typeof meCaseCapitalize == "number" ) {	// または meCaseCapitalize==3
  // 「単語の最初の文字を大文字に変換」
  document.selection.ChangeCase( meCaseCapitalize );
}
else {
  // ExecuteCommandByID() で「単語の最初の文字を大文字に変換」
  editor.ExecuteCommandByID( MEID_EDIT_CAPITALIZE = 2116 );
}
// ▼ 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( /mery\.exe$/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 クラス (MeryInfo.js) を利用して Mery.ini からいくつかの設定項目の値や状態を取得することはできるが、制約が非常に多い。

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


拙作の 組み込み関数 GetIniOption()GetIniOption2() はこれらの制約を受けず、とくに後者は Mery.ini のすべての項目にアクセスして値を取得することができる。
ただし、制約がない代わりに組み込み関数自体のコードが長いことや、引数や戻り値が配列であることでコードが煩雑にならざるをえない( ⇔ 配列を使用することで、複数の項目を取得する場合でも Mery.ini ファイルの読み込みを1回におさえられる)。

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

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

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

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

「現在の表示状態」を取得してから ON/OFF を指定しての切り替えを行なうためには、include ライブラリの IO クラスを利用するなどして外部に Mery.ini とは別の設定ファイル (e.g. JSON ファイル) を用意して、切り替え実行のたびに設定ファイルを読み書きする必要がある。
※ この場合、外部ファイルに設定内容をあずける項目の切り替えについては必ずマクロ経由で行なわなければならず、デフォルトの メニュー項目/ツールバーアイコン/ショートカットキー による通常操作でその項目の状態の変更をすると、最新の設定状態(現在の表示状態)と外部ファイルが保持している設定内容とのあいだに齟齬が生じてしまう。

Window オブジェクト

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

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

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)やポップアップメニューを使う方法もある)。
Mery のマクロで利用できるポップアップダイアログは、両方ともサウンドをともない、ボタン操作で閉じるまで作業を中断させてしまうので、あえて作業を一時停止させる必要がある場面以外ではステータス表示を使用するのがよい。
※ ユーザー側がステータス表示を使用するイベントマクロなどを別途で導入していることを考慮すると、マクロの終了時になんらかのイベントが発生するマクロの場合、重要なメッセージはダイアログで出力させるか、マクロ内の動作設定用の変数で出力方法を選択できるようにしておくとなお良い。

また、Mery の Window クラスのメソッド・プロパティを使うほかにも、WSH の WshShell.Popup メソッド によるメッセージボックス利用することもできる。
ダイアログ内の左側のアイコンや [OK], [キャンセル], [はい], [いいえ] などのボタンの種類をカスタマイズでき、指定時間の経過後に自動で閉じさせることもできるが、引数の指定や戻り値の処理が煩雑なので、[はい], [いいえ], [キャンセル] の3ボタンが必要な場合でもなければお勧めはしない…。
※ アイコンなしにすれば、システムのサウンドなしでダイアログを表示できる。

エラー処理

Mery のマクロで例外(エラー)が発生した場合、ダイアログのポップアップにより中断される。
マクロの開発者側にとってはソースファイル内の例外が発生した行に速やかにアクセスできるので便利ではあるが、コードを読むのに不慣れなユーザーにおいてはソースコードを開いたところで何が解決するわけでもない。
エラーダイアログは自家用の自作マクロのメンテナンスのさいには有用であるが、公開用のマクロの場合はユーザーがソースコードに誤った改変を加えてしまう惧れもあるので、基本的に必要性がないといえる。

※ wshShell.Run( "実在しない実行ファイル.exe /間違ったパラメータ" ); のようなコードの場合でも、Mery.exe のエラーとして扱われる。

例外が発生することを予期できたり、例外が発生してもそれを無視してマクロの実行を継続したり回避用の処理に移行させられる場合は、JavaScript の try...catch 文 を組み込むとよい。

// 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 ブロックは処理されない
   * 
   */ ;
}

/*
 * 上で Quit(); や return ***; を記述していない場合は
 * try ... catch 文のあとのコードも処理される
 */ ;
// テスト
try{
  hoge;
} catch(e) {
  Status = e.message;	// 「'hoge' は宣言されていません。」
  Alert(e);				// 「TypeError: 'hoge' は宣言されていません。」
}
Status = "Error Test";


>> 目次へ


その他、拙作マクロについて

  • sukemaru の Mery 運用環境はロースペックの Windows XP sp3 (32bit), JScript 5.8.20587 のノート PC です。
※ 制作したマクロの動作テストは、この XP 機でしかおこなっていません。
※ マクロの動作テストに使用している Mery のバージョンは、最新の "ベータ版" (または最新の "正式版" ver. 2.6.7) のみです。基本的に ver 2.6.7 以降のバージョンで動作するように作成していますので、ver 2.6.6 以前のバージョンでの利用を想定していません(2.6.6 以下での動作確認をしていません)。
※ ZIP 版の Mery でマクロを作成・運用しているので、インストーラ版では正しく動作しないマクロがあるかもしれません。
※ 開発環境が Windows XP なので、変数はすべて var で宣言し、JScript 5.8 の環境で実行できるようにコーディングしています。
  • Mery のオプション設定で「行の表示方法=論理座標 (論理行)」の状態で運用する前提でマクロを作っています。公開しているマクロでは、「表示座標 (表示行)」ベースで Mery を運用している場合でも利用できるように設定項目(変数)を設けるか「行の表示方法」を自動判定するコードを追加していますが、動作が不完全になったり処理がおそくなったりすることがあります。
※「表示座標 (表示行)」ベースでの動作テストはほとんどしていません。
  • ソースコード内ではしばしば unicode 文字を使用していますので、マクロの JS ファイルは UTF-8 形式で保存する前提となっています。
  • ソースコード内の変数名の検索などで「検索ジャンプ」マクロを利用しやすいように(個人的にタグジャンプ系のマクロに馴染めないので)、マクロのコードには半角空白を多用しています。
  • 基本的に、変数名は頭文字が小文字の camelCase に、関数名は頭文字が大文字の TitleCase にしてあります。


  • include ライブラリ (作成: ks 氏)」を利用する【include 版】と利用しない【通常版】とがあるマクロでは、include 版(←自家用)を優先的にメンテ・更新しています。
  • 外部実行ファイル「GetKeyState.exe (作成: pizz 氏)」の導入が必要なものもあります。[6]
  • ポップアップメニューマクロの「設定変更サブメニュー」など、複数のマクロで共通の自作関数を使用しているものがありますが、当面は「include ライブラリ」のような外部ファイルにまとめる予定なしです。
※ すでに公開しているマクロが多いこと、公開用と自家用とでコードの内容がちがうマクロが複数あること、それぞれのマクロごとに関数のコードに改変をくわえていることなどの理由で、関数・クラスを統一しなおして更新メンテするのが困難。



投稿した 構文ファイル

Mery の MSY 構文ファイル用
マクロの JS ファイル(JScript)用
JavaScript 用構文ファイル/入力補完用辞書/スペルチェック用辞書/おまけマクロ を同梱
※ Web 開発向けのキーワードは未収録
ReplaceStr.txt / ImageViewURLReplace.dat / URLExec.dat / command.dat に対応
bregonig の正規表現のハイライト可 (基本的に onigmo の正規表現にも利用可)


>> 目次へ


スクショ

マクロバーのアイコン化

マクロバー (1段目) にアイコンを詰めこむための sukemaru の試行錯誤の遍歴...

  • 共通
システム環境: Windows XP 32bit SP3 (Classic テーマ)
ウインドウサイズ (幅): 約 970 px
アイコンサイズ: 中 (24px)
アイコン:マテリアルデザインっぽいアイコン
標準ツールバー (2段目) のアイコン数: 28 コ


マクロバーのアイコン数 28 コ、ラベルなし、セパレータあり( #begingroup=3 )
Ver. 2.8.0

マクロバーのアイコン数 22 コ半、ラベルなし、余白あり( #title="" )
※ 3段目は外部ツールバー (アイコン 30 コ)
Ver. 2.7.8

  • Ver. 2.7.4 まで(2019/05/05)
マクロバーのアイテム数 16 件、ラベルあり(#title="hoge" の文字数を切りつめてやり繰り)
Ver. 2.7.4


>> 目次へ

スポンサーリンク