「「クリップボード履歴」メニューのマクロ化」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
(第4版(修正・更新版))
(第5版)
1行目: 1行目:
 
== 概要 ==
 
== 概要 ==
 
<br>
 
<br>
公式フォーラム[https://www.haijin-boys.com/discussions/4686] にて「[[ヘルプ:ツール#クリップボード履歴|クリップボード履歴]]」メニューの将来的に廃止されることが 予告?検討? されていますが、後継機能としては [[クリップボード履歴|「クリップボード履歴」プラグイン]] の登場により今後も安泰のようですね。
+
公式フォーラム[https://www.haijin-boys.com/discussions/4686] にて「[[ヘルプ:ツール#クリップボード履歴|クリップボード履歴]]」メニューの将来的に廃止されることが 予告?検討? されていますが、後継機能としては [[クリップボード履歴|「クリップボード履歴」プラグイン]] の登場により今後も安泰のようです。
  
 
ということで、試験運用中だった自家用マクロを再度リサイクルして「'''クリップボード履歴'''と'''スニペット'''」の統合版ポップアップメニューにしてみました。
 
ということで、試験運用中だった自家用マクロを再度リサイクルして「'''クリップボード履歴'''と'''スニペット'''」の統合版ポップアップメニューにしてみました。
11行目: 11行目:
 
<br>
 
<br>
 
<div class="warningbox">
 
<div class="warningbox">
* <b style="color:#c00;">このマクロは Mery 2.8.1 以降でしか利用できません。</b>
+
*'''「クリップボード履歴」機能は <span style="color:#c00;"> Mery 2.8.1 以降 </span> でしか利用できません。'''
 
* あらかじめ「[[includeライブラリ]]」の導入が必要です。
 
* あらかじめ「[[includeライブラリ]]」の導入が必要です。
 
</div>
 
</div>
* 外部実行ファイル「[[GetKeyState.exe(キー状態取得実行ファイル)|GetKeyState.exe]] 」で機能を拡張できます。
+
* 外部実行ファイル「[[GetKeyState.exe(キー状態取得実行ファイル)|GetKeyState.exe]]」で機能を拡張できます(なくても差し支えありません)。
 
* 「[[プラグイン:スニペットプラグイン|スニペットプラグイン]]」を導入していないでも「スニペット(定型文)」機能を利用できます。
 
* 「[[プラグイン:スニペットプラグイン|スニペットプラグイン]]」を導入していないでも「スニペット(定型文)」機能を利用できます。
 
: ※ '''snippets.txt''' 内のタブインデントによる階層構造をある程度ポップアップメニューに反映させました。(2019/11/05)
 
: ※ '''snippets.txt''' 内のタブインデントによる階層構造をある程度ポップアップメニューに反映させました。(2019/11/05)
26行目: 26行目:
  
 
=== ツールメニューの「クリップボード履歴」と異なる部分 ===
 
=== ツールメニューの「クリップボード履歴」と異なる部分 ===
(2019/11/05)
+
(2019/11/09)
 
<br>
 
<br>
 
* 「クリップボードのすべての履歴を削除」 「履歴からアイテムをひとつ削除」 「貼り付けしてからアイテムを削除」 「履歴からアイテムをスニペットに登録」 の機能を追加してあります。
 
* 「クリップボードのすべての履歴を削除」 「履歴からアイテムをひとつ削除」 「貼り付けしてからアイテムを削除」 「履歴からアイテムをスニペットに登録」 の機能を追加してあります。
32行目: 32行目:
 
* 「クリップボードのすべての履歴を削除」 したあとでも、Windows OS のクリップボードの最新の1件がテキストデータである場合は、「クリップボード履歴」にアイテムが表示されます。
 
* 「クリップボードのすべての履歴を削除」 したあとでも、Windows OS のクリップボードの最新の1件がテキストデータである場合は、「クリップボード履歴」にアイテムが表示されます。
 
: Mery 本来の「クリップボード履歴」機能でも「履歴を消去」したあとにも Ctrl+V によるペーストができることがあるので、これを可視化してあります。
 
: Mery 本来の「クリップボード履歴」機能でも「履歴を消去」したあとにも Ctrl+V によるペーストができることがあるので、これを可視化してあります。
 +
* 「クリップボード履歴」 に重複アイテムアイテムがある場合は、ひとつを残して削除します。
 
<br>
 
<br>
 
----
 
----
  
 
=== 「スニペットプラグイン」と異なる部分 ===
 
=== 「スニペットプラグイン」と異なる部分 ===
(2019/11/05)
+
(2019/11/09)
 
<br>
 
<br>
 
* <span style="color:#0000c0;">このマクロからスニペットに登録したアイテムは、snippets.txt の末尾に追加されます。</span>
 
* <span style="color:#0000c0;">このマクロからスニペットに登録したアイテムは、snippets.txt の末尾に追加されます。</span>
 
* snippets.txt 内の「 '''&''' 」記号によるアクセラレータをすべて無視します。
 
* snippets.txt 内の「 '''&''' 」記号によるアクセラレータをすべて無視します。
 
: → 有効文字列のある行を上から順に連番化し、番号をアクセラレータにします。
 
: → 有効文字列のある行を上から順に連番化し、番号をアクセラレータにします。
 +
* snippets.txt 内の半角ハイフン「 - 」ひとつとと空白だけの行をセパレータにしません。
 +
: (メイン階層を「クリップボード履歴」と共用しているため、体裁上の都合で「ピン止めアイテム」内でのセパレータは見送り)
 +
: ※「-」×2 以上であれば、有効文字列として扱います。
 +
: ※「ピン止めアイテム/スニペット」サブメニュー内では、階層ごとに区切ってベタで列挙します。
 
* snippets.txt 内の「空行・空白行」の扱い方などでスニペットプラグインと異なる解釈をしている部分があります。
 
* snippets.txt 内の「空行・空白行」の扱い方などでスニペットプラグインと異なる解釈をしている部分があります。
: <span style="color:#c00;">このマクロでは、snippets.txt 内の 空行とタブ文字だけの空白行を完全に無視するので、「空文字のサブメニュー見出し」を作りません。</span>
+
: <span style="color:#c00;">このマクロでは、snippets.txt 内の空行とタブ文字/半角空白だけの空白行を完全に無視するので、「空文字のサブメニュー見出し」を作りません</span>(ただし、全角空白や2つ以上のハイフン「 -- 」は有効な文字列として扱います)。
 
: → ポップアップメニューでの表示状態がスニペットプラグインと同じ階層構造にならないことがあります。
 
: → ポップアップメニューでの表示状態がスニペットプラグインと同じ階層構造にならないことがあります。
* snippets.txt 内の空行やタブインデントでのクループ化が適切でない部分は、ポップアップメニューに正しく反映されません (その行をスキップし、ポップアップメニューに表示しません)。
+
* snippets.txt 内の空行やタブインデントでのクループ化が適切でない部分は、ポップアップメニューに正しく反映されません。その行または段落/グループをスキップし、ポップアップメニューに表示しません。
: タブインデントの階層を深くするさいは、かならず一段ずつ下げてください(二段以上の差があるとエラーの元)。
+
: タブインデントの階層を深くするさいは、かならず一段ずつ下げてください。 二段以上の差があるとエラーの元になったり、または予期せぬ階層に表示されたりします(これはスニペットプラグインでも起きえます)。
: 階層を浅くするさいは、二段以上の差があっても構いません。
+
: 階層を浅くするさいは、二段以上の差があっても構いません。
 +
 
 +
 
 +
== ダウンロード ==
 +
; >> 「[[ファイル:クリップボード履歴.zip ‎]]」(アイコン入り)
 +
: 最終更新: 2019/11/09
 +
* ZIP 書庫には、メニューの階層表示や登録/貼り付けの動作テストに使用したテキストファイルが入っていますが、このマクロを使用するうえで必要なものではありません。
 +
: '''sunipetts.txt''' は「スニペットプラグイン」のものがあれば共用、なければ新規に生成しますので、マクロ本体のJS ファイルとアイコンだけをご利用ください。
  
  
 
== ソースコード ==
 
== ソースコード ==
; ダウンロード: 「[[ファイル:クリップボード履歴.zip ‎]]」(アイコン入り)
 
* 2019/11/05: 第4版(修正・更新版)
 
<br>
 
 
<source lang="javascript" style="height:60em; overflow:auto;">
 
<source lang="javascript" style="height:60em; overflow:auto;">
 
#title = "クリップボード履歴..."
 
#title = "クリップボード履歴..."
62行目: 71行目:
 
  * --------------------------------------------------
 
  * --------------------------------------------------
 
  * 「クリップボード履歴 と スニペット」マクロ
 
  * 「クリップボード履歴 と スニペット」マクロ
  *  sukemaru, 2019/08/01 - 2019/11/05
+
  *  sukemaru, 2019/08/01 - 2019/11/09
* ※ まだまだバグが残っているかもしれません。
 
 
  * --------------------------------------------------
 
  * --------------------------------------------------
 
  * 「クリップボード履歴」メニューと「スニペット」プラグインと同等の機能を
 
  * 「クリップボード履歴」メニューと「スニペット」プラグインと同等の機能を
 
  *  ひとつのポップアップメニューに統合します。
 
  *  ひとつのポップアップメニューに統合します。
 
  *  
 
  *  
 +
* ※ まだまだ不具合が残っているかもしれません。
 
  * ※ ソースコードの末尾に【能書き】
 
  * ※ ソースコードの末尾に【能書き】
 
  */
 
  */
 
var start = new Date();
 
  
 
// ---------- ▼ 設定項目 ▼ ---------- //
 
// ---------- ▼ 設定項目 ▼ ---------- //
 
// ■ クリップボード履歴内の重複アイテムを削除する
 
var delDupEnable = true; // true: 削除する / false: 削除しない
 
  
 
// ■ ポップアップメニューを表示する位置
 
// ■ ポップアップメニューを表示する位置
84行目: 88行目:
 
var menuWidth = 60;
 
var menuWidth = 60;
  
// ■ GetKeyState.exe のフルパスを指定する場合(「\」記号はふたつがさね「\\」で)
+
// ■ GetKeyState.exe のフルパスを指定する場合( \ 記号はふたつがさね「\\」で)
 
// 未指定 "" なら、Mery インストールフォルダの Macros\GetKeyState.exe
 
// 未指定 "" なら、Mery インストールフォルダの Macros\GetKeyState.exe
var getKeyStatePath = ""; // GetKeyState.exe なしのときも ""
+
var getKeyStatePath = ""; // GetKeyState.exe なしのときも "" にする
  
 
// ---------- ▲ 設定項目 ▲ ---------- //
 
// ---------- ▲ 設定項目 ▲ ---------- //
  
 +
 +
var start = new Date();
  
 
var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
 
var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
 
var WshShell = new ActiveXObject( "WScript.Shell" );
 
var WshShell = new ActiveXObject( "WScript.Shell" );
  
// ClipboardData.Get/ClearData() に引数を指定できるのは ver 2.8.1 以降
+
var meryPath = editor.FullName;
if ( ! VersionCheck( "2.8.1" ) ) {
+
var meryDir = meryPath.replace( /[^\\]+$/, "" );
  Status = " 動作要件: \"Mery ver 2.8.1\" 以上";
+
var isPortable = Fso.FileExists( meryPath.replace( /\.exe$/i, ".ini" ) );
}
+
var profileDir = ( isPortable )
 
 
else {
 
  var meryPath = editor.FullName;
 
  var meryDir = meryPath.replace( /[^\\]+$/, "" );
 
  var isPortable = Fso.FileExists( meryPath.replace( /\.exe$/i, ".ini" ) );
 
  var profileDir = ( isPortable )
 
 
                 ? meryDir
 
                 ? meryDir
 
                 : WshShell.SpecialFolders( "APPDATA" ) + "\\Mery\\";
 
                 : WshShell.SpecialFolders( "APPDATA" ) + "\\Mery\\";
  var snPath = profileDir + "Plugins\\Snippets\\Snippets.txt";
+
var snPath = profileDir + "Plugins\\Snippets\\Snippets.txt";
  var snIsExist = Fso.FileExists( snPath );
+
var snIsExist = Fso.FileExists( snPath );
 
+
var gksPath = getKeyStatePath || meryDir + "Macros\\GetKeyState.exe";
  var gksPath = getKeyStatePath || meryDir + "Macros\\GetKeyState.exe";
+
var gksIsExist = Fso.FileExists( gksPath );
  var gksIsExist = Fso.FileExists( gksPath );
+
var $ctrl = 0;
  var $ctrl = 0;
+
var versionCheck = VersionCheck( "2.8.1" );
 
+
var d = editor.ActiveDocument;
  var d = editor.ActiveDocument;
+
var s = d.selection;
  var s = d.selection;
+
var st = s.Text;
  var st = s.Text;
+
var $status = Status;
  var $status = Status;
 
  
  // ピン止めアイテム (スニペット)の準備
+
// ピン止めアイテム (スニペット)の準備
  var snText = "",  snArray = [],  snCount = 0;
+
var snText = "",  snArray = [],  snCount = 0;
  if ( snIsExist ) {
+
if ( snIsExist ) {
    // snippet.txt を読みこむ
+
  // snippet.txt を読みこむ
    snText = IO.LoadFromFile( snPath, "utf-8" ) || "";
+
  snText  = IO.LoadFromFile( snPath, "utf-8" ) || "";
    // 空白行を除去した配列にする
+
  // 空白行とセパレータ用の "-" の行を除去した配列にする
    snArray = snText.split( "\n" );
+
  snArray = snText.split( "\n" );
    for ( var i = 0, len = snArray.length; i < len; i ++ ) {
+
  for ( var i = 0; i < snArray.length; i ++ ) {
      if ( /^\t*$/.test( snArray[i] ) ) {
+
    if ( /^\s*-?\s*$/.test( snArray[i] ) ) {
        snArray.splice( i --, 1 );
+
      snArray.splice( i --, 1 );
      }
 
 
     }
 
     }
    snCount = snArray.length;
 
    // snText = snArray.join( "\n" );
 
 
   }
 
   }
 +
}
 +
snCount = snArray.length;
  
  // クリップボード履歴の準備
+
// クリップボード履歴の準備
  var cb = ClipboardData;
+
var cb = ClipboardData;
  var cbData = cb.GetData();
+
var cbData = cb.GetData();
  var cbArray = [];
+
var cbArray = [];
   var cbData0 = cb.GetData( 0 );
+
if ( versionCheck ) {
 +
   var cbData0 = cb.GetData( 0 );
 
   if ( cbData0 ) {
 
   if ( cbData0 ) {
 +
    outer:
 
     for ( var i = 0, cbItem;  ; i ++ ) {
 
     for ( var i = 0, cbItem;  ; i ++ ) {
 
       cbItem = cb.GetData( i ) || "";
 
       cbItem = cb.GetData( i ) || "";
       if ( ! cbItem ) { break; }
+
       if ( ! cbItem ) { break outer; }
 
       // 重複するアイテムを履歴から削除する
 
       // 重複するアイテムを履歴から削除する
       if ( delDupEnable ) {
+
       inner:
        for ( var j = i + 1, cbNextItem;  ; j ++ ) {
+
      for ( var j = i + 1, cbNextItem;  ; j ++ ) {
          cbNextItem = cb.GetData( j ) || "";
+
        cbNextItem = cb.GetData( j ) || "";
          if ( ! cbNextItem ) { break; }
+
        if ( ! cbNextItem ) { break inner; }
          if ( cbItem == cbNextItem ) {
+
        if ( cbItem == cbNextItem ) {
            cb.ClearData( j -- );
+
          cb.ClearData( j -- );
          }
 
 
         }
 
         }
 
       }
 
       }
157行目: 156行目:
 
     }
 
     }
 
   }
 
   }
  var cbCount = cbArray.length;
+
}
  var width = String( Math.max( snCount, cbCount ) ).length;
+
var cbCount = cbArray.length;
 +
var width = String( Math.max( snCount, cbCount ) ).length;
  
  
  // ポップアップメニューの準備
+
// ポップアップメニューの準備
  var menu = CreatePopupMenu();
+
var menu = CreatePopupMenu();
  var menuFlags = d.ReadOnly ? meMenuGrayed : 0;
+
var grayFlag = d.ReadOnly ? meMenuGrayed : 0;
  
  // 「ピン止めアイテム/スニペット」サブメニュー
+
// 「ピン止めアイテム/スニペット」サブメニュー
  var sm0 = CreatePopupMenu();
+
var sm0 = CreatePopupMenu();
  var t = ( snCount ) ? "▼ " : "";
+
var t   = ( snCount ) ? "▼ " : "";
  menu.AddPopup( t + "ピン止めアイテム/スニペット (&S) " + t, sm0 );
+
menu.AddPopup( t + "ピン止めアイテム/スニペット (&S) " + t, sm0 );
  if ( st ) {
+
if ( st ) {
    sm0.Add( "選択範囲を登録 (&P)", 300 );
+
  sm0.Add( "選択範囲を登録 (&P)", 300 );
  }
+
}
  if ( snIsExist ) {
+
if ( snIsExist ) {
    sm0.Add( "スニペットを編集 (&E) ...", 400 );
+
  sm0.Add( "スニペットを編集 (&E) ...", 400 );
  }
+
}
  if ( st || snIsExist ) {
+
if ( st || snIsExist ) {
    sm0.Add( "----", 0, meMenuSeparator );
+
  sm0.Add( "", 0, meMenuSeparator );
    sm0.Add( "キャンセル & ", 0 );
+
  sm0.Add( "キャンセル & ", 0 );
  }
+
}
  if ( snCount ) {
+
if ( snCount ) {
    sm0.Add( "----", 0, meMenuSeparator );
+
  sm0.Add( "", 0, meMenuSeparator );
  }
+
}
  
  // スニペットのアイテムをメニューに
+
// スニペットのアイテムをメニューに
  if ( snText ) {
+
if ( snText ) {
    var label1, label2, tab1, tab2,  label,  lines;
+
  var label, label0, label1, label2, tab1, tab2;
    var subArray = []; // SubMenu Array
+
  var subArray = []; // SubMenu Array
    for ( var i = 0; i < 10; i ++ ) { subArray.push( [] ); }
+
  for ( var i = 0; i < 10; i ++ ) { subArray.push( [] ); }
    var subId,  subId1,  subId2;
+
  var subId,  subId1,  subId2;
    for ( var i = 0, j = 1, tab0 = 0, id; i < snCount; i ++, j ++ ) {
+
  for ( var i = 0, j = 1, tab0 = 0, id; i < snCount; i ++, j ++ ) {
      try {
+
    try {
        label1 = snArray[i];
+
      label1 = snArray[i];
        label2 = snArray[j] || "";
+
      label2 = snArray[j] || "";
        tab1 = ( label1.charAt( 0 ) == "\t" ) ? label1.search( /[^\t]/ ) : 0;
+
      tab1   = ( label1.charAt( 0 ) == "\t" ) ? label1.search( /[^\t]/ ) : 0;
        tab2 = ( label2.charAt( 0 ) == "\t" ) ? label2.search( /[^\t]/ ) : 0;
+
      tab2   = ( label2.charAt( 0 ) == "\t" ) ? label2.search( /[^\t]/ ) : 0;
        label = MenuKey( label1.replace( /^\t+|\t+[^\t]*$/g, "" )
+
      label = MenuKey( label1.replace( /^\t+|\t+[^\t]*$/g, "" )
                      , j, width, menuWidth, true );
+
                      , j, width, menuWidth, true );
        id = j + 400;
+
      id     = j + 400;
        // メインメニューにサブメニュー項目を追加
+
      // メインメニューにサブメニュー項目を追加
        if ( tab1 == 0 && tab1 < tab2 ) {
+
      if ( tab1 == 0 && tab1 + 1 == tab2 ) {
          subId = subArray[0].length;
+
        subId = subArray[0].length;
          subArray[0].push( CreatePopupMenu() );
+
        subArray[0].push( CreatePopupMenu() );
          if ( menuFlags ) {
+
        if ( grayFlag ) {
            menu.Add( label + "\t▶", id, menuFlags );
+
          menu.Add( label + "\t▶", id, grayFlag );
          }
 
          else {
 
            menu.AddPopup( label, subArray[0][ subId ] );
 
          }
 
          sm0.Add( "----", 0, meMenuSeparator );
 
 
         }
 
         }
        // メインメニューにアイテムを追加
+
         else {
         else if ( tab1 == 0 && tab1 == tab2 ) {
+
           menu.AddPopup( label, subArray[0][ subId ] );
           menu.Add( label, id, menuFlags );
 
          if ( tab1 < tab0 ) {
 
            sm0.Add( "----", 0, meMenuSeparator );
 
          }
 
          sm0 .Add( label, id, menuFlags );
 
 
         }
 
         }
         // サブメニュー内にサブメニュー項目を追加
+
         sm0.Add( "", 0, meMenuSeparator );
        else if ( tab1 > 0 && tab1 < tab2 ) { //
+
        label0 = false;
          subId1 = subArray[ tab1 ].length;
+
      }
          subId2 = subArray[ tab1 -1 ].length - 1;
+
      // メインメニューにアイテムを追加
          subArray[ tab1 ].push( CreatePopupMenu() );
+
      else if ( tab1 == 0 && ( tab1 == tab2 || tab1 + 1 < tab2 ) ) {
          subArray[ tab1 -1 ][ subId2 ].AddPopup( label, subArray[ tab1 ][ subId1 ] );
+
        menu.Add( label, id, grayFlag );
           sm0.Add( "----", 0, meMenuSeparator );
+
        if ( tab1 < tab0 && label0 ) {
 +
           sm0.Add( "", 0, meMenuSeparator );
 
         }
 
         }
         // サブメニューにアイテムを追加
+
         sm0 .Add( label, id, grayFlag );
        else if ( tab1 > 0 && tab1 >= tab2 ) {
+
        label0 = true;
          subId = subArray[ tab1 -1 ].length - 1;
+
      }
          subArray[ tab1 -1 ][ subId ].Add( label, id, menuFlags );
+
      // サブメニュー内にサブメニュー項目を追加
          if ( tab1 < tab0 ) {
+
      else if ( tab1 > 0 && tab1 + 1 == tab2 ) {
            sm0.Add( "----", 0, meMenuSeparator );
+
        subId1 = subArray[ tab1 ].length;
          }
+
        subId2 = subArray[ tab1 -1 ].length - 1;
          sm0.Add( label, id, menuFlags );
+
        subArray[ tab1 ].push( CreatePopupMenu() );
 +
        subArray[ tab1 -1 ][ subId2 ].AddPopup( label, subArray[ tab1 ][ subId1 ] );
 +
        if ( label0 ) {
 +
          sm0.Add( "", 0, meMenuSeparator );
 
         }
 
         }
         tab0 = tab1;
+
         label0 = false;
 
       }
 
       }
       catch( e ) {
+
       // サブメニューにアイテムを追加
         OutputBar.Clear();
+
      else if ( tab1 > 0 && ( tab1 >= tab2 || tab1 + 1 < tab2 ) ) {
         OutputBar.Writeln( e.name + ":  " + ScriptFullName + "\n  \""
+
         subId = subArray[ tab1 -1 ].length - 1;
                        + snPath + "\" の\n  " + j
+
        subArray[ tab1 -1 ][ subId ].Add( label, id, grayFlag );
                        + " 件目のアイテム(空行は除外)を処理できませんでした。\n\""
+
         if ( tab1 < tab0 && label0 ) {
                        + label1.replace( /\t/g, " › " ) + "\"\n" ); //
+
          sm0.Add( "", 0, meMenuSeparator );
         // OutputBar.Visible = true;
+
        }
        // break; // ← ループ処理を中断する場合
+
        sm0.Add( label, id, grayFlag );
        continue; // ← ループ処理を継続する場合
+
         label0 = true;
 
       }
 
       }
 +
      tab0 = tab1;
 +
 
     }
 
     }
 +
    catch( e ) {
 +
      /**
 +
      * snArray[i] (行_A) と次の有効文字列の行 snArray[j] (行_B) の
 +
      * タブインデントを比較して、行_A よりも 行_B が二段以上深い場合、
 +
      * 行_A をサブメニュー見出し項目にせず、通常アイテムとして扱います。
 +
      * 行_B から始まるグループは、親になる項目が適切に処理されないことにより、
 +
      * メインメニュー部分の階層構造に正しく反映されなくなります
 +
      * (状況によっては部分的にエラー扱いなります)。
 +
      * ただし「▼ ピン止めアイテム/スニペット ▼」配下の
 +
      * ベタ置きのアイテムとしては(状況によっては不完全に)表示されます。
 +
      */
 +
    }
 
   }
 
   }
  menu.Add( "----", 0, meMenuSeparator );
+
}
 +
menu.Add( "", 0, meMenuSeparator );
  
  // クリップボード履歴のアイテムをメニューに
+
// クリップボード履歴のアイテムをメニューに
 +
if ( versionCheck ) {
 
   if ( cbCount ) {
 
   if ( cbCount ) {
 
     var sm1  = CreatePopupMenu();
 
     var sm1  = CreatePopupMenu();
258行目: 268行目:
 
     var sm4  = CreatePopupMenu();
 
     var sm4  = CreatePopupMenu();
 
     menu.AddPopup( "▼ クリップボード履歴の一覧 (&C) ▼", sm1 );
 
     menu.AddPopup( "▼ クリップボード履歴の一覧 (&C) ▼", sm1 );
     for ( var i = 0, id, label, lines; i < cbCount; i ++ ) {
+
     for ( var i = 0, id, label; i < cbCount; i ++ ) {
 
       id = i + 1;
 
       id = i + 1;
 
       label = MenuKey( cbArray[i], id, width, menuWidth );
 
       label = MenuKey( cbArray[i], id, width, menuWidth );
       menu.Add( label, id, menuFlags );
+
       menu.Add( label, id, grayFlag );
       sm2. Add( label, id + 100, menuFlags );
+
       sm2. Add( label, id + 100, grayFlag );
 
       sm3. Add( label, id + 200 );
 
       sm3. Add( label, id + 200 );
 
       sm4. Add( label, id + 300 );
 
       sm4. Add( label, id + 300 );
 
     }
 
     }
     menu.Add( "----", 0, meMenuSeparator );
+
     menu.Add( "", 0, meMenuSeparator );
 
     menu.Add( "クリップボードのすべての履歴を削除する (&E)", 99 );
 
     menu.Add( "クリップボードのすべての履歴を削除する (&E)", 99 );
 
     sm1.AddPopup( "履歴からアイテムをスニペットに登録 (&P)", sm4 );
 
     sm1.AddPopup( "履歴からアイテムをスニペットに登録 (&P)", sm4 );
 
     sm1.AddPopup( "貼り付けしてからアイテムを削除 (&M)", sm2 );
 
     sm1.AddPopup( "貼り付けしてからアイテムを削除 (&M)", sm2 );
 
     sm1.AddPopup( "履歴からアイテムを削除 (&D)", sm3 );
 
     sm1.AddPopup( "履歴からアイテムを削除 (&D)", sm3 );
     sm1.Add( "----", 0, meMenuSeparator );
+
     sm1.Add( "", 0, meMenuSeparator );
 
     sm1.Add( "すべての履歴を削除 (&E)", 99 );
 
     sm1.Add( "すべての履歴を削除 (&E)", 99 );
     sm1.Add( "----", 0, meMenuSeparator );
+
     sm1.Add( "", 0, meMenuSeparator );
 
     sm1.Add( "キャンセル & ", 0 );
 
     sm1.Add( "キャンセル & ", 0 );
 
   }
 
   }
  else if ( cbData.length ) {
+
}
    menu.Add( "▼ クリップボード ▼", 0, meMenuGrayed );
+
if ( ! cbCount && cbData.length ) {
    label = MenuKey( cbData, 1, width, menuWidth );
+
  menu.Add( "▼ クリップボード ▼", 0, meMenuGrayed );
    menu.Add( label, 17, menuFlags );
+
  label = MenuKey( cbData, 1, width, menuWidth );
  }
+
  menu.Add( label, 17, grayFlag );
  else {
+
}  
    menu.Add( "※ クリップボードにテキストデータはありません ※"
+
else if ( ! cbCount && ! cbData.length ) {
            , 0, meMenuGrayed );
+
  menu.Add( "※ クリップボードにテキストデータはありません ※"
  }
+
          , 0, meMenuGrayed );
 +
}
  
  menu.Add( "----", 0, meMenuSeparator );
+
menu.Add( "", 0, meMenuSeparator );
  menu.Add( "キャンセル & ", 0 );
+
menu.Add( "キャンセル & ", 0 );
  
  
  // ステータスバーの表示
+
// ステータスバーの表示
  if ( menuFlags ) {
+
if ( grayFlag ) {
    Status = " ドキュメントは書き換え禁止です。";
+
  Status = " ドキュメントは書き換え禁止です。";
   }
+
}
  else if ( gksIsExist && cbCount ) {
+
else if ( ! versionCheck ) {
    Status = " 履歴アイテムの Ctrl+クリック で 「貼り付けしてからアイテムを削除」";
+
   Status = " 「クリップボード履歴」機能の動作要件は"
  }
+
        + " \"Mery ver 2.8.1\" 以上です。";
  else {
+
}
    Status = " 「クリップボード履歴 と スニペット」マクロ";
+
else if ( gksIsExist && cbCount ) {
  }
+
  Status = " 履歴アイテムの Ctrl+クリック で"
  Status += " [ "
+
        + " 「貼り付けしてからアイテムを削除」";
        + ( ( new Date() - start ) / 1000 ).toFixed( 3 ).replace( /\./, ". " )
+
}
        + " 秒 ]";
+
else {
 +
  Status = " 「クリップボード履歴 と スニペット」マクロ";
 +
}
 +
Status += " [ "
 +
      + ( ( new Date() - start ) / 1000 ).toFixed( 3 ).replace( /\./, ". " )
 +
      + " 秒 ]";
  
  
  // ポップアップメニューを表示
+
// ポップアップメニューを表示
  var r = menu.Track( + menuPosMouse );
+
var r = menu.Track( + menuPosMouse );
  var confirmStr = "クリップボードのすべての履歴を削除しますか? ";
+
var confirmStr = "クリップボードのすべての履歴を削除しますか? ";
  
  if ( r == 0 ) {
+
if ( r == 0 ) { Status = $status; }
    Status = $status;
 
  }
 
  
  // 1 ~ 17: クリップボード履歴のアイテムを貼り付け
+
// 1 ~ 17: クリップボード履歴のアイテムを貼り付け
  else if ( r <= 16 ) {
+
else if ( r <= 16 ) {
    Status = "";
+
  d.Write( cbArray[ r -1 ] );
    d.Write( cbArray[ r -1 ] );
+
  Status = "";
    // Ctrl キーを押しながらのときは、貼り付けしてからアイテムを削除
+
  // Ctrl キーを押しながらのときは、貼り付けしてからアイテムを削除
    if ( gksIsExist ) {
+
  if ( gksIsExist ) {
      $ctrl = WshShell.Run( "\"" + gksPath + "\" c", 0, true );
+
    $ctrl = WshShell.Run( "\"" + gksPath + "\" c", 0, true );
      if ( $ctrl == 1 ) {
+
    if ( $ctrl == 1 ) {
        cb.ClearData( r -1 );
+
      cb.ClearData( r -1 );
        Status = " クリップボード履歴からアイテムを削除しました。";
+
      Status = " クリップボード履歴からアイテムを削除しました。";
      }
 
 
     }
 
     }
 
   }
 
   }
  else if ( r == 17 ) {
+
}
    d.Write( cbData );
+
else if ( r == 17 ) {
    Status = "";
+
  d.Write( cbData );
  }
+
  Status = "";
 +
}
  
  // 99: クリップボード履歴をすべて削除する
+
// 99: クリップボード履歴をすべて削除する
  else if ( r == 99 && Confirm( confirmStr ) ) {
+
else if ( r == 99 && Confirm( confirmStr ) ) {
    for ( var i = 0; i < cbCount; i ++ ) {
+
  for ( var i = 0; i < cbCount; i ++ ) {
      cb.ClearData( i );
+
    cb.ClearData( i );
      Status = " クリップボード履歴からすべてのアイテムを削除しました。";
+
    Status = " クリップボード履歴からすべてのアイテムを削除しました。";
    }
 
 
   }
 
   }
 +
}
  
  // 101 ~ 116: 貼り付けしてからアイテムを削除
+
// 101 ~ 116: 貼り付けしてからアイテムを削除
  else if ( r > 100 && r < 200 ) {
+
else if ( r > 100 && r < 200 ) {
    d.Write( cbArray[ r -101 ] );
+
  d.Write( cbArray[ r -101 ] );
    cb.ClearData( r -101 );
+
  cb.ClearData( r -101 );
    Status = " 履歴からアイテムを削除しました。";
+
  Status = " 履歴からアイテムを削除しました。";
  }
+
}
  
  // 201 ~ 216: クリップボード履歴からアイテムを削除
+
// 201 ~ 216: クリップボード履歴からアイテムを削除
  else if ( r > 200 && r < 300 ) {
+
else if ( r > 200 && r < 300 ) {
    cb.ClearData( r -201 );
+
  cb.ClearData( r -201 );
    Status = " 履歴からアイテムを削除しました。";
+
  Status = " 履歴からアイテムを削除しました。";
  }
+
}
  
  // 300 ~ 316: スニペットに登録(ピン止め)
+
// 300 ~ 316: スニペットに登録(ピン止め)
  else if ( r >= 300 && r < 400 ) {
+
else if ( r >= 300 && r < 400 ) {
 +
  try {
 
     var snippetsDir = Fso.GetParentFolderName( snPath );
 
     var snippetsDir = Fso.GetParentFolderName( snPath );
 
     var pluginsDir = Fso.GetParentFolderName( snippetsDir );
 
     var pluginsDir = Fso.GetParentFolderName( snippetsDir );
367行目: 382行目:
 
             : ( cb.GetData( r -301 ) || cb.GetData() );
 
             : ( cb.GetData( r -301 ) || cb.GetData() );
 
     str = snText
 
     str = snText
         + ( snText ? "\n" : "" )
+
         + ( ! snText || snText.charAt( snText.length -1 ) == "\n"
 +
          ? "" : "\n" )
 
         + str.replace( /\\/g, "\\\\" )
 
         + str.replace( /\\/g, "\\\\" )
 
             .replace( /\t/g, "\\t" )
 
             .replace( /\t/g, "\\t" )
 
             .replace( /\n/g, "\\n" )
 
             .replace( /\n/g, "\\n" )
             .replace( /\r/g, "\\r" )
+
             .replace( /\r/g, "\\r" );
 
     IO.SaveToFile( snPath, str, "utf-8", true );
 
     IO.SaveToFile( snPath, str, "utf-8", true );
 
     var copyFrom = ( r == 300 ) ? "範囲" : "したアイテム";
 
     var copyFrom = ( r == 300 ) ? "範囲" : "したアイテム";
 
     Status = " 選択" + copyFrom + "をスニペットに登録しました。";
 
     Status = " 選択" + copyFrom + "をスニペットに登録しました。";
 +
  } catch ( e ) {
 +
    Status = " スニペットに登録できませんでした。";
 
   }
 
   }
 +
}
  
  // 400: スニペットを編集(snippets.txt を開く)
+
// 400: スニペットを編集(snippets.txt を開く)
  else if ( r == 400 ) {
+
else if ( r == 400 ) {
    WshShell.Run( "\"" + editor.FullName + "\" \"" + snPath + "\"" );
+
  WshShell.Run( "\"" + editor.FullName + "\" \"" + snPath + "\"" );
    Status = " " + snPath;
+
  Status = " " + snPath;
  }
+
}
  
  // 401 ~ : ピン止めアイテムを貼り付け
+
// 401 ~ : ピン止めアイテムを貼り付け
  else if ( r > 400 ) {
+
else if ( r > 400 ) {
    var strArr = snArray[ r -401 ].replace( /^(?:\t)*[^\t]*\t/, "" )
+
  var strArr = snArray[ r -401 ].replace( /^(?:\t)*[^\t]*\t/, "" )
                                  .split( "\\\\" );
+
                                .split( "\\\\" );
    for ( var i = 0; i < strArr.length; i ++ ) {
+
  for ( var i = 0; i < strArr.length; i ++ ) {
      strArr[i] = strArr[i].replace( /\\t/g, "\t" )
+
    strArr[i] = strArr[i].replace( /\\t/g, "\t" )
                          .replace( /\\r/g, "\r" )
+
                        .replace( /\\r/g, "\r" )
                          .replace( /\\n/g, "\n" )
+
                        .replace( /\\n/g, "\n" )
    }
+
                        .replace( /\\/g, "" );
    var str = strArr.join( "\\" );
 
    d.Write( str );
 
    Status = "";
 
 
   }
 
   }
 
+
  var str = strArr.join( "\\" );
 +
  d.Write( str );
 +
  Status = "";
 
}
 
}
  
408行目: 426行目:
 
  */
 
  */
 
function VersionCheck( versionStr ) {
 
function VersionCheck( versionStr ) {
 +
  var editorVer, requirement;
 
   var Pad2 = function( str ) {
 
   var Pad2 = function( str ) {
 
     return str.replace( /[0-9]+/g , function( digit ) {
 
     return str.replace( /[0-9]+/g , function( digit ) {
413行目: 432行目:
 
     } )
 
     } )
 
   };
 
   };
   var editorVer = + ( Pad2( editor.Version ).replace( /\./g, "" )
+
   editorVer = + ( Pad2( editor.Version ).replace( /\./g, "" ).slice( 0, 6 ) );
                                            .slice( 0, 6 ) );
+
   requirement = + ( Pad2( versionStr ).replace( /\./g, "" ).slice( 0, 6 ) );
   var requirement = + ( Pad2( versionStr ).replace( /\./g, "" )
 
                                          .slice( 0, 6 ) );
 
 
   return ( editorVer >= requirement );
 
   return ( editorVer >= requirement );
 
}
 
}
424行目: 441行目:
 
  * ポップアップメニューに表示するラベルを生成する
 
  * ポップアップメニューに表示するラベルを生成する
 
  * ・行頭空白を除去、空白文字を圧縮: →「›」(U+203A)
 
  * ・行頭空白を除去、空白文字を圧縮: →「›」(U+203A)
  * ・改行記号を可視化: →「↲」(U+21B2) または「⏎」(U+23CE)
+
  * ・改行記号を可視化: →「↲」(U+21B2) または「⏎」(U+23CE)
 
  * ・削られてしまう「&」を補完
 
  * ・削られてしまう「&」を補完
 
  * ・「¥」(U+005C) を「∖」に置換: →「∖」(U+2216)
 
  * ・「¥」(U+005C) を「∖」に置換: →「∖」(U+2216)
438行目: 455行目:
 
     for ( var i = 0; i < strArr.length; i ++ ) {
 
     for ( var i = 0; i < strArr.length; i ++ ) {
 
       strArr[i] = strArr[i].replace( /\\t/g, " › " )
 
       strArr[i] = strArr[i].replace( /\\t/g, " › " )
                           .replace( /\\r|(\\r)?\\n/g, " ↲ " );
+
                           .replace( /\\r|(\\r)?\\n/g, " ↲ " )
 +
                          .replace( /\\/g, "" );
 
     }
 
     }
 
     str = strArr.join( "\\" );
 
     str = strArr.join( "\\" );
 
   }
 
   }
   var reg = /[\u00A0\u1680\u180e\u2000-\u200A\u2028\u2029\u202F\u205F\uFEFF]/g;
+
   var reg = /[\u00A0\u1680\u180E\u2000-\u200E\u2028\u2029\u202F\u205F\u2062\u2063\uFEFF]/g
 
   var menuKey = str.replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " )
 
   var menuKey = str.replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " )
 
                   .slice( 0, menuWidth + 1 )
 
                   .slice( 0, menuWidth + 1 )
464行目: 482行目:
  
 
/**
 
/**
  * 【このマクロの仕様・制限事項】
+
  【このマクロの仕様・制限事項】
  * ・ver 2.8.1 以前の Mery では使用できません。
+
  ・ver 2.8.1 以前の Mery では「クリップボード履歴」機能を使用できません。
  *
+
   
  * ・「クリップボード履歴」は Mery 本体のメモリストアのものを使用します。
+
  ・「クリップボード履歴」は Mery 本体のメモリストアのものを使用します。
  * ※「クリップボードのすべての履歴を削除」したあとでも、
+
   
  *    Windows OS のクリップボード(最新1件)にテキストデータが残っているときは
+
  ・「スニペット」プラグインの設定ファイル snippets.txt の読み書きをします。
*    クリップボード履歴メニューに1件だけ表示します。
+
  ※「include ライブラリ」が必要です(snippets.txt ファイルの読み書きに使用)。
*
+
  ※「スニペット」プラグインを導入していない場合でも、
* ・「スニペット」プラグインの設定ファイル snippets.txt の読み書きをします。
+
    「ピン止めアイテム/スニペット」機能を使用できます。
* ・
+
    snippets.txt ファイルの保存場所は Mery\Plugins\Snippets フォルダです
* ※「include ライブラリ」が必要です(snippets.txt ファイルの読み書きに使用)。
+
  (インストーラ版では %AppData%\Mery\Plugins\Snippets フォルダ)。
* ※「スニペット」プラグインを導入していない場合でも、
+
   
「ピン止めアイテム/スニペット」機能を使用できます。
+
  ・「GetKeyState.exe(キー状態取得実行ファイル) 」で機能を拡張できます。
*    snippets.txt ファイルの保存場所は Mery\Plugins\Snippets フォルダです
+
      → クリップボード履歴のアイテムを Ctrl+クリックした場合、
(インストーラ版では %AppData%\Mery\Plugins\Snippets フォルダ)。
+
        アイテムを貼り付けし、貼り終えたアイテムを削除します。
  *
+
  ※「GetKeyState.exe」は Mery\Macros フォルダに配置してください
  * ・「GetKeyState.exe(キー状態取得実行ファイル) 」で機能を拡張できます。
+
    (Macros フォルダ以外の場所にあるなら設定項目でパスを指定する)。
*      → クリップボード履歴のアイテムを Ctrl+クリックした場合、
+
  ※「GetKeyState.exe」がなくても、クリップボード履歴の
*        アイテムを貼り付けし、貼り終えたアイテムを削除します。
+
      サブメニュー項目から「貼り付けしてからアイテムを削除」できます。
*
+
* ※「GetKeyState.exe」は Mery\Macros フォルダに配置してください
+
【ツールメニューの「クリップボード履歴」と異なる部分】 (2019/11/05)
(Macros フォルダ以外の場所にあるなら設定項目でパスを指定する)。
+
  ・「クリップボードのすべての履歴を削除」したあとでも、
* ※「GetKeyState.exe」がなくても、クリップボード履歴の
+
   Windows OS のクリップボードの最新の1件がテキストデータである場合は、
  *   サブメニュー項目から「貼り付けしてからアイテムを削除」できます。
+
  「クリップボード履歴」にアイテムが表示されます。
  *
+
  ※ Mery 本来の「クリップボード履歴」機能でも「履歴を消去」したあとにも
  * 【スニペットプラグインと異なる部分】 (2019/11/05)
+
    Ctrl+V によるペーストができることがあるので、これを可視化してあります。
  * ・ このマクロからスニペットに登録したアイテムは
+
   
snippets.txt の末尾に追加されます。
+
  【スニペットプラグインと異なる部分】 (2019/11/07)
  * ・ snippets.txt 内の「&」記号によるアクセラレータはすべて無視します
+
  ・ このマクロからスニペットに登録したアイテムは
*  (有効文字列の行の順に連番化して)。
+
    snippets.txt の末尾に追加されます。
  * ・ snippets.txt 内の 空行・空白行 の扱い方などで
+
  ・ snippets.txt 内の「-」×1 と空白だけの行をセパレータにしません。
*  スニペットプラグインと異なる解釈をしている部分があり、
+
      → メイン階層を「クリップボード履歴」と共用しているため、
  snippets.txt 内の空行やタブインデントでのクループ化が適切でないと
+
        体裁上の都合で「ピン止めアイテム」内でのセパレータは見送り。
*  ポップアップメニューでの表示状態が
+
  ※「-」×2 以上であれば、有効文字列として扱います。
*  スニペットプラグインと同じ階層構造になりません。
+
  ※「ピン止めアイテム/スニペット」サブメニュー内では
* ※ このマクロでは、snippets.txt 内の 空行とタブ文字だけの空白行を
+
      階層ごとに区切ってベタで列挙します。
*   完全に無視するので、「空文字のサブメニュー見出し」を作りません。
+
  ・ snippets.txt 内の「&」記号によるアクセラレータはすべて無視します。
* ※ タブインデントの階層を深くするさいは、
+
      → 有効文字列のある行を上から順に連番化し、番号をアクセラレータにします。
  *    かならず一段ずつ下げてください(二段以上の差があるとエラーの元)。
+
  snippets.txt 内の「空行・空白行」の扱い方などで
*    階層を浅くするさいは、二段以上の差があっても構いません。
+
    スニペットプラグインと異なる解釈をしている部分があります。
* ※ タブインデントによる階層構造に不適切な部分があったときは、
+
  ※ このマクロでは、snippets.txt 内の 空行、タブ文字だけの空白行、「-」だけの行を
*   その行をスキップし、ポップアップメニューに表示しません。
+
      完全に無視するので、「空文字や "-" だけのサブメニュー見出し」を作りません
 +
    (ただし、全角空白や2つ以上のハイフン「--」は文字列として扱う)。
 +
        → ポップアップメニューでの表示状態がスニペットプラグインと
 +
          同じ階層構造にならないことがあります。
 +
   ※ snippets.txt 内の空行や「-」だけの行、タブインデントでのクループ化が
 +
    適切でない部分は、ポップアップメニューに正しく反映されません。
 +
  ・ タブインデントの階層を深くするさいは、かならず一段ずつ下げてください
 +
  (二段以上の差があるとエラーの元)。
 +
      → その行またはグループをスキップし、ポップアップメニューに表示しません。
 +
   ※ 階層を浅くするさいは、二段以上の差があっても構いません。
 
  */
 
  */
 
</source>
 
</source>
536行目: 563行目:
 
   ・スニペットプラグインのサブメニュー化階層構造をある程度再現した
 
   ・スニペットプラグインのサブメニュー化階層構造をある程度再現した
 
    ( … つもりだが、アレンジしたので同じ表示状態にならないことがある)
 
    ( … つもりだが、アレンジしたので同じ表示状態にならないことがある)
 +
 +
• 2019/11/09
 +
 ・ver 2.8.0 以前の Mery でもスニペット機能だけ利用できるように変更
 +
 ・「クリップボード履歴の重複アイテム削除」の設定項目を廃止( "削除する" で固定)
 +
 ・snippets.txt 内の単独「\」の処理をスニペットプラグインにあわせる修正
 +
 ・snippets.txt 内のセパレータ用の「-」の行をスキップする処理を追加
 +
: これでだいたいはスニペットの機能を再現できたとおもいますが…。

2019年11月9日 (土) 00:47時点における版

概要


公式フォーラム[1] にて「クリップボード履歴」メニューの将来的に廃止されることが 予告?検討? されていますが、後継機能としては 「クリップボード履歴」プラグイン の登場により今後も安泰のようです。

ということで、試験運用中だった自家用マクロを再度リサイクルして「クリップボード履歴スニペット」の統合版ポップアップメニューにしてみました。
一見して 誰得? なマクロですが、「クリップボード履歴」を「スニペット」機能とまとめてツールバーアイコン化できるという素敵なメリットがあります。

「クリップボード履歴」機能は Mery 2.8.1 以降の『延命措置』の新パラメータ[2] を利用したもの。
「スニペット」機能は スニペットプラグイン の設定ファイル snippets.txt を読み書きするというかたちにしています。


  • 「クリップボード履歴」機能は Mery 2.8.1 以降 でしか利用できません。
  • あらかじめ「includeライブラリ」の導入が必要です。
  • 外部実行ファイル「GetKeyState.exe」で機能を拡張できます(なくても差し支えありません)。
  • スニペットプラグイン」を導入していないでも「スニペット(定型文)」機能を利用できます。
snippets.txt 内のタブインデントによる階層構造をある程度ポップアップメニューに反映させました。(2019/11/05)
ref. 「スニペットプラグイン」のページの Snippets.txt の書き方 を参照のこと。
  • 動作確認は Windows XP sp3 (32bit) × Mery ベータ版 2.8.6 (ポータブル) でしかしていません。
なにかしらの支障を来たす不具合が見つかった場合は、このマクロを削除して使用を中止するか、または フォーラム にてご報告ください。


cf. マクロライブラリには「定型文を挿入」機能に特化したマクロも別途あります。



ツールメニューの「クリップボード履歴」と異なる部分

(2019/11/09)

  • 「クリップボードのすべての履歴を削除」 「履歴からアイテムをひとつ削除」 「貼り付けしてからアイテムを削除」 「履歴からアイテムをスニペットに登録」 の機能を追加してあります。
ポップアップメニュー内のアイテムの Ctrl+クリック で「貼り付けしてからアイテムを削除」する機能は、「GetKeyState.exe 」を導入している場合にかぎり利用できます。
  • 「クリップボードのすべての履歴を削除」 したあとでも、Windows OS のクリップボードの最新の1件がテキストデータである場合は、「クリップボード履歴」にアイテムが表示されます。
Mery 本来の「クリップボード履歴」機能でも「履歴を消去」したあとにも Ctrl+V によるペーストができることがあるので、これを可視化してあります。
  • 「クリップボード履歴」 に重複アイテムアイテムがある場合は、ひとつを残して削除します。



「スニペットプラグイン」と異なる部分

(2019/11/09)

  • このマクロからスニペットに登録したアイテムは、snippets.txt の末尾に追加されます。
  • snippets.txt 内の「 & 」記号によるアクセラレータをすべて無視します。
→ 有効文字列のある行を上から順に連番化し、番号をアクセラレータにします。
  • snippets.txt 内の半角ハイフン「 - 」ひとつとと空白だけの行をセパレータにしません。
(メイン階層を「クリップボード履歴」と共用しているため、体裁上の都合で「ピン止めアイテム」内でのセパレータは見送り)
※「-」×2 以上であれば、有効文字列として扱います。
※「ピン止めアイテム/スニペット」サブメニュー内では、階層ごとに区切ってベタで列挙します。
  • snippets.txt 内の「空行・空白行」の扱い方などでスニペットプラグインと異なる解釈をしている部分があります。
このマクロでは、snippets.txt 内の空行とタブ文字/半角空白だけの空白行を完全に無視するので、「空文字のサブメニュー見出し」を作りません(ただし、全角空白や2つ以上のハイフン「 -- 」は有効な文字列として扱います)。
→ ポップアップメニューでの表示状態がスニペットプラグインと同じ階層構造にならないことがあります。
  • snippets.txt 内の空行やタブインデントでのクループ化が適切でない部分は、ポップアップメニューに正しく反映されません。その行または段落/グループをスキップし、ポップアップメニューに表示しません。
タブインデントの階層を深くするさいは、かならず一段ずつ下げてください。 二段以上の差があるとエラーの元になったり、または予期せぬ階層に表示されたりします(これはスニペットプラグインでも起きえます)。
※ 階層を浅くするさいは、二段以上の差があっても構いません。


ダウンロード

>> 「ファイル:クリップボード履歴.zip」(アイコン入り)
最終更新: 2019/11/09
  • ZIP 書庫には、メニューの階層表示や登録/貼り付けの動作テストに使用したテキストファイルが入っていますが、このマクロを使用するうえで必要なものではありません。
sunipetts.txt は「スニペットプラグイン」のものがあれば共用、なければ新規に生成しますので、マクロ本体のJS ファイルとアイコンだけをご利用ください。


ソースコード

#title = "クリップボード履歴..."
#tooltip = "クリップボード履歴 と スニペット"
#icon = "clipboard_history[1].ico"
#include "include/IO.js"

/**
 * --------------------------------------------------
 * 「クリップボード履歴 と スニペット」マクロ
 *  sukemaru, 2019/08/01 - 2019/11/09
 * --------------------------------------------------
 * 「クリップボード履歴」メニューと「スニペット」プラグインと同等の機能を
 *   ひとつのポップアップメニューに統合します。
 * 
 * ※ まだまだ不具合が残っているかもしれません。
 * ※ ソースコードの末尾に【能書き】
 */

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

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

// ■ ポップアップメニューに表示する文字数
var menuWidth = 60;

// ■ GetKeyState.exe のフルパスを指定する場合( \ 記号はふたつがさね「\\」で)
// 未指定 "" なら、Mery インストールフォルダの Macros\GetKeyState.exe
var getKeyStatePath = "";	// ※ GetKeyState.exe なしのときも "" にする

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


var start = new Date();

var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
var WshShell = new ActiveXObject( "WScript.Shell" );

var meryPath	 = editor.FullName;
var meryDir		 = meryPath.replace( /[^\\]+$/, "" );
var isPortable	 = Fso.FileExists( meryPath.replace( /\.exe$/i, ".ini" ) );
var profileDir	 = ( isPortable )
                 ? meryDir
                 : WshShell.SpecialFolders( "APPDATA" ) + "\\Mery\\";
var snPath		 = profileDir + "Plugins\\Snippets\\Snippets.txt";
var snIsExist	 = Fso.FileExists( snPath );
var gksPath		 = getKeyStatePath || meryDir + "Macros\\GetKeyState.exe";
var gksIsExist	 = Fso.FileExists( gksPath );
var $ctrl		 = 0;
var versionCheck = VersionCheck( "2.8.1" );
var d	 = editor.ActiveDocument;
var s	 = d.selection;
var st	 = s.Text;
var $status = Status;

// ピン止めアイテム (スニペット)の準備
var snText = "",  snArray = [],  snCount = 0;
if ( snIsExist ) {
  // snippet.txt を読みこむ
  snText  = IO.LoadFromFile( snPath, "utf-8" ) || "";
  // 空白行とセパレータ用の "-" の行を除去した配列にする
  snArray = snText.split( "\n" );
  for ( var i = 0; i < snArray.length; i ++ ) {
    if ( /^\s*-?\s*$/.test( snArray[i] ) ) {
      snArray.splice( i --, 1 );
    }
  }
}
snCount = snArray.length;

// クリップボード履歴の準備
var cb		 = ClipboardData;
var cbData	 = cb.GetData();
var cbArray	 = [];
if ( versionCheck ) {
  var cbData0 = cb.GetData( 0 );
  if ( cbData0 ) {
    outer:
    for ( var i = 0, cbItem;  ; i ++ ) {
      cbItem = cb.GetData( i ) || "";
      if ( ! cbItem ) { break outer; }
      // 重複するアイテムを履歴から削除する
      inner:
      for ( var j = i + 1, cbNextItem;  ; j ++ ) {
        cbNextItem = cb.GetData( j ) || "";
        if ( ! cbNextItem ) { break inner; }
        if ( cbItem == cbNextItem ) {
          cb.ClearData( j -- );
        }
      }
      // 履歴アイテムを配列に収納する
      cbArray.push( cbItem );
    }
  }
}
var cbCount	 = cbArray.length;
var width	 = String( Math.max( snCount, cbCount ) ).length;


// ポップアップメニューの準備
var menu = CreatePopupMenu();
var grayFlag = d.ReadOnly ? meMenuGrayed : 0;

// 「ピン止めアイテム/スニペット」サブメニュー
var sm0 = CreatePopupMenu();
var t   = ( snCount ) ? "▼ " : "";
menu.AddPopup( t + "ピン止めアイテム/スニペット (&S) " + t, sm0 );
if ( st ) {
  sm0.Add( "選択範囲を登録 (&P)", 300 );
}
if ( snIsExist ) {
  sm0.Add( "スニペットを編集 (&E) ...", 400 );
}
if ( st || snIsExist ) {
  sm0.Add( "", 0, meMenuSeparator );
  sm0.Add( "キャンセル & ", 0 );
}
if ( snCount ) {
  sm0.Add( "", 0, meMenuSeparator );
}

// スニペットのアイテムをメニューに
if ( snText ) {
  var label, label0, label1, label2, tab1, tab2;
  var subArray = [];	// SubMenu Array
  for ( var i = 0; i < 10; i ++ ) { subArray.push( [] ); }
  var subId,  subId1,  subId2;
  for ( var i = 0, j = 1, tab0 = 0, id; i < snCount; i ++, j ++ ) {
    try {
      label1 = snArray[i];
      label2 = snArray[j] || "";
      tab1   = ( label1.charAt( 0 ) == "\t" ) ? label1.search( /[^\t]/ ) : 0;
      tab2   = ( label2.charAt( 0 ) == "\t" ) ? label2.search( /[^\t]/ ) : 0;
      label  = MenuKey( label1.replace( /^\t+|\t+[^\t]*$/g, "" )
                      , j, width, menuWidth, true );
      id     = j + 400;
      // メインメニューにサブメニュー項目を追加
      if ( tab1 == 0 && tab1 + 1 == tab2 ) {
        subId = subArray[0].length;
        subArray[0].push( CreatePopupMenu() );
        if ( grayFlag ) {
          menu.Add( label + "\t▶", id, grayFlag );
        }
        else {
          menu.AddPopup( label, subArray[0][ subId ] );
        }
        sm0.Add( "", 0, meMenuSeparator );
        label0 = false;
      }
      // メインメニューにアイテムを追加
      else if ( tab1 == 0 && ( tab1 == tab2 || tab1 + 1 < tab2 ) ) {
        menu.Add( label, id, grayFlag );
        if ( tab1 < tab0 && label0 ) {
          sm0.Add( "", 0, meMenuSeparator );
        }
        sm0 .Add( label, id, grayFlag );
        label0 = true;
      }
      // サブメニュー内にサブメニュー項目を追加
      else if ( tab1 > 0 && tab1 + 1 == tab2 ) {
        subId1 = subArray[ tab1 ].length;
        subId2 = subArray[ tab1 -1 ].length - 1;
        subArray[ tab1 ].push( CreatePopupMenu() );
        subArray[ tab1 -1 ][ subId2 ].AddPopup( label, subArray[ tab1 ][ subId1 ] );
        if ( label0 ) {
          sm0.Add( "", 0, meMenuSeparator );
        }
        label0 = false;
      }
      // サブメニューにアイテムを追加
      else if ( tab1 > 0 && ( tab1 >= tab2 || tab1 + 1 < tab2 ) ) {
        subId = subArray[ tab1 -1 ].length - 1;
        subArray[ tab1 -1 ][ subId ].Add( label, id, grayFlag );
        if ( tab1 < tab0 && label0 ) {
          sm0.Add( "", 0, meMenuSeparator );
        }
        sm0.Add( label, id, grayFlag );
        label0 = true;
      }
      tab0 = tab1;

    }
    catch( e ) {
      /**
       * snArray[i] (行_A) と次の有効文字列の行 snArray[j] (行_B) の
       * タブインデントを比較して、行_A よりも 行_B が二段以上深い場合、
       * 行_A をサブメニュー見出し項目にせず、通常アイテムとして扱います。
       * 行_B から始まるグループは、親になる項目が適切に処理されないことにより、
       * メインメニュー部分の階層構造に正しく反映されなくなります
       * (状況によっては部分的にエラー扱いなります)。
       * ただし「▼ ピン止めアイテム/スニペット ▼」配下の
       * ベタ置きのアイテムとしては(状況によっては不完全に)表示されます。
       */
     }
  }
}
menu.Add( "", 0, meMenuSeparator );

// クリップボード履歴のアイテムをメニューに
if ( versionCheck ) {
  if ( cbCount ) {
    var sm1  = CreatePopupMenu();
    var sm2  = CreatePopupMenu();
    var sm3  = CreatePopupMenu();
    var sm4  = CreatePopupMenu();
    menu.AddPopup( "▼ クリップボード履歴の一覧 (&C) ▼", sm1 );
    for ( var i = 0, id, label; i < cbCount; i ++ ) {
      id = i + 1;
      label = MenuKey( cbArray[i], id, width, menuWidth );
      menu.Add( label, id, grayFlag );
      sm2. Add( label, id + 100, grayFlag );
      sm3. Add( label, id + 200 );
      sm4. Add( label, id + 300 );
    }
    menu.Add( "", 0, meMenuSeparator );
    menu.Add( "クリップボードのすべての履歴を削除する (&E)", 99 );
    sm1.AddPopup( "履歴からアイテムをスニペットに登録 (&P)", sm4 );
    sm1.AddPopup( "貼り付けしてからアイテムを削除 (&M)", sm2 );
    sm1.AddPopup( "履歴からアイテムを削除 (&D)", sm3 );
    sm1.Add( "", 0, meMenuSeparator );
    sm1.Add( "すべての履歴を削除 (&E)", 99 );
    sm1.Add( "", 0, meMenuSeparator );
    sm1.Add( "キャンセル & ", 0 );
  }
}
if ( ! cbCount && cbData.length ) {
  menu.Add( "▼ クリップボード ▼", 0, meMenuGrayed );
  label = MenuKey( cbData, 1, width, menuWidth );
  menu.Add( label, 17, grayFlag );
} 
else if ( ! cbCount && ! cbData.length ) {
  menu.Add( "※ クリップボードにテキストデータはありません ※"
          , 0, meMenuGrayed );
}

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


// ステータスバーの表示
if ( grayFlag ) {
  Status = " ドキュメントは書き換え禁止です。";
}
else if ( ! versionCheck ) {
  Status = " 「クリップボード履歴」機能の動作要件は"
         + " \"Mery ver 2.8.1\" 以上です。";
}
else if ( gksIsExist && cbCount ) {
  Status = " 履歴アイテムの Ctrl+クリック で"
         + " 「貼り付けしてからアイテムを削除」";
}
else {
  Status = " 「クリップボード履歴 と スニペット」マクロ";
}
Status += " [ "
       + ( ( new Date() - start ) / 1000 ).toFixed( 3 ).replace( /\./, ". " )
       + " 秒 ]";


// ポップアップメニューを表示
var r = menu.Track( + menuPosMouse );
var confirmStr = "クリップボードのすべての履歴を削除しますか? ";

if ( r == 0 ) { Status = $status; }

// 1 ~ 17: クリップボード履歴のアイテムを貼り付け
else if ( r <= 16 ) {
  d.Write( cbArray[ r -1 ] );
  Status = "";
  // Ctrl キーを押しながらのときは、貼り付けしてからアイテムを削除
  if ( gksIsExist ) {
    $ctrl = WshShell.Run( "\"" + gksPath + "\" c", 0, true );
    if ( $ctrl == 1 ) {
      cb.ClearData( r -1 );
      Status = " クリップボード履歴からアイテムを削除しました。";
    }
  }
}
else if ( r == 17 ) {
  d.Write( cbData );
  Status = "";
}

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

// 101 ~ 116: 貼り付けしてからアイテムを削除
else if ( r > 100 && r < 200 ) {
  d.Write( cbArray[ r -101 ] );
  cb.ClearData( r -101 );
  Status = " 履歴からアイテムを削除しました。";
}

// 201 ~ 216: クリップボード履歴からアイテムを削除
else if ( r > 200 && r < 300 ) {
  cb.ClearData( r -201 );
  Status = " 履歴からアイテムを削除しました。";
}

// 300 ~ 316: スニペットに登録(ピン止め)
else if ( r >= 300 && r < 400 ) {
  try {
    var snippetsDir = Fso.GetParentFolderName( snPath );
    var pluginsDir = Fso.GetParentFolderName( snippetsDir );
    if ( ! Fso.FolderExists( pluginsDir ) ) {
      Fso.CreateFolder( pluginsDir );
    }
    if ( ! Fso.FolderExists( snippetsDir ) ) {
      Fso.CreateFolder( snippetsDir );
    }
    // 選択範囲 または クリップボード履歴のアイテム
    var str = ( r == 300 )
            ? st
            : ( cb.GetData( r -301 ) || cb.GetData() );
    str = snText
        + ( ! snText || snText.charAt( snText.length -1 ) == "\n"
          ? "" : "\n" )
        + str.replace( /\\/g, "\\\\" )
             .replace( /\t/g, "\\t" )
             .replace( /\n/g, "\\n" )
             .replace( /\r/g, "\\r" );
    IO.SaveToFile( snPath, str, "utf-8", true );
    var copyFrom = ( r == 300 ) ? "範囲" : "したアイテム";
    Status = " 選択" + copyFrom + "をスニペットに登録しました。";
  } catch ( e ) {
    Status = " スニペットに登録できませんでした。";
  }
}

// 400: スニペットを編集(snippets.txt を開く)
else if ( r == 400 ) {
  WshShell.Run( "\"" + editor.FullName + "\" \"" + snPath + "\"" );
  Status = " " + snPath;
}

// 401 ~ : ピン止めアイテムを貼り付け
else if ( r > 400 ) {
  var strArr = snArray[ r -401 ].replace( /^(?:\t)*[^\t]*\t/, "" )
                                 .split( "\\\\" );
  for ( var i = 0; i < strArr.length; i ++ ) {
    strArr[i] = strArr[i].replace( /\\t/g, "\t" )
                         .replace( /\\r/g, "\r" )
                         .replace( /\\n/g, "\n" )
                         .replace( /\\/g, "" );
  }
  var str = strArr.join( "\\" );
  d.Write( str );
  Status = "";
}


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

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

/**
 * 関数 MenuKey( str, num, numWidth, menuWidth, boolean )
 * ポップアップメニューに表示するラベルを生成する
 * ・行頭空白を除去、空白文字を圧縮:		→「›」(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, conv ) {
  if ( conv ) {
    var strArr = str.replace( /^[^\t]*\t/, "" ).split( "\\\\" );
    for ( var i = 0; i < strArr.length; i ++ ) {
      strArr[i] = strArr[i].replace( /\\t/g, " › " )
                           .replace( /\\r|(\\r)?\\n/g, " ↲ " )
                           .replace( /\\/g, "" );
    }
    str = strArr.join( "\\" );
  }
  var reg = /[\u00A0\u1680\u180E\u2000-\u200E\u2028\u2029\u202F\u205F\u2062\u2063\uFEFF]/g
  var menuKey = str.replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " )
                   .slice( 0, menuWidth + 1 )
                   .replace( /(?:\r?\n|\r)/g, " ↲ " )
                   .replace( /[&]/g, "&&" )
                   .replace( /[\\]/g, "∖" )
                   .replace( reg, "▯" )
                   .replace( /[!"%'(),.:;@\[\]`a-z{|}]/g,
                     function( tmp ) {
                       return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
                     } );
  num = num ? ( "   " + num ).slice( - numWidth ).replace( /\d$/, "&$&: " ) : "";
  menuKey = ( menuKey.length > menuWidth )
          ? menuKey.slice( 0, menuWidth ) + " ..."
          : menuKey;
  return num + menuKey;
}


// ---------- ▼ 能書き ▼ ---------- //

/**
 【このマクロの仕様・制限事項】
 ・ver 2.8.1 以前の Mery では「クリップボード履歴」機能を使用できません。
 
 ・「クリップボード履歴」は Mery 本体のメモリストアのものを使用します。
 
 ・「スニペット」プラグインの設定ファイル snippets.txt の読み書きをします。
   ※「include ライブラリ」が必要です(snippets.txt ファイルの読み書きに使用)。
   ※「スニペット」プラグインを導入していない場合でも、
     「ピン止めアイテム/スニペット」機能を使用できます。
     snippets.txt ファイルの保存場所は Mery\Plugins\Snippets フォルダです
   (インストーラ版では %AppData%\Mery\Plugins\Snippets フォルダ)。
 
 ・「GetKeyState.exe(キー状態取得実行ファイル) 」で機能を拡張できます。
      → クリップボード履歴のアイテムを Ctrl+クリックした場合、
         アイテムを貼り付けし、貼り終えたアイテムを削除します。
   ※「GetKeyState.exe」は Mery\Macros フォルダに配置してください
     (Macros フォルダ以外の場所にあるなら設定項目でパスを指定する)。
   ※「GetKeyState.exe」がなくても、クリップボード履歴の
      サブメニュー項目から「貼り付けしてからアイテムを削除」できます。
 
 【ツールメニューの「クリップボード履歴」と異なる部分】 (2019/11/05)
 ・「クリップボードのすべての履歴を削除」したあとでも、
   Windows OS のクリップボードの最新の1件がテキストデータである場合は、
  「クリップボード履歴」にアイテムが表示されます。
   ※ Mery 本来の「クリップボード履歴」機能でも「履歴を消去」したあとにも
     Ctrl+V によるペーストができることがあるので、これを可視化してあります。
 
 【スニペットプラグインと異なる部分】 (2019/11/07)
 ・ このマクロからスニペットに登録したアイテムは
    snippets.txt の末尾に追加されます。
 ・ snippets.txt 内の「-」×1 と空白だけの行をセパレータにしません。
      → メイン階層を「クリップボード履歴」と共用しているため、
         体裁上の都合で「ピン止めアイテム」内でのセパレータは見送り。
   ※「-」×2 以上であれば、有効文字列として扱います。
   ※「ピン止めアイテム/スニペット」サブメニュー内では
      階層ごとに区切ってベタで列挙します。
 ・ snippets.txt 内の「&」記号によるアクセラレータはすべて無視します。
      → 有効文字列のある行を上から順に連番化し、番号をアクセラレータにします。
 ・ snippets.txt 内の「空行・空白行」の扱い方などで
    スニペットプラグインと異なる解釈をしている部分があります。
   ※ このマクロでは、snippets.txt 内の 空行、タブ文字だけの空白行、「-」だけの行を
      完全に無視するので、「空文字や "-" だけのサブメニュー見出し」を作りません
    (ただし、全角空白や2つ以上のハイフン「--」は文字列として扱う)。
        → ポップアップメニューでの表示状態がスニペットプラグインと
          同じ階層構造にならないことがあります。
   ※ snippets.txt 内の空行や「-」だけの行、タブインデントでのクループ化が
    適切でない部分は、ポップアップメニューに正しく反映されません。
 ・ タブインデントの階層を深くするさいは、かならず一段ずつ下げてください
  (二段以上の差があるとエラーの元)。
      → その行またはグループをスキップし、ポップアップメニューに表示しません。
   ※ 階層を浅くするさいは、二段以上の差があっても構いません。
 */


更新履歴

• 2019/08/01: 初版
• 2019/08/06:
 ・「ピン止めアイテムを貼り付け」コードの変数ミスを修正
 ・クリップボード履歴内の重複アイテムを削除する設定を追加。
 ・ピン止めアイテムが少ないときはメインメニューにアイテムを表示。
 ・snippets.txt 内の空行を無視。
 ・クリップボード履歴に長大なデータがあるときの動作速度を少しだけ改善。
• 2019/11/01:
 ・ステータス表示を追加
 ・クリップボードにテキストデータがないときのメニュー構成を変更
 ・アイテムの行数(改行数+1)をメニュー内に追加表示
 ・メニュー内に表示する改行コードの矢印を「↲」(U+21B2) に変更
 ・スニペット機能での「ピン止め/貼り付け」のさいの、改行コードやタブコードではない文字列「\n」や「\t」の扱いを修正
 ・snippets.txt がないときのエラーを修正
• 2019/11/05
 ・各アイテムの行数表示を廃止
 ・クリップボード履歴からスニペットにアイテムを登録するコマンドを追加
 ・メインメニューに表示するピン止めアイテム数の上限設定を廃止
 ・スニペット機能での「ピン止め/貼り付け」のさいの、改行コードやタブコードではない文字列「\n」や「\t」の扱いを再修正
  ( … したつもりだが、まだ不完全かも)
 ・スニペットプラグインのサブメニュー化階層構造をある程度再現した
  ( … つもりだが、アレンジしたので同じ表示状態にならないことがある)
• 2019/11/09
 ・ver 2.8.0 以前の Mery でもスニペット機能だけ利用できるように変更
 ・「クリップボード履歴の重複アイテム削除」の設定項目を廃止( "削除する" で固定)
 ・snippets.txt 内の単独「\」の処理をスニペットプラグインにあわせる修正
 ・snippets.txt 内のセパレータ用の「-」の行をスキップする処理を追加
これでだいたいはスニペットの機能を再現できたとおもいますが…。
スポンサーリンク