Mery.his の履歴を整理

提供: MeryWiki
ナビゲーションに移動 検索に移動

Mery.his の履歴を整理[編集]

履歴ファイル Mery.his の内容を整理します。


機能[編集]

Mery.his には、過去に開いたファイルごとの
 ・カーソル位置
 ・縦書き表示 ON/OFF の状態
 ・ブックマーク行の論理行番号
が記録されていますが、移動・削除・リネームなどにより実体ファイルがなくなったファイルの記録も残りつづけ、Mery.his は肥大化していきます。

[オプション] 設定ダイアログの [履歴] カテゴリ(タブ) から [カーソル位置とブックマーク] の [履歴を消去] すると Mery.his ファイルをクリアできますが、ブックマーク機能を利用しているユーザーにおいては [履歴を消去] するわけにいきません。

このマクロは、実体ファイルがなくなったファイルについての情報を削除した Mery.his.his ファイルを作成します。


このページのマクロは、「includeライブラリ」を利用して、履歴ファイル(Mery.his)の読み込みと、整理済みの履歴ファイル(Mery.his.his)の保存をおこないます。
あらかじめ「includeライブラリ」を Macros フォルダに配置してください。


設定項目[編集]

  • 整理済みの履歴ファイルに付加する拡張子の指定: ext (初期値:"his"
"mery.his" のうしろに二重拡張子として追加する拡張子を指定します。
半角英数字の文字列で指定してください(ファイルシステムのダメ文字は無視されます)。
※ 未指定の場合は"his"が適用されます。
  • カーソル位置だけの履歴データも削除 する/しない:ignorePos (初期値:false
trueにすると、実体ファイルはあっても、保存されている履歴情報が「カーソル位置」だけのファイルの履歴データも削除できるようになります。
※「ブックマーク」や「縦書き表示」の設定が保存されている履歴データは削除しません。
  • 整理対象から除外するドライブレターの指定:excludeDrives (初期値:""
リムーバルドライブが接続されていないためにファイルの実体確認ができないようなファイルがある場合、ドライブレターを指定して「履歴の整理」から除外します。
※ 例: "E,F,Z" ← カンマで区切って指定する
  • アウトプットバーにログを出力 する/しない:outputEnable (初期値:true
対象の履歴データの件数や、削除対象の履歴データの行数・ファイルパスなどのログをアウトプットバーに出力 する/しない の設定です。


使い方[編集]

マクロから Mery.his ファイルの内容を変更することはできませんので、手動でのファイルの削除やリネーム操作が必要になります。

  1. このマクロのソースコードファイル「Mery.his の履歴を整理.js」を開き、冒頭の説明文をよく読んだうえで、動作設定 ext ignorePos excludeDrives outputEnable の各項目をカスタマイズしてください。
  2. このマクロを実行する前に、編集中のすべての文書を 保存済み にしてください。
    ※ 開いているすべてのタブ上で文書の編集操作をしておらず、カーソル位置の変更やブックマークの追加・削除だけをおこなっている場合は、Mery を再起動してください (Mery.his を最新の状態に更新する必要があるため)。
  3. このマクロを実行すると「履歴の整理」の開始前に確認ダイアログが表示されます。
    Mery.his の履歴を整理 1.png
  4. [OK] をクリックすると「履歴の整理」を実行して、「保存の確認」ダイアログが表示されます。
    Mery.his の履歴を整理 2.png
  5. [はい] をクリックすると、Mery.his があるフォルダ内に整理済みの履歴ファイル Mery.his.his を生成し、エクスプローラでフォルダを開きます。
    ※[キャンセル] した場合は、Mery.his.his の保存をせずに終了します。
  6. Mery のすべてのウインドウとシステムトレイの常駐アイコンを閉じて、既存の Mery.his ファイルを削除(またはリネームしてバックアップ)してから、Mery.his.his のファイル名を Mery.his にリネームしてください。
  7. 以上で「Mery.his の履歴を整理」が完了します。


ソースコード[編集]

ダウンロード >> 「ファイル:Mery.his の履歴を整理.zip

#title   = "Mery.his の履歴を整理"
#tooltip = "実在しないファイルの履歴データを削除して Mery.his.his として保存する"
#include "include/IO.js"
// #icon = "restore.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",34

/**
 * ---------------------------------------------------------
 * 「Mery.his の履歴を整理」マクロ
 * sukemaru, 2021/01/20
 * ---------------------------------------------------------
 * ▼ 機能 ▼
 * "Mery.his" からすべての履歴情報を読みこみ
 * ファイルの実在確認ができない履歴データを除去して
 * "Mery.his.his" (二重拡張子) として別名保存する。
 * ※ 既存の "Mery.his" ファイルと中身のデータは保持する。
 * 
 * ▼ 注意事項(仕様上の制限) ▼
 * ・要:「includeライブラリ」
 * https://www.haijin-boys.com/wiki/include%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA
 * 
 * ・マクロからは "Mery.his" ファイルを直接上書きすることはできないので、
 *   整理した履歴データは別名ファイル "Mery.his.his" (二重拡張子) として保存する。
 *   → このマクロの実行後に Mery のプロセスをすべて(タスクトレイの常駐も)終了してから、
 *      ユーザー自身が手動で既存の "Mery.his" を削除(またはバックアップ)し、
 *      "Mery.his.his" を "Mery.his" にリネームしなおす必要がある。
 * ※ 実行ファイル Mery.exe のベース名("Mery" の部分)を変更している場合、
 *    履歴ファイルのベース名もそれに同期して生成されるので、
 *    整理済みの履歴用のファイル名もそれに従う
 *    (e.g. "MyMery.exe" なら "MyMery.his" → "MyMery.his.his")。
 * ※ 二重拡張子の部分(元の拡張子の後ろに追加)は、設定項目から変更可。
 * 
 * ・"Mery.his" の履歴データの更新のタイミングはファイルの保存時か
 *   タブを閉じたとき、または Mery の終了時なので、
 *   マクロ実行前に未保存のタブがあると "Mery.his.his" に反映されない場合がある
 *   (マクロ実行後に変更したカーソル位置やブックマークの情報は保存されない)。
 * ※ Mery を一度再起動してからすぐにこのマクロを実行し、
 *    開いているタブの状態を変更せずに Mery を完全に(タスクトレイの常駐も)終了して、
 *   "Mery.his.his" を "Mery.his" にリネームしなおすのが好ましい。
 * 
 * ・ファイルパスがフルパス(絶対参照)で記録されていない履歴データは削除対象とする
 *   (マクロの document.Save( fileName ) で保存されたためにフォルダパスがないものなど)。
 * ※ Mery の再起動後に開きなおしてもブックマークなどが正常に読みこまれないので不要。
 * 
 * ・カーソル位置だけの履歴データも削除可
 *   (ブックマーク設定か縦書き設定がある履歴データは残す)。
 * ※ 設定項目の初期値: ignorePos = false (カーソル位置だけの履歴データを残す)
 * ※「ブックマーク」や「縦書き表示」の機能を利用していないなら…
 *   → [オプション] ダイアログ内から「カーソル位置とブックマーク」の履歴を消去。
 * ※「整理対象から除外するドライブ」の設定項目よりも優先的。
 * 
 * ・未接続のドライブがある状態でこのマクロを実行すると、
 *   そのドライブ配下のファイルについての履歴データは削除対象になる (実在確認できないため)。
 * ※ 整理対象から除外するドライブを、設定項目で指定可。
 * 
 * ・"Mery.his" 内の各ファイルごとの履歴データが空行で区切られている状態でないと
 *   すべての履歴データを正常に取得し、整理することができない
 *   (空行区切りの各ブロックごとに1件のデータとして処理する)。
 * ※ "Mery.his" の読みこみ/"Mery.his.his" の保存形式は UTF-8 (BOMつき)、CR+LF。
 * 
 * ▼ "Mery.his" に保存されている「各ファイルごとの履歴データ」の記述形式 ▼
 *   [pathStrings]↲	: ファイルのフルパス
 *   Pos=###↲		: カーソル位置
 *   Vertical=#↲	: 縦書き表示 ON/OFF の状態
 *   Mark#=###↲		: ブックマーク行の論理行番号(Mery ver 2.7.0 ~ )
 *   ##=###↲		( ~ Mery ver 2.6.x では、通し番号とブックマーク行の行頭インデックス)
 *   ↲	: (空行)
 * 
 */

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

// ■ 整理済みファイルに付加する拡張子の指定 ※ 必須 ※
// ("mery.his" のうしろに二重拡張子として追加)
var ext = "his";	// 初期値: "his"  →  新しいファイル名は "Mery.his.his"

// ■ カーソル位置だけの履歴データも削除する ※ 任意 ※
// true なら、「ブックマーク」や「縦書き表示」の設定がない履歴データは削除
var ignorePos = true;	// 初期値: false

// ■ 整理対象から除外するドライブレター ※ 任意 ※
// ※ 実在確認できなくても削除しないが、ignorePos (←優先) の削除対象には含める
var excludeDrives = "";	// 例: "E,F,Z" ← カンマで区切って指定する

// ■ アウトプットバーにログを出力する ※ 任意 ※
// 整理実行の前/後の履歴データの総数、削除したデータの件数、
// 削除した各データブロックごとの行数や先頭行の文字列など
var outputEnable = true;

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


Main: {
  // ext に指定した文字列が不適切な文字を含むなら除去、または ".his" に変更
  var appendExt  = ( ext && /\w/.test( String( ext ) ) )
                 ? '.' + ext.toString().replace( /[\s.\/"*:<>?\\|]/g, '' ) : '.his';
  var ruleOutDrv = String( excludeDrives || '' );
  var strong     = Boolean( ignorePos || false );

  var Fso        = new ActiveXObject( 'Scripting.FileSystemObject' );
  var WshShell   = new ActiveXObject( 'WScript.Shell' );
  var meryPath   = editor.FullName;
  var meryName   = Fso.GetBaseName( meryPath );
  var meryDir    = Fso.GetParentFolderName( meryPath ) + '\\';
  var dataDir    = Fso.FileExists( meryDir + meryName + '.ini' )
                 ? meryDir
                 : WshShell.SpecialFolders( 'APPDATA' ) + '\\Mery\\';
  var iniPath    = dataDir + meryName + '.ini';
  var hisName    = meryName + '.his';
  var hisPath    = dataDir + hisName;
  var hishisName = hisName + appendExt;
  var hishisPath = hisPath + appendExt;
  var hisText,  iniText,  msgStr,  strTitle,  r;
  var trayIcon = true;
  var $status  = Status;
  Status = ' 「Mery.his の履歴を整理」マクロ: ' + hisPath;

  // mery.his ファイルがなければ終了
  if ( ! Fso.FileExists( hisPath ) ) {
    Alert ( '"' + hisName + '" ファイルがありません。 ' );
    break Main;
  }

  // タスクトレイ常駐の有無を確認(mery.ini から取得)
  try {
    iniText  = IO.LoadFromFile( iniPath, "utf-8" ) || '';
    trayIcon = ( iniText.indexOf( "TrayIcon=0\n" ) === -1 );
  } catch( e ) { ; }

  // 「履歴の整理」の実行前に確認ダイアログを表示
  strTitle = 'Mery: 「Mery.his の履歴を整理」マクロ';
  msgStr = '"' + hisName + '" ファイルから非実在ファイルの履歴データを消去したものを  \n'
  + '"' + hishisName + '" ファイルとして保存します。\n\n'
  + '履歴の整理を実行しますか?\n\n'
  + '※ "' + hisName + '" ファイル自体の内容は変更しません。\n'
  + '※ 編集中 (未保存) のタブがある場合は、実行前に保存しておくことをお勧めします。  \n'
  + ( trayIcon ? '\nタスクトレイに ' + meryName + ' が常駐している場合は、\n'
  + 'トレイアイコンの右クリックメニューからトレイアイコンを閉じてください。  \n' : '');
  // ボタン 1:[OK][キャンセル], アイコン 32:[?]
  var msgBox = WshShell.Popup( msgStr, nSecondsToWait = 0, strTitle, nType = 1 + 32 );

  // キャンセル(終了)
  if ( msgBox === 2 ) {	// [OK] = 1 / [キャンセル] = 2
    Status = $status;
    break Main;
  }

  // mery.his ファイルを読みこむ
  hisText = IO.LoadFromFile( hisPath, 'utf-8' );

  // mery.his の読みこみに失敗したら終了
  if ( hisText === null ) {
    Alert ( '"' + hisName + '" ファイルを読みこめませんでした。 ' );
    WshShell.Run( Fso.FileExists( hisPath )
    ? 'explorer /select,"' + hisPath + '"' : '"' + dataDir + '"' );
    break Main;
  }
  // mery.his にデータがなければ終了
  else if ( ! /\S/g.test( hisText ) ) {
    Alert ( '"' + hisName + '" ファイルに履歴データがありませんでした。 ' );
    Status = $status;
    break Main;
  }

  // mery.his の履歴データを整理
  r = MeryHisCleaner( hisText, hisPath, hisName, appendExt, strong, ruleOutDrv, outputEnable );

  // 履歴データの件数に変更がなければ終了
  if ( ! r.del ) {
    Status = $status;
    Alert( '削除する必要のある履歴データはありませんでした。 \n\n'
    + '履歴データの件数: ' + r.result + ' 件\n' );
    break Main;
  }

  // "mery.his.his" を保存して Mery フォルダを開くための確認ダイアログを表示
  Status = ' 保存先: ' + hishisPath;
  strTitle = 'Mery: 「Mery.his の履歴を整理」マクロ - 保存の確認';
  msgStr = '削除する履歴データの件数: ' + r.del + ' 件\n'
  + '保存する履歴データの件数: ' + r.result + ' 件\n\n\n'
  + '"' + hishisPath + '" に保存して  \n'
  + ' ' + meryName + ' のデータフォルダを開きますか? \n\n\n'
  + '※ 元の "' + hisName + '" ファイル自体の内容は変更しません。 \n'
  + '※ 既存の "' + hishisName + '" ファイルがあれば上書きします。 \n\n'
  + '手動操作で ' + meryName + '.exe のプロセスを完全に終了してから \n'
  + '"' + hisName + '" ファイルを削除 (またはバックアップ) して、 \n'
  + '"' + hishisName + '" ファイルを "' + hisName + '" にリネームしてください。  \n'
  + ( trayIcon ? '\nタスクトレイに ' + meryName + ' が常駐している場合は、\n'
  + 'トレイアイコンの右クリックメニューから「終了」してください。 \n' : '');
  // ボタン 4:[はい][いいえ], アイコン 32:[?], 既定 256:[第2ボタン]
  msgBox = WshShell.Popup( msgStr, 0, strTitle, 4 + 32 );	// + 256

  // キャンセル(終了)
  if ( msgBox === 7 ) {	// [はい] = 6 / [いいえ] = 7
    Status = $status;
    Output( '*保存しないで終了\n', outputEnable );
    break Main;
  }

  // "mery.his.his" ファイルを保存して Mery のデータフォルダを開く
  try {
    // Mery.his.his の保存形式は UTF-8 (BOMつき) / CR+LF
    IO.SaveToFile( path = hishisPath, text = r.hishis
    , charset = 'utf-8', hasBOM = true, newline = '\r\n' );
    Output( '*"'+ hishisPath + '" に保存\n', outputEnable );
    WshShell.Run( 'explorer /select,"' + hisPath + '"' );
  }
  // "mery.his.his" を保存できなかったとき
  catch( e ) {
    Status = ' データフォルダ: ' + dataDir;
    Output( '*"'+ hishisPath + '" の保存に失敗\n' + e + '\n', outputEnable );
    Alert( e + ' \n\n"' + hishisPath + '" に保存できませんでした。 ' );
    WshShell.Run( Fso.FileExists( hishisPath )
    ? 'explorer /select,"' + hishisPath + '"' : '"' + dataDir + '"' );
  }
}	// Main: {}
iniText = hisText = r = Fso = WshShell = null;


/**
 * 関数 Output( str, outputEnable )
 * ログのアウトプット用
 */
function Output( str, outputEnable ) {
  if ( outputEnable ) { OutputBar.Writeln( str ); }
}

/**
 * 関数 MeryHisCleaner( hisText, hisPath, hisName, ext, ignorePos, excludeDrives, outputEnable )
 * Mery.his を読みこみ、実在確認できないファイルの履歴データや無効な行の有無をチェックする。
 */
function MeryHisCleaner( hisText, hisPath, hisName, ext, ignorePos, excludeDrives, outputEnable ) {
  // 除外するドライブレター、パス
  var dLetters = excludeDrives.split( ',' );
  var dCount   = dLetters.length;

  // 履歴データを配列化;
  var hisArray = hisText.split( /\n\n+/ );	// 空行ごとに区切って取得
  var len      = hisArray.length;
  Output( '「Mery.his の履歴を整理」 マクロ - MeryHisCleaner\n・"'
  + hisName + '" 内の履歴データの件数: ' + len + ' 件'
  , outputEnable );

  var filePathReg   = /^\[(.+)\]$/m;            // 各ブロックの先頭行
  var newLinesReg   = /\n/g;                    // 各ブロックの行数(ログ用)
  var dataLinesReg  = /\n[\s\S]*/;              // 2行目以降(ログ用)
  var dLetterReg    = /[a-z]:[\/\\]/i;          // ドライブレター
  var bookmarkReg   = /^(?:Mark)?\d+=\d+$/m;    // ブックマーク設定
  var verticalReg   = /^Vertical=1$/m;          // 縦書き表示の設定
  var cursorPos0Reg = /^Pos=0$/m;               // カーソル位置の設定

  // 不要な履歴データを削除したテキストを作成する
  var newStr = '';
  var del    = 0;
  var fso    = new ActiveXObject( 'Scripting.FileSystemObject' );
  OuterLoop:
  for ( var i = 0, hisItem, filePath, outputStr; i < len; i ++ ) {
    hisItem   = hisArray[i] || '';
    filePath  = filePathReg.exec( hisItem );
    outputStr = ( hisItem.match( newLinesReg ) || '' ).length + '行:'
              + hisItem.replace( dataLinesReg, '' ) + ' ...';

    // 無効なデータ(1行目が [pathStrings] ではない)
    if ( ! filePath ) {
      del ++;
      Output( '‐削除対象(無効なデータ)' + outputStr, outputEnable );
    }
    // 絶対参照でないファイルパス(ドライブ名がない)
    else if ( ! dLetterReg.test( filePath[1] ) ) {
      del ++;
      Output( '‐削除対象(不完全なパス)' + outputStr, outputEnable );
    }

    // ブックマークと縦書き表示の設定がない履歴データ
    else if ( ! bookmarkReg.test( hisItem ) && ! verticalReg.test( hisItem )
    // カーソル位置が文頭 または カーソル位置を無視
    && ( cursorPos0Reg.test( hisItem ) || ignorePos ) ) {
      del ++;
      Output( '‐削除対象(不要な履歴)' + outputStr, outputEnable );
    }

    // ファイルの実在確認ができない履歴データ
    else if ( ! fso.FileExists( filePath[1] ) ) {
      // 除外対象ドライブのチェック
      for ( var j = 0, exclude = false, roleOutReg; j < dCount; j ++ ) {
        roleOutReg = RegExp( '^' + dLetters[j] + ':[\\/\\\\]', 'i' );
        // 実在確認できなくても残す
        if ( roleOutReg.test( filePath[1] ) ) {
          exclude = true;
          newStr += hisItem + '\n\n';
          Output( '※ 除外対象 (' + dLetters[j] + ':) ' + outputStr, outputEnable );
          continue OuterLoop;
        }
      }
      // 削除する
      if ( ! exclude ) {
        del ++;
        Output( '‐削除対象(実体なし)' + outputStr, outputEnable );
      }
    }

    // 残す履歴データ
    else { newStr += hisItem + '\n\n'; }
  }	// OuterLoop:

  // 戻り値用のオブジェクト
  var r = {
    del    : del,
    result : len - del,
    hishis : newStr
  };

  // 削除対象のデータあり
  if ( del ) {
    Output( '・削除する履歴データの件数: ' + del + ' 件\n'
    + '・"'+ hisName + ext + '" に残す履歴データの件数: ' + r.result + ' 件'
    , outputEnable );
  }
  // 履歴データの変更なし
  else {
    Output( '*履歴データの件数に変更なし\n', outputEnable );
  }

  hisText = hisArray = newStr = fso = null;
  return r;
}
スポンサーリンク