ファイルを読み直す・開きなおす

提供: MeryWiki
移動先: 案内検索

「読みなおす・開きなおす」ポップアップメニュー[編集]

標準ツールバーの「読み直し」アイコン(ファイル メニューの「読み直し」コマンド)のポップアップメニューを再現します。


エンコード指定 の選択肢のほかに以下の機能を追加してあります。

  • Mery の 書き換え禁止 フラグ ON/OFF の変更
  • 読み取り専用属性 ON/OFF の変更(ファイルを開きなおす)
  • ファイルを 閉じて開きなおす
  • 編集モードの設定」パネルを開く
  • 編集モード」を変更するサブメニュー (オプション)
  • ファイルの「プロパティ」を開く
  • さいごに閉じたファイル」を開く
  • 自動保存フォルダバックアップフォルダを開く(Mery ver 2.6.9 以上)
  • 親フォルダ、Mery フォルダ、データフォルダを開く
  • エンコード変更の読みなおし後に元のテキストを貼り付け (追加オプション)
  • 「編集モード」の状態を Mery.ini から読みこみ (追加オプション)
  • 「さいごに閉じたファイル」から自動保存・バックアップファイルを除外する設定を追加
  • 実体ファイルをデスクトップにコピーする


ポップアップメニューのスクリーンショット (2019/05/30)

ファイルを読み直す・開きなおす.png

仕様上の制限[編集]

  • Mery ver 2.6.15 まででは、「読みなおし」や「書き換え禁止にする」を実行すると、ブックマークが消えてしまいます(Mery 本体側の仕様なので、ファイルメニューや編集メニューの標準コマンドでも同様にブックマークが消えます)。
  • ファイルを「開きなおす」場合は、タブの並び順のさいごの位置に開きます。
    また、開きなおしたファイルは、拡張子ごとの既定の「編集モード」になります。
  • 「無題」ドキュメントでは読み直しやエンコード指定ができないので、「編集モード サブメニュー」と「さいごに閉じたファイル」だけを表示します。
  • 「編集モード サブメニュー」は、「編集モードの設定」でカスタマイズした並び順にはなりません(※ マクロから「編集モードの設定」にあるアイテムを取得する方法がない ので、追加/削除されたものに対応するには、マクロのソースコードの書き換えが必要です。 → ZIP の ソースコードで 280行目 ~ 320行目 付近)。
「編集モードの設定」にあるアイテムと並び順を Mery.ini から取得するオプションを追加 (手動設定での並び替え・添削も可)
  • アクセラレータの重複でトグル移動してしまうときは、Enter キーで確定するか、ソースコード内でアクセラレータ( & 記号の位置や (&X) のアルファベット部分)を変更してください。
  • document → editor.ActiveDocument にしたので、ツールバーやメニューから実行する場合は、アウトプットバーにフォーカスがあるときでも動作するはず?(ショートカットキーでの実行は無理かも)
  • エディタの設定で タブが無効 または タブの「閉じるボタン」を表示していない 場合は、閉じたときに Mery (のウインドウ)が終了してしまい、マクロが中断されてしまうので開きなおしができません。
    また、「読み取り専用属性」の変更もできません。
  • さいごに閉じたファイル」メニューを表示できるのは、Mery 本体のオプション設定 >> 履歴 >> 「カーソル位置とブックマークを保存する」が有効で、本マクロの設定項目「読みなおし サブメニュー」が有効の場合のみです。
  • Mery 本体(エディタエンジン)の仕様上、「キャレット位置が文書の先頭」×「ブックマークなし」×「横書き表示」で閉じたファイルは、Mery を終了したときに Mery.his から記録が削除されます。履歴に残したいファイルを閉じるさいは、キャレットの位置を文頭からズラすか、任意の行にブックマークをつけておくようにしてください。
  • 「自動保存/バックアップフォルダ」の設定を Mery.ini から読みとるため、Mery の「オプション」設定の「自動保存」でフォルダパスが指定されていてフォルダの実在確認ができるなら、「自動保存/バックアップ」の有効/無効によらずポップアップメニュー内にコマンドを表示します。
→ 「自動保存/バックアップ」の 有効/無効 の設定状態により非表示またはグレーアウトするように変更。


ダウンロード[編集]

ファイルを読み直す・開きなおす.zip」(アイコン入り)

  • 初版
  • 2019/04/06 - 2019/04/08:
  • 「編集モードサブメニュー」を追加。
  • Quit() メソッドを削除。
  • 「プロパティ」を追加。動作コードの記述を簡略化。
  • 2019/04/28 - 2019/04/30:
  • 「さいごに閉じたファイル」を追加。
  • 「自動保存フォルダ/バックアップフォルダを開く」を追加。
  • エラーの修正。
  • 2019/05/13 - 2019/05/15:
  • 「親フォルダ/Mery フォルダ/データフォルダを開く」を追加。
  • 自動保存/バックアップフォルダが Mery のインストールフォルダと同じドライブがあるときに相対パスを検知できなかったミスを修正。
  • 「編集モード」の状態を Mery.ini から読みこみ。(追加オプション)
  • その他の修正と少しだけ高速化(当社比 @ win XP)。
  • 『sukemaru 自家用』版を追加。
  • 2019/05/19 - 2019/05/21
  • 自動保存/バックアップの項目の表示に Mery 本体のバージョンチェックを適用。
  • 同梱の『sukemaru 自家用』版を『include版』に変更。
  • 2019/05/28-2019/05/30
  • 「さいごに閉じたファイル」から自動保存・バックアップファイルを除外する設定を追加。
  • 実体ファイルをデスクトップにコピーする。
  • 編集モードの手動設定で VBScript と VisualBasic のメニュー ID が重複していたのを修正(VisualBasic 以下の項目の ID を繰り下げ)。

ソースコード[編集]

#title = "ファイルを読み直す・開きなおす..."
#tooltip = "エンコード指定/読み取り専用属性/編集モードの変更"
// #icon = "reload.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",262
var start = new Date();	// 所要時間計測(開始)

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

// ■「さいごに閉じたファイル」の件数
var numLatestClosed = 5;

// ■「さいごに閉じたファイル」に自動保存・バックアップフォルダのファイルを含めない
var woAutoSaved = false;

// ■「編集モード サブメニュー」を表示する
var viewModeMenuEnable = true;

// ■「編集モード」を Mery.ini から自動で取得する
var viewModeAutoSerchEnable = true;

// ■「読みなおし サブメニュー」を表示する
var reloadMenuEnable = true;

// ■諸外国語用(UTF-** とシフトJIS 以外)の文字コードを表示する
var variousLanguageEnable = true;

// ■エンコードを変更して読みなおししたとき変更前のテキストを貼り付けする
var pasteAfterReload = false;

// ■ ポップアップメニューを表示する位置
var menuPosMouse = true;

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


var d = editor.ActiveDocument;
var path = d.FullName;
var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
var WshShell = new ActiveXObject( "WScript.Shell" );
var desktopDir = WshShell.SpecialFolders( "Desktop" );
var currentDir = WshShell.CurrentDirectory;

// メニューに付けるチェックマークとグレーアウト設定

// 書き換え禁止フラグ
var dReadOnly = d.ReadOnly;
var rCheckFlags = dReadOnly ? meMenuChecked : 0;
var rGrayFlags1 = dReadOnly ? meMenuGrayed : 0;
var rGrayFlags2 = dReadOnly ? 0 : meMenuGrayed;

if ( path ) {
  var tabEnble = editor.EnableTab;

  // 読み取り専用属性
  var f = Fso.GetFile( path );
  var attributeReadOnly = ( f.Attributes & 1 );
  var aCheckFlags = attributeReadOnly ? meMenuChecked : 0;
  var aGrayFlags  = tabEnble ? 0 : meMenuGrayed;
  var aGrayFlags1 = attributeReadOnly ? meMenuGrayed : 0;
  var aGrayFlags2 = attributeReadOnly ? 0 : meMenuGrayed;

  // エンコード
  var dEnc = d.Encoding;
  var utf8 = ( dEnc == meEncodingUTF8
            || dEnc == meEncodingUTF8BOM
            || dEnc == meEncodingUTF8NoBOM )
    ? meMenuChecked : 0;
  var utf16le = ( dEnc == meEncodingUTF16LE
               || dEnc == meEncodingUTF16LEBOM
               || dEnc == meEncodingUTF16LENoBOM )
    ? meMenuChecked : 0;
  var utf16be = ( dEnc == meEncodingUTF16BE
               || dEnc == meEncodingUTF16BEBOM
               || dEnc == meEncodingUTF16BENoBOM )
    ? meMenuChecked : 0;
  var EncCheck = function( encoding ) {
    return ( encoding == dEnc ) ? meMenuChecked : 0;
  };
}

// 編集モード
if ( viewModeMenuEnable ) {
  var dMode = d.Mode;
  var ModeCheck = function( mode ) {
    return ( mode == dMode ) ? meMenuChecked : 0;
  };
}
else {
  viewModeAutoSerchEnable = false;
}

// Mery フォルダとデータフォルダ
var meryPath = editor.FullName;
var mery = Fso.GetBaseName( meryPath );
var meryDir = Fso.GetParentFolderName( meryPath ) + "\\";
var profileDir = meryDir;
var iniPath = meryDir + mery + ".ini";
var hisPath = meryDir + mery + ".his";
if ( ! Fso.FileExists( iniPath ) ) {
  profileDir = WshShell.SpecialFolders( "APPDATA" ) + "\\Mery\\";
  iniPath = profileDir + mery + ".ini";
  hisPath = profileDir + mery + ".his";
}
var profileDirExist = ( profileDir != meryDir );

// 自動保存フォルダとバックアップフォルダ
var versionCheck = VersionCheck( "2.6.9" );
var iniKey = [ "AutoSaveEnabled", "AutoSaveToFolder", "AutoSaveFolder"
             , "BackupSaveToFolder", "BackupFolder" ];

/* 配列 iniValue には編集モード名の配列もふくまれる */
// GetIniOption 関数は「読みなおし」マクロ用に改造
var iniValue = GetIniOption( iniPath, iniKey, viewModeAutoSerchEnable );

if ( versionCheck ) {
  // 相対パス解決のためにカレントディレクトリを設定
  WshShell.CurrentDirectory = meryDir;
  var autoSaveFolder = Fso.GetAbsolutePathName( iniValue[0][2] );
  var backupFolder = Fso.GetAbsolutePathName( iniValue[0][4] );
  // パスが "" のときも FolderExists は True なのでグレーアウトの条件を追加
  var autoSaveFlags = ( iniValue[0][1] && iniValue[0][2]	// iniValue[0][0] &&
                        && Fso.FolderExists( autoSaveFolder ) )
                    ? 0 : meMenuGrayed;
  var backupFlags = ( iniValue[0][3] && Fso.FolderExists( backupFolder ) )
                  ? 0 : meMenuGrayed;
}
var autoSaveBackup = ( versionCheck
                       && ( autoSaveFlags == 0 || backupFlags == 0 ) );

// さいごに閉じたファイル
if ( numLatestClosed > 0 ) {
  var latestClosedFile = LatestClosedFile( hisPath, numLatestClosed, woAutoSaved );
  numLatestClosed = latestClosedFile.length;
}


// ポップアップメニュー項目
var m   = CreatePopupMenu();
var sm1 = CreatePopupMenu();
var sm2 = CreatePopupMenu();

m.Add( "書き換え禁止 ON/OFF (&Y)", 2, rCheckFlags );
// 「無題」ドキュメントでは読み直しメニューを表示しない
if ( path ) {
  if ( tabEnble ) {
    m.Add( "読み取り専用属性 ON/OFF (&W)", 5, aCheckFlags + aGrayFlags );
    m.Add( "閉じて開きなおす (&O)", 1 );
  }
  m.Add( "", 0, meMenuSeparator );
  m.Add( "親フォルダを開く (&F)", 10 );
  m.Add( "フルパスをコピー (&C)", 17 );
  m.Add( "プロパティ (&R)", 8 );

  if ( reloadMenuEnable ) {
    m.Add( "", 0, meMenuSeparator );
    m.AddPopup( "読みなおし サブメニュー (&L)", sm1 );
    {
      sm1.Add( "書き換え禁止にする (&Y)", 3, rGrayFlags1 );
      sm1.Add( "書き換え禁止を解除 (&Y)", 4, rGrayFlags2 );
      sm1.Add( "", 0, meMenuSeparator );
      if ( tabEnble ) {
        sm1.Add( "読み取り専用属性にして開きなおす (&R)", 6, aGrayFlags1 );
        sm1.Add( "読み取り専用属性を解除して開きなおす (&R)", 7, aGrayFlags2 );
        sm1.Add( "", 0, meMenuSeparator );
      }
      if ( path ) {
        sm1.Add( "", 0, meMenuSeparator );
        sm1.Add( "ファイル名をコピー (&N)", 16 );
        sm1.Add( "フルパスをコピー (&C)", 17 );
        sm1.Add( "プロパティ (&R)", 8 );
        sm1.Add( "", 0, meMenuSeparator );
        sm1.Add( "親フォルダのパスをコピー (&P)", 18 );
        sm1.Add( "親フォルダを開く (&F)", 10 );
        sm1.Add( "実体ファイルをデスクトップにコピー (&Y)", 26 );
        sm1.Add( "", 0, meMenuSeparator );
      }
      sm1.Add( "デスクトップフォルダを開く (&H)", 15 );
      sm1.Add( " Mery フォルダを開く (&M)", 11 );
      if ( profileDirExist ) {
        sm1.Add( "データフォルダを開く (&D)", 12 );
      }
      if ( autoSaveBackup ) {
        sm1.Add( "自動保存フォルダを開く (&A)", 13, autoSaveFlags );
        sm1.Add( "バックアップフォルダを開く (&B)", 14, backupFlags );
      }
      // 「さいごに閉じたファイル」
      if ( numLatestClosed > 0 ) {
        LatestClosedFileMenu( latestClosedFile, sm1, 300 );
      }
      sm1.Add( "", 0, meMenuSeparator );
      sm1.Add( "「読み直し」マクロの JS ファイルを開く (&J)", 9 );
      sm1.Add( "オプション (&O) ...", 21 );
      sm1.Add( "", 0, meMenuSeparator );
      sm1.Add( "キャンセル & ", 0 );
    }
  }
}

if ( viewModeMenuEnable ) {
  m.Add( "", 0, meMenuSeparator );
  m.AddPopup( "編集モード サブメニュー (&M)", sm2 );
  {
    sm2.Add( "現在の編集モードのプロパティ (&P)...", 100 );
    sm2.Add( "", 0, meMenuSeparator );

    // 編集モードサブメニューの項目を自動で生成する
    if ( viewModeAutoSerchEnable ) {
      for ( var i = 0, len = iniValue[1].length, mode; i < len; i ++ ) {
        mode = iniValue[1][i];
        sm2.Add( "&" + mode, i + 101, ModeCheck( mode ) )
        if ( mode == "XML" && i + 1 != len ) {
          sm2.Add( "", 0, meMenuSeparator );
        }
      }
      sm2.Add( "", 0, meMenuSeparator );
      sm2.Add( "編集モードの設定 (&C)...", 200 );
    }

    // 編集モードサブメニューの項目を手動で取捨選択する
    else {
      sm2.Add( "編集モードの設定 (&C)...", 200 );
      sm2.Add( "", 0, meMenuSeparator );
/* 以下、追加/削除したものがあれば任意で変更すること。並べ替え可 */
      // ▼ デフォルトの編集モード ▼
      sm2.Add( "&Bat", 101, ModeCheck( "Bat" ) );
      sm2.Add( "C&#", 102, ModeCheck( "C#" ) );
      sm2.Add( "C&++", 103, ModeCheck( "C++" ) );
      sm2.Add( "ColdFusion", 104, ModeCheck( "ColdFusion" ) );
      sm2.Add( "&CSS", 105, ModeCheck( "CSS" ) );
      sm2.Add( "&Delphi", 106, ModeCheck( "Delphi" ) );
      sm2.Add( "HSP", 107, ModeCheck( "HSP" ) );
      sm2.Add( "&HTML", 108, ModeCheck( "HTML" ) );
      sm2.Add( "&INI", 109, ModeCheck( "INI" ) );
      sm2.Add( "J&ava", 110, ModeCheck( "Java" ) );
      sm2.Add( "&JavaScript", 111, ModeCheck( "JavaScript" ) );
      sm2.Add( "JSP", 112, ModeCheck( "JSP" ) );
      sm2.Add( "Per&l", 113, ModeCheck( "Perl" ) );
      sm2.Add( "P&erlScript", 114, ModeCheck( "PerlScript" ) );
      sm2.Add( "&PHP", 115, ModeCheck( "PHP" ) );
      sm2.Add( "P&owerShell", 116, ModeCheck( "PowerShell" ) );
      sm2.Add( "P&ython", 117, ModeCheck( "Python" ) );
      sm2.Add( "RHT&ML", 118, ModeCheck( "RHTML" ) );
      sm2.Add( "&Ruby", 119, ModeCheck( "Ruby" ) );
      sm2.Add( "S&QL", 120, ModeCheck( "SQL" ) );
      sm2.Add( "TeX", 121, ModeCheck( "TeX" ) );
      sm2.Add( "&Text", 122, ModeCheck( "Text" ) );
      sm2.Add( "&UWSC", 123, ModeCheck( "UWSC" ) );
      sm2.Add( "VB&Script", 124, ModeCheck( "VBScript" ) );
      sm2.Add( "&VisualBasic", 125, ModeCheck( "VisualBasic" ) );
      sm2.Add( "&Widows Script", 126, ModeCheck( "Widows Script" ) );
      sm2.Add( "x86 Assembler", 127, ModeCheck( "x86 Assembler" ) );
      sm2.Add( "&XML", 128, ModeCheck( "XML" ) );
      // ▲ デフォルトの編集モード ▲
      sm2.Add( "", 0, meMenuSeparator );

/* ▼ ココに追加の編集モードを列挙する ▼ */
      // 編集モード名は正確に、アクセラレータの「&」または「(&A)」以外は付加しないこと
//    sm2.Add( "Hoge (&G)", 129 );
//    sm2.Add( "Fuga (&F)", 130 );
//    sm2.Add( "Piyo", 131 );
//
//    sm2.Add( "&Mery_Macro_JS", 132, ModeCheck( "Mery_Macro_JS" ) );
//    sm2.Add( "Mery MS&Y", 133, ModeCheck( "Mery MSY" ) );
//    sm2.Add( "&JaneStyle (正規表現用)", 135, ModeCheck( "JaneStyle (正規表現用)" ) );
/* ▲ ココに追加の編集モードを列挙する ▲ */
    }
    sm2.Add( "", 0, meMenuSeparator );
    sm2.Add( "キャンセル & ", 0 );
  }
}

// 「無題」ドキュメントではエンコードメニューを表示しない
if ( path ) {
  // 2068 からの ID は ExecuteCommandByID() の定数
  m.Add( "", 0, meMenuSeparator );
  m.Add( "", 0, meMenuSeparator );
  m.Add( "自動選択 (&A)", 2068 );
  m.Add( "", 0, meMenuSeparator );
  m.Add( "UTF-1&6LE", 2069, utf16le );
  m.Add( "UTF-16&BE", 2070, utf16be );
  m.Add( "UTF-&8", 2071, utf8 );
  m.Add( "UTF-&7", 2072, EncCheck( meEncodingUTF7 ) );
  m.Add( "", 0, meMenuSeparator );
  m.Add( "日本語 (シフト JI&S)", 2083, EncCheck( meEncodingShiftJIS ) );

  if ( variousLanguageEnable ) {
    m.Add( "日本語 (&JIS)", 2082, EncCheck( meEncodingJIS ) );
    m.Add( "日本語 (&EUC)", 2081, EncCheck( meEncodingEUC ) );
    m.Add( "", 0, meMenuSeparator );
    m.Add( "西ヨーロッパ言語", 2088, EncCheck( meEncodingWesternEuropean ) );
    m.Add( "中央ヨーロッパ言語", 2075, EncCheck( meEncodingCentralEuropean ) );
    m.Add( "キリル言語", 2078, EncCheck( meEncodingCyrillic ) );
    m.Add( "バルト言語", 2074, EncCheck( meEncodingBaltic ) );
    m.Add( "ギリシャ語", 2079, EncCheck( meEncodingGreek ) );
    m.Add( "ヘブライ語", 2080, EncCheck( meEncodingHebrew ) );
    m.Add( "トルコ語", 2086, EncCheck( meEncodingTurkish ) );
    m.Add( "アラビア語", 2073, EncCheck( meEncodingArabic ) );
    m.Add( "タイ語", 2085, EncCheck( meEncodingThai ) );
    m.Add( "ベトナム語", 2087, EncCheck( meEncodingVietnamese ) );
    m.Add( "簡体中国語 (GB2312)", 2076, EncCheck( meEncodingChineseSimplified ) );
    m.Add( "繁体中国語 (Big5)", 2077, EncCheck( meEncodingChineseTraditional ) );
    m.Add( "韓国語", 2084, EncCheck( meEncodingKorean ) );
  }
}

// 「無題」ドキュメント用のポップアップメニュー項目
if ( ! path ) {
  if ( reloadMenuEnable ) {
    m.Add( "", 0, meMenuSeparator );
    m.Add( "デスクトップフォルダを開く (&H)", 15 );
    m.Add( "Mery フォルダを開く (&M)", 11 );
    if ( profileDirExist ) {
      m.Add( "データフォルダを開く (&D)", 12 );
    }
    if ( autoSaveBackup ) {
      m.Add( "自動保存フォルダを開く (&A)", 13, autoSaveFlags );
      m.Add( "バックアップフォルダを開く (&B)", 14, backupFlags );
    }
  }
  // 「さいごに閉じたファイル」
  if ( numLatestClosed > 0 ) {
    LatestClosedFileMenu( latestClosedFile, m, 300 );
  }
  if ( reloadMenuEnable ) {
    m.Add( "", 0, meMenuSeparator );
    m.Add( "「読み直し」マクロの JS ファイルを開く (&J)", 9 );
    m.Add( "オプション (&O) ...", 21 );
  }
}

m.Add( "", 0, meMenuSeparator );
m.Add( "キャンセル & ", 0 );


// ポップアップメニューを表示
Status = " 「読みなおし」 マクロ  [ "
       + ( ( new Date() - start ) /1000 ).toFixed( 3 )
         .replace( /\./, ". " ) +" 秒 ]";
var r = m.Track( menuPosMouse );

/**
 * 動作コードを変更
 * ポップアップメニューを表示するまでの準備段階で
 * 変数の準備や属性のチェックは済ませてあるので
 * 各コマンドを簡略化した。
 */
switch ( r ) {
  case 0:
    break;

  case 1:	// ファイルを閉じて開きなおす
    d.Close();
    ReopenFile( path );
    break;

  // 書き換え禁止フラグ ON/OFF を変更する
  case 2: case 3: case 4:
    d.ReadOnly = ! dReadOnly;
    break;

  // 読み取り専用属性 ON/OFF を変更して開き直す
  case 5: case 6: case 7:
    // d.Save();	// コメントアウトすると未保存で閉じる前に確認ダイアログ
    d.Close();
    f.Attributes = attributeReadOnly
                 ? attributeReadOnly - 1
                 : attributeReadOnly + 1;
    ReopenFile( path );
    break;

  case 8:	// ファイルのプロパティを開く
    var fileName = d.Name;
    var folderpath = d.Path;
    var shell = new ActiveXObject( "Shell.Application" );
    shell.NameSpace( folderpath )
         .ParseName( fileName )
         .InvokeVerb( "プロパティ(&R)" );
    break;

  case 9:	// このマクロの JS ファイルを開く
    OpenJumpJS( "▼ 設定項目 ▼" );
    break;

  case 10:	// 親フォルダを開く
    WshShell.Run( "explorer /select,\"" + path + "\""  );
    break;

  // フォルダを開く
    case 11:  case 12:  case 13:  case 14:  case 15:
    var folder = ( r == 11 ) ? meryDir		// Mery フォルダを開く
               : ( r == 12 ) ? profileDir	// データフォルダを開く
               : ( r == 13 ) ? autoSaveFolder	// 自動保存フォルダを開く
               : ( r == 14 ) ? backupFolder		// バックアップフォルダ
               :               desktopDir;		// デスクトップフォルダ
    WshShell.Run( "\"" + folder + "\"");
    break;

  // パスをコピー
  case 16:  case 17:  case 18:
    var data = ( r == 16 ) ? d.Name		// ファイル名をコピー
             : ( r == 17 ) ? path		// フルパスをコピー
             :               d.Path;	// 親フォルダのパスをコピー
    ClipboardData.SetData( data );
    break;

  case 21:	// オプション... (環境設定)
    editor.ExecuteCommandByID( MEID_TOOLS_OPTIONS = 2177 );
    break;

  case 26:	// デスクトップにコピー
    CopyFileTo( path, desktopDir );
    break;

  case 100:	// 現在の編集モードのプロパティ...
    WshShell.SendKeys( "%P" );
    editor.ExecuteCommandByID( MEID_VIEW_MODE_CUSTOMIZE = 2144 );
    break;

  case 200:	// 編集モードの設定...
    editor.ExecuteCommandByID( MEID_VIEW_MODE_CUSTOMIZE = 2144 );
    break;

  default:
    if ( r >= 300 && r < 400 ) {	// さいごに閉じたファイル
      ReopenFile( latestClosedFile[ r - 300 ] );
    }
    else if ( r > 2000 ) {	// エンコード指定で読みなおす
      if ( pasteAfterReload ) {
        // 貼り付けオプション
        PasteAfterReload( d, r );
      }
      else {
        editor.ExecuteCommandByID( r );
      }
    }
    else {	// 編集モードを変更( r = 100 番台)
      var label = m.GetText( r )
                   .replace( /[ ]*\(&.\)[ ]*|&/g , "" );
      d.Mode = label;
    }
    break;
}

// プロセスのカレントディレクトリを復旧する
WshShell.CurrentDirectory = currentDir;


/**
 * 関数 VersionCheck( versionStr )
 * Mery 本体が引数で指定したバージョン以上かチェックする( i.e. "2.6.9" )
 * 戻り値は、真偽値 true/false
 */
function VersionCheck( versionStr ) {
  var Pad2 = function( str ) {
    return str.replace( /[0-9]+/g , function( digit ) {
      return digit.length < 2 ? "0" + digit : digit
    } )
  };
  var editorVer = + ( Pad2( editor.Version ).replace( /\./g, "" ).slice( 0, 6 ) );
  var requirement = + ( Pad2( versionStr ).replace( /\./g, "" ).slice( 0, 6 ) );
  return ( editorVer >= requirement );
}

/**
 * 組み込み関数 GetIniOption( meryIniPath, keyArray, viewModeSerch )
 * 引数で指定した INI オプション項目の値と
 * 編集モード一覧を配列で返す
 */
function GetIniOption( iniPath, keyArray, viewModeSerch ) {
  // 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 );	// .replace( /\r\n?/g, "\n" )
  Adodb.Close();
  // 引数の配列をループ処理して ini からオプションの値を取得する
  var reg, value, iniOption = [];
  for ( var i = 0, len = keyArray.length; i < len; i ++ ) {
    reg = new RegExp( "^" + keyArray[i] + "=(.*?)$" , "m" );
    try {
      value = reg.exec( iniText )[1];
    } catch ( e ) { ; }	// エラーがあっても継続 → value = undefined
    if ( /^-?[0-9]+$/.test( value ) ) {
      value = Number( value );	// 10進数なら Number 型で返す
    }
    iniOption.push( value );
  }
  // 編集モード名を取得する
  var modeArray = [];
  if ( viewModeSerch ) {
    // \r\n [Modes\Mode##] \r\n Caption=ModeName を抽出
    var reg2 = /\r\n\[Modes\\Mode\d+\]\r\nCaption=[^\r\n]+/g;
    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];
    }
  }
  return [ iniOption, modeArray ];
}

/**
 * 関数 LatestClosedFile( meryhisPath, num, exclude )
 * ※「読みなおし」マクロ用改造版
 * Mery.his を読み込んで「さいごに閉じたファイル」のフルパスの配列を返す
 * 
 * ※ Mery の「オプション」設定で「カーソル位置とブックマークを保存する」
 *   が無効(Mery.his がない)なら [] を返す
 * ※ 自動保存・バックアップフォルダのパスはグローバル変数を参照する
 */
function LatestClosedFile( hisPath, num, woAutoSaved ) {
  var num = num ? num : 1;
  var closedFile = "";
  var closedFileArray = [];
  var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
  try {
    // 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 );	// .replace( /\r\n?/g, "\n" )
    Adodb.Close();
    // Mery.his からファイルパスを抽出する
    var hisArray = hisText.match( /^\[.+\]$/gm );
    // 現在開いているファイルにないものを「さいごに閉じたファイル」とする
    hisArray.reverse();
    var hCount = hisArray.length;
    var eCount = Editors.Count;
    var docus, dCount, filePath, hit;
    var _autoSaveFolder = autoSaveFolder;
    var _backupFolder = backupFolder;
    var CheckAutoSaveBackup = function( path ) {
      return ( path.indexOf( _autoSaveFolder ) == 0
            || path.indexOf( _backupFolder ) == 0 );
    };
    for ( var i = 0; i < hCount, closedFileArray.length < num; i ++ ) {
      closedFile = hisArray[i].slice( 1, -1 );
      if ( woAutoSaved && CheckAutoSaveBackup( closedFile ) ) {
        continue;
      }
      for ( var ee = 0, hit = 0; ee < eCount; ee ++ ) {
        docus = Editors.Item( ee ).Documents;
        dCount = docus.Count;
        for ( var dd = 0; dd < dCount; dd ++ ) {
          filePath = docus.Item( dd ).FullName;
          if ( closedFile == filePath ) { hit ++; }
        }
      }
      if ( ! hit && Fso.FileExists( closedFile ) ) {
        closedFileArray.push( closedFile );
      }
    }
  } catch ( e ) { closedFileArray = []; }
  finally { return closedFileArray; }
}

/**
 * 関数 LatestClosedFileMenu( objArray, objMenu, id )
 * 「さいごに閉じたファイル」のメニューを返す
 */
function LatestClosedFileMenu( objArray, objMenu, id ) {
  var count = objArray.length;
  var width = String( count ).length;
  var label, num;
  objMenu.Add( "", 0, meMenuSeparator );
  objMenu.Add( "  ▼ さいごに閉じたファイル " + count + " 件 ▼"
             , 0, meMenuGrayed );
  for ( var i = 0; i < count; i ++ ) {
    // 「通し番号: 親フォルダ名\ ファイル名」に切りつめる
    num = ( "   " + ( i + 1 ) ).slice( - width ).replace( /\d$/, "&$&" );
    label = objArray[i].replace( /(?:.+\\)*([^\\]+\\)([^\\]+)$/, "$1 $2" );
    objMenu.Add( num + ":  " + label, i + id );
  }
}

/**
 * 関数 ReopenFile( strPath )
 * 「開きなおす」
 */
function ReopenFile( strPath ) {
  if ( editor.ActiveDocument.FullName
       || editor.ActiveDocument.Text ) {
    editor.NewFile();
  }
  editor.OpenFile( strPath );
}

/**
 * 関数 CopyFileTo( sourcePath, targetDir )
 * 「デスクトップにコピー」
 */
function CopyFileTo( strPath, targetDir ) {
  targetDir = targetDir.replace( /[\\]*$/, "\\" );
  var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
  try {
    // 上書きなしでコピーを実行
    Fso.CopyFile( strPath, targetDir, false );
  } catch ( e ) {
    if ( e.number == -2146828230 ) {	// "既に同名のファイルが存在しています。"
      var msgStr = e.message + " \n\n"
                 + targetDir + strPath.replace( /\\[^\\]+$/, "" )
                 + " \n\n上書きしますか?"
      var nSecondsToWait = 0;
      var strTitle = "Mery: デスクトップにコピー - 「読みなおし」マクロ";
      var nType = 36;	// ボタン 4:[はい][いいえ]、アイコン 32:[?]
      var msgBox = WshShell.Popup( msgStr, nSecondsToWait, strTitle, nType );
      if ( msgBox == 6 ) {	// 1:[OK], 6:[はい]
        try {
          // 上書きありでコピーを実行
          Fso.CopyFile( strPath, targetDir, true );
        }
        catch ( e ) {  Alert( e ); }	// e.g. "書き込みできません。"
      }
    }
    else { Alert( e ); }	// 重複以外のエラーのとき
  }
}

/**
 * 関数 PasteAfterReload( objDocu, encoding )
 * 【改造版】追加機能
 * エンコードを変更して読み直しをしたあと
 * 元のテキストをコピペする
 */
function PasteAfterReload( objDocu, encoding ) {
  var d = objDocu, s = d.selection;
  var y = s.GetActivePointY( mePosLogical );
  var saved = d.Saved;
  s.SelectAll();
  var txt = s.Text;		// s.Copy();
  editor.ExecuteCommandByID( encoding );
  d.ReadOnly = false;
  s.SelectAll();
  // s.Text = txt  でうまくいかないようなら Copy/Paste
  s.Text = txt;		// s.Paste();
  s.SetActivePoint( mePosLogical, 1, y );
  d.Saved = saved;	// 「変更*」フラグを読みなおし前の状態に戻す
}

/**
 * 関数 OpenJumpJS( str )
 * このマクロを開いて設定項目の行にジャンプする
 */
function OpenJumpJS( str ) {
  Redraw = false;
  var targetStr = str || "";
  var eCount = editors.Count;
  var docus, dCount, dItem, ee, js;
  var isOpen = false;
  outerLoop:
  for ( var j = 0; j < eCount; j ++ ) {
    docus = editors.Item( j ).documents;
    dCount = docus.Count;
    for ( var i = 0; i < dCount; i ++ ) {
      dItem = docus.Item( i );
      if ( dItem.FullName == ScriptFullName ) {
        js = dItem;
        isOpen = true;
        break outerLoop;
      }
    }
  }
  if ( ! isOpen ) {
    editor.NewFile();
    ee = ( editor.EnableTab ) ? editor : editors.Item( eCount );
    ee.OpenFile( ScriptFullName, 0 );
    js = ee.ActiveDocument;
  }
  js.Activate();
  var settingPos = js.Text.indexOf( targetStr );
  js.selection.EndOfDocument();
  js.selection.SetActivePos( settingPos );
  js.selection.StartOfLine( false, mePosLogical );	// 行頭
  Redraw = true;
}



include版[編集]

『sukemaru 自家用 (include版)』のポップアップメニュー(2019/05/30)

ファイルを読み直す・開きなおす【自家用版】.png

変更箇所と追加機能[編集]

  • エンコード一覧と「さいごに閉じたファイル」の配置を入れ替え
  • ファイル・フォルダ サブメニューを追加
  • 設定変更 サブメニューを追加(マクロの動作設定をサブメニュー内から変更可)
  • ポップアップメニューの表示位置を指定可(マウス位置/キャレット位置)
    キャレット位置表示のときは設定変更後にメニューを再表示する
  • 「文字カウント」「バイト数」「すべて閉じる」マクロを呼び出す
  • 「お気に入り」プラグインのポップアップメニューと「コピー」ツール(デスクトップにコピー)を呼び出す

外部リソースのインポート[編集]

  • 『sukemaru 自家用 (include版)』の使用にあたっては「includeライブラリ」の導入が必要となります。「includeライブラリ」のページにしたがってダウンロード、インストールしてください。
  • 文字カウント」「バイト数」「すべて閉じる」マクロと「お気に入り2」プラグインをサブメニューにインポート(擬似 include)する場合は、それぞれのマクロ/プラグインの実体ファイルが必要となります。また、インポートする各マクロの保存形式は UTF-8 でなければなりません。
  • ファイルコピー用外部アプリケーションを利用して、アクティブな文書の実体ファイルを「デスクトップにコピー」する機能を置き換えできます。
  • 文字カウント」マクロの 2018/08/04版 を擬似 include する場合は、「文字カウント」マクロのソースコードを改造する必要があるようです。
    2018/08/04版のソースコードを 4 ヶ所変更
  • 8 行目の (function(){ を // (function(){  に変更する(コメントアウト)。
  • 11 行目 の var BR = (function(){ を var BR = function(){  に変更する(1文字削除)。
  • 34 行目の }()); を };  に変更する(3文字削除)。
  • 133 行目の }()); を // }());  に変更する(コメントアウト)。
※「文字カウント」マクロ 2019/06/16版 であれば、ソースコードの改変なしで擬似 include できるようです。


  • すべて閉じる」マクロの『include版』を擬似 include する場合は、「すべて閉じる」マクロのソースコード(2019/05/03)を改造する必要があります。
  • 58 行目の if ( typeof IO == "object" && settingEnable ) { の行を以下のとおりの 2 行に変更する
var macroCloseAllJS;
if ( typeof IO == "object" && settingEnable && macroCloseAllJS == undefined ) {
※『include版』以外の「すべて閉じる」マクロの場合は、ソースコードを変更する必要はありません。

※ これらは include ライブラリ/ IO クラスの「擬似 include 処理」 eval( IO.Include( macroPath, "utf-8" ) ); を利用するうえで必要な変更となります。
※ 以上の各箇所を変更しても、各マクロ単体での実行にあたって支障をきたすことはありません。

  • マクロライブラリにある「バイト数」マクロの擬似 include にあたっては、いずれのバージョンにおいてもソースコードの改変の必要はありません(イベントマクロであっても呼び出すことができます)。本マクロのソースコード内の設定項目で、実体ファイルのパスを指定すればそのまま利用できます。


  • 「お気に入り」プラグインは、公式 プラグイン 版と プラグインライブラリ 版のどちらでも利用できますが、「プラグインの設定」ダイアログに登録した順位([プラグイン] メニュー内で表示される通し番号)の指定が必要になります。


  • アクティブなタブの実体ファイルを「デスクトップにコピー」する機能では、外部の実行ファイル(e.g. RoboCopy, TeraCopy, FireFileCopy)を使用することができますので、コマンドライン引数を設定することによりタイムスタンプやファイル属性などを維持した状態でのコピー、上書きコピーの可否や上書き確認の有無などを指定することができます。
※ ソースコードのデフォルト状態では、外部の実行ファイルは使用せず、WSH の機能でファイルをコピーするようにしてあります。同名ファイルがあるばあいは上書き確認のダイアログを表示しますが、書き込み先のファイル/フォルダの状態によっては上書きコピーできないことがあります。
※ ソースコードのデフォルト状態では「デスクトップにコピー」するようにしてあります。コピー先フォルダの変更用の設定項目は用意してありません。

ソースコード[編集]

#title = "ファイルを読み直す・開きなおす..."
#tooltip = "エンコード指定/読み取り専用属性/編集モードの変更"
// #icon = "reload.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",262

var start = new Date();

var d = editor.ActiveDocument;
var path = d.FullName;
var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
var WshShell = new ActiveXObject( "WScript.Shell" );
var desktopDir = WshShell.SpecialFolders( "Desktop" );
var currentDir = WshShell.CurrentDirectory;


// ---------- ▼ 【include版】 初期設定項目 ▼ ---------- //

// ◆ 「設定変更」サブメニューを表示するか?
var settingEnable = true;	// (true する / false しない)

// ◆ JSON ファイルのベース名
var jsonName = Fso.GetBaseName( ScriptFullName );	// 既定値

  // 任意の名前に変更する場合はアンコメントして書き換える
  // jsonName = "読みなおし";

// ---------- ▼ 通常版 設定項目 ▼ ---------- //

// ■「さいごに閉じたファイル」の件数
var numLatestClosed = 10;

// ■「さいごに閉じたファイル」に自動保存・バックアップフォルダのファイルを含めない
var woAutoSaved = false;

// ■「読みなおし サブメニュー」を表示する
var reloadMenuEnable = true;

// ■「編集モード サブメニュー」を表示する
var viewModeMenuEnable = true;

// ■「編集モード」を Mery.ini から自動で取得する
var viewModeAutoSerchEnable = true;

// ■諸外国語用(UTF-** とシフトJIS 以外)の文字コードを表示する
var variousLanguageEnable = true;

// ■エンコードを変更して読みなおししたとき変更前のテキストを貼り付けする
var pasteAfterReload = false;

// ■ ポップアップメニューを表示する位置
var menuPosMouse = false;

// ---------- ▼ 外部リソース 設定項目 ▼ ---------- //

// マクロは "絶対パス" か "このマクロの親フォルダからの相対パス" で指定する
// ■「文字カウント」マクロ(※要 改造)
var macroCountJS = "";
 // macroCountJS = "文字カウント.js";

// ■「バイト数」マクロ
var macroBytesJS = "";
 // macroBytesJS = "バイト数.js";

// ■「すべて閉じる」マクロ(※要 改造)
var macroCloseAllJS = "";
 // macroCloseAllJS = "すべて閉じる(モード選択).js";

// ■「お気に入り」プラグインの表示名
var pluginFavorite = "";
// ■「お気に入り」プラグインの [プラグイン] メニュー内での通し番号( 1 ~ )
var pluginFavoriteAt;
 // pluginFavorite = "お気に入り";
 // pluginFavoriteAt = 1;

// ■「デスクトップにコピー」で使用する実行ファイル
//   (パスが通っていないときはフルパスで指定する / "" なら WSH でコピーを実行)
var toolCopy = "";
// ■「デスクトップにコピー」で使用するコマンドライン引数(先頭にスペースを入れること)
var toolCopyOptions = "";

//   // RoboCopy を使用する場合(※ 強制上書き)
//   toolCopy = "c:\\hoge\\RoboCopy.exe";
//   toolCopyOptions = " \"" + d.Path.slice( 0, -1 ) + "\""
//                   + " \"" + desktopDir + "\""
//                   + " \"" + d.Name + "\""
//                   + " /B /COPY:DAT /R:1 /W:1";

//   TeraCopy を使用する場合(※ 上書きなし → 別名で保存)
//   toolCopy = "c:\\fuga\\TeraCopy.exe";
//   toolCopyOptions = " Copy"	// Operation
//                   + " \"" + d.FullName + "\""
//                   + " \"" + desktopDir + "\""
//                   + " /RenameAll /Close";

//   // FireFileCopy を使用する場合(※上書き確認あり)
//   toolCopy = "c:\\piyo\\FFC.exe";
//   toolCopyOptions = " /copy /bg /go!"
//                   + " /to:\"" + desktopDir + "\""
//                   + " \"" + d.FullName + "\"";

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


/* ▼ 【include版】の追加コード ▼ */ 

// ソースコードの「設定項目」内の初期値を保存する
var setting = {
  settingEnable : settingEnable,
  viewModeMenuEnable : viewModeMenuEnable,
  viewModeAutoSerchEnable : viewModeAutoSerchEnable,
  reloadMenuEnable : reloadMenuEnable,
  variousLanguageEnable : variousLanguageEnable,
  pasteAfterReload : pasteAfterReload,
  numLatestClosed : numLatestClosed,
  woAutoSaved : woAutoSaved,
  menuPosMouse : menuPosMouse,
  macroCountJS : macroCountJS,
  macroBytesJS : macroBytesJS,
  pluginFavorite : pluginFavorite,
  pluginFavoriteAt : pluginFavoriteAt,
  toolCopy : toolCopy,
  toolCopyOptions : toolCopyOptions
};
var initialSettings = setting;
if ( initialSettings.settingEnable ) {
  // JSON ファイルから設定を読み込む
  jsonName = jsonName || ScriptName.replace( /\.js$/i, "" );
  setting = IO.Deserialize( setting, jsonName );
  // 通常版の設定変数に再代入
  settingEnable = setting.settingEnable;
  viewModeMenuEnable = setting.viewModeMenuEnable;
  viewModeAutoSerchEnable = setting.viewModeAutoSerchEnable;
  reloadMenuEnable = setting.reloadMenuEnable;
  variousLanguageEnable = setting.variousLanguageEnable;
  pasteAfterReload = setting.pasteAfterReload;
  numLatestClosed = setting.numLatestClosed;
  woAutoSaved = setting.woAutoSaved;
  menuPosMouse = setting.menuPosMouse;
}

// 設定変更した場合はメニューを再表示する(キャレット位置表示のときのみ)
var r = 0;
do {

  // ループで再表示したときはタイマーをリセット
  if ( r ) { start = new Date(); }

/* ▲ 【include版】の追加コード ▲ */ 


  // メニューに付けるチェックマークとグレーアウト設定

  // 書き換え禁止フラグ
  var dReadOnly = d.ReadOnly;
  var rCheckFlags = dReadOnly ? meMenuChecked : 0;
  var rGrayFlags1 = dReadOnly ? meMenuGrayed : 0;
  var rGrayFlags2 = dReadOnly ? 0 : meMenuGrayed;

  if ( path ) {
    var tabEnble = editor.EnableTab;

    // 読み取り専用属性
    var f = Fso.GetFile( path );
    var attributeReadOnly = ( f.Attributes & 1 );
    var aCheckFlags = attributeReadOnly ? meMenuChecked : 0;
    var aGrayFlags  = tabEnble ? 0 : meMenuGrayed;
    var aGrayFlags1 = attributeReadOnly ? meMenuGrayed : 0;
    var aGrayFlags2 = attributeReadOnly ? 0 : meMenuGrayed;

    // エンコード
    var dEnc = d.Encoding;
    var utf8 = ( dEnc == meEncodingUTF8
              || dEnc == meEncodingUTF8BOM
              || dEnc == meEncodingUTF8NoBOM )
      ? meMenuChecked : 0;
    var utf16le = ( dEnc == meEncodingUTF16LE
                 || dEnc == meEncodingUTF16LEBOM
                 || dEnc == meEncodingUTF16LENoBOM )
      ? meMenuChecked : 0;
    var utf16be = ( dEnc == meEncodingUTF16BE
                 || dEnc == meEncodingUTF16BEBOM
                 || dEnc == meEncodingUTF16BENoBOM )
      ? meMenuChecked : 0;
    var EncCheck = function( encoding ) {
      return ( encoding == dEnc ) ? meMenuChecked : 0;
    };
  }

  // 編集モード
  if ( viewModeMenuEnable ) {
    var dMode = d.Mode;
    var ModeCheck = function( mode ) {
      return ( mode == dMode ) ? meMenuChecked : 0;
    };
  }
  else {
    viewModeAutoSerchEnable = false;
  }

  // Mery フォルダとデータフォルダ
  var meryPath = editor.FullName;
  var mery = Fso.GetBaseName( meryPath );
  var meryDir = Fso.GetParentFolderName( meryPath ) + "\\";
  var profileDir = meryDir;
  var iniPath = meryDir + mery + ".ini";
  var hisPath = meryDir + mery + ".his";
  if ( ! Fso.FileExists( iniPath ) ) {
    profileDir = WshShell.SpecialFolders( "APPDATA" ) + "\\Mery\\";
    iniPath = profileDir + mery + ".ini";
    hisPath = profileDir + mery + ".his";
  }
// 	// ※ sukemaru 自家用: データフォルダをつねに表示する
// 	profileDir = WshShell.SpecialFolders( "APPDATA" ) + "\\Mery\\";
  var profileDirExist = ( profileDir != meryDir );

  // 自動保存フォルダとバックアップフォルダ
  var versionCheck = VersionCheck( "2.6.9" );
  var iniKey = [ "AutoSaveEnabled", "AutoSaveToFolder", "AutoSaveFolder"
               , "BackupSaveToFolder", "BackupFolder" ];

  /* 配列 iniValue には編集モード名の配列もふくまれる */
  // GetIniOption 関数は「読みなおし」マクロ用に改造
  var iniValue = GetIniOption( iniPath, iniKey, viewModeAutoSerchEnable );

  if ( versionCheck ) {
    // 相対パス解決のためにカレントディレクトリを設定
    WshShell.CurrentDirectory = meryDir;
    var autoSaveFolder = Fso.GetAbsolutePathName( iniValue[0][2] );
    var backupFolder = Fso.GetAbsolutePathName( iniValue[0][4] );
    // パスが "" のときも FolderExists は True なのでグレーアウトの条件を追加
    var autoSaveFlags = ( iniValue[0][1] && iniValue[0][2]
                          && Fso.FolderExists( autoSaveFolder ) )
                      ? 0 : meMenuGrayed;
    var backupFlags = ( iniValue[0][3] && Fso.FolderExists( backupFolder ) )
                    ? 0 : meMenuGrayed;
  }
  var autoSaveBackup = ( versionCheck
                         && ( autoSaveFlags == 0 || backupFlags == 0 ) );

  // さいごに閉じたファイル
  if ( numLatestClosed > 0 ) {
    var latestClosedFile = LatestClosedFile( hisPath, numLatestClosed, woAutoSaved );
    numLatestClosed = latestClosedFile.length;
  }

  // 「疑似 include 処理」するマクロのチェック
  // マクロのパスを解決する
  var MacroPath = function( macro ) {
    var macroPath;
    // 上でカレントディレクトリを変更しているので誤爆の可能性あり
    // if ( Fso.FileExists( macro ) ) {
    //   macroPath = macro;
    //   return macroPath;
    // }
    var macroDir = Fso.GetParentFolderName( ScriptFullName ) + "\\";
    if ( Fso.FileExists( macroDir + macro ) ) {
      macroPath = macroDir + macro;
      return macroPath;
    }
    WshShell.CurrentDirectory = macroDir;
    macroPath = Fso.GetAbsolutePathName( macro );
    if ( Fso.FileExists( macroPath ) ) {
      return macroPath;
    }
    if ( Fso.FileExists( meryDir + "Macros\\" + macro ) ) {
      macroPath = meryDir + "Macros\\" + macro;
      return macroPath;
    }
    return "";
  };
  var MacroExist = function( macro ) {
    return MacroPath( macro ) ? 0 : meMenuGrayed;
  };


  // ポップアップメニュー項目
  var m   = CreatePopupMenu();
  var sm1 = CreatePopupMenu();
  var sm2 = CreatePopupMenu();
  var sm3 = CreatePopupMenu();

  m.Add( "  書き換え禁止 ON/OFF (&Y)", 2, rCheckFlags );
  m.Add( "", 0, meMenuSeparator );

  m.AddPopup( "  ファイル・フォルダ サブメニュー (&F)", sm3 );
  if ( path ) {
    sm3.Add( "ファイル名をコピー (&N)", 16 );
    sm3.Add( "フルパスをコピー (&C)", 17 );
    sm3.Add( "プロパティ (&R)", 8 );
    sm3.Add( "", 0, meMenuSeparator );
    sm3.Add( "親フォルダのパスをコピー (&P)", 18 );
    sm3.Add( "親フォルダを開く (&F)", 10 );
    sm3.Add( "実体ファイルをデスクトップにコピー (&Y)", 26 );
  }
  sm3.Add( "デスクトップフォルダを開く (&H)", 15 );
  sm3.Add( "", 0, meMenuSeparator );
  sm3.Add( "Mery フォルダを開く (&M)", 11 );
  if ( profileDirExist ) {
    sm3.Add( "データフォルダを開く (&D)", 12 );
  }
  if ( autoSaveBackup ) {
    sm3.Add( "自動保存フォルダを開く (&A)", 13, autoSaveFlags );
    sm3.Add( "バックアップフォルダを開く (&B)", 14, backupFlags );
  }
  sm3.Add( "", 0, meMenuSeparator );
  sm3.Add( "Mery.txt を開く (&T)", 19 );
  sm3.Add( "Mery.ini を開く (&I)", 20 );
  sm3.Add( "オプション (&O) ...", 21 );
  sm3.Add( "", 0, meMenuSeparator );
  if ( macroCountJS ) {
    sm3.Add( "&1. 「文字カウント」マクロ ...", 22, MacroExist( macroCountJS ) );
  }
  if ( macroBytesJS ) {
    sm3.Add( "&2. 「バイト数」マクロ", 23, MacroExist( macroBytesJS ) );
  }
  if ( pluginFavorite && pluginFavoriteAt ) {
    sm3.Add( "&3. 「" + pluginFavorite + "」プラグイン ...", 25 );
  }
  if ( macroCloseAllJS ) {
    sm3.Add( "", 0, meMenuSeparator );
    sm3.Add( "&4. 「すべて閉じる」マクロ ...", 24, MacroExist( macroCloseAllJS ) );
  }
  sm3.Add( "", 0, meMenuSeparator );
  sm3.Add( "「読み直し」マクロの JS ファイルを開く (&J)", 9 );
  sm3.Add( "", 0, meMenuSeparator );
  sm3.Add( "キャンセル & ", 0 );

  // 「無題」ドキュメントでは「読み直し」メニューを表示しない
  if ( path && reloadMenuEnable ) {
    m.AddPopup( "  読みなおし サブメニュー (&S)", sm1 );
    if ( tabEnble ) {
      sm1.Add( "閉じて開きなおす (&O)", 1 );
      sm1.Add( "", 0, meMenuSeparator );
    }
    sm1.Add( "書き換え禁止にする (&Y)", 3, rGrayFlags1 );
    sm1.Add( "書き換え禁止を解除 (&Y)", 4, rGrayFlags2 );
    if ( tabEnble ) {
      sm1.Add( "", 0, meMenuSeparator );
      // sm1.Add( "読み取り専用属性 ON/OFF (&W)", 5, aCheckFlags + aGrayFlags );
      sm1.Add( "読み取り専用属性にして開きなおす (&R)", 6, aGrayFlags1 );
      sm1.Add( "読み取り専用属性を解除して開きなおす (&R)", 7, aGrayFlags2 );
    }
    sm1.Add( "", 0, meMenuSeparator );

    // エンコード指定読みなおしメニュー
    // 2068 からの ID は ExecuteCommandByID() の定数
    sm1.Add( "", 0, meMenuSeparator );
    sm1.Add( "自動選択 (&A)", 2068 );
    sm1.Add( "", 0, meMenuSeparator );
    sm1.Add( "UTF-1&6LE", 2069, utf16le );
    sm1.Add( "UTF-16&BE", 2070, utf16be );
    sm1.Add( "UTF-&8", 2071, utf8 );
    sm1.Add( "UTF-&7", 2072, EncCheck( meEncodingUTF7 ) );
    sm1.Add( "", 0, meMenuSeparator );
    sm1.Add( "日本語 (シフト JI&S)", 2083, EncCheck( meEncodingShiftJIS ) );

    if ( variousLanguageEnable ) {
      sm1.Add( "日本語 (&JIS)", 2082, EncCheck( meEncodingJIS ) );
      sm1.Add( "日本語 (&EUC)", 2081, EncCheck( meEncodingEUC ) );
      sm1.Add( "", 0, meMenuSeparator );
      sm1.Add( "西ヨーロッパ言語", 2088, EncCheck( meEncodingWesternEuropean ) );
      sm1.Add( "中央ヨーロッパ言語", 2075, EncCheck( meEncodingCentralEuropean ) );
      sm1.Add( "キリル言語", 2078, EncCheck( meEncodingCyrillic ) );
      sm1.Add( "バルト言語", 2074, EncCheck( meEncodingBaltic ) );
      sm1.Add( "ギリシャ語", 2079, EncCheck( meEncodingGreek ) );
      sm1.Add( "ヘブライ語", 2080, EncCheck( meEncodingHebrew ) );
      sm1.Add( "トルコ語", 2086, EncCheck( meEncodingTurkish ) );
      sm1.Add( "アラビア語", 2073, EncCheck( meEncodingArabic ) );
      sm1.Add( "タイ語", 2085, EncCheck( meEncodingThai ) );
      sm1.Add( "ベトナム語", 2087, EncCheck( meEncodingVietnamese ) );
      sm1.Add( "簡体中国語 (GB2312)", 2076, EncCheck( meEncodingChineseSimplified ) );
      sm1.Add( "繁体中国語 (Big5)", 2077, EncCheck( meEncodingChineseTraditional ) );
      sm1.Add( "韓国語", 2084, EncCheck( meEncodingKorean ) );
    }
    sm1.Add( "", 0, meMenuSeparator );
    sm1.Add( "キャンセル & ", 0 );
  }	// if ( path && reloadMenuEnable )

  if ( viewModeMenuEnable ) {
    m.AddPopup( "  編集モード サブメニュー (&V)", sm2 );
    sm2.Add( "現在の編集モードのプロパティ (&P)...", 100 );
    sm2.Add( "", 0, meMenuSeparator );

    // 編集モードサブメニューの項目を自動で生成する場合
    if ( viewModeAutoSerchEnable ) {
      for ( var i = 0, len = iniValue[1].length, mode; i < len; i ++ ) {
        mode = iniValue[1][i];
        sm2.Add( "&" + mode, i + 101, ModeCheck( mode ) )
        // 下にセパレータを入れたい
        if ( mode == "XML" && i + 1 != len ) {
          sm2.Add( "", 0, meMenuSeparator );
        }
      }
      sm2.Add( "編集モードの設定 (&C)...", 200 );
    }

    // 編集モードサブメニューの項目を手動で取捨選択する場合
    else {
      sm2.Add( "編集モードの設定 (&C)...", 200 );
      /**
       * 以下、追加/削除したものがあれば任意で変更すること。
       * sm2 グループ内での並べ替え可。
       */ 

    /* ▼ ココに追加の編集モードを列挙する(id の範囲は 128 - 199)▼ */
      sm2.Add( "", 0, meMenuSeparator );
      // 編集モード名は正確に、アクセラレータの「&」または「(&A)」以外は付加しないこと
      // sm2.Add( "Hoge (&G)", 129 );
      // sm2.Add( "Fuga (&F)", 130 );
      // sm2.Add( "Piyo", 131 );

      // sm2.Add( "&Mery_Macro_JS", 132, ModeCheck( "Mery_Macro_JS" ) );
      // sm2.Add( "Mery MS&Y", 133, ModeCheck( "Mery MSY" ) );
      // sm2.Add( "&JaneStyle (正規表現用)", 134, ModeCheck( "JaneStyle (正規表現用)" ) );
    /* ▲ ココに追加の編集モードを列挙する ▲ */

      // ▼ デフォルトの編集モード ▼
      sm2.Add( "", 0, meMenuSeparator );
      sm2.Add( "&Bat", 101, ModeCheck( "Bat" ) );
      sm2.Add( "C&#", 102, ModeCheck( "C#" ) );
      sm2.Add( "C&++", 103, ModeCheck( "C++" ) );
      sm2.Add( "ColdFusion", 104, ModeCheck( "ColdFusion" ) );
      sm2.Add( "&CSS", 105, ModeCheck( "CSS" ) );
      sm2.Add( "&Delphi", 106, ModeCheck( "Delphi" ) );
      sm2.Add( "HSP", 107, ModeCheck( "HSP" ) );
      sm2.Add( "&HTML", 108, ModeCheck( "HTML" ) );
      sm2.Add( "&INI", 109, ModeCheck( "INI" ) );
      sm2.Add( "J&ava", 110, ModeCheck( "Java" ) );
      sm2.Add( "&JavaScript", 111, ModeCheck( "JavaScript" ) );
      sm2.Add( "JSP", 112, ModeCheck( "JSP" ) );
      sm2.Add( "Per&l", 113, ModeCheck( "Perl" ) );
      sm2.Add( "P&erlScript", 114, ModeCheck( "PerlScript" ) );
      sm2.Add( "&PHP", 115, ModeCheck( "PHP" ) );
      sm2.Add( "P&owerShell", 116, ModeCheck( "PowerShell" ) );
      sm2.Add( "P&ython", 117, ModeCheck( "Python" ) );
      sm2.Add( "RHT&ML", 118, ModeCheck( "RHTML" ) );
      sm2.Add( "&Ruby", 119, ModeCheck( "Ruby" ) );
      sm2.Add( "S&QL", 120, ModeCheck( "SQL" ) );
      sm2.Add( "TeX", 121, ModeCheck( "TeX" ) );
      sm2.Add( "&Text", 122, ModeCheck( "Text" ) );
      sm2.Add( "&UWSC", 123, ModeCheck( "UWSC" ) );
      sm2.Add( "VB&Script", 124, ModeCheck( "VBScript" ) );
      sm2.Add( "&VisualBasic", 125, ModeCheck( "VisualBasic" ) );
      sm2.Add( "&Widows Script", 126, ModeCheck( "Widows Script" ) );
      sm2.Add( "x86 Assembler", 127, ModeCheck( "x86 Assembler" ) );
      sm2.Add( "&XML", 128, ModeCheck( "XML" ) );
      // ▲ デフォルトの編集モード ▲
    }
    sm2.Add( "", 0, meMenuSeparator );
    sm2.Add( "キャンセル & ", 0 );
  }	// if ( viewModeMenuEnable )

  /* 【include版】の設定変更サブメニュー */ 
  if ( initialSettings.settingEnable  ) {
    m.Add( "", 0, meMenuSeparator );
    SettingsMenu( m );
  }

  if ( path ) {
    m.Add( "", 0, meMenuSeparator );
    m.Add( "  親フォルダを開く (&P)", 10 );
    m.Add( "  フルパスをコピー (&C)", 17 );
    m.Add( "  プロパティ (&R)", 8 );
  }

  // 「さいごに閉じたファイル」
  if ( numLatestClosed > 0 ) {
    m.Add( "", 0, meMenuSeparator );
    LatestClosedFileMenu( latestClosedFile, m, 300 );
  }

  if ( macroCloseAllJS ) {
    m.Add( "", 0, meMenuSeparator );
    m.Add( " 「すべて閉じる」マクロ ...", 24, MacroExist( macroCloseAllJS ) );
  }

  m.Add( "", 0, meMenuSeparator );
  m.Add( "  キャンセル & ", 0 );


  // ポップアップメニューを表示
  Status = " 「読みなおし」 マクロ  [ "
         + ( ( new Date() - start ) /1000 ).toFixed( 3 )
           .replace( /\./, ". " ) +" 秒 ]";
  r = m.Track( menuPosMouse );

  /**
   * 動作コードを変更 (2019/04/08)
   * ポップアップメニューを表示するまでの準備段階で
   * 変数の準備や属性のチェックは済ませてあるので
   * 各コマンドを簡略化した。
   */
  switch ( r ) {
    case 0:
      break;

    case 1:	// ファイルを閉じて開きなおす
      d.Close();
      ReopenFile( path );
      break;

    case 2:	// 書き換え禁止フラグ ON/OFF を変更する
    case 3:	// 書き換え禁止にする
    case 4:	// 書き換え禁止を解除
      d.ReadOnly = ! dReadOnly;
      break;

    case 5:	// 読み取り専用属性 ON/OFF を変更して開き直す
    case 6:	// 読み取り専用属性に変更して開き直す
    case 7:	// 読み取り専用属性を解除して開き直す
      // d.Save();	// コメントアウトすると未保存で閉じる前に確認ダイアログ
      d.Close();
      f.Attributes = attributeReadOnly
                   ? attributeReadOnly - 1
                   : attributeReadOnly + 1;
      ReopenFile( path );
      break;

    case 8:	// ファイルのプロパティを開く
      var fileName = d.Name;
      var folderPath = d.Path;
      var shell = new ActiveXObject( "Shell.Application" );
      shell.NameSpace( folderPath )
           .ParseName( fileName )
           .InvokeVerb( "プロパティ(&R)" );
      break;

    case 9:	// このマクロの JS ファイルを開く
      OpenJumpJS( "var settingEnable = " );
      break;

    // フォルダを開く
    case 10:	// 親フォルダを開く
      WshShell.Run( "explorer /select,\"" + path + "\"" );
      break;

    case 11:  case 12:  case 13:  case 14:  case 15:
      // var desktopDir = WshShell.SpecialFolders( "DeskTop" );
      var folder = ( r == 11 ) ? meryDir		// Mery フォルダ
                 : ( r == 12 ) ? profileDir		// データフォルダ
                 : ( r == 13 ) ? autoSaveFolder	// 自動保存フォルダ
                 : ( r == 14 ) ? backupFolder	// バックアップフォルダ
                 :               desktopDir;	// デスクトップフォルダ
      WshShell.Run( "\"" + folder + "\"");
      break;

    // パスをコピー
    case 16:  case 17:  case 18:
      var data = ( r == 16 ) ? d.Name	// ファイル名をコピー
               : ( r == 17 ) ? path		// フルパスをコピー
               :               d.Path;	// 親フォルダのパスをコピー
      ClipboardData.SetData( data );
      break;

    case 19:	// Mery.txt を開く
      ReopenFile( meryDir + "Mery.txt" );
      break;

    case 20:	// Mery.ini を開く
      ReopenFile( iniPath );
      break;

    case 21:	// オプション... (環境設定)
      editor.ExecuteCommandByID(MEID_TOOLS_OPTIONS = 2177);
      break;

    // 「文字カウント」「バイト数」「すべて閉じる」マクロを擬似インクルード
    case 22:  case 23:  case 24:
      macroPath = ( r == 22 ) ? MacroPath( macroCountJS )	// 「文字カウント」
                : ( r == 23 ) ? MacroPath( macroBytesJS )	// 「バイト数」
                :               MacroPath( macroCloseAllJS );	// 「すべて閉じる」
      try {
        eval( IO.Include( macroPath, "utf-8" ) );
      } catch ( e ) { Alert( e ); }
      break;

    case 25:	// 「お気に入り」プラグイン
      var meID = pluginFavoriteAt + 7167;	// MEID_PLUGINS = 7168 からの連番
      try {
        editor.ExecuteCommandByID( meID );
      } catch ( e ) { Alert( e ); }
      break;

    case 26:	// デスクトップにコピー
      if ( toolCopy && toolCopyOptions.charAt( 0 ) == " " ) {
        try {
          WshShell.Run( toolCopy + toolCopyOptions );
        } catch ( e ) { Alert( e ); }
      }
      else {
        CopyFileTo( path, desktopDir );
      }
      break;

    case 100:	// 現在の編集モードのプロパティ...
      WshShell.SendKeys( "%P" );
      editor.ExecuteCommandByID( MEID_VIEW_MODE_CUSTOMIZE = 2144 );
      break;

    case 200:	// 編集モードの設定...
      editor.ExecuteCommandByID( MEID_VIEW_MODE_CUSTOMIZE = 2144 );
      break;

    default:
      /* 【include版】の設定変更サブメニュー項目を選択した場合 */
      if ( r >= 10000000 && r <= 10000015 ) {
        SettingsChange( r );
      }

      else if ( r >= 300 && r < 400 ) {	// さいごに閉じたファイル
        ReopenFile( latestClosedFile[ r - 300 ] );
      }
      else if ( r >= 2068 && r <= 2091 ) {	// エンコード指定で読みなおす
        if ( pasteAfterReload ) {
          // 貼り付けオプション
          PasteAfterReload( d, r );
        }
        else {
          editor.ExecuteCommandByID( r );
        }
      }
      else {	// 編集モードを変更する( r = 100 番台)
        var label = m.GetText( r )
                     .replace( /[ ]*\(&.\)[ ]*|&/g , "" );
        d.Mode = label;
      }
      break;
  }

// 設定変更した場合はメニューを再表示する(キャレット位置表示のときのみ)
} while ( ! menuPosMouse && r >= 10000000 && r < 10000010 );

// プロセスのカレントディレクトリを復旧する
WshShell.CurrentDirectory = currentDir;


// ---------- ▼ 関数 ▼ ----------
// ※各関数は部分的にメインスコープの変数を参照する

/**
 * 関数 VersionCheck( versionStr )
 * Mery 本体が引数で指定したバージョン以上かチェックする( i.e. "2.6.9" )
 * 戻り値は、真偽値 true/false
 */
function VersionCheck( versionStr ) {
  var Pad2 = function( str ) {
    return str.replace( /[0-9]+/g , function( digit ) {
      return digit.length < 2 ? "0" + digit : digit
    } )
  };
  var editorVer = + ( Pad2( editor.Version ).replace( /\./g, "" ).slice( 0, 6 ) );
  var requirement = + ( Pad2( versionStr ).replace( /\./g, "" ).slice( 0, 6 ) );
  return ( editorVer >= requirement );
}

/**
 * 関数 GetIniOption( meryIniPath, keyArray, viewModeSerch )
 * ※「読みなおし」マクロ用改造版
 * 引数で指定した INI オプション項目の値と
 * 編集モード一覧を配列で返す
 */
function GetIniOption( iniPath, keyArray, viewModeSerch ) {
  // 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 );	// .replace( /\r\n?/g, "\n" )
  Adodb.Close();

  // 引数の配列をループ処理して ini からオプションの値を取得する
  var reg, value, iniOption = [];
  for ( var i = 0, len = keyArray.length; i < len; i ++ ) {
    reg = new RegExp( "^" + keyArray[i] + "=(.*?)$" , "m" );
    try {
      value = reg.exec( iniText )[1];
    } catch ( e ) { ; }	// エラーがあっても継続 → value = undefined
    if ( /^-?[0-9]+$/.test( value ) ) {
      value = Number( value );	// 10進数なら Number 型で返す
    }
    iniOption.push( value );
  }

  // 編集モード名を取得する
  var modeArray = [];
  if ( viewModeSerch ) {
    // \r\n [Modes\Mode##] \r\n Caption=ModeName を抽出
    var reg2 = /\r\n\[Modes\\Mode\d+\]\r\nCaption=[^\r\n]+/g;
    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];
    }
  }
  return [ iniOption, modeArray ];
}

/**
 * 関数 LatestClosedFile( meryhisPath, num, exclude )
 * ※「読みなおし」マクロ用改造版
 * Mery.his を読み込んで「さいごに閉じたファイル」のフルパスの配列を返す
 * 
 * ※ Mery の「オプション」設定で「カーソル位置とブックマークを保存する」
 *   が無効(Mery.his がない)なら [] を返す
 * ※ 自動保存・バックアップフォルダのパスはグローバル変数を参照する
 */
function LatestClosedFile( hisPath, num, woAutoSaved ) {
  var num = num ? num : 1;
  var closedFile = "";
  var closedFileArray = [];
  var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
  try {
    // 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 );	// .replace( /\r\n?/g, "\n" )
    Adodb.Close();
    // Mery.his からファイルパスを抽出する
    var hisArray = hisText.match( /^\[.+\]$/gm );
    // 現在開いているファイルにないものを「さいごに閉じたファイル」とする
    hisArray.reverse();
    var hCount = hisArray.length;
    var eCount = Editors.Count;
    var docus, dCount, filePath, hit;
    var _autoSaveFolder = autoSaveFolder;
    var _backupFolder = backupFolder;
    var CheckAutoSaveBackup = function( path ) {
      return ( path.indexOf( _autoSaveFolder ) == 0
            || path.indexOf( _backupFolder ) == 0 );
    };
    for ( var i = 0; i < hCount, closedFileArray.length < num; i ++ ) {
      closedFile = hisArray[i].slice( 1, -1 );
      if ( woAutoSaved && CheckAutoSaveBackup( closedFile ) ) {
        continue;
      }
      for ( var ee = 0, hit = 0; ee < eCount; ee ++ ) {
        docus = Editors.Item( ee ).Documents;
        dCount = docus.Count;
        for ( var dd = 0; dd < dCount; dd ++ ) {
          filePath = docus.Item( dd ).FullName;
          if ( closedFile == filePath ) { hit ++; }
        }
      }
      if ( ! hit && Fso.FileExists( closedFile ) ) {
        closedFileArray.push( closedFile );
      }
    }
  } catch ( e ) { closedFileArray = []; }
  finally { return closedFileArray; }
}

/**
 * 関数 LatestClosedFileMenu( objArray, objMenu, id )
 * 「さいごに閉じたファイル」のメニューを返す
 */
function LatestClosedFileMenu( objArray, objMenu, id ) {
  var count = objArray.length;
  var width = String( count ).length;
  var label, num;
  // objMenu.Add( "", 0, meMenuSeparator );
  objMenu.Add( "  ▼ さいごに閉じたファイル " + count + " 件 ▼"
             , 0, meMenuGrayed );
  for ( var i = 0; i < count; i ++ ) {
    // 「通し番号: 親フォルダ名\ ファイル名」に切りつめる
    num = ( "   " + ( i + 1 ) ).slice( - width ).replace( /\d$/, "&$&" );
    label = objArray[i].replace( /(?:.+\\)*([^\\]+\\)([^\\]+)$/, "$1 $2" );
    objMenu.Add( num + ":  " + label, i + id );
  }
}

/**
 * 関数 ReopenFile( strPath )
 * 「開きなおす」
 */
function ReopenFile( strPath ) {
  var WshShell = new ActiveXObject( "WScript.Shell" );
  WshShell.Run( "\"" + editor.FullName + "\" \""
              + strPath + "\"" );
}

/**
 * 関数 CopyFileTo( sourcePath, targetDir )
 * 「デスクトップにコピー」
 */
function CopyFileTo( strPath, targetDir ) {
  targetDir = targetDir.replace( /[\\]*$/, "\\" );
  var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
  try {
    // 上書きなしでコピーを実行
    Fso.CopyFile( strPath, targetDir, false );
  }
  catch ( e ) {
    // "既に同名のファイルが存在しています。"
    if ( e.number == -2146828230 ) {
      var msgStr = e.message + " \n\n"
                 + targetDir + strPath.replace( /\\[^\\]+$/, "" )
                 + " \n\n上書きしますか?"
      var nSecondsToWait = 0;
      var strTitle = "Mery: デスクトップにコピー - 「読みなおし」マクロ";
      var nType = 36;		// ボタン 4:[はい][いいえ]、アイコン 32:[?]
      var msgBox = WshShell.Popup( msgStr, nSecondsToWait, strTitle, nType );
      if ( msgBox == 6 ) {	// 1:[OK], 6:[はい]
        try {
          // 上書きありでコピーを実行
          Fso.CopyFile( strPath, targetDir, true );
        }
        catch ( e ) {	// e.g. "書き込みできません。" (-2146828218)
          // OutputBar.Writeln( e.message + " (" + e.number + ")" );
          Alert( e );
        }
      }
    }
    // 重複以外のエラーのとき
    else {
      // OutputBar.Writeln( e.message + " (" + e.number + ")" );
      Alert( e );
    }
  }
}

/**
 * 関数 PasteAfterReload( objDocu, encoding )
 * ※「読みなおし」マクロ 【改造版】 追加機能
 * エンコードを変更して読み直しをしたあと
 * 元のテキストをコピペする
 */
function PasteAfterReload( objDocu, encoding ) {
  var d = objDocu, s = d.selection;
  var y = s.GetActivePointY( mePosLogical );
  var saved = d.Saved; 
  s.SelectAll();
  var txt = s.Text;		// s.Copy();
  editor.ExecuteCommandByID( encoding );
  d.ReadOnly = false;
  s.SelectAll();
  // s.Text = txt  でうまくいかないようなら Copy/Paste
  s.Text = txt;		// s.Paste();
  s.SetActivePoint( mePosLogical, 1, y );
  d.Saved = saved;	// 「変更*」フラグを読みなおし前の状態に戻す
}

/**
 * 関数 OpenJumpJS( str )
 * ※「読みなおし」マクロ用改造版
 * このマクロを開いて設定項目の行にジャンプする
 */
function OpenJumpJS( str ) {
  Redraw = false;
  var targetStr = str || "";
  var eCount = editors.Count;
  var docus, dCount, dItem, ee, js;
  var isOpen = false;
  outerLoop:
  for ( var j = 0; j < eCount; j ++ ) {
    docus = editors.Item( j ).documents;
    dCount = docus.Count;
    for ( var i = 0; i < dCount; i ++ ) {
      dItem = docus.Item( i );
      if ( dItem.FullName == ScriptFullName ) {
        js = dItem;
        isOpen = true;
        break outerLoop;
      }
    }
  }
  if ( ! isOpen ) {
    editor.NewFile();
    ee = ( editor.EnableTab ) ? editor : editors.Item( eCount );
    ee.OpenFile( ScriptFullName, 0 );
    js = ee.ActiveDocument;
  }
  js.Activate();
  var settingPos = js.Text.indexOf( targetStr );
  js.selection.EndOfDocument();	// ScrollY よりも確実性が高い
  js.selection.SetActivePos( settingPos + targetStr.length );
  js.selection.WordRight( true );	// true を範囲選択
  Redraw = true;
}


// ---------- ▼ 【include版】 関数 ▼ ----------

/**
 * 関数 SettingsMenu( objPopupMenu )
 * ポップアップメニューに「設定変更」サブメニューを表示する
 * ※ 引数に設定項目オブジェクトをつけても処理速度に有意な差はない
 */
function SettingsMenu( objMenu ) {
  var subMenu = CreatePopupMenu();
  // メニューのオプションフラグ
  // ※定数 meMenuChecked の値は 1 なので hogeEnable *1 で代用できる
  // var settingFlag = settingEnable ? 0 : meMenuChecked;  →  settingEnable *1
  var grayFlag = ! settingEnable ? meMenuGrayed : 0;
  var grayFlag_1 = ( ! viewModeMenuEnable || ! settingEnable )
                 ? meMenuGrayed : 0;
  var grayFlag_2 = ( ! reloadMenuEnable || ! settingEnable )
                 ? meMenuGrayed : 0;
  var maxLatestClosedFlag = ( numLatestClosed > 29 ) ? meMenuGrayed : 0;
  var minLatestClosedFlag = ( numLatestClosed < 1 ) ? meMenuGrayed : 0;
  var woAutosaveFlag = ( minLatestClosedFlag || ! settingEnable )
                   ? meMenuGrayed : 0;

  // 「設定変更」サブメニューのアイテム
  // objMenu.Add( "----", 0, meMenuSeparator );
  objMenu.AddPopup( "  設定を変更する (&S)", subMenu );
  subMenu.Add( "「編集モード サブメニュー」を表示する (&V)"
             , 10000001, viewModeMenuEnable + grayFlag );
  subMenu.Add( "「編集モード」を自動で取得する (&A)"
             , 10000002, viewModeAutoSerchEnable + grayFlag_1 );
  subMenu.Add( "----", 0, meMenuSeparator );
  if ( path ) {
    subMenu.Add( "「読みなおし サブメニュー」を表示する (&L)"
               , 10000003, reloadMenuEnable + grayFlag );
    subMenu.Add( "  諸外国語用の文字コードを表示する (&F)"
               , 10000004, variousLanguageEnable + grayFlag_2 );
    subMenu.Add( "  読みなおし後に元のテキストを貼り付ける (&P)"
               , 10000005, pasteAfterReload + grayFlag_2 );
    subMenu.Add( "----", 0, meMenuSeparator );
  }
  subMenu.Add( "「さいごに閉じたファイル」の履歴を 2 件 増やす (&U)\t"
             + Math.max( numLatestClosed, 0 )
             + ( numLatestClosed > 29 ? "" : " → " + ( numLatestClosed + 2 ) )
             , 10000006, maxLatestClosedFlag || grayFlag );
  subMenu.Add( "「さいごに閉じたファイル」の履歴を 2 件 減らす (&D)\t"
             + Math.max( numLatestClosed, 0 )
             + ( numLatestClosed < 1 ? "" : " → "
             +  Math.max( ( numLatestClosed - 2 ), 0 ) ),
               10000007, minLatestClosedFlag || grayFlag );
  subMenu.Add( "  履歴に自動保存・バックアップファイルを含めない (&E)"
             , 10000008, woAutoSaved + woAutosaveFlag );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "  入力カーソル の位置 にメニューを表示する"
             + ( menuPosMouse ? " (&M)" : "" )
             , 10000009, ! menuPosMouse + grayFlag );
  subMenu.Add( "  マウスポインタの位置 にメニューを表示する"
             + ( menuPosMouse ? "" : " (&M)" )
             , 10000009, menuPosMouse + grayFlag );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "  設定内容をロックする (&S)", 10000000, ! settingEnable *1 );
  subMenu.Add( "", 0, meMenuSeparator );
  subMenu.Add( "「読みなおし」マクロの JS ファイルを開く (&J)", 10000013 );
  subMenu.Add( "「読みなおし」マクロの JSON ファイルを開く (&O)", 10000014 );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "  設定を初期化する (&I)", 10000015, grayFlag );
  subMenu.Add( "----", 0, meMenuSeparator );
  subMenu.Add( "  キャンセル\t& ", 0 );
}

/**
 * 関数 SettingsChange( num )
 * ポップアップメニューで選択した項目の設定状態を変更する
 * 
 * ※ グローバルスコープの設定変数と設定項目オブジェクトを書き換える
 * ※ 設定変更でのメニュー再表示 do - while ループのさいに
 *    JSON の再読みこみを省略するために
 *      ローカル変数名 = JSON 項目名(setting.hogeEnable) = 設定値
 *    の形式で記述する
 */
function SettingsChange( num ) {
  var sIsChanged = true;
  switch ( num ) {
    case 10000000:
      settingEnable = setting.settingEnable
                    = ! settingEnable;
      break;
    case 10000001:
      viewModeMenuEnable = setting.viewModeMenuEnable
                         = ! viewModeMenuEnable;
      break;
    case 10000002:
      viewModeAutoSerchEnable = setting.viewModeAutoSerchEnable
                              = ! viewModeAutoSerchEnable;
      break;
    case 10000003:
      reloadMenuEnable = setting.reloadMenuEnable
                       = ! reloadMenuEnable;
      break;
    case 10000004:
      variousLanguageEnable = setting.variousLanguageEnable
                            = ! variousLanguageEnable;
      break;
    case 10000005:
      pasteAfterReload = setting.pasteAfterReload
                       = ! pasteAfterReload;
      break;
    case 10000006:
      numLatestClosed = setting.numLatestClosed += 2;
      break;
    case 10000007:
      numLatestClosed = setting.numLatestClosed -= 2;
      break;
    case 10000008:
      woAutoSaved = setting.woAutoSaved
                       = ! woAutoSaved;
      break;
    case 10000009:
      menuPosMouse = setting.menuPosMouse
                   = ! menuPosMouse;
      break;
    case 10000013:
      sIsChanged = false;
      Status = " " + ScriptFullName;
      OpenJumpJS( "var settingEnable = " );
      break;
    case 10000014:
      sIsChanged = false;
      OpenJumpJson( jsonName, true );
      break;
    case 10000015:
      sIsChanged = false;
      CheckJsonFile( jsonName );
      break;
    default:
      sIsChanged = false;
      break;
  }
  if ( sIsChanged ) {
    try {
      IO.Serialize( setting, jsonName );
    } catch ( e ) {
      Status = "  " + e.message;
      Alert( e );
    }
    Status = e ? "  " + e.message : "  設定の変更を保存しました。";
  }
}

/**
 * 関数 OpenJumpJson( jsonName, bool )
 * ※「読みなおし」マクロ用改造版
 * JSON ファイルを開く
 */
function OpenJumpJson( jsonName, bool ) {
  // var jsonName = jsonName || ScriptName.replace( /\.js$/i, "" );
  bool = bool || false;
  var WshShell = new ActiveXObject( "WScript.Shell" );
  try {
    IO.Serialize( setting, jsonName );
  } catch ( e ) { ; }
  Sleep( 500 );
  var jsonDir = JsonDir();
  var jsonPath = jsonDir + "\\" + jsonName + ".json";
  var jsonContents = JsonContents( jsonPath, bool );
  if ( ! e && IO.Path.IsExist( jsonPath ) && jsonContents.length ) {
    var confirmStr = "設定ファイルの内容:"
                   + ( bool ? " (※デコードして表示)" : "" ) + " \n\n"
                   + jsonContents
                   + "設定ファイルを開きますか? ";
    var nSecondsToWait = 0;
    var strTitle = "Mery: JSON ファイルの確認 - 「読みなおし」マクロ";
    var nType = 36;	// ボタン 4:[はい][いいえ]、アイコン 32:[?]
    var msgBox = WshShell.Popup( confirmStr, nSecondsToWait, strTitle, nType );
    if ( msgBox == 6 ) {	// 6:[はい]
      ReopenFile( jsonPath );
    }
  }
  else if ( e ) {
    Alert( e + " \n\n"
         + jsonPath + "  " );
  }
  else if ( ! e ) {
    Alert( "設定ファイルがありません \n\n"
         + jsonDir + "  " );
  }
}

/** 
 * 関数 CheckJsonFile( jsonName, bool )
 * ※「読みなおし」マクロ用改造版
 * JSON ファイルの初期化/実在確認
 */
function CheckJsonFile( jsonName, bool ) {
  // var jsonName = jsonName || ScriptName.replace( /\.js$/i, "" );
  var WshShell = new ActiveXObject( "WScript.Shell" );
  var jsonDir = JsonDir();
  var jsonPath = jsonDir + "\\" + jsonName + ".json";
  bool = bool || false;
  var msgStr = jsonPath + "  \n\n"
             + "設定ファイルを初期化しますか? "
  var nSecondsToWait = 0;
  var strTitle = "Mery: JSON ファイルの初期化 - 「読みなおし」マクロ";
  var nType = 52;	// ボタン 4:[はい][いいえ]、アイコン 48:[!]
  var msgBox = WshShell.Popup( msgStr, nSecondsToWait, strTitle, nType );
  if ( msgBox == 6 ) {	// 6:[はい]
    try {
      IO.Serialize( setting, jsonName );
    } catch ( e ) { ; }
    Sleep( 500 );
    var jsonContents = JsonContents( jsonPath, bool );
    if ( ! e && IO.Path.IsExist( jsonPath ) && jsonContents.length ) {
      msgStr = "設定ファイルを初期化しました。"
             + ( bool ? "(※デコードして表示)" : "" ) + " \n\n"
             + jsonContents;
      var nType = 64;
      WshShell.Popup( msgStr, nSecondsToWait, strTitle, nType );
    }
    else if ( e ) {
      Alert( e + " \n\n"
           + jsonPath + "  " );
    }
    else if ( ! e ) {
      Alert( "設定ファイルを初期化できませんでした。 \n\n"
           + jsonDir + "  " );
    }
  }
}

/** 
 * 関数 JsonDir()
 * ※「読みなおし」マクロ用改造版
 * JSON ファイルの親フォルダのパス
 */
function JsonDir() {
  var jsonDir;
  var WshShell = new ActiveXObject( "WScript.Shell" );
  if ( IO.Path.IsExist( editor.FullName.replace( /\.exe$/i, ".ini" ) ) ) {
    jsonDir = editor.FullName.replace( /[^\\]+\.exe$/i, "" )
            + "Macros\\MacroSettings";
  }
  else {
    jsonDir = WshShell.SpecialFolders( "APPDATA" )
            + "\\Mery\\MacroSettings";
  }
  return jsonDir;
}

/** 
 * 関数 JsonContents( jsonPath [, bool] )
 * JSON ファイルの文字列をメッセージボックス用に整形する
 */
function JsonContents( jsonPath, bool ) {
  var contents = ( jsonPath + "  \n"
  + IO.LoadFromFile( jsonPath )
     .replace( /^\{/, "\n{\n  " )
     .replace( /\}$/g, "\n}\n\n" )
     .replace( /,/g, " ,\n  " )
     .replace( /\":/g, "\": " )
  );
  if ( bool ) {
    // 「テキスト整形」マクロより >> 符号化/復号化 >> \uHHHH デコード
    var Decode_uHHHH = function( str ) {
      return str.replace( /\\u([0-9A-Fa-f]{4})/g, function( s, n ) {
        return String.fromCharCode( Number( "0x" + n ) )
      } )
    };
    return Decode_uHHHH( contents );
  }
  else {
    // 半角アルファベットの小文字を全角にするなら
    contents = contents.replace( /[a-z]/g, function( tmp ) {
      return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
    } );
    return contents;
  }
}

メモ[編集]

自家用で使っているソースコードから実験的要素を間引いたものにしてあります。当方ではバグのない状態で使用できていますが、公開用のソースコードでは「機能を間引いた」さいにミスをしてしまっている可能性がありますので、お気づきの点がありましたら、こちらのメモ欄の「編集」からお知らせください。

機能を盛りすぎてマクロの処理速度が遅くなってしまいましたが、2回目以降は 0.1 秒程度でポップアップメニューが表示されるようなので、許容範囲内として様子見…。


スポンサーリンク