コンパクトメニュー

提供:MeryWiki
2020年5月4日 (月) 16:50時点におけるSukemaru (トーク | 投稿記録)による版 (→‎機能)
ナビゲーションに移動 検索に移動

機能


メニューバーの全項目をひとつのポップアップメニューにまとめて表示します。


  • [ ファイル(F) / 編集(E) / 検索(S) / 表示(V) / マクロ(M) / ツール(T) / ウィンドウ(W) / ヘルプ(H) ] の各メニュー項目とそれらのサブメニューを再現します。
  • 「編集モード」 「マクロ」 「プラグイン」 「外部ツール」 「辞書」 「クリップボード履歴」 「タブ一覧」 は、自動で取得します(Mery.iniMery.his などから読みこむ)。
  • 右クリックメニューまたはツールバーアイコンからの起動を想定しています。
※ このマクロを導入しても、エディタウインドウの「メニューバー」を非表示にすることはできません (Firefox や Thunderbird のアドオン CompactMenu2 の機能を再現するものではありません)。


拡張メニュー
  • 標準メニューでは表示されない、ポップアップメニューやキーボードショートカット専用のコマンドを表示できるので、「コンパクトメニュー」マクロひとつで Mery の機能を隅々まで使いこなすことができるようになります。
※「コンパクトメニュー」マクロのデフォルト状態では拡張コマンドは非表示です。


⇒ ソースコード内の設定項目 var xMenuEnable = true; にすると
  • ベータ版 3.0.1 までで追加されたものを含めて、ほぼすべてのコマンド(キーボードマップに表示される全コマンド)を表示します。
※ Mery 本体のバージョンに応じて項目の 表示/非表示 を自動化。
  • サブメニュー項目「拡張メニュー」が追加されて、「プロパティ」 「フルパスをコピー」 「親フォルダを開く」 などのコマンドを使用できます。
     ⇒ 拡張サブメニュー の表示位置をメインメニューの最上部に変更 (2020/03/29)
  • [ ヘルプ ] メニューに「Mery 作者のホームページ」へのハイパーリンクコマンドが追加され、既定の WEB ブラウザで 公式ブログフォーラムMery Wiki などを開けるようになります。 (2020/03/29 追加)

制限事項

  • 多分 Mery ver 2.6.7 以降であれば動作するはずです。
「編集モード」 「マクロ」 「プラグイン」 「外部ツール」 の一覧が表示されないときは、それぞれの設定ダイアログを開いて OK ボタンで閉じると表示されるようになるはずです
(Mery を初期設定状態のまま使っている場合、それぞれの設定ダイアログを開いて [ OK ] で閉じたことがないと、Mery.ini に書きこまれない?)。
  • Mery の [オプション] >> [履歴] 設定パネル内の各種項目が OFF (無効) になっていると、利用できなくなる機能があります。
  • すべてのメニュー項目の 完全な再現は無理 です( "エディタの状態" について、マクロからは取得できない部分が多々あるため)。
  • 項目を グレーアウト させる条件の完全な再現は無理
  • ON/OFF 切り替えのトグル項目などの左につける ✔ チェックマーク の完全な再現は無理
  • メニュー右側の ショートカットキー の表示は無し
「編集モード」 「マクロ」 「プラグイン」 「外部ツール」 などのショートカットキーを取得できないので、全部まとめて無視した
  • ファイルメニューの 「最近のファイル」の履歴 の再現は無理 → 「最近閉じたファイル」の履歴 で代替
  • 表示メニュー配下の 「フォント」の履歴 の表示は無理 (マクロからフォントを変更する手段がない)
  • ウインドウメニューの「タブ一覧」のアイテムの「無題-<x>」の連番の再現は無理
  • マクロ名」の自動取得は困難なので、実体ファイルのベース名(e.g. ファイル名が "HogeHoge.js" なら "HogeHoge")で表示します。
    また、親フォルダ名を追加表示することができますので、大量のマクロをカテゴリごとにフォルダ分けしている場合は設定項目 var showParent = true; にしてください。 (2020/03/29 追加)
  • Mery Wiki に収録されている「プラグイン名」は表示できますが、DLL ファイルをリネームしている場合はファイルのベース名で表示します。
  • スペルチェック用の「辞書名」は、実体ファイル(拡張子 AFF)のファイル名順で表示しますが、本来の表示順のルールが不明のため、辞書の切り替えが正しく機能しないかも。
  • クリップボード履歴」は Mery ベータ版 2.8.1 以降であれば 16 件まで表示されるはずです。
    2.8.0 以前のバージョンでは最新の 1 件しか表示できません(外部のアプリでテキスト以外のデータを「コピー」しているときは 0 件になる)。


  • マクロの [記録] の開始はできますが、[停止] はできません (ホットキー Shift+F4 で停止可)。
    また、[記録したマクロの編集] もできません。
    ※「コンパクトメニュー」マクロを実行した時点で「最後に使ったマクロ」が「コンパクトメニュー」になってしまうため、当マクロのポップアップメニュー内の [編集] や [実行] コマンドの対象は「コンパクトメニュー」となります。
→ [実行] については [このマクロを実行] コマンドで代替しています (アクティブタブがマクロのソースファイルのとき)。
最後に使ったマクロの再試行は、ショートカットキー F4 から実行してください。


  • 他にも「コンパクトメニュー」内からは実行できない機能や不完全な動作をする項目があるかもしれません。


  • 任意でメニュー項目の配置を変更しても差しつかえありませんが、menu.Add(string, id, flags) メソッドの第2引数(editor.ExecuteCommandByID(id) メソッドに渡す定数: id)は変更しないで下さい。


Mery インストールフォルダ内の Macros フォルダに実行ファイル GetKeyState.exe を配置してください(または、設定項目 var getKeyStatePath でフルパスを指定)。
※ GetKeyState.exe を導入していないばあいは、メニューに表示されたとおりのコマンドをそのまま実行します。


ダウンロード

>> 「ファイル:コンパクトメニュー.zip」 (アイコン入り)

更新履歴
* 2020/03/29: (第7版 - Mery ベータ版 3.0.1 に対応)
 ・[拡張メニュー] を [ファイル] カテゴリ内からメインメニューの先頭へ移動。
 ・[拡張メニュー] にコマンドを追加。
  ・「未保存* フラグ ON/OFF」
  ・「すべて戻す」
  ・「強制的に上書き保存」
 ・[ヘルプ] カテゴリに拡張コマンドを追加。 (作者の WEB ページ)
 ・「新しいウインドウに移動」 を [ファイル] カテゴリに追加。 (Mery ver 2.8.7)
 ・Mery ver 3.0.0 の追加コマンドに対応。 (マルチカーソル関係)
 ・標準ビルトインコマンドの追加により、拡張表示コマンドのアクセラレータを一部変更。
 ・「スクロールバーのマーカーを表示」 を [ウインドウ] カテゴリへ。フラグ追加。
 ・「SQL整形」 と 「ドキュメントの整形」 の ID を入れ替え。 ( plugin.h のミス? )
 ・「最後に閉じたファイル」 と 「開いているファイル」 が 10 件超の場合はサブメニュー化。
 ・「最後に閉じたファイルのアイテムを開く」 とき『無題<x>』のタブを保持。
 ・「開いているファイル」 のリストを複数ウインドウに対応させ、「選択したタブをアクティブ化」 するさいのフォーカスの不具合をムリヤリ修正。
 ・「このマクロを実行」 用に Mery.ini から [マクロの実行] のショートカットキーを自動で取得するように変更。
 (※ 特殊キーをふくむキーパターンについての動作検証をしていない)  ・マクロ名の表示に親フォルダ名を追加できるよう 設定項目を追加
 ( → var showParent = true; にする)  ・テキストを編集したときは、タブをアクティブ化。  ・GetIniOptionsCM() 関数をカスタマイズ。  ・GetKeyState.exe による機能拡張を追加。 (拡張メニューが有効のとき)   ・[クリップボード履歴] から貼り付けてアイテムを削除   ・[マクロ] カテゴリのマクロ名を選択したときに Mery で実体ファイルを開く
  ( → 追加設定項目 var macroEditEnable = true; にする)   ・[プロパティ] では、簡易的なメッセージボックスで表示 (高速)   ・[パスのコピー] では、パスのデリミタ \ を二重化 ( \\ にしてコピー)   ・[フォルダを開く] では、フォルダのパスをクリップボードにコピーするだけ   ・[作業フォルダを確認] では、作業フォルダのパスをクリップボードにコピー   ・[メモ帳で開く] では、指定した外部アプリケーションで開く
  (※ 追加設定項目 var exNotepadPath のパス未指定ならメモ帳のまま)   ・テキストの編集を伴うコマンドを実行後に、編集したテキストを選択
  (※ コマンドの内容によっては選択範囲がズレる。 また、マクロを選択・実行したときは無効)
* 2019/11/21: (第6版)
 ・メニューラベルのアンパサンド記号 & を補完
 ・バージョンチェック関数の使用を中止
 ・拡張メニューの ID を変更 ( 100 ~ )
* 2019/11/01:(修正・第5版)
 ・バージョンチェックによるグレーアウト処理を非表示化に変更
 ・項目のグレーアウト条件を精査
* 2019/10/30:(修正・第4版)
 ・拡張メニューを追加
 ・バージョンチェックによるグレーアウト処理を追加
 ・関数のエラーを修正
* 2019/10/29:(修正・第3版)
 ・「クリップボード履歴」の取得は ベータ版 2.8.1 以降でないとエラーになるので回避処理を追加
* 2019/10/27:(修正・第2版)
 ・動作要件を Mery 2.6.7 (正式版)以上になるよう、バージョンチェックによる内部処理を追加
 ・エラーの修正
* 2019/10/26:(初版)
 動作要件: Mery ベータ版 2.6.10 以上

ソースコード

#title = "コンパクトメニュー2"
#tooltip = "メニューバーの全アイテムを階層化表示"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",317
// #icon = "menu+.ico"

/**
 * ---------------------------------------------------------
 * コンパクトメニュー2
 * sukemaru, 2019/10/25 - 2020/03/29
 * ---------------------------------------------------------
 * メニューバーのアイテムをポップアップメニューで階層化して表示する。
 * 
 * 通常のメニュー項目にないコマンド(ショートカット/右クリックメニュー用)や、
 * 当マクロ独自の拡張コマンドの追加表示可。
 */

// ---------- ▼ 設定項目 ▼ ---------- //

// ■ ポップアップメニューを表示する位置
var menuPosMouse = true;	// true: マウス位置 / false: キャレット位置

// ■ クリップボード履歴で表示する文字数の目安
var menuWidth = 60;

// ■ 拡張メニューを表示する (ファイルメニューの拡張と、非表示機能の可視化)
var xMenuEnable = true;		// true: 表示する / false: 表示しない

// ---------- ▼ 追加設定 ▼ ---------- //

// ■ [マクロ] カテゴリ内の各マクロの親フォルダ名を表示する
var showParent = false;		// true: 表示する / false: 表示しない

// ■ GetKeyState.exe のフルパスを指定する場合
var getKeyStatePath = "";

  // 未指定 "" なら、Mery インストールフォルダの Macros\GetKeyState.exe
  // ※ GetKeyState.exe なしのときも "" にする
  // ※ \ 記号はふたつがさね「\\」で記述すること

// ■ Ctrl キーを押しながらマクロ名を選択したときは、ソースコードを編集する
var macroEditEnable = false;	// true: コードを編集する / false: マクロを実行する

  // ※ 呼び出し先マクロが GetKeyState.exe を導入している場合に支障を来たすので、
  //   true のときでも Ctrl キーを押しながら「マクロメニュー」を起動したときには
  //   マクロ名の Ctrl+クリック で選択したマクロの「実行」とする。

// ■「メモ帳で開く」で Ctrl キーを押しながらのときは、指定した外部アプリケーションで開く
var exNotepadPath = "";

  // 例: ワードパッド
  // var exNotepadPath = "C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe";

// ---------- ▲ 設定項目 ▲ ---------- //


// 【準備】
var start = new Date();
var d = editor.ActiveDocument,  s = d.selection;
var dt = d.Text;
var tp = Math.min( s.GetAnchorPos(), s.GetActivePos() );
var Fso		 = new ActiveXObject( "Scripting.FileSystemObject" );
var WshShell = new ActiveXObject( "WScript.Shell" );

// Mery フォルダとデータフォルダなど
var meryPath = editor.FullName;
var mery	 = Fso.GetBaseName( meryPath );
var meryDir	 = Fso.GetParentFolderName( meryPath ) + "\\";
var iniPath	 = meryDir + mery + ".ini";
var hisPath	 = meryDir + mery + ".his";
var dicsDir	 = meryDir + "Dicts\\";
var profileDir = meryDir;
if ( ! Fso.FileExists( iniPath ) ) {
  profileDir = WshShell.SpecialFolders( "APPDATA" ) + "\\Mery\\";
  iniPath	 = profileDir + mery + ".ini";
  hisPath	 = profileDir + mery + ".his";
}
var meryVer	 = + ( editor.Version.replace( /[0-9]+/g , function( digit ) {
                     return digit.length < 2 ? "0" + digit : digit
                 } ).replace( /\./g, "" ).slice( 0, 6 ) );

// Mery.ini から各種データを取得
var iniKey	 = [ "MaxRecentFile", "Untitled", "MacrosRunAction"
               , "AutoSaveFolder", "BackupFolder", "UseSystemScrollBar" ] ;
var iniItem	 = GetIniOptionCM( iniKey, iniPath );

// 「最後に閉じたファイル」の準備
// 表示数は「オプション」の「最近のファイルの表示数」の設定値を利用する
var maxRecentFile = Number( iniItem.options[0] );
var recentFiles	 = GetClosedFiles( maxRecentFile, hisPath );
var rfCount		 = recentFiles.length;
var rfWidth		 = ( "" + rfCount ).length || 1;
var rfMenu;

// 「編集モード」 「マクロ」 「プラグイン」 「外部ツール」 の準備
var dMode		 = d.Mode;
var modeArray	 = iniItem.modes;
var mdCount		 = modeArray.length;
var macroArray	 = iniItem.macros;
var mcCount		 = macroArray.length;
var mcWidth		 = ( "" + mcCount ).length;
var pluginArray	 = iniItem.plugins;
var plCount		 = pluginArray.length;
var plWidth		 = ( "" + plCount ).length;
var toolArray	 = iniItem.tools;
var tlCount		 = toolArray.length;
var tlWidth		 = ( "" + tlCount ).length;
// ファイル名先頭の連番と、拡張子 .JS を削除
var mcReg1 = /^\d+[-._ ]+|\.js$/g;
// "親フォルダ名/ ファイル名"
var mcReg2 = /(?:[^\\]+?\\)*?(?:([^\\]+)(?:\\))?([^\\]+)$/;

// 「クリップボード履歴」の準備
var cb		 = ClipboardData;
var cbData	 = cb.GetData();
var cbArray	 = [];
if ( meryVer >= 20801 ) {
  cbArray	 = GetClipboardData( cb );
}
var cbCount	 = Math.min( cbArray.length, 16 );
var cbWidth	 = ( "" + cbCount ).length;
var cbClearStr	 = "クリップボードのすべての履歴を削除しますか? ";

// 「辞書」の準備
var dicsArray	 = GetDics( dicsDir );
var dicCount	 = dicsArray.length;
var dicWidth	 = ( "" + dicCount ).length;

// 「タブ一覧」の準備
var eCount = Editors.Count;
/* ▼ 複数ウインドウ状態に対応 ▼ */
var docus	 = function() {
  var docuArray = [];
  for ( var ee = 0, i = 0, docus, dCount; ee < eCount; ee ++ ) {
    docus  = Editors.Item( ee ).Documents;
    dCount = docus.Count;
    for ( var dd = 0; dd < dCount; dd ++ ) {
      docuArray.push( { docu: docus.Item( dd ), ed: ee, tab: dd } )
    }
  }
  return docuArray;
} ( eCount );
var dsCount	 = docus.length;
var dsWidth	 = ( "" + dsCount ).length;
var untitled = iniItem.options[1] || "無題";
var tabMenu;

// 拡張メニューの準備
if ( xMenuEnable ) {
  var fullPath		 = Fso.FileExists( d.FullName ) ? d.FullName : "";
  var fileName		 = fullPath ? d.Name : "";
  var folderPath	 = fullPath ? d.Path : "";
  var macroDir		 = meryDir + "macros\\";
  var autoSaveDir	 = iniItem.options[3] || "";
  var backupDir		 = iniItem.options[4] || "";
  var desktoptDir	 = WshShell.SpecialFolders( "Desktop" );
  var documentsDir	 = WshShell.SpecialFolders( "MyDocuments" );
  var currentDir	 = WshShell.CurrentDirectory;
  var toCurrentDir	 = fullPath ? "親" : "Mery ";	// 作業フォルダ変更コマンド用
  var portableMode	 = ( profileDir == meryDir );
  var runKey		 = GetHotkey( iniItem.options[2] );	// MacrosRunAction
}

// オプションフラグ
var unnamed	 = d.FullName ? 0 : meMenuGrayed;	// 無題タブ
var sv		 = d.Saved;
var saved	 = sv ? meMenuGrayed : 0;			// 保存済み
var blank	 = dt ? 0 : meMenuGrayed;			// 白紙の文書
var empty	 = s.IsEmpty ? meMenuGrayed : 0;	// 選択範囲なし
var readOnly = d.ReadOnly ? meMenuGrayed : 0;	// 書き換え禁止
var cbExists = cbData ? 0 : meMenuGrayed;		// クリップボード
var multiW	 = ( eCount == 1 ) ? meMenuGrayed : 0;	// 複数ウインドウ
var sqlDll	 = Fso.FileExists( meryDir + "sqlfmt.dll" );	// SQL 整形
var eol		 = ( meryVer >= 20610 )
             ? d.LineEnding : undefined;	// 改行モード
var dEnc	 = d.Encoding;					// エンコード
var utf8	 = ( dEnc == 65001 || dEnc == 650011 || dEnc == 650010 )
			 ? meMenuChecked : 0;
var utf16le	 = ( dEnc == 65537 || dEnc == 655371 || dEnc == 655370 )
			 ? meMenuChecked : 0;
var utf16be	 = ( dEnc == 65538 || dEnc == 655381 || dEnc == 655380 )
			 ? meMenuChecked : 0;
var v20609	 = ( meryVer >= 20609 );	// 自動保存などの追加コマンド多数
var v30000	 = ( meryVer >= 30000 );	// マルチカーソルなどの追加コマンド多数
var multiL	 = ( s.GetTopPointY( mePosView ) != s.GetBottomPointY( mePosView ) )
  			 ? 0 : meMenuGrayed;
if ( xMenuEnable ) {
  var autoSave	 = ( autoSaveDir && Fso.FolderExists( autoSaveDir ) )
  				 ? 0 : meMenuGrayed;
  var backup	 = ( backupDir && Fso.FolderExists( backupDir ) )
  				 ? 0 : meMenuGrayed;
  var sMarker	 = ( + iniItem.options[5] )	// スクロールバーのマーカー
  				 ? meMenuGrayed : 0;
  var extReg	 = /^\.(?:js|pls?|php|pys?|rbs?|vbs)$/i;
  var ext		 = fileName.substring( fileName.lastIndexOf( "\." ) );
  var isScript	 = extReg.test( ext ) ? 0 : meMenuGrayed;
  var runFlags	 = ( blank || unnamed || isScript );
}

// GetKeyState.exe
var gksPath		 = getKeyStatePath || meryDir + "Macros\\GetKeyState.exe";
var gksIsExist	 = xMenuEnable && Fso.FileExists( gksPath );
var $ctrl		 = 0;

	// Ctrl キーにより [マクロ] カテゴリのマクロ選択時の処理方法を変更
	if ( gksIsExist && macroEditEnable
	  && WshShell.Run( "\"" + gksPath + "\" c", 0, true ) == 1 ) {
	  macroEditEnable = ! macroEditEnable;
	}


// 【ポップアップメニュー項目】
var menu = CreatePopupMenu();
var id,  num,  label;
var b1 = "\u2002",  b2 = "\u2002\u2002";	// EN SPACE「 」(U+2002)

// 拡張メニュー
if ( xMenuEnable ) {
  var xMenu = XMenu( fullPath, mery, portableMode, v20609, autoSave, backup, sv, toCurrentDir );
  menu.AddPopup( "拡張メニュー(&X)**", xMenu );	// **
  menu.Add( "-----", 0, meMenuSeparator );	// **
}

// 「ファイル」メニュー
/* 「最近開いたファイル」の替わりに「最後に閉じたファイル」を表示 */
menu.AddPopup( "ファイル(&F)", fMenu = CreatePopupMenu() );
  fMenu.Add( "新規作成(&N)", 2061 );
  fMenu.Add( "開く(&O)...", 2062 );
  fMenu.Add( "閉じて開く(&D)...", 2063 );
  fMenu.Add( "上書き保存(&S)", 2064, unnamed || saved );
  fMenu.Add( "名前を付けて保存(&A)...", 2065 );
  fMenu.Add( "すべて保存(&L)", 2066 );
  fMenu.Add( "-----", 0, meMenuSeparator );
if ( v20609 ) {
  /* 「自動保存」ON/OFF の ✔ チェックマーク表示は不可 */
  fMenu.Add( "自動保存(&U)", 2240 );
}
  fMenu.Add( "-----", 0, meMenuSeparator );
  fMenu.Add( "挿入(&I)...", 2067 );
if ( unnamed ) {
  fMenu.Add( "読みなおし(&R)", 0, meMenuGrayed );
} else {
  fMenu.AddPopup( "読みなおし(&R)", rlMenu = CreatePopupMenu() );
    rlMenu.Add( "自動選択(&A)", 2068 );
    rlMenu.Add( "-----", 0, meMenuSeparator );
    rlMenu.Add( "&UTF-16LE", 2069, utf16le );
    rlMenu.Add( "UTF-1&6BE", 2070, utf16be );
    rlMenu.Add( "UTF-&8", 2071, utf8 );
    rlMenu.Add( "UTF-&7", 2072, ( dEnc == 65000 ) *1 );
    rlMenu.Add( "-----", 0, meMenuSeparator );
    rlMenu.Add( "アラビア語", 2073, ( dEnc == 1256 ) *1 );
    rlMenu.Add( "バルト言語", 2074, ( dEnc == 1257 ) *1 );
    rlMenu.Add( "中央ヨーロッパ言語", 2075, ( dEnc == 1250 ) *1 );
    rlMenu.Add( "簡体中国語 (GB2312)", 2076, ( dEnc == 936 ) *1 );
    rlMenu.Add( "繁体中国語 (Big5)", 2077, ( dEnc == 950 ) *1 );
    rlMenu.Add( "キリル言語", 2078, ( dEnc == 1251 ) *1 );
    rlMenu.Add( "ギリシャ語", 2079, ( dEnc == 1253 ) *1 );
    rlMenu.Add( "ヘブライ語", 2080, ( dEnc == 1255 ) *1 );
    rlMenu.Add( "日本語 (&EUC)", 2081, ( dEnc == 51932 ) *1 );
    rlMenu.Add( "日本語 (&JIS)", 2082, ( dEnc == 50222 ) *1 );
    if ( xMenuEnable )	rlMenu.Add( "-----", 0, meMenuSeparator );
    rlMenu.Add( "日本語 (シフト JI&S)", 2083, ( dEnc == 932 ) *1 );
    if ( xMenuEnable )	rlMenu.Add( "-----", 0, meMenuSeparator );
    rlMenu.Add( "韓国語", 2084, ( dEnc == 949 ) *1 );
    rlMenu.Add( "タイ語", 2085, ( dEnc == 874 ) *1 );
    rlMenu.Add( "トルコ語", 2086, ( dEnc == 1254 ) *1 );
    rlMenu.Add( "ベトナム語", 2087, ( dEnc == 1258 ) *1 );
    rlMenu.Add( "西ヨーロッパ言語", 2088, ( dEnc == 1252 ) *1 );
}
  fMenu.AddPopup( "改行コード(&G)", leMenu = CreatePopupMenu() );
    leMenu.Add( "CR+LF (&Windows)", 2089, ( eol === 0 ) *1 );
    leMenu.Add( "CR (&Macintosh)", 2090, ( eol === 1 ) *1 );
    leMenu.Add( "LF (&UNIX)", 2091, ( eol === 2 ) *1 );
  fMenu.Add( "-----", 0, meMenuSeparator );
  fMenu.Add( "印刷(&P)...", 2092 );
  fMenu.Add( "印刷プレビュー(&W)...", 2093 );
  fMenu.Add( "-----", 0, meMenuSeparator );
/* 最後に閉じたファイルを列挙 */
if ( maxRecentFile > 0 && rfCount ) {
  if ( xMenuEnable && rfCount > 10 ) {
  fMenu.AddPopup( "最後に閉じたファイル(&F)*", rfMenu = CreatePopupMenu() );
  }
  for ( var i = 0, rfMenu = rfMenu || fMenu; i < rfCount; i ++ ) {
    id = i + 200;
    num = ( b2 + ( i + 1 ) ).slice( - rfWidth ).replace( /\d$/, "&$&:" + b1 );
    label = recentFiles[i].replace( /.*?([^\\]+\\)?([^\\]+\\)([^\\]+)$/, "$1 $2 $3" )
                          .replace( /&/g, "&&" );
    rfMenu.Add( num + label, id );
  }
  fMenu.Add( "-----", 0, meMenuSeparator );
}
  fMenu.Add( "保存して閉じる(&E)", 2094 );
  fMenu.Add( "閉じる(&C)", 2095 );
  fMenu.Add( "-----", 0, meMenuSeparator );
if ( xMenuEnable && meryVer >= 20705 ) {
  fMenu.Add( "他のタブをすべて閉じる(&Z)*", 2249 );	//
  fMenu.Add( "左のタブをすべて閉じる(&H)*", 2250 );	//
  fMenu.Add( "右のタブをすべて閉じる(&M)*", 2251 );	//
  fMenu.Add( "-----", 0, meMenuSeparator );	//
}
if ( xMenuEnable && meryVer >= 20807 ) {
  fMenu.Add( "新しいウインドウに移動(&Y)*", 2253 );	//
  fMenu.Add( "-----", 0, meMenuSeparator );	//
}
  fMenu.Add( "すべて保存して閉じる(&V)", 2096 );
  fMenu.Add( "すべて閉じる(&X)", 2097 );

// 「編集」メニュー
menu.AddPopup( "編集(&E)", eMenu = CreatePopupMenu() );
  eMenu.Add( "元に戻す(&U)", 2098, readOnly );
  eMenu.Add( "やり直し(&R)", 2099, readOnly );
  eMenu.Add( "-----", 0, meMenuSeparator );
  eMenu.Add( "切り取り(&T)", 2100, readOnly );
  eMenu.Add( "コピー(&C)", 2101 );
  eMenu.Add( "貼り付け(&P)", 2103, readOnly || cbExists );
  eMenu.Add( "引用つきコピー(&Q)", 2102 );
if ( xMenuEnable ) {
  eMenu.Add( "引用つき貼り付け(&A)*", 2200, readOnly || cbExists );	//
}
  eMenu.Add( "削除(&L)", 2104, readOnly );
  eMenu.Add( "-----", 0, meMenuSeparator );
  eMenu.Add( "すべて選択(&A)", 2105 );
if ( xMenuEnable && v30000 ) {
  eMenu.Add( "選択範囲を行に分ける(&M)*", 2254, multiL );	//
}
if ( v30000 ) {
  eMenu.Add( "前の行にカーソルを追加(&O)", 2256 );
  eMenu.Add( "次の行にカーソルを追加(&W)", 2255 );
  eMenu.Add( "-----", 0, meMenuSeparator );
}
  eMenu.Add( "日付と時刻(&D)", 2106, readOnly );
  eMenu.Add( "-----", 0, meMenuSeparator );
if ( xMenuEnable ) {
  eMenu.Add( "リンクをコピー(&H)*", 2201  );	//
  eMenu.Add( "リンクを開く(&K)*", 2202  );		//
  eMenu.Add( "-----*", 0, meMenuSeparator );	//
}
  eMenu.Add( "行へ移動(&G)...", 2107 );
if ( xMenuEnable ) {
  eMenu.Add( "ファイルへ移動(&F)*", 2108 );		//
  eMenu.Add( "-----*", 0, meMenuSeparator );	//
if ( v20609 ) {
  eMenu.Add( "最後に編集した位置へ移動(&L)*", 2241 );	//
}
if ( meryVer >= 20612 ) {
  eMenu.Add( "次の変更行(&N)*", 2243 );			//
  eMenu.Add( "前の変更行(&J)*", 2244 );			//
  eMenu.Add( "-----*", 0, meMenuSeparator );	//
}
  eMenu.Add( "挿入/上書の切り替え(&I)*", 2125 );	//
}
  eMenu.Add( "書き換え禁止(&Y)", 2109, readOnly /2 );
  eMenu.Add( "-----", 0, meMenuSeparator );
  eMenu.AddPopup( "選択範囲の変換(&S)", cvMenu = CreatePopupMenu() );
    cvMenu.Add( "改行を挿入(&R)", 2110, empty || readOnly );
    cvMenu.Add( "改行を削除(&E)", 2111, empty || readOnly );
    cvMenu.Add( "-----", 0, meMenuSeparator );
    cvMenu.Add( "行の分割(&S)", 2112, empty || readOnly );
    cvMenu.Add( "行の統合(&J)", 2113, empty || readOnly );
    cvMenu.Add( "-----", 0, meMenuSeparator );
  if ( xMenuEnable ) {
    cvMenu.Add( "行切り取り*", 2217, readOnly );	//
    cvMenu.Add( "行コピー*", 2218 );				//
    cvMenu.Add( "行削除*", 2219, readOnly );		//
    cvMenu.Add( "行右削除*", 2220, readOnly );		//
    cvMenu.Add( "行左削除*", 2221, readOnly );		//
    cvMenu.Add( "-----", 0, meMenuSeparator );		//
    cvMenu.Add( "単語の削除*", 2222, readOnly );	//
    cvMenu.Add( "単語の右削除*", 2223, readOnly );	//
    cvMenu.Add( "単語の左削除*", 2224, readOnly );	//
    cvMenu.Add( "-----", 0, meMenuSeparator );		//
  }
    cvMenu.Add( "大文字に変換(&U)", 2114, empty || readOnly );
    cvMenu.Add( "小文字に変換(&L)", 2115, empty || readOnly );
    cvMenu.Add( "単語の最初の文字を大文字に変換(&A)", 2116, empty || readOnly );
    cvMenu.Add( "-----", 0, meMenuSeparator );
    cvMenu.Add( "半角に変換(&H)", 2117, empty || readOnly );
    cvMenu.Add( "全角に変換(&F)", 2118, empty || readOnly );
    cvMenu.Add( "-----", 0, meMenuSeparator );
    cvMenu.Add( "空白をタブに変換(&T)", 2119, empty || readOnly );
    cvMenu.Add( "タブを空白に変換(&N)", 2120, empty || readOnly );
    cvMenu.Add( "-----", 0, meMenuSeparator );
    cvMenu.Add( "インデント(&I)", 2121, empty || readOnly );
    cvMenu.Add( "逆インデント(&D)", 2122, empty || readOnly );
    cvMenu.Add( "-----", 0, meMenuSeparator );
    cvMenu.Add( "再変換(&V)", 2123, empty || readOnly );
  if ( meryVer >= 20613 ) {
    cvMenu.Add( "文字コードの切り替え(&O)", 2245, blank || readOnly );
  }
    cvMenu.Add( "-----", 0, meMenuSeparator );
    cvMenu.Add( "Base64 デコード(&B)...", 2124, empty );
    cvMenu.Add( "Base64 エンコード(&C)...", 2239 );
  eMenu.AddPopup( "ブックマーク(&B)", bmMenu = CreatePopupMenu() );
    bmMenu.Add( "ブックマークを設定/解除(&T)", 2126 );
    bmMenu.Add( "次のブックマーク(&N)", 2127 );
    bmMenu.Add( "前のブックマーク(&P)", 2128 );
    bmMenu.Add( "-----", 0, meMenuSeparator );
    bmMenu.Add( "ブックマークをクリア(&C)", 2129 );
  eMenu.AddPopup( "スペルチェック(&E)", scMenu = CreatePopupMenu() );
    /* スペルチェック配下の ✔ チェックマーク表示はすべて無理 */
    scMenu.Add( "スペルチェック(&C)", 2130 );
    scMenu.AddPopup( "スペルチェックを行う場所(&I)", spMenu = CreatePopupMenu() );
      /* 「場所」のアイテムのグレーアウトは無理 */
      spMenu.Add( "すべて(&A)", 2207 );
      spMenu.Add( "-----", 0, meMenuSeparator );
      spMenu.Add( "1重引用符で囲まれた文字列(&S)", 2208 );
      spMenu.Add( "2重引用符で囲まれた文字列(&D)", 2209 );
      spMenu.Add( "コメント(&C)", 2210 );
      spMenu.Add( "スクリプト(&R)", 2211 );
      spMenu.Add( "タグ(&T)", 2212 );
      spMenu.Add( "強調文字列(&H)", 2213 );
      spMenu.Add( "ハイパーリンク(&Y)", 2214 );
      spMenu.Add( "その他(&E)", 2215 );
    scMenu.AddPopup( "辞書(&D)", dicMenu = CreatePopupMenu() );
    /* 辞書一覧を列挙
       Add() の第2引数 id は 4096 からの連番 */
    for ( var i = 0; i < dicCount; i ++ ) {
      id = i + 4096;
      label = /([^\\]+)\.aff$/i.exec( dicsArray[i] )[1].replace( /&/g, "&&" );
      num = ( b2 + ( i + 1 ) ).slice( - dicWidth ).replace( /\d$/, "&$&:" + b1 );
      dicMenu.Add( num + label, id );
    }
    scMenu.Add( "-----", 0, meMenuSeparator );
    scMenu.Add( "次のスペルミス(&N)", 2131 );
    scMenu.Add( "前のスペルミス(&P)", 2132 );

// 「検索」メニュー
menu.AddPopup( "検索(&S)", sMenu = CreatePopupMenu() );
  sMenu.Add( "検索(&F)...", 2133 );
  sMenu.Add( "次を検索(&N)", 2134 );
  sMenu.Add( "前を検索(&P)", 2135 );
  sMenu.Add( "次の文字列を検索(&X)", 2136 );
  sMenu.Add( "前の文字列を検索(&V)", 2137 );
  sMenu.Add( "-----", 0, meMenuSeparator );
if ( v30000 ) {
  sMenu.Add( "すべて検索して選択(&A)", 2257 );
  sMenu.Add( "選択範囲に次の候補を追加(&D)", 2258 );
  sMenu.Add( "スキップして次の候補を追加(&S)", 2259 );
  sMenu.Add( "選択範囲を元に戻す(&U)*", 2260 );	//
  sMenu.Add( "選択範囲をやり直し(&Y)*", 2261 );	//
  sMenu.Add( "-----", 0, meMenuSeparator );
}
  sMenu.Add( "置換(&R)...", 2138, readOnly );
  sMenu.Add( "-----", 0, meMenuSeparator );
  sMenu.Add( "検索文字列の強調を解除(&E)", 2139 );
  sMenu.Add( "-----", 0, meMenuSeparator );
  sMenu.Add( "ファイルから検索(&I)...", 2140 );
  sMenu.Add( "ファイルから置換(&L)...", 2141 );
  sMenu.Add( "-----", 0, meMenuSeparator );
  sMenu.Add( "Google で検索(&G)", 2142, v30000 ? 0 : empty );
  sMenu.Add( "Wikipedia で検索(&W)", 2143, v30000 ? 0 : empty );

// 「表示」メニュー
/* トグル項目の ✔ チェックマーク表示は無理 */
menu.AddPopup( "表示(&V)", vMenu = CreatePopupMenu() );
  vMenu.AddPopup( "編集モード(&M)", mdMenu = CreatePopupMenu() );
    mdMenu.Add( "現在の編集モードのプロパティ(&P)...**", 19 );	// **
    mdMenu.Add( "-----**", 0, meMenuSeparator );	// **
  /* 編集モード一覧を列挙
     Add() の第2引数 id は 5120 からの連番 */
  for ( var i = 0; i < mdCount; i ++ ) {
    id = i + 5120;
    label = modeArray[i].replace( /&/g, "&&" );
    mdMenu.Add( "&" + label, id, ( dMode == label ) *1 )
  }
    mdMenu.Add( "-----", 0, meMenuSeparator );
    mdMenu.Add( "編集モードの設定(&C)...", 2144 );
  vMenu.Add( "-----", 0, meMenuSeparator );
  vMenu.Add( "折り返さない(&N)", 2146 );
  vMenu.Add( "指定文字数で折り返し(&C)", 2147 );
  vMenu.Add( "ウインドウの右端で折り返し(&W)", 2148 );
  vMenu.Add( "-----", 0, meMenuSeparator );
  vMenu.Add( "縦書き(&V)", 2238 );
  vMenu.Add( "色の反転(&I)", 2145 );
  vMenu.Add( "-----", 0, meMenuSeparator );
  vMenu.Add( "行番号(&L)", 2149 );
  vMenu.Add( "ルーラ(&R)", 2150 );
  vMenu.AddPopup( "記号(&A)", sigMenu = CreatePopupMenu() );
    sigMenu.Add( "改行(&L)", 2151 );
    sigMenu.Add( "折り返し(&R)", 2152 );
    sigMenu.Add( "EOF(&E)", 2153 );
    sigMenu.Add( "タブ(&T)", 2154 );
    sigMenu.Add( "半角空白(&S)", 2155 );
    sigMenu.Add( "全角空白(&W)", 2156 );
    sigMenu.Add( "CR と LF を区別して表示(&D)", 2157 );
  if ( v20609 ) {
    sigMenu.Add( "変更行を強調表示(&H)", 2242 );
  }
  vMenu.Add( "-----", 0, meMenuSeparator );
  vMenu.AddPopup( "ツールバー(&T)", barMenu = CreatePopupMenu() );
    barMenu.Add( "標準ツールバー(&S)", 2158 );
    barMenu.Add( "マクロバー(&M)", 2159 );
    barMenu.Add( "マーカーバー(&K)", 2227 );
    barMenu.Add( "プラグインバー(&P)", 2160 );
    barMenu.Add( "外部ツールバー(&E)", 2161 );
    barMenu.Add( "-----", 0, meMenuSeparator );
    barMenu.Add( "ツールバーのタイトル(&O)", 2162 );
    barMenu.Add( "ツールバーを固定する(&L)", 2163 );
  if ( meryVer >= 20800 ) {
    barMenu.Add( "マクロバーのラベルを表示(&B)", 2252 );
  }
    barMenu.Add( "-----", 0, meMenuSeparator );
    barMenu.Add( "小アイコン(&A)", 2228 );
    barMenu.Add( "中アイコン(&D)", 2229 );
    barMenu.Add( "大アイコン(&R)", 2230 );
    barMenu.Add( "特大アイコン(&X)", 2231 );
    barMenu.Add( "-----", 0, meMenuSeparator );
    barMenu.Add( "カスタマイズ(&C)...", 2164 );
  vMenu.Add( "ステータスバー(&S)", 2165 );
  vMenu.Add( "アウトプット(&O)", 2166, OutputBar.Visible *1 );
  vMenu.Add( "全画面表示(&U)", 2203 );
if ( meryVer >= 20615 ) {
  vMenu.Add( "Zen モード(&Z)", 2246 );
  vMenu.Add( "タイプライタースクロール(&Y)", 2247 );
}
  vMenu.Add( "-----", 0, meMenuSeparator );
if ( xMenuEnable && meryVer >= 20700 ) {	// 本来は [ウインドウ] カテゴリ
  vMenu.Add( "スクロールバーのマーカーを表示(&B)*", 2248, sMarker );	//
  // vMenu.Add( "-----", 0, meMenuSeparator );				//
}
  vMenu.AddPopup( "マーカー(&K)", mkMenu = CreatePopupMenu() );
    mkMenu.Add( "マーカーに追加/削除(&A)", 2232 );
    mkMenu.Add( "-----", 0, meMenuSeparator );
    mkMenu.Add( "すべて有効(&E)", 2233 );
    mkMenu.Add( "すべて無効(&D)", 2234 );
    mkMenu.Add( "-----", 0, meMenuSeparator );
    mkMenu.Add( "すべて削除(&L)", 2235 );
    mkMenu.Add( "-----", 0, meMenuSeparator );
    mkMenu.Add( "自動マーカー(&T)", 2236 );
    mkMenu.Add( "-----", 0, meMenuSeparator );
    mkMenu.Add( "マーカーの設定(&C)...", 2237 );
  vMenu.Add( "-----", 0, meMenuSeparator );
  vMenu.AddPopup( "フォント(&F)", fonMenu = CreatePopupMenu() );
    /* フォントの履歴の取得は無理 */
    fonMenu.Add( "*** フォントの使用履歴を表示できません ***", 0, meMenuGrayed );	//
    fonMenu.Add( "-----", 0, meMenuSeparator );
  if ( xMenuEnable ) {
    fonMenu.Add( "大きいフォントサイズ(&L)*", 2167 );		//
    fonMenu.Add( "小さいフォントサイズ(&S)*", 2168 );		//
    fonMenu.Add( "フォントサイズをリセット(&R)*", 2205 );	//
    fonMenu.Add( "現在のフォントサイズを規定に設定(&D)*", 2206 );	//
    fonMenu.Add( "-----*", 0, meMenuSeparator );	//
  }
    fonMenu.Add( "フォントの設定(&C)...", 2169 );

// 「マクロ」メニュー
/* 記録/停止(S) による一時マクロがらみの項目の 表示/非表示 の切り替えは無理。 */
menu.AddPopup( "マクロ(&M)", mMenu = CreatePopupMenu() );
  mMenu.Add( "記録/停止(&S)", 2170 );
  mMenu.Add( "実行(&R)  " + ScriptName.replace( /&/g, "&&" ), 2171 );
if ( xMenuEnable ) {
  mMenu.Add( "一時オプションを設定してマクロ実行(&O)...*", 2204 );		//
}
  mMenu.Add( "-----", 0, meMenuSeparator );
  mMenu.Add( "名前を付けて保存(&A)...", 2172 );
  mMenu.Add( "編集(&E)  " + ScriptName.replace( /&/g, "&&" ), 2173 );
  mMenu.Add( "選択(&L)...", 2174 );
  mMenu.Add( "これを選択(&T)", 2175, blank || unnamed );
if ( xMenuEnable && fullPath != ScriptFullName && runKey ) {
  mMenu.Add( "このマクロを実行(&G)**  " + fileName, 20, runFlags );		// **
}
  mMenu.Add( "カスタマイズ(&C)...", 2176 );
  mMenu.Add( "-----", 0, meMenuSeparator );
/* マクロのファイル名一覧を列挙	※ 非表示マクロをサブメニュー化 
   Add() の第2引数 id は 6144 からの連番
  JS ファイルの場合は拡張子を省略する */
if ( xMenuEnable ) {
  mMenu.AddPopup( "非表示マクロ(&H)**", smMenu = CreatePopupMenu() );	// **
  mMenu.Add( "-----", 0, meMenuSeparator );	// **
}
for ( var i = 0, j = 1, k = 1, macro; i < mcCount; i ++ ) {
  id = i + 6144;
  macro = macroArray[i];	// 「マクロの相対パス」+「Visible フラグ 1 or 0」
  // ※ ファイル名先頭の連番と、拡張子 .JS を削除 (i.e. "ベース名")
  label = macro.slice( macro.lastIndexOf( "\\" ) + 1, -1 )
               .replace( mcReg1, "" ).replace( /&/g, "&&" );
  // ※ "親フォルダ名/ ファイル名"
  label = ( showParent ) ? macro.replace( mcReg2, "$1/ " ) + label : label;
  if ( macro.slice( -1 ) == "1" ) {
    num = ( b2 + ( j ++ ) ).slice( - mcWidth ).replace( /\d$/, "&$&:" + b1 );
    mMenu.Add( num + label, id );
  } else if ( xMenuEnable ) {
    num = ( b2 + ( k ++ ) ).slice( - mcWidth ).replace( /\d$/, "&$&:" + b1 );
    smMenu.Add( num + label, id );
  }
}

// 「ツール」メニュー
menu.AddPopup( "ツール(&T)", tMenu = CreatePopupMenu() );
  tMenu.Add( "オプション(&O)...", 2177 );
  tMenu.Add( "-----", 0, meMenuSeparator );
if ( xMenuEnable ) {
  tMenu.Add( "単語補完(&A)*", 2178, readOnly );	// 入力補完(オートコンプリート)	//
  tMenu.Add( "-----", 0, meMenuSeparator );	//
}
if ( readOnly ) {
  tMenu.Add( "HTML Tidy(&H)", 0, readOnly );
} else {
  tMenu.AddPopup( "HTML Tidy(&H)", htMenu = CreatePopupMenu() );
    // htMenu.Add( "ドキュメントの整形(&C)", 2180 );
    htMenu.Add( "ドキュメントの整形(&C)", 2179 );
    htMenu.Add( "ドキュメントのエラーをチェック(&F)", 2225 );
}
if ( sqlDll ) {
  // tMenu.Add( "SQL 整形(&S)", 2179, empty || readOnly );
  tMenu.Add( "SQL 整形(&S)", 2180, empty || readOnly );
}
  tMenu.Add( "-----", 0, meMenuSeparator );
  /* クリップボード履歴を列挙 */
  tMenu.AddPopup( "クリップボード履歴(&C)", cbMenu = CreatePopupMenu() );
if ( cbCount ) {
  for ( var i = 0; i < cbCount; i ++ ) {
    id = i + 1;
    label = MenuKey( cbArray[i], id, cbWidth, menuWidth );
    cbMenu.Add( label, id, readOnly );
  }
  if ( xMenuEnable ) {
    cbMenu.Add( "", 0, meMenuSeparator );
    cbMenu.Add( "すべての履歴を削除する(&E)**", 18 );	// **
  }
} else if ( cbData.length ) {
    cbMenu.Add( MenuKey( cbData, 1, 1, menuWidth ), 17, readOnly );	// **
} else {
    cbMenu.Add( "※ クリップボードにテキストデータはありません ※"
              , 0, meMenuGrayed );	// **
}
  tMenu.Add( "-----", 0, meMenuSeparator );
  tMenu.AddPopup( "プラグイン(&I)", plMenu = CreatePopupMenu() );
  /* プラグイン名一覧を列挙
     有効/無効の ✔ チェックマーク表示は無理
     Add() の第2引数 id は 7168 からの連番
     Mery Wiki に登録されたプラグインは名前で表示 */
  for ( var i = 0; i < plCount; i ++ ) {
    id = i + 7168;
    label = GetPluginName( pluginArray[i] ).replace( /&/g, "&&" );
    num = ( b2 + ( i + 1 ) ).slice( - plWidth ).replace( /\d$/, "&$&:" + b1 );
    plMenu.Add( num + label, id );
  }
    plMenu.Add( "-----", 0, meMenuSeparator );
    plMenu.Add( "プラグインの設定(&C)...", 2181 );
  tMenu.AddPopup( "外部ツール(&E)", etMenu = CreatePopupMenu() );
  /* 外部ツール名一覧を列挙
     Add() の第2引数 id は 8192 からの連番 */
  for ( var i = 0; i < tlCount; i ++ ) {
    id = i + 8192;
    label = toolArray[i].replace( /&/g, "&&" );
    num = ( b2 + ( i + 1 ) ).slice( - tlWidth ).replace( /\d$/, "&$&:" + b1 );
    etMenu.Add( num + label, id );
  }
    etMenu.Add( "-----", 0, meMenuSeparator );
    etMenu.Add( "外部ツールの設定(&C)...", 2182 );
    etMenu.Add( "-----", 0, meMenuSeparator );
    etMenu.Add( "ツールジョブの中止(&J)", 2183 );
  tMenu.Add( "-----", 0, meMenuSeparator );
  tMenu.Add( "ポップアップメニューの設定(&P)...", 2184 );

// 「ウインドウ」メニュー
/* トグル項目の ✔ チェックマーク表示は無理 */
menu.AddPopup( "ウインドウ(&W)", wMenu = CreatePopupMenu() );
  wMenu.Add( "常に最上位(&A)", 2185 );
  wMenu.Add( "-----", 0, meMenuSeparator );
  wMenu.Add( "上下に分割(&S)", 2186 );
  wMenu.Add( "左右に分割(&L)", 2226 );
  wMenu.Add( "-----", 0, meMenuSeparator );
if ( xMenuEnable ) {
  wMenu.Add( "次のペイン(&F)*", 2187 );		//
  wMenu.Add( "前のペイン(&B)*", 2188 );		//
  wMenu.Add( "アクティブなペイン(&D)*", 2189, ( d == document ) *3 );	//
  wMenu.Add( "-----*", 0, meMenuSeparator );	//
}
  wMenu.Add( "タブを有効にする(&T)", 2190, editor.EnableTab *1 );
  wMenu.Add( "-----", 0, meMenuSeparator );
  wMenu.Add( "重ねて表示(&C)", 2191, multiW );
  wMenu.Add( "上下に並べて表示(&H)", 2192, multiW );
  wMenu.Add( "左右に並べて表示(&V)", 2193, multiW );
  wMenu.Add( "すべて最小化(&M)", 2194 );
  wMenu.Add( "-----", 0, meMenuSeparator );
  wMenu.Add( "次の文書(&N)", 2195 );
  wMenu.Add( "前の文書(&P)", 2196 );
  wMenu.Add( "-----", 0, meMenuSeparator );
/* タブ一覧を列挙 */
if ( xMenuEnable && dsCount > 10 ) {
  wMenu.AddPopup( "開いているファイル(&O)*", tabMenu = CreatePopupMenu() );
}
for ( var i = 0, docu, tabMenu = tabMenu || wMenu; i < dsCount; i ++ ) {
  if ( tabMenu != wMenu && i > 0 && docus[i].ed != docus[i-1].ed ) {
    tabMenu.Add( "-----", 0, meMenuSeparator );
  }
  id = i + 300;
  docu = docus[i].docu;
  num = ( b2 + ( i + 1 ) ).slice( - dsWidth ).replace( /\d$/, "&$&:" + b1 );
  label = docu.FullName || untitled;
	  // フォルダパスは2階層上まで
	  label = label.replace( /.*?([^\\]+\\)?([^\\]+\\)([^\\]+)$/, "$1 $2 $3" )
	               .replace( /&/g, "&&" );
  tabMenu.Add( num + label, id, ( docu == d ) *1 );
}
if ( xMenuEnable && meryVer >= 20700 ) {
  wMenu.Add( "-----", 0, meMenuSeparator );
  wMenu.Add( "スクロールバーのマーカーを表示(&R)*", 2248, sMarker );	//
}

// 「ヘルプ」メニュー
menu.AddPopup( "ヘルプ(&H)", hMenu = CreatePopupMenu() );
  hMenu.Add( "オンラインヘルプ(&O)...", 2197 );
  hMenu.Add( "キーボードマップ(&K)...", 2198 );
  hMenu.Add( "-----", 0, meMenuSeparator );
  hMenu.Add( "バージョン情報(&A)...", 2199 );
if ( xMenuEnable ) {
  hMenu.Add( "-----", 0, meMenuSeparator );	// **
  hMenu.Add( "-----", 0, meMenuSeparator );	// **
  hMenu.AddPopup( "Mery 作者のホームページ(&H)**", webMenu = CreatePopupMenu() );	// **
    webMenu.Add( "Mery 公式ブログ(&M)...**", 21 );	// **
    webMenu.Add( "Mery 公式フォーラム(&F)...**", 22 );	// **
    webMenu.Add( "-----", 0, meMenuSeparator );	// **
    webMenu.Add( "Mery Wiki(&W)...**", 23 );	// **
    webMenu.Add( "-----", 0, meMenuSeparator );	// **
    webMenu.Add( "Twitter(&T)...**", 24 );	// **
    webMenu.Add( "GitHub(&G)...**", 25 );	// **
    webMenu.Add( "プロ生ちゃんプラグイン - BOOTH(&B)...**", 26 );	// **
  // hMenu.Add( "-----", 0, meMenuSeparator );	// **
  hMenu.Add( "マクロライブラリの「コンパクトメニュー」のページ(&C)...**", 27 );	// **
}


// 【ポップアップメニューを表示】
Status = " 「コンパクトメニュー」 マクロ"
       + ( xMenuEnable ? "  【 ** メニュー拡張 ** 】" : "" )
       + "  [ "
       + ( ( new Date() - start ) / 1000 ).toFixed( 3 ).replace( /\./, ". " )
       + " 秒 ]";

var r = menu.Track( menuPosMouse );


// 【コマンドを実行】

	// Ctrl キーによる機能拡張
	if ( r && gksIsExist ) {
	  $ctrl = ( WshShell.Run( "\"" + gksPath + "\" c", 0, true ) == 1 )
	        ? 1 : 0;
	}

var commandReg = /^\u2002*\d*&\d:\u2002|^&| ?\(&.\)|\*+/g;
Status = " " + menu.GetText( r ).replace( commandReg, "" );

if ( r == 0 ) { ; }

// クリップボード履歴の文字列を貼り付け
else if ( r <= 16 ) {
  d.Write( cbArray[ r -1 ] );
  if ( $ctrl ) {
    cb.ClearData( r -1 );
    Status = " クリップボード履歴からアイテムを削除しました。";
  }
}
else if ( r == 17 ) {
  d.Write( cbData );
}

// クリップボード履歴をすべて削除する **
else if ( r == 18 && Confirm( cbClearStr ) ) {
  for ( var i = 0; i < cbArray.length; i ++ ) {
    cb.ClearData( i );
  }
  Status = " クリップボード履歴からすべてのアイテムを削除しました。";
}

// 現在の編集モードのプロパティ **
else if ( r == 19 ) {
  Status = " \"" + dMode + "\" のプロパティ";
  WshShell.SendKeys( "%P" );
  editor.ExecuteCommandByID( MEID_VIEW_MODE_CUSTOMIZE = 2144 );
}

// このマクロを実行 **
else if ( r == 20 ) {
  Status = " \"" + fileName + "\" を実行します。";
  editor.ExecuteCommandByID( MEID_MACROS_SELECT_THIS = 2175 );	// これを選択
  // editor.ExecuteCommandByID( MEID_MACROS_RUN = 2171 );		// マクロの実行
  WshShell.SendKeys( runKey );		// マクロの実行
}

// Mery 公式 WEB サイトを開く **
else if ( r >= 21 && r <= 27 ) {
  Status += " を開きます。";
  var url = ( r == 21 ) ? "https://www.haijin-boys.com/software/mery/"	// ブログ
          : ( r == 21 ) ? "https://www.haijin-boys.com/discussions"		// フォーラム
          : ( r == 23 ) ? "https://www.haijin-boys.com/wiki/メインページ"	// Mery Wiki
          : ( r == 24 ) ? "https://twitter.com/haijinboys"	// Twitter
          : ( r == 25 ) ? "https://github.com/haijinboys"	// GitHub
          : ( r == 26 ) ? "https://mery.booth.pm/items/1466284"	// プロ生ちゃんプラグイン
          :/* r == 27 */  "https://www.haijin-boys.com/wiki/コンパクトメニュー";	// コンパクトメニュー(マクロライブラリ)
  WshShell.Run( url );		// 規定の WEB ブラウザで開く
}

// 拡張メニュー項目 **
else if ( r >= 100 && r < 200 ) {
  switch ( r ) {

    case 100:	// ファイルのプロパティを開く
    Status = " \"" + fullPath + "\" のプロパティ";
    if ( $ctrl ) {
      // WSH のメッセージボックスで表示(高速)
      FileProperty( d, fullPath, fileName );
    }
    else {
      var ShellApp = new ActiveXObject( "Shell.Application" );
      ShellApp.NameSpace( folderPath )
              .ParseName( fileName )
              .InvokeVerb( "プロパティ(&R)" );
    }
    break;

    case 101: case 102: case 103: case 104:		// パスをコピー
    var data = ( ( r == 101 ) ? fileName		// ファイル名をコピー
               : ( r == 102 ) ? fullPath		// フルパスをコピー
               : ( r == 103 ) ? folderPath		// 親フォルダのパスをコピー
               :/* r == 104 */  meryPath		// Mery のフルパスをコピー
               ).replace( /\\+$/, "" );
    // Ctrl キーを押しながらのときは、パスのデリミタ \ を二重化 → \\
    cb.SetData( ( $ctrl ) ? data.replace( /\\/g, "\\$&" ) : data );
    Status = " " + cb.GetData();
    break;

    case 105: case 106: case 107:			// フォルダを開く
    var path = ( r == 105 ) ? fullPath 		// 親フォルダ
             : ( r == 106 ) ? meryPath		// Mery フォルダ
             :/* r == 107 */  iniPath;		// ユーザーフォルダ
    if ( $ctrl ) {
      path = Fso.GetParentFolderName( path );
      cb.SetData( path );  Status = " " + path;
    }
    else {
      Status = " " + path;
      WshShell.Run( "explorer /select,\"" + path + "\"" );
    }
    break;

    case 108: case 109: case 110: case 111: case 112: case 114:
    var folder = ( r == 108 ) ? macroDir		// Macros フォルダ
               : ( r == 109 ) ? autoSaveDir		// 自動保存フォルダ
               : ( r == 110 ) ? backupDir		// バックアップフォルダ
               : ( r == 111 ) ? desktoptDir		// デスクトップフォルダ
               : ( r == 112 ) ? documentsDir	// マイドキュメントフォルダ
               :/* r == 114 */  currentDir;		// 作業フォルダ
    Status = " " + folder;
    if ( $ctrl ) { cb.SetData( folder ); }
    else              { WshShell.Run( "\"" + folder + "\""); }
    break;

    case 113:	// 作業フォルダを確認
    Status = " 作業フォルダ:  " + currentDir;
    if ( $ctrl ) { cb.SetData( currentDir ); }
    break;

    case 115:	// 作業フォルダに設定する(カレントディレクトリを変更)
    WshShell.CurrentDirectory = ( fullPath ) ? folderPath : meryDir;
    Status = " 作業フォルダ:  " + WshShell.CurrentDirectory;
    break;

    case 116:	// メモ帳で開く
    var command = "\""
                + ( ( $ctrl && exNotepadPath && Fso.FileExists( exNotepadPath ) )
                    ? exNotepadPath : "notepad.exe" )
                + "\" \"" + fullPath + "\"";
    // Status = " " + command;
    WshShell.Run( command );
    break;

    case 117:	// すべて戻す
    Redraw = false;
    var restart = new Date(),  elpased;
    do {
      d.Undo();
      elpased = new Date() - restart;			// 経過時間(ミリ秒)
    } while ( elpased < 3000 && ! d.Saved );	// 無限ループ防止のため3秒制限
    Redraw = true;
    Status = ( d.Saved ? " 保存済みの内容に戻しました。  "
                       : " …戻せる部分は戻しました。  " )
           + "[ " + ( ( elpased ) / 1000 ).toFixed( 3 ).replace( /\./, ". " ) + " 秒 ]";
    break;

    case 118:	// 未保存* フラグ ON/OFF
    d.Saved = ! sv;
    Status = " 未保存* フラグを" + ( sv ? "設定" : "解除" ) + "しました。";
    break;

    case 119:	// 強制的に上書き保存
    d.Saved = false;
    d.Save();
    Status = " ファイルを保存しました。";
    break;
  }
}

// 最後に閉じたファイルのアイテムを開く
else if ( r >= 200 && r < 300 ) {
  // 無題タブの上書きを抑止
  WshShell.Run( "\"" + meryPath + "\" \"" + recentFiles[ r - 200 ] + "\"" );
}

// 選択したタブをアクティブ化
else if ( r >= 300 && r < 400 ) {
  // 複数ウインドウへの対応(最小化しているウインドウを無理やり前面化)
  var ed = Editors.Item( docus[ r - 300 ].ed );
  ed.Documents.Item( docus[ r - 300 ].tab ).Activate();
  ed.ExecuteCommandByID( MEID_WINDOW_ACTIVE_PANE = 2189 );
	  // ウインドウ/タスクボタンのシステムメニューから「元のサイズに戻す」
	  if ( ed != editor ) { WshShell.SendKeys( "%{ }R" ); }
}

// Ctrl キーを押しながらマクロ名を選択したときは、Mery でマクロの実体ファイルを開く
else if ( macroEditEnable && $ctrl && r >= 6144 && r < 7168 ) {
  WshShell.CurrentDirectory = meryDir;
  var path = Fso.GetAbsolutePathName( macroArray[ r - 6144 ] ).slice( 0, -1 );
  WshShell.CurrentDirectory = currentDir;
  Status = " " + path;
  WshShell.Run( "\"" + meryPath + "\" \"" + path + "\"");
}

// 標準コマンド
else {
  editor.ExecuteCommandByID( r );
}

// テキストの編集をした場合は、タブをアクティブ化する
if ( d && d.Text != dt ) {
  editor.ExecuteCommandByID( MEID_WINDOW_ACTIVE_PANE = 2189 );

  // Ctrl キーを押しながらのときは、範囲選択
  if ( $ctrl && ! ( r >= 6144 && r < 7168 ) ) {
    s.SetAnchorPos( tp );
  }
}
Quit();


// ---------- ▼ 関数 ▼ ---------- //

/**
 * 関数 XMenu( docuPath, meryName, portableMode, versionCheck_2_6_9, autoSaveFlag, backupFlag, savedFlag, toCurrentDir )
 * ファイルメニュー拡張
 */
function XMenu( fullPath, mery, portableMode, v20609, autoSave, backup, sv, toCurrentDir ) {
  var xMenu = CreatePopupMenu();
  if ( fullPath ) {
    xMenu.Add( "プロパティ(&R)...", 100 );
    xMenu.Add( "-----", 0, meMenuSeparator );
  }
    xMenu.Add( "すべて戻す(&Z)", 117, saved );	// ※ 無限ループするかも
    xMenu.Add( ( sv ? "未保存* " : "保存済み" ) + "にする(&G)", 118 );
    xMenu.Add( "強制的に上書き保存(&X)", 119, unnamed );
    xMenu.Add( "-----", 0, meMenuSeparator );
  if ( fullPath ) {
    xMenu.Add( "ファイル名をコピー(&N)", 101 );
    xMenu.Add( "フルパスをコピー(&P)", 102 );
    xMenu.Add( "メモ帳で開く(&O)", 116 );
    xMenu.Add( "-----", 0, meMenuSeparator );
    xMenu.Add( "親フォルダのパスをコピー(&F)", 103 );
    xMenu.Add( "親フォルダを開く(&D)", 105 );
    xMenu.Add( "-----", 0, meMenuSeparator );
  }
    xMenu.Add( mery + ".exe のフルパスをコピー(&E)", 104 );
    xMenu.Add( mery + ".exe の親フォルダを開く(&M)", 106 );
    xMenu.Add( "Macros フォルダを開く(&S)", 108 );
  if ( ! portableMode ) {
    xMenu.Add( "ユーザーフォルダを開く(&U)", 107 );
  }
  if ( v20609 ) {
    xMenu.Add( "自動保存フォルダを開く(&A)", 109, autoSave );
    xMenu.Add( "バックアップフォルダを開く(&B)", 110, backup );
  }
    xMenu.Add( "-----", 0, meMenuSeparator );
    xMenu.Add( "デスクトップフォルダを開く(&H)", 111 );
    xMenu.Add( "マイドキュメントフォルダを開く(&D)", 112 );
    xMenu.Add( "-----", 0, meMenuSeparator );
    xMenu.Add( "作業フォルダを確認(&V)", 113 );
    xMenu.Add( "作業フォルダを開く(&U)", 114 );
    xMenu.Add( toCurrentDir + "フォルダを作業フォルダに設定する (&C)", 115 );
  return xMenu;
}

/**
 * 関数 GetIniOptionCM( keyArray, iniPath )
 * ※「コンパクトメニュー」マクロ用 魔改造版
 * 
 * 引数 keyArray で指定した INI オプション項目の値と
 * 「編集モード」 「マクロ」 「プラグイン」 「外部ツール」 の
 * 一覧をそれぞれ配列で返す
 * { options: iniOptionArray, modes: modeArray, macros: macroArray, plugins: pluginArray, tools: toolArray }
 * 
 * 第1引数: INI オプション項目を指定する配列
 * 第2引数: Mery.ini のフルパス
 */
function GetIniOptionCM( keyArray, iniPath ) {
  // Mery.ini を読みこむ
  var Adodb = new ActiveXObject( "ADODB.Stream" );
  var adTypeText = 2,  adReadAll = -1;
  Adodb.Type = adTypeText,  Adodb.Charset = "UTF-8";
  Adodb.Open();
  Adodb.LoadFromFile( iniPath );
  var iniText = Adodb.ReadText( adReadAll );
  Adodb.Close();

  // GetIniOption() バージョン
  // 引数の配列をループ処理して ini からオプションの値を取得する
  var reg1, iniOptionArray = [];
  for ( var i = 0, len = keyArray.length, value; i < len; i ++ ) {
    reg1 = new RegExp( "^" + keyArray[i] + "=([^\\r\\n]*?)$" , "m" );
    if ( reg1.test( iniText ) ) { value = reg1.exec( iniText )[1]; }
    else                        { value = ""; }
    iniOptionArray.push( value );
  }

  // 編集モード名を取得する
  // \r\n [Modes\Mode##] \r\n Caption=ModeName を抽出
  var reg2 = /\r\n\[Modes\\Mode\d+\]\r\nCaption=[^\r\n]+/g;
  var modeArray = iniText.match( reg2 ) || [];		// 抽出結果の配列
  // ModeName を抽出
  var reg3 = /Caption=([^\r\n]+)/;
  for ( var i = 0, len = modeArray.length; i < len; i ++ ) {
    modeArray[i] = reg3.exec( modeArray[i] )[1];
  }

  // マクロのパスを取得する(末尾に Visible キーの値を付加する)
  // \r\n [Macros\Macro##] \r\n FileName=MacroPath \r\n Visible=# を抽出
  var reg4 = /\r\n\[Macros\\Macro\d+\]\r\nFileName=[^\r\n]+\r\nVisible=\d/g;
  var macroArray = iniText.match( reg4 ) || [];		// 抽出結果の配列
  // MacroPath を抽出
  var reg5 = /\r\nFileName=([^\r\n]+)\r\n/;
  for ( var i = 0, len = macroArray.length; i < len; i ++ ) {
    macroArray[i] = reg5.exec( macroArray[i] )[1]
                  + macroArray[i].slice( -1 );
  }

  // プラグインのパスを取得する
  // \r\n [Plugins\Plugin##] \r\n FileName=PluginPath を抽出
  var reg6 = /\r\n\[Plugins\\Plugin\d+\]\r\nFileName=[^\r\n]+/g;
  var pluginArray = iniText.match( reg6 ) || [];	// 抽出結果の配列
  // PluginPath を抽出
  var reg7 = /FileName=(?:[^\\]+\\)*([^\r\n]+)/;
  for ( var i = 0, len = pluginArray.length; i < len; i ++ ) {
    pluginArray[i] = reg7.exec( pluginArray[i] )[1];
  }

  // 外部ツール名を取得する
  // \r\n [Tools\Tool##] \r\n Caption=ToolName を抽出
  var reg8 = /\r\n\[Tools\\Tool\d+\]\r\nCaption=[^\r\n]+/g;
  var toolArray = iniText.match( reg8 ) || [];		// 抽出結果の配列
  // ToolName を抽出
  var reg9 = /Caption=([^\r\n]+)/;
  for ( var i = 0, len = toolArray.length; i < len; i ++ ) {
    toolArray[i] = reg9.exec( toolArray[i] )[1];
  }

  return {
    options: iniOptionArray,
    modes:   modeArray,
    macros:  macroArray,
    plugins: pluginArray,
    tools:   toolArray
  };
}

/**
 * 関数 GetHotkey( hotkeys )
 * Mery.ini から読みこんだショートカットキー設定の文字列値から
 * ひとつめのショートカットキーのパターンを
 * WshShell.SendKes() メソッド用に整形した文字列で返す
 * 
 * 引数: Mery.ini から読みこんだショートカットキー設定の文字列値
 */
function GetHotkey( hotkeys ) {
  if ( ! hotkeys ) { return ""; }
  var key = hotkeys.split( /,(?!["])/ )[0].replace( /"/g, "" ).split( "+" );
  for ( var i = 0, len = key.length, k; i < len; i ++ ) {
    k = key[i].toUpperCase();
    key[i] = ( k == "SHIFT" ) ? "+"
           : ( k == "CTRL" )  ? "^"
           : ( k == "ALT" )   ? "%"
           : /*  others  */     "{" + k + "}"
  }
  return key.join( "" );
}

/**
 * 関数 GetClosedFiles( num, hisPath )
 * 「最後に閉じたファイル」のフルパスの配列を返す
 * 
 * 第1引数: 「最後に閉じたファイル」の件数を指定
 * 第2引数: Mery.his のフルパス
 */
function GetClosedFiles( num, hisPath ) {
  var closedFile = "",  closedFileArray = [];
  var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
  if ( ! num || ! Fso.FileExists( hisPath ) ) { return closedFile; }

  // Mery.his を読みこむ
  var Adodb = new ActiveXObject( "ADODB.Stream" );
  var adTypeText = 2,  adReadAll = -1;
  Adodb.Type = adTypeText,  Adodb.Charset = "UTF-8";
  Adodb.Open();
  Adodb.LoadFromFile( hisPath );
  var hisText = Adodb.ReadText( adReadAll );
  Adodb.Close();
  
  // Mery.his からファイルパスを抽出し、後ろから順にチェック
  var hisArray = hisText.match( /^\[.+\]$/gm );
  if ( ! hisArray ) { return closedFile; }
  hisArray.reverse();
  var hCount = hisArray.length;
  var eCount = Editors.Count;
  var docus,  dCount,  hit;
  outerLoop:
  for ( var i = 0; i < hCount && closedFileArray.length < num; i ++ ) {
    closedFile = hisArray[i].slice( 1, -1 );
    for ( var ee = 0, hit = false; ee < eCount; ee ++ ) {
      docus = Editors.Item( ee ).Documents;
      dCount = docus.Count;
      for ( var dd = 0; dd < dCount; dd ++ ) {
        if ( docus.Item( dd ).FullName == closedFile ) {
          hit = true;
          continue outerLoop;
        }
      }
    }
    // 現在開いていないものを「最後に閉じたファイル」に追加する
    if ( ! hit && Fso.FileExists( closedFile ) ) {
      closedFileArray.push( closedFile );
    }
  }
  return closedFileArray;
}

/**
 * 関数 GetDics( dicsDir )
 * 辞書ファイルのフルパスの配列を返す
 * 
 * 引数: Dics フォルダのフルパス
 */
function GetDics( dir ) {
  var dics = new Enumerator( Fso.GetFolder( dir ).Files );
  var dicsArray = [];
  for ( ; ! dics.atEnd(); dics.moveNext() ) {
    if ( /\.aff$/i.test( dics.item() ) ) {
      dicsArray.push( dics.item() );
    }
  }
  return dicsArray;
}

/**
 * 関数 GetPluginName( dllName )
 * プラグイン.DLL のファイル名から「プラグイン名」を返す
 */
function GetPluginName( dll ) {
  if ( dll.indexOf( "Outline" ) > -1 ) return "アウトライン";
  if ( dll.indexOf( "KureiKei" ) > -1 ) return "プロ生ちゃん";
  if ( dll.indexOf( "EditorConfig" ) > -1 ) return "EditorConfig";
  if ( dll.indexOf( "LiveStyle" ) > -1 ) return "Emmet LiveStyle";
  if ( dll.indexOf( "AlphaBlend" ) > -1 ) return "半透明";
  if ( dll.indexOf( "ClassView" ) > -1 ) return "クラスビュー";
  if ( dll.indexOf( "Conversion" ) > -1 ) return "半角/全角 変換";
  if ( dll.indexOf( "Favorites" ) > -1 ) return "お気に入り";
  if ( dll.indexOf( "HSPRun" ) > -1 ) return "HSPコンパイル実行";
  if ( dll.indexOf( "Snippets" ) > -1 ) return "スニペット";
  if ( dll.indexOf( "WebPreview" ) > -1 ) return "Webプレビュー";
  if ( dll.indexOf( "ClipboardHistory" ) > -1 ) return "クリップボード履歴";
  if ( dll.indexOf( "PathPaste" ) > -1 ) return "コピーしたファイルやフォルダのパスを貼り付け";
  if ( dll.indexOf( "RectangleInput" ) > -1 ) return "矩形選択範囲の各行の先頭に文字を挿入";
  if ( dll.indexOf( "OutputBarHook" ) > -1 ) return "OutputBar拡張";
  if ( dll.indexOf( "MeryRelay2Plugin" ) > -1 ) return "プロセス中継";
  if ( dll.indexOf( "MeryRelay" ) > -1 ) return "別プロセスで編集";
  if ( dll.indexOf( "CheckModified" ) > -1 ) return "文書の変更をチェック";
  if ( dll.indexOf( "CloseSplitEditor" ) > -1 ) return "分割されたエディタを閉じる";
  if ( dll.indexOf( "IPMessenger" ) > -1 ) return "IPメッセンジャー";
  if ( dll.indexOf( "MeryCsvList" ) > -1 ) return "MeryCsvList";
  if ( dll.indexOf( "SearchToolbar" ) > -1 ) return "検索バー";
  else return dll.replace( /\.dll$/i, "" );
}

/**
 * 関数 GetClipboardData( objClipboardData )
 * クリップボード履歴を配列で返す
 * ※ ベータ版 2.8.1 以降
 */
function GetClipboardData( cb ) {
  var cbArray = [];
  for ( var i = 0, cbItem;  ; i ++ ) {
    cbItem = cb.GetData( i ) || "";
    if ( ! cbItem ) { break; }
    deleteLoop:				// 重複するアイテムを履歴から削除
    for ( var j = i + 1, cbNextItem;  ; j ++ ) {
      cbNextItem = cb.GetData( j ) || "";
      if ( ! cbNextItem ) { break deleteLoop; }
      if ( cbItem == cbNextItem ) { cb.ClearData( j -- ); }
    }
    cbArray.push( cbItem );	// 履歴のアイテムを配列に追加
  }
  return cbArray;
}

/**
 * 関数 MenuKey( str, num, numWidth, menuWidth )
 * クリップボード履歴のラベルを整形する
 * 
 * ・行頭空白を除去、空白文字を圧縮:		→「›」(U+203A)
 * ・改行記号を可視化:					→「↲」(U+21B2) または「⏎」(U+23CE)
 * ・削られてしまう「&」を補完
 * ・「¥」(U+005C) を「∖」に置換:			→「∖」(U+2216)
 * ・ゼロ幅や特殊な空白文字を豆腐に置換:	→「⊠」(U+22A0) または「▯」(U+25AF)
 * ・判読しづらいメタ文字を全角に置換:		!"%'(),.:;@[]`{|}
 * ・「a-z」を全角に置換
 * ・行番号を空白でケタ埋め:				EN SPACE「 」(U+2002)
 * ・文字数を切り詰め
 */
function MenuKey( str, num, numWidth, menuWidth ) {
  var invisible = /[\u00A0\u1680\u180E\u2000-\u200E\u2028\u2029\u202F\u205F\u2062\u2063\uFEFF]/g;
  var menuKey = str.replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " \u203A " )
                   .slice( 0, menuWidth + 1 )
                   .replace( /(?:\r?\n|\r)/g, " \u21B2 " )
                   .replace( /[&]/g, "&&" )
                   .replace( /[\\]/g, "\u2216" )
                   .replace( invisible, "\u25AF" )
                   .replace( /[!"%'(),.:;@\[\]`a-z{|}]/g,
                     function( tmp ) {
                       return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
                     } );
  num = ( "\u2002\u2002" + num ).slice( - numWidth )
                                .replace( /\d$/, "&$&:\u2002" );
  menuKey = ( menuKey.length > menuWidth )
          ? menuKey.slice( 0, menuWidth ) + " ..."
          : menuKey;
  return num + menuKey;
}

/**
 * 関数 FileProperty( objDocu, fullPath, fileName )
 * ファイルのプロパティをメッセージボックスに表示する
 */
function FileProperty( objDocu, fullPath, fileName ) {
  var Fso		 = new ActiveXObject( "Scripting.FileSystemObject" );
  var WshShell	 = new ActiveXObject( "WScript.Shell" );
  var f		 = Fso.GetFile( fullPath );
  var size	 = f.Size.toString().replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
  var len	 = objDocu.Text.length.toString()
         	                      .replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
  var row	 = objDocu.GetLines( 0 ).toString()
         	                        .replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
  var fa	 = f.Attributes;	// ※ インデックス属性と暗号化属性は取得できない
  var attr	 = ( fa &   1 ? "R" : "" )		// 読み取り専用属性
           	 + ( fa &   2 ? "H" : "" )		// 隠し属性
           	 + ( fa &   4 ? "S" : "" )		// システム属性
           	 + ( fa &  32 ? "A" : "" )		// アーカイブ属性
           	 + ( fa & 128 ? "C" : "" );		// 圧縮属性
  /* 日時を  "YYYY年MM月DD日、hh:mm:ss"  で返す */
  var DateTimeJ = function ( date ) {
    var dd = new Date( date );
    var dateTime = dd.getFullYear() + "年" + ( dd.getMonth() + 1 ) + "月"
                 + dd.getDate() +"日、" + dd.toLocaleTimeString();
    /* 1ケタの数字をゼロ埋めして2ケタで返す */ 
    return dateTime.replace( /[0-9]+/g , function( digit ) {
        return digit.length < 2 ? "0" + digit : digit;
    } );
  }
  // メッセージボックスに表示する
  var msgStr = "名前:\t" + fileName + "\n\n"
             + "種類:\t" + f.Type + "\n\n"
             + "場所:\t" + Fso.GetParentFolderName( fullPath ) + "\\  \n\n"
             + "サイズ:\t" + size + " バイト" + "\n"
             + "\t" + len + " 文字 ( " + row + " 行 )\n\n"
             + "作成日時:\t" + DateTimeJ( f.DateCreated ) + "\n"
             + "更新日時:\t" + DateTimeJ( f.DateLastModified ) + "\n\n"
             + "属性:\t" + ( attr || "0" ) + "\n\n";
  var nSecondsToWait = 0;
  var strTitle		 = "「" + fileName + "」 のプロパティ";
  var nType			 = 64;	// ボタン 0:[OK],  アイコン 64:[i]
  WshShell.Popup( msgStr, nSecondsToWait, strTitle, nType );
}

メモ

不具合など、お気づきになったことがありましたら Mery 公式フォーラム にてお知らせください。


  • 2019/10/29 (sukemaru)
ベータ版 2.8.1 以降でないとエラーになる「クリップボード履歴」の取得コードを使っているのを忘れていました…。
第3版で修正しておきました。
  • 2019/10/30 (sukemaru)
初期設定状態からほとんど弄っていない Mery だと設定項目のいくつかは Mery.ini に反映されていない状態らしく、扱いが難しいです。
  • 2020/03/29 (sukemaru)
Mery ベータ版 3.0.2 までのメニュー項目と非表示コマンドには概ね対応できたとおもいます。
スポンサーリンク